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

@ -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(&current_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) => {

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.
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<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> {
let mut numbers: Vec<f64> = Vec::new();
for arg in &self.args {