Replaced f64 with rug::Float.

This commit is contained in:
PaddiM8 2020-06-04 14:46:45 +02:00
parent 0d2d6df85b
commit 93321c3dac
7 changed files with 229 additions and 122 deletions

70
Cargo.lock generated
View File

@ -27,12 +27,29 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
[[package]]
name = "az"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e9bcd47d94aa4eb8c076b50fc61a75020789394ffb9bd74a180b3379130f6569"
[[package]]
name = "base64"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7"
[[package]]
name = "bigdecimal"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1374191e2dd25f9ae02e3aa95041ed5d747fc77b3c102b49fe2dd9a8117a6244"
dependencies = [
"num-bigint",
"num-integer",
"num-traits",
]
[[package]]
name = "bitflags"
version = "1.2.1"
@ -112,6 +129,16 @@ dependencies = [
"wasi",
]
[[package]]
name = "gmp-mpfr-sys"
version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c04ccc68f16a0be7164b9de26e65aab8507596cc1969cec2e32fb1692b53b1b"
dependencies = [
"libc",
"winapi",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
@ -123,7 +150,9 @@ name = "lek"
version = "0.1.0"
dependencies = [
"ansi_term",
"bigdecimal",
"phf",
"rug",
"rustyline",
]
@ -161,6 +190,36 @@ dependencies = [
"void",
]
[[package]]
name = "num-bigint"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-integer"
version = "0.1.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba"
dependencies = [
"autocfg",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096"
dependencies = [
"autocfg",
]
[[package]]
name = "phf"
version = "0.8.0"
@ -303,6 +362,17 @@ dependencies = [
"rust-argon2",
]
[[package]]
name = "rug"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6cfccfa888f22369385e0fc5f37a37fca05782fc653df5fe7de0934cbe66632"
dependencies = [
"az",
"gmp-mpfr-sys",
"libc",
]
[[package]]
name = "rust-argon2"
version = "0.7.0"

View File

@ -14,3 +14,5 @@ panic = "abort"
rustyline = "6.1.2"
phf = { version = "0.8", features = ["macros"] }
ansi_term = "0.12"
bigdecimal = "0.1.2"
rug = "1.9.0"

View File

@ -2,21 +2,25 @@ use crate::ast::{compare_enums, Expr, Stmt, Unit};
use crate::lexer::TokenKind;
use crate::prelude;
use crate::symbol_table::SymbolTable;
use rug::ops::Pow;
use rug::Float;
pub struct Context<'a> {
symbol_table: &'a mut SymbolTable,
angle_unit: Unit,
precision: u32,
}
impl<'a> Context<'a> {
pub fn new(angle_unit: Unit, symbol_table: &'a mut SymbolTable) -> Self {
pub fn new(symbol_table: &'a mut SymbolTable, angle_unit: Unit, precision: u32) -> Self {
Context {
angle_unit: angle_unit.clone(),
symbol_table,
precision,
}
}
pub fn interpret(&mut self, statements: Vec<Stmt>) -> Result<Option<f64>, String> {
pub fn interpret(&mut self, statements: Vec<Stmt>) -> Result<Option<Float>, String> {
for (i, stmt) in statements.iter().enumerate() {
let value = eval_stmt(self, stmt);
@ -31,7 +35,7 @@ impl<'a> Context<'a> {
}
}
fn eval_stmt(context: &mut Context, stmt: &Stmt) -> Result<f64, String> {
fn eval_stmt(context: &mut Context, stmt: &Stmt) -> Result<Float, String> {
match stmt {
Stmt::VarDecl(identifier, _) => eval_var_decl_stmt(context, stmt, identifier),
Stmt::FnDecl(_, _, _) => eval_fn_decl_stmt(context),
@ -39,20 +43,24 @@ fn eval_stmt(context: &mut Context, stmt: &Stmt) -> Result<f64, String> {
}
}
fn eval_var_decl_stmt(context: &mut Context, stmt: &Stmt, identifier: &str) -> Result<f64, String> {
fn eval_var_decl_stmt(
context: &mut Context,
stmt: &Stmt,
identifier: &str,
) -> Result<Float, String> {
context.symbol_table.insert(&identifier, stmt.clone());
Ok(0f64)
Ok(Float::with_val(context.precision, 1))
}
fn eval_fn_decl_stmt(_: &mut Context) -> Result<f64, String> {
Ok(0f64) // Nothing needs to happen here, since the parser will already have added the FnDecl's to the symbol table.
fn eval_fn_decl_stmt(context: &mut Context) -> Result<Float, String> {
Ok(Float::with_val(context.precision, 1)) // Nothing needs to happen here, since the parser will already have added the FnDecl's to the symbol table.
}
fn eval_expr_stmt(context: &mut Context, expr: &Expr) -> Result<f64, String> {
fn eval_expr_stmt(context: &mut Context, expr: &Expr) -> Result<Float, String> {
eval_expr(context, &expr)
}
fn eval_expr(context: &mut Context, expr: &Expr) -> Result<f64, String> {
fn eval_expr(context: &mut Context, expr: &Expr) -> Result<Float, String> {
match expr {
Expr::Binary(left, op, right) => eval_binary_expr(context, &left, op, &right),
Expr::Unary(op, expr) => eval_unary_expr(context, op, expr),
@ -71,7 +79,7 @@ fn eval_binary_expr(
left: &Expr,
op: &TokenKind,
right: &Expr,
) -> Result<f64, String> {
) -> Result<Float, String> {
let left = eval_expr(context, &left)?;
let right = eval_expr(context, &right)?;
@ -80,22 +88,25 @@ fn eval_binary_expr(
TokenKind::Minus => left - right,
TokenKind::Star => left * right,
TokenKind::Slash => left / right,
TokenKind::Power => left.powf(right),
_ => 0f64,
TokenKind::Power => left.pow(right),
_ => Float::with_val(1, 1),
})
}
fn eval_unary_expr(context: &mut Context, op: &TokenKind, expr: &Expr) -> Result<f64, String> {
fn eval_unary_expr(context: &mut Context, op: &TokenKind, expr: &Expr) -> Result<Float, String> {
let expr_value = eval_expr(context, &expr)?.clone();
match op {
TokenKind::Minus => Ok(-expr_value),
TokenKind::Exclamation => Ok(prelude::special_funcs::factorial(expr_value as i32) as f64),
TokenKind::Exclamation => Ok(Float::with_val(
context.precision,
prelude::special_funcs::factorial(expr_value),
)),
_ => Err(String::from("Invalid operator for unary expression.")),
}
}
fn eval_unit_expr(context: &mut Context, expr: &Expr, kind: &TokenKind) -> Result<f64, String> {
fn eval_unit_expr(context: &mut Context, expr: &Expr, kind: &TokenKind) -> Result<Float, String> {
let x = eval_expr(context, &expr);
let unit = kind.to_unit()?;
@ -108,13 +119,15 @@ fn eval_unit_expr(context: &mut Context, expr: &Expr, kind: &TokenKind) -> Resul
}
}
match unit {
/*match unit {
Unit::Degrees => Ok(x?.to_radians()),
Unit::Radians => Ok(x?.to_degrees()),
}
}*/
x
}
fn eval_var_expr(context: &mut Context, identifier: &str) -> Result<f64, String> {
fn eval_var_expr(context: &mut Context, identifier: &str) -> Result<Float, String> {
// If there is a constant with this name, return a literal expression with its value
if let Some(value) = prelude::CONSTANTS.get(identifier) {
return eval_expr(context, &Expr::Literal(value.to_string()));
@ -128,14 +141,14 @@ fn eval_var_expr(context: &mut Context, identifier: &str) -> Result<f64, String>
}
}
fn eval_literal_expr(_: &mut Context, value: &str) -> Result<f64, String> {
match value.parse() {
Ok(parsed_value) => Ok(parsed_value),
fn eval_literal_expr(context: &mut Context, value: &str) -> Result<Float, String> {
match Float::parse(value) {
Ok(parsed_value) => Ok(Float::with_val(context.precision, parsed_value)),
Err(_) => Err(format!("Invalid number literal: '{}'.", value)),
}
}
fn eval_group_expr(context: &mut Context, expr: &Expr) -> Result<f64, String> {
fn eval_group_expr(context: &mut Context, expr: &Expr) -> Result<Float, String> {
eval_expr(context, expr)
}
@ -143,7 +156,7 @@ fn eval_fn_call_expr(
context: &mut Context,
identifier: &str,
expressions: &Vec<Expr>,
) -> Result<f64, String> {
) -> Result<Float, String> {
// Prelude
let prelude_func = match expressions.len() {
1 => {
@ -164,7 +177,7 @@ fn eval_fn_call_expr(
// Special functions
match identifier {
"sum" => {
"sum" | "Σ" => {
// Make sure exactly 3 arguments were supplied.
if expressions.len() != 3 {
return Err(format!(
@ -173,9 +186,9 @@ fn eval_fn_call_expr(
));
}
let start = eval_expr(context, &expressions[0])? as i32;
let end = eval_expr(context, &expressions[1])? as i32;
let mut sum = 0f64;
let start = eval_expr(context, &expressions[0])?.to_f64() as i128;
let end = eval_expr(context, &expressions[1])?.to_f64() as i128;
let mut sum = Float::with_val(context.precision, 0);
for n in start..=end {
let n_expr = Expr::Literal(String::from(n.to_string()));

View File

@ -51,7 +51,7 @@ impl<'a> Lexer<'a> {
// If there isn't already an EOF token, add it.
if let TokenKind::EOF = tokens.last().unwrap().kind {
} else {
tokens.push(lexer.build(TokenKind::EOF, ""));
tokens.push(build(TokenKind::EOF, ""));
}
tokens
@ -64,7 +64,7 @@ impl<'a> Lexer<'a> {
self.advance();
if self.is_at_end() {
return self.build(TokenKind::EOF, "");
return build(TokenKind::EOF, "");
} else {
c = self.peek();
}
@ -73,47 +73,47 @@ impl<'a> Lexer<'a> {
let token = match c {
'+' => {
self.advance();
self.build(TokenKind::Plus, "")
build(TokenKind::Plus, "")
}
'-' => {
self.advance();
self.build(TokenKind::Minus, "")
build(TokenKind::Minus, "")
}
'*' => {
self.advance();
self.build(TokenKind::Star, "")
build(TokenKind::Star, "")
}
'/' => {
self.advance();
self.build(TokenKind::Slash, "")
build(TokenKind::Slash, "")
}
'^' => {
self.advance();
self.build(TokenKind::Power, "")
build(TokenKind::Power, "")
}
'(' => {
self.advance();
self.build(TokenKind::OpenParenthesis, "")
build(TokenKind::OpenParenthesis, "")
}
')' => {
self.advance();
self.build(TokenKind::ClosedParenthesis, "")
build(TokenKind::ClosedParenthesis, "")
}
'|' => {
self.advance();
self.build(TokenKind::Pipe, "")
build(TokenKind::Pipe, "")
}
'=' => {
self.advance();
self.build(TokenKind::Equals, "")
build(TokenKind::Equals, "")
}
'!' => {
self.advance();
self.build(TokenKind::Exclamation, "")
build(TokenKind::Exclamation, "")
}
',' => {
self.advance();
self.build(TokenKind::Comma, "")
build(TokenKind::Comma, "")
}
_ => {
if c.is_digit(10) {
@ -122,7 +122,7 @@ impl<'a> Lexer<'a> {
self.next_identifier()
} else {
self.advance();
self.build(TokenKind::Unknown, "")
build(TokenKind::Unknown, "")
}
}
};
@ -140,9 +140,9 @@ impl<'a> Lexer<'a> {
}
if let Ok(value) = str::from_utf8(&self.source[start..end]) {
self.build(TokenKind::Literal, value)
build(TokenKind::Literal, value)
} else {
self.build(TokenKind::Unknown, "")
build(TokenKind::Unknown, "")
}
}
@ -162,16 +162,9 @@ impl<'a> Lexer<'a> {
_ => TokenKind::Identifier,
};
self.build(kind, value)
build(kind, value)
} else {
self.build(TokenKind::Unknown, "")
}
}
fn build(&self, kind: TokenKind, value: &str) -> Token {
Token {
kind,
value: value.to_string(),
build(TokenKind::Unknown, "")
}
}
@ -188,6 +181,13 @@ impl<'a> Lexer<'a> {
}
}
fn is_valid_identifier(c: char) -> bool {
c.is_alphabetic() || c == '°' || c == '√' || c == '\'' || c == '¨'
fn build(kind: TokenKind, value: &str) -> Token {
Token {
kind,
value: value.to_string(),
}
}
fn is_valid_identifier(c: char) -> bool {
c.is_alphabetic() || c == '°' || c == '√' || c == '\'' || c == '¨' || c == 'Σ'
}

View File

@ -48,8 +48,14 @@ fn eval_repl(parser: &mut parser::Context, input: &str) {
}
fn eval(parser: &mut parser::Context, input: &str) {
match parser::parse(parser, input, get_angle_unit()) {
Ok(Some(result)) => println!("{}", result),
match parser::parse(parser, input, get_angle_unit(), 53) {
Ok(Some(result)) => {
if result.clone().fract() == 0 {
println!("{}", result.to_integer().unwrap());
} else {
println!("{}", result);
}
}
Ok(None) => print!(""),
Err(err) => println!("{}", Red.paint(err)),
}

View File

@ -4,6 +4,7 @@ use crate::{
lexer::{Lexer, Token, TokenKind},
symbol_table::SymbolTable,
};
use rug::Float;
pub struct Context {
//angle_unit: Unit,
@ -22,7 +23,12 @@ impl Context {
}
}
pub fn parse(context: &mut Context, input: &str, angle_unit: Unit) -> Result<Option<f64>, String> {
pub fn parse(
context: &mut Context,
input: &str,
angle_unit: Unit,
precision: u32,
) -> Result<Option<Float>, String> {
context.tokens = Lexer::lex(input);
context.pos = 0;
@ -30,7 +36,8 @@ pub fn parse(context: &mut Context, input: &str, angle_unit: Unit) -> Result<Opt
while !is_at_end(context) {
statements.push(parse_stmt(context)?);
}
let mut interpreter = interpreter::Context::new(angle_unit, &mut context.symbol_table);
let mut interpreter =
interpreter::Context::new(&mut context.symbol_table, angle_unit, precision);
interpreter.interpret(statements)
}

View File

@ -1,3 +1,4 @@
use rug::Float;
use FuncType::*;
pub const CONSTANTS: phf::Map<&'static str, &'static str> = phf::phf_map! {
@ -66,12 +67,12 @@ enum FuncType {
}
// Unary functions
pub struct UnaryFuncInfo(fn(f64) -> f64, FuncType);
pub struct UnaryFuncInfo(fn(Float) -> Float, FuncType);
pub struct BinaryFuncInfo(fn(f64, f64) -> f64, FuncType);
pub struct BinaryFuncInfo(fn(Float, Float) -> Float, FuncType);
impl UnaryFuncInfo {
fn call(&self, x: f64, angle_unit: &Unit) -> f64 {
fn call(&self, x: Float, angle_unit: &Unit) -> Float {
let func = self.0;
match self.1 {
FuncType::Trig => func(from_angle_unit(x, angle_unit)),
@ -82,7 +83,7 @@ impl UnaryFuncInfo {
}
impl BinaryFuncInfo {
fn call(&self, x: f64, y: f64, angle_unit: &Unit) -> f64 {
fn call(&self, x: Float, y: Float, angle_unit: &Unit) -> Float {
let func = self.0;
match self.1 {
FuncType::Trig => func(
@ -95,7 +96,7 @@ impl BinaryFuncInfo {
}
}
pub fn call_unary_func(name: &str, x: f64, angle_unit: &Unit) -> Option<f64> {
pub fn call_unary_func(name: &str, x: Float, angle_unit: &Unit) -> Option<Float> {
if let Some(func_info) = UNARY_FUNCS.get(name) {
Some(func_info.call(x, &angle_unit))
} else {
@ -103,7 +104,7 @@ pub fn call_unary_func(name: &str, x: f64, angle_unit: &Unit) -> Option<f64> {
}
}
pub fn call_binary_func(name: &str, x: f64, y: f64, angle_unit: &Unit) -> Option<f64> {
pub fn call_binary_func(name: &str, x: Float, y: Float, angle_unit: &Unit) -> Option<Float> {
if let Some(func_info) = BINARY_FUNCS.get(name) {
Some(func_info.call(x, y, angle_unit))
} else {
@ -111,188 +112,196 @@ pub fn call_binary_func(name: &str, x: f64, y: f64, angle_unit: &Unit) -> Option
}
}
fn to_angle_unit(x: f64, angle_unit: &Unit) -> f64 {
fn to_angle_unit(x: Float, angle_unit: &Unit) -> Float {
match angle_unit {
Unit::Radians => x,
Unit::Degrees => x.to_degrees(),
Unit::Degrees => special_funcs::to_degrees(x),
}
}
fn from_angle_unit(x: f64, angle_unit: &Unit) -> f64 {
fn from_angle_unit(x: Float, angle_unit: &Unit) -> Float {
match angle_unit {
Unit::Radians => x,
Unit::Degrees => x.to_radians(),
Unit::Degrees => special_funcs::to_radians(x),
}
}
pub mod special_funcs {
pub fn factorial(x: i32) -> i32 {
let mut value = 1;
for i in 1..=x {
value *= i;
}
use rug::Float;
value
pub fn factorial(x: Float) -> Float {
((x + 1) as Float).gamma()
}
pub fn to_degrees(x: Float) -> Float {
Float::with_val(10, x.to_f64().to_degrees())
}
pub fn to_radians(x: Float) -> Float {
Float::with_val(10, x.to_f64().to_radians())
}
}
mod funcs {
pub fn abs(x: f64) -> f64 {
use rug::ops::Pow;
use rug::Float;
pub fn abs(x: Float) -> Float {
x.abs()
}
pub fn acos(x: f64) -> f64 {
pub fn acos(x: Float) -> Float {
x.acos()
}
pub fn acosh(x: f64) -> f64 {
pub fn acosh(x: Float) -> Float {
x.acosh()
}
pub fn acot(x: f64) -> f64 {
pub fn acot(x: Float) -> Float {
(1f64 / x).atan()
}
pub fn acoth(x: f64) -> f64 {
pub fn acoth(x: Float) -> Float {
(1f64 / x).atanh()
}
pub fn acosec(x: f64) -> f64 {
pub fn acosec(x: Float) -> Float {
(1f64 / x).asin()
}
pub fn acosech(x: f64) -> f64 {
pub fn acosech(x: Float) -> Float {
(1f64 / x).asinh()
}
pub fn asec(x: f64) -> f64 {
pub fn asec(x: Float) -> Float {
(1f64 / x).acos()
}
pub fn asech(x: f64) -> f64 {
pub fn asech(x: Float) -> Float {
(1f64 / x).acosh()
}
pub fn asin(x: f64) -> f64 {
pub fn asin(x: Float) -> Float {
x.asin()
}
pub fn asinh(x: f64) -> f64 {
pub fn asinh(x: Float) -> Float {
x.asinh()
}
pub fn atan(x: f64) -> f64 {
pub fn atan(x: Float) -> Float {
x.atan()
}
pub fn atanh(x: f64) -> f64 {
pub fn atanh(x: Float) -> Float {
x.atanh()
}
pub fn cbrt(x: f64) -> f64 {
pub fn cbrt(x: Float) -> Float {
x.cbrt()
}
pub fn ceil(x: f64) -> f64 {
pub fn ceil(x: Float) -> Float {
x.ceil()
}
pub fn cos(x: f64) -> f64 {
pub fn cos(x: Float) -> Float {
x.cos()
}
pub fn cosh(x: f64) -> f64 {
pub fn cosh(x: Float) -> Float {
x.cos()
}
pub fn cosec(x: f64) -> f64 {
pub fn cosec(x: Float) -> Float {
1f64 / x.sin()
}
pub fn cosech(x: f64) -> f64 {
pub fn cosech(x: Float) -> Float {
1f64 / x.sinh()
}
pub fn cot(x: f64) -> f64 {
x.cos() / x.sin()
pub fn cot(x: Float) -> Float {
x.clone().cos() / x.sin()
}
pub fn coth(x: f64) -> f64 {
x.cosh() / x.sinh()
pub fn coth(x: Float) -> Float {
x.clone().cosh() / x.sinh()
}
pub fn exp(x: f64) -> f64 {
pub fn exp(x: Float) -> Float {
x.exp()
}
pub fn floor(x: f64) -> f64 {
pub fn floor(x: Float) -> Float {
x.floor()
}
pub fn frac(x: f64) -> f64 {
pub fn frac(x: Float) -> Float {
x.fract()
}
pub fn hyp(x: f64, y: f64) -> f64 {
x.hypot(y)
pub fn hyp(x: Float, y: Float) -> Float {
x.hypot(&y)
}
pub fn log(x: f64) -> f64 {
x.log(10f64)
pub fn log(x: Float) -> Float {
x.log10()
}
pub fn logx(x: f64, y: f64) -> f64 {
x.log(y)
pub fn logx(x: Float, y: Float) -> Float {
x.log10() / y.log10()
}
pub fn ln(x: f64) -> f64 {
pub fn ln(x: Float) -> Float {
x.ln()
}
pub fn max(x: f64, y: f64) -> f64 {
x.max(y)
pub fn max(x: Float, y: Float) -> Float {
x.max(&y)
}
pub fn min(x: f64, y: f64) -> f64 {
x.min(y)
pub fn min(x: Float, y: Float) -> Float {
x.min(&y)
}
pub fn round(x: f64) -> f64 {
pub fn round(x: Float) -> Float {
x.round()
}
pub fn sec(x: f64) -> f64 {
pub fn sec(x: Float) -> Float {
1f64 / x.cos()
}
pub fn sech(x: f64) -> f64 {
pub fn sech(x: Float) -> Float {
1f64 / x.cosh()
}
pub fn sin(x: f64) -> f64 {
pub fn sin(x: Float) -> Float {
x.sin()
}
pub fn sinh(x: f64) -> f64 {
pub fn sinh(x: Float) -> Float {
x.sinh()
}
pub fn sqrt(x: f64) -> f64 {
pub fn sqrt(x: Float) -> Float {
x.sqrt()
}
pub fn nth_sqrt(x: f64, n: f64) -> f64 {
x.powf(1f64 / n)
pub fn nth_sqrt(x: Float, n: Float) -> Float {
x.pow(Float::with_val(1, 1) / n)
}
pub fn tan(x: f64) -> f64 {
pub fn tan(x: Float) -> Float {
x.tan()
}
pub fn tanh(x: f64) -> f64 {
pub fn tanh(x: Float) -> Float {
x.tanh()
}
pub fn trunc(x: f64) -> f64 {
pub fn trunc(x: Float) -> Float {
x.trunc()
}
}