add sin cos tan to stdlib and make sure you cant redeclare a stdlib fn (#497)

more tests

Signed-off-by: Jess Frazelle <github@jessfraz.com>
This commit is contained in:
Jess Frazelle
2023-09-13 15:09:07 -07:00
committed by GitHub
parent f8ed830b60
commit 0466f04d82
5 changed files with 307 additions and 2 deletions

View File

@ -9322,6 +9322,34 @@
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false
}, },
{
"name": "cos",
"summary": "Computes the sine of a number (in radians).",
"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": "extrude", "name": "extrude",
"summary": "Extrudes by a given amount.", "summary": "Extrudes by a given amount.",
@ -13018,6 +13046,24 @@
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false
}, },
{
"name": "pi",
"summary": "Return the value of `pi`.",
"description": "",
"tags": [],
"args": [],
"returnValue": {
"name": "",
"type": "number",
"schema": {
"type": "number",
"format": "double"
},
"required": true
},
"unpublished": false,
"deprecated": false
},
{ {
"name": "segAng", "name": "segAng",
"summary": "Returns the angle of the segment.", "summary": "Returns the angle of the segment.",
@ -15302,6 +15348,34 @@
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false
}, },
{
"name": "sin",
"summary": "Computes the sine of a number (in radians).",
"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": "startSketchAt", "name": "startSketchAt",
"summary": "Start a sketch at a given point.", "summary": "Start a sketch at a given point.",
@ -15789,6 +15863,34 @@
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false
}, },
{
"name": "tan",
"summary": "Computes the tangent of a number (in radians).",
"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": "xLine", "name": "xLine",
"summary": "Draw a line on the x-axis.", "summary": "Draw a line on the x-axis.",

View File

@ -16,6 +16,7 @@
* [`arc`](#arc) * [`arc`](#arc)
* [`bezierCurve`](#bezierCurve) * [`bezierCurve`](#bezierCurve)
* [`close`](#close) * [`close`](#close)
* [`cos`](#cos)
* [`extrude`](#extrude) * [`extrude`](#extrude)
* [`getExtrudeWallTransform`](#getExtrudeWallTransform) * [`getExtrudeWallTransform`](#getExtrudeWallTransform)
* [`lastSegX`](#lastSegX) * [`lastSegX`](#lastSegX)
@ -26,12 +27,15 @@
* [`line`](#line) * [`line`](#line)
* [`lineTo`](#lineTo) * [`lineTo`](#lineTo)
* [`min`](#min) * [`min`](#min)
* [`pi`](#pi)
* [`segAng`](#segAng) * [`segAng`](#segAng)
* [`segEndX`](#segEndX) * [`segEndX`](#segEndX)
* [`segEndY`](#segEndY) * [`segEndY`](#segEndY)
* [`segLen`](#segLen) * [`segLen`](#segLen)
* [`show`](#show) * [`show`](#show)
* [`sin`](#sin)
* [`startSketchAt`](#startSketchAt) * [`startSketchAt`](#startSketchAt)
* [`tan`](#tan)
* [`xLine`](#xLine) * [`xLine`](#xLine)
* [`xLineTo`](#xLineTo) * [`xLineTo`](#xLineTo)
* [`yLine`](#yLine) * [`yLine`](#yLine)
@ -1637,6 +1641,26 @@ close(sketch_group: SketchGroup) -> SketchGroup
### cos
Computes the sine of a number (in radians).
```
cos(num: number) -> number
```
#### Arguments
* `num`: `number`
#### Returns
* `number`
### extrude ### extrude
Extrudes by a given amount. Extrudes by a given amount.
@ -2354,6 +2378,25 @@ min(args: [number]) -> number
### pi
Return the value of `pi`.
```
pi() -> number
```
#### Arguments
#### Returns
* `number`
### segAng ### segAng
Returns the angle of the segment. Returns the angle of the segment.
@ -2764,6 +2807,26 @@ show(sketch: SketchGroup)
### sin
Computes the sine of a number (in radians).
```
sin(num: number) -> number
```
#### Arguments
* `num`: `number`
#### Returns
* `number`
### startSketchAt ### startSketchAt
Start a sketch at a given point. Start a sketch at a given point.
@ -2855,6 +2918,26 @@ startSketchAt(data: LineData) -> SketchGroup
### tan
Computes the tangent of a number (in radians).
```
tan(num: number) -> number
```
#### Arguments
* `num`: `number`
#### Returns
* `number`
### xLine ### xLine
Draw a line on the x-axis. Draw a line on the x-axis.

View File

@ -1287,7 +1287,8 @@ impl Parser {
let current_token = self.get_token(index)?; let current_token = self.get_token(index)?;
// Make sure they are not assigning a variable to a reserved keyword. // Make sure they are not assigning a variable to a reserved keyword.
if current_token.token_type == TokenType::Keyword { // Or a stdlib function.
if current_token.token_type == TokenType::Keyword || self.stdlib.fns.contains_key(&current_token.value) {
return Err(KclError::Syntax(KclErrorDetails { return Err(KclError::Syntax(KclErrorDetails {
source_ranges: vec![current_token.into()], source_ranges: vec![current_token.into()],
message: format!( message: format!(
@ -1399,7 +1400,8 @@ impl Parser {
} }
// Make sure they are not assigning a variable to a reserved keyword. // Make sure they are not assigning a variable to a reserved keyword.
if argument_token.token_type == TokenType::Keyword { // Or a stdlib function.
if argument_token.token_type == TokenType::Keyword || self.stdlib.fns.contains_key(&argument_token.value) {
return Err(KclError::Syntax(KclErrorDetails { return Err(KclError::Syntax(KclErrorDetails {
source_ranges: vec![argument_token.clone().into()], source_ranges: vec![argument_token.clone().into()],
message: format!( message: format!(
@ -3287,6 +3289,19 @@ e
); );
} }
#[test]
fn test_error_stdlib_in_fn_name() {
let some_program_string = r#"fn cos = () {}"#;
let tokens = crate::tokeniser::lexer(some_program_string);
let parser = crate::parser::Parser::new(tokens);
let result = parser.ast();
assert!(result.is_err());
assert_eq!(
result.err().unwrap().to_string(),
r#"syntax: KclErrorDetails { source_ranges: [SourceRange([3, 6])], message: "Cannot assign a variable to a reserved keyword: cos" }"#
);
}
#[test] #[test]
fn test_error_keyword_in_fn_args() { fn test_error_keyword_in_fn_args() {
let some_program_string = r#"fn thing = (let) => { let some_program_string = r#"fn thing = (let) => {
@ -3302,6 +3317,21 @@ e
); );
} }
#[test]
fn test_error_stdlib_in_fn_args() {
let some_program_string = r#"fn thing = (cos) => {
return 1
}"#;
let tokens = crate::tokeniser::lexer(some_program_string);
let parser = crate::parser::Parser::new(tokens);
let result = parser.ast();
assert!(result.is_err());
assert_eq!(
result.err().unwrap().to_string(),
r#"syntax: KclErrorDetails { source_ranges: [SourceRange([12, 15])], message: "Cannot assign a variable to a reserved keyword: cos" }"#
);
}
#[test] #[test]
fn test_keyword_ok_in_fn_args_return() { fn test_keyword_ok_in_fn_args_return() {
let some_program_string = r#"fn thing = (param) => { let some_program_string = r#"fn thing = (param) => {

View File

@ -0,0 +1,70 @@
//! Functions related to mathematics.
use anyhow::Result;
use derive_docs::stdlib;
use schemars::JsonSchema;
use crate::{errors::KclError, executor::MemoryItem, std::Args};
/// Computes the cosine of a number (in radians).
pub fn cos(args: &mut Args) -> Result<MemoryItem, KclError> {
let num = args.get_number()?;
let result = inner_cos(num)?;
args.make_user_val_from_f64(result)
}
/// Computes the sine of a number (in radians).
#[stdlib {
name = "cos",
}]
fn inner_cos(num: f64) -> Result<f64, KclError> {
Ok(num.cos())
}
/// Computes the sine of a number (in radians).
pub fn sin(args: &mut Args) -> Result<MemoryItem, KclError> {
let num = args.get_number()?;
let result = inner_sin(num)?;
args.make_user_val_from_f64(result)
}
/// Computes the sine of a number (in radians).
#[stdlib {
name = "sin",
}]
fn inner_sin(num: f64) -> Result<f64, KclError> {
Ok(num.sin())
}
/// Computes the tangent of a number (in radians).
pub fn tan(args: &mut Args) -> Result<MemoryItem, KclError> {
let num = args.get_number()?;
let result = inner_tan(num)?;
args.make_user_val_from_f64(result)
}
/// Computes the tangent of a number (in radians).
#[stdlib {
name = "tan",
}]
fn inner_tan(num: f64) -> Result<f64, KclError> {
Ok(num.tan())
}
/// Return the value of `pi`.
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`.
#[stdlib {
name = "pi",
}]
fn inner_pi() -> Result<f64, KclError> {
Ok(std::f64::consts::PI)
}

View File

@ -1,6 +1,7 @@
//! Functions implemented for language execution. //! Functions implemented for language execution.
pub mod extrude; pub mod extrude;
pub mod math;
pub mod segment; pub mod segment;
pub mod sketch; pub mod sketch;
pub mod utils; pub mod utils;
@ -61,6 +62,10 @@ impl StdLib {
Box::new(crate::std::sketch::Close), Box::new(crate::std::sketch::Close),
Box::new(crate::std::sketch::Arc), Box::new(crate::std::sketch::Arc),
Box::new(crate::std::sketch::BezierCurve), Box::new(crate::std::sketch::BezierCurve),
Box::new(crate::std::math::Cos),
Box::new(crate::std::math::Sin),
Box::new(crate::std::math::Tan),
Box::new(crate::std::math::Pi),
]; ];
let mut fns = HashMap::new(); let mut fns = HashMap::new();
@ -122,6 +127,21 @@ impl<'a> Args<'a> {
)?)) )?))
} }
fn get_number(&self) -> Result<f64, KclError> {
let first_value = self
.args
.first()
.ok_or_else(|| {
KclError::Type(KclErrorDetails {
message: format!("Expected a number as the first argument, found `{:?}`", self.args),
source_ranges: vec![self.source_range],
})
})?
.get_json_value()?;
parse_json_number_as_f64(&first_value, self.source_range)
}
fn get_number_array(&self) -> Result<Vec<f64>, KclError> { fn get_number_array(&self) -> Result<Vec<f64>, KclError> {
let mut numbers: Vec<f64> = Vec::new(); let mut numbers: Vec<f64> = Vec::new();
for arg in &self.args { for arg in &self.args {