diff --git a/docs/kcl/std.json b/docs/kcl/std.json index 82f6e7179..734e5d9b3 100644 --- a/docs/kcl/std.json +++ b/docs/kcl/std.json @@ -9322,6 +9322,34 @@ "unpublished": 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", "summary": "Extrudes by a given amount.", @@ -13018,6 +13046,24 @@ "unpublished": 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", "summary": "Returns the angle of the segment.", @@ -15302,6 +15348,34 @@ "unpublished": 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", "summary": "Start a sketch at a given point.", @@ -15789,6 +15863,34 @@ "unpublished": 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", "summary": "Draw a line on the x-axis.", diff --git a/docs/kcl/std.md b/docs/kcl/std.md index 4e32cabd3..d98366a73 100644 --- a/docs/kcl/std.md +++ b/docs/kcl/std.md @@ -16,6 +16,7 @@ * [`arc`](#arc) * [`bezierCurve`](#bezierCurve) * [`close`](#close) + * [`cos`](#cos) * [`extrude`](#extrude) * [`getExtrudeWallTransform`](#getExtrudeWallTransform) * [`lastSegX`](#lastSegX) @@ -26,12 +27,15 @@ * [`line`](#line) * [`lineTo`](#lineTo) * [`min`](#min) + * [`pi`](#pi) * [`segAng`](#segAng) * [`segEndX`](#segEndX) * [`segEndY`](#segEndY) * [`segLen`](#segLen) * [`show`](#show) + * [`sin`](#sin) * [`startSketchAt`](#startSketchAt) + * [`tan`](#tan) * [`xLine`](#xLine) * [`xLineTo`](#xLineTo) * [`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 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 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 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 Draw a line on the x-axis. diff --git a/src/wasm-lib/kcl/src/parser.rs b/src/wasm-lib/kcl/src/parser.rs index 885850471..b8242e18a 100644 --- a/src/wasm-lib/kcl/src/parser.rs +++ b/src/wasm-lib/kcl/src/parser.rs @@ -1287,7 +1287,8 @@ impl Parser { let current_token = self.get_token(index)?; // 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(¤t_token.value) { return Err(KclError::Syntax(KclErrorDetails { source_ranges: vec![current_token.into()], message: format!( @@ -1399,7 +1400,8 @@ impl Parser { } // 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 { source_ranges: vec![argument_token.clone().into()], 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] fn test_error_keyword_in_fn_args() { 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] fn test_keyword_ok_in_fn_args_return() { let some_program_string = r#"fn thing = (param) => { diff --git a/src/wasm-lib/kcl/src/std/math.rs b/src/wasm-lib/kcl/src/std/math.rs new file mode 100644 index 000000000..bd4cc309f --- /dev/null +++ b/src/wasm-lib/kcl/src/std/math.rs @@ -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 { + 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 { + Ok(num.cos()) +} + +/// Computes the sine of a number (in radians). +pub fn sin(args: &mut Args) -> Result { + 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 { + Ok(num.sin()) +} + +/// Computes the tangent of a number (in radians). +pub fn tan(args: &mut Args) -> Result { + 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 { + Ok(num.tan()) +} + +/// Return the value of `pi`. +pub fn pi(args: &mut Args) -> Result { + let result = inner_pi()?; + + args.make_user_val_from_f64(result) +} + +/// Return the value of `pi`. +#[stdlib { + name = "pi", +}] +fn inner_pi() -> Result { + Ok(std::f64::consts::PI) +} diff --git a/src/wasm-lib/kcl/src/std/mod.rs b/src/wasm-lib/kcl/src/std/mod.rs index 5f9dc30a8..ef3d106c6 100644 --- a/src/wasm-lib/kcl/src/std/mod.rs +++ b/src/wasm-lib/kcl/src/std/mod.rs @@ -1,6 +1,7 @@ //! Functions implemented for language execution. pub mod extrude; +pub mod math; pub mod segment; pub mod sketch; pub mod utils; @@ -61,6 +62,10 @@ impl StdLib { Box::new(crate::std::sketch::Close), Box::new(crate::std::sketch::Arc), 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(); @@ -122,6 +127,21 @@ impl<'a> Args<'a> { )?)) } + fn get_number(&self) -> Result { + 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, KclError> { let mut numbers: Vec = Vec::new(); for arg in &self.args {