mirror of
https://github.com/PaddiM8/kalker.git
synced 2024-12-13 01:50:41 +01:00
Print result in another base when appropriate
This commit is contained in:
parent
f1881ac9b6
commit
95a5718e38
@ -13,6 +13,7 @@ pub mod regular;
|
|||||||
pub use regular::*;
|
pub use regular::*;
|
||||||
|
|
||||||
use crate::ast::Expr;
|
use crate::ast::Expr;
|
||||||
|
use crate::radix;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
@ -76,7 +77,7 @@ impl ScientificNotation {
|
|||||||
let mut digits_and_mul = if self.digits == "1" {
|
let mut digits_and_mul = if self.digits == "1" {
|
||||||
String::new()
|
String::new()
|
||||||
} else {
|
} else {
|
||||||
format!("{}*", &self.digits)
|
format!("{}×", &self.digits)
|
||||||
};
|
};
|
||||||
|
|
||||||
if self.digits.len() > 1 {
|
if self.digits.len() > 1 {
|
||||||
@ -107,8 +108,8 @@ impl KalkNum {
|
|||||||
complex_number_type: ComplexNumberType,
|
complex_number_type: ComplexNumberType,
|
||||||
) -> ScientificNotation {
|
) -> ScientificNotation {
|
||||||
let value_string = match complex_number_type {
|
let value_string = match complex_number_type {
|
||||||
ComplexNumberType::Real => self.to_string_real(),
|
ComplexNumberType::Real => self.to_string_real(10),
|
||||||
ComplexNumberType::Imaginary => self.to_string_imaginary(false),
|
ComplexNumberType::Imaginary => self.to_string_imaginary(10, false),
|
||||||
}
|
}
|
||||||
.trim_start_matches("-")
|
.trim_start_matches("-")
|
||||||
.to_string();
|
.to_string();
|
||||||
@ -170,12 +171,12 @@ impl KalkNum {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_string_real(&self) -> String {
|
pub fn to_string_real(&self, radix: u8) -> String {
|
||||||
format_number(self.to_f64())
|
radix::to_radix_pretty(self.to_f64(), radix)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_string_imaginary(&self, include_i: bool) -> String {
|
pub fn to_string_imaginary(&self, radix: u8, include_i: bool) -> String {
|
||||||
let value = format_number(self.imaginary_to_f64());
|
let value = radix::to_radix_pretty(self.imaginary_to_f64(), radix);
|
||||||
if include_i && value == "1" {
|
if include_i && value == "1" {
|
||||||
String::from("i")
|
String::from("i")
|
||||||
} else if include_i && value == "-1" {
|
} else if include_i && value == "-1" {
|
||||||
@ -187,7 +188,7 @@ impl KalkNum {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_string_pretty(&self) -> String {
|
fn to_string_pretty_radix(&self, radix: u8) -> String {
|
||||||
if let Some(boolean_value) = self.boolean_value {
|
if let Some(boolean_value) = self.boolean_value {
|
||||||
return boolean_value.to_string();
|
return boolean_value.to_string();
|
||||||
}
|
}
|
||||||
@ -205,12 +206,16 @@ impl KalkNum {
|
|||||||
let sci_notation_real = self.to_scientific_notation(ComplexNumberType::Real);
|
let sci_notation_real = self.to_scientific_notation(ComplexNumberType::Real);
|
||||||
let mut adjusted_num = self.clone();
|
let mut adjusted_num = self.clone();
|
||||||
let result_str = if (-6..8).contains(&sci_notation_real.exponent) || self.value == 0f64 {
|
let result_str = if (-6..8).contains(&sci_notation_real.exponent) || self.value == 0f64 {
|
||||||
self.to_string_real()
|
self.to_string_real(radix)
|
||||||
} else if sci_notation_real.exponent <= -14 {
|
} else if sci_notation_real.exponent <= -14 {
|
||||||
adjusted_num.value = KalkNum::from(0f64).value;
|
adjusted_num.value = KalkNum::from(0f64).value;
|
||||||
String::from("0")
|
String::from("0")
|
||||||
} else {
|
} else {
|
||||||
|
if radix == 10 {
|
||||||
sci_notation_real.to_string().trim().to_string()
|
sci_notation_real.to_string().trim().to_string()
|
||||||
|
} else {
|
||||||
|
return String::new();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let sci_notation_imaginary = self.to_scientific_notation(ComplexNumberType::Imaginary);
|
let sci_notation_imaginary = self.to_scientific_notation(ComplexNumberType::Imaginary);
|
||||||
@ -218,12 +223,16 @@ impl KalkNum {
|
|||||||
|| self.imaginary_value == 0f64
|
|| self.imaginary_value == 0f64
|
||||||
|| self.imaginary_value == 1f64
|
|| self.imaginary_value == 1f64
|
||||||
{
|
{
|
||||||
self.to_string_imaginary(true)
|
self.to_string_imaginary(radix, true)
|
||||||
} else if sci_notation_imaginary.exponent <= -14 {
|
} else if sci_notation_imaginary.exponent <= -14 {
|
||||||
adjusted_num.imaginary_value = KalkNum::from(0f64).value;
|
adjusted_num.imaginary_value = KalkNum::from(0f64).value;
|
||||||
String::from("0")
|
String::from("0")
|
||||||
} else {
|
} else {
|
||||||
|
if radix == 10 {
|
||||||
format!("{}", sci_notation_imaginary.to_string().trim())
|
format!("{}", sci_notation_imaginary.to_string().trim())
|
||||||
|
} else {
|
||||||
|
return String::new();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut output = result_str;
|
let mut output = result_str;
|
||||||
@ -256,7 +265,7 @@ impl KalkNum {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(estimate) = adjusted_num.estimate() {
|
if let Some(estimate) = adjusted_num.estimate() {
|
||||||
if estimate != output {
|
if estimate != output && radix == 10 {
|
||||||
output.push_str(&format!(" ≈ {}", estimate));
|
output.push_str(&format!(" ≈ {}", estimate));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -264,6 +273,17 @@ impl KalkNum {
|
|||||||
output
|
output
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn to_string_pretty(&self) -> String {
|
||||||
|
if let Some(other_radix) = self.other_radix {
|
||||||
|
let with_other_radix = self.to_string_pretty_radix(other_radix);
|
||||||
|
if with_other_radix != "" {
|
||||||
|
return format!("{}\n{}", self.to_string_pretty_radix(10), with_other_radix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.to_string_pretty_radix(10)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_too_big(&self) -> bool {
|
pub fn is_too_big(&self) -> bool {
|
||||||
self.value.is_infinite()
|
self.value.is_infinite()
|
||||||
}
|
}
|
||||||
@ -474,13 +494,13 @@ impl KalkNum {
|
|||||||
if let Some(value) = rounded_real {
|
if let Some(value) = rounded_real {
|
||||||
output.push_str(&value);
|
output.push_str(&value);
|
||||||
} else if self.has_real() {
|
} else if self.has_real() {
|
||||||
output.push_str(&self.to_string_real());
|
output.push_str(&self.to_string_real(10));
|
||||||
}
|
}
|
||||||
|
|
||||||
let imaginary_value = if let Some(value) = rounded_imaginary {
|
let imaginary_value = if let Some(value) = rounded_imaginary {
|
||||||
Some(value)
|
Some(value)
|
||||||
} else if self.has_imaginary() {
|
} else if self.has_imaginary() {
|
||||||
Some(self.to_string_imaginary(false))
|
Some(self.to_string_imaginary(10, false))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
@ -520,7 +540,9 @@ impl KalkNum {
|
|||||||
fn estimate_one_value(&self, complex_number_type: ComplexNumberType) -> Option<String> {
|
fn estimate_one_value(&self, complex_number_type: ComplexNumberType) -> Option<String> {
|
||||||
let (value, value_string) = match complex_number_type {
|
let (value, value_string) = match complex_number_type {
|
||||||
ComplexNumberType::Real => (&self.value, self.to_string()),
|
ComplexNumberType::Real => (&self.value, self.to_string()),
|
||||||
ComplexNumberType::Imaginary => (&self.imaginary_value, self.to_string_imaginary(true)),
|
ComplexNumberType::Imaginary => {
|
||||||
|
(&self.imaginary_value, self.to_string_imaginary(10, true))
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let fract = value.clone().fract().abs();
|
let fract = value.clone().fract().abs();
|
||||||
@ -679,7 +701,7 @@ impl KalkNum {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format_number(input: f64) -> String {
|
pub fn format_number(input: f64) -> String {
|
||||||
let rounded = format!("{:.1$}", input, 10);
|
let rounded = format!("{:.1$}", input, 10);
|
||||||
if rounded.contains(".") {
|
if rounded.contains(".") {
|
||||||
rounded
|
rounded
|
||||||
|
@ -8,6 +8,7 @@ pub struct KalkNum {
|
|||||||
pub(crate) unit: String,
|
pub(crate) unit: String,
|
||||||
pub(crate) imaginary_value: f64,
|
pub(crate) imaginary_value: f64,
|
||||||
pub(crate) boolean_value: Option<bool>,
|
pub(crate) boolean_value: Option<bool>,
|
||||||
|
pub(crate) other_radix: Option<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
@ -18,6 +19,7 @@ impl KalkNum {
|
|||||||
unit: unit.to_string(),
|
unit: unit.to_string(),
|
||||||
imaginary_value: 0f64,
|
imaginary_value: 0f64,
|
||||||
boolean_value: None,
|
boolean_value: None,
|
||||||
|
other_radix: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,6 +33,7 @@ impl KalkNum {
|
|||||||
imaginary_value
|
imaginary_value
|
||||||
},
|
},
|
||||||
boolean_value: None,
|
boolean_value: None,
|
||||||
|
other_radix: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,6 +43,7 @@ impl KalkNum {
|
|||||||
unit: String::new(),
|
unit: String::new(),
|
||||||
imaginary_value: value,
|
imaginary_value: value,
|
||||||
boolean_value: None,
|
boolean_value: None,
|
||||||
|
other_radix: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,6 +53,7 @@ impl KalkNum {
|
|||||||
unit: String::new(),
|
unit: String::new(),
|
||||||
imaginary_value: 0f64,
|
imaginary_value: 0f64,
|
||||||
boolean_value: Some(value),
|
boolean_value: Some(value),
|
||||||
|
other_radix: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ pub struct KalkNum {
|
|||||||
pub(crate) unit: String,
|
pub(crate) unit: String,
|
||||||
pub(crate) imaginary_value: Float,
|
pub(crate) imaginary_value: Float,
|
||||||
pub(crate) boolean_value: Option<bool>,
|
pub(crate) boolean_value: Option<bool>,
|
||||||
|
pub(crate) other_radix: Option<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl KalkNum {
|
impl KalkNum {
|
||||||
@ -22,6 +23,7 @@ impl KalkNum {
|
|||||||
unit: unit.to_string(),
|
unit: unit.to_string(),
|
||||||
imaginary_value: Float::with_val(precision, 0),
|
imaginary_value: Float::with_val(precision, 0),
|
||||||
boolean_value: None,
|
boolean_value: None,
|
||||||
|
other_radix: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,6 +37,7 @@ impl KalkNum {
|
|||||||
imaginary_value
|
imaginary_value
|
||||||
},
|
},
|
||||||
boolean_value: None,
|
boolean_value: None,
|
||||||
|
other_radix: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,6 +47,7 @@ impl KalkNum {
|
|||||||
unit: String::new(),
|
unit: String::new(),
|
||||||
imaginary_value: value,
|
imaginary_value: value,
|
||||||
boolean_value: None,
|
boolean_value: None,
|
||||||
|
other_radix: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,6 +57,7 @@ impl KalkNum {
|
|||||||
unit: String::new(),
|
unit: String::new(),
|
||||||
imaginary_value: Float::with_val(63, 0),
|
imaginary_value: Float::with_val(63, 0),
|
||||||
boolean_value: Some(value),
|
boolean_value: Some(value),
|
||||||
|
other_radix: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,18 +56,23 @@ pub struct Token {
|
|||||||
pub struct Lexer<'a> {
|
pub struct Lexer<'a> {
|
||||||
chars: Peekable<Chars<'a>>,
|
chars: Peekable<Chars<'a>>,
|
||||||
index: usize,
|
index: usize,
|
||||||
|
other_radix: Option<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Lexer<'a> {
|
impl<'a> Lexer<'a> {
|
||||||
pub fn lex(source: &str) -> Vec<Token> {
|
pub fn new(source: &'a str) -> Self {
|
||||||
let mut lexer = Lexer {
|
Lexer {
|
||||||
chars: source.chars().peekable(),
|
chars: source.chars().peekable(),
|
||||||
index: 0,
|
index: 0,
|
||||||
};
|
other_radix: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lex(&mut self) -> Vec<Token> {
|
||||||
let mut tokens = Vec::new();
|
let mut tokens = Vec::new();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let next = lexer.next();
|
let next = self.next();
|
||||||
|
|
||||||
if let TokenKind::EOF = next.kind {
|
if let TokenKind::EOF = next.kind {
|
||||||
tokens.push(next);
|
tokens.push(next);
|
||||||
@ -80,6 +85,10 @@ impl<'a> Lexer<'a> {
|
|||||||
tokens
|
tokens
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_other_radix(&self) -> Option<u8> {
|
||||||
|
self.other_radix
|
||||||
|
}
|
||||||
|
|
||||||
fn next(&mut self) -> Token {
|
fn next(&mut self) -> Token {
|
||||||
let eof = build(TokenKind::EOF, "", (self.index, self.index));
|
let eof = build(TokenKind::EOF, "", (self.index, self.index));
|
||||||
let mut c = if let Some(c) = self.peek() {
|
let mut c = if let Some(c) = self.peek() {
|
||||||
@ -179,7 +188,7 @@ impl<'a> Lexer<'a> {
|
|||||||
let mut end = start;
|
let mut end = start;
|
||||||
let mut value = String::new();
|
let mut value = String::new();
|
||||||
let mut leading_zero = self.peek().unwrap_or(&'\0') == &'0';
|
let mut leading_zero = self.peek().unwrap_or(&'\0') == &'0';
|
||||||
let mut base = 10u32;
|
let mut base = 10u8;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let c = if let Some(c) = self.peek() {
|
let c = if let Some(c) = self.peek() {
|
||||||
@ -210,7 +219,7 @@ impl<'a> Lexer<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !c.is_digit(base) && c != '.' && c != '_' && !c.is_whitespace()
|
if !c.is_digit(base as u32) && c != '.' && c != '_' && !c.is_whitespace()
|
||||||
|| c == '\n'
|
|| c == '\n'
|
||||||
|| c == '\r'
|
|| c == '\r'
|
||||||
{
|
{
|
||||||
@ -231,12 +240,21 @@ impl<'a> Lexer<'a> {
|
|||||||
|
|
||||||
if base_str != "" {
|
if base_str != "" {
|
||||||
base = crate::text_utils::subscript_to_digits(base_str.chars())
|
base = crate::text_utils::subscript_to_digits(base_str.chars())
|
||||||
.parse::<u32>()
|
.parse::<u8>()
|
||||||
.unwrap_or(10);
|
.unwrap_or(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
if base != 10 {
|
if base != 10 {
|
||||||
value.push_str(&format!("_{}", base));
|
value.push_str(&format!("_{}", base));
|
||||||
|
if let Some(other_radix) = self.other_radix {
|
||||||
|
// Don't bother keeping track of radixes
|
||||||
|
// if several different ones are used
|
||||||
|
if other_radix != base {
|
||||||
|
self.other_radix = None;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.other_radix = Some(base);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
build(TokenKind::Literal, &value, (start, end))
|
build(TokenKind::Literal, &value, (start, end))
|
||||||
@ -358,7 +376,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn test_token_kinds() {
|
fn test_token_kinds() {
|
||||||
let tokens = Lexer::lex("+-*/%^()|=!,");
|
let tokens = Lexer::new("+-*/%^()|=!,").lex();
|
||||||
let expected = vec![
|
let expected = vec![
|
||||||
TokenKind::Plus,
|
TokenKind::Plus,
|
||||||
TokenKind::Minus,
|
TokenKind::Minus,
|
||||||
@ -381,7 +399,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn test_brackets() {
|
fn test_brackets() {
|
||||||
let tokens = Lexer::lex("[1 < 2]");
|
let tokens = Lexer::new("[1 < 2]").lex();
|
||||||
let expected = vec![
|
let expected = vec![
|
||||||
TokenKind::OpenBracket,
|
TokenKind::OpenBracket,
|
||||||
TokenKind::Literal,
|
TokenKind::Literal,
|
||||||
@ -401,7 +419,7 @@ mod tests {
|
|||||||
let test_cases = vec![" ", " ", "test ", " test "];
|
let test_cases = vec![" ", " ", "test ", " test "];
|
||||||
|
|
||||||
for input in test_cases {
|
for input in test_cases {
|
||||||
let tokens = Lexer::lex(input);
|
let tokens = Lexer::new(input).lex();
|
||||||
|
|
||||||
if regex::Regex::new(r"^\s*$").unwrap().is_match(input) {
|
if regex::Regex::new(r"^\s*$").unwrap().is_match(input) {
|
||||||
let expected = vec![TokenKind::EOF];
|
let expected = vec![TokenKind::EOF];
|
||||||
@ -417,7 +435,7 @@ mod tests {
|
|||||||
#[test_case("24")]
|
#[test_case("24")]
|
||||||
#[test_case("56.4")]
|
#[test_case("56.4")]
|
||||||
fn test_number_literal(input: &str) {
|
fn test_number_literal(input: &str) {
|
||||||
let tokens = Lexer::lex(input);
|
let tokens = Lexer::new(input).lex();
|
||||||
let expected = vec![TokenKind::Literal, TokenKind::EOF];
|
let expected = vec![TokenKind::Literal, TokenKind::EOF];
|
||||||
|
|
||||||
assert_eq!(&tokens[0].value, input);
|
assert_eq!(&tokens[0].value, input);
|
||||||
@ -427,7 +445,7 @@ mod tests {
|
|||||||
#[test_case("x")]
|
#[test_case("x")]
|
||||||
#[test_case("xy")]
|
#[test_case("xy")]
|
||||||
fn test_identifier(input: &str) {
|
fn test_identifier(input: &str) {
|
||||||
let tokens = Lexer::lex(input);
|
let tokens = Lexer::new(input).lex();
|
||||||
let expected = vec![TokenKind::Identifier, TokenKind::EOF];
|
let expected = vec![TokenKind::Identifier, TokenKind::EOF];
|
||||||
|
|
||||||
assert_eq!(&tokens[0].value, input);
|
assert_eq!(&tokens[0].value, input);
|
||||||
@ -436,7 +454,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_function_call() {
|
fn test_function_call() {
|
||||||
let tokens = Lexer::lex("f(x)");
|
let tokens = Lexer::new("f(x)").lex();
|
||||||
let expected = vec![
|
let expected = vec![
|
||||||
TokenKind::Identifier,
|
TokenKind::Identifier,
|
||||||
TokenKind::OpenParenthesis,
|
TokenKind::OpenParenthesis,
|
||||||
|
@ -33,6 +33,7 @@ pub struct Context {
|
|||||||
is_in_integral: bool,
|
is_in_integral: bool,
|
||||||
current_function: Option<String>,
|
current_function: Option<String>,
|
||||||
current_function_parameters: Option<Vec<String>>,
|
current_function_parameters: Option<Vec<String>>,
|
||||||
|
other_radix: Option<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
@ -53,6 +54,7 @@ impl Context {
|
|||||||
is_in_integral: false,
|
is_in_integral: false,
|
||||||
current_function: None,
|
current_function: None,
|
||||||
current_function_parameters: None,
|
current_function_parameters: None,
|
||||||
|
other_radix: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
parse(&mut context, crate::prelude::INIT).unwrap();
|
parse(&mut context, crate::prelude::INIT).unwrap();
|
||||||
@ -176,17 +178,25 @@ pub fn eval(
|
|||||||
None
|
None
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
interpreter.interpret(statements)
|
let result = interpreter.interpret(statements);
|
||||||
|
if let Ok(Some(mut num)) = result {
|
||||||
|
num.other_radix = context.other_radix;
|
||||||
|
Ok(Some(num))
|
||||||
|
} else {
|
||||||
|
result
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse expressions/declarations and return a syntax tree.
|
/// Parse expressions/declarations and return a syntax tree.
|
||||||
///
|
///
|
||||||
/// `None` will be returned if the last statement is a declaration.
|
/// `None` will be returned if the last statement is a declaration.
|
||||||
pub fn parse(context: &mut Context, input: &str) -> Result<Vec<Stmt>, CalcError> {
|
pub fn parse(context: &mut Context, input: &str) -> Result<Vec<Stmt>, CalcError> {
|
||||||
context.tokens = Lexer::lex(input);
|
let mut lexer = Lexer::new(input);
|
||||||
|
context.tokens = lexer.lex();
|
||||||
context.pos = 0;
|
context.pos = 0;
|
||||||
context.parsing_unit_decl = false;
|
context.parsing_unit_decl = false;
|
||||||
context.unit_decl_base_unit = None;
|
context.unit_decl_base_unit = None;
|
||||||
|
context.other_radix = lexer.get_other_radix();
|
||||||
|
|
||||||
let mut statements: Vec<Stmt> = Vec::new();
|
let mut statements: Vec<Stmt> = Vec::new();
|
||||||
while !is_at_end(context) {
|
while !is_at_end(context) {
|
||||||
@ -856,7 +866,7 @@ fn is_at_end(context: &Context) -> bool {
|
|||||||
|
|
||||||
fn string_to_num(value: &str) -> Result<f64, CalcError> {
|
fn string_to_num(value: &str) -> Result<f64, CalcError> {
|
||||||
let base = get_base(value)?;
|
let base = get_base(value)?;
|
||||||
if let Some(result) = crate::radix::parse_float_radix(value.replace(" ", ""), base) {
|
if let Some(result) = crate::radix::parse_float_radix(&value.replace(" ", ""), base) {
|
||||||
Ok(result)
|
Ok(result)
|
||||||
} else {
|
} else {
|
||||||
Err(CalcError::InvalidNumberLiteral(value.into()))
|
Err(CalcError::InvalidNumberLiteral(value.into()))
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
pub fn parse_float_radix(value: String, radix: u8) -> Option<f64> {
|
pub fn parse_float_radix(value: &str, radix: u8) -> Option<f64> {
|
||||||
if radix == 10 {
|
if radix == 10 {
|
||||||
return if let Ok(result) = value.parse::<f64>() {
|
return if let Ok(result) = value.parse::<f64>() {
|
||||||
Some(result)
|
Some(result)
|
||||||
@ -9,7 +9,7 @@ pub fn parse_float_radix(value: String, radix: u8) -> Option<f64> {
|
|||||||
|
|
||||||
let mut sum = 0f64;
|
let mut sum = 0f64;
|
||||||
let length = value.find('_').unwrap_or(value.len());
|
let length = value.find('_').unwrap_or(value.len());
|
||||||
let mut i = (value.find('.').unwrap_or(length) - 1) as i32;
|
let mut i = (value.find('.').unwrap_or(length) as i32) - 1;
|
||||||
for c in value.chars() {
|
for c in value.chars() {
|
||||||
if c == '_' {
|
if c == '_' {
|
||||||
break;
|
break;
|
||||||
@ -26,3 +26,46 @@ pub fn parse_float_radix(value: String, radix: u8) -> Option<f64> {
|
|||||||
|
|
||||||
return Some(sum);
|
return Some(sum);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DIGITS: &'static str = "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||||
|
pub fn int_to_radix(value: i64, radix: u8) -> String {
|
||||||
|
let mut num = value.abs();
|
||||||
|
let mut result_str = String::new();
|
||||||
|
while num > 0 {
|
||||||
|
let digit_index = (num % radix as i64) as usize;
|
||||||
|
result_str.insert(0, DIGITS.as_bytes()[digit_index] as char);
|
||||||
|
num /= radix as i64;
|
||||||
|
}
|
||||||
|
|
||||||
|
if result_str == "" {
|
||||||
|
return String::from("0");
|
||||||
|
}
|
||||||
|
|
||||||
|
let sign = if value.is_positive() { "" } else { "-" };
|
||||||
|
format!("{}{}", sign, result_str)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn float_to_radix(value: f64, radix: u8) -> String {
|
||||||
|
let mut result = int_to_radix(value.floor() as i64, radix);
|
||||||
|
let fract = value.fract();
|
||||||
|
if fract != 0f64 {
|
||||||
|
result.push('.');
|
||||||
|
let precision = 10;
|
||||||
|
let fract_digits = (fract * (radix as i64).pow(precision) as f64) as i64;
|
||||||
|
result.push_str(&int_to_radix(fract_digits, radix).trim_end_matches('0'))
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_radix_pretty(value: f64, radix: u8) -> String {
|
||||||
|
if radix == 10 {
|
||||||
|
crate::kalk_num::format_number(value)
|
||||||
|
} else {
|
||||||
|
format!(
|
||||||
|
"{}{}",
|
||||||
|
float_to_radix(value, radix),
|
||||||
|
crate::text_utils::digits_to_subscript(radix.to_string().chars())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user