UPDATE: Dump of initial files

This commit is contained in:
Nicolás Hatcher
2023-11-18 21:26:18 +01:00
commit c5b8efd83d
279 changed files with 42654 additions and 0 deletions

View File

@@ -0,0 +1,297 @@
use super::lexer::{Compare, Lexer, Token};
pub struct Digit {
pub kind: char, // '#' | '?' | '0'
pub index: i32,
pub number: char, // 'i' | 'd' | 'e' (integer, decimal or exponent)
}
pub enum TextToken {
Literal(char),
Text(String),
Ghost(char),
Spacer(char),
// Text
Raw,
Digit(Digit),
Period,
// Dates
Day,
DayPadded,
DayNameShort,
DayName,
Month,
MonthPadded,
MonthNameShort,
MonthName,
MonthLetter,
YearShort,
Year,
}
pub struct NumberPart {
pub color: Option<i32>,
pub condition: Option<(Compare, f64)>,
pub use_thousands: bool,
pub percent: i32, // multiply number by 100^percent
pub comma: i32, // divide number by 1000^comma
pub tokens: Vec<TextToken>,
pub digit_count: i32, // number of digit tokens (#, 0 or ?) to the left of the decimal point
pub precision: i32, // number of digits to the right of the decimal point
pub is_scientific: bool,
pub scientific_minus: bool,
pub exponent_digit_count: i32,
}
pub struct DatePart {
pub color: Option<i32>,
pub tokens: Vec<TextToken>,
}
pub struct ErrorPart {}
pub struct GeneralPart {}
pub enum ParsePart {
Number(NumberPart),
Date(DatePart),
Error(ErrorPart),
General(GeneralPart),
}
pub struct Parser {
pub parts: Vec<ParsePart>,
lexer: Lexer,
}
impl ParsePart {
pub fn is_error(&self) -> bool {
match &self {
ParsePart::Date(..) => false,
ParsePart::Number(..) => false,
ParsePart::Error(..) => true,
ParsePart::General(..) => false,
}
}
pub fn is_date(&self) -> bool {
match &self {
ParsePart::Date(..) => true,
ParsePart::Number(..) => false,
ParsePart::Error(..) => false,
ParsePart::General(..) => false,
}
}
}
impl Parser {
pub fn new(format: &str) -> Self {
let lexer = Lexer::new(format);
let parts = vec![];
Parser { parts, lexer }
}
pub fn parse(&mut self) {
while self.lexer.peek_token() != Token::EOF {
let part = self.parse_part();
self.parts.push(part);
}
}
fn parse_part(&mut self) -> ParsePart {
let mut token = self.lexer.next_token();
let mut digit_count = 0;
let mut precision = 0;
let mut is_date = false;
let mut is_number = false;
let mut found_decimal_dot = false;
let mut use_thousands = false;
let mut comma = 0;
let mut percent = 0;
let mut last_token_is_digit = false;
let mut color = None;
let mut condition = None;
let mut tokens = vec![];
let mut is_scientific = false;
let mut scientific_minus = false;
let mut exponent_digit_count = 0;
let mut number = 'i';
let mut index = 0;
while token != Token::EOF && token != Token::Separator {
let next_token = self.lexer.next_token();
let token_is_digit = token.is_digit();
is_number = is_number || token_is_digit;
let next_token_is_digit = next_token.is_digit();
if token_is_digit {
if is_scientific {
exponent_digit_count += 1;
} else if found_decimal_dot {
precision += 1;
} else {
digit_count += 1;
}
}
match token {
Token::General => {
if tokens.is_empty() {
return ParsePart::General(GeneralPart {});
} else {
return ParsePart::Error(ErrorPart {});
}
}
Token::Comma => {
// If it is in between digit token then we use the thousand separator
if last_token_is_digit && next_token_is_digit {
use_thousands = true;
} else if digit_count > 0 {
comma += 1;
} else {
// Before the number is just a literal.
tokens.push(TextToken::Literal(','));
}
}
Token::Percent => {
tokens.push(TextToken::Literal('%'));
percent += 1;
}
Token::Period => {
if !found_decimal_dot {
tokens.push(TextToken::Period);
found_decimal_dot = true;
if number == 'i' {
number = 'd';
index = 0;
}
} else {
tokens.push(TextToken::Literal('.'));
}
}
Token::Color(index) => {
color = Some(index);
}
Token::Condition(cmp, value) => {
condition = Some((cmp, value));
}
Token::QuestionMark => {
tokens.push(TextToken::Digit(Digit {
kind: '?',
index,
number,
}));
index += 1;
}
Token::Sharp => {
tokens.push(TextToken::Digit(Digit {
kind: '#',
index,
number,
}));
index += 1;
}
Token::Zero => {
tokens.push(TextToken::Digit(Digit {
kind: '0',
index,
number,
}));
index += 1;
}
Token::Literal(value) => {
tokens.push(TextToken::Literal(value));
}
Token::Text(value) => {
tokens.push(TextToken::Text(value));
}
Token::Ghost(value) => {
tokens.push(TextToken::Ghost(value));
}
Token::Spacer(value) => {
tokens.push(TextToken::Spacer(value));
}
Token::Day => {
is_date = true;
tokens.push(TextToken::Day);
}
Token::DayPadded => {
is_date = true;
tokens.push(TextToken::DayPadded);
}
Token::DayNameShort => {
is_date = true;
tokens.push(TextToken::DayNameShort);
}
Token::DayName => {
is_date = true;
tokens.push(TextToken::DayName);
}
Token::MonthNameShort => {
is_date = true;
tokens.push(TextToken::MonthNameShort);
}
Token::MonthName => {
is_date = true;
tokens.push(TextToken::MonthName);
}
Token::Month => {
is_date = true;
tokens.push(TextToken::Month);
}
Token::MonthPadded => {
is_date = true;
tokens.push(TextToken::MonthPadded);
}
Token::MonthLetter => {
is_date = true;
tokens.push(TextToken::MonthLetter);
}
Token::YearShort => {
is_date = true;
tokens.push(TextToken::YearShort);
}
Token::Year => {
is_date = true;
tokens.push(TextToken::Year);
}
Token::Scientific => {
if !is_scientific {
index = 0;
number = 'e';
}
is_scientific = true;
}
Token::ScientificMinus => {
is_scientific = true;
scientific_minus = true;
}
Token::Separator => {}
Token::Raw => {
tokens.push(TextToken::Raw);
}
Token::ILLEGAL => {
return ParsePart::Error(ErrorPart {});
}
Token::EOF => {}
}
last_token_is_digit = token_is_digit;
token = next_token;
}
if is_date {
if is_number {
return ParsePart::Error(ErrorPart {});
}
ParsePart::Date(DatePart { color, tokens })
} else {
ParsePart::Number(NumberPart {
color,
condition,
use_thousands,
percent,
comma,
tokens,
digit_count,
precision,
is_scientific,
scientific_minus,
exponent_digit_count,
})
}
}
}