SeraphScript/src/parsing/lex_numerical.rs

243 lines
6.6 KiB
Rust
Raw Normal View History

2021-05-15 14:53:53 +00:00
use crate::defines::{LiteralFloat, LiteralInt};
use crate::parsing::lex_tokens::LexToken;
use itertools::MultiPeek;
use std::str::Chars;
#[inline(always)]
fn get_decimal_value(c: char) -> Option<LiteralInt> {
match c {
'0' => Some(0),
'1' => Some(1),
'2' => Some(2),
'3' => Some(3),
'4' => Some(4),
'5' => Some(5),
'6' => Some(6),
'7' => Some(7),
'8' => Some(8),
'9' => Some(9),
_ => None,
}
}
#[inline(always)]
fn lex_numeric_default(chars: &mut MultiPeek<Chars>) -> LexToken {
let mut int_value: LiteralInt = 0;
let mut decimal_value: LiteralInt = 0;
let mut exponent_value: LiteralInt = 0;
let mut decimal_length: LiteralInt = 0;
let mut is_decimal = false;
let mut is_exponent = false;
let mut is_reading = true;
let mut c: Option<char> = chars.peek().cloned();
while c.is_some() && is_reading {
let v = get_decimal_value(c.unwrap());
match v {
None => {
if c.unwrap() == '_' {
chars.next();
c = chars.peek().cloned();
continue;
}
if !is_decimal && c.unwrap() == '.' {
is_decimal = true;
chars.next();
c = chars.peek().cloned();
continue;
}
if is_decimal && c.unwrap() == 'e' || c.unwrap() == 'E' {
is_decimal = false;
is_exponent = true;
chars.next();
c = chars.peek().cloned();
continue;
}
c = chars.peek().cloned();
is_reading = false;
continue;
}
Some(i) => {
chars.next();
if is_decimal {
decimal_value *= 10;
decimal_value += i;
decimal_length += 1;
} else if is_exponent {
exponent_value *= 10;
exponent_value += i;
} else {
int_value *= 10;
int_value += i;
}
}
}
c = chars.peek().cloned();
}
chars.reset_peek();
if is_decimal || is_exponent {
let mut val = int_value as LiteralFloat
+ (decimal_value as LiteralFloat / 10_i64.pow(decimal_length as u32) as LiteralFloat);
if is_exponent {
val *= exponent_value.pow(10) as LiteralFloat;
}
LexToken::FloatLiteral(val)
} else {
LexToken::IntegerLiteral(int_value)
}
}
#[inline(always)]
fn get_hexadecimal_value(c: char) -> Option<LiteralInt> {
match c {
'0' => Some(0),
'1' => Some(1),
'2' => Some(2),
'3' => Some(3),
'4' => Some(4),
'5' => Some(5),
'6' => Some(6),
'7' => Some(7),
'8' => Some(8),
'9' => Some(9),
'A' | 'a' => Some(10),
'B' | 'b' => Some(11),
'C' | 'c' => Some(12),
'D' | 'd' => Some(13),
'E' | 'e' => Some(14),
'F' | 'f' => Some(15),
_ => None,
}
}
#[inline(always)]
fn lex_numeric_hexadecimal(chars: &mut MultiPeek<Chars>) -> LexToken {
let mut int_value: LiteralInt = 0;
let mut reading = true;
let mut n = chars.peek().cloned();
while n.is_some() && reading {
match get_hexadecimal_value(n.unwrap()) {
Some(i) => {
int_value <<= 4;
int_value += i;
chars.next();
}
None => {
if n.unwrap() == '_' {
chars.next();
} else {
reading = false
}
}
}
n = chars.peek().cloned();
}
LexToken::IntegerLiteral(int_value)
}
#[inline(always)]
fn get_octal_value(c: char) -> Option<LiteralInt> {
match c {
'0' => Some(0),
'1' => Some(1),
'2' => Some(2),
'3' => Some(3),
'4' => Some(4),
'5' => Some(5),
'6' => Some(6),
'7' => Some(7),
_ => None,
}
}
#[inline(always)]
fn lex_numeric_octal(chars: &mut MultiPeek<Chars>) -> LexToken {
let mut int_value: LiteralInt = 0;
let mut reading = true;
let mut n = chars.peek().cloned();
while n.is_some() && reading {
match get_octal_value(n.unwrap()) {
Some(i) => {
int_value <<= 3;
int_value += i;
chars.next();
}
None => {
if n.unwrap() == '_' {
chars.next();
} else {
reading = false
}
}
}
n = chars.peek().cloned();
}
LexToken::IntegerLiteral(int_value)
}
#[inline(always)]
fn get_binary_value(c: char) -> Option<LiteralInt> {
match c {
'0' => Some(0),
'1' => Some(1),
_ => None,
}
}
#[inline(always)]
fn lex_numeric_binary(chars: &mut MultiPeek<Chars>) -> LexToken {
let mut int_value: LiteralInt = 0;
let mut reading = true;
let mut n = chars.peek().cloned();
while n.is_some() && reading {
match get_binary_value(n.unwrap()) {
Some(i) => {
int_value <<= 1;
int_value += i;
chars.next();
}
None => {
if n.unwrap() == '_' {
chars.next();
} else {
reading = false
}
}
}
n = chars.peek().cloned();
}
LexToken::IntegerLiteral(int_value)
}
#[inline(always)]
pub fn lex_numeric(chars: &mut MultiPeek<Chars>) -> LexToken {
chars.reset_peek();
if chars.peek() == Some(&'0') {
match chars.peek() {
Some(&'D') | Some(&'d') => {
chars.next();
chars.next();
return lex_numeric_default(chars);
}
Some(&'X') | Some(&'x') => {
chars.next();
chars.next();
return lex_numeric_hexadecimal(chars);
}
Some(&'O') | Some(&'o') => {
chars.next();
chars.next();
return lex_numeric_octal(chars);
}
Some(&'B') | Some(&'b') => {
chars.next();
chars.next();
return lex_numeric_binary(chars);
}
_ => {}
}
}
chars.reset_peek();
lex_numeric_default(chars)
}