adds more math functions and fixes parens (#558)

* nested parens fix

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* e, tau

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* docs

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* remove test w log since that is a stdlib fn now

Signed-off-by: Jess Frazelle <github@jessfraz.com>

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
This commit is contained in:
Jess Frazelle
2023-09-15 17:40:57 -07:00
committed by GitHub
parent ae7143a94f
commit cf686bdeb0
8 changed files with 487 additions and 64 deletions

View File

@ -9490,6 +9490,24 @@
"unpublished": false,
"deprecated": false
},
{
"name": "e",
"summary": "Return the value of Eulers number `e`.",
"description": "",
"tags": [],
"args": [],
"returnValue": {
"name": "",
"type": "number",
"schema": {
"type": "number",
"format": "double"
},
"required": true
},
"unpublished": false,
"deprecated": false
},
{
"name": "extrude",
"summary": "Extrudes by a given amount.",
@ -13183,9 +13201,130 @@
"unpublished": false,
"deprecated": false
},
{
"name": "ln",
"summary": "Computes the natural logarithm of the number.",
"description": "",
"tags": [],
"args": [
{
"name": "num",
"type": "number",
"schema": {
"type": "number",
"format": "double"
},
"required": true
}
],
"returnValue": {
"name": "",
"type": "number",
"schema": {
"type": "number",
"format": "double"
},
"required": true
},
"unpublished": false,
"deprecated": false
},
{
"name": "log",
"summary": "Computes the logarithm of the number with respect to an arbitrary base.",
"description": "The result might not be correctly rounded owing to implementation details; `log2()` can produce more accurate results for base 2, and `log10()` can produce more accurate results for base 10.",
"tags": [],
"args": [
{
"name": "num",
"type": "number",
"schema": {
"type": "number",
"format": "double"
},
"required": true
},
{
"name": "base",
"type": "number",
"schema": {
"type": "number",
"format": "double"
},
"required": true
}
],
"returnValue": {
"name": "",
"type": "number",
"schema": {
"type": "number",
"format": "double"
},
"required": true
},
"unpublished": false,
"deprecated": false
},
{
"name": "log10",
"summary": "Computes the base 10 logarithm of the number.",
"description": "",
"tags": [],
"args": [
{
"name": "num",
"type": "number",
"schema": {
"type": "number",
"format": "double"
},
"required": true
}
],
"returnValue": {
"name": "",
"type": "number",
"schema": {
"type": "number",
"format": "double"
},
"required": true
},
"unpublished": false,
"deprecated": false
},
{
"name": "log2",
"summary": "Computes the base 2 logarithm of the number.",
"description": "",
"tags": [],
"args": [
{
"name": "num",
"type": "number",
"schema": {
"type": "number",
"format": "double"
},
"required": true
}
],
"returnValue": {
"name": "",
"type": "number",
"schema": {
"type": "number",
"format": "double"
},
"required": true
},
"unpublished": false,
"deprecated": false
},
{
"name": "max",
"summary": "Returns the maximum of the given arguments.",
"summary": "Computes the maximum of the given arguments.",
"description": "",
"tags": [],
"args": [
@ -13216,7 +13355,7 @@
},
{
"name": "min",
"summary": "Returns the minimum of the given arguments.",
"summary": "Computes the minimum of the given arguments.",
"description": "",
"tags": [],
"args": [
@ -13247,7 +13386,7 @@
},
{
"name": "pi",
"summary": "Return the value of `pi`.",
"summary": "Return the value of `pi`. Archimedes constant (π).",
"description": "",
"tags": [],
"args": [],
@ -16155,6 +16294,24 @@
"unpublished": false,
"deprecated": false
},
{
"name": "tau",
"summary": "Return the value of `tau`. The full circle constant (τ). Equal to 2π.",
"description": "",
"tags": [],
"args": [],
"returnValue": {
"name": "",
"type": "number",
"schema": {
"type": "number",
"format": "double"
},
"required": true
},
"unpublished": false,
"deprecated": false
},
{
"name": "xLine",
"summary": "Draw a line on the x-axis.",

View File

@ -22,6 +22,7 @@
* [`ceil`](#ceil)
* [`close`](#close)
* [`cos`](#cos)
* [`e`](#e)
* [`extrude`](#extrude)
* [`floor`](#floor)
* [`getExtrudeWallTransform`](#getExtrudeWallTransform)
@ -32,6 +33,10 @@
* [`legLen`](#legLen)
* [`line`](#line)
* [`lineTo`](#lineTo)
* [`ln`](#ln)
* [`log`](#log)
* [`log10`](#log10)
* [`log2`](#log2)
* [`max`](#max)
* [`min`](#min)
* [`pi`](#pi)
@ -45,6 +50,7 @@
* [`sqrt`](#sqrt)
* [`startSketchAt`](#startSketchAt)
* [`tan`](#tan)
* [`tau`](#tau)
* [`xLine`](#xLine)
* [`xLineTo`](#xLineTo)
* [`yLine`](#yLine)
@ -1770,6 +1776,25 @@ cos(num: number) -> number
### e
Return the value of Eulers number `e`.
```
e() -> number
```
#### Arguments
#### Returns
* `number`
### extrude
Extrudes by a given amount.
@ -2487,9 +2512,90 @@ lineTo(data: LineToData, sketch_group: SketchGroup) -> SketchGroup
### ln
Computes the natural logarithm of the number.
```
ln(num: number) -> number
```
#### Arguments
* `num`: `number`
#### Returns
* `number`
### log
Computes the logarithm of the number with respect to an arbitrary base.
The result might not be correctly rounded owing to implementation details; `log2()` can produce more accurate results for base 2, and `log10()` can produce more accurate results for base 10.
```
log(num: number, base: number) -> number
```
#### Arguments
* `num`: `number`
* `base`: `number`
#### Returns
* `number`
### log10
Computes the base 10 logarithm of the number.
```
log10(num: number) -> number
```
#### Arguments
* `num`: `number`
#### Returns
* `number`
### log2
Computes the base 2 logarithm of the number.
```
log2(num: number) -> number
```
#### Arguments
* `num`: `number`
#### Returns
* `number`
### max
Returns the maximum of the given arguments.
Computes the maximum of the given arguments.
@ -2509,7 +2615,7 @@ max(args: [number]) -> number
### min
Returns the minimum of the given arguments.
Computes the minimum of the given arguments.
@ -2529,7 +2635,7 @@ min(args: [number]) -> number
### pi
Return the value of `pi`.
Return the value of `pi`. Archimedes constant (π).
@ -3128,6 +3234,25 @@ tan(num: number) -> number
### tau
Return the value of `tau`. The full circle constant (τ). Equal to 2π.
```
tau() -> number
```
#### Arguments
#### Returns
* `number`
### xLine
Draw a line on the x-axis.

View File

@ -139,54 +139,6 @@ const newVar = myVar + 1
},
])
})
test('using std function "log"', () => {
const code = `log(5, "hello", aIdentifier)`
const { body } = parser_wasm(code)
expect(body).toEqual([
{
type: 'ExpressionStatement',
start: 0,
end: 28,
expression: {
type: 'CallExpression',
start: 0,
end: 28,
callee: {
type: 'Identifier',
start: 0,
end: 3,
name: 'log',
},
arguments: [
{
type: 'Literal',
start: 4,
end: 5,
value: 5,
raw: '5',
},
{
type: 'Literal',
start: 7,
end: 14,
value: 'hello',
raw: '"hello"',
},
{
type: 'Identifier',
start: 16,
end: 27,
name: 'aIdentifier',
},
],
function: {
type: 'InMemory',
},
optional: false,
},
},
])
})
})
describe('testing function declaration', () => {

View File

@ -1203,6 +1203,54 @@ const bracket = startSketchAt([0,0])
|> line([leg2, 0], %)
|> line([0, -thickness], %)
|> line([-leg2 + thickness, 0], %)
"#;
parse_execute(ast).await.unwrap();
}
#[tokio::test(flavor = "multi_thread")]
async fn test_math_doubly_nested_parens() {
let ast = r#"const sigmaAllow = 35000 // psi
const width = 4 // inch
const p = 150 // Force on shelf - lbs
const distance = 6 // inches
const FOS = 2
const leg1 = 5 // inches
const leg2 = 8 // inches
const thickness_squared = (distance * p * FOS * 6 / (sigmaAllow - width))
const thickness = 0.32 // inches. App does not support square root function yet
const bracket = startSketchAt([0,0])
|> line([0, leg1], %)
|> line([leg2, 0], %)
|> line([0, -thickness], %)
|> line([-1 * leg2 + thickness, 0], %)
|> line([0, -1 * leg1 + thickness], %)
|> close(%)
|> extrude(width, %)
show(bracket)
"#;
parse_execute(ast).await.unwrap();
}
#[tokio::test(flavor = "multi_thread")]
async fn test_math_nested_parens_one_less() {
let ast = r#"const sigmaAllow = 35000 // psi
const width = 4 // inch
const p = 150 // Force on shelf - lbs
const distance = 6 // inches
const FOS = 2
const leg1 = 5 // inches
const leg2 = 8 // inches
const thickness_squared = distance * p * FOS * 6 / (sigmaAllow - width)
const thickness = 0.32 // inches. App does not support square root function yet
const bracket = startSketchAt([0,0])
|> line([0, leg1], %)
|> line([leg2, 0], %)
|> line([0, -thickness], %)
|> line([-1 * leg2 + thickness, 0], %)
|> line([0, -1 * leg1 + thickness], %)
|> close(%)
|> extrude(width, %)
show(bracket)
"#;
parse_execute(ast).await.unwrap();
}

View File

@ -1271,4 +1271,22 @@ mod test {
let output = parser.build_tree(&input_tokens, vec![]).unwrap();
assert_eq!(output, expected_output);
}
#[test]
fn test_parse_expression_braces_around_lots_of_math() {
let code = "(distance * p * FOS * 6 / (sigmaAllow * width))";
let tokens = crate::tokeniser::lexer(code);
let mut parser = MathParser::new(&tokens);
let result = parser.parse();
assert!(result.is_ok());
}
#[test]
fn test_parse_expression_braces_around_internals_lots_of_math() {
let code = "distance * p * FOS * 6 / (sigmaAllow * width)";
let tokens = crate::tokeniser::lexer(code);
let mut parser = MathParser::new(&tokens);
let result = parser.parse();
assert!(result.is_ok());
}
}

View File

@ -880,10 +880,12 @@ impl Parser {
last_index: function_expression.last_index,
})
} else {
return Err(KclError::Unimplemented(KclErrorDetails {
source_ranges: vec![current_token.into()],
message: "expression with braces".to_string(),
}));
// This is likely a binary expression that starts with a parenthesis.
let binary_expression = self.make_binary_expression(index)?;
Ok(ValueReturn {
value: Value::BinaryExpression(Box::new(binary_expression.expression)),
last_index: binary_expression.last_index,
})
}
} else {
return Err(KclError::Unimplemented(KclErrorDetails {

View File

@ -58,14 +58,14 @@ fn inner_tan(num: f64) -> Result<f64, KclError> {
Ok(num.tan())
}
/// Return the value of `pi`.
/// Return the value of `pi`. Archimedes constant (π).
pub fn pi(args: &mut Args) -> Result<MemoryItem, KclError> {
let result = inner_pi()?;
args.make_user_val_from_f64(result)
}
/// Return the value of `pi`.
/// Return the value of `pi`. Archimedes constant (π).
#[stdlib {
name = "pi",
}]
@ -137,7 +137,7 @@ fn inner_ceil(num: f64) -> Result<f64, KclError> {
Ok(num.ceil())
}
/// Returns the minimum of the given arguments.
/// Computes the minimum of the given arguments.
pub fn min(args: &mut Args) -> Result<MemoryItem, KclError> {
let nums = args.get_number_array()?;
let result = inner_min(nums);
@ -145,7 +145,7 @@ pub fn min(args: &mut Args) -> Result<MemoryItem, KclError> {
args.make_user_val_from_f64(result)
}
/// Returns the minimum of the given arguments.
/// Computes the minimum of the given arguments.
#[stdlib {
name = "min",
}]
@ -160,7 +160,7 @@ fn inner_min(args: Vec<f64>) -> f64 {
min
}
/// Returns the maximum of the given arguments.
/// Computes the maximum of the given arguments.
pub fn max(args: &mut Args) -> Result<MemoryItem, KclError> {
let nums = args.get_number_array()?;
let result = inner_max(nums);
@ -168,7 +168,7 @@ pub fn max(args: &mut Args) -> Result<MemoryItem, KclError> {
args.make_user_val_from_f64(result)
}
/// Returns the maximum of the given arguments.
/// Computes the maximum of the given arguments.
#[stdlib {
name = "max",
}]
@ -260,3 +260,118 @@ pub fn atan(args: &mut Args) -> Result<MemoryItem, KclError> {
fn inner_atan(num: f64) -> Result<f64, KclError> {
Ok(num.atan())
}
/// Computes the logarithm of the number with respect to an arbitrary base.
///
/// The result might not be correctly rounded owing to implementation
/// details; `log2()` can produce more accurate results for base 2,
/// and `log10()` can produce more accurate results for base 10.
pub fn log(args: &mut Args) -> Result<MemoryItem, KclError> {
let nums = args.get_number_array()?;
if nums.len() > 2 {
return Err(KclError::Type(KclErrorDetails {
message: format!("expected 2 arguments, got {}", nums.len()),
source_ranges: vec![args.source_range],
}));
}
if nums.len() <= 1 {
return Err(KclError::Type(KclErrorDetails {
message: format!("expected 2 arguments, got {}", nums.len()),
source_ranges: vec![args.source_range],
}));
}
let result = inner_log(nums[0], nums[1])?;
args.make_user_val_from_f64(result)
}
/// Computes the logarithm of the number with respect to an arbitrary base.
///
/// The result might not be correctly rounded owing to implementation
/// details; `log2()` can produce more accurate results for base 2,
/// and `log10()` can produce more accurate results for base 10.
#[stdlib {
name = "log",
}]
fn inner_log(num: f64, base: f64) -> Result<f64, KclError> {
Ok(num.log(base))
}
/// Computes the base 2 logarithm of the number.
pub fn log2(args: &mut Args) -> Result<MemoryItem, KclError> {
let num = args.get_number()?;
let result = inner_log2(num)?;
args.make_user_val_from_f64(result)
}
/// Computes the base 2 logarithm of the number.
#[stdlib {
name = "log2",
}]
fn inner_log2(num: f64) -> Result<f64, KclError> {
Ok(num.log2())
}
/// Computes the base 10 logarithm of the number.
pub fn log10(args: &mut Args) -> Result<MemoryItem, KclError> {
let num = args.get_number()?;
let result = inner_log10(num)?;
args.make_user_val_from_f64(result)
}
/// Computes the base 10 logarithm of the number.
#[stdlib {
name = "log10",
}]
fn inner_log10(num: f64) -> Result<f64, KclError> {
Ok(num.log10())
}
/// Computes the natural logarithm of the number.
pub fn ln(args: &mut Args) -> Result<MemoryItem, KclError> {
let num = args.get_number()?;
let result = inner_ln(num)?;
args.make_user_val_from_f64(result)
}
/// Computes the natural logarithm of the number.
#[stdlib {
name = "ln",
}]
fn inner_ln(num: f64) -> Result<f64, KclError> {
Ok(num.ln())
}
/// Return the value of Eulers number `e`.
pub fn e(args: &mut Args) -> Result<MemoryItem, KclError> {
let result = inner_e()?;
args.make_user_val_from_f64(result)
}
/// Return the value of Eulers number `e`.
#[stdlib {
name = "e",
}]
fn inner_e() -> Result<f64, KclError> {
Ok(std::f64::consts::E)
}
/// Return the value of `tau`. The full circle constant (τ). Equal to 2π.
pub fn tau(args: &mut Args) -> Result<MemoryItem, KclError> {
let result = inner_tau()?;
args.make_user_val_from_f64(result)
}
/// Return the value of `tau`. The full circle constant (τ). Equal to 2π.
#[stdlib {
name = "tau",
}]
fn inner_tau() -> Result<f64, KclError> {
Ok(std::f64::consts::TAU)
}

View File

@ -68,6 +68,8 @@ impl StdLib {
Box::new(crate::std::math::Asin),
Box::new(crate::std::math::Atan),
Box::new(crate::std::math::Pi),
Box::new(crate::std::math::E),
Box::new(crate::std::math::Tau),
Box::new(crate::std::math::Sqrt),
Box::new(crate::std::math::Abs),
Box::new(crate::std::math::Floor),
@ -75,6 +77,10 @@ impl StdLib {
Box::new(crate::std::math::Min),
Box::new(crate::std::math::Max),
Box::new(crate::std::math::Pow),
Box::new(crate::std::math::Log),
Box::new(crate::std::math::Log2),
Box::new(crate::std::math::Log10),
Box::new(crate::std::math::Ln),
];
let mut fns = HashMap::new();