use super::*;
impl Lexer {
pub(super) fn lex_word(&mut self, chars: &[char], ln: u32, start: usize) -> usize {
let col = (start + 1) as u32;
let mut end = start;
while end < chars.len() && (chars[end].is_ascii_alphanumeric() || chars[end] == '_') {
end += 1;
}
let word: String = chars[start..end].iter().collect();
if word == "oh" {
let mut j = end;
while j < chars.len() && chars[j] == ' ' {
j += 1;
}
let mut k = j;
while k < chars.len() && (chars[k].is_ascii_alphanumeric() || chars[k] == '_') {
k += 1;
}
let next: String = chars[j..k].iter().collect();
if next == "no" {
self.push(TokenKind::OhNo, ln, col);
return k;
}
}
match keywords::lookup(&word) {
Some(kind) => self.push(kind, ln, col),
None => self.push(TokenKind::Ident(word), ln, col),
}
end
}
pub(super) fn lex_number(
&mut self,
chars: &[char],
ln: u32,
start: usize,
) -> Result<usize, Diagnostic> {
let col = (start + 1) as u32;
let mut end = start;
while end < chars.len() && chars[end].is_ascii_digit() {
end += 1;
}
let is_float =
end + 1 < chars.len() && chars[end] == '.' && chars[end + 1].is_ascii_digit();
if is_float {
end += 1; while end < chars.len() && chars[end].is_ascii_digit() {
end += 1;
}
let text: String = chars[start..end].iter().collect();
let value: f64 = text
.parse()
.expect("compiler bug: digit-only float must parse");
self.push(TokenKind::Float(value), ln, col);
return Ok(end);
}
let text: String = chars[start..end].iter().collect();
match text.parse::<i64>() {
Ok(value) => {
self.push(TokenKind::Int(value), ln, col);
Ok(end)
}
Err(_) => Err(self
.diag(ln, col, "this whole number is too big to hold")
.with_headline("very big. much number.")
.with_hint(format!(
"whole numbers must be between {} and {}",
i64::MIN,
i64::MAX
))),
}
}
pub(super) fn lex_operator(
&mut self,
chars: &[char],
ln: u32,
i: usize,
col: u32,
) -> Result<usize, Diagnostic> {
use crate::ast::BinOp;
let c = chars[i];
let next = chars.get(i + 1).copied();
let third = chars.get(i + 2).copied();
let three = match (c, next, third) {
('*', Some('*'), Some('=')) => Some(BinOp::Pow),
('/', Some('/'), Some('=')) => Some(BinOp::FloorDiv),
('<', Some('<'), Some('=')) => Some(BinOp::Shl),
('>', Some('>'), Some('=')) => Some(BinOp::Shr),
_ => None,
};
if let Some(op) = three {
self.push(TokenKind::AugAssign(op), ln, col);
return Ok(i + 3);
}
let two = match (c, next) {
('*', Some('*')) => Some(TokenKind::StarStar),
('/', Some('/')) => Some(TokenKind::SlashSlash),
('<', Some('<')) => Some(TokenKind::Shl),
('>', Some('>')) => Some(TokenKind::Shr),
('=', Some('=')) => Some(TokenKind::EqEq),
('!', Some('=')) => Some(TokenKind::NotEq),
('<', Some('=')) => Some(TokenKind::LtEq),
('>', Some('=')) => Some(TokenKind::GtEq),
('+', Some('=')) => Some(TokenKind::AugAssign(BinOp::Add)),
('-', Some('=')) => Some(TokenKind::AugAssign(BinOp::Sub)),
('*', Some('=')) => Some(TokenKind::AugAssign(BinOp::Mul)),
('/', Some('=')) => Some(TokenKind::AugAssign(BinOp::Div)),
('%', Some('=')) => Some(TokenKind::AugAssign(BinOp::Rem)),
('&', Some('=')) => Some(TokenKind::AugAssign(BinOp::BitAnd)),
('|', Some('=')) => Some(TokenKind::AugAssign(BinOp::BitOr)),
('^', Some('=')) => Some(TokenKind::AugAssign(BinOp::BitXor)),
_ => None,
};
if let Some(kind) = two {
self.push(kind, ln, col);
return Ok(i + 2);
}
let kind = match c {
'+' => TokenKind::Plus,
'-' => TokenKind::Minus,
'*' => TokenKind::Star,
'/' => TokenKind::Slash,
'%' => TokenKind::Percent,
'&' => TokenKind::Amp,
'|' => TokenKind::Pipe,
'^' => TokenKind::Caret,
'~' => TokenKind::Tilde,
'=' => TokenKind::Eq,
'!' => TokenKind::Bang,
'<' => TokenKind::Lt,
'>' => TokenKind::Gt,
':' => TokenKind::Colon,
',' => TokenKind::Comma,
'.' => TokenKind::Dot,
'(' => {
self.bracket_stack.push(Span { line: ln, col });
TokenKind::LParen
}
'[' => {
self.bracket_stack.push(Span { line: ln, col });
TokenKind::LBracket
}
'{' => {
self.bracket_stack.push(Span { line: ln, col });
TokenKind::LBrace
}
')' => {
self.bracket_stack.pop();
TokenKind::RParen
}
']' => {
self.bracket_stack.pop();
TokenKind::RBracket
}
'}' => {
self.bracket_stack.pop();
TokenKind::RBrace
}
other => {
return Err(self
.diag(ln, col, format!("'{other}' means nothing to doge here"))
.with_hint("remove it, or check for a typo"));
}
};
self.push(kind, ln, col);
Ok(i + 1)
}
}