Add 'base' command for setting output radix, closes #109

This commit is contained in:
PaddiM8 2023-01-24 19:11:35 +01:00
parent 85bd77f99f
commit b13c459aee
6 changed files with 40 additions and 12 deletions

View File

@ -15,10 +15,12 @@ Overview of features
Different number bases: Either with a format like 0b1101, 0o5.3, 0xff Different number bases: Either with a format like 0b1101, 0o5.3, 0xff
or a format like 1101_2. The latter does not support letters, as they or a format like 1101_2. The latter does not support letters, as they
would be interpreted as variables would be interpreted as variables. The "base" command can be used to
tell the REPL to also show output in another number base. For example,
"base 16" would make it show results in hexadecimal as well as decimal.
Root finding using Newton's method (eg. x^2 = 64). Note: estimation and Root finding using Newton's method (eg. x^2 = 64). Note: estimation and
limited to one root limited to one root.
Derivation (prime notation) and integration (eg. integral(a, b, x dx) Derivation (prime notation) and integration (eg. integral(a, b, x dx)
The value of an integral is estimated using Simpson's 3/8 rule, The value of an integral is estimated using Simpson's 3/8 rule,

View File

@ -68,7 +68,12 @@ fn default_action(context: &Context) {
repl::start(&mut parser_context, precision); repl::start(&mut parser_context, precision);
} else { } else {
// Direct output // Direct output
output::eval(&mut parser_context, &context.args.join(" "), precision); output::eval(
&mut parser_context,
&context.args.join(" "),
precision,
10u8,
);
} }
} }

View File

@ -3,9 +3,11 @@ use kalk::parser;
pub(crate) const DEFAULT_PRECISION: u32 = 63; pub(crate) const DEFAULT_PRECISION: u32 = 63;
pub fn eval(parser: &mut parser::Context, input: &str, precision: u32) { pub fn eval(parser: &mut parser::Context, input: &str, precision: u32, base: u8) {
match parser::eval(parser, input, precision) { match parser::eval(parser, input, precision) {
Ok(Some(result)) => { Ok(Some(mut result)) => {
result.set_radix(base);
if precision == DEFAULT_PRECISION { if precision == DEFAULT_PRECISION {
println!("{}", result.to_string_pretty()) println!("{}", result.to_string_pretty())
} else { } else {
@ -19,5 +21,5 @@ pub fn eval(parser: &mut parser::Context, input: &str, precision: u32) {
pub fn print_err(msg: &str) { pub fn print_err(msg: &str) {
Red.paint(msg).to_string(); Red.paint(msg).to_string();
println!("{}", msg); eprintln!("{}", msg);
} }

View File

@ -20,6 +20,10 @@ use std::collections::HashMap;
use std::fs; use std::fs;
use std::process; use std::process;
struct Context {
base: u8,
}
pub fn start(parser: &mut parser::Context, precision: u32) { pub fn start(parser: &mut parser::Context, precision: u32) {
let mut editor = Editor::<RLHelper>::new(); let mut editor = Editor::<RLHelper>::new();
editor.set_helper(Some(RLHelper { editor.set_helper(Some(RLHelper {
@ -50,6 +54,7 @@ pub fn start(parser: &mut parser::Context, precision: u32) {
); );
} }
let mut repl = Context { base: 10u8 };
loop { loop {
let prompt = if cfg!(windows) { let prompt = if cfg!(windows) {
String::from(">> ") String::from(">> ")
@ -61,7 +66,7 @@ pub fn start(parser: &mut parser::Context, precision: u32) {
match readline { match readline {
Ok(input) => { Ok(input) => {
editor.add_history_entry(input.as_str()); editor.add_history_entry(input.as_str());
eval_repl(parser, &input, precision); eval_repl(&mut repl, parser, &input, precision);
} }
Err(ReadlineError::Interrupted) => break, Err(ReadlineError::Interrupted) => break,
_ => break, _ => break,
@ -73,22 +78,35 @@ pub fn start(parser: &mut parser::Context, precision: u32) {
} }
} }
fn eval_repl(parser: &mut parser::Context, input: &str, precision: u32) { fn eval_repl(repl: &mut self::Context, parser: &mut parser::Context, input: &str, precision: u32) {
if let Some(file_name) = input.strip_prefix("load ") { if let Some(file_name) = input.strip_prefix("load ") {
if let Some(file_path) = crate::get_input_file_by_name(file_name) { if let Some(file_path) = crate::get_input_file_by_name(file_name) {
crate::load_input_file(&file_path, precision, parser); crate::load_input_file(&file_path, precision, parser);
} else { } else {
println!("Unable to find '{}'", file_name); eprintln!("Unable to find '{}'", file_name);
} }
return; return;
} }
if let Some(base_str) = input.strip_prefix("base ") {
if !base_str.is_empty() && base_str.chars().next().unwrap().is_ascii_digit() {
if let Ok(base) = base_str.parse::<u8>() {
repl.base = base;
} else {
eprintln!("Invalid number base");
}
return;
}
}
match input { match input {
"" => eprint!(""), "" => eprint!(""),
"clear" => print!("\x1B[2J"), "clear" => print!("\x1B[2J"),
"exit" => process::exit(0), "exit" => process::exit(0),
"help" => print_cli_help(), "help" => print_cli_help(),
_ => output::eval(parser, input, precision), _ => output::eval(parser, input, precision, repl.base),
} }
} }

View File

@ -65,7 +65,8 @@ impl CalculationResult {
self.value.imaginary_to_f64() self.value.imaginary_to_f64()
} }
pub(crate) fn set_radix(&mut self, radix: u8) { #[wasm_bindgen(js_name = setRadix)]
pub fn set_radix(&mut self, radix: u8) {
self.radix = radix; self.radix = radix;
} }

View File

@ -288,7 +288,7 @@ impl KalkValue {
} }
} }
pub(crate) fn to_string_pretty_radix(&self, radix: u8) -> String { pub fn to_string_pretty_radix(&self, radix: u8) -> String {
let (real, imaginary, unit) = match self { let (real, imaginary, unit) = match self {
KalkValue::Number(real, imaginary, unit) => (real, imaginary, unit), KalkValue::Number(real, imaginary, unit) => (real, imaginary, unit),
_ => return self.to_string(), _ => return self.to_string(),