Added numeric type annotations
This commit is contained in:
parent
a26a1c0d4a
commit
a154741176
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue