From 2fe579d9cc6cb062fc1487796a373e99e395e211 Mon Sep 17 00:00:00 2001 From: Thakee Nathees Date: Thu, 21 Apr 2022 21:37:38 +0530 Subject: [PATCH] math module moved to cli/modules --- cli/all.c | 1 + cli/modules/modules.h | 12 ++ cli/modules/std_io.c | 8 +- cli/modules/std_math.c | 218 ++++++++++++++++++++++++++ cli/modules/std_path.c | 28 ++-- src/pk_core.c | 298 ++++++------------------------------ src/pk_value.c | 27 +--- tests/examples/brainfuck.pk | 2 +- tests/examples/pi.pk | 6 +- tests/lang/basics.pk | 8 +- tests/lang/core.pk | 58 ------- tests/modules/math.pk | 64 ++++++++ tests/native/README.md | 4 +- tests/native/example1.c | 37 ++--- tests/native/example2.c | 222 +++++++-------------------- tests/random/linked_list.pk | 67 ++++++++ tests/random/lisp_eval.pk | 4 +- tests/tests.py | 5 + 18 files changed, 522 insertions(+), 547 deletions(-) create mode 100644 cli/modules/std_math.c create mode 100644 tests/modules/math.pk create mode 100644 tests/random/linked_list.pk diff --git a/cli/all.c b/cli/all.c index 1b8cae7..294fd44 100644 --- a/cli/all.c +++ b/cli/all.c @@ -15,6 +15,7 @@ #include "modules/std_io.c" #include "modules/std_path.c" +#include "modules/std_math.c" /*****************************************************************************/ /* THIRDPARTY SOURCES */ diff --git a/cli/modules/modules.h b/cli/modules/modules.h index d81854b..0088f4a 100644 --- a/cli/modules/modules.h +++ b/cli/modules/modules.h @@ -16,12 +16,14 @@ void registerModuleIO(PKVM* vm); void registerModulePath(PKVM* vm); +void registerModuleMath(PKVM* vm); // Registers all the cli modules. #define REGISTER_ALL_MODULES(vm) \ do { \ registerModuleIO(vm); \ registerModulePath(vm); \ + registerModuleMath(vm); \ } while (false) /*****************************************************************************/ @@ -35,6 +37,16 @@ void registerModulePath(PKVM* vm); // callback. #define FREE_OBJ(ptr) free(ptr) +// Returns the docstring of the function, which is a static const char* defined +// just above the function by the DEF() macro below. +#define DOCSTRING(fn) __doc_##fn + +// A macro to declare a function, with docstring, which is defined as +// ___doc_ = docstring; That'll used to generate function help text. +#define DEF(fn, docstring) \ + static const char* DOCSTRING(fn) = docstring; \ + static void fn(PKVM* vm) + /*****************************************************************************/ /* SHARED FUNCTIONS */ /*****************************************************************************/ diff --git a/cli/modules/std_io.c b/cli/modules/std_io.c index e2c6402..84030c5 100644 --- a/cli/modules/std_io.c +++ b/cli/modules/std_io.c @@ -56,7 +56,7 @@ void _deleteFile(void* ptr) { /* FILE MODULE FUNCTIONS */ /*****************************************************************************/ -static void _fileOpen(PKVM* vm) { +DEF(_fileOpen, "") { int argc = pkGetArgc(vm); if (!pkCheckArgcRange(vm, argc, 1, 2)) return; @@ -103,7 +103,7 @@ static void _fileOpen(PKVM* vm) { } } -static void _fileRead(PKVM* vm) { +DEF(_fileRead, "") { // This TODO is just a blockade from running the bellow code, complete the // native interface and test before removing it. TODO; @@ -126,7 +126,7 @@ static void _fileRead(PKVM* vm) { pkReturnString(vm, (const char*)buff); } -static void _fileWrite(PKVM* vm) { +DEF(_fileWrite, "") { // This TODO is just a blockade from running the bellow code, complete the // native interface and test before removing it. TODO; @@ -148,7 +148,7 @@ static void _fileWrite(PKVM* vm) { fwrite(text, sizeof(char), (size_t)length, file->fp); } -static void _fileClose(PKVM* vm) { +DEF(_fileClose, "") { // This TODO is just a blockade from running the bellow code, complete the // native interface and test before removing it. TODO; diff --git a/cli/modules/std_math.c b/cli/modules/std_math.c new file mode 100644 index 0000000..d27ae20 --- /dev/null +++ b/cli/modules/std_math.c @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2020-2022 Thakee Nathees + * Copyright (c) 2021-2022 Pocketlang Contributors + * Distributed Under The MIT License + */ + +#include "modules.h" + +#include + +// M_PI is non standard. The macro _USE_MATH_DEFINES defining before importing +// will define the constants for MSVC. But for a portable solution, +// we're defining it ourselves if it isn't already. +#ifndef M_PI + #define M_PI 3.14159265358979323846 +#endif + +DEF(stdMathFloor, + "floor(value:num) -> num\n") { + + double num; + if (!pkGetArgNumber(vm, 1, &num)) return; + pkReturnNumber(vm, floor(num)); +} + +DEF(stdMathCeil, + "ceil(value:num) -> num\n") { + + double num; + if (!pkGetArgNumber(vm, 1, &num)) return; + pkReturnNumber(vm, ceil(num)); +} + +DEF(stdMathPow, + "pow(value:num) -> num\n") { + + double num, ex; + if (!pkGetArgNumber(vm, 1, &num)) return; + if (!pkGetArgNumber(vm, 2, &ex)) return; + pkReturnNumber(vm, pow(num, ex)); +} + +DEF(stdMathSqrt, + "sqrt(value:num) -> num\n") { + + double num; + if (!pkGetArgNumber(vm, 1, &num)) return; + pkReturnNumber(vm, sqrt(num)); +} + +DEF(stdMathAbs, + "abs(value:num) -> num\n") { + + double num; + if (!pkGetArgNumber(vm, 1, &num)) return; + if (num < 0) num = -num; + pkReturnNumber(vm, num); +} + +DEF(stdMathSign, + "sign(value:num) -> num\n") { + + double num; + if (!pkGetArgNumber(vm, 1, &num)) return; + if (num < 0) num = -1; + else if (num > 0) num = +1; + else num = 0; + pkReturnNumber(vm, num); +} + +DEF(stdMathSine, + "sin(rad:num) -> num\n" + "Return the sine value of the argument [rad] which is an angle expressed " + "in radians.") { + + double rad; + if (!pkGetArgNumber(vm, 1, &rad)) return; + pkReturnNumber(vm, sin(rad)); +} + +DEF(stdMathCosine, + "cos(rad:num) -> num\n" + "Return the cosine value of the argument [rad] which is an angle expressed " + "in radians.") { + + double rad; + if (!pkGetArgNumber(vm, 1, &rad)) return; + pkReturnNumber(vm, cos(rad)); +} + +DEF(stdMathTangent, + "tan(rad:num) -> num\n" + "Return the tangent value of the argument [rad] which is an angle expressed " + "in radians.") { + + double rad; + if (!pkGetArgNumber(vm, 1, &rad)) return; + pkReturnNumber(vm, tan(rad)); +} + +DEF(stdMathSinh, + "sinh(val) -> val\n" + "Return the hyperbolic sine value of the argument [val].") { + + double val; + if (!pkGetArgNumber(vm, 1, &val)) return; + pkReturnNumber(vm, sinh(val)); +} + +DEF(stdMathCosh, + "cosh(val) -> val\n" + "Return the hyperbolic cosine value of the argument [val].") { + + double val; + if (!pkGetArgNumber(vm, 1, &val)) return; + pkReturnNumber(vm, cosh(val)); +} + +DEF(stdMathTanh, + "tanh(val) -> val\n" + "Return the hyperbolic tangent value of the argument [val].") { + + double val; + if (!pkGetArgNumber(vm, 1, &val)) return; + pkReturnNumber(vm, tanh(val)); +} + +DEF(stdMathArcSine, + "asin(num) -> num\n" + "Return the arcsine value of the argument [num] which is an angle " + "expressed in radians.") { + + double num; + if (!pkGetArgNumber(vm, 1, &num)) return; + + if (num < -1 || 1 < num) { + pkSetRuntimeError(vm, "Argument should be between -1 and +1"); + } + + pkReturnNumber(vm, asin(num)); +} + +DEF(stdMathArcCosine, + "acos(num) -> num\n" + "Return the arc cosine value of the argument [num] which is " + "an angle expressed in radians.") { + + double num; + if (!pkGetArgNumber(vm, 1, &num)) return; + + if (num < -1 || 1 < num) { + pkSetRuntimeError(vm, "Argument should be between -1 and +1"); + } + + pkReturnNumber(vm, acos(num)); +} + +DEF(stdMathArcTangent, + "atan(num) -> num\n" + "Return the arc tangent value of the argument [num] which is " + "an angle expressed in radians.") { + + double num; + if (!pkGetArgNumber(vm, 1, &num)) return; + pkReturnNumber(vm, atan(num)); +} + +DEF(stdMathLog10, + "log10(value:num) -> num\n" + "Return the logarithm to base 10 of argument [value]") { + + double num; + if (!pkGetArgNumber(vm, 1, &num)) return; + pkReturnNumber(vm, log10(num)); +} + +DEF(stdMathRound, + "round(value:num) -> num\n" + "Round to nearest integer, away from zero and return the number.") { + + double num; + if (!pkGetArgNumber(vm, 1, &num)) return; + pkReturnNumber(vm, round(num)); +} + +void registerModuleMath(PKVM* vm) { + + PkHandle* math = pkNewModule(vm, "math"); + + pkModuleAddFunction(vm, math, "floor", stdMathFloor, 1); + pkModuleAddFunction(vm, math, "ceil", stdMathCeil, 1); + pkModuleAddFunction(vm, math, "pow", stdMathPow, 2); + pkModuleAddFunction(vm, math, "sqrt", stdMathSqrt, 1); + pkModuleAddFunction(vm, math, "abs", stdMathAbs, 1); + pkModuleAddFunction(vm, math, "sign", stdMathSign, 1); + pkModuleAddFunction(vm, math, "sin", stdMathSine, 1); + pkModuleAddFunction(vm, math, "cos", stdMathCosine, 1); + pkModuleAddFunction(vm, math, "tan", stdMathTangent, 1); + pkModuleAddFunction(vm, math, "sinh", stdMathSinh, 1); + pkModuleAddFunction(vm, math, "cosh", stdMathCosh, 1); + pkModuleAddFunction(vm, math, "tanh", stdMathTanh, 1); + pkModuleAddFunction(vm, math, "asin", stdMathArcSine, 1); + pkModuleAddFunction(vm, math, "acos", stdMathArcCosine, 1); + pkModuleAddFunction(vm, math, "atan", stdMathArcTangent, 1); + pkModuleAddFunction(vm, math, "log10", stdMathLog10, 1); + pkModuleAddFunction(vm, math, "round", stdMathRound, 1); + + // FIXME: + // Refactor native type interface and add PI as a global to the module. + // + // Note that currently it's mutable (since it's a global variable, not + // constant and pocketlang doesn't support constant) so the user shouldn't + // modify the PI, like in python. + //pkModuleAddGlobal(vm, math, "PI", Handle-Of-PI); + + pkRegisterModule(vm, math); + pkReleaseHandle(vm, math); +} diff --git a/cli/modules/std_path.c b/cli/modules/std_path.c index 52e16ba..4f62a4c 100644 --- a/cli/modules/std_path.c +++ b/cli/modules/std_path.c @@ -4,6 +4,8 @@ * Distributed Under The MIT License */ +#include "modules.h" + #include "thirdparty/cwalk/cwalk.h" #if defined(_WIN32) && (defined(_MSC_VER) || defined(__TINYC__)) #include "thirdparty/dirent/dirent.h" @@ -90,13 +92,13 @@ static inline size_t pathAbs(const char* path, char* buff, size_t buff_size) { /* PATH MODULE FUNCTIONS */ /*****************************************************************************/ -static void _pathSetStyleUnix(PKVM* vm) { +DEF(_pathSetStyleUnix, "") { bool value; if (!pkGetArgBool(vm, 1, &value)) return; cwk_path_set_style((value) ? CWK_STYLE_UNIX : CWK_STYLE_WINDOWS); } -static void _pathGetCWD(PKVM* vm) { +DEF(_pathGetCWD, "") { char cwd[FILENAME_MAX]; if (get_cwd(cwd, sizeof(cwd)) == NULL) { // TODO: Handle error. @@ -104,7 +106,7 @@ static void _pathGetCWD(PKVM* vm) { pkReturnString(vm, cwd); } -static void _pathAbspath(PKVM* vm) { +DEF(_pathAbspath, "") { const char* path; if (!pkGetArgString(vm, 1, &path, NULL)) return; @@ -113,7 +115,7 @@ static void _pathAbspath(PKVM* vm) { pkReturnStringLength(vm, abspath, len); } -static void _pathRelpath(PKVM* vm) { +DEF(_pathRelpath, "") { const char* from, * path; if (!pkGetArgString(vm, 1, &from, NULL)) return; if (!pkGetArgString(vm, 2, &path, NULL)) return; @@ -130,7 +132,7 @@ static void _pathRelpath(PKVM* vm) { pkReturnStringLength(vm, result, len); } -static void _pathJoin(PKVM* vm) { +DEF(_pathJoin, "") { const char* paths[MAX_JOIN_PATHS + 1]; // +1 for NULL. int argc = pkGetArgc(vm); @@ -150,7 +152,7 @@ static void _pathJoin(PKVM* vm) { pkReturnStringLength(vm, result, len); } -static void _pathNormalize(PKVM* vm) { +DEF(_pathNormalize, "") { const char* path; if (!pkGetArgString(vm, 1, &path, NULL)) return; @@ -159,7 +161,7 @@ static void _pathNormalize(PKVM* vm) { pkReturnStringLength(vm, result, len); } -static void _pathBaseName(PKVM* vm) { +DEF(_pathBaseName, "") { const char* path; if (!pkGetArgString(vm, 1, &path, NULL)) return; @@ -169,7 +171,7 @@ static void _pathBaseName(PKVM* vm) { pkReturnString(vm, base_name); } -static void _pathDirName(PKVM* vm) { +DEF(_pathDirName, "") { const char* path; if (!pkGetArgString(vm, 1, &path, NULL)) return; @@ -178,14 +180,14 @@ static void _pathDirName(PKVM* vm) { pkReturnStringLength(vm, path, length); } -static void _pathIsPathAbs(PKVM* vm) { +DEF(_pathIsPathAbs, "") { const char* path; if (!pkGetArgString(vm, 1, &path, NULL)) return; pkReturnBool(vm, cwk_path_is_absolute(path)); } -static void _pathGetExtension(PKVM* vm) { +DEF(_pathGetExtension, "") { const char* path; if (!pkGetArgString(vm, 1, &path, NULL)) return; @@ -198,19 +200,19 @@ static void _pathGetExtension(PKVM* vm) { } } -static void _pathExists(PKVM* vm) { +DEF(_pathExists, "") { const char* path; if (!pkGetArgString(vm, 1, &path, NULL)) return; pkReturnBool(vm, pathIsExists(path)); } -static void _pathIsFile(PKVM* vm) { +DEF(_pathIsFile, "") { const char* path; if (!pkGetArgString(vm, 1, &path, NULL)) return; pkReturnBool(vm, pathIsFileExists(path)); } -static void _pathIsDir(PKVM* vm) { +DEF(_pathIsDir, "") { const char* path; if (!pkGetArgString(vm, 1, &path, NULL)) return; pkReturnBool(vm, pathIsDirectoryExists(path)); diff --git a/src/pk_core.c b/src/pk_core.c index 9fe0306..cf94153 100644 --- a/src/pk_core.c +++ b/src/pk_core.c @@ -15,13 +15,6 @@ #include "pk_utils.h" #include "pk_vm.h" -// M_PI is non standard. The macro _USE_MATH_DEFINES defining before importing -// will define the constants for MSVC. But for a portable solution, -// we're defining it ourselves if it isn't already. -#ifndef M_PI - #define M_PI 3.14159265358979323846 -#endif - // Returns the docstring of the function, which is a static const char* defined // just above the function by the DEF() macro below. #define DOCSTRING(fn) _pk_doc_##fn @@ -109,9 +102,16 @@ void pkClassAddMethod(PKVM* vm, PkHandle* cls, // won't be garbage collected (class handle has reference to the module). Closure* method = newClosure(vm, fn); - vmPushTempRef(vm, &method->_super); // method. - pkClosureBufferWrite(&class_->methods, vm, method); - vmPopTempRef(vm); // method. + + // FIXME: name "_init" is literal everywhere. + if (strcmp(name, "_init") == 0) { + class_->ctor = method; + + } else { + vmPushTempRef(vm, &method->_super); // method. + pkClosureBufferWrite(&class_->methods, vm, method); + vmPopTempRef(vm); // method. + } } void* pkGetSelf(const PKVM* vm) { @@ -535,7 +535,7 @@ DEF(coreAssert, DEF(coreBin, "bin(value:num) -> string\n" - "Returns as a binary value string with '0x' prefix.") { + "Returns as a binary value string with '0b' prefix.") { int64_t value; if (!validateInteger(vm, ARG(1), &value, "Argument 1")) return; @@ -613,6 +613,35 @@ DEF(coreToString, RET(VAR_OBJ(toString(vm, ARG(1)))); } +DEF(coreChr, + "chr(value:num) -> string\n" + "Returns the ASCII string value of the integer argument.") { + + int64_t num; + if (!validateInteger(vm, ARG(1), &num, "Argument 1")) return; + + if (!IS_NUM_BYTE(num)) { + RET_ERR(newString(vm, "The number is not in a byte range.")); + } + + char c = (char)num; + RET(VAR_OBJ(newStringLength(vm, &c, 1))); +} + +DEF(coreOrd, + "ord(value:string) -> num\n" + "Returns integer value of the given ASCII character.") { + + String* c; + if (!validateArgString(vm, 1, &c)) return; + if (c->length != 1) { + RET_ERR(newString(vm, "Expected a string of length 1.")); + + } else { + RET(VAR_NUM((double)c->data[0])); + } +} + DEF(corePrint, "print(...) -> void\n" "Write each argument as space seperated, to the stdout and ends with a " @@ -700,35 +729,6 @@ DEF(coreStrSub, RET(VAR_OBJ(newStringLength(vm, str->data + pos, (uint32_t)len))); } -DEF(coreStrChr, - "str_chr(value:num) -> string\n" - "Returns the ASCII string value of the integer argument.") { - - int64_t num; - if (!validateInteger(vm, ARG(1), &num, "Argument 1")) return; - - if (!IS_NUM_BYTE(num)) { - RET_ERR(newString(vm, "The number is not in a byte range.")); - } - - char c = (char)num; - RET(VAR_OBJ(newStringLength(vm, &c, 1))); -} - -DEF(coreStrOrd, - "str_ord(value:string) -> num\n" - "Returns integer value of the given ASCII character.") { - - String* c; - if (!validateArgString(vm, 1, &c)) return; - if (c->length != 1) { - RET_ERR(newString(vm, "Expected a string of length 1.")); - - } else { - RET(VAR_NUM((double)c->data[0])); - } -} - // List functions. // --------------- @@ -806,14 +806,17 @@ static void initializeBuiltinFunctions(PKVM* vm) { INITIALIZE_BUILTIN_FN("hex", coreHex, 1); INITIALIZE_BUILTIN_FN("yield", coreYield, -1); INITIALIZE_BUILTIN_FN("to_string", coreToString, 1); + INITIALIZE_BUILTIN_FN("chr", coreChr, 1); + INITIALIZE_BUILTIN_FN("ord", coreOrd, 1); INITIALIZE_BUILTIN_FN("print", corePrint, -1); INITIALIZE_BUILTIN_FN("input", coreInput, -1); INITIALIZE_BUILTIN_FN("exit", coreExit, -1); + // FIXME: + // move this functions as methods. and make "append()" a builtin. + // String functions. INITIALIZE_BUILTIN_FN("str_sub", coreStrSub, 3); - INITIALIZE_BUILTIN_FN("str_chr", coreStrChr, 1); - INITIALIZE_BUILTIN_FN("str_ord", coreStrOrd, 1); // List functions. INITIALIZE_BUILTIN_FN("list_append", coreListAppend, 2); @@ -934,192 +937,6 @@ DEF(stdLangWrite, } } -// TODO: Move math to cli as it's not part of the pocketlang core. -// -// 'math' library methods. -// ----------------------- - -DEF(stdMathFloor, - "floor(value:num) -> num\n") { - - double num; - if (!validateNumeric(vm, ARG(1), &num, "Argument 1")) return; - RET(VAR_NUM(floor(num))); -} - -DEF(stdMathCeil, - "ceil(value:num) -> num\n") { - - double num; - if (!validateNumeric(vm, ARG(1), &num, "Argument 1")) return; - RET(VAR_NUM(ceil(num))); -} - -DEF(stdMathPow, - "pow(value:num) -> num\n") { - - double num, ex; - if (!validateNumeric(vm, ARG(1), &num, "Argument 1")) return; - if (!validateNumeric(vm, ARG(2), &ex, "Argument 2")) return; - RET(VAR_NUM(pow(num, ex))); -} - -DEF(stdMathSqrt, - "sqrt(value:num) -> num\n") { - - double num; - if (!validateNumeric(vm, ARG(1), &num, "Argument 1")) return; - RET(VAR_NUM(sqrt(num))); -} - -DEF(stdMathAbs, - "abs(value:num) -> num\n") { - - double num; - if (!validateNumeric(vm, ARG(1), &num, "Argument 1")) return; - if (num < 0) num = -num; - RET(VAR_NUM(num)); -} - -DEF(stdMathSign, - "sign(value:num) -> num\n") { - - double num; - if (!validateNumeric(vm, ARG(1), &num, "Argument 1")) return; - if (num < 0) num = -1; - else if (num > 0) num = +1; - else num = 0; - RET(VAR_NUM(num)); -} - -DEF(stdMathHash, - "hash(value:var) -> num\n" - "Return the hash value of the variable, if it's not hashable it'll " - "return null.") { - - if (IS_OBJ(ARG(1))) { - if (!isObjectHashable(AS_OBJ(ARG(1))->type)) { - RET(VAR_NULL); - } - } - RET(VAR_NUM((double)varHashValue(ARG(1)))); -} - -DEF(stdMathSine, - "sin(rad:num) -> num\n" - "Return the sine value of the argument [rad] which is an angle expressed " - "in radians.") { - - double rad; - if (!validateNumeric(vm, ARG(1), &rad, "Argument 1")) return; - RET(VAR_NUM(sin(rad))); -} - -DEF(stdMathCosine, - "cos(rad:num) -> num\n" - "Return the cosine value of the argument [rad] which is an angle expressed " - "in radians.") { - - double rad; - if (!validateNumeric(vm, ARG(1), &rad, "Argument 1")) return; - RET(VAR_NUM(cos(rad))); -} - -DEF(stdMathTangent, - "tan(rad:num) -> num\n" - "Return the tangent value of the argument [rad] which is an angle expressed " - "in radians.") { - - double rad; - if (!validateNumeric(vm, ARG(1), &rad, "Argument 1")) return; - RET(VAR_NUM(tan(rad))); -} - -DEF(stdMathSinh, - "sinh(val) -> val\n" - "Return the hyperbolic sine value of the argument [val].") { - - double val; - if (!validateNumeric(vm, ARG(1), &val, "Argument 1")) return; - RET(VAR_NUM(sinh(val))); -} - -DEF(stdMathCosh, - "cosh(val) -> val\n" - "Return the hyperbolic cosine value of the argument [val].") { - - double val; - if (!validateNumeric(vm, ARG(1), &val, "Argument 1")) return; - RET(VAR_NUM(cosh(val))); -} - -DEF(stdMathTanh, - "tanh(val) -> val\n" - "Return the hyperbolic tangent value of the argument [val].") { - - double val; - if (!validateNumeric(vm, ARG(1), &val, "Argument 1")) return; - RET(VAR_NUM(tanh(val))); -} - -DEF(stdMathArcSine, - "asin(num) -> num\n" - "Return the arcsine value of the argument [num] which is an angle " - "expressed in radians.") { - - double num; - if (!validateNumeric(vm, ARG(1), &num, "Argument 1")) return; - - if (num < -1 || 1 < num) { - RET_ERR(newString(vm, "Argument should be between -1 and +1")); - } - - RET(VAR_NUM(asin(num))); -} - -DEF(stdMathArcCosine, - "acos(num) -> num\n" - "Return the arc cosine value of the argument [num] which is " - "an angle expressed in radians.") { - - double num; - if (!validateNumeric(vm, ARG(1), &num, "Argument 1")) return; - - if (num < -1 || 1 < num) { - RET_ERR(newString(vm, "Argument should be between -1 and +1")); - } - - RET(VAR_NUM(acos(num))); -} - -DEF(stdMathArcTangent, - "atan(num) -> num\n" - "Return the arc tangent value of the argument [num] which is " - "an angle expressed in radians.") { - - double num; - if (!validateNumeric(vm, ARG(1), &num, "Argument 1")) return; - RET(VAR_NUM(atan(num))); -} - -DEF(stdMathLog10, - "log10(value:num) -> num\n" - "Return the logarithm to base 10 of argument [value]") { - - double num; - if (!validateNumeric(vm, ARG(1), &num, "Argument 1")) return; - RET(VAR_NUM(log10(num))); -} - -DEF(stdMathRound, - "round(value:num) -> num\n" - "Round to nearest integer, away from zero and return the number.") { - - double num; - if (!validateNumeric(vm, ARG(1), &num, "Argument 1")) return; - RET(VAR_NUM(round(num))); -} - static void initializeCoreModules(PKVM* vm) { #define MODULE_ADD_FN(module, name, fn, argc) \ moduleAddFunctionInternal(vm, module, name, fn, argc, DOCSTRING(fn)) @@ -1139,31 +956,6 @@ static void initializeCoreModules(PKVM* vm) { MODULE_ADD_FN(lang, "debug_break", stdLangDebugBreak, 0); #endif - NEW_MODULE(math, "math"); - MODULE_ADD_FN(math, "floor", stdMathFloor, 1); - MODULE_ADD_FN(math, "ceil", stdMathCeil, 1); - MODULE_ADD_FN(math, "pow", stdMathPow, 2); - MODULE_ADD_FN(math, "sqrt", stdMathSqrt, 1); - MODULE_ADD_FN(math, "abs", stdMathAbs, 1); - MODULE_ADD_FN(math, "sign", stdMathSign, 1); - MODULE_ADD_FN(math, "hash", stdMathHash, 1); - MODULE_ADD_FN(math, "sin", stdMathSine, 1); - MODULE_ADD_FN(math, "cos", stdMathCosine, 1); - MODULE_ADD_FN(math, "tan", stdMathTangent, 1); - MODULE_ADD_FN(math, "sinh", stdMathSinh, 1); - MODULE_ADD_FN(math, "cosh", stdMathCosh, 1); - MODULE_ADD_FN(math, "tanh", stdMathTanh, 1); - MODULE_ADD_FN(math, "asin", stdMathArcSine, 1); - MODULE_ADD_FN(math, "acos", stdMathArcCosine, 1); - MODULE_ADD_FN(math, "atan", stdMathArcTangent, 1); - MODULE_ADD_FN(math, "log10", stdMathLog10, 1); - MODULE_ADD_FN(math, "round", stdMathRound, 1); - - // Note that currently it's mutable (since it's a global variable, not - // constant and pocketlang doesn't support constant) so the user shouldn't - // modify the PI, like in python. - moduleAddGlobal(vm, math, "PI", 2, VAR_NUM(M_PI)); - #undef MODULE_ADD_FN #undef NEW_MODULE } diff --git a/src/pk_value.c b/src/pk_value.c index a07be49..b388137 100644 --- a/src/pk_value.c +++ b/src/pk_value.c @@ -779,7 +779,8 @@ List* listJoin(PKVM* vm, List* l1, List* l2) { return list; } -// Return a hash value for the object. +// Return a hash value for the object. Only String and Range objects can be +// hashable. static uint32_t _hashObject(Object* obj) { ASSERT(isObjectHashable(obj->type), @@ -790,28 +791,10 @@ static uint32_t _hashObject(Object* obj) { case OBJ_STRING: return ((String*)obj)->hash; - case OBJ_LIST: - case OBJ_MAP: - goto L_unhashable; - - case OBJ_RANGE: - { + case OBJ_RANGE: { Range* range = (Range*)obj; return utilHashNumber(range->from) ^ utilHashNumber(range->to); } - - case OBJ_MODULE: - case OBJ_FUNC: - case OBJ_FIBER: - case OBJ_CLASS: - case OBJ_INST: - TODO; - UNREACHABLE(); - - default: - L_unhashable: - UNREACHABLE(); - break; } UNREACHABLE(); @@ -1346,8 +1329,8 @@ bool isValuesEqual(Var v1, Var v2) { } bool isObjectHashable(ObjectType type) { - // Only list and map are un-hashable. - return type != OBJ_LIST && type != OBJ_MAP; + // Only String and Range are hashable (since they're immutable). + return type == OBJ_STRING || type == OBJ_RANGE; } // This will prevent recursive list/map from crash when calling to_string, by diff --git a/tests/examples/brainfuck.pk b/tests/examples/brainfuck.pk index dd63727..0f35837 100644 --- a/tests/examples/brainfuck.pk +++ b/tests/examples/brainfuck.pk @@ -67,7 +67,7 @@ def execute(expr) ## output the byte at the data pointer. else if c == '.' - write(str_chr(mem[ptr])) + write(chr(mem[ptr])) else if c == ',' assert(false, "Currently input isn't supported in pocketlang.") diff --git a/tests/examples/pi.pk b/tests/examples/pi.pk index 3440632..b6e4ff2 100644 --- a/tests/examples/pi.pk +++ b/tests/examples/pi.pk @@ -3,7 +3,11 @@ ## ## PI/4 = 1 - 1/3 + 1/5 - 1/7 + 1/9 - ... -from math import abs, PI +from math import abs + +## Temproarly we cannot register variables on native modules +## will be implemented soon. So defining the PI here. +PI = 3.14159265358979323846 pi_by_4 = 0; sign = -1 for i in 1..100000 diff --git a/tests/lang/basics.pk b/tests/lang/basics.pk index 89e43d1..f415e0f 100644 --- a/tests/lang/basics.pk +++ b/tests/lang/basics.pk @@ -37,11 +37,9 @@ assert(!('foo' in {'bar':'baz'})) ## Builtin functions tests. assert(to_string(42) == '42') -## Core module test. -import math -h1 = math.hash("testing"); h2 = math.hash("test" + "ing") -assert(h1 == h2) -assert(math.ceil(1.1) == math.floor(2.9)) +## FIXME: add hash function. +##h1 = math.hash("testing"); h2 = math.hash("test" + "ing") +##assert(h1 == h2) ## Logical statement test val = 0; a = false; b = true diff --git a/tests/lang/core.pk b/tests/lang/core.pk index f2aae8c..1089351 100644 --- a/tests/lang/core.pk +++ b/tests/lang/core.pk @@ -1,8 +1,5 @@ ## Core builtin functions and attribute tests. -## Math functions -from math import * - assert(hex(12648430) == '0xc0ffee') assert(hex(255) == '0xff' and hex(10597059) == '0xa1b2c3') assert(hex(-4294967295) == '-0xffffffff') ## the largest. @@ -48,61 +45,6 @@ assert(r.as_list == [1, 2, 3, 4]) assert(r.first == 1) assert(r.last == 5) -assert(sin(0) == 0) -assert(sin(PI/2) == 1) - -threshold = 0.0000000000001 - -assert(abs(cos(PI/3) - 0.5) < threshold ) -assert(abs(tan(PI/4) - 1.0) < threshold ) -for i in 0..1000 - assert(abs(sin(i) / cos(i) - tan(i)) < threshold) -end - -assert((cosh(.5) - 1.1276259652063807) < threshold) -assert((tanh(0.5) - 1.127625965206) < threshold) -for i in 0..100 - assert(abs(sinh(i) / cosh(i) - tanh(i)) < threshold) -end - -assert(abs(acos(PI/4) - 0.5) < 0.35) -assert(abs(atan(PI/4) - 0.5) < 0.2) - -assert((acos(0.5) - 1.1276259652063807) < threshold) -assert((atan(0.3) - 1.1276259652063807) < threshold) - -x = -1; interval = 1000 -for i in 0..interval-1 - x += 2/interval - assert(abs(sin(asin(x)) - x) < threshold) - assert(abs(cos(acos(x)) - x) < threshold) - assert(abs(tan(atan(x)) - x) < threshold) -end - -assert(abs(log10(2) - 0.3010299956639812) < threshold) -assert(round(1.4) == 1) -assert(round(1.5) == 2) -assert(round(-1.5) == -2) - -## Note that these mathe functions are removed temproarly from the core -## For more information see PR #201 -## -##assert(abs(log2(2) - 1) < threshold) -##assert(abs(log2(1) - 0) < threshold) -##assert(abs(log2(5) - 2.321928094887362) < threshold) -## -##assert(abs(hypot(1,1) - 1.414213562373095) < threshold) -##assert(abs(hypot(3,5) - 5.830951894845301) < threshold) -## -##assert(abs(cbrt(27) - 3) < threshold) -##assert(abs(cbrt(9) - 2.080083823051904) < threshold) -## -##assert(abs(gamma(5) - 24) < threshold) -##assert(abs(gamma(2.2) - 1.101802490879713) < threshold) - - - - # If we got here, that means all test were passed. print('All TESTS PASSED') diff --git a/tests/modules/math.pk b/tests/modules/math.pk new file mode 100644 index 0000000..4356ba8 --- /dev/null +++ b/tests/modules/math.pk @@ -0,0 +1,64 @@ + +from math import * + +assert(ceil(1.1) == floor(2.9)) + +## FIXME: +## temproarly modules cannot define globals via native interface +## and it'll be fixed soon. +PI = 3.14159265358979323846 + +assert(sin(0) == 0) +assert(sin(PI/2) == 1) + +threshold = 0.0000000000001 + +assert(abs(cos(PI/3) - 0.5) < threshold ) +assert(abs(tan(PI/4) - 1.0) < threshold ) +for i in 0..1000 + assert(abs(sin(i) / cos(i) - tan(i)) < threshold) +end + +assert((cosh(.5) - 1.1276259652063807) < threshold) +assert((tanh(0.5) - 1.127625965206) < threshold) +for i in 0..100 + assert(abs(sinh(i) / cosh(i) - tanh(i)) < threshold) +end + +assert(abs(acos(PI/4) - 0.5) < 0.35) +assert(abs(atan(PI/4) - 0.5) < 0.2) + +assert((acos(0.5) - 1.1276259652063807) < threshold) +assert((atan(0.3) - 1.1276259652063807) < threshold) + +x = -1; interval = 1000 +for i in 0..interval-1 + x += 2/interval + assert(abs(sin(asin(x)) - x) < threshold) + assert(abs(cos(acos(x)) - x) < threshold) + assert(abs(tan(atan(x)) - x) < threshold) +end + +assert(abs(log10(2) - 0.3010299956639812) < threshold) +assert(round(1.4) == 1) +assert(round(1.5) == 2) +assert(round(-1.5) == -2) + +## Note that these mathe functions are removed temproarly from the core +## For more information see PR #201 +## +##assert(abs(log2(2) - 1) < threshold) +##assert(abs(log2(1) - 0) < threshold) +##assert(abs(log2(5) - 2.321928094887362) < threshold) +## +##assert(abs(hypot(1,1) - 1.414213562373095) < threshold) +##assert(abs(hypot(3,5) - 5.830951894845301) < threshold) +## +##assert(abs(cbrt(27) - 3) < threshold) +##assert(abs(cbrt(9) - 2.080083823051904) < threshold) +## +##assert(abs(gamma(5) - 24) < threshold) +##assert(abs(gamma(2.2) - 1.101802490879713) < threshold) + +# If we got here, that means all test were passed. +print('All TESTS PASSED') diff --git a/tests/native/README.md b/tests/native/README.md index 140b7e5..1ba5fc9 100644 --- a/tests/native/README.md +++ b/tests/native/README.md @@ -1,7 +1,7 @@ ## Example on how to integrate pocket VM with in your application. -- Including this example this repository contains several examples on how to integrate -pocket VM with your application +- Including this example this repository contains several examples on how to +integrate pocket VM with your application - These examples (currently 2 examples) - The `cli/` application - The `docs/try/main.c` web assembly version of pocketlang diff --git a/tests/native/example1.c b/tests/native/example1.c index c490613..12446fa 100644 --- a/tests/native/example1.c +++ b/tests/native/example1.c @@ -10,17 +10,17 @@ // The pocket script we're using to test. static const char* code = - " from YourModule import variableToC \n" - " a = 42 \n" - " b = variableToC(a) \n" - " print('[pocket] b =', b) \n" + " from my_module import cFunction \n" + " a = 42 \n" + " b = cFunction(a) \n" + " print('[pocket] b = $b') \n" ; /*****************************************************************************/ /* MODULE FUNCTION */ /*****************************************************************************/ -static void variableToC(PKVM* vm) { +static void cFunction(PKVM* vm) { // Get the parameter from pocket VM. double a; @@ -36,15 +36,7 @@ static void variableToC(PKVM* vm) { /* POCKET VM CALLBACKS */ /*****************************************************************************/ -// Error report callback. -static void reportError(PKVM* vm, PkErrorType type, - const char* file, int line, - const char* message) { - fprintf(stderr, "Error: %s\n", message); -} - -// print() callback to write stdout. -static void stdoutWrite(PKVM* vm, const char* text) { +static void stdoutCallback(PKVM* vm, const char* text) { fprintf(stdout, "%s", text); } @@ -56,21 +48,20 @@ int main(int argc, char** argv) { // Pocket VM configuration. PkConfiguration config = pkNewConfiguration(); - config.error_fn = reportError; - config.write_fn = stdoutWrite; - //config.read_fn = stdinRead; + config.write_fn = stdoutCallback; // Create a new pocket VM. PKVM* vm = pkNewVM(&config); - // Register your module. - PkHandle* your_module = pkNewModule(vm, "YourModule"); - pkModuleAddFunction(vm, your_module, "variableToC", variableToC, 1); - pkReleaseHandle(vm, your_module); + // Registering a native module. + PkHandle* my_module = pkNewModule(vm, "my_module"); + pkModuleAddFunction(vm, my_module, "cFunction", cFunction, 1); + pkRegisterModule(vm, my_module); + pkReleaseHandle(vm, my_module); // The path and the source code. - PkStringPtr source = { code, NULL, NULL, 0, 0 }; - PkStringPtr path = { "./some/path/", NULL, NULL, 0, 0 }; + PkStringPtr source = { .string = code }; + PkStringPtr path = { .string = "./some/path/" }; // Run the code. PkResult result = pkInterpretSource(vm, source, path, NULL/*options*/); diff --git a/tests/native/example2.c b/tests/native/example2.c index 7a9e2ae..2d0b238 100644 --- a/tests/native/example2.c +++ b/tests/native/example2.c @@ -3,174 +3,85 @@ * Distributed Under The MIT License */ +#error Native interface is being refactored and will be completed soon. + // This is an example on how to write your own custom type (Vector here) and // bind it with with the pocket VM. #include -#include -#include -#include +#include /* For malloc */ +#include /* For printf */ +#include /* For strncmp */ +#include /* For sqrt */ // The script we're using to test the native Vector type. static const char* code = - " import Vector # The native module. \n" - " print('Module =', Vector) \n" - " \n" - " vec1 = Vector.new(1, 2) # Calling native method. \n" - " print('vec1 =', 'Vector.new(1, 2)') \n" - " print() \n" - " \n" - " # Using the native getter. \n" - " print('vec1.x =', vec1.x) \n" - " print('vec1.y =', vec1.y) \n" - " print('vec1.length =', vec1.length) \n" - " print() \n" - " \n" - " # Using the native setter. \n" - " vec1.x = 3; vec1.y = 4; \n" - " print('vec1.x =', vec1.x) \n" - " print('vec1.y =', vec1.y) \n" - " print('vec1.length =', vec1.length) \n" - " print() \n" - " \n" - " vec2 = Vector.new(5, 6) \n" - " vec3 = Vector.add(vec1, vec2) \n" - " print('vec3 =', 'Vector.add(vec1, vec2)') \n" - " print('vec3.x =', vec3.x) \n" - " print('vec3.y =', vec3.y) \n" - " \n" + " from vector import Vec2 \n" + " print('Class = $Vec2') \n" + " \n" + " v1 = Vec2(1, 2) \n" + " print('v1 = $v1') \n" + " print() \n" + " \n" + " print('v1.x = ${v1.x}') \n" + " print('v1.y = ${v1.y}') \n" + " print('v1.length = ${v1.length}') \n" + " print() \n" + " \n" + " v1.x = 3; v1.y = 4; \n" + " print('v1.x = ${v1.x}') \n" + " print('v1.y = ${v1.y}') \n" + " print('v1.length = ${v1.length}') \n" + " print() \n" + " \n" + " v2 = Vec2(5, 6) \n" + " v3 = v1.add(v2) \n" + " print('v3 = ${v3}') \n" + " print('v3.x = ${v3.x}') \n" + " print('v3.y = ${v3.y}') \n" + " \n" ; -/*****************************************************************************/ -/* NATIVE TYPE DEFINES & CALLBACKS */ -/*****************************************************************************/ - -// An enum value of native object, used as unique of the type in pocketlang. -typedef enum { - OBJ_VECTOR = 0, -} ObjType; - -typedef struct { - double x, y; // Vector variables. -} Vector; - -// Get name callback, will called from pocketlang to get the type name from -// the ID (the enum value). -const char* getObjName(uint32_t id) { - switch ((ObjType)id) { - case OBJ_VECTOR: return "Vector"; - } - return NULL; // Unreachable. -} - -// Instance getter callback to get a value from the native instance. -// The hash value and the length of the string are provided with the -// argument [attrib]. -void objGetAttrib(PKVM* vm, void* instance, uint32_t id, PkStringPtr attrib) { - - switch ((ObjType)id) { - case OBJ_VECTOR: { - Vector* vector = ((Vector*)instance); - - if (strcmp(attrib.string, "x") == 0) { - pkReturnNumber(vm, vector->x); - return; - - } else if (strcmp(attrib.string, "y") == 0) { - pkReturnNumber(vm, vector->y); - return; - - } else if (strcmp(attrib.string, "length") == 0) { - double length = sqrt(pow(vector->x, 2) + pow(vector->y, 2)); - pkReturnNumber(vm, length); - return; - - } - } break; - } - - // If we reached here that means the attribute doesn't exists. - // Since we haven't used pkReturn...() function, pocket VM already - // know that the attribute doesn't exists. just return. - return; -} - -// Instance setter callback to set the value to the native instance. -// The hash value and the length of the string are provided with the -// argument [attrib]. -bool objSetAttrib(PKVM* vm, void* instance, uint32_t id, PkStringPtr attrib) { - - switch ((ObjType)id) { - case OBJ_VECTOR: { - Vector* vector = ((Vector*)instance); - - if (strcmp(attrib.string, "x") == 0) { - double x; // Get the number x. - if (!pkGetArgNumber(vm, 0, &x)) return false; - vector->x = x; - return true; - - } else if (strcmp(attrib.string, "y") == 0) { - double y; // Get the number x. - if (!pkGetArgNumber(vm, 0, &y)) return false; - vector->y = y; - return true; - - } - } break; - } - - // If we reached here that means the attribute doesn't exists. - // Return false to indicate it. - return false; -} - -// The free object callback, called just before the native instance, garbage -// collect. -void freeObj(PKVM* vm, void* instance, uint32_t id) { - free((void*)instance); // Your cleanups. -} - /*****************************************************************************/ /* VECTOR MODULE FUNCTIONS REGISTER */ /*****************************************************************************/ -// The Vector.new(x, y) function. -void _vecNew(PKVM* vm) { - double x, y; // The args. - - // Get the args from the stack, If it's not number, return. - if (!pkGetArgNumber(vm, 1, &x)) return; - if (!pkGetArgNumber(vm, 2, &y)) return; - - // Create a new vector. +typedef struct { + double x, y; +} Vector; + +// Native instance allocation callback. +void* _newVec() { Vector* vec = (Vector*)malloc(sizeof(Vector)); - vec->x = x, vec->y = y; - pkReturnInstNative(vm, (void*)vec, OBJ_VECTOR); + vec->x = 0; + vec->y = 0; + return vec; } -// The Vector.length(vec) function. -void _vecAdd(PKVM* vm) { - Vector *v1, *v2; - if (!pkGetArgInst(vm, 1, OBJ_VECTOR, (void**)&v1)) return; - if (!pkGetArgInst(vm, 2, OBJ_VECTOR, (void**)&v2)) return; - - // Create a new vector. - Vector* v3 = (Vector*)malloc(sizeof(Vector)); - v3->x = v1->x + v2->x; - v3->y = v1->y + v2->y; +// Native instance de-allocatoion callback. +void _deleteVec(void* vector) { + free(vector); +} - pkReturnInstNative(vm, (void*)v3, OBJ_VECTOR); +// Vec2 'add' method. +void _vec2Add(PKVM* vm) { + Vector* self = (Vector*)pkGetSelf(vm); + // FIXME: + // Temproarly it's not possible to get vector from the args since the native + // interface is being refactored. Will be implemented soon. } // Register the 'Vector' module and it's functions. void registerVector(PKVM* vm) { - PkHandle* vector = pkNewModule(vm, "Vector"); + PkHandle* vector = pkNewModule(vm, "vector"); - pkModuleAddFunction(vm, vector, "new", _vecNew, 2); - pkModuleAddFunction(vm, vector, "add", _vecAdd, 2); + PkHandle* Vec2 = pkNewClass(vm, "Vec2", NULL /*Base Class*/, + vector, _newVec, _deleteVec); + pkClassAddMethod(vm, Vec2, "add", _vec2Add, 1); + pkReleaseHandle(vm, Vec2); + pkRegisterModule(vm, vector); pkReleaseHandle(vm, vector); } @@ -178,35 +89,20 @@ void registerVector(PKVM* vm) { /* POCKET VM CALLBACKS */ /*****************************************************************************/ -// Error report callback. -void reportError(PKVM* vm, PkErrorType type, - const char* file, int line, - const char* message) { - fprintf(stderr, "Error: %s\n", message); -} - -// print() callback to write stdout. -void stdoutWrite(PKVM* vm, const char* text) { +void stdoutCallback(PKVM* vm, const char* text) { fprintf(stdout, "%s", text); } - int main(int argc, char** argv) { PkConfiguration config = pkNewConfiguration(); - config.error_fn = reportError; - config.write_fn = stdoutWrite; - //config.read_fn = stdinRead; - config.inst_free_fn = freeObj; - config.inst_name_fn = getObjName; - config.inst_get_attrib_fn = objGetAttrib; - config.inst_set_attrib_fn = objSetAttrib; + config.write_fn = stdoutCallback; PKVM* vm = pkNewVM(&config); registerVector(vm); - PkStringPtr source = { code, NULL, NULL, 0, 0 }; - PkStringPtr path = { "./some/path/", NULL, NULL, 0, 0 }; + PkStringPtr source = { .string = code }; + PkStringPtr path = { .string = "./some/path/" }; PkResult result = pkInterpretSource(vm, source, path, NULL/*options*/); pkFreeVM(vm); diff --git a/tests/random/linked_list.pk b/tests/random/linked_list.pk new file mode 100644 index 0000000..26e3c60 --- /dev/null +++ b/tests/random/linked_list.pk @@ -0,0 +1,67 @@ + +class Node + def _init(val) + self.val = val + self.next = null + end + + def _to_string() + return "(${self.val})" + end +end + +class LinkedList + def _init() + self.head = null + end + + def append(node) + if self.head == null + self.head = node + else + last = self.head + while last.next + last = last.next + end + last.next = node + end + end + + def reverse() + curr = self.head + prev = null; next = null + while curr + next = curr.next + curr.next = prev + prev = curr + curr = next + end + self.head = prev + end + + def _to_string() + ret = "" + next = self.head + while next + ret += next._to_string() + ret += " --> " + next = next.next + end + ret += "null" + return ret + end +end + +ll = LinkedList() +ll.append(Node(4)) +ll.append(Node(6)) +ll.append(Node(3)) +ll.append(Node(9)) + +## FIXME: No override supported at the moment. +print(ll._to_string()) + +ll.reverse() + +print(ll._to_string()) + diff --git a/tests/random/lisp_eval.pk b/tests/random/lisp_eval.pk index fc3b403..3493668 100644 --- a/tests/random/lisp_eval.pk +++ b/tests/random/lisp_eval.pk @@ -65,7 +65,7 @@ def eval(expr, ind) return [r[1] / r[2], r[3]] else if isnum(c) - val = str_ord(c) - str_ord('0') + val = ord(c) - ord('0') assert(0 <= val and val < 10) return [val, ind] @@ -93,7 +93,7 @@ end ## Return true if c in numeric. def isnum(c) - k = str_ord(c) - str_ord('0') + k = ord(c) - ord('0') ## TODO: k in 0..10 return (0 <= k and k < 10) end diff --git a/tests/tests.py b/tests/tests.py index ffeded7..637ed1e 100644 --- a/tests/tests.py +++ b/tests/tests.py @@ -26,8 +26,13 @@ TEST_SUITE = { "lang/functions.pk", "lang/import.pk", ), + + "Modules Test" : ( + "modules/math.pk", + ), "Random Scripts" : ( + "random/linked_list.pk", "random/lisp_eval.pk", "random/string_algo.pk", ),