From e3e9ca7ece8abbb5dde931e03164f09c4b37b295 Mon Sep 17 00:00:00 2001 From: Add00 Date: Mon, 31 Jul 2023 23:31:12 -0400 Subject: [PATCH] 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