mirror of
https://github.com/zekexiao/pocketlang.git
synced 2025-02-05 20:26:53 +08:00
math module moved to cli/modules
This commit is contained in:
parent
179026294d
commit
2fe579d9cc
@ -15,6 +15,7 @@
|
||||
|
||||
#include "modules/std_io.c"
|
||||
#include "modules/std_path.c"
|
||||
#include "modules/std_math.c"
|
||||
|
||||
/*****************************************************************************/
|
||||
/* THIRDPARTY SOURCES */
|
||||
|
@ -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_<fn> = 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 */
|
||||
/*****************************************************************************/
|
||||
|
@ -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;
|
||||
|
218
cli/modules/std_math.c
Normal file
218
cli/modules/std_math.c
Normal file
@ -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 <math.h>
|
||||
|
||||
// M_PI is non standard. The macro _USE_MATH_DEFINES defining before importing
|
||||
// <math.h> 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);
|
||||
}
|
@ -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));
|
||||
|
298
src/pk_core.c
298
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
|
||||
// <math.h> 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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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.")
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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')
|
||||
|
||||
|
64
tests/modules/math.pk
Normal file
64
tests/modules/math.pk
Normal file
@ -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')
|
@ -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
|
||||
|
@ -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*/);
|
||||
|
@ -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 <pocketlang.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h> /* For malloc */
|
||||
#include <stdio.h> /* For printf */
|
||||
#include <string.h> /* For strncmp */
|
||||
#include <math.h> /* 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);
|
||||
|
67
tests/random/linked_list.pk
Normal file
67
tests/random/linked_list.pk
Normal file
@ -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())
|
||||
|
@ -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
|
||||
|
@ -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",
|
||||
),
|
||||
|
Loading…
Reference in New Issue
Block a user