diff --git a/repl/lib_math.c b/repl/lib_math.c new file mode 100644 index 0000000..f68ce30 --- /dev/null +++ b/repl/lib_math.c @@ -0,0 +1,1152 @@ +#include "lib_math.h" + +#include "toy_memory.h" + +#include + +#define LIB_MATH_PI 3.14159265358979323846f +#define LIB_MATH_E 2.71828182845904523536f +#define LIB_MATH_EPSILON 0.000001f + +static int nativePow(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + if (arguments->count != 2) { + interpreter->errorOutput("Incorrect number of arguments to pow\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 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; + } + + // 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 sqrt\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 sqrt\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 cbrt\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 cbrt\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 != 2) { + interpreter->errorOutput("Incorrect number of arguments to hypot\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 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; + } + + // 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 nativeToRadians(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 nativeToDegrees(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 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); + 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; + } + + // 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 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 checkIsNaN\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 checkIsNaN\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 = isnan(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 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"); + 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; +} + +//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[] = { + // Exponential + + // Power + {"pow", nativePow}, + {"sqrt", nativeSqrt}, + {"cbrt", nativeCbrt}, + {"hypot", nativeHypot}, + + // Trigonometric + {"toRadians", nativeToRadians}, + {"toDegrees", nativeToDegrees}, + {"sin", nativeSin}, + {"cos", nativeCos}, + {"tan", nativeTan}, + {"asin", nativeAsin}, + {"acos", nativeAcos}, + {"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} + }; + + // 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); + + 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)) { + //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); + 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); + 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, anyType); + 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) || + Toy_isDeclaredScopeVariable(interpreter->scope, epsilonKeyLiteral) || + Toy_isDeclaredScopeVariable(interpreter->scope, nanKeyLiteral) || + Toy_isDeclaredScopeVariable(interpreter->scope, infinityLiteral) + ) { + 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); + Toy_freeLiteral(epsilonIdentifierLiteral); + Toy_freeLiteral(epsilonKeyLiteral); + Toy_freeLiteral(nanIdentifierLiteral); + Toy_freeLiteral(nanKeyLiteral); + Toy_freeLiteral(infinityIdentifierLiteral); + Toy_freeLiteral(infinityLiteral); + + 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); + + // 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); + Toy_freeLiteral(piIdentifierLiteral); + Toy_freeLiteral(piLiteral); + 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/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/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..e8603ac --- /dev/null +++ b/test/scripts/lib/math.toy @@ -0,0 +1,185 @@ +import math; + + +// 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 checkIsNaN(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 toRadians(0) == 0, "toRadians(0) failed"; + assert toRadians(180) == PI, "toRadians(180) failed"; + assert toRadians(360) == 2 * PI, "toRadians(360) failed"; +} + + +// test toDeg +{ + 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 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 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 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 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 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 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 epsilionCompare(atans(0, 0), 0), "atan2(0, 0) failed"; + assert epsilionCompare(atans(7, 0), 1.570796), "atans(7, 0) failed"; +} + + +// 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"; + 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 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"; + 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} };