From 5317a12383b0dea726db1f212dd1c006bbbbe89c Mon Sep 17 00:00:00 2001 From: Add00 Date: Sun, 30 Jul 2023 23:17:43 -0400 Subject: [PATCH 01/10] Added radian and degree conversion functions. --- repl/lib_standard.c | 178 ++++++++++++++++++++++++++++++++++ test/scripts/lib/standard.toy | 23 ++++- 2 files changed, 199 insertions(+), 2 deletions(-) diff --git a/repl/lib_standard.c b/repl/lib_standard.c index ebfb0a3..8d35f50 100644 --- a/repl/lib_standard.c +++ b/repl/lib_standard.c @@ -583,6 +583,180 @@ static int nativeLerp(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) return 1; } +static int nativeToRad(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + if (arguments->count != 1) { + interpreter->errorOutput("Incorrect number of arguments to toRad\n"); + return -1; + } + + //get the argument + Toy_Literal degreesLiteral = Toy_popLiteralArray(arguments); + + //parse the argument (if it's an identifier) + Toy_Literal degreesLiteralIdn = degreesLiteral; + if (TOY_IS_IDENTIFIER(degreesLiteral) && Toy_parseIdentifierToValue(interpreter, °reesLiteral)) { + Toy_freeLiteral(degreesLiteralIdn); + } + + //check the argument type + if (!(TOY_IS_INTEGER(degreesLiteral) || TOY_IS_FLOAT(degreesLiteral))) { + interpreter->errorOutput("Incorrect argument type passed to toRad\n"); + Toy_freeLiteral(degreesLiteral); + return -1; + } + + // cast int to float to handle all types of numbers + float degrees = TOY_IS_INTEGER(degreesLiteral)? TOY_AS_INTEGER(degreesLiteral) : TOY_AS_FLOAT(degreesLiteral); + + const float PI = 3.14159265358979323846f; + + float result = degrees * (PI / 180.0); + + //return the result + Toy_Literal resultLiteral = TOY_TO_FLOAT_LITERAL(result); + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); + + //cleanup + Toy_freeLiteral(resultLiteral); + Toy_freeLiteral(degreesLiteral); + + return 1; +} + +static int nativeToDeg(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + if (arguments->count != 1) { + interpreter->errorOutput("Incorrect number of arguments to toDeg\n"); + return -1; + } + + //get the argument + Toy_Literal radiansLiteral = Toy_popLiteralArray(arguments); + + //parse the argument (if it's an identifier) + Toy_Literal radiansLiteralIdn = radiansLiteral; + if (TOY_IS_IDENTIFIER(radiansLiteral) && Toy_parseIdentifierToValue(interpreter, &radiansLiteral)) { + Toy_freeLiteral(radiansLiteralIdn); + } + + //check the argument type + if (!(TOY_IS_INTEGER(radiansLiteral) || TOY_IS_FLOAT(radiansLiteral))) { + interpreter->errorOutput("Incorrect argument type passed to toDeg\n"); + Toy_freeLiteral(radiansLiteral); + return -1; + } + + // cast int to float to handle all types of numbers + float radians = TOY_IS_INTEGER(radiansLiteral)? TOY_AS_INTEGER(radiansLiteral) : TOY_AS_FLOAT(radiansLiteral); + + const float PI = 3.14159265358979323846f; + + float result = radians * (180.0 / PI); + + //return the result + Toy_Literal resultLiteral = TOY_TO_FLOAT_LITERAL(result); + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); + + //cleanup + Toy_freeLiteral(resultLiteral); + Toy_freeLiteral(radiansLiteral); + + return 1; +} + +static int nativeSin(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + if (arguments->count != 1) { + interpreter->errorOutput("Incorrect number of arguments to sin\n"); + return -1; + } + + //get the argument + Toy_Literal valueLiteral = Toy_popLiteralArray(arguments); + + //parse the argument (if it's an identifier) + Toy_Literal valueLiteralIdn = valueLiteral; + if (TOY_IS_IDENTIFIER(valueLiteral) && Toy_parseIdentifierToValue(interpreter, &valueLiteral)) { + Toy_freeLiteral(valueLiteralIdn); + } + + //check the argument type + if (!(TOY_IS_INTEGER(valueLiteral) || TOY_IS_FLOAT(valueLiteral))) { + interpreter->errorOutput("Incorrect argument type passed to lerp\n"); + Toy_freeLiteral(valueLiteral); + return -1; + } + + // cast ints to floats to handle all types of numbers + float value = TOY_IS_INTEGER(valueLiteral)? TOY_AS_INTEGER(valueLiteral) : TOY_AS_FLOAT(valueLiteral); + + // calculate the result + // using Taylor series approximation + float result = 0; + float power = value; + int sign = 1; + + for (int n = 1; n <= 10; n += 2) { + result += sign * power / n; + power = power * value * value; + sign = -sign; + } + + //return the result + Toy_Literal resultLiteral = TOY_TO_FLOAT_LITERAL(result); + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); + + //cleanup + Toy_freeLiteral(resultLiteral); + + return 1; +} + +static int nativeCos(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + if (arguments->count != 1) { + interpreter->errorOutput("Incorrect number of arguments to sin\n"); + return -1; + } + + //get the argument + Toy_Literal valueLiteral = Toy_popLiteralArray(arguments); + + //parse the argument (if it's an identifier) + Toy_Literal valueLiteralIdn = valueLiteral; + if (TOY_IS_IDENTIFIER(valueLiteral) && Toy_parseIdentifierToValue(interpreter, &valueLiteral)) { + Toy_freeLiteral(valueLiteralIdn); + } + + //check the argument type + if (!(TOY_IS_INTEGER(valueLiteral) || TOY_IS_FLOAT(valueLiteral))) { + interpreter->errorOutput("Incorrect argument type passed to lerp\n"); + Toy_freeLiteral(valueLiteral); + return -1; + } + + // cast ints to floats to handle all types of numbers + float value = TOY_IS_INTEGER(valueLiteral)? TOY_AS_INTEGER(valueLiteral) : TOY_AS_FLOAT(valueLiteral); + + // calculate the result + // using Taylor series approximation + float result = 0; + float power = value; + int sign = 1; + + for (int n = 1; n <= 10; n += 2) { + result += sign * power / n; + power = power * value * value; + sign = -sign; + } + + //return the result + Toy_Literal resultLiteral = TOY_TO_FLOAT_LITERAL(result); + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); + + //cleanup + Toy_freeLiteral(resultLiteral); + + return 1; +} + static int nativeConcat(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { //no arguments if (arguments->count != 2) { @@ -2148,6 +2322,10 @@ int Toy_hookStandard(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_L {"normalize", nativeNormalize}, {"clamp", nativeClamp}, {"lerp", nativeLerp}, + {"toRad", nativeToRad}, + {"toDeg", nativeToDeg}, + // {"sin", nativeSin}, + // {"cos", nativeCos}, //compound utils {"concat", nativeConcat}, //array, dictionary, string diff --git a/test/scripts/lib/standard.toy b/test/scripts/lib/standard.toy index ab50ff4..4233bd3 100644 --- a/test/scripts/lib/standard.toy +++ b/test/scripts/lib/standard.toy @@ -143,8 +143,8 @@ import standard; assert clamp(0.0, 1.0, 5.0) == 1, "clamp(0.0, 1.0, 5.0) failed"; assert clamp(10.0, 1.0, 5.0) == 5, "clamp(10.0, 1.0, 5.0) failed"; - assert typeof clamp(10, 1, 5) == int, "typeof clamp(10, 1, 5) == int failed"; - assert typeof clamp(10.0, 1, 5) == int, "typeof clamp(10.0, 1, 5) == int failed"; + // assert typeof clamp(10, 1, 5) == int, "typeof clamp(10, 1, 5) == int failed"; + // assert typeof clamp(10.0, 1, 5) == int, "typeof clamp(10.0, 1, 5) == int failed"; assert typeof clamp(10, 1, 5.0) == float, "typeof clamp(10, 1, 5.0) == float failed"; } @@ -158,6 +158,25 @@ import standard; } +// test toRad +{ + var PI: float const = 3.14159265358979323846; + + assert toRad(0) == 0, "toRad 0° failed"; + assert toRad(180) == PI, "toRad 180° failed"; + assert toRad(360) == 2 * PI, "toRad 360° failed"; +} + +// test toDeg +{ + var PI: float const = 3.14159265358979323846; + + assert toDeg(0) == 0, "toDeg 0 failed"; + assert toDeg(PI) == 180, "toDeg π failed"; + assert toDeg(2 * PI) == 360, "toDeg 2π failed"; +} + + //test concat { //test array concat From c43310f316d35e37d7617dd8cb0a99f319e12e48 Mon Sep 17 00:00:00 2001 From: Add00 Date: Mon, 31 Jul 2023 13:13:10 -0400 Subject: [PATCH 02/10] Code clean up --- repl/lib_standard.c | 8 +++++--- test/scripts/lib/standard.toy | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/repl/lib_standard.c b/repl/lib_standard.c index 8d35f50..1c261b1 100644 --- a/repl/lib_standard.c +++ b/repl/lib_standard.c @@ -706,6 +706,7 @@ static int nativeSin(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) //cleanup Toy_freeLiteral(resultLiteral); + Toy_freeLiteral(valueLiteral); return 1; } @@ -741,9 +742,9 @@ static int nativeCos(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) float power = value; int sign = 1; - for (int n = 1; n <= 10; n += 2) { - result += sign * power / n; - power = power * value * value; + for (int n = 0; n <= 10; n += 2) { + result += sign * power; + power = power * value * value / ((n + 1) * (n + 2)); sign = -sign; } @@ -753,6 +754,7 @@ static int nativeCos(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) //cleanup Toy_freeLiteral(resultLiteral); + Toy_freeLiteral(valueLiteral); return 1; } diff --git a/test/scripts/lib/standard.toy b/test/scripts/lib/standard.toy index 4233bd3..c068468 100644 --- a/test/scripts/lib/standard.toy +++ b/test/scripts/lib/standard.toy @@ -143,8 +143,8 @@ import standard; assert clamp(0.0, 1.0, 5.0) == 1, "clamp(0.0, 1.0, 5.0) failed"; assert clamp(10.0, 1.0, 5.0) == 5, "clamp(10.0, 1.0, 5.0) failed"; - // assert typeof clamp(10, 1, 5) == int, "typeof clamp(10, 1, 5) == int failed"; - // assert typeof clamp(10.0, 1, 5) == int, "typeof clamp(10.0, 1, 5) == int failed"; + assert typeof clamp(10, 1, 5) == int, "typeof clamp(10, 1, 5) == int failed"; + assert typeof clamp(10.0, 1, 5) == int, "typeof clamp(10.0, 1, 5) == int failed"; assert typeof clamp(10, 1, 5.0) == float, "typeof clamp(10, 1, 5.0) == float failed"; } From 027d093e2190c14a81f66c34c14d5dfaa624ad6d Mon Sep 17 00:00:00 2001 From: Add00 Date: Mon, 31 Jul 2023 13:56:06 -0400 Subject: [PATCH 03/10] Added math constants for pi and e --- repl/lib_standard.c | 60 +++++++++++++++++++++++++++++++---- test/scripts/lib/standard.toy | 5 --- 2 files changed, 54 insertions(+), 11 deletions(-) diff --git a/repl/lib_standard.c b/repl/lib_standard.c index 356564b..8c1a289 100644 --- a/repl/lib_standard.c +++ b/repl/lib_standard.c @@ -7,6 +7,9 @@ #include #include +#define STD_MATH_PI 3.14159265358979323846f +#define STD_MATH_E 2.71828182845904523536f + static int nativeClock(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { //no arguments if (arguments->count != 0) { @@ -608,9 +611,7 @@ static int nativeToRad(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments // cast int to float to handle all types of numbers float degrees = TOY_IS_INTEGER(degreesLiteral)? TOY_AS_INTEGER(degreesLiteral) : TOY_AS_FLOAT(degreesLiteral); - const float PI = 3.14159265358979323846f; - - float result = degrees * (PI / 180.0); + float result = degrees * (STD_MATH_PI / 180.0); //return the result Toy_Literal resultLiteral = TOY_TO_FLOAT_LITERAL(result); @@ -648,9 +649,7 @@ static int nativeToDeg(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments // cast int to float to handle all types of numbers float radians = TOY_IS_INTEGER(radiansLiteral)? TOY_AS_INTEGER(radiansLiteral) : TOY_AS_FLOAT(radiansLiteral); - const float PI = 3.14159265358979323846f; - - float result = radians * (180.0 / PI); + float result = radians * (180.0 / STD_MATH_PI); //return the result Toy_Literal resultLiteral = TOY_TO_FLOAT_LITERAL(result); @@ -2352,6 +2351,16 @@ int Toy_hookStandard(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_L {NULL, NULL} }; + // math constants + Toy_Literal piKeyLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString("PI")); + Toy_Literal piIdentifierLiteral = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefString("PI")); + Toy_Literal piLiteral = TOY_TO_FLOAT_LITERAL(STD_MATH_PI); + + Toy_Literal eKeyLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString("E")); + Toy_Literal eIdentifierLiteral = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefString("E")); + Toy_Literal eLiteral = TOY_TO_FLOAT_LITERAL(STD_MATH_PI); + + //store the library in an aliased dictionary if (!TOY_IS_NULL(alias)) { //make sure the name isn't taken @@ -2376,6 +2385,9 @@ int Toy_hookStandard(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_L Toy_freeLiteral(func); } + Toy_setLiteralDictionary(dictionary, piKeyLiteral, piLiteral); + Toy_setLiteralDictionary(dictionary, eKeyLiteral, eLiteral); + //build the type Toy_Literal type = TOY_TO_TYPE_LITERAL(TOY_LITERAL_DICTIONARY, true); Toy_Literal strType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_STRING, true); @@ -2391,6 +2403,13 @@ int Toy_hookStandard(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_L //cleanup Toy_freeLiteral(dict); Toy_freeLiteral(type); + Toy_freeLiteral(piKeyLiteral); + Toy_freeLiteral(piIdentifierLiteral); + Toy_freeLiteral(piLiteral); + Toy_freeLiteral(eKeyLiteral); + Toy_freeLiteral(eIdentifierLiteral); + Toy_freeLiteral(eLiteral); + return 0; } @@ -2399,5 +2418,34 @@ int Toy_hookStandard(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_L Toy_injectNativeFn(interpreter, natives[i].name, natives[i].fn); } + if (Toy_isDeclaredScopeVariable(interpreter->scope, piKeyLiteral)) { + interpreter->errorOutput("Can't override an existing variable\n"); + + // cleanup + Toy_freeLiteral(alias); + Toy_freeLiteral(piKeyLiteral); + + return -1; + } + + Toy_Literal floatType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_FLOAT, false); + + // pi + Toy_declareScopeVariable(interpreter->scope, piIdentifierLiteral, floatType); + Toy_setScopeVariable(interpreter->scope, piIdentifierLiteral, piLiteral, false); + + // e + Toy_declareScopeVariable(interpreter->scope, eIdentifierLiteral, floatType); + Toy_setScopeVariable(interpreter->scope, eIdentifierLiteral, eLiteral, false); + + // cleanup + Toy_freeLiteral(floatType); + Toy_freeLiteral(piKeyLiteral); + Toy_freeLiteral(piIdentifierLiteral); + Toy_freeLiteral(piLiteral); + Toy_freeLiteral(eKeyLiteral); + Toy_freeLiteral(eIdentifierLiteral); + Toy_freeLiteral(eLiteral); + return 0; } diff --git a/test/scripts/lib/standard.toy b/test/scripts/lib/standard.toy index c068468..9d4a0b8 100644 --- a/test/scripts/lib/standard.toy +++ b/test/scripts/lib/standard.toy @@ -157,11 +157,8 @@ import standard; assert typeof lerp(0, 10, 0) == float, "typeof lerp result failed"; } - // test toRad { - var PI: float const = 3.14159265358979323846; - assert toRad(0) == 0, "toRad 0° failed"; assert toRad(180) == PI, "toRad 180° failed"; assert toRad(360) == 2 * PI, "toRad 360° failed"; @@ -169,8 +166,6 @@ import standard; // test toDeg { - var PI: float const = 3.14159265358979323846; - assert toDeg(0) == 0, "toDeg 0 failed"; assert toDeg(PI) == 180, "toDeg π failed"; assert toDeg(2 * PI) == 360, "toDeg 2π failed"; From 81fe278c963d82fdac181c3e817e0040a9b694df Mon Sep 17 00:00:00 2001 From: Add00 Date: Mon, 31 Jul 2023 19:02:55 -0400 Subject: [PATCH 04/10] Added partial cos and sine implementations --- repl/lib_standard.c | 75 ++++++++++++++++++----------------- test/scripts/lib/standard.toy | 12 ++++++ 2 files changed, 50 insertions(+), 37 deletions(-) diff --git a/repl/lib_standard.c b/repl/lib_standard.c index 8c1a289..7032050 100644 --- a/repl/lib_standard.c +++ b/repl/lib_standard.c @@ -7,8 +7,9 @@ #include #include -#define STD_MATH_PI 3.14159265358979323846f -#define STD_MATH_E 2.71828182845904523536f +#define STD_MATH_PI 3.14159265358979323846f +#define STD_MATH_E 2.71828182845904523536f +#define STD_MATH_LIMIT 20 static int nativeClock(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { //no arguments @@ -669,34 +670,40 @@ static int nativeSin(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) } //get the argument - Toy_Literal valueLiteral = Toy_popLiteralArray(arguments); + Toy_Literal radiansLiteral = Toy_popLiteralArray(arguments); //parse the argument (if it's an identifier) - Toy_Literal valueLiteralIdn = valueLiteral; - if (TOY_IS_IDENTIFIER(valueLiteral) && Toy_parseIdentifierToValue(interpreter, &valueLiteral)) { - Toy_freeLiteral(valueLiteralIdn); + Toy_Literal radiansLiteralIdn = radiansLiteral; + if (TOY_IS_IDENTIFIER(radiansLiteral) && Toy_parseIdentifierToValue(interpreter, &radiansLiteral)) { + Toy_freeLiteral(radiansLiteralIdn); } //check the argument type - if (!(TOY_IS_INTEGER(valueLiteral) || TOY_IS_FLOAT(valueLiteral))) { - interpreter->errorOutput("Incorrect argument type passed to lerp\n"); - Toy_freeLiteral(valueLiteral); + if (!(TOY_IS_INTEGER(radiansLiteral) || TOY_IS_FLOAT(radiansLiteral))) { + interpreter->errorOutput("Incorrect argument type passed to sin\n"); + Toy_freeLiteral(radiansLiteral); return -1; } // cast ints to floats to handle all types of numbers - float value = TOY_IS_INTEGER(valueLiteral)? TOY_AS_INTEGER(valueLiteral) : TOY_AS_FLOAT(valueLiteral); + float radians = TOY_IS_INTEGER(radiansLiteral)? TOY_AS_INTEGER(radiansLiteral) : TOY_AS_FLOAT(radiansLiteral); // calculate the result // using Taylor series approximation - float result = 0; - float power = value; - int sign = 1; + float result = radians; + float numerator = radians; + float denominator = 1; - for (int n = 1; n <= 10; n += 2) { - result += sign * power / n; - power = power * value * value; - sign = -sign; + for (int i = 1; i <= STD_MATH_LIMIT; i++) { + numerator *= radians * radians; + denominator *= (2 * i) * (2 * i + 1); + + float value = numerator / denominator; + + if (i & 0x01) + result -= value; + else + result += value; } //return the result @@ -705,7 +712,7 @@ static int nativeSin(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) //cleanup Toy_freeLiteral(resultLiteral); - Toy_freeLiteral(valueLiteral); + Toy_freeLiteral(radiansLiteral); return 1; } @@ -717,43 +724,37 @@ static int nativeCos(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) } //get the argument - Toy_Literal valueLiteral = Toy_popLiteralArray(arguments); + Toy_Literal radiansLiteral = Toy_popLiteralArray(arguments); //parse the argument (if it's an identifier) - Toy_Literal valueLiteralIdn = valueLiteral; - if (TOY_IS_IDENTIFIER(valueLiteral) && Toy_parseIdentifierToValue(interpreter, &valueLiteral)) { - Toy_freeLiteral(valueLiteralIdn); + Toy_Literal radiansLiteralIdn = radiansLiteral; + if (TOY_IS_IDENTIFIER(radiansLiteral) && Toy_parseIdentifierToValue(interpreter, &radiansLiteral)) { + Toy_freeLiteral(radiansLiteralIdn); } //check the argument type - if (!(TOY_IS_INTEGER(valueLiteral) || TOY_IS_FLOAT(valueLiteral))) { + if (!(TOY_IS_INTEGER(radiansLiteral) || TOY_IS_FLOAT(radiansLiteral))) { interpreter->errorOutput("Incorrect argument type passed to lerp\n"); - Toy_freeLiteral(valueLiteral); + Toy_freeLiteral(radiansLiteral); return -1; } // cast ints to floats to handle all types of numbers - float value = TOY_IS_INTEGER(valueLiteral)? TOY_AS_INTEGER(valueLiteral) : TOY_AS_FLOAT(valueLiteral); + float radians = TOY_IS_INTEGER(radiansLiteral)? TOY_AS_INTEGER(radiansLiteral) : TOY_AS_FLOAT(radiansLiteral); // calculate the result // using Taylor series approximation - float result = 0; - float power = value; - int sign = 1; - - for (int n = 0; n <= 10; n += 2) { - result += sign * power; - power = power * value * value / ((n + 1) * (n + 2)); - sign = -sign; - } + // TODO + float result = -1; + //return the result Toy_Literal resultLiteral = TOY_TO_FLOAT_LITERAL(result); Toy_pushLiteralArray(&interpreter->stack, resultLiteral); //cleanup Toy_freeLiteral(resultLiteral); - Toy_freeLiteral(valueLiteral); + Toy_freeLiteral(radiansLiteral); return 1; } @@ -2325,8 +2326,8 @@ int Toy_hookStandard(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_L {"lerp", nativeLerp}, {"toRad", nativeToRad}, {"toDeg", nativeToDeg}, - // {"sin", nativeSin}, - // {"cos", nativeCos}, + {"sin", nativeSin}, + {"cos", nativeCos}, //compound utils {"concat", nativeConcat}, //array, dictionary, string diff --git a/test/scripts/lib/standard.toy b/test/scripts/lib/standard.toy index 9d4a0b8..2c9ef6e 100644 --- a/test/scripts/lib/standard.toy +++ b/test/scripts/lib/standard.toy @@ -157,6 +157,7 @@ import standard; assert typeof lerp(0, 10, 0) == float, "typeof lerp result failed"; } + // test toRad { assert toRad(0) == 0, "toRad 0° failed"; @@ -164,6 +165,7 @@ import standard; assert toRad(360) == 2 * PI, "toRad 360° failed"; } + // test toDeg { assert toDeg(0) == 0, "toDeg 0 failed"; @@ -171,6 +173,16 @@ import standard; assert toDeg(2 * PI) == 360, "toDeg 2π failed"; } +// test sin +{ + assert sin(PI) == 0, "sin π failed"; +} + + +// test cos +{ + assert cos(PI) == -1, "cos π failed"; +} //test concat { From e3e9ca7ece8abbb5dde931e03164f09c4b37b295 Mon Sep 17 00:00:00 2001 From: Add00 Date: Mon, 31 Jul 2023 23:31:12 -0400 Subject: [PATCH 05/10] Added math library --- repl/lib_math.c | 604 ++++++++++++++++++++++++++++++++++ repl/lib_math.h | 5 + repl/lib_standard.c | 244 -------------- repl/makefile | 2 +- repl/repl_main.c | 2 + repl/repl_tools.c | 2 + test/makefile | 2 +- test/scripts/lib/math.toy | 27 ++ test/scripts/lib/standard.toy | 26 -- 9 files changed, 642 insertions(+), 272 deletions(-) create mode 100644 repl/lib_math.c create mode 100644 repl/lib_math.h create mode 100644 test/scripts/lib/math.toy diff --git a/repl/lib_math.c b/repl/lib_math.c new file mode 100644 index 0000000..07108a9 --- /dev/null +++ b/repl/lib_math.c @@ -0,0 +1,604 @@ +#include "lib_math.h" + +#include "toy_memory.h" + +#include + +#define LIB_MATH_PI 3.14159265358979323846f +#define LIB_MATH_E 2.71828182845904523536f + +static int nativeMod(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + if (arguments->count != 1) { + interpreter->errorOutput("Incorrect number of arguments to sin\n"); + return -1; + } + + //get the arguments + Toy_Literal xLiteral = Toy_popLiteralArray(arguments); + Toy_Literal yLiteral = Toy_popLiteralArray(arguments); + + //parse the argument (if it's an identifier) + Toy_Literal xLiteralIdn = xLiteral; + if (TOY_IS_IDENTIFIER(xLiteral) && Toy_parseIdentifierToValue(interpreter, &xLiteral)) { + Toy_freeLiteral(xLiteralIdn); + } + + Toy_Literal yLiteralIdn = yLiteral; + if (TOY_IS_IDENTIFIER(yLiteral) && Toy_parseIdentifierToValue(interpreter, &yLiteral)) { + Toy_freeLiteral(yLiteralIdn); + } + + //check the argument types + if (!(TOY_IS_INTEGER(xLiteral) || TOY_IS_FLOAT(xLiteral))) { + interpreter->errorOutput("Incorrect argument type passed to sin\n"); + Toy_freeLiteral(xLiteral); + return -1; + } + + if (!(TOY_IS_INTEGER(yLiteral) || TOY_IS_FLOAT(yLiteral))) { + interpreter->errorOutput("Incorrect argument type passed to sin\n"); + Toy_freeLiteral(yLiteral); + return -1; + } + + // cast ints to floats to handle all types of numbers + float x = TOY_IS_INTEGER(xLiteral)? TOY_AS_INTEGER(xLiteral) : TOY_AS_FLOAT(xLiteral); + float y = TOY_IS_INTEGER(yLiteral)? TOY_AS_INTEGER(yLiteral) : TOY_AS_FLOAT(yLiteral); + + // calculate the result + float result = fmodf(x, y); + + // return the result + Toy_Literal resultLiteral = TOY_TO_FLOAT_LITERAL(result); + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); + + // cleanup + Toy_freeLiteral(resultLiteral); + Toy_freeLiteral(xLiteral); + Toy_freeLiteral(yLiteral); + + return 1; +} + +static int nativePow(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + if (arguments->count != 1) { + interpreter->errorOutput("Incorrect number of arguments to sin\n"); + return -1; + } + + //get the arguments + Toy_Literal xLiteral = Toy_popLiteralArray(arguments); + Toy_Literal yLiteral = Toy_popLiteralArray(arguments); + + //parse the argument (if it's an identifier) + Toy_Literal xLiteralIdn = xLiteral; + if (TOY_IS_IDENTIFIER(xLiteral) && Toy_parseIdentifierToValue(interpreter, &xLiteral)) { + Toy_freeLiteral(xLiteralIdn); + } + + Toy_Literal yLiteralIdn = yLiteral; + if (TOY_IS_IDENTIFIER(yLiteral) && Toy_parseIdentifierToValue(interpreter, &yLiteral)) { + Toy_freeLiteral(yLiteralIdn); + } + + //check the argument types + if (!(TOY_IS_INTEGER(xLiteral) || TOY_IS_FLOAT(xLiteral))) { + interpreter->errorOutput("Incorrect argument type passed to sin\n"); + Toy_freeLiteral(xLiteral); + return -1; + } + + if (!(TOY_IS_INTEGER(yLiteral) || TOY_IS_FLOAT(yLiteral))) { + interpreter->errorOutput("Incorrect argument type passed to sin\n"); + Toy_freeLiteral(yLiteral); + return -1; + } + + // cast ints to floats to handle all types of numbers + float x = TOY_IS_INTEGER(xLiteral)? TOY_AS_INTEGER(xLiteral) : TOY_AS_FLOAT(xLiteral); + float y = TOY_IS_INTEGER(yLiteral)? TOY_AS_INTEGER(yLiteral) : TOY_AS_FLOAT(yLiteral); + + // calculate the result + float result = powf(x, y); + + // return the result + Toy_Literal resultLiteral = TOY_TO_FLOAT_LITERAL(result); + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); + + // cleanup + Toy_freeLiteral(resultLiteral); + Toy_freeLiteral(xLiteral); + Toy_freeLiteral(yLiteral); + + return 1; +} + +static int nativeSqrt(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + if (arguments->count != 1) { + interpreter->errorOutput("Incorrect number of arguments to sin\n"); + return -1; + } + + //get the argument + Toy_Literal xLiteral = Toy_popLiteralArray(arguments); + + //parse the argument (if it's an identifier) + Toy_Literal xLiteralIdn = xLiteral; + if (TOY_IS_IDENTIFIER(xLiteral) && Toy_parseIdentifierToValue(interpreter, &xLiteral)) { + Toy_freeLiteral(xLiteralIdn); + } + + //check the argument type + if (!(TOY_IS_INTEGER(xLiteral) || TOY_IS_FLOAT(xLiteral))) { + interpreter->errorOutput("Incorrect argument type passed to sin\n"); + Toy_freeLiteral(xLiteral); + return -1; + } + + // cast ints to floats to handle all types of numbers + float x = TOY_IS_INTEGER(xLiteral)? TOY_AS_INTEGER(xLiteral) : TOY_AS_FLOAT(xLiteral); + + // calculate the result + float result = sqrtf(x); + + //return the result + Toy_Literal resultLiteral = TOY_TO_FLOAT_LITERAL(result); + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); + + //cleanup + Toy_freeLiteral(resultLiteral); + Toy_freeLiteral(xLiteral); + + return 1; +} + +static int nativeCbrt(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + if (arguments->count != 1) { + interpreter->errorOutput("Incorrect number of arguments to sin\n"); + return -1; + } + + //get the argument + Toy_Literal xLiteral = Toy_popLiteralArray(arguments); + + //parse the argument (if it's an identifier) + Toy_Literal xLiteralIdn = xLiteral; + if (TOY_IS_IDENTIFIER(xLiteral) && Toy_parseIdentifierToValue(interpreter, &xLiteral)) { + Toy_freeLiteral(xLiteralIdn); + } + + //check the argument type + if (!(TOY_IS_INTEGER(xLiteral) || TOY_IS_FLOAT(xLiteral))) { + interpreter->errorOutput("Incorrect argument type passed to sin\n"); + Toy_freeLiteral(xLiteral); + return -1; + } + + // cast ints to floats to handle all types of numbers + float x = TOY_IS_INTEGER(xLiteral)? TOY_AS_INTEGER(xLiteral) : TOY_AS_FLOAT(xLiteral); + + // calculate the result + float result = cbrtf(x); + + //return the result + Toy_Literal resultLiteral = TOY_TO_FLOAT_LITERAL(result); + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); + + //cleanup + Toy_freeLiteral(resultLiteral); + Toy_freeLiteral(xLiteral); + + return 1; +} + +static int nativeHypot(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + if (arguments->count != 1) { + interpreter->errorOutput("Incorrect number of arguments to sin\n"); + return -1; + } + + //get the arguments + Toy_Literal xLiteral = Toy_popLiteralArray(arguments); + Toy_Literal yLiteral = Toy_popLiteralArray(arguments); + + //parse the argument (if it's an identifier) + Toy_Literal xLiteralIdn = xLiteral; + if (TOY_IS_IDENTIFIER(xLiteral) && Toy_parseIdentifierToValue(interpreter, &xLiteral)) { + Toy_freeLiteral(xLiteralIdn); + } + + Toy_Literal yLiteralIdn = yLiteral; + if (TOY_IS_IDENTIFIER(yLiteral) && Toy_parseIdentifierToValue(interpreter, &yLiteral)) { + Toy_freeLiteral(yLiteralIdn); + } + + //check the argument types + if (!(TOY_IS_INTEGER(xLiteral) || TOY_IS_FLOAT(xLiteral))) { + interpreter->errorOutput("Incorrect argument type passed to sin\n"); + Toy_freeLiteral(xLiteral); + return -1; + } + + if (!(TOY_IS_INTEGER(yLiteral) || TOY_IS_FLOAT(yLiteral))) { + interpreter->errorOutput("Incorrect argument type passed to sin\n"); + Toy_freeLiteral(yLiteral); + return -1; + } + + // cast ints to floats to handle all types of numbers + float x = TOY_IS_INTEGER(xLiteral)? TOY_AS_INTEGER(xLiteral) : TOY_AS_FLOAT(xLiteral); + float y = TOY_IS_INTEGER(yLiteral)? TOY_AS_INTEGER(yLiteral) : TOY_AS_FLOAT(yLiteral); + + // calculate the result + float result = hypotf(x, y); + + // return the result + Toy_Literal resultLiteral = TOY_TO_FLOAT_LITERAL(result); + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); + + // cleanup + Toy_freeLiteral(resultLiteral); + Toy_freeLiteral(xLiteral); + Toy_freeLiteral(yLiteral); + + return 1; +} + +static int nativeToRad(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + if (arguments->count != 1) { + interpreter->errorOutput("Incorrect number of arguments to toRad\n"); + return -1; + } + + //get the argument + Toy_Literal degreesLiteral = Toy_popLiteralArray(arguments); + + //parse the argument (if it's an identifier) + Toy_Literal degreesLiteralIdn = degreesLiteral; + if (TOY_IS_IDENTIFIER(degreesLiteral) && Toy_parseIdentifierToValue(interpreter, °reesLiteral)) { + Toy_freeLiteral(degreesLiteralIdn); + } + + //check the argument type + if (!(TOY_IS_INTEGER(degreesLiteral) || TOY_IS_FLOAT(degreesLiteral))) { + interpreter->errorOutput("Incorrect argument type passed to toRad\n"); + Toy_freeLiteral(degreesLiteral); + return -1; + } + + // cast int to float to handle all types of numbers + float degrees = TOY_IS_INTEGER(degreesLiteral)? TOY_AS_INTEGER(degreesLiteral) : TOY_AS_FLOAT(degreesLiteral); + + float result = degrees * (LIB_MATH_PI / 180.0); + + //return the result + Toy_Literal resultLiteral = TOY_TO_FLOAT_LITERAL(result); + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); + + //cleanup + Toy_freeLiteral(resultLiteral); + Toy_freeLiteral(degreesLiteral); + + return 1; +} + +static int nativeToDeg(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + if (arguments->count != 1) { + interpreter->errorOutput("Incorrect number of arguments to toDeg\n"); + return -1; + } + + //get the argument + Toy_Literal radiansLiteral = Toy_popLiteralArray(arguments); + + //parse the argument (if it's an identifier) + Toy_Literal radiansLiteralIdn = radiansLiteral; + if (TOY_IS_IDENTIFIER(radiansLiteral) && Toy_parseIdentifierToValue(interpreter, &radiansLiteral)) { + Toy_freeLiteral(radiansLiteralIdn); + } + + //check the argument type + if (!(TOY_IS_INTEGER(radiansLiteral) || TOY_IS_FLOAT(radiansLiteral))) { + interpreter->errorOutput("Incorrect argument type passed to toDeg\n"); + Toy_freeLiteral(radiansLiteral); + return -1; + } + + // cast int to float to handle all types of numbers + float radians = TOY_IS_INTEGER(radiansLiteral)? TOY_AS_INTEGER(radiansLiteral) : TOY_AS_FLOAT(radiansLiteral); + + float result = radians * (180.0 / LIB_MATH_PI); + + //return the result + Toy_Literal resultLiteral = TOY_TO_FLOAT_LITERAL(result); + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); + + //cleanup + Toy_freeLiteral(resultLiteral); + Toy_freeLiteral(radiansLiteral); + + return 1; +} + +static int nativeSin(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + if (arguments->count != 1) { + interpreter->errorOutput("Incorrect number of arguments to sin\n"); + return -1; + } + + //get the argument + Toy_Literal radiansLiteral = Toy_popLiteralArray(arguments); + + //parse the argument (if it's an identifier) + Toy_Literal radiansLiteralIdn = radiansLiteral; + if (TOY_IS_IDENTIFIER(radiansLiteral) && Toy_parseIdentifierToValue(interpreter, &radiansLiteral)) { + Toy_freeLiteral(radiansLiteralIdn); + } + + //check the argument type + if (!(TOY_IS_INTEGER(radiansLiteral) || TOY_IS_FLOAT(radiansLiteral))) { + interpreter->errorOutput("Incorrect argument type passed to sin\n"); + Toy_freeLiteral(radiansLiteral); + return -1; + } + + // cast ints to floats to handle all types of numbers + float radians = TOY_IS_INTEGER(radiansLiteral)? TOY_AS_INTEGER(radiansLiteral) : TOY_AS_FLOAT(radiansLiteral); + + // calculate the result + float result = sinf(radians); + + //return the result + Toy_Literal resultLiteral = TOY_TO_FLOAT_LITERAL(result); + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); + + //cleanup + Toy_freeLiteral(resultLiteral); + Toy_freeLiteral(radiansLiteral); + + return 1; +} + +static int nativeCos(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + if (arguments->count != 1) { + interpreter->errorOutput("Incorrect number of arguments to cos\n"); + return -1; + } + + //get the argument + Toy_Literal radiansLiteral = Toy_popLiteralArray(arguments); + + //parse the argument (if it's an identifier) + Toy_Literal radiansLiteralIdn = radiansLiteral; + if (TOY_IS_IDENTIFIER(radiansLiteral) && Toy_parseIdentifierToValue(interpreter, &radiansLiteral)) { + Toy_freeLiteral(radiansLiteralIdn); + } + + //check the argument type + if (!(TOY_IS_INTEGER(radiansLiteral) || TOY_IS_FLOAT(radiansLiteral))) { + interpreter->errorOutput("Incorrect argument type passed to cos\n"); + Toy_freeLiteral(radiansLiteral); + return -1; + } + + // cast ints to floats to handle all types of numbers + float radians = TOY_IS_INTEGER(radiansLiteral)? TOY_AS_INTEGER(radiansLiteral) : TOY_AS_FLOAT(radiansLiteral); + + // calculate the result + float result = cosf(radians); + + //return the result + Toy_Literal resultLiteral = TOY_TO_FLOAT_LITERAL(result); + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); + + //cleanup + Toy_freeLiteral(resultLiteral); + Toy_freeLiteral(radiansLiteral); + + return 1; +} + +static int nativeTan(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + if (arguments->count != 1) { + interpreter->errorOutput("Incorrect number of arguments to tan\n"); + return -1; + } + + //get the argument + Toy_Literal radiansLiteral = Toy_popLiteralArray(arguments); + + //parse the argument (if it's an identifier) + Toy_Literal radiansLiteralIdn = radiansLiteral; + if (TOY_IS_IDENTIFIER(radiansLiteral) && Toy_parseIdentifierToValue(interpreter, &radiansLiteral)) { + Toy_freeLiteral(radiansLiteralIdn); + } + + //check the argument type + if (!(TOY_IS_INTEGER(radiansLiteral) || TOY_IS_FLOAT(radiansLiteral))) { + interpreter->errorOutput("Incorrect argument type passed to tan\n"); + Toy_freeLiteral(radiansLiteral); + return -1; + } + + // cast ints to floats to handle all types of numbers + float radians = TOY_IS_INTEGER(radiansLiteral)? TOY_AS_INTEGER(radiansLiteral) : TOY_AS_FLOAT(radiansLiteral); + + // calculate the result + float result = tanf(radians); + + //return the result + Toy_Literal resultLiteral = TOY_TO_FLOAT_LITERAL(result); + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); + + //cleanup + Toy_freeLiteral(resultLiteral); + Toy_freeLiteral(radiansLiteral); + + return 1; +} + +static int nativeTan(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + if (arguments->count != 1) { + interpreter->errorOutput("Incorrect number of arguments to tan\n"); + return -1; + } + + //get the argument + Toy_Literal radiansLiteral = Toy_popLiteralArray(arguments); + + //parse the argument (if it's an identifier) + Toy_Literal radiansLiteralIdn = radiansLiteral; + if (TOY_IS_IDENTIFIER(radiansLiteral) && Toy_parseIdentifierToValue(interpreter, &radiansLiteral)) { + Toy_freeLiteral(radiansLiteralIdn); + } + + //check the argument type + if (!(TOY_IS_INTEGER(radiansLiteral) || TOY_IS_FLOAT(radiansLiteral))) { + interpreter->errorOutput("Incorrect argument type passed to tan\n"); + Toy_freeLiteral(radiansLiteral); + return -1; + } + + // cast ints to floats to handle all types of numbers + float radians = TOY_IS_INTEGER(radiansLiteral)? TOY_AS_INTEGER(radiansLiteral) : TOY_AS_FLOAT(radiansLiteral); + + // calculate the result + float result = tanf(radians); + + //return the result + Toy_Literal resultLiteral = TOY_TO_FLOAT_LITERAL(result); + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); + + //cleanup + Toy_freeLiteral(resultLiteral); + Toy_freeLiteral(radiansLiteral); + + return 1; +} + +//call the hook +typedef struct Natives { + char* name; + Toy_NativeFn fn; +} Natives; + +int Toy_hookMath(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias) { + //build the natives list + Natives natives[] = { + // Common + {"mod", nativeMod}, + + // Power + {"pow", nativePow}, + {"sqrt", nativeSqrt}, + {"cbrt", nativeCbrt}, + {"hypot", nativeHypot}, + + // Trigonometric + {"toRad", nativeToRad}, + {"toDeg", nativeToDeg}, + {"sin", nativeSin}, + {"cos", nativeCos}, + {"tan", nativeTan}, + + {NULL, NULL} + }; + + // math constants + Toy_Literal piKeyLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString("PI")); + Toy_Literal piIdentifierLiteral = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefString("PI")); + Toy_Literal piLiteral = TOY_TO_FLOAT_LITERAL(LIB_MATH_PI); + + Toy_Literal eKeyLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString("E")); + Toy_Literal eIdentifierLiteral = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefString("E")); + Toy_Literal eLiteral = TOY_TO_FLOAT_LITERAL(LIB_MATH_E); + + + //store the library in an aliased dictionary + if (!TOY_IS_NULL(alias)) { + //make sure the name isn't taken + if (Toy_isDeclaredScopeVariable(interpreter->scope, alias)) { + interpreter->errorOutput("Can't override an existing variable\n"); + Toy_freeLiteral(alias); + return -1; + } + + //create the dictionary to load up with functions + Toy_LiteralDictionary* dictionary = TOY_ALLOCATE(Toy_LiteralDictionary, 1); + Toy_initLiteralDictionary(dictionary); + + //load the dict with functions + for (int i = 0; natives[i].name; i++) { + Toy_Literal name = TOY_TO_STRING_LITERAL(Toy_createRefString(natives[i].name)); + Toy_Literal func = TOY_TO_FUNCTION_NATIVE_LITERAL(natives[i].fn); + + Toy_setLiteralDictionary(dictionary, name, func); + + Toy_freeLiteral(name); + Toy_freeLiteral(func); + } + + Toy_setLiteralDictionary(dictionary, piKeyLiteral, piLiteral); + Toy_setLiteralDictionary(dictionary, eKeyLiteral, eLiteral); + + + //build the type + Toy_Literal type = TOY_TO_TYPE_LITERAL(TOY_LITERAL_DICTIONARY, true); + Toy_Literal strType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_STRING, true); + Toy_Literal fnType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_FUNCTION_NATIVE, true); + TOY_TYPE_PUSH_SUBTYPE(&type, strType); + TOY_TYPE_PUSH_SUBTYPE(&type, fnType); + + //set scope + Toy_Literal dict = TOY_TO_DICTIONARY_LITERAL(dictionary); + Toy_declareScopeVariable(interpreter->scope, alias, type); + Toy_setScopeVariable(interpreter->scope, alias, dict, false); + + //cleanup + Toy_freeLiteral(dict); + Toy_freeLiteral(type); + return 0; + } + + //default + for (int i = 0; natives[i].name; i++) { + Toy_injectNativeFn(interpreter, natives[i].name, natives[i].fn); + } + + if ( + Toy_isDeclaredScopeVariable(interpreter->scope, piKeyLiteral) || + Toy_isDeclaredScopeVariable(interpreter->scope, eKeyLiteral) + ) { + interpreter->errorOutput("Can't override an existing variable\n"); + + // cleanup + Toy_freeLiteral(alias); + Toy_freeLiteral(piIdentifierLiteral); + Toy_freeLiteral(piKeyLiteral); + Toy_freeLiteral(eIdentifierLiteral); + Toy_freeLiteral(eKeyLiteral); + + return -1; + } + + Toy_Literal floatType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_FLOAT, false); + + // pi + Toy_declareScopeVariable(interpreter->scope, piIdentifierLiteral, floatType); + Toy_setScopeVariable(interpreter->scope, piIdentifierLiteral, piLiteral, false); + + // e + Toy_declareScopeVariable(interpreter->scope, eIdentifierLiteral, floatType); + Toy_setScopeVariable(interpreter->scope, eIdentifierLiteral, eLiteral, false); + + // cleanup + Toy_freeLiteral(floatType); + Toy_freeLiteral(piKeyLiteral); + Toy_freeLiteral(piIdentifierLiteral); + Toy_freeLiteral(piLiteral); + Toy_freeLiteral(eKeyLiteral); + Toy_freeLiteral(eIdentifierLiteral); + Toy_freeLiteral(eLiteral); + + return 0; +} diff --git a/repl/lib_math.h b/repl/lib_math.h new file mode 100644 index 0000000..8021100 --- /dev/null +++ b/repl/lib_math.h @@ -0,0 +1,5 @@ +#pragma once + +#include "toy_interpreter.h" + +int Toy_hookMath(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias); diff --git a/repl/lib_standard.c b/repl/lib_standard.c index 7032050..162011f 100644 --- a/repl/lib_standard.c +++ b/repl/lib_standard.c @@ -7,10 +7,6 @@ #include #include -#define STD_MATH_PI 3.14159265358979323846f -#define STD_MATH_E 2.71828182845904523536f -#define STD_MATH_LIMIT 20 - static int nativeClock(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { //no arguments if (arguments->count != 0) { @@ -587,178 +583,6 @@ static int nativeLerp(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) return 1; } -static int nativeToRad(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { - if (arguments->count != 1) { - interpreter->errorOutput("Incorrect number of arguments to toRad\n"); - return -1; - } - - //get the argument - Toy_Literal degreesLiteral = Toy_popLiteralArray(arguments); - - //parse the argument (if it's an identifier) - Toy_Literal degreesLiteralIdn = degreesLiteral; - if (TOY_IS_IDENTIFIER(degreesLiteral) && Toy_parseIdentifierToValue(interpreter, °reesLiteral)) { - Toy_freeLiteral(degreesLiteralIdn); - } - - //check the argument type - if (!(TOY_IS_INTEGER(degreesLiteral) || TOY_IS_FLOAT(degreesLiteral))) { - interpreter->errorOutput("Incorrect argument type passed to toRad\n"); - Toy_freeLiteral(degreesLiteral); - return -1; - } - - // cast int to float to handle all types of numbers - float degrees = TOY_IS_INTEGER(degreesLiteral)? TOY_AS_INTEGER(degreesLiteral) : TOY_AS_FLOAT(degreesLiteral); - - float result = degrees * (STD_MATH_PI / 180.0); - - //return the result - Toy_Literal resultLiteral = TOY_TO_FLOAT_LITERAL(result); - Toy_pushLiteralArray(&interpreter->stack, resultLiteral); - - //cleanup - Toy_freeLiteral(resultLiteral); - Toy_freeLiteral(degreesLiteral); - - return 1; -} - -static int nativeToDeg(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { - if (arguments->count != 1) { - interpreter->errorOutput("Incorrect number of arguments to toDeg\n"); - return -1; - } - - //get the argument - Toy_Literal radiansLiteral = Toy_popLiteralArray(arguments); - - //parse the argument (if it's an identifier) - Toy_Literal radiansLiteralIdn = radiansLiteral; - if (TOY_IS_IDENTIFIER(radiansLiteral) && Toy_parseIdentifierToValue(interpreter, &radiansLiteral)) { - Toy_freeLiteral(radiansLiteralIdn); - } - - //check the argument type - if (!(TOY_IS_INTEGER(radiansLiteral) || TOY_IS_FLOAT(radiansLiteral))) { - interpreter->errorOutput("Incorrect argument type passed to toDeg\n"); - Toy_freeLiteral(radiansLiteral); - return -1; - } - - // cast int to float to handle all types of numbers - float radians = TOY_IS_INTEGER(radiansLiteral)? TOY_AS_INTEGER(radiansLiteral) : TOY_AS_FLOAT(radiansLiteral); - - float result = radians * (180.0 / STD_MATH_PI); - - //return the result - Toy_Literal resultLiteral = TOY_TO_FLOAT_LITERAL(result); - Toy_pushLiteralArray(&interpreter->stack, resultLiteral); - - //cleanup - Toy_freeLiteral(resultLiteral); - Toy_freeLiteral(radiansLiteral); - - return 1; -} - -static int nativeSin(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { - if (arguments->count != 1) { - interpreter->errorOutput("Incorrect number of arguments to sin\n"); - return -1; - } - - //get the argument - Toy_Literal radiansLiteral = Toy_popLiteralArray(arguments); - - //parse the argument (if it's an identifier) - Toy_Literal radiansLiteralIdn = radiansLiteral; - if (TOY_IS_IDENTIFIER(radiansLiteral) && Toy_parseIdentifierToValue(interpreter, &radiansLiteral)) { - Toy_freeLiteral(radiansLiteralIdn); - } - - //check the argument type - if (!(TOY_IS_INTEGER(radiansLiteral) || TOY_IS_FLOAT(radiansLiteral))) { - interpreter->errorOutput("Incorrect argument type passed to sin\n"); - Toy_freeLiteral(radiansLiteral); - return -1; - } - - // cast ints to floats to handle all types of numbers - float radians = TOY_IS_INTEGER(radiansLiteral)? TOY_AS_INTEGER(radiansLiteral) : TOY_AS_FLOAT(radiansLiteral); - - // calculate the result - // using Taylor series approximation - float result = radians; - float numerator = radians; - float denominator = 1; - - for (int i = 1; i <= STD_MATH_LIMIT; i++) { - numerator *= radians * radians; - denominator *= (2 * i) * (2 * i + 1); - - float value = numerator / denominator; - - if (i & 0x01) - result -= value; - else - result += value; - } - - //return the result - Toy_Literal resultLiteral = TOY_TO_FLOAT_LITERAL(result); - Toy_pushLiteralArray(&interpreter->stack, resultLiteral); - - //cleanup - Toy_freeLiteral(resultLiteral); - Toy_freeLiteral(radiansLiteral); - - return 1; -} - -static int nativeCos(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { - if (arguments->count != 1) { - interpreter->errorOutput("Incorrect number of arguments to sin\n"); - return -1; - } - - //get the argument - Toy_Literal radiansLiteral = Toy_popLiteralArray(arguments); - - //parse the argument (if it's an identifier) - Toy_Literal radiansLiteralIdn = radiansLiteral; - if (TOY_IS_IDENTIFIER(radiansLiteral) && Toy_parseIdentifierToValue(interpreter, &radiansLiteral)) { - Toy_freeLiteral(radiansLiteralIdn); - } - - //check the argument type - if (!(TOY_IS_INTEGER(radiansLiteral) || TOY_IS_FLOAT(radiansLiteral))) { - interpreter->errorOutput("Incorrect argument type passed to lerp\n"); - Toy_freeLiteral(radiansLiteral); - return -1; - } - - // cast ints to floats to handle all types of numbers - float radians = TOY_IS_INTEGER(radiansLiteral)? TOY_AS_INTEGER(radiansLiteral) : TOY_AS_FLOAT(radiansLiteral); - - // calculate the result - // using Taylor series approximation - - // TODO - float result = -1; - - //return the result - Toy_Literal resultLiteral = TOY_TO_FLOAT_LITERAL(result); - Toy_pushLiteralArray(&interpreter->stack, resultLiteral); - - //cleanup - Toy_freeLiteral(resultLiteral); - Toy_freeLiteral(radiansLiteral); - - return 1; -} - static int nativeConcat(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { //no arguments if (arguments->count != 2) { @@ -2324,10 +2148,6 @@ int Toy_hookStandard(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_L {"normalize", nativeNormalize}, {"clamp", nativeClamp}, {"lerp", nativeLerp}, - {"toRad", nativeToRad}, - {"toDeg", nativeToDeg}, - {"sin", nativeSin}, - {"cos", nativeCos}, //compound utils {"concat", nativeConcat}, //array, dictionary, string @@ -2352,16 +2172,6 @@ int Toy_hookStandard(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_L {NULL, NULL} }; - // math constants - Toy_Literal piKeyLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString("PI")); - Toy_Literal piIdentifierLiteral = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefString("PI")); - Toy_Literal piLiteral = TOY_TO_FLOAT_LITERAL(STD_MATH_PI); - - Toy_Literal eKeyLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString("E")); - Toy_Literal eIdentifierLiteral = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefString("E")); - Toy_Literal eLiteral = TOY_TO_FLOAT_LITERAL(STD_MATH_PI); - - //store the library in an aliased dictionary if (!TOY_IS_NULL(alias)) { //make sure the name isn't taken @@ -2386,31 +2196,6 @@ int Toy_hookStandard(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_L Toy_freeLiteral(func); } - Toy_setLiteralDictionary(dictionary, piKeyLiteral, piLiteral); - Toy_setLiteralDictionary(dictionary, eKeyLiteral, eLiteral); - - //build the type - Toy_Literal type = TOY_TO_TYPE_LITERAL(TOY_LITERAL_DICTIONARY, true); - Toy_Literal strType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_STRING, true); - Toy_Literal fnType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_FUNCTION_NATIVE, true); - TOY_TYPE_PUSH_SUBTYPE(&type, strType); - TOY_TYPE_PUSH_SUBTYPE(&type, fnType); - - //set scope - Toy_Literal dict = TOY_TO_DICTIONARY_LITERAL(dictionary); - Toy_declareScopeVariable(interpreter->scope, alias, type); - Toy_setScopeVariable(interpreter->scope, alias, dict, false); - - //cleanup - Toy_freeLiteral(dict); - Toy_freeLiteral(type); - Toy_freeLiteral(piKeyLiteral); - Toy_freeLiteral(piIdentifierLiteral); - Toy_freeLiteral(piLiteral); - Toy_freeLiteral(eKeyLiteral); - Toy_freeLiteral(eIdentifierLiteral); - Toy_freeLiteral(eLiteral); - return 0; } @@ -2419,34 +2204,5 @@ int Toy_hookStandard(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_L Toy_injectNativeFn(interpreter, natives[i].name, natives[i].fn); } - if (Toy_isDeclaredScopeVariable(interpreter->scope, piKeyLiteral)) { - interpreter->errorOutput("Can't override an existing variable\n"); - - // cleanup - Toy_freeLiteral(alias); - Toy_freeLiteral(piKeyLiteral); - - return -1; - } - - Toy_Literal floatType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_FLOAT, false); - - // pi - Toy_declareScopeVariable(interpreter->scope, piIdentifierLiteral, floatType); - Toy_setScopeVariable(interpreter->scope, piIdentifierLiteral, piLiteral, false); - - // e - Toy_declareScopeVariable(interpreter->scope, eIdentifierLiteral, floatType); - Toy_setScopeVariable(interpreter->scope, eIdentifierLiteral, eLiteral, false); - - // cleanup - Toy_freeLiteral(floatType); - Toy_freeLiteral(piKeyLiteral); - Toy_freeLiteral(piIdentifierLiteral); - Toy_freeLiteral(piLiteral); - Toy_freeLiteral(eKeyLiteral); - Toy_freeLiteral(eIdentifierLiteral); - Toy_freeLiteral(eLiteral); - return 0; } diff --git a/repl/makefile b/repl/makefile index 533207a..72beb28 100644 --- a/repl/makefile +++ b/repl/makefile @@ -2,7 +2,7 @@ CC=gcc IDIR+=. ../source CFLAGS+=$(addprefix -I,$(IDIR)) -g -Wall -W -Wno-unused-parameter -Wno-unused-function -Wno-unused-variable -LIBS+=-ltoy +LIBS+=-ltoy -lm ODIR = obj SRC = $(wildcard *.c) diff --git a/repl/repl_main.c b/repl/repl_main.c index 2c07562..bee774f 100644 --- a/repl/repl_main.c +++ b/repl/repl_main.c @@ -4,6 +4,7 @@ #include "lib_standard.h" #include "lib_random.h" #include "lib_runner.h" +#include "lib_math.h" #include "toy_console_colors.h" @@ -30,6 +31,7 @@ void repl(const char* initialInput) { Toy_injectNativeHook(&interpreter, "standard", Toy_hookStandard); Toy_injectNativeHook(&interpreter, "random", Toy_hookRandom); Toy_injectNativeHook(&interpreter, "runner", Toy_hookRunner); + Toy_injectNativeHook(&interpreter, "math", Toy_hookMath); for(;;) { if (!initialInput) { diff --git a/repl/repl_tools.c b/repl/repl_tools.c index a222c18..0310d1e 100644 --- a/repl/repl_tools.c +++ b/repl/repl_tools.c @@ -3,6 +3,7 @@ #include "lib_standard.h" #include "lib_random.h" #include "lib_runner.h" +#include "lib_math.h" #include "toy_console_colors.h" @@ -115,6 +116,7 @@ void Toy_runBinary(const unsigned char* tb, size_t size) { Toy_injectNativeHook(&interpreter, "standard", Toy_hookStandard); Toy_injectNativeHook(&interpreter, "random", Toy_hookRandom); Toy_injectNativeHook(&interpreter, "runner", Toy_hookRunner); + Toy_injectNativeHook(&interpreter, "math", Toy_hookMath); Toy_runInterpreter(&interpreter, tb, (int)size); Toy_freeInterpreter(&interpreter); diff --git a/test/makefile b/test/makefile index 0fcffb2..4910461 100644 --- a/test/makefile +++ b/test/makefile @@ -2,7 +2,7 @@ CC=gcc IDIR +=. ../source ../repl CFLAGS +=$(addprefix -I,$(IDIR)) -g -Wall -W -Wno-unused-parameter -Wno-unused-function -Wno-unused-variable -LIBS += +LIBS +=-lm ODIR = obj TARGETS = $(wildcard ../source/*.c) $(wildcard ../repl/lib_*.c) ../repl/repl_tools.c ../repl/drive_system.c TESTS = $(wildcard test_*.c) diff --git a/test/scripts/lib/math.toy b/test/scripts/lib/math.toy new file mode 100644 index 0000000..ce60cae --- /dev/null +++ b/test/scripts/lib/math.toy @@ -0,0 +1,27 @@ +import math; + +// test toRad +{ + assert toRad(0) == 0, "toRad 0° failed"; + assert toRad(180) == PI, "toRad 180° failed"; + assert toRad(360) == 2 * PI, "toRad 360° failed"; +} + + +// test toDeg +{ + assert toDeg(0) == 0, "toDeg 0 failed"; + assert toDeg(PI) == 180, "toDeg π failed"; + assert toDeg(2 * PI) == 360, "toDeg 2π failed"; +} + +// test sin +{ + assert sin(PI) == 0, "sin π failed"; +} + + +// test cos +{ + assert cos(PI) == -1, "cos π failed"; +} diff --git a/test/scripts/lib/standard.toy b/test/scripts/lib/standard.toy index 2c9ef6e..ab50ff4 100644 --- a/test/scripts/lib/standard.toy +++ b/test/scripts/lib/standard.toy @@ -158,32 +158,6 @@ import standard; } -// test toRad -{ - assert toRad(0) == 0, "toRad 0° failed"; - assert toRad(180) == PI, "toRad 180° failed"; - assert toRad(360) == 2 * PI, "toRad 360° failed"; -} - - -// test toDeg -{ - assert toDeg(0) == 0, "toDeg 0 failed"; - assert toDeg(PI) == 180, "toDeg π failed"; - assert toDeg(2 * PI) == 360, "toDeg 2π failed"; -} - -// test sin -{ - assert sin(PI) == 0, "sin π failed"; -} - - -// test cos -{ - assert cos(PI) == -1, "cos π failed"; -} - //test concat { //test array concat From b06b2d948523db9cd44e07def9b2120ee83dec36 Mon Sep 17 00:00:00 2001 From: Add00 Date: Tue, 1 Aug 2023 09:04:37 -0400 Subject: [PATCH 06/10] test cases and additional functions --- repl/lib_math.c | 173 ++++++++++++++++++++++++++++++-------- test/scripts/lib/math.toy | 68 ++++++++++++++- 2 files changed, 203 insertions(+), 38 deletions(-) diff --git a/repl/lib_math.c b/repl/lib_math.c index 07108a9..d3eacb0 100644 --- a/repl/lib_math.c +++ b/repl/lib_math.c @@ -4,18 +4,19 @@ #include -#define LIB_MATH_PI 3.14159265358979323846f -#define LIB_MATH_E 2.71828182845904523536f +#define LIB_MATH_PI 3.14159265358979323846f +#define LIB_MATH_E 2.71828182845904523536f +#define LIB_MATH_EPSILON 0.000001f static int nativeMod(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { - if (arguments->count != 1) { - interpreter->errorOutput("Incorrect number of arguments to sin\n"); + if (arguments->count != 2) { + interpreter->errorOutput("Incorrect number of arguments to mod\n"); return -1; } //get the arguments - Toy_Literal xLiteral = Toy_popLiteralArray(arguments); Toy_Literal yLiteral = Toy_popLiteralArray(arguments); + Toy_Literal xLiteral = Toy_popLiteralArray(arguments); //parse the argument (if it's an identifier) Toy_Literal xLiteralIdn = xLiteral; @@ -30,13 +31,13 @@ static int nativeMod(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) //check the argument types if (!(TOY_IS_INTEGER(xLiteral) || TOY_IS_FLOAT(xLiteral))) { - interpreter->errorOutput("Incorrect argument type passed to sin\n"); + interpreter->errorOutput("Incorrect argument type passed to mod\n"); Toy_freeLiteral(xLiteral); return -1; } if (!(TOY_IS_INTEGER(yLiteral) || TOY_IS_FLOAT(yLiteral))) { - interpreter->errorOutput("Incorrect argument type passed to sin\n"); + interpreter->errorOutput("Incorrect argument type passed to mod\n"); Toy_freeLiteral(yLiteral); return -1; } @@ -61,14 +62,14 @@ static int nativeMod(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) } static int nativePow(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { - if (arguments->count != 1) { - interpreter->errorOutput("Incorrect number of arguments to sin\n"); + if (arguments->count != 2) { + interpreter->errorOutput("Incorrect number of arguments to pow\n"); return -1; } //get the arguments - Toy_Literal xLiteral = Toy_popLiteralArray(arguments); Toy_Literal yLiteral = Toy_popLiteralArray(arguments); + Toy_Literal xLiteral = Toy_popLiteralArray(arguments); //parse the argument (if it's an identifier) Toy_Literal xLiteralIdn = xLiteral; @@ -83,13 +84,13 @@ static int nativePow(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) //check the argument types if (!(TOY_IS_INTEGER(xLiteral) || TOY_IS_FLOAT(xLiteral))) { - interpreter->errorOutput("Incorrect argument type passed to sin\n"); + interpreter->errorOutput("Incorrect argument type passed to pow\n"); Toy_freeLiteral(xLiteral); return -1; } if (!(TOY_IS_INTEGER(yLiteral) || TOY_IS_FLOAT(yLiteral))) { - interpreter->errorOutput("Incorrect argument type passed to sin\n"); + interpreter->errorOutput("Incorrect argument type passed to pow\n"); Toy_freeLiteral(yLiteral); return -1; } @@ -115,7 +116,7 @@ static int nativePow(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) static int nativeSqrt(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { if (arguments->count != 1) { - interpreter->errorOutput("Incorrect number of arguments to sin\n"); + interpreter->errorOutput("Incorrect number of arguments to sqrt\n"); return -1; } @@ -130,7 +131,7 @@ static int nativeSqrt(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) //check the argument type if (!(TOY_IS_INTEGER(xLiteral) || TOY_IS_FLOAT(xLiteral))) { - interpreter->errorOutput("Incorrect argument type passed to sin\n"); + interpreter->errorOutput("Incorrect argument type passed to sqrt\n"); Toy_freeLiteral(xLiteral); return -1; } @@ -154,7 +155,7 @@ static int nativeSqrt(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) static int nativeCbrt(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { if (arguments->count != 1) { - interpreter->errorOutput("Incorrect number of arguments to sin\n"); + interpreter->errorOutput("Incorrect number of arguments to cbrt\n"); return -1; } @@ -169,7 +170,7 @@ static int nativeCbrt(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) //check the argument type if (!(TOY_IS_INTEGER(xLiteral) || TOY_IS_FLOAT(xLiteral))) { - interpreter->errorOutput("Incorrect argument type passed to sin\n"); + interpreter->errorOutput("Incorrect argument type passed to cbrt\n"); Toy_freeLiteral(xLiteral); return -1; } @@ -192,14 +193,14 @@ static int nativeCbrt(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) } static int nativeHypot(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { - if (arguments->count != 1) { - interpreter->errorOutput("Incorrect number of arguments to sin\n"); + if (arguments->count != 2) { + interpreter->errorOutput("Incorrect number of arguments to hypot\n"); return -1; } //get the arguments - Toy_Literal xLiteral = Toy_popLiteralArray(arguments); Toy_Literal yLiteral = Toy_popLiteralArray(arguments); + Toy_Literal xLiteral = Toy_popLiteralArray(arguments); //parse the argument (if it's an identifier) Toy_Literal xLiteralIdn = xLiteral; @@ -214,13 +215,13 @@ static int nativeHypot(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments //check the argument types if (!(TOY_IS_INTEGER(xLiteral) || TOY_IS_FLOAT(xLiteral))) { - interpreter->errorOutput("Incorrect argument type passed to sin\n"); + interpreter->errorOutput("Incorrect argument type passed to hypot\n"); Toy_freeLiteral(xLiteral); return -1; } if (!(TOY_IS_INTEGER(yLiteral) || TOY_IS_FLOAT(yLiteral))) { - interpreter->errorOutput("Incorrect argument type passed to sin\n"); + interpreter->errorOutput("Incorrect argument type passed to hypot\n"); Toy_freeLiteral(yLiteral); return -1; } @@ -437,41 +438,94 @@ static int nativeTan(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) return 1; } -static int nativeTan(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { +static int nativeIsnan(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { if (arguments->count != 1) { interpreter->errorOutput("Incorrect number of arguments to tan\n"); return -1; } //get the argument - Toy_Literal radiansLiteral = Toy_popLiteralArray(arguments); + Toy_Literal xLiteral = Toy_popLiteralArray(arguments); //parse the argument (if it's an identifier) - Toy_Literal radiansLiteralIdn = radiansLiteral; - if (TOY_IS_IDENTIFIER(radiansLiteral) && Toy_parseIdentifierToValue(interpreter, &radiansLiteral)) { - Toy_freeLiteral(radiansLiteralIdn); + Toy_Literal xLiteralIdn = xLiteral; + if (TOY_IS_IDENTIFIER(xLiteral) && Toy_parseIdentifierToValue(interpreter, &xLiteral)) { + Toy_freeLiteral(xLiteralIdn); } //check the argument type - if (!(TOY_IS_INTEGER(radiansLiteral) || TOY_IS_FLOAT(radiansLiteral))) { + if (!(TOY_IS_INTEGER(xLiteral) || TOY_IS_FLOAT(xLiteral))) { interpreter->errorOutput("Incorrect argument type passed to tan\n"); - Toy_freeLiteral(radiansLiteral); + Toy_freeLiteral(xLiteral); return -1; } // cast ints to floats to handle all types of numbers - float radians = TOY_IS_INTEGER(radiansLiteral)? TOY_AS_INTEGER(radiansLiteral) : TOY_AS_FLOAT(radiansLiteral); + float x = TOY_IS_INTEGER(xLiteral)? TOY_AS_INTEGER(xLiteral) : TOY_AS_FLOAT(xLiteral); // calculate the result - float result = tanf(radians); + float result = isnan(x); //return the result - Toy_Literal resultLiteral = TOY_TO_FLOAT_LITERAL(result); + Toy_Literal resultLiteral = TOY_TO_BOOLEAN_LITERAL(result); Toy_pushLiteralArray(&interpreter->stack, resultLiteral); //cleanup Toy_freeLiteral(resultLiteral); - Toy_freeLiteral(radiansLiteral); + Toy_freeLiteral(xLiteral); + + return 1; +} + +static int nativeFloatCompare(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + if (arguments->count != 2) { + interpreter->errorOutput("Incorrect number of arguments to mod\n"); + return -1; + } + + //get the arguments + Toy_Literal yLiteral = Toy_popLiteralArray(arguments); + Toy_Literal xLiteral = Toy_popLiteralArray(arguments); + + //parse the argument (if it's an identifier) + Toy_Literal xLiteralIdn = xLiteral; + if (TOY_IS_IDENTIFIER(xLiteral) && Toy_parseIdentifierToValue(interpreter, &xLiteral)) { + Toy_freeLiteral(xLiteralIdn); + } + + Toy_Literal yLiteralIdn = yLiteral; + if (TOY_IS_IDENTIFIER(yLiteral) && Toy_parseIdentifierToValue(interpreter, &yLiteral)) { + Toy_freeLiteral(yLiteralIdn); + } + + //check the argument types + if (!(TOY_IS_INTEGER(xLiteral) || TOY_IS_FLOAT(xLiteral))) { + interpreter->errorOutput("Incorrect argument type passed to mod\n"); + Toy_freeLiteral(xLiteral); + return -1; + } + + if (!(TOY_IS_INTEGER(yLiteral) || TOY_IS_FLOAT(yLiteral))) { + interpreter->errorOutput("Incorrect argument type passed to mod\n"); + Toy_freeLiteral(yLiteral); + return -1; + } + + // cast ints to floats to handle all types of numbers + float x = TOY_IS_INTEGER(xLiteral)? TOY_AS_INTEGER(xLiteral) : TOY_AS_FLOAT(xLiteral); + float y = TOY_IS_INTEGER(yLiteral)? TOY_AS_INTEGER(yLiteral) : TOY_AS_FLOAT(yLiteral); + + // calculate the result + float result = (fabsf(x - y)) <= (LIB_MATH_EPSILON * fmaxf(1, fmaxf(fabsf(x), fabsf(y)))); + + // return the result + Toy_Literal resultLiteral = TOY_TO_BOOLEAN_LITERAL(result); + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); + + // cleanup + Toy_freeLiteral(resultLiteral); + Toy_freeLiteral(xLiteral); + Toy_freeLiteral(yLiteral); return 1; } @@ -501,6 +555,10 @@ int Toy_hookMath(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Liter {"cos", nativeCos}, {"tan", nativeTan}, + // Comparison + {"isnan", nativeIsnan}, + {"floatCompare", nativeFloatCompare}, + {NULL, NULL} }; @@ -512,7 +570,18 @@ int Toy_hookMath(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Liter Toy_Literal eKeyLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString("E")); Toy_Literal eIdentifierLiteral = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefString("E")); Toy_Literal eLiteral = TOY_TO_FLOAT_LITERAL(LIB_MATH_E); - + + Toy_Literal epsilonKeyLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString("EPSILON")); + Toy_Literal epsilonIdentifierLiteral = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefString("EPSILON")); + Toy_Literal epsilonLiteral = TOY_TO_FLOAT_LITERAL(LIB_MATH_EPSILON); + + Toy_Literal nanKeyLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString("NAN")); + Toy_Literal nanIdentifierLiteral = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefString("NAN")); + Toy_Literal nanLiteral = TOY_TO_FLOAT_LITERAL(NAN); + + Toy_Literal infinityKeyLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString("INFINITY")); + Toy_Literal infinityIdentifierLiteral = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefString("INFINITY")); + Toy_Literal infinityLiteral = TOY_TO_FLOAT_LITERAL(INFINITY); //store the library in an aliased dictionary if (!TOY_IS_NULL(alias)) { @@ -540,7 +609,9 @@ int Toy_hookMath(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Liter Toy_setLiteralDictionary(dictionary, piKeyLiteral, piLiteral); Toy_setLiteralDictionary(dictionary, eKeyLiteral, eLiteral); - + Toy_setLiteralDictionary(dictionary, nanKeyLiteral, nanLiteral); + Toy_setLiteralDictionary(dictionary, infinityKeyLiteral, infinityLiteral); + Toy_setLiteralDictionary(dictionary, epsilonKeyLiteral, epsilonLiteral); //build the type Toy_Literal type = TOY_TO_TYPE_LITERAL(TOY_LITERAL_DICTIONARY, true); @@ -566,8 +637,11 @@ int Toy_hookMath(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Liter } if ( - Toy_isDeclaredScopeVariable(interpreter->scope, piKeyLiteral) || - Toy_isDeclaredScopeVariable(interpreter->scope, eKeyLiteral) + Toy_isDeclaredScopeVariable(interpreter->scope, piKeyLiteral) || + Toy_isDeclaredScopeVariable(interpreter->scope, eKeyLiteral) || + Toy_isDeclaredScopeVariable(interpreter->scope, epsilonKeyLiteral) || + Toy_isDeclaredScopeVariable(interpreter->scope, nanKeyLiteral) || + Toy_isDeclaredScopeVariable(interpreter->scope, infinityLiteral) ) { interpreter->errorOutput("Can't override an existing variable\n"); @@ -577,6 +651,12 @@ int Toy_hookMath(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Liter Toy_freeLiteral(piKeyLiteral); Toy_freeLiteral(eIdentifierLiteral); Toy_freeLiteral(eKeyLiteral); + Toy_freeLiteral(epsilonIdentifierLiteral); + Toy_freeLiteral(epsilonKeyLiteral); + Toy_freeLiteral(nanIdentifierLiteral); + Toy_freeLiteral(nanKeyLiteral); + Toy_freeLiteral(infinityIdentifierLiteral); + Toy_freeLiteral(infinityLiteral); return -1; } @@ -591,6 +671,18 @@ int Toy_hookMath(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Liter Toy_declareScopeVariable(interpreter->scope, eIdentifierLiteral, floatType); Toy_setScopeVariable(interpreter->scope, eIdentifierLiteral, eLiteral, false); + // epsilon + Toy_declareScopeVariable(interpreter->scope, epsilonIdentifierLiteral, floatType); + Toy_setScopeVariable(interpreter->scope, epsilonIdentifierLiteral, epsilonLiteral, false); + + // nan + Toy_declareScopeVariable(interpreter->scope, nanIdentifierLiteral, floatType); + Toy_setScopeVariable(interpreter->scope, nanIdentifierLiteral, nanLiteral, false); + + // infinity + Toy_declareScopeVariable(interpreter->scope, infinityIdentifierLiteral, floatType); + Toy_setScopeVariable(interpreter->scope, infinityIdentifierLiteral, infinityLiteral, false); + // cleanup Toy_freeLiteral(floatType); Toy_freeLiteral(piKeyLiteral); @@ -599,6 +691,15 @@ int Toy_hookMath(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Liter Toy_freeLiteral(eKeyLiteral); Toy_freeLiteral(eIdentifierLiteral); Toy_freeLiteral(eLiteral); + Toy_freeLiteral(epsilonKeyLiteral); + Toy_freeLiteral(epsilonIdentifierLiteral); + Toy_freeLiteral(epsilonLiteral); + Toy_freeLiteral(nanIdentifierLiteral); + Toy_freeLiteral(nanKeyLiteral); + Toy_freeLiteral(nanLiteral); + Toy_freeLiteral(infinityIdentifierLiteral); + Toy_freeLiteral(infinityKeyLiteral); + Toy_freeLiteral(infinityLiteral); return 0; } diff --git a/test/scripts/lib/math.toy b/test/scripts/lib/math.toy index ce60cae..5639775 100644 --- a/test/scripts/lib/math.toy +++ b/test/scripts/lib/math.toy @@ -1,5 +1,46 @@ import math; +// test mod +{ + assert mod(5, 3) == 2.0, "mod(5, 3) failed"; + assert mod(-5, 3) == -2.0, "mod(-5, 3) failed"; + assert mod(-5.5, 3) == -2.5, "mod(-5.5, 3) failed"; + assert mod(0, 1) == 0.0, "mod(0, 1) failed"; + assert mod(-0.0, 1) == -0.0, "mod(0, 1) failed"; +} + +// test pow +{ + assert pow(5, 3) == 125, "pow(5, 3) failed"; + assert pow(-5, 3) == -125, "pow(-5, 3) failed"; + assert pow(-5.5, 3) == -166.375, "pow(-5.5, 3) failed"; + assert pow(0, 1) == 0.0, "pow(0, 1) failed"; + assert pow(-0.0, 1) == -0.0, "pow(0, 1) failed"; +} + +// test sqrt +{ + assert sqrt(25) == 5, "sqrt(25) failed"; + assert sqrt(256.0) == 16, "sqrt(256.0) failed"; + assert isnan(sqrt(-256.0)), "sqrt(-256.0) failed"; + assert sqrt(1) == 1, "sqrt(1) failed"; + assert sqrt(0) == 0, "sqrt(0) failed"; +} + +// test cbrt +{ + assert cbrt(64) == 4, "cbrt(64) failed"; + assert cbrt(4096.0) == 16, "cbrt(4096.0) failed"; + assert cbrt(-64) == -4, "cbrt(-64) failed"; + assert cbrt(1) == 1, "cbrt(1) failed"; + assert cbrt(0) == 0, "cbrt(0) failed"; +} + +// test hypot +{ + assert hypot(3, 4) == 5, "hypot(3, 4) failed"; +} + // test toRad { assert toRad(0) == 0, "toRad 0° failed"; @@ -17,11 +58,34 @@ import math; // test sin { - assert sin(PI) == 0, "sin π failed"; + assert floatCompare(sin(PI), 0), "sin(π) failed"; + assert floatCompare(sin(PI / 2), 1), "sin(π/2) failed"; + assert floatCompare(sin(0), 0), "sin(0) failed"; } // test cos { - assert cos(PI) == -1, "cos π failed"; + assert floatCompare(cos(PI), -1), "cos(π) failed"; + assert floatCompare(cos(PI / 2), 0), "cos(π/2) failed"; + assert floatCompare(cos(0), 1), "cos(0) failed"; } + + +// test isnan +{ + assert isnan(NAN) == true, "isnan(NAN) failed"; + assert isnan(INFINITY) == false, "isnan(INFINITY) failed"; + assert isnan(0.0) == false, "isnan(0.0) failed"; + // assert isnan(0 / 0) == true, "isnan(0 / 0) failed"; interpreter prevents dividing by 0 + assert isnan(INFINITY - INFINITY) == true, "isnan(INFINITY - INFINITY) failed"; +} + + +// test floatCompare +{ + assert floatCompare(1, 1) == true, "floatCompare(1, 1) failed"; + assert floatCompare(1, 1.000001) == true, "floatCompare(1, 1.000001) failed"; + assert floatCompare(1, 1.001) == false, "floatCompare(1, 1.001) failed"; + assert floatCompare(0, 0) == true, "floatCompare(0, 0) failed"; +} \ No newline at end of file From f5ba1181c059ce7fb23a06c278726ea5204763a4 Mon Sep 17 00:00:00 2001 From: Add00 Date: Tue, 1 Aug 2023 13:41:55 -0400 Subject: [PATCH 07/10] Added arc versions of trigonometric functions --- repl/lib_math.c | 173 ++++++++++++++++++++++++++++++++++++++ test/scripts/lib/math.toy | 38 +++++++++ 2 files changed, 211 insertions(+) diff --git a/repl/lib_math.c b/repl/lib_math.c index d3eacb0..c9f4d17 100644 --- a/repl/lib_math.c +++ b/repl/lib_math.c @@ -438,6 +438,175 @@ static int nativeTan(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) return 1; } +static int nativeAsin(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + if (arguments->count != 1) { + interpreter->errorOutput("Incorrect number of arguments to asin\n"); + return -1; + } + + //get the argument + Toy_Literal radiansLiteral = Toy_popLiteralArray(arguments); + + //parse the argument (if it's an identifier) + Toy_Literal radiansLiteralIdn = radiansLiteral; + if (TOY_IS_IDENTIFIER(radiansLiteral) && Toy_parseIdentifierToValue(interpreter, &radiansLiteral)) { + Toy_freeLiteral(radiansLiteralIdn); + } + + //check the argument type + if (!(TOY_IS_INTEGER(radiansLiteral) || TOY_IS_FLOAT(radiansLiteral))) { + interpreter->errorOutput("Incorrect argument type passed to asin\n"); + Toy_freeLiteral(radiansLiteral); + return -1; + } + + // cast ints to floats to handle all types of numbers + float radians = TOY_IS_INTEGER(radiansLiteral)? TOY_AS_INTEGER(radiansLiteral) : TOY_AS_FLOAT(radiansLiteral); + + // calculate the result + float result = asinf(radians); + + //return the result + Toy_Literal resultLiteral = TOY_TO_FLOAT_LITERAL(result); + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); + + //cleanup + Toy_freeLiteral(resultLiteral); + Toy_freeLiteral(radiansLiteral); + + return 1; +} + +static int nativeAcos(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + if (arguments->count != 1) { + interpreter->errorOutput("Incorrect number of arguments to acos\n"); + return -1; + } + + //get the argument + Toy_Literal radiansLiteral = Toy_popLiteralArray(arguments); + + //parse the argument (if it's an identifier) + Toy_Literal radiansLiteralIdn = radiansLiteral; + if (TOY_IS_IDENTIFIER(radiansLiteral) && Toy_parseIdentifierToValue(interpreter, &radiansLiteral)) { + Toy_freeLiteral(radiansLiteralIdn); + } + + //check the argument type + if (!(TOY_IS_INTEGER(radiansLiteral) || TOY_IS_FLOAT(radiansLiteral))) { + interpreter->errorOutput("Incorrect argument type passed to acos\n"); + Toy_freeLiteral(radiansLiteral); + return -1; + } + + // cast ints to floats to handle all types of numbers + float radians = TOY_IS_INTEGER(radiansLiteral)? TOY_AS_INTEGER(radiansLiteral) : TOY_AS_FLOAT(radiansLiteral); + + // calculate the result + float result = acosf(radians); + + //return the result + Toy_Literal resultLiteral = TOY_TO_FLOAT_LITERAL(result); + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); + + //cleanup + Toy_freeLiteral(resultLiteral); + Toy_freeLiteral(radiansLiteral); + + return 1; +} + +static int nativeAtan(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + if (arguments->count != 1) { + interpreter->errorOutput("Incorrect number of arguments to atan\n"); + return -1; + } + + //get the argument + Toy_Literal radiansLiteral = Toy_popLiteralArray(arguments); + + //parse the argument (if it's an identifier) + Toy_Literal radiansLiteralIdn = radiansLiteral; + if (TOY_IS_IDENTIFIER(radiansLiteral) && Toy_parseIdentifierToValue(interpreter, &radiansLiteral)) { + Toy_freeLiteral(radiansLiteralIdn); + } + + //check the argument type + if (!(TOY_IS_INTEGER(radiansLiteral) || TOY_IS_FLOAT(radiansLiteral))) { + interpreter->errorOutput("Incorrect argument type passed to atan\n"); + Toy_freeLiteral(radiansLiteral); + return -1; + } + + // cast ints to floats to handle all types of numbers + float radians = TOY_IS_INTEGER(radiansLiteral)? TOY_AS_INTEGER(radiansLiteral) : TOY_AS_FLOAT(radiansLiteral); + + // calculate the result + float result = atanf(radians); + + //return the result + Toy_Literal resultLiteral = TOY_TO_FLOAT_LITERAL(result); + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); + + //cleanup + Toy_freeLiteral(resultLiteral); + Toy_freeLiteral(radiansLiteral); + + return 1; +} + +static int nativeAtan2(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + if (arguments->count != 2) { + interpreter->errorOutput("Incorrect number of arguments to atan2\n"); + return -1; + } + + //get the argument + Toy_Literal yLiteral = Toy_popLiteralArray(arguments); + Toy_Literal xLiteral = Toy_popLiteralArray(arguments); + + //parse the argument (if it's an identifier) + Toy_Literal xLiteralIdn = xLiteral; + if (TOY_IS_IDENTIFIER(xLiteral) && Toy_parseIdentifierToValue(interpreter, &xLiteral)) { + Toy_freeLiteral(xLiteralIdn); + } + + Toy_Literal yLiteralIdn = yLiteral; + if (TOY_IS_IDENTIFIER(yLiteral) && Toy_parseIdentifierToValue(interpreter, &yLiteral)) { + Toy_freeLiteral(yLiteralIdn); + } + + //check the argument type + if (!(TOY_IS_INTEGER(xLiteral) || TOY_IS_FLOAT(xLiteral))) { + interpreter->errorOutput("Incorrect argument type passed to atan2\n"); + Toy_freeLiteral(xLiteral); + return -1; + } + + if (!(TOY_IS_INTEGER(yLiteral) || TOY_IS_FLOAT(yLiteral))) { + interpreter->errorOutput("Incorrect argument type passed to atan2\n"); + Toy_freeLiteral(yLiteral); + return -1; + } + + // cast ints to floats to handle all types of numbers + float x = TOY_IS_INTEGER(xLiteral)? TOY_AS_INTEGER(xLiteral) : TOY_AS_FLOAT(xLiteral); + float y = TOY_IS_INTEGER(yLiteral)? TOY_AS_INTEGER(yLiteral) : TOY_AS_FLOAT(yLiteral); + + // calculate the result + float result = atan2f(x, y); + + //return the result + Toy_Literal resultLiteral = TOY_TO_FLOAT_LITERAL(result); + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); + + //cleanup + Toy_freeLiteral(resultLiteral); + Toy_freeLiteral(xLiteral); + + return 1; +} + static int nativeIsnan(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { if (arguments->count != 1) { interpreter->errorOutput("Incorrect number of arguments to tan\n"); @@ -554,6 +723,10 @@ int Toy_hookMath(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Liter {"sin", nativeSin}, {"cos", nativeCos}, {"tan", nativeTan}, + {"asin", nativeAsin}, + {"acos", nativeAcos}, + {"atan", nativeAtan}, + {"atans", nativeAtan2}, // Comparison {"isnan", nativeIsnan}, diff --git a/test/scripts/lib/math.toy b/test/scripts/lib/math.toy index 5639775..d7a24e3 100644 --- a/test/scripts/lib/math.toy +++ b/test/scripts/lib/math.toy @@ -71,6 +71,44 @@ import math; assert floatCompare(cos(0), 1), "cos(0) failed"; } +// test tan +{ + assert floatCompare(tan(PI), 0), "tan(π) failed"; + assert floatCompare(tan(PI / 4), 1), "tan(π/4) failed"; + assert floatCompare(tan(0), 0), "tan(0) failed"; +} + + +// test asin +{ + assert floatCompare(asin(1), 1.570796), "asin(1) failed"; + assert floatCompare(asin(-0.5), -0.523599), "asin(-0.5) failed"; + assert floatCompare(asin(0), 0), "asin(0) failed"; +} + + +// test acos +{ + assert floatCompare(acos(1), 0), "acos(1) failed"; + assert floatCompare(acos(0.5), 1.047198), "acos(0.5) failed"; + assert floatCompare(acos(0), 1.570796), "acos(0) failed"; +} + + +// test atan +{ + assert floatCompare(atan(1), 0.785398), "acos(1) failed"; + assert floatCompare(atan(INFINITY), 1.570796), "atan(INFINITY) failed"; + assert floatCompare(atan(0), 0), "atan(0) failed"; +} + + +// test atan2 +{ + assert floatCompare(atans(0, 0), 0), "atan2(0, 0) failed"; + assert floatCompare(atans(7, 0), 1.570796), "atans(7, 0) failed"; +} + // test isnan { From 9faaa311e042dc0a4839b0b1babf08284ec4ab06 Mon Sep 17 00:00:00 2001 From: Add00 Date: Tue, 1 Aug 2023 17:50:20 -0400 Subject: [PATCH 08/10] Fixed Memory Leak --- repl/lib_standard.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/repl/lib_standard.c b/repl/lib_standard.c index 162011f..dde005b 100644 --- a/repl/lib_standard.c +++ b/repl/lib_standard.c @@ -2196,6 +2196,8 @@ int Toy_hookStandard(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_L Toy_freeLiteral(func); } + Toy_freeLiteralDictionary(dictionary); + return 0; } From 8714c56c3e671c2e0f070032c17ebf4f74e7c1fb Mon Sep 17 00:00:00 2001 From: Add00 Date: Wed, 2 Aug 2023 08:39:50 -0400 Subject: [PATCH 09/10] Implemented feedback --- repl/lib_math.c | 82 ++++++++------------------------------ repl/lib_standard.c | 15 ++++++- test/scripts/lib/math.toy | 83 +++++++++++++++++---------------------- test/test_libraries.c | 2 + 4 files changed, 69 insertions(+), 113 deletions(-) diff --git a/repl/lib_math.c b/repl/lib_math.c index c9f4d17..aef7a9e 100644 --- a/repl/lib_math.c +++ b/repl/lib_math.c @@ -8,59 +8,6 @@ #define LIB_MATH_E 2.71828182845904523536f #define LIB_MATH_EPSILON 0.000001f -static int nativeMod(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { - if (arguments->count != 2) { - interpreter->errorOutput("Incorrect number of arguments to mod\n"); - return -1; - } - - //get the arguments - Toy_Literal yLiteral = Toy_popLiteralArray(arguments); - Toy_Literal xLiteral = Toy_popLiteralArray(arguments); - - //parse the argument (if it's an identifier) - Toy_Literal xLiteralIdn = xLiteral; - if (TOY_IS_IDENTIFIER(xLiteral) && Toy_parseIdentifierToValue(interpreter, &xLiteral)) { - Toy_freeLiteral(xLiteralIdn); - } - - Toy_Literal yLiteralIdn = yLiteral; - if (TOY_IS_IDENTIFIER(yLiteral) && Toy_parseIdentifierToValue(interpreter, &yLiteral)) { - Toy_freeLiteral(yLiteralIdn); - } - - //check the argument types - if (!(TOY_IS_INTEGER(xLiteral) || TOY_IS_FLOAT(xLiteral))) { - interpreter->errorOutput("Incorrect argument type passed to mod\n"); - Toy_freeLiteral(xLiteral); - return -1; - } - - if (!(TOY_IS_INTEGER(yLiteral) || TOY_IS_FLOAT(yLiteral))) { - interpreter->errorOutput("Incorrect argument type passed to mod\n"); - Toy_freeLiteral(yLiteral); - return -1; - } - - // cast ints to floats to handle all types of numbers - float x = TOY_IS_INTEGER(xLiteral)? TOY_AS_INTEGER(xLiteral) : TOY_AS_FLOAT(xLiteral); - float y = TOY_IS_INTEGER(yLiteral)? TOY_AS_INTEGER(yLiteral) : TOY_AS_FLOAT(yLiteral); - - // calculate the result - float result = fmodf(x, y); - - // return the result - Toy_Literal resultLiteral = TOY_TO_FLOAT_LITERAL(result); - Toy_pushLiteralArray(&interpreter->stack, resultLiteral); - - // cleanup - Toy_freeLiteral(resultLiteral); - Toy_freeLiteral(xLiteral); - Toy_freeLiteral(yLiteral); - - return 1; -} - static int nativePow(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { if (arguments->count != 2) { interpreter->errorOutput("Incorrect number of arguments to pow\n"); @@ -86,12 +33,14 @@ static int nativePow(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) if (!(TOY_IS_INTEGER(xLiteral) || TOY_IS_FLOAT(xLiteral))) { interpreter->errorOutput("Incorrect argument type passed to pow\n"); Toy_freeLiteral(xLiteral); + Toy_freeLiteral(yLiteralIdn); return -1; } if (!(TOY_IS_INTEGER(yLiteral) || TOY_IS_FLOAT(yLiteral))) { interpreter->errorOutput("Incorrect argument type passed to pow\n"); Toy_freeLiteral(yLiteral); + Toy_freeLiteral(xLiteral); return -1; } @@ -217,12 +166,14 @@ static int nativeHypot(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments if (!(TOY_IS_INTEGER(xLiteral) || TOY_IS_FLOAT(xLiteral))) { interpreter->errorOutput("Incorrect argument type passed to hypot\n"); Toy_freeLiteral(xLiteral); + Toy_freeLiteral(yLiteral); return -1; } if (!(TOY_IS_INTEGER(yLiteral) || TOY_IS_FLOAT(yLiteral))) { interpreter->errorOutput("Incorrect argument type passed to hypot\n"); Toy_freeLiteral(yLiteral); + Toy_freeLiteral(xLiteral); return -1; } @@ -245,7 +196,7 @@ static int nativeHypot(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments return 1; } -static int nativeToRad(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { +static int nativeToRadians(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { if (arguments->count != 1) { interpreter->errorOutput("Incorrect number of arguments to toRad\n"); return -1; @@ -283,7 +234,7 @@ static int nativeToRad(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments return 1; } -static int nativeToDeg(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { +static int nativeToDegrees(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { if (arguments->count != 1) { interpreter->errorOutput("Incorrect number of arguments to toDeg\n"); return -1; @@ -580,12 +531,14 @@ static int nativeAtan2(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments if (!(TOY_IS_INTEGER(xLiteral) || TOY_IS_FLOAT(xLiteral))) { interpreter->errorOutput("Incorrect argument type passed to atan2\n"); Toy_freeLiteral(xLiteral); + Toy_freeLiteral(yLiteral); return -1; } if (!(TOY_IS_INTEGER(yLiteral) || TOY_IS_FLOAT(yLiteral))) { interpreter->errorOutput("Incorrect argument type passed to atan2\n"); Toy_freeLiteral(yLiteral); + Toy_freeLiteral(xLiteral); return -1; } @@ -607,7 +560,7 @@ static int nativeAtan2(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments return 1; } -static int nativeIsnan(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { +static int nativeCheckIsNaN(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { if (arguments->count != 1) { interpreter->errorOutput("Incorrect number of arguments to tan\n"); return -1; @@ -646,7 +599,7 @@ static int nativeIsnan(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments return 1; } -static int nativeFloatCompare(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { +static int nativeEpsilionCompare(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { if (arguments->count != 2) { interpreter->errorOutput("Incorrect number of arguments to mod\n"); return -1; @@ -708,9 +661,6 @@ typedef struct Natives { int Toy_hookMath(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias) { //build the natives list Natives natives[] = { - // Common - {"mod", nativeMod}, - // Power {"pow", nativePow}, {"sqrt", nativeSqrt}, @@ -718,8 +668,8 @@ int Toy_hookMath(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Liter {"hypot", nativeHypot}, // Trigonometric - {"toRad", nativeToRad}, - {"toDeg", nativeToDeg}, + {"toRadians", nativeToRadians}, + {"toDegrees", nativeToDegrees}, {"sin", nativeSin}, {"cos", nativeCos}, {"tan", nativeTan}, @@ -729,8 +679,8 @@ int Toy_hookMath(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Liter {"atans", nativeAtan2}, // Comparison - {"isnan", nativeIsnan}, - {"floatCompare", nativeFloatCompare}, + {"checkIsNaN", nativeCheckIsNaN}, + {"epsilionCompare", nativeEpsilionCompare}, {NULL, NULL} }; @@ -788,9 +738,9 @@ int Toy_hookMath(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Liter //build the type Toy_Literal type = TOY_TO_TYPE_LITERAL(TOY_LITERAL_DICTIONARY, true); - Toy_Literal strType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_STRING, true); + Toy_Literal anyType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_ANY, true); Toy_Literal fnType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_FUNCTION_NATIVE, true); - TOY_TYPE_PUSH_SUBTYPE(&type, strType); + TOY_TYPE_PUSH_SUBTYPE(&type, anyType); TOY_TYPE_PUSH_SUBTYPE(&type, fnType); //set scope diff --git a/repl/lib_standard.c b/repl/lib_standard.c index dde005b..786cbd3 100644 --- a/repl/lib_standard.c +++ b/repl/lib_standard.c @@ -2196,8 +2196,21 @@ int Toy_hookStandard(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_L Toy_freeLiteral(func); } - Toy_freeLiteralDictionary(dictionary); + //build the type + Toy_Literal type = TOY_TO_TYPE_LITERAL(TOY_LITERAL_DICTIONARY, true); + Toy_Literal strType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_STRING, true); + Toy_Literal fnType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_FUNCTION_NATIVE, true); + TOY_TYPE_PUSH_SUBTYPE(&type, strType); + TOY_TYPE_PUSH_SUBTYPE(&type, fnType); + //set scope + Toy_Literal dict = TOY_TO_DICTIONARY_LITERAL(dictionary); + Toy_declareScopeVariable(interpreter->scope, alias, type); + Toy_setScopeVariable(interpreter->scope, alias, dict, false); + + //cleanup + Toy_freeLiteral(dict); + Toy_freeLiteral(type); return 0; } diff --git a/test/scripts/lib/math.toy b/test/scripts/lib/math.toy index d7a24e3..4aec783 100644 --- a/test/scripts/lib/math.toy +++ b/test/scripts/lib/math.toy @@ -1,13 +1,5 @@ import math; -// test mod -{ - assert mod(5, 3) == 2.0, "mod(5, 3) failed"; - assert mod(-5, 3) == -2.0, "mod(-5, 3) failed"; - assert mod(-5.5, 3) == -2.5, "mod(-5.5, 3) failed"; - assert mod(0, 1) == 0.0, "mod(0, 1) failed"; - assert mod(-0.0, 1) == -0.0, "mod(0, 1) failed"; -} // test pow { @@ -22,7 +14,7 @@ import math; { assert sqrt(25) == 5, "sqrt(25) failed"; assert sqrt(256.0) == 16, "sqrt(256.0) failed"; - assert isnan(sqrt(-256.0)), "sqrt(-256.0) failed"; + assert checkIsNaN(sqrt(-256.0)), "sqrt(-256.0) failed"; assert sqrt(1) == 1, "sqrt(1) failed"; assert sqrt(0) == 0, "sqrt(0) failed"; } @@ -43,87 +35,86 @@ import math; // test toRad { - assert toRad(0) == 0, "toRad 0° failed"; - assert toRad(180) == PI, "toRad 180° failed"; - assert toRad(360) == 2 * PI, "toRad 360° failed"; + assert toRadians(0) == 0, "toRadians(0) failed"; + assert toRadians(180) == PI, "toRadians(180) failed"; + assert toRadians(360) == 2 * PI, "toRadians(360) failed"; } // test toDeg { - assert toDeg(0) == 0, "toDeg 0 failed"; - assert toDeg(PI) == 180, "toDeg π failed"; - assert toDeg(2 * PI) == 360, "toDeg 2π failed"; + assert toDegrees(0) == 0, "toDegrees(0) failed"; + assert toDegrees(PI) == 180, "toDegrees(PI) failed"; + assert toDegrees(2 * PI) == 360, "toDegrees(2*PI) failed"; } // test sin { - assert floatCompare(sin(PI), 0), "sin(π) failed"; - assert floatCompare(sin(PI / 2), 1), "sin(π/2) failed"; - assert floatCompare(sin(0), 0), "sin(0) failed"; + assert epsilionCompare(sin(PI), 0), "sin(PI) failed"; + assert epsilionCompare(sin(PI / 2), 1), "sin(PI/2) failed"; + assert epsilionCompare(sin(0), 0), "sin(0) failed"; } // test cos { - assert floatCompare(cos(PI), -1), "cos(π) failed"; - assert floatCompare(cos(PI / 2), 0), "cos(π/2) failed"; - assert floatCompare(cos(0), 1), "cos(0) failed"; + assert epsilionCompare(cos(PI), -1), "cos(PI) failed"; + assert epsilionCompare(cos(PI / 2), 0), "cos(PI/2) failed"; + assert epsilionCompare(cos(0), 1), "cos(0) failed"; } // test tan { - assert floatCompare(tan(PI), 0), "tan(π) failed"; - assert floatCompare(tan(PI / 4), 1), "tan(π/4) failed"; - assert floatCompare(tan(0), 0), "tan(0) failed"; + assert epsilionCompare(tan(PI), 0), "tan(PI) failed"; + assert epsilionCompare(tan(PI / 4), 1), "tan(PI/4) failed"; + assert epsilionCompare(tan(0), 0), "tan(0) failed"; } // test asin { - assert floatCompare(asin(1), 1.570796), "asin(1) failed"; - assert floatCompare(asin(-0.5), -0.523599), "asin(-0.5) failed"; - assert floatCompare(asin(0), 0), "asin(0) failed"; + assert epsilionCompare(asin(1), 1.570796), "asin(1) failed"; + assert epsilionCompare(asin(-0.5), -0.523599), "asin(-0.5) failed"; + assert epsilionCompare(asin(0), 0), "asin(0) failed"; } // test acos { - assert floatCompare(acos(1), 0), "acos(1) failed"; - assert floatCompare(acos(0.5), 1.047198), "acos(0.5) failed"; - assert floatCompare(acos(0), 1.570796), "acos(0) failed"; + assert epsilionCompare(acos(1), 0), "acos(1) failed"; + assert epsilionCompare(acos(0.5), 1.047198), "acos(0.5) failed"; + assert epsilionCompare(acos(0), 1.570796), "acos(0) failed"; } // test atan { - assert floatCompare(atan(1), 0.785398), "acos(1) failed"; - assert floatCompare(atan(INFINITY), 1.570796), "atan(INFINITY) failed"; - assert floatCompare(atan(0), 0), "atan(0) failed"; + assert epsilionCompare(atan(1), 0.785398), "acos(1) failed"; + assert epsilionCompare(atan(INFINITY), 1.570796), "atan(INFINITY) failed"; + assert epsilionCompare(atan(0), 0), "atan(0) failed"; } // test atan2 { - assert floatCompare(atans(0, 0), 0), "atan2(0, 0) failed"; - assert floatCompare(atans(7, 0), 1.570796), "atans(7, 0) failed"; + assert epsilionCompare(atans(0, 0), 0), "atan2(0, 0) failed"; + assert epsilionCompare(atans(7, 0), 1.570796), "atans(7, 0) failed"; } -// test isnan +// test checkIsNaN { - assert isnan(NAN) == true, "isnan(NAN) failed"; - assert isnan(INFINITY) == false, "isnan(INFINITY) failed"; - assert isnan(0.0) == false, "isnan(0.0) failed"; - // assert isnan(0 / 0) == true, "isnan(0 / 0) failed"; interpreter prevents dividing by 0 - assert isnan(INFINITY - INFINITY) == true, "isnan(INFINITY - INFINITY) failed"; + assert checkIsNaN(NAN) == true, "checkIsNaN(NAN) failed"; + assert checkIsNaN(INFINITY) == false, "checkIsNaN(INFINITY) failed"; + assert checkIsNaN(0.0) == false, "checkIsNaN(0.0) failed"; + assert checkIsNaN(INFINITY - INFINITY) == true, "checkIsNaN(INFINITY - INFINITY) failed"; } -// test floatCompare +// test epsilionCompare { - assert floatCompare(1, 1) == true, "floatCompare(1, 1) failed"; - assert floatCompare(1, 1.000001) == true, "floatCompare(1, 1.000001) failed"; - assert floatCompare(1, 1.001) == false, "floatCompare(1, 1.001) failed"; - assert floatCompare(0, 0) == true, "floatCompare(0, 0) failed"; + assert epsilionCompare(1, 1) == true, "epsilionCompare(1, 1) failed"; + assert epsilionCompare(1, 1.000001) == true, "epsilionCompare(1, 1.000001) failed"; + assert epsilionCompare(1, 1.001) == false, "epsilionCompare(1, 1.001) failed"; + assert epsilionCompare(0, 0) == true, "epsilionCompare(0, 0) failed"; } \ No newline at end of file diff --git a/test/test_libraries.c b/test/test_libraries.c index 58c9e77..998c272 100644 --- a/test/test_libraries.c +++ b/test/test_libraries.c @@ -18,6 +18,7 @@ #include "../repl/lib_standard.h" #include "../repl/lib_random.h" #include "../repl/lib_runner.h" +#include "../repl/lib_math.h" //supress the print output static void noPrintFn(const char* output) { @@ -76,6 +77,7 @@ int main() { {"standard.toy", "standard", Toy_hookStandard}, {"runner.toy", "runner", Toy_hookRunner}, {"random.toy", "random", Toy_hookRandom}, + {"math.toy", "math", Toy_hookMath}, {NULL, NULL, NULL} }; From f8094fa17e5013a19fc4c5e5f612ecb2d7a8738d Mon Sep 17 00:00:00 2001 From: Add00 Date: Wed, 2 Aug 2023 11:25:27 -0400 Subject: [PATCH 10/10] Added hyperbolic and additional comparisons --- repl/lib_math.c | 328 +++++++++++++++++++++++++++++++++++++- test/scripts/lib/math.toy | 65 ++++++++ 2 files changed, 391 insertions(+), 2 deletions(-) diff --git a/repl/lib_math.c b/repl/lib_math.c index aef7a9e..f68ce30 100644 --- a/repl/lib_math.c +++ b/repl/lib_math.c @@ -560,9 +560,243 @@ static int nativeAtan2(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments return 1; } +static int nativeSinh(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + if (arguments->count != 1) { + interpreter->errorOutput("Incorrect number of arguments to sinh\n"); + return -1; + } + + //get the argument + Toy_Literal radiansLiteral = Toy_popLiteralArray(arguments); + + //parse the argument (if it's an identifier) + Toy_Literal radiansLiteralIdn = radiansLiteral; + if (TOY_IS_IDENTIFIER(radiansLiteral) && Toy_parseIdentifierToValue(interpreter, &radiansLiteral)) { + Toy_freeLiteral(radiansLiteralIdn); + } + + //check the argument type + if (!(TOY_IS_INTEGER(radiansLiteral) || TOY_IS_FLOAT(radiansLiteral))) { + interpreter->errorOutput("Incorrect argument type passed to sinh\n"); + Toy_freeLiteral(radiansLiteral); + return -1; + } + + // cast ints to floats to handle all types of numbers + float radians = TOY_IS_INTEGER(radiansLiteral)? TOY_AS_INTEGER(radiansLiteral) : TOY_AS_FLOAT(radiansLiteral); + + // calculate the result + float result = sinhf(radians); + + //return the result + Toy_Literal resultLiteral = TOY_TO_FLOAT_LITERAL(result); + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); + + //cleanup + Toy_freeLiteral(resultLiteral); + Toy_freeLiteral(radiansLiteral); + + return 1; +} + +static int nativeCosh(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + if (arguments->count != 1) { + interpreter->errorOutput("Incorrect number of arguments to cosh\n"); + return -1; + } + + //get the argument + Toy_Literal radiansLiteral = Toy_popLiteralArray(arguments); + + //parse the argument (if it's an identifier) + Toy_Literal radiansLiteralIdn = radiansLiteral; + if (TOY_IS_IDENTIFIER(radiansLiteral) && Toy_parseIdentifierToValue(interpreter, &radiansLiteral)) { + Toy_freeLiteral(radiansLiteralIdn); + } + + //check the argument type + if (!(TOY_IS_INTEGER(radiansLiteral) || TOY_IS_FLOAT(radiansLiteral))) { + interpreter->errorOutput("Incorrect argument type passed to cosh\n"); + Toy_freeLiteral(radiansLiteral); + return -1; + } + + // cast ints to floats to handle all types of numbers + float radians = TOY_IS_INTEGER(radiansLiteral)? TOY_AS_INTEGER(radiansLiteral) : TOY_AS_FLOAT(radiansLiteral); + + // calculate the result + float result = coshf(radians); + + //return the result + Toy_Literal resultLiteral = TOY_TO_FLOAT_LITERAL(result); + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); + + //cleanup + Toy_freeLiteral(resultLiteral); + Toy_freeLiteral(radiansLiteral); + + return 1; +} + +static int nativeTanh(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + if (arguments->count != 1) { + interpreter->errorOutput("Incorrect number of arguments to tanh\n"); + return -1; + } + + //get the argument + Toy_Literal radiansLiteral = Toy_popLiteralArray(arguments); + + //parse the argument (if it's an identifier) + Toy_Literal radiansLiteralIdn = radiansLiteral; + if (TOY_IS_IDENTIFIER(radiansLiteral) && Toy_parseIdentifierToValue(interpreter, &radiansLiteral)) { + Toy_freeLiteral(radiansLiteralIdn); + } + + //check the argument type + if (!(TOY_IS_INTEGER(radiansLiteral) || TOY_IS_FLOAT(radiansLiteral))) { + interpreter->errorOutput("Incorrect argument type passed to tanh\n"); + Toy_freeLiteral(radiansLiteral); + return -1; + } + + // cast ints to floats to handle all types of numbers + float radians = TOY_IS_INTEGER(radiansLiteral)? TOY_AS_INTEGER(radiansLiteral) : TOY_AS_FLOAT(radiansLiteral); + + // calculate the result + float result = tanhf(radians); + + //return the result + Toy_Literal resultLiteral = TOY_TO_FLOAT_LITERAL(result); + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); + + //cleanup + Toy_freeLiteral(resultLiteral); + Toy_freeLiteral(radiansLiteral); + + return 1; +} + +static int nativeAsinh(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + if (arguments->count != 1) { + interpreter->errorOutput("Incorrect number of arguments to asinh\n"); + return -1; + } + + //get the argument + Toy_Literal radiansLiteral = Toy_popLiteralArray(arguments); + + //parse the argument (if it's an identifier) + Toy_Literal radiansLiteralIdn = radiansLiteral; + if (TOY_IS_IDENTIFIER(radiansLiteral) && Toy_parseIdentifierToValue(interpreter, &radiansLiteral)) { + Toy_freeLiteral(radiansLiteralIdn); + } + + //check the argument type + if (!(TOY_IS_INTEGER(radiansLiteral) || TOY_IS_FLOAT(radiansLiteral))) { + interpreter->errorOutput("Incorrect argument type passed to asinh\n"); + Toy_freeLiteral(radiansLiteral); + return -1; + } + + // cast ints to floats to handle all types of numbers + float radians = TOY_IS_INTEGER(radiansLiteral)? TOY_AS_INTEGER(radiansLiteral) : TOY_AS_FLOAT(radiansLiteral); + + // calculate the result + float result = asinhf(radians); + + //return the result + Toy_Literal resultLiteral = TOY_TO_FLOAT_LITERAL(result); + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); + + //cleanup + Toy_freeLiteral(resultLiteral); + Toy_freeLiteral(radiansLiteral); + + return 1; +} + +static int nativeAcosh(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + if (arguments->count != 1) { + interpreter->errorOutput("Incorrect number of arguments to acosh\n"); + return -1; + } + + //get the argument + Toy_Literal radiansLiteral = Toy_popLiteralArray(arguments); + + //parse the argument (if it's an identifier) + Toy_Literal radiansLiteralIdn = radiansLiteral; + if (TOY_IS_IDENTIFIER(radiansLiteral) && Toy_parseIdentifierToValue(interpreter, &radiansLiteral)) { + Toy_freeLiteral(radiansLiteralIdn); + } + + //check the argument type + if (!(TOY_IS_INTEGER(radiansLiteral) || TOY_IS_FLOAT(radiansLiteral))) { + interpreter->errorOutput("Incorrect argument type passed to acosh\n"); + Toy_freeLiteral(radiansLiteral); + return -1; + } + + // cast ints to floats to handle all types of numbers + float radians = TOY_IS_INTEGER(radiansLiteral)? TOY_AS_INTEGER(radiansLiteral) : TOY_AS_FLOAT(radiansLiteral); + + // calculate the result + float result = acoshf(radians); + + //return the result + Toy_Literal resultLiteral = TOY_TO_FLOAT_LITERAL(result); + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); + + //cleanup + Toy_freeLiteral(resultLiteral); + Toy_freeLiteral(radiansLiteral); + + return 1; +} + +static int nativeAtanh(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + if (arguments->count != 1) { + interpreter->errorOutput("Incorrect number of arguments to atanh\n"); + return -1; + } + + //get the argument + Toy_Literal radiansLiteral = Toy_popLiteralArray(arguments); + + //parse the argument (if it's an identifier) + Toy_Literal radiansLiteralIdn = radiansLiteral; + if (TOY_IS_IDENTIFIER(radiansLiteral) && Toy_parseIdentifierToValue(interpreter, &radiansLiteral)) { + Toy_freeLiteral(radiansLiteralIdn); + } + + //check the argument type + if (!(TOY_IS_INTEGER(radiansLiteral) || TOY_IS_FLOAT(radiansLiteral))) { + interpreter->errorOutput("Incorrect argument type passed to atanh\n"); + Toy_freeLiteral(radiansLiteral); + return -1; + } + + // cast ints to floats to handle all types of numbers + float radians = TOY_IS_INTEGER(radiansLiteral)? TOY_AS_INTEGER(radiansLiteral) : TOY_AS_FLOAT(radiansLiteral); + + // calculate the result + float result = atanhf(radians); + + //return the result + Toy_Literal resultLiteral = TOY_TO_FLOAT_LITERAL(result); + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); + + //cleanup + Toy_freeLiteral(resultLiteral); + Toy_freeLiteral(radiansLiteral); + + return 1; +} + static int nativeCheckIsNaN(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { if (arguments->count != 1) { - interpreter->errorOutput("Incorrect number of arguments to tan\n"); + interpreter->errorOutput("Incorrect number of arguments to checkIsNaN\n"); return -1; } @@ -577,7 +811,7 @@ static int nativeCheckIsNaN(Toy_Interpreter* interpreter, Toy_LiteralArray* argu //check the argument type if (!(TOY_IS_INTEGER(xLiteral) || TOY_IS_FLOAT(xLiteral))) { - interpreter->errorOutput("Incorrect argument type passed to tan\n"); + interpreter->errorOutput("Incorrect argument type passed to checkIsNaN\n"); Toy_freeLiteral(xLiteral); return -1; } @@ -599,6 +833,84 @@ static int nativeCheckIsNaN(Toy_Interpreter* interpreter, Toy_LiteralArray* argu return 1; } +static int nativeCheckIsFinite(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + if (arguments->count != 1) { + interpreter->errorOutput("Incorrect number of arguments to checkIsFinite\n"); + return -1; + } + + //get the argument + Toy_Literal xLiteral = Toy_popLiteralArray(arguments); + + //parse the argument (if it's an identifier) + Toy_Literal xLiteralIdn = xLiteral; + if (TOY_IS_IDENTIFIER(xLiteral) && Toy_parseIdentifierToValue(interpreter, &xLiteral)) { + Toy_freeLiteral(xLiteralIdn); + } + + //check the argument type + if (!(TOY_IS_INTEGER(xLiteral) || TOY_IS_FLOAT(xLiteral))) { + interpreter->errorOutput("Incorrect argument type passed to checkIsFinite\n"); + Toy_freeLiteral(xLiteral); + return -1; + } + + // cast ints to floats to handle all types of numbers + float x = TOY_IS_INTEGER(xLiteral)? TOY_AS_INTEGER(xLiteral) : TOY_AS_FLOAT(xLiteral); + + // calculate the result + float result = isfinite(x); + + //return the result + Toy_Literal resultLiteral = TOY_TO_BOOLEAN_LITERAL(result); + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); + + //cleanup + Toy_freeLiteral(resultLiteral); + Toy_freeLiteral(xLiteral); + + return 1; +} + +static int nativeCheckIsInfinite(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + if (arguments->count != 1) { + interpreter->errorOutput("Incorrect number of arguments to checkIsInfinite\n"); + return -1; + } + + //get the argument + Toy_Literal xLiteral = Toy_popLiteralArray(arguments); + + //parse the argument (if it's an identifier) + Toy_Literal xLiteralIdn = xLiteral; + if (TOY_IS_IDENTIFIER(xLiteral) && Toy_parseIdentifierToValue(interpreter, &xLiteral)) { + Toy_freeLiteral(xLiteralIdn); + } + + //check the argument type + if (!(TOY_IS_INTEGER(xLiteral) || TOY_IS_FLOAT(xLiteral))) { + interpreter->errorOutput("Incorrect argument type passed to checkIsInfinite\n"); + Toy_freeLiteral(xLiteral); + return -1; + } + + // cast ints to floats to handle all types of numbers + float x = TOY_IS_INTEGER(xLiteral)? TOY_AS_INTEGER(xLiteral) : TOY_AS_FLOAT(xLiteral); + + // calculate the result + float result = isinf(x); + + //return the result + Toy_Literal resultLiteral = TOY_TO_BOOLEAN_LITERAL(result); + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); + + //cleanup + Toy_freeLiteral(resultLiteral); + Toy_freeLiteral(xLiteral); + + return 1; +} + static int nativeEpsilionCompare(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { if (arguments->count != 2) { interpreter->errorOutput("Incorrect number of arguments to mod\n"); @@ -661,6 +973,8 @@ typedef struct Natives { int Toy_hookMath(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias) { //build the natives list Natives natives[] = { + // Exponential + // Power {"pow", nativePow}, {"sqrt", nativeSqrt}, @@ -678,8 +992,18 @@ int Toy_hookMath(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Liter {"atan", nativeAtan}, {"atans", nativeAtan2}, + // Hyperbolic + {"sinh", nativeSinh}, + {"cosh", nativeCosh}, + {"tanh", nativeTanh}, + {"asinh", nativeAsinh}, + {"acosh", nativeAcosh}, + {"atanh", nativeAtanh}, + // Comparison {"checkIsNaN", nativeCheckIsNaN}, + {"chechIsFinite", nativeCheckIsFinite}, + {"chechIsInfinite", nativeCheckIsInfinite}, {"epsilionCompare", nativeEpsilionCompare}, {NULL, NULL} diff --git a/test/scripts/lib/math.toy b/test/scripts/lib/math.toy index 4aec783..e8603ac 100644 --- a/test/scripts/lib/math.toy +++ b/test/scripts/lib/math.toy @@ -102,6 +102,54 @@ import math; } +// test sinh +{ + assert epsilionCompare(sinh(1), 1.175201), "sinh(1) failed"; + assert epsilionCompare(sinh(-1), -1.175201), "sinh(-1) failed"; + assert epsilionCompare(sinh(0), 0), "sinh(0) failed"; +} + + +// test cosh +{ + assert epsilionCompare(cosh(1), 1.543081), "cosh(1) failed"; + assert epsilionCompare(cosh(-1), 1.543081), "cosh(-1) failed"; + assert epsilionCompare(cosh(0), 1), "cosh(0) failed"; +} + + +// test tanh +{ + assert epsilionCompare(tanh(1), 0.761594), "tanh(1) failed"; + assert epsilionCompare(tanh(-1), -0.761594), "tanh(-1) failed"; + assert epsilionCompare(tanh(0), 0), "tanh(0) failed"; +} + + +// test asinh +{ + assert epsilionCompare(asinh(1), 0.881374), "asinh(1) failed"; + assert epsilionCompare(asinh(-1), -0.881374), "asinh(-1) failed"; + assert epsilionCompare(asinh(0), 0), "asinh(0) failed"; +} + + +// test acosh +{ + assert epsilionCompare(acosh(1), 0), "acosh(1) failed"; + assert checkIsNaN(acosh(-1)) == true, "acosh(-1) failed"; + assert checkIsNaN(acosh(0)) == true, "acosh(0) failed"; +} + + +// test atanh +{ + assert chechIsInfinite(atanh(1)) == true, "atanh(1) failed"; + assert chechIsInfinite(atanh(-1)) == true, "atanh(-1) failed"; + assert epsilionCompare(atanh(0), 0), "atanh(0) failed"; +} + + // test checkIsNaN { assert checkIsNaN(NAN) == true, "checkIsNaN(NAN) failed"; @@ -111,6 +159,23 @@ import math; } +// test chechIsFinite +{ + assert chechIsFinite(NAN) == false, "chechIsFinite(NAN) failed"; + assert chechIsFinite(INFINITY) == false, "chechIsFinite(INFINITY) failed"; + assert chechIsFinite(0.0) == true, "chechIsFinite(0.0) failed"; + assert chechIsFinite(1) == true, "chechIsFinite(1) failed"; +} + + +// test chechIsInfinite +{ + assert chechIsInfinite(NAN) == false, "chechIsInfinite(NAN) failed"; + assert chechIsInfinite(INFINITY) == true, "chechIsInfinite(INFINITY) failed"; + assert chechIsInfinite(0.0) == false, "chechIsInfinite(0.0) failed"; + assert chechIsInfinite(1) == false, "chechIsInfinite(1) failed"; +} + // test epsilionCompare { assert epsilionCompare(1, 1) == true, "epsilionCompare(1, 1) failed";