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) {
char buff[STR_INT_BUFF_SIZE];
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) {
@ -1245,7 +1246,8 @@ L_do_call:
// No constructor is defined on the class. Just return self.
if (closure == NULL) {
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);
}
@ -1265,8 +1267,8 @@ L_do_call:
// -1 argument means multiple number of args.
if (closure->fn->arity != -1 && closure->fn->arity != argc) {
char buff[STR_INT_BUFF_SIZE]; sprintf(buff, "%d", closure->fn->arity);
String* msg = stringFormat(vm, "Expected exactly $ argument(s).",
buff);
String* msg = stringFormat(vm, "Expected exactly $ argument(s) "
"for function $", buff, closure->fn->name);
RUNTIME_ERROR(msg);
}

View File

@ -9,6 +9,10 @@
#include "gen/ext_term.pk.h" //<< AMALG_INLINE >>
#endif
#ifdef _WIN32
#include <fcntl.h>
#endif
#define TERM_IMPLEMENT
#include "thirdparty/term/term.h" //<< AMALG_INLINE >>
#undef TERM_IMPLEMENT
@ -229,6 +233,14 @@ void _termReadEvent(PKVM* vm) {
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 */
/*****************************************************************************/
@ -252,6 +264,11 @@ void registerModuleTerm(PKVM* vm) {
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);
pkReleaseHandle(vm, term);
}

View File

@ -35,14 +35,12 @@ DEF(_ioWrite,
pkSetRuntimeError(vm, "Cannot write to stdin.");
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:
fprintf(stdout, "%s", bytes);
fwrite(bytes, sizeof(char), length, stdout);
return;
case 2:
fprintf(stderr, "%s", bytes);
fwrite(bytes, sizeof(char), length, stderr);
return;
}
}
@ -54,6 +52,13 @@ DEF(_ioFlush,
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 */
/*****************************************************************************/
@ -81,8 +86,8 @@ typedef enum {
FMODE_APPEND_EXT = (_FMODE_EXT | FMODE_APPEND),
FMODE_READ_BIN = (_FMODE_BIN | FMODE_READ),
FMODE_WRITE_BIN = (_FMODE_BIN | FMODE_READ),
FMODE_APPEND_BIN = (_FMODE_BIN | FMODE_READ),
FMODE_WRITE_BIN = (_FMODE_BIN | FMODE_WRITE),
FMODE_APPEND_BIN = (_FMODE_BIN | FMODE_APPEND),
FMODE_READ_BIN_EXT = (_FMODE_BIN | FMODE_READ_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, "flush", _ioFlush, 0);
pkModuleAddFunction(vm, io, "getc", _ioGetc, 0);
PkHandle* cls_file = pkNewClass(vm, "File", NULL, io, _fileNew, _fileDelete);
pkClassAddMethod(vm, cls_file, "open", _fileOpen, -1);

View File

@ -82,6 +82,83 @@ static Var _cJsonToPocket(PKVM* vm, cJSON* item) {
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,
"json.parse(json_str:String) -> var\n"
"Parse a json string into pocket lang object.") {
@ -108,6 +185,39 @@ DEF(_jsonParse,
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 */
/*****************************************************************************/
@ -116,6 +226,7 @@ void registerModuleJson(PKVM* vm) {
PkHandle* json = pkNewModule(vm, "json");
pkModuleAddFunction(vm, json, "parse", _jsonParse, 1);
pkModuleAddFunction(vm, json, "print", _jsonPrint, -1);
pkRegisterModule(vm, json);
pkReleaseHandle(vm, json);

View File

@ -46,17 +46,17 @@ DEF(_typesHash,
/* BYTE BUFFER */
/*****************************************************************************/
void* _bytebuffNew(PKVM* vm) {
static void* _bytebuffNew(PKVM* vm) {
pkByteBuffer* self = pkRealloc(vm, NULL, sizeof(pkByteBuffer));
pkByteBufferInit(self);
return self;
}
void _bytebuffDelete(PKVM* vm, void* buff) {
static void _bytebuffDelete(PKVM* vm, void* buff) {
pkRealloc(vm, buff, 0);
}
void _bytebuffReserve(PKVM* vm) {
DEF(_bytebuffReserve, "") {
double size;
if (!pkValidateSlotNumber(vm, 1, &size)) return;
@ -65,7 +65,7 @@ void _bytebuffReserve(PKVM* vm) {
}
// buff.fill(data, count)
void _bytebuffFill(PKVM* vm) {
DEF(_bytebuffFill, "") {
uint32_t n;
if (!pkValidateSlotInteger(vm, 1, &n)) return;
if (n < 0x00 || n > 0xff) {
@ -81,14 +81,14 @@ void _bytebuffFill(PKVM* vm) {
pkByteBufferFill(self, vm, (uint8_t) n, (int) count);
}
void _bytebuffClear(PKVM* vm) {
DEF(_bytebuffClear, "") {
// TODO: Should I also zero or reduce the capacity?
pkByteBuffer* self = pkGetSelf(vm);
self->count = 0;
}
// Returns the length of bytes were written.
void _bytebuffWrite(PKVM* vm) {
DEF(_bytebuffWrite, "") {
pkByteBuffer* self = pkGetSelf(vm);
PkVarType type = pkGetSlotType(vm, 1);
@ -135,7 +135,7 @@ void _bytebuffWrite(PKVM* vm) {
}
void _bytebuffSubscriptGet(PKVM* vm) {
DEF(_bytebuffSubscriptGet, "") {
double index;
if (!pkValidateSlotNumber(vm, 1, &index)) return;
if (floor(index) != index) {
@ -154,7 +154,7 @@ void _bytebuffSubscriptGet(PKVM* vm) {
}
void _bytebuffSubscriptSet(PKVM* vm) {
DEF(_bytebuffSubscriptSet, "") {
double index, value;
if (!pkValidateSlotNumber(vm, 1, &index)) 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);
pkSetSlotStringLength(vm, 0, self->data, self->count);
}
void _bytebuffCount(PKVM* vm) {
DEF(_bytebuffCount, "") {
pkByteBuffer* self = pkGetSelf(vm);
pkSetSlotNumber(vm, 0, self->count);
}
@ -202,17 +202,17 @@ typedef struct {
double x, y, z;
} Vector;
void* _vectorNew(PKVM* vm) {
static void* _vectorNew(PKVM* vm) {
Vector* vec = pkRealloc(vm, NULL, sizeof(Vector));
memset(vec, 0, sizeof(Vector));
return vec;
}
void _vectorDelete(PKVM* vm, void* vec) {
static void _vectorDelete(PKVM* vm, void* vec) {
pkRealloc(vm, vec, 0);
}
void _vectorInit(PKVM* vm) {
DEF(_vectorInit, "") {
int argc = pkGetArgc(vm);
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;
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;
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);
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.
print('All TESTS PASSED')