use crate::Word; #[derive(Debug, Clone, PartialEq, Eq)] pub(crate) enum Token { Label(String), Operator(String), Symbol(String), SymbolDef(String), Number(Word), Address(Word), String(String), } pub fn split(mut line: String) -> Vec { line.push('\n'); let mut res = Vec::new(); let mut buffer = String::new(); let mut has_label = false; let mut string_started = false; let mut skip_next = false; let mut address = false; for c in line.chars() { buffer.push(c); if skip_next || (string_started && c != '"') { skip_next = false; continue; } match c { ':' => if ! has_label { buffer.pop(); res.push(Token::Label(buffer.clone())); buffer.clear(); has_label = true; } else { panic!("Found double labels!"); }, ' ' | '\t' => { buffer.pop(); if buffer.is_empty() { continue; } if (has_label && (res.len() == 1)) || (!has_label && (res.is_empty())) { res.push(Token::Operator(buffer.clone())); buffer.clear(); } }, '"' => { buffer.pop(); if string_started { res.push(Token::String(buffer.clone())); buffer.clear(); } string_started = !string_started; }, ',' | '\n' | ';' => { buffer.pop(); if buffer.is_empty() { if c == ';' { break; } else { continue; } } if let Some(num) = buffer.parse::().ok() { if address { address = false; res.push(Token::Address(num)); } else { res.push(Token::Number(num)); } } else if res.len() == has_label as usize { res.push(Token::Operator(buffer.clone())); } else { res.push(Token::Symbol(buffer.clone())); } buffer.clear(); if c == ';' { break; } }, '=' => if buffer.is_empty() { panic!("Cannot begin the line with an =") } else if let Token::Operator(name) = &res[0] { res[0] = Token::SymbolDef(name.clone()); buffer.clear(); } else { panic!("Before an = you may only have a symbol name!"); }, '\\' => skip_next = true, '%' => { buffer.pop(); address = true; }, '-' => if address { panic!("Addresses cannot be negative!"); }, 'A'..='Z' | 'a'..='z' | '0'..='9' | '_' | '.' | '$' | '?' => {}, _ => panic!("Found invalid character '{}'", c), } } res }