Merge pull request #249 from ThakeeNathees/enhancements

minor enhancements/improvements
This commit is contained in:
Thakee Nathees 2022-06-05 12:56:31 +05:30 committed by GitHub
commit e6b094a926
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 164 additions and 26 deletions

View File

@ -181,7 +181,8 @@ bool vmPrepareFiber(PKVM* vm, Fiber* fiber, int argc, Var* argv) {
if ((fiber->closure->fn->arity != -1) && argc != fiber->closure->fn->arity) { if ((fiber->closure->fn->arity != -1) && argc != fiber->closure->fn->arity) {
char buff[STR_INT_BUFF_SIZE]; char buff[STR_INT_BUFF_SIZE];
sprintf(buff, "%d", fiber->closure->fn->arity); sprintf(buff, "%d", fiber->closure->fn->arity);
_ERR_FAIL(stringFormat(vm, "Expected exactly $ argument(s).", buff)); _ERR_FAIL(stringFormat(vm, "Expected exactly $ argument(s) for "
"function $.", buff, fiber->closure->fn->name));
} }
if (fiber->state != FIBER_NEW) { if (fiber->state != FIBER_NEW) {
@ -1245,7 +1246,8 @@ L_do_call:
// No constructor is defined on the class. Just return self. // No constructor is defined on the class. Just return self.
if (closure == NULL) { if (closure == NULL) {
if (argc != 0) { if (argc != 0) {
String* msg = stringFormat(vm, "Expected exactly 0 argument(s)."); String* msg = stringFormat(vm, "Expected exactly 0 argument(s) "
"for constructor $.", cls->name->data);
RUNTIME_ERROR(msg); RUNTIME_ERROR(msg);
} }
@ -1265,8 +1267,8 @@ L_do_call:
// -1 argument means multiple number of args. // -1 argument means multiple number of args.
if (closure->fn->arity != -1 && closure->fn->arity != argc) { if (closure->fn->arity != -1 && closure->fn->arity != argc) {
char buff[STR_INT_BUFF_SIZE]; sprintf(buff, "%d", closure->fn->arity); char buff[STR_INT_BUFF_SIZE]; sprintf(buff, "%d", closure->fn->arity);
String* msg = stringFormat(vm, "Expected exactly $ argument(s).", String* msg = stringFormat(vm, "Expected exactly $ argument(s) "
buff); "for function $", buff, closure->fn->name);
RUNTIME_ERROR(msg); RUNTIME_ERROR(msg);
} }

View File

@ -9,6 +9,10 @@
#include "gen/ext_term.pk.h" //<< AMALG_INLINE >> #include "gen/ext_term.pk.h" //<< AMALG_INLINE >>
#endif #endif
#ifdef _WIN32
#include <fcntl.h>
#endif
#define TERM_IMPLEMENT #define TERM_IMPLEMENT
#include "thirdparty/term/term.h" //<< AMALG_INLINE >> #include "thirdparty/term/term.h" //<< AMALG_INLINE >>
#undef TERM_IMPLEMENT #undef TERM_IMPLEMENT
@ -229,6 +233,14 @@ void _termReadEvent(PKVM* vm) {
pkSetSlotBool(vm, 0, term_read_event(event)); pkSetSlotBool(vm, 0, term_read_event(event));
} }
// On windows it'll set stdout to binary mode, on other platforms this function
// won't make make any difference.
void _termBinaryMode(PKVM* vm) {
#ifdef _WIN32
(void) _setmode(_fileno(stdout), _O_BINARY);
#endif
}
/*****************************************************************************/ /*****************************************************************************/
/* MODULE REGISTER */ /* MODULE REGISTER */
/*****************************************************************************/ /*****************************************************************************/
@ -252,6 +264,11 @@ void registerModuleTerm(PKVM* vm) {
pkModuleAddSource(vm, term, ext_term_pk); pkModuleAddSource(vm, term, ext_term_pk);
// This is required for language server. Since we need to send '\r\n' to
// the lsp client but windows will change '\n' to '\r\n' and it'll become
// '\r\r\n', binary mode will prevent this.
pkModuleAddFunction(vm, term, "binary_mode", _termBinaryMode, 0);
pkRegisterModule(vm, term); pkRegisterModule(vm, term);
pkReleaseHandle(vm, term); pkReleaseHandle(vm, term);
} }

View File

@ -35,14 +35,12 @@ DEF(_ioWrite,
pkSetRuntimeError(vm, "Cannot write to stdin."); pkSetRuntimeError(vm, "Cannot write to stdin.");
return; return;
// TODO: If the string contain null bytes it won't print anything after
// that, not sure if that needs to be fixed.
case 1: case 1:
fprintf(stdout, "%s", bytes); fwrite(bytes, sizeof(char), length, stdout);
return; return;
case 2: case 2:
fprintf(stderr, "%s", bytes); fwrite(bytes, sizeof(char), length, stderr);
return; return;
} }
} }
@ -54,6 +52,13 @@ DEF(_ioFlush,
fflush(stdout); fflush(stdout);
} }
DEF(_ioGetc,
"io.getc() -> String\n"
"Read a single character from stdin and return it.") {
char c = (char) fgetc(stdin);
pkSetSlotStringLength(vm, 0, &c, 1);
}
/*****************************************************************************/ /*****************************************************************************/
/* FILE CLASS */ /* FILE CLASS */
/*****************************************************************************/ /*****************************************************************************/
@ -81,8 +86,8 @@ typedef enum {
FMODE_APPEND_EXT = (_FMODE_EXT | FMODE_APPEND), FMODE_APPEND_EXT = (_FMODE_EXT | FMODE_APPEND),
FMODE_READ_BIN = (_FMODE_BIN | FMODE_READ), FMODE_READ_BIN = (_FMODE_BIN | FMODE_READ),
FMODE_WRITE_BIN = (_FMODE_BIN | FMODE_READ), FMODE_WRITE_BIN = (_FMODE_BIN | FMODE_WRITE),
FMODE_APPEND_BIN = (_FMODE_BIN | FMODE_READ), FMODE_APPEND_BIN = (_FMODE_BIN | FMODE_APPEND),
FMODE_READ_BIN_EXT = (_FMODE_BIN | FMODE_READ_EXT), FMODE_READ_BIN_EXT = (_FMODE_BIN | FMODE_READ_EXT),
FMODE_WRITE_BIN_EXT = (_FMODE_BIN | FMODE_WRITE_EXT), FMODE_WRITE_BIN_EXT = (_FMODE_BIN | FMODE_WRITE_EXT),
@ -439,6 +444,7 @@ void registerModuleIO(PKVM* vm) {
pkModuleAddFunction(vm, io, "write", _ioWrite, 2); pkModuleAddFunction(vm, io, "write", _ioWrite, 2);
pkModuleAddFunction(vm, io, "flush", _ioFlush, 0); pkModuleAddFunction(vm, io, "flush", _ioFlush, 0);
pkModuleAddFunction(vm, io, "getc", _ioGetc, 0);
PkHandle* cls_file = pkNewClass(vm, "File", NULL, io, _fileNew, _fileDelete); PkHandle* cls_file = pkNewClass(vm, "File", NULL, io, _fileNew, _fileDelete);
pkClassAddMethod(vm, cls_file, "open", _fileOpen, -1); pkClassAddMethod(vm, cls_file, "open", _fileOpen, -1);

View File

@ -82,6 +82,83 @@ static Var _cJsonToPocket(PKVM* vm, cJSON* item) {
UNREACHABLE(); UNREACHABLE();
} }
static cJSON* _pocketToCJson(PKVM* vm, Var item) {
PkVarType vt = getVarType(item);
switch (vt) {
case PK_NULL:
return cJSON_CreateNull();
case PK_BOOL:
return cJSON_CreateBool(AS_BOOL(item));
case PK_NUMBER:
return cJSON_CreateNumber(AS_NUM(item));
case PK_STRING:
return cJSON_CreateString(((String*) AS_OBJ(item))->data);
case PK_LIST: {
List* list = (List*) AS_OBJ(item);
cJSON* arr = cJSON_CreateArray();
bool err = false;
for (uint32_t i = 0; i < list->elements.count; i++) {
cJSON* elem = _pocketToCJson(vm, list->elements.data[i]);
if (elem == NULL) {
err = true; break;
};
cJSON_AddItemToArray(arr, elem);
}
if (err) {
cJSON_Delete(arr);
return NULL;
}
return arr;
}
case PK_MAP: {
Map* map = (Map*) AS_OBJ(item);
cJSON* obj = cJSON_CreateObject();
bool err = false;
MapEntry* e = map->entries;
for (; e < map->entries + map->capacity; e++) {
if (IS_UNDEF(e->key)) continue;
if (!IS_OBJ_TYPE(e->key, OBJ_STRING)) {
pkSetRuntimeErrorFmt(vm, "Expected string as json object key, "
"instead got type '%s'.", varTypeName(e->key));
err = true; break;
}
cJSON* value = _pocketToCJson(vm, e->value);
if (value == NULL) { err = true; break; }
cJSON_AddItemToObject(obj, ((String*) AS_OBJ(e->key))->data, value);
}
if (err) {
cJSON_Delete(obj);
return NULL;
}
return obj;
}
default: {
pkSetRuntimeErrorFmt(vm, "Object of type '%s' cannot be serialized "
"to json.", varTypeName(item));
return NULL;
}
}
UNREACHABLE();
return NULL;
}
DEF(_jsonParse, DEF(_jsonParse,
"json.parse(json_str:String) -> var\n" "json.parse(json_str:String) -> var\n"
"Parse a json string into pocket lang object.") { "Parse a json string into pocket lang object.") {
@ -108,6 +185,39 @@ DEF(_jsonParse,
vm->fiber->ret[0] = obj; vm->fiber->ret[0] = obj;
} }
DEF(_jsonPrint,
"json.print(value:Var[, pretty:Bool=false])\n"
"Render a pocketlang value into text. Takes an optional argument pretty, if "
"true it'll pretty print the output.") {
int argc = pkGetArgc(vm);
if (!pkCheckArgcRange(vm, argc, 1, 2)) return;
bool pretty = false;
if (argc == 2) {
if (!pkValidateSlotBool(vm, 2, &pretty)) return;
}
Var value = vm->fiber->ret[1];
cJSON* json = _pocketToCJson(vm, value);
// A runtime error already set.
if (json == NULL) return;
char* string = (pretty)
? cJSON_Print(json)
: cJSON_PrintUnformatted(json);
cJSON_Delete(json);
if (string == NULL) {
pkSetRuntimeError(vm, "Failed to print json.");
return;
}
pkSetSlotString(vm, 0, string);
free(string);
}
/*****************************************************************************/ /*****************************************************************************/
/* MODULE REGISTER */ /* MODULE REGISTER */
/*****************************************************************************/ /*****************************************************************************/
@ -116,6 +226,7 @@ void registerModuleJson(PKVM* vm) {
PkHandle* json = pkNewModule(vm, "json"); PkHandle* json = pkNewModule(vm, "json");
pkModuleAddFunction(vm, json, "parse", _jsonParse, 1); pkModuleAddFunction(vm, json, "parse", _jsonParse, 1);
pkModuleAddFunction(vm, json, "print", _jsonPrint, -1);
pkRegisterModule(vm, json); pkRegisterModule(vm, json);
pkReleaseHandle(vm, json); pkReleaseHandle(vm, json);

View File

@ -46,17 +46,17 @@ DEF(_typesHash,
/* BYTE BUFFER */ /* BYTE BUFFER */
/*****************************************************************************/ /*****************************************************************************/
void* _bytebuffNew(PKVM* vm) { static void* _bytebuffNew(PKVM* vm) {
pkByteBuffer* self = pkRealloc(vm, NULL, sizeof(pkByteBuffer)); pkByteBuffer* self = pkRealloc(vm, NULL, sizeof(pkByteBuffer));
pkByteBufferInit(self); pkByteBufferInit(self);
return self; return self;
} }
void _bytebuffDelete(PKVM* vm, void* buff) { static void _bytebuffDelete(PKVM* vm, void* buff) {
pkRealloc(vm, buff, 0); pkRealloc(vm, buff, 0);
} }
void _bytebuffReserve(PKVM* vm) { DEF(_bytebuffReserve, "") {
double size; double size;
if (!pkValidateSlotNumber(vm, 1, &size)) return; if (!pkValidateSlotNumber(vm, 1, &size)) return;
@ -65,7 +65,7 @@ void _bytebuffReserve(PKVM* vm) {
} }
// buff.fill(data, count) // buff.fill(data, count)
void _bytebuffFill(PKVM* vm) { DEF(_bytebuffFill, "") {
uint32_t n; uint32_t n;
if (!pkValidateSlotInteger(vm, 1, &n)) return; if (!pkValidateSlotInteger(vm, 1, &n)) return;
if (n < 0x00 || n > 0xff) { if (n < 0x00 || n > 0xff) {
@ -81,14 +81,14 @@ void _bytebuffFill(PKVM* vm) {
pkByteBufferFill(self, vm, (uint8_t) n, (int) count); pkByteBufferFill(self, vm, (uint8_t) n, (int) count);
} }
void _bytebuffClear(PKVM* vm) { DEF(_bytebuffClear, "") {
// TODO: Should I also zero or reduce the capacity? // TODO: Should I also zero or reduce the capacity?
pkByteBuffer* self = pkGetSelf(vm); pkByteBuffer* self = pkGetSelf(vm);
self->count = 0; self->count = 0;
} }
// Returns the length of bytes were written. // Returns the length of bytes were written.
void _bytebuffWrite(PKVM* vm) { DEF(_bytebuffWrite, "") {
pkByteBuffer* self = pkGetSelf(vm); pkByteBuffer* self = pkGetSelf(vm);
PkVarType type = pkGetSlotType(vm, 1); PkVarType type = pkGetSlotType(vm, 1);
@ -135,7 +135,7 @@ void _bytebuffWrite(PKVM* vm) {
} }
void _bytebuffSubscriptGet(PKVM* vm) { DEF(_bytebuffSubscriptGet, "") {
double index; double index;
if (!pkValidateSlotNumber(vm, 1, &index)) return; if (!pkValidateSlotNumber(vm, 1, &index)) return;
if (floor(index) != index) { if (floor(index) != index) {
@ -154,7 +154,7 @@ void _bytebuffSubscriptGet(PKVM* vm) {
} }
void _bytebuffSubscriptSet(PKVM* vm) { DEF(_bytebuffSubscriptSet, "") {
double index, value; double index, value;
if (!pkValidateSlotNumber(vm, 1, &index)) return; if (!pkValidateSlotNumber(vm, 1, &index)) return;
if (!pkValidateSlotNumber(vm, 2, &value)) return; if (!pkValidateSlotNumber(vm, 2, &value)) return;
@ -184,12 +184,12 @@ void _bytebuffSubscriptSet(PKVM* vm) {
} }
void _bytebuffString(PKVM* vm) { DEF(_bytebuffString, "") {
pkByteBuffer* self = pkGetSelf(vm); pkByteBuffer* self = pkGetSelf(vm);
pkSetSlotStringLength(vm, 0, self->data, self->count); pkSetSlotStringLength(vm, 0, self->data, self->count);
} }
void _bytebuffCount(PKVM* vm) { DEF(_bytebuffCount, "") {
pkByteBuffer* self = pkGetSelf(vm); pkByteBuffer* self = pkGetSelf(vm);
pkSetSlotNumber(vm, 0, self->count); pkSetSlotNumber(vm, 0, self->count);
} }
@ -202,17 +202,17 @@ typedef struct {
double x, y, z; double x, y, z;
} Vector; } Vector;
void* _vectorNew(PKVM* vm) { static void* _vectorNew(PKVM* vm) {
Vector* vec = pkRealloc(vm, NULL, sizeof(Vector)); Vector* vec = pkRealloc(vm, NULL, sizeof(Vector));
memset(vec, 0, sizeof(Vector)); memset(vec, 0, sizeof(Vector));
return vec; return vec;
} }
void _vectorDelete(PKVM* vm, void* vec) { static void _vectorDelete(PKVM* vm, void* vec) {
pkRealloc(vm, vec, 0); pkRealloc(vm, vec, 0);
} }
void _vectorInit(PKVM* vm) { DEF(_vectorInit, "") {
int argc = pkGetArgc(vm); int argc = pkGetArgc(vm);
if (!pkCheckArgcRange(vm, argc, 0, 3)) return; if (!pkCheckArgcRange(vm, argc, 0, 3)) return;
@ -237,7 +237,7 @@ void _vectorInit(PKVM* vm) {
} }
void _vectorGetter(PKVM* vm) { DEF(_vectorGetter, "") {
const char* name; uint32_t length; const char* name; uint32_t length;
if (!pkValidateSlotString(vm, 1, &name, &length)) return; if (!pkValidateSlotString(vm, 1, &name, &length)) return;
@ -256,7 +256,7 @@ void _vectorGetter(PKVM* vm) {
} }
} }
void _vectorSetter(PKVM* vm) { DEF(_vectorSetter, "") {
const char* name; uint32_t length; const char* name; uint32_t length;
if (!pkValidateSlotString(vm, 1, &name, &length)) return; if (!pkValidateSlotString(vm, 1, &name, &length)) return;
@ -279,7 +279,7 @@ void _vectorSetter(PKVM* vm) {
} }
} }
void _vectorRepr(PKVM* vm) { DEF(_vectorRepr, "") {
Vector* vec = pkGetSelf(vm); Vector* vec = pkGetSelf(vm);
pkSetSlotStringFmt(vm, 0, "[%g, %g, %g]", vec->x, vec->y, vec->z); pkSetSlotStringFmt(vm, 0, "[%g, %g, %g]", vec->x, vec->y, vec->z);
} }

View File

@ -42,5 +42,7 @@ assert(obj['quiz']['maths'] ==
} }
}) })
assert(json.parse(json.print(obj)) == obj)
# If we got here, that means all test were passed. # If we got here, that means all test were passed.
print('All TESTS PASSED') print('All TESTS PASSED')