Added numeric type annotations

This commit is contained in:
Kyler Olsen 2025-12-02 11:31:27 -07:00
parent a26a1c0d4a
commit a154741176
1 changed files with 172 additions and 0 deletions

View File

@ -153,6 +153,15 @@ pub struct LexError {
pub type LexResult<T> = Result<T, LexError>;
#[derive(Debug, Clone, Copy)]
enum NumericLiteralType {
Binary,
Octal,
Decimal,
Hexadecimal,
Float,
}
impl LexerInfo {
fn make_error(&self, message: impl Into<String>, start_line: usize, start_col: usize) -> LexError {
LexError {
@ -316,6 +325,10 @@ impl LexerInfo {
c = self.advance();
}
if c == ':' {
return self.parse_numeric_type(start, start_line, start_col, NumericLiteralType::Binary);
}
let value = self.create_binary_integer(start);
Ok(Token::I64(value as i64))
}
@ -326,6 +339,10 @@ impl LexerInfo {
c = self.advance();
}
if c == ':' {
return self.parse_numeric_type(start, start_line, start_col, NumericLiteralType::Octal);
}
let value = self.create_octal_integer(start);
Ok(Token::I64(value as i64))
}
@ -341,6 +358,10 @@ impl LexerInfo {
return self.parse_float(start, start_line, start_col);
}
if c == ':' {
return self.parse_numeric_type(start, start_line, start_col, NumericLiteralType::Decimal);
}
let value = self.create_decimal_integer(start);
Ok(Token::I64(value as i64))
}
@ -351,6 +372,10 @@ impl LexerInfo {
c = self.advance();
}
if c == ':' {
return self.parse_numeric_type(start, start_line, start_col, NumericLiteralType::Hexadecimal);
}
let value = self.create_hexadecimal_integer(start);
Ok(Token::I64(value as i64))
}
@ -361,10 +386,157 @@ impl LexerInfo {
c = self.advance();
}
if c == ':' {
return self.parse_numeric_type(start, start_line, start_col, NumericLiteralType::Float);
}
let value = self.create_float(start);
Ok(Token::Double(value))
}
fn parse_numeric_type(&mut self, start: usize, start_line: usize, start_col: usize, literal_type: NumericLiteralType) -> LexResult<Token> {
let mut c = self.advance(); // skip ':'
let mut is_float = false;
let mut is_unsigned = false;
let mut bit_size = 64; // default
if c == 'f' {
is_float = true;
if !matches!(literal_type, NumericLiteralType::Decimal | NumericLiteralType::Float) {
return Err(self.make_error("Invalid numeric literal: float type not allowed.", start_line, start_col));
}
c = self.advance();
if c == '6' && self.far_peek(1) == '4' {
bit_size = 64;
self.advance();
self.advance();
} else if c == '3' && self.far_peek(1) == '2' {
bit_size = 32;
self.advance();
self.advance();
} else {
return Err(self.make_error("Invalid float type: must be of type 'f64' or 'f32'.", start_line, start_col));
}
} else if c == 'i' || c == 'u' {
if matches!(literal_type, NumericLiteralType::Float) {
return Err(self.make_error("Invalid float type: must be of type 'f64' or 'f32'.", start_line, start_col));
}
is_unsigned = c == 'u';
c = self.advance();
if c == '6' && self.far_peek(1) == '4' {
bit_size = 64;
self.advance();
self.advance();
} else if c == '3' && self.far_peek(1) == '2' {
bit_size = 32;
self.advance();
self.advance();
} else if c == '1' && self.far_peek(1) == '6' {
bit_size = 16;
self.advance();
self.advance();
} else if c == '8' {
bit_size = 8;
self.advance();
} else {
let type_name = if is_unsigned { "unsigned" } else { "signed" };
return Err(self.make_error(
format!("Invalid {} integer type: must be of type '{}64', '{}32', '{}16', or '{}8'.",
type_name, if is_unsigned { "u" } else { "i" },
if is_unsigned { "u" } else { "i" },
if is_unsigned { "u" } else { "i" },
if is_unsigned { "u" } else { "i" }),
start_line, start_col));
}
} else {
return Err(self.make_error("Invalid numeric type: type must start with 'f', 'i', or 'u'.", start_line, start_col));
}
// Create the token based on the parsed type
if is_float {
let value = self.create_float(start);
match bit_size {
32 => Ok(Token::Float(value as f32)),
64 => Ok(Token::Double(value)),
_ => unreachable!()
}
} else {
let value = match literal_type {
NumericLiteralType::Binary => self.create_binary_integer(start),
NumericLiteralType::Octal => self.create_octal_integer(start),
NumericLiteralType::Decimal => self.create_decimal_integer(start),
NumericLiteralType::Hexadecimal => self.create_hexadecimal_integer(start),
NumericLiteralType::Float => return Err(self.make_error("Internal error: float literal in integer path", start_line, start_col)),
};
self.create_integer_token(value, is_unsigned, bit_size, start, start_line, start_col)
}
}
fn create_integer_token(&self, value: u64, is_unsigned: bool, bit_size: u32, start: usize, start_line: usize, start_col: usize) -> LexResult<Token> {
let is_negative = self.source[start..].starts_with('-');
match (is_unsigned, bit_size) {
(false, 64) => Ok(Token::I64(value as i64)),
(false, 32) => {
let signed = value as i64;
if signed < i32::MIN as i64 || signed > i32::MAX as i64 {
return Err(self.make_error("Integer overflow: value exceeds range for i32.", start_line, start_col));
}
Ok(Token::I32(value as i32))
}
(false, 16) => {
let signed = value as i64;
if signed < i16::MIN as i64 || signed > i16::MAX as i64 {
return Err(self.make_error("Integer overflow: value exceeds range for i16.", start_line, start_col));
}
Ok(Token::I16(value as i16))
}
(false, 8) => {
let signed = value as i64;
if signed < i8::MIN as i64 || signed > i8::MAX as i64 {
return Err(self.make_error("Integer overflow: value exceeds range for i8.", start_line, start_col));
}
Ok(Token::I8(value as i8))
}
(true, 64) => {
if is_negative {
return Err(self.make_error("Integer overflow: value exceeds range for u64.", start_line, start_col));
}
Ok(Token::U64(value))
}
(true, 32) => {
if is_negative {
return Err(self.make_error("Integer overflow: value exceeds range for u32.", start_line, start_col));
}
if value > u32::MAX as u64 {
return Err(self.make_error("Integer overflow: value exceeds range for u32.", start_line, start_col));
}
Ok(Token::U32(value as u32))
}
(true, 16) => {
if is_negative {
return Err(self.make_error("Integer overflow: value exceeds range for u16.", start_line, start_col));
}
if value > u16::MAX as u64 {
return Err(self.make_error("Integer overflow: value exceeds range for u16.", start_line, start_col));
}
Ok(Token::U16(value as u16))
}
(true, 8) => {
if is_negative {
return Err(self.make_error("Integer overflow: value exceeds range for u8.", start_line, start_col));
}
if value > u8::MAX as u64 {
return Err(self.make_error("Integer overflow: value exceeds range for u8.", start_line, start_col));
}
Ok(Token::U8(value as u8))
}
_ => Err(self.make_error("Invalid bit size for integer type.", start_line, start_col))
}
}
fn create_binary_integer(&self, start: usize) -> u64 {
let token = &self.source[start..self.pos];
let mut value = 0u64;