diff --git a/SLS_Rust/sls/Cargo.toml b/SLS_Rust/sls/Cargo.toml index 1d1282f..2647058 100644 --- a/SLS_Rust/sls/Cargo.toml +++ b/SLS_Rust/sls/Cargo.toml @@ -4,3 +4,8 @@ version = "0.1.0" edition = "2021" [dependencies] + +[build-dependencies] +rustc_version = "0.4" +chrono = "0.4" +vergen = { version = "8", features = ["build"] } diff --git a/SLS_Rust/sls/build.rs b/SLS_Rust/sls/build.rs new file mode 100644 index 0000000..ed4dc0f --- /dev/null +++ b/SLS_Rust/sls/build.rs @@ -0,0 +1,47 @@ +use std::process::Command; +use vergen::EmitBuilder; + +fn try_cmd(cmd: &mut Command) -> Option { + let out = cmd.output().ok()?; + if !out.status.success() { + return None; + } + Some(String::from_utf8_lossy(&out.stdout).trim().to_string()) +} + +fn main() -> Result<(), Box> { + // Emit vergen default build info (BUILD_DATE / BUILD_TIME) + EmitBuilder::builder().build()?; + + // Git describe + commit date (exact match to your Python) + let commit_info = (|| { + let hash = try_cmd( + Command::new("git") + .arg("describe") + .arg("--always") + .arg("--dirty") + .arg("--abbrev=7"), + )?; + + let date = try_cmd( + Command::new("git") + .arg("show") + .arg("-s") + .arg("--format=%ci"), + )?; + + Some(format!("{} {}", hash, date)) + })() + .unwrap_or_else(|| "unknown".into()); + + println!("cargo:rustc-env=GIT_COMMIT_HASH={}", commit_info); + + // Compiler name and rustc version + println!("cargo:rustc-env=COMPILER_NAME=rustc"); + + let rustc_ver = try_cmd(Command::new("rustc").arg("--version")) + .unwrap_or_else(|| "unknown".into()); + println!("cargo:rustc-env=COMPILER_VER={}", rustc_ver); + + Ok(()) +} diff --git a/SLS_Rust/sls/src/builtin.rs b/SLS_Rust/sls/src/builtin.rs index 7b22861..e69de29 100644 --- a/SLS_Rust/sls/src/builtin.rs +++ b/SLS_Rust/sls/src/builtin.rs @@ -1,6 +0,0 @@ -use crate::types::Value; - -/// Collection of builtin functions. This is a placeholder module. -pub fn hello() -> Value { - Value::Str("hello from builtin".to_string()) -} diff --git a/SLS_Rust/sls/src/errors.rs b/SLS_Rust/sls/src/errors.rs deleted file mode 100644 index fa46543..0000000 --- a/SLS_Rust/sls/src/errors.rs +++ /dev/null @@ -1,20 +0,0 @@ -use std::fmt; - -#[derive(Debug)] -pub enum SlsError { - Runtime(String), - Lexer(String), - Io(String), -} - -impl std::error::Error for SlsError {} - -impl fmt::Display for SlsError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - SlsError::Runtime(s) => write!(f, "Runtime: {}", s), - SlsError::Lexer(s) => write!(f, "Lexer: {}", s), - SlsError::Io(s) => write!(f, "IO: {}", s), - } - } -} diff --git a/SLS_Rust/sls/src/file.rs b/SLS_Rust/sls/src/file.rs index 1aa4622..d9cbf8d 100644 --- a/SLS_Rust/sls/src/file.rs +++ b/SLS_Rust/sls/src/file.rs @@ -1,16 +1,71 @@ -use crate::errors::SlsError; use std::fs; +use std::io; -pub struct SlsFile { - pub path: String, -} +use crate::interpreter::InterpreterState; +use crate::lexer::{LexerInfo, lexical_analysis}; +use crate::string::SlsStr; +use crate::errors::{LexerResult, LexerTokenResult}; -impl SlsFile { - pub fn open(path: impl Into) -> Self { - SlsFile { path: path.into() } - } +/// Execute the contents of a script file. +pub fn exec_file(interpreter: &mut InterpreterState, filename: SlsStr) -> bool { + // Read the whole file + let source = match fs::read_to_string(&filename.str) { + Ok(s) => s, + Err(e) => { + eprintln!("Cannot read file: {} ({})", filename.str, e); + return false; + } + }; - pub fn read_all(&self) -> Result { - fs::read_to_string(&self.path).map_err(|e| SlsError::Io(e.to_string())) + // Wrap source in SlsStr + let code = SlsStr::from_string(source); + let mut lexer_info = LexerInfo::new(filename.clone(), code); + + let result = lexical_analysis(&mut lexer_info); + + match result { + LexerResult::Error(err) => { + eprintln!("{}", err.message); + false + } + + LexerResult::Ok(mut head) => { + let mut node = Some(head.as_mut()); + while let Some(tok) = node { + match tok { + LexerTokenResult::Error(err) => { + eprintln!("{}", err.message); + return false; + } + LexerTokenResult::Token(token) => { + if !interpreter.execute(token) { + eprintln!("A runtime error occurred!"); + return false; + } + node = None; // No linked list, next handled below + } + LexerTokenResult::Next(_, next) => { + node = next.as_deref_mut(); + } + } + } + true + } + } +} + +/// Stand-alone file execution entry point. +pub fn run_file(filename: SlsStr) -> i32 { + println!("Executing file: {}", filename.str); + + let mut interpreter = match InterpreterState::new() { + Some(i) => i, + None => return 1, + }; + + if exec_file(&mut interpreter, filename) { + 0 + } else { + 1 } } diff --git a/SLS_Rust/sls/src/interpreter.rs b/SLS_Rust/sls/src/interpreter.rs index 43f61c4..294661d 100644 --- a/SLS_Rust/sls/src/interpreter.rs +++ b/SLS_Rust/sls/src/interpreter.rs @@ -1,17 +1,137 @@ -use crate::types::Value; use std::collections::HashMap; -pub struct Interpreter { - pub globals: HashMap, +use crate::lexer::*; // Identifier, Token, TokenString, etc. + +pub type BuiltinFn = fn(&mut InterpreterState) -> bool; + +#[derive(Debug, Clone)] +pub enum StackValue { + Identifier(Identifier), + + I64(i64), + I32(i32), + I16(i16), + I8(i8), + + U64(u64), + U32(u32), + U16(u16), + U8(u8), + + Float(f32), + Double(f64), + + Character(u8), + Boolean(bool), + + TokenString(TokenString), + + Callable(FunctionItem), } -impl Interpreter { +#[derive(Debug, Clone)] +pub enum FunctionItem { + TokenString(TokenString), + Builtin(BuiltinFn), +} + +#[derive(Debug)] +pub struct InterpreterState { + pub stack: Vec, + pub functions: HashMap, +} + +impl InterpreterState { pub fn new() -> Self { - Interpreter { globals: HashMap::new() } - } - - /// Evaluate source and return a Value. This is a stubbed placeholder. - pub fn eval(&mut self, _src: &str) -> Result> { - Ok(Value::Nil) + Self { + stack: Vec::new(), + functions: HashMap::new(), + } } } + +pub fn push_token(state: &mut InterpreterState, token: Token) -> bool { + let value = match token { + Token::Eof => return true, + + Token::Identifier(id) => { + StackValue::Identifier(id) + } + + Token::I64(v) => StackValue::I64(v), + Token::I32(v) => StackValue::I32(v), + Token::I16(v) => StackValue::I16(v), + Token::I8(v) => StackValue::I8(v), + + Token::U64(v) => StackValue::U64(v), + Token::U32(v) => StackValue::U32(v), + Token::U16(v) => StackValue::U16(v), + Token::U8(v) => StackValue::U8(v), + + Token::Float(v) => StackValue::Float(v), + Token::Double(v) => StackValue::Double(v), + + Token::Character(c) => StackValue::Character(c), + Token::Boolean(b) => StackValue::Boolean(b), + + Token::TokenString(ts) => StackValue::TokenString(ts), + + Token::StringLiteral(_) | + Token::Array(_) | + Token::TypeTuple(_) => return false, + }; + + state.stack.push(value); + true +} + +pub fn execute_func(state: &mut InterpreterState, key: &str) -> bool { + let item = match state.functions.get(key) { + Some(v) => v.clone(), + None => return false, + }; + + match item { + FunctionItem::Builtin(f) => f(state), + FunctionItem::TokenString(ts) => execute_token_string(state, ts), + } +} + +pub fn execute_token_string(state: &mut InterpreterState, ts: TokenString) -> bool { + for token in ts.tokens { + if let Token::Identifier(id) = &token { + if !id.is_literal { + if !execute_func(state, &id.name) { + return false; + } + continue; + } + } + + if !push_token(state, token) { + return false; + } + } + true +} + +pub fn execute(state: &mut InterpreterState, token: Token) -> bool { + match token { + Token::Identifier(id) if !id.is_literal => { + execute_func(state, &id.name) + } + _ => push_token(state, token), + } +} + +pub fn interpreter_create(load_builtins: fn(&mut InterpreterState) -> bool) + -> Option +{ + let mut state = InterpreterState::new(); + + if !load_builtins(&mut state) { + return None; + } + + Some(state) +} diff --git a/SLS_Rust/sls/src/lexer.rs b/SLS_Rust/sls/src/lexer.rs index bc671e3..93ba757 100644 --- a/SLS_Rust/sls/src/lexer.rs +++ b/SLS_Rust/sls/src/lexer.rs @@ -1,409 +1,127 @@ -#[derive(Debug, Clone, PartialEq)] -pub enum TokenType { - Illegal, +#[derive(Debug, Clone)] +pub struct LexerInfo { + pub filename: String, + pub source: String, + pub pos: usize, + pub column: usize, + pub line: usize, +} + +impl LexerInfo { + pub fn new(filename: impl Into, source: impl Into) -> Self { + Self { + filename: filename.into(), + source: source.into(), + pos: 0, + column: 1, + line: 1, + } + } +} + +#[derive(Debug, Clone)] +pub struct Identifier { + pub name: String, + pub is_literal: bool, +} + +#[derive(Debug, Clone)] +pub enum ArrayLiteral { + Identifiers(Vec), + I64(Vec), + I32(Vec), + I16(Vec), + I8(Vec), + U64(Vec), + U32(Vec), + U16(Vec), + U8(Vec), + Float(Vec), + Double(Vec), + Character(Vec), + Strings(Vec), + Boolean(Vec), + TokenStrings(Vec), + TypeTuples(Vec), + StructInline(StructInline), +} + +#[derive(Debug, Clone)] +pub struct ShapedArray { + pub array: ArrayLiteral, + pub shape: Vec, +} + +#[derive(Debug, Clone)] +pub struct TokenString { + pub tokens: Vec, +} + +#[derive(Debug, Clone)] +pub struct TypeTuple { + pub inputs: Vec, + pub outputs: Vec, +} + +#[derive(Debug, Clone)] +pub struct StructInline { + pub name: String, + pub values: Vec, +} + +#[derive(Debug, Clone)] +pub enum StructValue { + Integer(i64), + Float(f32), + Double(f64), + Boolean(bool), + Character(u8), + String(String), + Token(Token), +} + +#[derive(Debug, Clone)] +pub enum Token { Eof, - Ident, - Int, - Float, - Str, + Identifier(Identifier), - // Operators - Assign, - Plus, - Minus, - Asterisk, - Slash, - Bang, - Lt, - Gt, - Eq, - NotEq, + // All integer sizes + I64(i64), + I32(i32), + I16(i16), + I8(i8), + U64(u64), + U32(u32), + U16(u16), + U8(u8), - // Delimiters - Comma, - Semicolon, - Colon, - LParen, - RParen, - LBrace, - RBrace, - LBracket, - RBracket, + Float(f32), + Double(f64), + + Character(u8), + StringLiteral(String), + Boolean(bool), + + Array(ShapedArray), + TokenString(TokenString), + TypeTuple(TypeTuple), } -#[derive(Debug, Clone, PartialEq)] -pub struct Token { - pub ttype: TokenType, - pub lexeme: String, +#[derive(Debug, Clone)] +pub struct LexError { + pub message: String, + pub file: String, pub line: usize, pub column: usize, - pub numeric: Option, - pub float: Option, } -pub struct Lexer { - input: Vec, - pos: usize, // current position in input (points to current char) - read_pos: usize, // current reading position in input (after current char) - ch: Option, - line: usize, - column: usize, +pub type LexResult = Result; + +pub fn get_token(_lexer: &mut LexerInfo) -> Option { + None } -impl Lexer { - pub fn new(input: impl Into) -> Self { - let s = input.into(); - let mut lexer = Lexer { - input: s.chars().collect(), - pos: 0, - read_pos: 0, - ch: None, - line: 1, - column: 0, - }; - lexer.read_char(); - lexer - } - - fn read_char(&mut self) { - if self.read_pos >= self.input.len() { - self.ch = None; - } else { - self.ch = Some(self.input[self.read_pos]); - } - self.pos = self.read_pos; - self.read_pos += 1; - - if let Some(c) = self.ch { - if c == '\n' { - self.line += 1; - self.column = 0; - } else { - self.column += 1; - } - } - } - - fn peek_char(&self) -> Option { - if self.read_pos >= self.input.len() { - None - } else { - Some(self.input[self.read_pos]) - } - } - - fn skip_whitespace(&mut self) { - while let Some(c) = self.ch { - if c.is_whitespace() { - self.read_char(); - } else { - break; - } - } - } - - fn read_identifier(&mut self) -> String { - let start = self.pos; - while let Some(c) = self.ch { - if is_identifier_char(c) { - self.read_char(); - } else { - break; - } - } - self.input[start..self.pos].iter().collect() - } - - fn read_number(&mut self) -> String { - // Simple numeric reader: read digits, dot, underscores, and suffixes will be handled by caller - let start = self.pos; - while let Some(c) = self.ch { - if c.is_ascii_digit() || c == '.' || c == '_' || c == 'x' || c == 'b' || c == 'o' || c.is_ascii_hexdigit() { - self.read_char(); - } else { - break; - } - } - self.input[start..self.pos].iter().collect() - } - - fn read_string(&mut self) -> String { - // consume opening quote - self.read_char(); - let start = self.pos; - while let Some(c) = self.ch { - if c == '"' { - break; - } - // support escape handling later - self.read_char(); - } - let s: String = self.input[start..self.pos].iter().collect(); - // consume closing quote - self.read_char(); - s - } - - pub fn next_token(&mut self) -> Token { - self.skip_whitespace(); - - let token = match self.ch { - Some('=') => { - if self.peek_char() == Some('=') { - self.read_char(); - let lex = "==".to_string(); - Token { ttype: TokenType::Eq, lexeme: lex, line: self.line, column: self.column, numeric: None, float: None } - } else { - Token { ttype: TokenType::Assign, lexeme: "=".to_string(), line: self.line, column: self.column, numeric: None, float: None } - } - } - Some('+') => { Token { ttype: TokenType::Plus, lexeme: "+".to_string(), line: self.line, column: self.column, numeric: None, float: None } } - Some('*') => { Token { ttype: TokenType::Asterisk, lexeme: "*".to_string(), line: self.line, column: self.column, numeric: None, float: None } } - Some('/') => { Token { ttype: TokenType::Slash, lexeme: "/".to_string(), line: self.line, column: self.column, numeric: None, float: None } } - Some('!') => { - if self.peek_char() == Some('=') { - self.read_char(); - Token { ttype: TokenType::NotEq, lexeme: "!=".to_string(), line: self.line, column: self.column, numeric: None, float: None } - } else { - Token { ttype: TokenType::Bang, lexeme: "!".to_string(), line: self.line, column: self.column, numeric: None, float: None } - } - } - Some('<') => { Token { ttype: TokenType::Lt, lexeme: "<".to_string(), line: self.line, column: self.column, numeric: None, float: None } } - Some('>') => { Token { ttype: TokenType::Gt, lexeme: ">".to_string(), line: self.line, column: self.column, numeric: None, float: None } } - Some(',') => { Token { ttype: TokenType::Comma, lexeme: ",".to_string(), line: self.line, column: self.column, numeric: None, float: None } } - Some(';') => { Token { ttype: TokenType::Semicolon, lexeme: ";".to_string(), line: self.line, column: self.column, numeric: None, float: None } } - Some(':') => { Token { ttype: TokenType::Colon, lexeme: ":".to_string(), line: self.line, column: self.column, numeric: None, float: None } } - Some('(') => { Token { ttype: TokenType::LParen, lexeme: "(".to_string(), line: self.line, column: self.column, numeric: None, float: None } } - Some(')') => { Token { ttype: TokenType::RParen, lexeme: ")".to_string(), line: self.line, column: self.column, numeric: None, float: None } } - Some('{') => { Token { ttype: TokenType::LBrace, lexeme: "{".to_string(), line: self.line, column: self.column, numeric: None, float: None } } - Some('}') => { Token { ttype: TokenType::RBrace, lexeme: "}".to_string(), line: self.line, column: self.column, numeric: None, float: None } } - Some('[') => { Token { ttype: TokenType::LBracket, lexeme: "[".to_string(), line: self.line, column: self.column, numeric: None, float: None } } - Some(']') => { Token { ttype: TokenType::RBracket, lexeme: "]".to_string(), line: self.line, column: self.column, numeric: None, float: None } } - Some('"') => { - let s = self.read_string(); - Token { ttype: TokenType::Str, lexeme: s, line: self.line, column: self.column, numeric: None, float: None } - } - Some(c) if is_letter(c) => { - let ident = self.read_identifier(); - Token { ttype: TokenType::Ident, lexeme: ident, line: self.line, column: self.column, numeric: None, float: None } - } - Some(c) if c.is_ascii_digit() || (c == '-' && self.peek_char().map_or(false, |pc| pc.is_ascii_digit())) => { - // Handle optional leading '-' as part of number - let mut sign = 1i128; - if c == '-' { - sign = -1; - self.read_char(); - } - // Determine base and read digits with underscores and optional suffix - let start_pos = self.pos; - // If starting with '0' and next is x/b/o, handle prefixes - let mut base = 10u32; - let mut raw_digits = String::new(); - if self.ch == Some('0') && self.peek_char().map_or(false, |pc| pc == 'x' || pc == 'X' || pc == 'b' || pc == 'o') { - // consume '0' - self.read_char(); - if let Some(prefix) = self.ch { - match prefix { - 'x' | 'X' => base = 16, - 'b' => base = 2, - 'o' => base = 8, - _ => {} - } - // consume prefix - self.read_char(); - // read digits appropriate for base (allow underscores) - while let Some(d) = self.ch { - if d == '_' { self.read_char(); continue; } - if base == 16 && d.is_ascii_hexdigit() { raw_digits.push(d); self.read_char(); continue; } - if base == 10 && d.is_ascii_digit() { raw_digits.push(d); self.read_char(); continue; } - if base == 8 && ('0'..='7').contains(&d) { raw_digits.push(d); self.read_char(); continue; } - if base == 2 && (d == '0' || d == '1') { raw_digits.push(d); self.read_char(); continue; } - break; - } - } - } else { - // Decimal or float — detect invalid characters inside the literal - let mut seen_dot = false; - let mut invalid_start = false; - while let Some(d) = self.ch { - if d == '_' { self.read_char(); continue; } - if d == '.' { - if seen_dot { break; } - seen_dot = true; - raw_digits.push('.'); - self.read_char(); - continue; - } - if d.is_ascii_digit() { - raw_digits.push(d); - self.read_char(); - continue; - } - // if we encounter a comma or alphabetic character inside a decimal - // treat the whole sequence as an invalid literal - if d == ',' || d.is_ascii_alphabetic() { - invalid_start = true; - break; - } - break; - } - - if invalid_start { - // consume until whitespace or a clear delimiter to form a single Illegal token - while let Some(ch) = self.ch { - if ch.is_whitespace() { break; } - match ch { - '+' | '*' | '/' | '!' | '<' | '>' | '=' | ';' | '(' | ')' | '{' | '}' | '[' | ']' | '"' | '\'' => break, - _ => { self.read_char(); } - } - } - raw_digits = self.input[start_pos..self.pos].iter().collect(); - } - } - - // After digits, check for optional type suffix like ':i8' - let mut suffix: Option = None; - if self.ch == Some(':') { - // consume ':' - self.read_char(); - let mut sstart = self.pos; - while let Some(sc) = self.ch { - if sc.is_ascii_alphanumeric() || sc == '_' { self.read_char(); } else { break; } - } - suffix = Some(self.input[sstart..self.pos].iter().collect()); - } - - // Now attempt to parse numeric value - let mut token = Token { ttype: TokenType::Int, lexeme: String::new(), line: self.line, column: self.column, numeric: None, float: None }; - // reconstruct lexeme (include sign and any prefix) - let lexeme: String = self.input[start_pos..self.pos].iter().collect(); - let full_lex = if sign < 0 { format!("-{}", lexeme) } else { lexeme.clone() }; - token.lexeme = full_lex.clone(); - - // parse according to base - if raw_digits.contains('.') { - // float - match full_lex.replace("_", "").parse::() { - Ok(f) => { token.ttype = TokenType::Float; token.float = Some(f); } - Err(_) => { token.ttype = TokenType::Illegal; } - } - } else { - // integer: need to remove underscores and handle base - let digits = raw_digits.replace("_", ""); - if digits.is_empty() { - token.ttype = TokenType::Illegal; - } else { - // if prefix was used, adjust parsing - let parsed = if base == 10 { - digits.parse::().ok() - } else { - i128::from_str_radix(&digits, base).ok() - }; - if let Some(mut v) = parsed { - v *= sign; - // If base was non-decimal and a signed suffix exists, interpret - // the parsed unsigned bits as a two's-complement signed value - if base != 10 { - if let Some(ref sfx) = suffix { - match sfx.as_str() { - "i8" => { - let bits = 8u32; - let max_unsigned = (1i128 << bits) - 1; - let signed_max = i8::MAX as i128; - if v >= 0 && v <= max_unsigned && v > signed_max { - v = v - (1i128 << bits); - } - } - "i16" => { - let bits = 16u32; - let max_unsigned = (1i128 << bits) - 1; - let signed_max = i16::MAX as i128; - if v >= 0 && v <= max_unsigned && v > signed_max { - v = v - (1i128 << bits); - } - } - "i32" => { - let bits = 32u32; - let max_unsigned = (1i128 << bits) - 1; - let signed_max = i32::MAX as i128; - if v >= 0 && v <= max_unsigned && v > signed_max { - v = v - (1i128 << bits); - } - } - "i64" => { - let bits = 64u32; - let max_unsigned = (1i128 << bits) - 1; - let signed_max = i64::MAX as i128; - if v >= 0 && v <= max_unsigned && v > signed_max { - v = v - (1i128 << bits); - } - } - _ => {} - } - } - } - - // validate suffix ranges if present - let mut overflow = false; - if let Some(ref s) = suffix { - match s.as_str() { - "i8" => if v < i8::MIN as i128 || v > i8::MAX as i128 { overflow = true; } - "i16" => if v < i16::MIN as i128 || v > i16::MAX as i128 { overflow = true; } - "i32" => if v < i32::MIN as i128 || v > i32::MAX as i128 { overflow = true; } - "i64" => if v < i64::MIN as i128 || v > i64::MAX as i128 { overflow = true; } - "u8" => if v < 0 || v > u8::MAX as i128 { overflow = true; } - "u16" => if v < 0 || v > u16::MAX as i128 { overflow = true; } - "u32" => if v < 0 || v > u32::MAX as i128 { overflow = true; } - "u64" => if v < 0 || v > u64::MAX as i128 { overflow = true; } - _ => {} - } - } else { - // default type is i64 per tests: check i64 range - if v < i64::MIN as i128 || v > i64::MAX as i128 { overflow = true; } - } - - if overflow { - token.ttype = TokenType::Illegal; - } else { - token.numeric = Some(v); - token.ttype = TokenType::Int; - } - } else { - token.ttype = TokenType::Illegal; - } - } - } - - token - } - Some('-') => { Token { ttype: TokenType::Minus, lexeme: "-".to_string(), line: self.line, column: self.column, numeric: None, float: None } } - None => { Token { ttype: TokenType::Eof, lexeme: "".to_string(), line: self.line, column: self.column, numeric: None, float: None } } - Some(_) => { Token { ttype: TokenType::Illegal, lexeme: self.ch.unwrap().to_string(), line: self.line, column: self.column, numeric: None, float: None } } - }; - - // advance to next char if not EOF and we didn't already advance inside readers - if self.ch.is_some() { - // For cases where read_identifier/read_number/read_string already moved position - // we don't want to skip an extra char. The read_* helpers leave `ch` at the - // character after the token. To keep behavior consistent, only call read_char - // when the token was produced from a single-char branch. - match token.ttype { - TokenType::Ident | TokenType::Int | TokenType::Float | TokenType::Str => {} - TokenType::Eof => {} - _ => { self.read_char(); } - } - } - - token - } +pub fn lexical_analysis(_lexer: &mut LexerInfo) -> LexResult> { + Ok(Vec::new()) } - -fn is_letter(c: char) -> bool { - c.is_ascii_alphabetic() || c == '_' -} - -fn is_identifier_char(c: char) -> bool { - c.is_ascii_alphanumeric() || c == '_' -} - diff --git a/SLS_Rust/sls/src/lib.rs b/SLS_Rust/sls/src/lib.rs deleted file mode 100644 index 134d811..0000000 --- a/SLS_Rust/sls/src/lib.rs +++ /dev/null @@ -1,13 +0,0 @@ -pub mod types; -pub mod errors; -pub mod file; -pub mod lexer; -pub mod interpreter; -pub mod repl; -pub mod meta; -pub mod builtin; - -// Re-export commonly used items for tests and external users -pub use crate::lexer::{Lexer, Token, TokenType}; -pub use crate::types::Value; -pub use crate::interpreter::Interpreter; diff --git a/SLS_Rust/sls/src/main.rs b/SLS_Rust/sls/src/main.rs index 8f07065..f70da23 100644 --- a/SLS_Rust/sls/src/main.rs +++ b/SLS_Rust/sls/src/main.rs @@ -1,15 +1,69 @@ -use sls::interpreter::Interpreter; -use sls::meta; -use sls::repl; +use std::env; +use std::process; + +use crate::file::run_file; +use crate::repl::repl; +use crate::string::SlsStr; + +// These mirror the C macros. +const SLS_NAME: &str = "SLS_RUST"; +const SLS_VER: &str = "a.0.0"; + +// Environment variables set via build.rs for commit hash / compiler. +const GIT_COMMIT_HASH: &str = env!("GIT_COMMIT_HASH", "UNKNOWN"); +const COMPILER_NAME: &str = env!("COMPILER_NAME", "Unknown"); +const COMPILER_VER: &str = env!("COMPILER_VER", "0"); + +fn print_version() { + println!( + "YREA SLS ({}) {} ({})", + SLS_NAME, + SLS_VER, + GIT_COMMIT_HASH + ); + println!( + "Compiled with {} {} on {} {}", + COMPILER_NAME, + COMPILER_VER, + env!("BUILD_DATE"), + env!("BUILD_TIME") + ); +} fn main() { - println!("Starting sls (Rust) - {} v{}", meta::NAME, meta::VERSION); - let mut interp = Interpreter::new(); - // placeholder: evaluate empty program to ensure basic startup - match interp.eval("") { - Ok(_) => println!("Interpreter initialized."), - Err(e) => eprintln!("Interpreter failed to initialize: {}", e), + let mut args = env::args().skip(1); + + let mut version_flag = false; + let mut filename: Option = None; + + match args.len() { + 0 => {} + 1 => { + let arg = args.next().unwrap(); + if arg == "--version" || arg == "-v" { + version_flag = true; + } else { + filename = Some(arg); + } + } + _ => { + eprintln!("Too many arguments!"); + process::exit(1); + } } - // start REPL stub - repl::run_repl(); + + if version_flag { + print_version(); + process::exit(0); + } + + if let Some(file) = filename { + let sls_filename = SlsStr::from_string(file); + let status = run_file(sls_filename); + process::exit(status); + } + + // Default to REPL + let status = repl(); + process::exit(status); } diff --git a/SLS_Rust/sls/src/meta.rs b/SLS_Rust/sls/src/meta.rs deleted file mode 100644 index 347d4c9..0000000 --- a/SLS_Rust/sls/src/meta.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub const VERSION: &str = "0.1.0"; -pub const NAME: &str = "sls_rust"; diff --git a/SLS_Rust/sls/src/repl.rs b/SLS_Rust/sls/src/repl.rs index 4999145..59acbb3 100644 --- a/SLS_Rust/sls/src/repl.rs +++ b/SLS_Rust/sls/src/repl.rs @@ -1,8 +1,104 @@ -use crate::interpreter::Interpreter; +use std::io::{self, Write}; -pub fn run_repl() { - let mut interp = Interpreter::new(); - println!("SLS REPL (stub). Type Ctrl+C to exit."); - // For now just call eval once as a smoke test - let _ = interp.eval(""); +use crate::lexer::{Lexer, LexerInfo, lexical_analysis}; +use crate::meta::print_version; +use crate::interpreter::{InterpreterState, StackType}; +use crate::string::{SlsStr}; +use crate::errors::{LexerTokenResult, LexerResult}; + +static REPL_FILE_NAME: &str = ""; + +fn print_top_of_stack(state: &InterpreterState) { + let Some(item) = state.stack_top() else { + println!("#0: "); + return; + }; + + match &item.value { + StackType::Identifier(id) => { + println!("#0: ::{}", id.name); + } + StackType::I64(v) => println!("#0: {}", v), + StackType::I32(v) => println!("#0: {}:i32", v), + StackType::I16(v) => println!("#0: {}:i16", v), + StackType::I8(v) => println!("#0: {}:i8", v), + + StackType::U64(v) => println!("#0: {}:u64", v), + StackType::U32(v) => println!("#0: {}:u32", v), + StackType::U16(v) => println!("#0: {}:u16", v), + StackType::U8(v) => println!("#0: {}:u8", v), + + StackType::F32(v) => println!("#0: {}:f32", v), + StackType::F64(v) => println!("#0: {}", v), + + StackType::Character(ch) => println!("#0: {}", ch), + StackType::Boolean(b) => println!("#0: {}", if *b { "TRUE" } else { "FALSE" }), + + StackType::TokenString(_) => println!("#0: "), + StackType::Callable(_) => println!("#0: "), + }; +} + +pub fn repl() -> i32 { + print_version(); + println!("===== YREA SLS REPL ====="); + println!("Type `#exit` to exit."); + io::stdout().flush().unwrap(); + + let mut interpreter = match InterpreterState::new() { + Some(i) => i, + None => return 1, + }; + + let stdin = io::stdin(); + let mut buf = String::new(); + + loop { + buf.clear(); + + if stdin.read_line(&mut buf).is_err() { + return 1; + } + + if buf.trim_end() == "#exit" { + return 0; + } + + let code = SlsStr::from_string(buf.clone()); + let mut lexer_info = LexerInfo::new(REPL_FILE_NAME.into(), code.clone()); + let result = lexical_analysis(&mut lexer_info); + + match result { + LexerResult::Error(err) => { + println!("{}", err.message); + } + + LexerResult::Ok(mut head) => { + let mut node = Some(head.as_mut()); + + while let Some(tok_node) = node { + match tok_node { + LexerTokenResult::Error(err) => { + println!("{}", err.message); + break; + } + LexerTokenResult::Token(tok) => { + if !interpreter.execute(tok) { + println!("A runtime error occurred!"); + break; + } + } + LexerTokenResult::Next(_, next) => { + node = next.as_deref_mut(); + continue; + } + } + + node = None; + } + + print_top_of_stack(&interpreter); + } + } + } } diff --git a/SLS_Rust/sls/src/types.rs b/SLS_Rust/sls/src/types.rs deleted file mode 100644 index 5cfd6f4..0000000 --- a/SLS_Rust/sls/src/types.rs +++ /dev/null @@ -1,26 +0,0 @@ -use std::collections::HashMap; - -#[derive(Debug, Clone)] -pub enum Value { - Nil, - Bool(bool), - Int(i64), - Float(f64), - Str(String), - Object(HashMap), - Function(String), -} - -impl Value { - pub fn type_name(&self) -> &'static str { - match self { - Value::Nil => "nil", - Value::Bool(_) => "bool", - Value::Int(_) => "int", - Value::Float(_) => "float", - Value::Str(_) => "str", - Value::Object(_) => "object", - Value::Function(_) => "function", - } - } -} diff --git a/SLS_Rust/sls/tests/lexer_tests_generated.rs b/SLS_Rust/sls/tests/lexer_tests_generated.rs deleted file mode 100644 index f02e4bd..0000000 --- a/SLS_Rust/sls/tests/lexer_tests_generated.rs +++ /dev/null @@ -1,6129 +0,0 @@ -// Generated tests - do not edit by hand -// Use: run `python3 SLS_Tests/yaml_to_rust_tests.py SLS_Tests/cases.yaml tests/lexer_tests_generated.rs` - -use sls; // crate under test - -const INT64_MIN: i128 = i64::MIN as i128; -const UINT64_MAX: i128 = u64::MAX as i128; - -#[test] -fn test_empty_statement() { - let src = ""; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert!(got.is_empty()); -} - -#[test] -fn test_integer_default_decimal_0() { - let src = "0"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 0); -} - -#[test] -fn test_integer_default_decimal_1() { - let src = "-1"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), -1); -} - -#[test] -fn test_integer_default_decimal_42() { - let src = "42"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 42); -} - -#[test] -fn test_integer_default_decimal_leading_zeros() { - let src = "00042"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 42); -} - -#[test] -fn test_integer_default_hex_0xff() { - let src = "0xFF"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 255); -} - -#[test] -fn test_integer_default_hex_0xdeadbeef() { - let src = "0xdeadbeef"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 3735928559); -} - -#[test] -fn test_integer_default_hex_max() { - let src = "0x7FFFFFFFFFFFFFFF"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 9223372036854775807); -} - -#[test] -fn test_integer_default_binary_0b1010() { - let src = "0b1010"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 10); -} - -#[test] -fn test_integer_default_binary_all_ones() { - let src = "0b1111111111111111"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 65535); -} - -#[test] -fn test_integer_default_octal_0o755() { - let src = "0o755"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 493); -} - -#[test] -fn test_integer_default_octal_max_three_digits() { - let src = "0o777"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 511); -} - -#[test] -fn test_integer_default_decimal_max_i64() { - let src = "9223372036854775807"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 9223372036854775807); -} - -#[test] -fn test_integer_default_decimal_min_i64() { - let src = "-9223372036854775808"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), INT64_MIN); -} - -#[test] -fn test_integer_default_decimal_with_underscore() { - let src = "1_000_000"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 1000000); -} - -#[test] -fn test_integer_default_underscore_end() { - let src = "42_"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 42); -} - -#[test] -fn test_integer_default_underscore_double() { - let src = "4__2"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 42); -} - -#[test] -fn test_integer_default_whitespace() { - let src = " 42 "; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 42); -} - -#[test] -fn test_integer_default_hex_zero() { - let src = "0x0"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 0); -} - -#[test] -fn test_integer_default_binary_zero() { - let src = "0b0"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 0); -} - -#[test] -fn test_integer_default_octal_zero() { - let src = "0o0"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 0); -} - -#[test] -fn test_integer_default_decimal_with_commas_invalid() { - let src = "1,000,000"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Illegal); -} - -#[test] -fn test_integer_default_invalid_characters() { - let src = "12a3"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Illegal); -} - -#[test] -fn test_integer_default_invalid_prefix() { - let src = "0b2"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Illegal); -} - -#[test] -fn test_integer_i8_decimal_positive() { - let src = "42:i8"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 42); -} - -#[test] -fn test_integer_i8_zero() { - let src = "0:i8"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 0); -} - -#[test] -fn test_integer_i8_decimal_negative() { - let src = "-100:i8"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), -100); -} - -#[test] -fn test_integer_i8_hex() { - let src = "0x7F:i8"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 127); -} - -#[test] -fn test_integer_i8_binary() { - let src = "0b1111:i8"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 15); -} - -#[test] -fn test_integer_i8_octal() { - let src = "0o77:i8"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 63); -} - -#[test] -fn test_integer_i8_max_value() { - let src = "127:i8"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 127); -} - -#[test] -fn test_integer_i8_min_value() { - let src = "-128:i8"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), -128); -} - -#[test] -fn test_integer_i8_overflow() { - let src = "128:i8"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Illegal); -} - -#[test] -fn test_integer_i8_underflow() { - let src = "-129:i8"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Illegal); -} - -#[test] -fn test_integer_i16_decimal_positive() { - let src = "42:i16"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 42); -} - -#[test] -fn test_integer_i16_zero() { - let src = "0:i16"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 0); -} - -#[test] -fn test_integer_i16_decimal_negative() { - let src = "-100:i16"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), -100); -} - -#[test] -fn test_integer_i16_hex() { - let src = "0xFF:i16"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 255); -} - -#[test] -fn test_integer_i16_binary() { - let src = "0b1111:i16"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 15); -} - -#[test] -fn test_integer_i16_octal() { - let src = "0o77:i16"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 63); -} - -#[test] -fn test_integer_i16_max_value() { - let src = "32767:i16"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 32767); -} - -#[test] -fn test_integer_i16_min_value() { - let src = "-32768:i16"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), -32768); -} - -#[test] -fn test_integer_i16_overflow() { - let src = "32768:i16"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Illegal); -} - -#[test] -fn test_integer_i16_underflow() { - let src = "-32769:i16"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Illegal); -} - -#[test] -fn test_integer_i32_decimal_positive() { - let src = "42:i32"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 42); -} - -#[test] -fn test_integer_i32_zero() { - let src = "0:i32"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 0); -} - -#[test] -fn test_integer_i32_decimal_negative() { - let src = "-100:i32"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), -100); -} - -#[test] -fn test_integer_i32_hex() { - let src = "0xFF:i32"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 255); -} - -#[test] -fn test_integer_i32_binary() { - let src = "0b1111:i32"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 15); -} - -#[test] -fn test_integer_i32_octal() { - let src = "0o77:i32"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 63); -} - -#[test] -fn test_integer_i32_max_value() { - let src = "2147483647:i32"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 2147483647); -} - -#[test] -fn test_integer_i32_min_value() { - let src = "-2147483648:i32"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), -2147483648); -} - -#[test] -fn test_integer_i32_overflow() { - let src = "2147483648:i32"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Illegal); -} - -#[test] -fn test_integer_i32_underflow() { - let src = "-2147483649:i32"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Illegal); -} - -#[test] -fn test_integer_i32_with_underscores() { - let src = "1_000_000:i32"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 1000000); -} - -#[test] -fn test_integer_i64_decimal_positive() { - let src = "42:i64"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 42); -} - -#[test] -fn test_integer_i64_zero() { - let src = "0:i64"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 0); -} - -#[test] -fn test_integer_i64_decimal_negative() { - let src = "-100:i64"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), -100); -} - -#[test] -fn test_integer_i64_hex() { - let src = "0xFF:i64"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 255); -} - -#[test] -fn test_integer_i64_binary() { - let src = "0b1111:i64"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 15); -} - -#[test] -fn test_integer_i64_octal() { - let src = "0o77:i64"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 63); -} - -#[test] -fn test_integer_i64_max_value() { - let src = "9223372036854775807:i64"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 9223372036854775807); -} - -#[test] -fn test_integer_i64_min_value() { - let src = "-9223372036854775808:i64"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), INT64_MIN); -} - -#[test] -fn test_integer_i64_overflow() { - let src = "9223372036854775808:i64"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Illegal); -} - -#[test] -fn test_integer_i64_underflow() { - let src = "-9223372036854775809:i64"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Illegal); -} - -#[test] -fn test_integer_i64_with_underscores() { - let src = "1_000_000:i64"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 1000000); -} - -#[test] -fn test_integer_u8_decimal_positive() { - let src = "42:u8"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 42); -} - -#[test] -fn test_integer_u8_zero() { - let src = "0:u8"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 0); -} - -#[test] -fn test_integer_u8_hex() { - let src = "0xFF:u8"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 255); -} - -#[test] -fn test_integer_u8_binary() { - let src = "0b1111:u8"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 15); -} - -#[test] -fn test_integer_u8_octal() { - let src = "0o77:u8"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 63); -} - -#[test] -fn test_integer_u8_max_value() { - let src = "255:u8"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 255); -} - -#[test] -fn test_integer_u8_min_value() { - let src = "0:u8"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 0); -} - -#[test] -fn test_integer_u8_overflow() { - let src = "256:u8"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Illegal); -} - -#[test] -fn test_integer_u8_underflow() { - let src = "-1:u8"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Illegal); -} - -#[test] -fn test_integer_u16_decimal_positive() { - let src = "42:u16"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 42); -} - -#[test] -fn test_integer_u16_zero() { - let src = "0:u16"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 0); -} - -#[test] -fn test_integer_u16_hex() { - let src = "0xFF:u16"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 255); -} - -#[test] -fn test_integer_u16_binary() { - let src = "0b1111:u16"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 15); -} - -#[test] -fn test_integer_u16_octal() { - let src = "0o77:u16"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 63); -} - -#[test] -fn test_integer_u16_max_value() { - let src = "65535:u16"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 65535); -} - -#[test] -fn test_integer_u16_min_value() { - let src = "0:u16"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 0); -} - -#[test] -fn test_integer_u16_overflow() { - let src = "65536:u16"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Illegal); -} - -#[test] -fn test_integer_u16_underflow() { - let src = "-1:u16"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Illegal); -} - -#[test] -fn test_integer_u32_decimal_positive() { - let src = "42:u32"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 42); -} - -#[test] -fn test_integer_u32_zero() { - let src = "0:u32"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 0); -} - -#[test] -fn test_integer_u32_hex() { - let src = "0xFF:u32"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 255); -} - -#[test] -fn test_integer_u32_binary() { - let src = "0b1111:u32"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 15); -} - -#[test] -fn test_integer_u32_octal() { - let src = "0o77:u32"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 63); -} - -#[test] -fn test_integer_u32_max_value() { - let src = "4294967295:u32"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 4294967295); -} - -#[test] -fn test_integer_u32_min_value() { - let src = "0:u32"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 0); -} - -#[test] -fn test_integer_u32_overflow() { - let src = "4294967296:u32"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Illegal); -} - -#[test] -fn test_integer_u32_underflow() { - let src = "-1:u32"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Illegal); -} - -#[test] -fn test_integer_u32_with_underscores() { - let src = "1_000_000:u32"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 1000000); -} - -#[test] -fn test_integer_u64_decimal_positive() { - let src = "42:u64"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 42); -} - -#[test] -fn test_integer_u64_zero() { - let src = "0:u64"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 0); -} - -#[test] -fn test_integer_u64_hex() { - let src = "0xFF:u64"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 255); -} - -#[test] -fn test_integer_u64_binary() { - let src = "0b1111:u64"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 15); -} - -#[test] -fn test_integer_u64_octal() { - let src = "0o77:u64"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 63); -} - -#[test] -fn test_integer_u64_max_value() { - let src = "18446744073709551615:u64"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), UINT64_MAX); -} - -#[test] -fn test_integer_u64_min_value() { - let src = "0:u64"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 0); -} - -#[test] -fn test_integer_u64_overflow() { - let src = "18446744073709551616:u64"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Illegal); -} - -#[test] -fn test_integer_u64_underflow() { - let src = "-1:u64"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Illegal); -} - -#[test] -fn test_integer_u64_with_underscores() { - let src = "1_000_000:u64"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 1000000); -} - -#[test] -fn test_integer_i8_hex_max() { - let src = "0x7F:i8"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 127); -} - -#[test] -fn test_integer_i8_binary_max() { - let src = "0b01111111:i8"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 127); -} - -#[test] -fn test_integer_i8_octal_max() { - let src = "0o177:i8"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 127); -} - -#[test] -fn test_integer_i8_negative_hex() { - let src = "-0x80:i8"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), -128); -} - -#[test] -fn test_integer_u8_hex_max() { - let src = "0xFF:u8"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 255); -} - -#[test] -fn test_integer_u8_binary_max() { - let src = "0b11111111:u8"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 255); -} - -#[test] -fn test_integer_u8_octal_max() { - let src = "0o377:u8"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 255); -} - -#[test] -fn test_integer_i16_hex_sample() { - let src = "0x1234:i16"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 4660); -} - -#[test] -fn test_integer_i16_binary_sample() { - let src = "0b1111111100000000:i16"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), -256); -} - -#[test] -fn test_integer_i16_octal_sample() { - let src = "0o1234:i16"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 668); -} - -#[test] -fn test_integer_u16_hex_max() { - let src = "0xFFFF:u16"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 65535); -} - -#[test] -fn test_integer_u16_binary_max() { - let src = "0b1111111111111111:u16"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 65535); -} - -#[test] -fn test_integer_u16_octal_max() { - let src = "0o177777:u16"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 65535); -} - -#[test] -fn test_integer_u16_decimal_mid() { - let src = "50000:u16"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 50000); -} - -#[test] -fn test_integer_i32_hex_sample() { - let src = "0xABCD:i32"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 43981); -} - -#[test] -fn test_integer_i32_binary_sample() { - let src = "0b11110000:i32"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 240); -} - -#[test] -fn test_integer_u32_hex_max() { - let src = "0xFFFFFFFF:u32"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 4294967295); -} - -#[test] -fn test_integer_u32_binary_sample() { - let src = "0b11111111000000001111111100000000:u32"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 4278255360); -} - -#[test] -fn test_integer_u32_octal_max() { - let src = "0o37777777777:u32"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 4294967295); -} - -#[test] -fn test_integer_u32_decimal_mid() { - let src = "1000000:u32"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 1000000); -} - -#[test] -fn test_integer_i64_decimal_positive_42() { - let src = "42:i64"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 42); -} - -#[test] -fn test_integer_i64_hex_0xff() { - let src = "0xFF:i64"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 255); -} - -#[test] -fn test_integer_i64_binary_0b1010() { - let src = "0b1010:i64"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 10); -} - -#[test] -fn test_integer_i64_octal_0o755() { - let src = "0o755:i64"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 493); -} - -#[test] -fn test_integer_u64_hex_max() { - let src = "0xFFFFFFFFFFFFFFFF:u64"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), UINT64_MAX); -} - -#[test] -fn test_integer_u64_binary_sample() { - let src = "0b1010101010101010:u64"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 43690); -} - -#[test] -fn test_integer_u64_octal_sample() { - let src = "0o7777:u64"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 4095); -} - -#[test] -fn test_integer_u64_decimal() { - let src = "42:u64"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 42); -} - -#[test] -fn test_integer_hex_with_underscores() { - let src = "0xDEAD_BEEF:i64"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 3735928559); -} - -#[test] -fn test_integer_binary_with_underscores() { - let src = "0b1111_0000_1010_0101:i32"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 61605); -} - -#[test] -fn test_integer_octal_with_underscores() { - let src = "0o7_7_7:i16"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 511); -} - -#[test] -fn test_float_default_simple() { - let src = "3.14"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Float); - assert!(got[0].float.is_some(), "expected float value"); - assert!((got[0].float.unwrap() - 3.14).abs() < 1e-12); -} - -#[test] -fn test_float_default_zero() { - let src = "0.0"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Float); - assert!(got[0].float.is_some(), "expected float value"); - assert!((got[0].float.unwrap() - 0.0).abs() < 1e-12); -} - -#[test] -fn test_float_default_negative() { - let src = "-2.5"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Float); - assert!(got[0].float.is_some(), "expected float value"); - assert!((got[0].float.unwrap() - -2.5).abs() < 1e-12); -} - -#[test] -fn test_float_default_one() { - let src = "1.0"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Float); - assert!(got[0].float.is_some(), "expected float value"); - assert!((got[0].float.unwrap() - 1.0).abs() < 1e-12); -} - -#[test] -fn test_float_f32_simple() { - let src = "3.14:f32"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Float); - assert!(got[0].float.is_some(), "expected float value"); - assert!((got[0].float.unwrap() - 3.14).abs() < 1e-12); -} - -#[test] -fn test_float_f64_simple() { - let src = "2.718:f64"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Float); - assert!(got[0].float.is_some(), "expected float value"); - assert!((got[0].float.unwrap() - 2.718).abs() < 1e-12); -} - -#[test] -fn test_float_default_leading_zeros() { - let src = "00042.5"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Float); - assert!(got[0].float.is_some(), "expected float value"); - assert!((got[0].float.unwrap() - 42.5).abs() < 1e-12); -} - -#[test] -fn test_float_default_leading_zero_decimal() { - let src = "0.5"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Float); - assert!(got[0].float.is_some(), "expected float value"); - assert!((got[0].float.unwrap() - 0.5).abs() < 1e-12); -} - -#[test] -fn test_float_default_trailing_zeros() { - let src = "3.1400"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Float); - assert!(got[0].float.is_some(), "expected float value"); - assert!((got[0].float.unwrap() - 3.14).abs() < 1e-12); -} - -#[test] -fn test_float_default_no_leading_digit() { - let src = ".5"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Float); - assert!(got[0].float.is_some(), "expected float value"); - assert!((got[0].float.unwrap() - 0.5).abs() < 1e-12); -} - -#[test] -fn test_float_default_no_leading_digit_negative() { - let src = "-.25"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Float); - assert!(got[0].float.is_some(), "expected float value"); - assert!((got[0].float.unwrap() - -0.25).abs() < 1e-12); -} - -#[test] -fn test_float_default_no_trailing_digits() { - let src = "42."; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Float); - assert!(got[0].float.is_some(), "expected float value"); - assert!((got[0].float.unwrap() - 42.0).abs() < 1e-12); -} - -#[test] -fn test_float_default_no_trailing_digits_negative() { - let src = "-7."; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Float); - assert!(got[0].float.is_some(), "expected float value"); - assert!((got[0].float.unwrap() - -7.0).abs() < 1e-12); -} - -#[test] -fn test_float_default_very_small() { - let src = "0.000001"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Float); - assert!(got[0].float.is_some(), "expected float value"); - assert!((got[0].float.unwrap() - 1e-06).abs() < 1e-12); -} - -#[test] -fn test_float_default_very_large() { - let src = "1000000.0"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Float); - assert!(got[0].float.is_some(), "expected float value"); - assert!((got[0].float.unwrap() - 1000000.0).abs() < 1e-12); -} - -#[test] -fn test_float_default_underscore_integer_part() { - let src = "1_000_000.5"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Float); - assert!(got[0].float.is_some(), "expected float value"); - assert!((got[0].float.unwrap() - 1000000.5).abs() < 1e-12); -} - -#[test] -fn test_float_default_underscore_decimal_part() { - let src = "3.141_592_653"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Float); - assert!(got[0].float.is_some(), "expected float value"); - assert!((got[0].float.unwrap() - 3.141592653).abs() < 1e-12); -} - -#[test] -fn test_float_default_underscore_both_parts() { - let src = "1_234.567_89"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Float); - assert!(got[0].float.is_some(), "expected float value"); - assert!((got[0].float.unwrap() - 1234.56789).abs() < 1e-12); -} - -#[test] -fn test_float_default_underscore_trailing() { - let src = "42.5_"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Float); - assert!(got[0].float.is_some(), "expected float value"); - assert!((got[0].float.unwrap() - 42.5).abs() < 1e-12); -} - -#[test] -fn test_float_default_underscore_double() { - let src = "4__2.5"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Float); - assert!(got[0].float.is_some(), "expected float value"); - assert!((got[0].float.unwrap() - 42.5).abs() < 1e-12); -} - -#[test] -fn test_float_f32_with_underscores() { - let src = "1_234.567_89:f32"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Float); - assert!(got[0].float.is_some(), "expected float value"); - assert!((got[0].float.unwrap() - 1234.56789).abs() < 1e-12); -} - -#[test] -fn test_float_f32_precision_limit() { - let src = "1.2345678:f32"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Float); - assert!(got[0].float.is_some(), "expected float value"); - assert!((got[0].float.unwrap() - 1.2345678).abs() < 1e-12); -} - -#[test] -fn test_float_f32_high_precision() { - let src = "3.141592653589793:f32"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Float); - assert!(got[0].float.is_some(), "expected float value"); - assert!((got[0].float.unwrap() - 3.141592653589793).abs() < 1e-12); -} - -#[test] -fn test_float_f64_precision_limit() { - let src = "1.234567890123456:f64"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Float); - assert!(got[0].float.is_some(), "expected float value"); - assert!((got[0].float.unwrap() - 1.234567890123456).abs() < 1e-12); -} - -#[test] -fn test_float_f64_high_precision() { - let src = "3.141592653589793238:f64"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Float); - assert!(got[0].float.is_some(), "expected float value"); - assert!((got[0].float.unwrap() - 3.141592653589793).abs() < 1e-12); -} - -#[test] -fn test_float_f64_close_numbers_1() { - let src = "1.0000000000000001:f64"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Float); - assert!(got[0].float.is_some(), "expected float value"); - assert!((got[0].float.unwrap() - 1.0).abs() < 1e-12); -} - -#[test] -fn test_float_f64_close_numbers_2() { - let src = "1.0000000000000002:f64"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Float); - assert!(got[0].float.is_some(), "expected float value"); - assert!((got[0].float.unwrap() - 1.0000000000000002).abs() < 1e-12); -} - -#[test] -fn test_float_invalid_multiple_decimal_points() { - let src = "3.14.159"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Illegal); -} - -#[test] -fn test_float_invalid_characters() { - let src = "3.1a4"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Illegal); -} - -#[test] -fn test_float_invalid_type_annotation() { - let src = "3.14:i32"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Illegal); -} - -#[test] -fn test_float_invalid_type_name() { - let src = "3.14:f16"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Illegal); -} - -#[test] -fn test_float_invalid_comma_separator() { - let src = "1,234.56"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Illegal); -} - -#[test] -fn test_float_default_leading_whitespace() { - let src = " 3.14"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Float); - assert!(got[0].float.is_some(), "expected float value"); - assert!((got[0].float.unwrap() - 3.14).abs() < 1e-12); -} - -#[test] -fn test_float_default_trailing_whitespace() { - let src = "3.14 "; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Float); - assert!(got[0].float.is_some(), "expected float value"); - assert!((got[0].float.unwrap() - 3.14).abs() < 1e-12); -} - -#[test] -fn test_float_default_both_whitespace() { - let src = " 3.14 "; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Float); - assert!(got[0].float.is_some(), "expected float value"); - assert!((got[0].float.unwrap() - 3.14).abs() < 1e-12); -} - -#[test] -fn test_float_f32_with_whitespace() { - let src = " 2.718:f32 "; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Float); - assert!(got[0].float.is_some(), "expected float value"); - assert!((got[0].float.unwrap() - 2.718).abs() < 1e-12); -} - -#[test] -fn test_float_default_pi_approximate() { - let src = "3.141592653589793"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Float); - assert!(got[0].float.is_some(), "expected float value"); - assert!((got[0].float.unwrap() - 3.141592653589793).abs() < 1e-12); -} - -#[test] -fn test_float_f32_pi_approximate() { - let src = "3.1415927:f32"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Float); - assert!(got[0].float.is_some(), "expected float value"); - assert!((got[0].float.unwrap() - 3.1415927).abs() < 1e-12); -} - -#[test] -fn test_float_default_euler_approximate() { - let src = "2.718281828459045"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Float); - assert!(got[0].float.is_some(), "expected float value"); - assert!((got[0].float.unwrap() - 2.718281828459045).abs() < 1e-12); -} - -#[test] -fn test_float_f32_euler_approximate() { - let src = "2.7182817:f32"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Float); - assert!(got[0].float.is_some(), "expected float value"); - assert!((got[0].float.unwrap() - 2.7182817).abs() < 1e-12); -} - -#[test] -fn test_float_default_golden_ratio() { - let src = "1.618033988749895"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Float); - assert!(got[0].float.is_some(), "expected float value"); - assert!((got[0].float.unwrap() - 1.618033988749895).abs() < 1e-12); -} - -#[test] -fn test_float_default_sqrt2() { - let src = "1.4142135623730951"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Float); - assert!(got[0].float.is_some(), "expected float value"); - assert!((got[0].float.unwrap() - 1.4142135623730951).abs() < 1e-12); -} - -#[test] -fn test_float_default_positive_zero() { - let src = "0.0"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Float); - assert!(got[0].float.is_some(), "expected float value"); - assert!((got[0].float.unwrap() - 0.0).abs() < 1e-12); -} - -#[test] -fn test_float_default_negative_zero() { - let src = "-0.0"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Float); - assert!(got[0].float.is_some(), "expected float value"); - assert!((got[0].float.unwrap() - -0.0).abs() < 1e-12); -} - -#[test] -fn test_float_f32_positive_zero() { - let src = "0.0:f32"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Float); - assert!(got[0].float.is_some(), "expected float value"); - assert!((got[0].float.unwrap() - 0.0).abs() < 1e-12); -} - -#[test] -fn test_float_f32_negative_zero() { - let src = "-0.0:f32"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Float); - assert!(got[0].float.is_some(), "expected float value"); - assert!((got[0].float.unwrap() - -0.0).abs() < 1e-12); -} - -#[test] -fn test_char_simple_letter_uppercase_a() { - let src = "'A'"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric char code"); - assert_eq!(got[0].numeric.unwrap(), 65); -} - -#[test] -fn test_char_simple_letter_lowercase_a() { - let src = "'a'"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric char code"); - assert_eq!(got[0].numeric.unwrap(), 97); -} - -#[test] -fn test_char_simple_letter_uppercase_z() { - let src = "'Z'"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric char code"); - assert_eq!(got[0].numeric.unwrap(), 90); -} - -#[test] -fn test_char_simple_letter_lowercase_z() { - let src = "'z'"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric char code"); - assert_eq!(got[0].numeric.unwrap(), 122); -} - -#[test] -fn test_char_digit_0() { - let src = "'0'"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric char code"); - assert_eq!(got[0].numeric.unwrap(), 48); -} - -#[test] -fn test_char_digit_5() { - let src = "'5'"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric char code"); - assert_eq!(got[0].numeric.unwrap(), 53); -} - -#[test] -fn test_char_digit_9() { - let src = "'9'"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric char code"); - assert_eq!(got[0].numeric.unwrap(), 57); -} - -#[test] -fn test_char_space() { - let src = "' '"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric char code"); - assert_eq!(got[0].numeric.unwrap(), 32); -} - -#[test] -fn test_char_exclamation() { - let src = "'!'"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric char code"); - assert_eq!(got[0].numeric.unwrap(), 33); -} - -#[test] -fn test_char_question_mark() { - let src = "'?'"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric char code"); - assert_eq!(got[0].numeric.unwrap(), 63); -} - -#[test] -fn test_char_period() { - let src = "'.'"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric char code"); - assert_eq!(got[0].numeric.unwrap(), 46); -} - -#[test] -fn test_char_comma() { - let src = "','"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric char code"); - assert_eq!(got[0].numeric.unwrap(), 44); -} - -#[test] -fn test_char_semicolon() { - let src = "';'"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric char code"); - assert_eq!(got[0].numeric.unwrap(), 59); -} - -#[test] -fn test_char_colon() { - let src = "':'"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric char code"); - assert_eq!(got[0].numeric.unwrap(), 58); -} - -#[test] -fn test_char_plus() { - let src = "'+'"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric char code"); - assert_eq!(got[0].numeric.unwrap(), 43); -} - -#[test] -fn test_char_minus() { - let src = "'-'"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric char code"); - assert_eq!(got[0].numeric.unwrap(), 45); -} - -#[test] -fn test_char_asterisk() { - let src = "'*'"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric char code"); - assert_eq!(got[0].numeric.unwrap(), 42); -} - -#[test] -fn test_char_slash() { - let src = "'/'"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric char code"); - assert_eq!(got[0].numeric.unwrap(), 47); -} - -#[test] -fn test_char_equals() { - let src = "'='"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric char code"); - assert_eq!(got[0].numeric.unwrap(), 61); -} - -#[test] -fn test_char_less_than() { - let src = "'<'"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric char code"); - assert_eq!(got[0].numeric.unwrap(), 60); -} - -#[test] -fn test_char_greater_than() { - let src = "'>'"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric char code"); - assert_eq!(got[0].numeric.unwrap(), 62); -} - -#[test] -fn test_char_left_paren() { - let src = "'('"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric char code"); - assert_eq!(got[0].numeric.unwrap(), 40); -} - -#[test] -fn test_char_right_paren() { - let src = "')'"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric char code"); - assert_eq!(got[0].numeric.unwrap(), 41); -} - -#[test] -fn test_char_left_bracket() { - let src = "'['"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric char code"); - assert_eq!(got[0].numeric.unwrap(), 91); -} - -#[test] -fn test_char_right_bracket() { - let src = "']'"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric char code"); - assert_eq!(got[0].numeric.unwrap(), 93); -} - -#[test] -fn test_char_left_brace() { - let src = "'{'"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric char code"); - assert_eq!(got[0].numeric.unwrap(), 123); -} - -#[test] -fn test_char_right_brace() { - let src = "'}'"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric char code"); - assert_eq!(got[0].numeric.unwrap(), 125); -} - -#[test] -fn test_char_escape_single_quote() { - let src = "'\\\\''"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric char code"); - assert_eq!(got[0].numeric.unwrap(), 39); -} - -#[test] -fn test_char_escape_newline() { - let src = "'\\\\n'"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric char code"); - assert_eq!(got[0].numeric.unwrap(), 10); -} - -#[test] -fn test_char_escape_null_character() { - let src = "'\\\\0'"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric char code"); - assert_eq!(got[0].numeric.unwrap(), 0); -} - -#[test] -fn test_char_escape_backslash() { - let src = "'\\\\\\\\'"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric char code"); - assert_eq!(got[0].numeric.unwrap(), 92); -} - -#[test] -fn test_char_escape_tab() { - let src = "'\\\\t'"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric char code"); - assert_eq!(got[0].numeric.unwrap(), 9); -} - -#[test] -fn test_char_escape_carriage_return() { - let src = "'\\\\r'"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric char code"); - assert_eq!(got[0].numeric.unwrap(), 13); -} - -#[test] -fn test_char_with_leading_whitespace() { - let src = " 'A'"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric char code"); - assert_eq!(got[0].numeric.unwrap(), 65); -} - -#[test] -fn test_char_with_trailing_whitespace() { - let src = "'A' "; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric char code"); - assert_eq!(got[0].numeric.unwrap(), 65); -} - -#[test] -fn test_char_with_both_whitespace() { - let src = " 'A' "; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric char code"); - assert_eq!(got[0].numeric.unwrap(), 65); -} - -#[test] -fn test_char_tab_before() { - let src = "\\t'B'"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric char code"); - assert_eq!(got[0].numeric.unwrap(), 66); -} - -#[test] -fn test_char_newline_before() { - let src = "\\n'C'"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric char code"); - assert_eq!(got[0].numeric.unwrap(), 67); -} - -#[test] -fn test_char_empty_literal() { - let src = "''"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Illegal); -} - -#[test] -fn test_char_multiple_characters() { - let src = "'AB'"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Illegal); -} - -#[test] -fn test_char_unclosed_quote() { - let src = "'A"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Illegal); -} - -#[test] -fn test_char_unescaped_newline() { - let src = "'\\n'"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Illegal); -} - -#[test] -fn test_char_invalid_escape() { - let src = "'\\\\q'"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Illegal); -} - -#[test] -fn test_identifier_simple_lowercase() { - let src = "hello"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "hello"); -} - -#[test] -fn test_identifier_simple_uppercase() { - let src = "HELLO"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "HELLO"); -} - -#[test] -fn test_identifier_mixed_case() { - let src = "HelloWorld"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "HelloWorld"); -} - -#[test] -fn test_identifier_single_letter() { - let src = "x"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "x"); -} - -#[test] -fn test_identifier_single_letter_upper() { - let src = "X"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "X"); -} - -#[test] -fn test_identifier_with_numbers() { - let src = "var123"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "var123"); -} - -#[test] -fn test_identifier_numbers_end() { - let src = "myVar2"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "myVar2"); -} - -#[test] -fn test_identifier_mixed_numbers() { - let src = "a1b2c3"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "a1b2c3"); -} - -#[test] -fn test_identifier_with_underscore() { - let src = "hello_world"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "hello_world"); -} - -#[test] -fn test_identifier_leading_underscore() { - let src = "_private"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "_private"); -} - -#[test] -fn test_identifier_multiple_underscores() { - let src = "my_long_var_name"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "my_long_var_name"); -} - -#[test] -fn test_identifier_double_underscore() { - let src = "my__var"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "my__var"); -} - -#[test] -fn test_identifier_trailing_underscore() { - let src = "var_"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "var_"); -} - -#[test] -fn test_identifier_only_underscores() { - let src = "___"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "___"); -} - -#[test] -fn test_identifier_snake_case() { - let src = "my_variable_name"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "my_variable_name"); -} - -#[test] -fn test_identifier_camel_case() { - let src = "myVariableName"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "myVariableName"); -} - -#[test] -fn test_identifier_pascal_case() { - let src = "MyClassName"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "MyClassName"); -} - -#[test] -fn test_identifier_all_caps() { - let src = "MY_CONSTANT"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "MY_CONSTANT"); -} - -#[test] -fn test_identifier_with_dash() { - let src = "my-var"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "my-var"); -} - -#[test] -fn test_identifier_literal_simple() { - let src = "::hello"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "hello"); -} - -#[test] -fn test_identifier_literal_uppercase() { - let src = "::Point"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "Point"); -} - -#[test] -fn test_identifier_literal_snake_case() { - let src = "::my_var"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "my_var"); -} - -#[test] -fn test_identifier_literal_type_i64() { - let src = "::i64"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "i64"); -} - -#[test] -fn test_identifier_literal_type_string() { - let src = "::String"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "String"); -} - -#[test] -fn test_identifier_literal_type_point() { - let src = "::Point"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "Point"); -} - -#[test] -fn test_identifier_literal_trait_addable() { - let src = "::Addable"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "Addable"); -} - -#[test] -fn test_identifier_literal_trait_drawable() { - let src = "::Drawable"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "Drawable"); -} - -#[test] -fn test_identifier_literal_field_x() { - let src = "::x"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "x"); -} - -#[test] -fn test_identifier_literal_field_width() { - let src = "::width"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "width"); -} - -#[test] -fn test_identifier_literal_with_underscore() { - let src = "::_private"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "_private"); -} - -#[test] -fn test_identifier_literal_multiple_underscores() { - let src = "::my_long_name"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "my_long_name"); -} - -#[test] -fn test_identifier_literal_with_numbers() { - let src = "::var123"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "var123"); -} - -#[test] -fn test_identifier_leading_whitespace() { - let src = " hello"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "hello"); -} - -#[test] -fn test_identifier_trailing_whitespace() { - let src = "hello "; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "hello"); -} - -#[test] -fn test_identifier_both_whitespace() { - let src = " hello "; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "hello"); -} - -#[test] -fn test_identifier_tab_before() { - let src = "\\thello"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "hello"); -} - -#[test] -fn test_identifier_literal_leading_whitespace() { - let src = " ::hello"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "hello"); -} - -#[test] -fn test_identifier_literal_trailing_whitespace() { - let src = "::hello "; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "hello"); -} - -#[test] -fn test_identifier_literal_both_whitespace() { - let src = " ::hello "; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "hello"); -} - -#[test] -fn test_identifier_moderate_length() { - let src = "thisIsAReasonablyLongVariableName"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "thisIsAReasonablyLongVariableName"); -} - -#[test] -fn test_identifier_very_long() { - let src = "this_is_a_very_long_identifier_name_that_someone_might_use_for_some_reason"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "this_is_a_very_long_identifier_name_that_someone_might_use_for_some_reason"); -} - -#[test] -fn test_identifier_long_with_numbers() { - let src = "variable_with_many_numbers_123_456_789_000"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "variable_with_many_numbers_123_456_789_000"); -} - -#[test] -fn test_identifier_starting_with_number() { - let src = "123abc"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Illegal); -} - -#[test] -fn test_identifier_with_octothorpe() { - let src = "my#var"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "my"); -} - -#[test] -fn test_identifier_with_colon() { - let src = "my:var"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Illegal); -} - -#[test] -fn test_identifier_double_colon_inside() { - let src = "my::var"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Illegal); -} - -#[test] -fn test_identifier_only_numbers() { - let src = "123"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 123); -} - -#[test] -fn test_identifier_literal_empty() { - let src = "::"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Illegal); -} - -#[test] -fn test_identifier_case_lower() { - let src = "variable"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "variable"); -} - -#[test] -fn test_identifier_case_upper() { - let src = "VARIABLE"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "VARIABLE"); -} - -#[test] -fn test_identifier_case_mixed() { - let src = "Variable"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "Variable"); -} - -#[test] -fn test_identifier_case_camel() { - let src = "variableName"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "variableName"); -} - -#[test] -fn test_identifier_case_pascal() { - let src = "VariableName"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "VariableName"); -} - -#[test] -fn test_identifier_reserved_word_if() { - let src = "if"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "if"); -} - -#[test] -fn test_identifier_reserved_word_while() { - let src = "while"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "while"); -} - -#[test] -fn test_identifier_reserved_word_for() { - let src = "for"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "for"); -} - -#[test] -fn test_identifier_reserved_word_match() { - let src = "match"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "match"); -} - -#[test] -fn test_identifier_reserved_word_break() { - let src = "break"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "break"); -} - -#[test] -fn test_identifier_reserved_word_continue() { - let src = "continue"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "continue"); -} - -#[test] -fn test_identifier_reserved_word_fn() { - let src = "fn"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "fn"); -} - -#[test] -fn test_identifier_reserved_word_struct() { - let src = "struct"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "struct"); -} - -#[test] -fn test_identifier_reserved_word_union() { - let src = "union"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "union"); -} - -#[test] -fn test_identifier_reserved_word_enum() { - let src = "enum"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "enum"); -} - -#[test] -fn test_identifier_reserved_word_trait() { - let src = "trait"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "trait"); -} - -#[test] -fn test_identifier_reserved_word_impl() { - let src = "impl"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "impl"); -} - -#[test] -fn test_identifier_reserved_word_inher() { - let src = "inher"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "inher"); -} - -#[test] -fn test_identifier_reserved_word_dup() { - let src = "dup"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "dup"); -} - -#[test] -fn test_identifier_reserved_word_drop() { - let src = "drop"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "drop"); -} - -#[test] -fn test_identifier_reserved_word_swap() { - let src = "swap"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "swap"); -} - -#[test] -fn test_identifier_reserved_word_over() { - let src = "over"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "over"); -} - -#[test] -fn test_identifier_reserved_word_rot() { - let src = "rot"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "rot"); -} - -#[test] -fn test_identifier_reserved_word_pick() { - let src = "pick"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "pick"); -} - -#[test] -fn test_identifier_reserved_word_roll() { - let src = "roll"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "roll"); -} - -#[test] -fn test_identifier_reserved_word_depth() { - let src = "depth"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "depth"); -} - -#[test] -fn test_bool_true() { - let src = "true"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "true"); -} - -#[test] -fn test_bool_false() { - let src = "false"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "false"); -} - -#[test] -fn test_bool_true_leading_whitespace() { - let src = " true"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "true"); -} - -#[test] -fn test_bool_true_trailing_whitespace() { - let src = "true "; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "true"); -} - -#[test] -fn test_bool_true_both_whitespace() { - let src = " true "; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "true"); -} - -#[test] -fn test_bool_true_tab_before() { - let src = "\\ttrue"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "true"); -} - -#[test] -fn test_bool_false_leading_whitespace() { - let src = " false"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "false"); -} - -#[test] -fn test_bool_false_trailing_whitespace() { - let src = "false "; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "false"); -} - -#[test] -fn test_bool_false_both_whitespace() { - let src = " false "; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "false"); -} - -#[test] -fn test_bool_false_tab_before() { - let src = "\\tfalse"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "false"); -} - -#[test] -fn test_bool_true_capitalized() { - let src = "True"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "True"); -} - -#[test] -fn test_bool_false_capitalized() { - let src = "False"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "False"); -} - -#[test] -fn test_bool_true_all_caps() { - let src = "TRUE"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "TRUE"); -} - -#[test] -fn test_bool_false_all_caps() { - let src = "FALSE"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "FALSE"); -} - -#[test] -fn test_bool_true_mixed_case() { - let src = "tRuE"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "tRuE"); -} - -#[test] -fn test_bool_false_mixed_case() { - let src = "fAlSe"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "fAlSe"); -} - -#[test] -fn test_bool_numeric_1() { - let src = "1"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 1); -} - -#[test] -fn test_bool_numeric_0() { - let src = "0"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Int); - assert!(got[0].numeric.is_some(), "expected numeric value"); - assert_eq!(got[0].numeric.unwrap(), 0); -} - -#[test] -fn test_bool_yes() { - let src = "yes"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "yes"); -} - -#[test] -fn test_bool_no() { - let src = "no"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "no"); -} - -#[test] -fn test_bool_typo_ture() { - let src = "ture"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "ture"); -} - -#[test] -fn test_bool_typo_flase() { - let src = "flase"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "flase"); -} - -#[test] -fn test_bool_multiple_true_false() { - let src = "true false"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 2usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "true"); - assert_eq!(got[1].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[1].lexeme, "false"); -} - -#[test] -fn test_bool_multiple_same() { - let src = "true true"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 2usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "true"); - assert_eq!(got[1].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[1].lexeme, "true"); -} - -#[test] -fn test_bool_three_values() { - let src = "true false true"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 3usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[0].lexeme, "true"); - assert_eq!(got[1].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[1].lexeme, "false"); - assert_eq!(got[2].ttype, sls::lexer::TokenType::Ident); - assert_eq!(got[2].lexeme, "true"); -} - -#[test] -fn test_tokenstring_empty() { - let src = "{ }"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - // token_string check not implemented; received token: {:#?} - // TODO: implement nested expectations - // for now just assert we got an Ident or similar - assert!(!got[0].lexeme.is_empty()); -} - -#[test] -fn test_tokenstring_single_integer() { - let src = "{ 42 }"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - // token_string check not implemented; received token: {:#?} - // TODO: implement nested expectations - // for now just assert we got an Ident or similar - assert!(!got[0].lexeme.is_empty()); -} - -#[test] -fn test_tokenstring_single_identifier() { - let src = "{ dup }"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - // token_string check not implemented; received token: {:#?} - // TODO: implement nested expectations - // for now just assert we got an Ident or similar - assert!(!got[0].lexeme.is_empty()); -} - -#[test] -fn test_tokenstring_two_integers() { - let src = "{ 2 3 }"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - // token_string check not implemented; received token: {:#?} - // TODO: implement nested expectations - // for now just assert we got an Ident or similar - assert!(!got[0].lexeme.is_empty()); -} - -#[test] -fn test_tokenstring_simple_expression() { - let src = "{ 2 3 + }"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - // token_string check not implemented; received token: {:#?} - // TODO: implement nested expectations - // for now just assert we got an Ident or similar - assert!(!got[0].lexeme.is_empty()); -} - -#[test] -fn test_tokenstring_stack_ops() { - let src = "{ dup * }"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - // token_string check not implemented; received token: {:#?} - // TODO: implement nested expectations - // for now just assert we got an Ident or similar - assert!(!got[0].lexeme.is_empty()); -} - -#[test] -fn test_tokenstring_integer_literals() { - let src = "{ 0 42 -10 1000 }"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - // token_string check not implemented; received token: {:#?} - // TODO: implement nested expectations - // for now just assert we got an Ident or similar - assert!(!got[0].lexeme.is_empty()); -} - -#[test] -fn test_tokenstring_float_literals() { - let src = "{ 3.14 -2.5 0.0 }"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - // token_string check not implemented; received token: {:#?} - // TODO: implement nested expectations - // for now just assert we got an Ident or similar - assert!(!got[0].lexeme.is_empty()); -} - -#[test] -fn test_tokenstring_char_literal() { - let src = "{ 'A' }"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - // token_string check not implemented; received token: {:#?} - // TODO: implement nested expectations - // for now just assert we got an Ident or similar - assert!(!got[0].lexeme.is_empty()); -} - -#[test] -fn test_tokenstring_boolean_literals() { - let src = "{ true false }"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - // token_string check not implemented; received token: {:#?} - // TODO: implement nested expectations - // for now just assert we got an Ident or similar - assert!(!got[0].lexeme.is_empty()); -} - -#[test] -fn test_tokenstring_multiple_identifiers() { - let src = "{ dup swap over }"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - // token_string check not implemented; received token: {:#?} - // TODO: implement nested expectations - // for now just assert we got an Ident or similar - assert!(!got[0].lexeme.is_empty()); -} - -#[test] -fn test_tokenstring_identifier_literals() { - let src = "{ ::x ::y }"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - // token_string check not implemented; received token: {:#?} - // TODO: implement nested expectations - // for now just assert we got an Ident or similar - assert!(!got[0].lexeme.is_empty()); -} - -#[test] -fn test_tokenstring_mixed_identifiers() { - let src = "{ ::Point get x swap }"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - // token_string check not implemented; received token: {:#?} - // TODO: implement nested expectations - // for now just assert we got an Ident or similar - assert!(!got[0].lexeme.is_empty()); -} - -#[test] -fn test_tokenstring_nested_single() { - let src = "{ { 2 3 + } }"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - // token_string check not implemented; received token: {:#?} - // TODO: implement nested expectations - // for now just assert we got an Ident or similar - assert!(!got[0].lexeme.is_empty()); -} - -#[test] -fn test_tokenstring_nested_with_others() { - let src = "{ x { dup * } }"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - // token_string check not implemented; received token: {:#?} - // TODO: implement nested expectations - // for now just assert we got an Ident or similar - assert!(!got[0].lexeme.is_empty()); -} - -#[test] -fn test_tokenstring_multiple_nested() { - let src = "{ { 2 3 + } { 4 5 * } }"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - // token_string check not implemented; received token: {:#?} - // TODO: implement nested expectations - // for now just assert we got an Ident or similar - assert!(!got[0].lexeme.is_empty()); -} - -#[test] -fn test_tokenstring_double_nested() { - let src = "{ { { 42 } } }"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - // token_string check not implemented; received token: {:#?} - // TODO: implement nested expectations - // for now just assert we got an Ident or similar - assert!(!got[0].lexeme.is_empty()); -} - -#[test] -fn test_tokenstring_complex_nesting() { - let src = "{ 1 { 2 { 3 } 4 } 5 }"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - // token_string check not implemented; received token: {:#?} - // TODO: implement nested expectations - // for now just assert we got an Ident or similar - assert!(!got[0].lexeme.is_empty()); -} - -#[test] -fn test_tokenstring_no_whitespace() { - let src = "{2 3 +}"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - // token_string check not implemented; received token: {:#?} - // TODO: implement nested expectations - // for now just assert we got an Ident or similar - assert!(!got[0].lexeme.is_empty()); -} - -#[test] -fn test_tokenstring_extra_whitespace() { - let src = "{ 2 3 + }"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - // token_string check not implemented; received token: {:#?} - // TODO: implement nested expectations - // for now just assert we got an Ident or similar - assert!(!got[0].lexeme.is_empty()); -} - -#[test] -fn test_tokenstring_leading_whitespace_outside() { - let src = " { 2 3 + }"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - // token_string check not implemented; received token: {:#?} - // TODO: implement nested expectations - // for now just assert we got an Ident or similar - assert!(!got[0].lexeme.is_empty()); -} - -#[test] -fn test_tokenstring_trailing_whitespace_outside() { - let src = "{ 2 3 + } "; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - // token_string check not implemented; received token: {:#?} - // TODO: implement nested expectations - // for now just assert we got an Ident or similar - assert!(!got[0].lexeme.is_empty()); -} - -#[test] -fn test_tokenstring_with_tabs() { - let src = "{\\t2\\t3\\t+\\t}"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - // token_string check not implemented; received token: {:#?} - // TODO: implement nested expectations - // for now just assert we got an Ident or similar - assert!(!got[0].lexeme.is_empty()); -} - -#[test] -fn test_tokenstring_multiline_simple() { - let src = "{\\n 2 3 +\\n}"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - // token_string check not implemented; received token: {:#?} - // TODO: implement nested expectations - // for now just assert we got an Ident or similar - assert!(!got[0].lexeme.is_empty()); -} - -#[test] -fn test_tokenstring_multiline_multiple() { - let src = "{\\n dup\\n *\\n 2\\n +\\n}"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - // token_string check not implemented; received token: {:#?} - // TODO: implement nested expectations - // for now just assert we got an Ident or similar - assert!(!got[0].lexeme.is_empty()); -} - -#[test] -fn test_tokenstring_mixed_line_breaks() { - let src = "{ 1 2\\n3 4\\n\\n5 6 }"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - // token_string check not implemented; received token: {:#?} - // TODO: implement nested expectations - // for now just assert we got an Ident or similar - assert!(!got[0].lexeme.is_empty()); -} - -#[test] -fn test_tokenstring_indented_multiline() { - let src = "{\\n dup 0 >\\n { }\\n { 0 swap - }\\n if\\n}"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - // token_string check not implemented; received token: {:#?} - // TODO: implement nested expectations - // for now just assert we got an Ident or similar - assert!(!got[0].lexeme.is_empty()); -} - -#[test] -fn test_tokenstring_comment_end_of_line() { - let src = "{ 2 3 + // add them\\n}"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - // token_string check not implemented; received token: {:#?} - // TODO: implement nested expectations - // for now just assert we got an Ident or similar - assert!(!got[0].lexeme.is_empty()); -} - -#[test] -fn test_tokenstring_multiple_comments() { - let src = "{ 2 // first\\n3 // second\\n+ // add\\n}"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - // token_string check not implemented; received token: {:#?} - // TODO: implement nested expectations - // for now just assert we got an Ident or similar - assert!(!got[0].lexeme.is_empty()); -} - -#[test] -fn test_tokenstring_comment_own_line() { - let src = "{\\n // This is a comment\\n 2 3 +\\n}"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - // token_string check not implemented; received token: {:#?} - // TODO: implement nested expectations - // for now just assert we got an Ident or similar - assert!(!got[0].lexeme.is_empty()); -} - -#[test] -fn test_tokenstring_comment_at_start() { - let src = "{ // comment\\n2 3 + }"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - // token_string check not implemented; received token: {:#?} - // TODO: implement nested expectations - // for now just assert we got an Ident or similar - assert!(!got[0].lexeme.is_empty()); -} - -#[test] -fn test_tokenstring_multiple_comment_lines() { - let src = "{\\n // First comment\\n // Second comment\\n 2 3 +\\n}"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - // token_string check not implemented; received token: {:#?} - // TODO: implement nested expectations - // for now just assert we got an Ident or similar - assert!(!got[0].lexeme.is_empty()); -} - -#[test] -fn test_tokenstring_comments_nested() { - let src = "{ { 2 3 + // inner comment\\n} // outer comment\\n}"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - // token_string check not implemented; received token: {:#?} - // TODO: implement nested expectations - // for now just assert we got an Ident or similar - assert!(!got[0].lexeme.is_empty()); -} - -#[test] -fn test_tokenstring_unclosed() { - let src = "{ 2 3 +"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Illegal); -} - -#[test] -fn test_tokenstring_unclosed_nested() { - let src = "{ { 2 3 + }"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Illegal); -} - -#[test] -fn test_tokenstring_extra_closing_brace() { - let src = "{ 2 3 + } }"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 2usize, "token count mismatch"); - // token_string check not implemented; received token: {:#?} - // TODO: implement nested expectations - // for now just assert we got an Ident or similar - assert!(!got[0].lexeme.is_empty()); - assert_eq!(got[1].ttype, sls::lexer::TokenType::Illegal); -} - -#[test] -fn test_tokenstring_only_closing_brace() { - let src = "}"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - assert_eq!(got[0].ttype, sls::lexer::TokenType::Illegal); -} - -#[test] -fn test_tokenstring_error_inside() { - let src = "{ 2 3a + }"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - // token_string check not implemented; received token: {:#?} - // TODO: implement nested expectations - // for now just assert we got an Ident or similar - assert!(!got[0].lexeme.is_empty()); -} - -#[test] -fn test_tokenstring_function_body() { - let src = "{ dup * }"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - // token_string check not implemented; received token: {:#?} - // TODO: implement nested expectations - // for now just assert we got an Ident or similar - assert!(!got[0].lexeme.is_empty()); -} - -#[test] -fn test_tokenstring_loop_body() { - let src = "{ dup print 1 + }"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - // token_string check not implemented; received token: {:#?} - // TODO: implement nested expectations - // for now just assert we got an Ident or similar - assert!(!got[0].lexeme.is_empty()); -} - -#[test] -fn test_tokenstring_struct_fields() { - let src = "{ x: y: }"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - // token_string check not implemented; received token: {:#?} - // TODO: implement nested expectations - // for now just assert we got an Ident or similar - assert!(!got[0].lexeme.is_empty()); -} - -#[test] -fn test_tokenstring_lambda() { - let src = "{ 2 * }"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - // token_string check not implemented; received token: {:#?} - // TODO: implement nested expectations - // for now just assert we got an Ident or similar - assert!(!got[0].lexeme.is_empty()); -} - -#[test] -fn test_tokenstring_array_map() { - let src = "{ dup * }"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - // token_string check not implemented; received token: {:#?} - // TODO: implement nested expectations - // for now just assert we got an Ident or similar - assert!(!got[0].lexeme.is_empty()); -} - -#[test] -fn test_tokenstring_conditional_complex() { - let src = "{\\n dup 0 >\\n { dup * }\\n { drop 0 }\\n if\\n}"; - let mut lexer = sls::lexer::Lexer::new(src); - let mut got = vec![]; - loop { - let t = lexer.next_token(); - if t.ttype == sls::lexer::TokenType::Eof { break; } - got.push(t); - } - - assert_eq!(got.len(), 1usize, "token count mismatch"); - // token_string check not implemented; received token: {:#?} - // TODO: implement nested expectations - // for now just assert we got an Ident or similar - assert!(!got[0].lexeme.is_empty()); -} diff --git a/SLS_Tests/yaml_to_rust_tests.py b/SLS_Tests/yaml_to_rust_tests.py deleted file mode 100644 index a0620c9..0000000 --- a/SLS_Tests/yaml_to_rust_tests.py +++ /dev/null @@ -1,127 +0,0 @@ -import yaml -import re -from pathlib import Path - -""" -Convert YAML test cases to Rust integration tests for the `sls` crate. - -Usage: - python3 SLS_Tests/yaml_to_rust_tests.py SLS_Tests/cases.yaml SLS_Rust/sls/tests/lexer_tests_generated.rs - -This generator produces simple `#[test]` functions that run the lexer and -verify token kinds and values (basic checks). It's intentionally conservative -— it compares token types and lexemes/numeric values where applicable. -""" - -def sanitize_name(name: str) -> str: - name = re.sub(r"[^a-zA-Z0-9_]", "_", name) - name = re.sub(r"_+", "_", name) - name = name.strip("_") - name = name.lower() - if not name: - name = "unnamed" - return f"test_{name}" - - -def rust_string_literal(s: str) -> str: - return s.replace('\\', '\\\\').replace('"', '\\"') - - -def token_match_expectation(token_var: str, expected: dict) -> str: - ttype = expected.get('type') - val = expected.get('value') - - if ttype in ('i64','i32','i16','i8','u64','u32','u16','u8'): - # check numeric field produced by the lexer - # allow constant names like INT64_MIN to be used directly in generated code - if isinstance(val, str) and re.match(r"^[A-Za-z_][A-Za-z0-9_]*$", val): - vexpr = val - else: - vexpr = str(val) - return f"assert_eq!({token_var}.ttype, sls::lexer::TokenType::Int);\n assert!({token_var}.numeric.is_some(), \"expected numeric value\");\n assert_eq!({token_var}.numeric.unwrap(), {vexpr});" - elif ttype in ('f64','f32'): - return f"assert_eq!({token_var}.ttype, sls::lexer::TokenType::Float);\n assert!({token_var}.float.is_some(), \"expected float value\");\n assert!(({token_var}.float.unwrap() - {val}).abs() < 1e-12);" - elif ttype == 'string': - return f"assert_eq!({token_var}.ttype, sls::lexer::TokenType::Str);\n assert_eq!({token_var}.lexeme, \"{rust_string_literal(str(val))}\");" - elif ttype in ('identifier', 'identifier_literal'): - return f"assert_eq!({token_var}.ttype, sls::lexer::TokenType::Ident);\n assert_eq!({token_var}.lexeme, \"{rust_string_literal(str(val))}\");" - elif ttype == 'char': - codepoint = ord(val) if isinstance(val, str) and len(val) == 1 else val - return f"assert_eq!({token_var}.ttype, sls::lexer::TokenType::Int);\n assert!({token_var}.numeric.is_some(), \"expected numeric char code\");\n assert_eq!({token_var}.numeric.unwrap(), {codepoint});" - elif ttype == 'bool': - return f"assert_eq!({token_var}.ttype, sls::lexer::TokenType::Ident);\n assert_eq!({token_var}.lexeme, \"{'true' if val else 'false'}\");" - elif ttype == 'error': - # For now, assert that we got an Illegal token - return f"assert_eq!({token_var}.ttype, sls::lexer::TokenType::Illegal);" - elif ttype == 'token_string': - # Complex nested token strings are not handled by this simple generator - return f"// token_string check not implemented; received token: {{:#?}}\n // TODO: implement nested expectations\n // for now just assert we got an Ident or similar\n assert!(!{token_var}.lexeme.is_empty());" - else: - return f"// Unhandled expected token type: {ttype}\n assert!(!{token_var}.lexeme.is_empty());" - - -def generate_rust_test(test: dict) -> str: - name = sanitize_name(test.get('name','unnamed')) - code = test.get('code','') - tokens = test.get('tokens', []) - - fn_lines = [f"#[test]", f"fn {name}() " "{"] - fn_lines.append(f" let src = \"{rust_string_literal(str(code))}\";") - fn_lines.append(" let mut lexer = sls::lexer::Lexer::new(src);") - fn_lines.append(" let mut got = vec![];") - fn_lines.append(" loop {") - fn_lines.append(" let t = lexer.next_token();") - fn_lines.append(" if t.ttype == sls::lexer::TokenType::Eof { break; }") - fn_lines.append(" got.push(t);") - fn_lines.append(" }") - fn_lines.append("") - # Basic assertion count vs expected (allow zero expected -> empty) - if tokens: - fn_lines.append(f" assert_eq!(got.len(), {len(tokens)}usize, \"token count mismatch\");") - else: - fn_lines.append(" assert!(got.is_empty());") - - for i, token in enumerate(tokens): - expectation = token_match_expectation(f"got[{i}]", token) - # indent lines of expectation properly - for line in expectation.split('\n'): - fn_lines.append(f" {line}") - - fn_lines.append("}") - fn_lines.append("") - return "\n".join(fn_lines) - - -def yaml_to_rust_tests(yaml_path: str, output_path: str): - with open(yaml_path, 'r', encoding='utf-8') as f: - tests = yaml.safe_load(f) - - if not isinstance(tests, list): - raise ValueError('Expected YAML to be a list of tests') - - rust_tests = [] - for t in tests: - rust_tests.append(generate_rust_test(t)) - - header = """// Generated tests - do not edit by hand -// Use: run `python3 SLS_Tests/yaml_to_rust_tests.py SLS_Tests/cases.yaml tests/lexer_tests_generated.rs` - -use sls; // crate under test - -const INT64_MIN: i128 = i64::MIN as i128; -const UINT64_MAX: i128 = u64::MAX as i128; - -""" - - out_text = header + "\n".join(rust_tests) - Path(output_path).write_text(out_text, encoding='utf-8') - print(f"Generated {len(rust_tests)} Rust tests -> {output_path}") - - -if __name__ == '__main__': - import argparse - parser = argparse.ArgumentParser() - parser.add_argument('input') - parser.add_argument('output') - args = parser.parse_args() - yaml_to_rust_tests(args.input, args.output)