mirror of
https://github.com/zekexiao/pocketlang.git
synced 2025-03-04 13:15:55 +08:00
Minor code enhancements (read bellow)
- Warnings were fixed - Libraries are registered internally when PKVM created and cleanedup when PKVM freed (if PK_NO_LIBS not defined) - Lang.clock() moved to time module and sleep, epoch time were added. - Support both upper case and lower case hex literals - Support hex excaped characters inside strings (ex: "\x41") - Native api for import modules added `pkImportModule(...)` - pkAllocString, pkDeallocString are changed to pkRealloc. - NewInstance, DeleteInstance functions now take PKVM however delete function should not allocate any memory since it's invoked at the GC execution.
This commit is contained in:
parent
710d0c47f3
commit
6a22653263
@ -17,7 +17,7 @@ were used as a reference to write this language.
|
|||||||
|
|
||||||
```ruby
|
```ruby
|
||||||
# Python like import statement.
|
# Python like import statement.
|
||||||
from lang import clock as now
|
from time import clock as now
|
||||||
|
|
||||||
# A recursive fibonacci function.
|
# A recursive fibonacci function.
|
||||||
def fib(n)
|
def fib(n)
|
||||||
|
@ -60,7 +60,6 @@ static PKVM* intializePocketVM() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
PKVM* vm = pkNewVM(&config);
|
PKVM* vm = pkNewVM(&config);
|
||||||
pkRegisterLibs(vm);
|
|
||||||
return vm;
|
return vm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -384,7 +384,7 @@ from lang import clock as now
|
|||||||
import foo.bar # Import module bar from foo directory
|
import foo.bar # Import module bar from foo directory
|
||||||
import baz # If baz is a directory it'll import baz/_init.pk
|
import baz # If baz is a directory it'll import baz/_init.pk
|
||||||
|
|
||||||
# I'll only search for foo relatievly.
|
# It'll only search for foo relatievly.
|
||||||
import .foo # ./foo.pk or ./foo/_init.pk or ./foo.dll, ...
|
import .foo # ./foo.pk or ./foo/_init.pk or ./foo.dll, ...
|
||||||
|
|
||||||
# ^ meaning parent directory relative to this script.
|
# ^ meaning parent directory relative to this script.
|
||||||
|
@ -6,7 +6,7 @@ from shutil import which
|
|||||||
## This file is not intended to be included in other files at the moment.
|
## This file is not intended to be included in other files at the moment.
|
||||||
THIS_PATH = abspath(dirname(__file__))
|
THIS_PATH = abspath(dirname(__file__))
|
||||||
|
|
||||||
POCKET_SOURCE_DIR = join(THIS_PATH, "../../../pocketlang/src/")
|
POCKET_ROOT = join(THIS_PATH, "../../../pocketlang/src/")
|
||||||
JS_API_PATH = join(THIS_PATH, "io_api.js")
|
JS_API_PATH = join(THIS_PATH, "io_api.js")
|
||||||
MAIN_C = join(THIS_PATH, "main.c")
|
MAIN_C = join(THIS_PATH, "main.c")
|
||||||
TARGET_DIR = join(THIS_PATH, "../static/wasm/")
|
TARGET_DIR = join(THIS_PATH, "../static/wasm/")
|
||||||
@ -27,7 +27,7 @@ def main():
|
|||||||
os.mkdir(TARGET_DIR)
|
os.mkdir(TARGET_DIR)
|
||||||
|
|
||||||
sources = ' '.join(collect_source_files())
|
sources = ' '.join(collect_source_files())
|
||||||
include = '-I' + join(POCKET_SOURCE_DIR, 'include/')
|
include = '-I' + join(POCKET_ROOT, 'include/')
|
||||||
output = join(TARGET_DIR, TARGET_NAME)
|
output = join(TARGET_DIR, TARGET_NAME)
|
||||||
exports = "\"EXPORTED_RUNTIME_METHODS=['ccall','cwrap']\""
|
exports = "\"EXPORTED_RUNTIME_METHODS=['ccall','cwrap']\""
|
||||||
js_api = JS_API_PATH
|
js_api = JS_API_PATH
|
||||||
@ -39,9 +39,10 @@ def main():
|
|||||||
|
|
||||||
def collect_source_files():
|
def collect_source_files():
|
||||||
sources = []
|
sources = []
|
||||||
for file in os.listdir(POCKET_SOURCE_DIR):
|
for dir in ('core/', 'libs/'):
|
||||||
|
for file in os.listdir(join(POCKET_ROOT, dir)):
|
||||||
if isdir(file): continue
|
if isdir(file): continue
|
||||||
if file.endswith('.c'): sources.append(join(POCKET_SOURCE_DIR, file))
|
if file.endswith('.c'): sources.append(join(POCKET_ROOT, dir, file))
|
||||||
return sources
|
return sources
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
@ -96,10 +96,10 @@ def generate():
|
|||||||
'\n'
|
'\n'
|
||||||
gen += parse(header) + '\n'
|
gen += parse(header) + '\n'
|
||||||
|
|
||||||
gen += '#ifdef PK_IMPL\n\n'
|
gen += '#ifdef PK_IMPLEMENT\n\n'
|
||||||
for source in SOURCES:
|
for source in SOURCES:
|
||||||
gen += parse(source)
|
gen += parse(source)
|
||||||
gen += '#endif // PK_IMPL\n'
|
gen += '#endif // PK_IMPLEMENT\n'
|
||||||
|
|
||||||
return gen
|
return gen
|
||||||
|
|
||||||
|
@ -8,6 +8,9 @@
|
|||||||
## To get the trace report redefine TRACE_MEMORY as 1 at the
|
## To get the trace report redefine TRACE_MEMORY as 1 at the
|
||||||
## pk_internal.h and compile pocketlang.
|
## pk_internal.h and compile pocketlang.
|
||||||
|
|
||||||
|
raise "This script Need refactor after removing pkAllocString " + \
|
||||||
|
"and adding pkRealloc"
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
def detect_leak():
|
def detect_leak():
|
||||||
|
@ -664,6 +664,28 @@ static void setNextValueToken(Parser* parser, _TokenType type, Var value);
|
|||||||
static void setNextToken(Parser* parser, _TokenType type);
|
static void setNextToken(Parser* parser, _TokenType type);
|
||||||
static bool matchChar(Parser* parser, char c);
|
static bool matchChar(Parser* parser, char c);
|
||||||
|
|
||||||
|
#define _BETWEEN(a, c, b) (((a) <= (c)) && ((c) <= (b)))
|
||||||
|
static inline bool _isCharHex(char c) {
|
||||||
|
return (_BETWEEN('0', c, '9')
|
||||||
|
|| _BETWEEN('a', c, 'z')
|
||||||
|
|| _BETWEEN('A', c, 'Z'));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint8_t _charHexVal(char c) {
|
||||||
|
ASSERT(_isCharHex(c), OOPS);
|
||||||
|
|
||||||
|
if (_BETWEEN('0', c, '9')) {
|
||||||
|
return c - '0';
|
||||||
|
} else if (_BETWEEN('a', c, 'z')) {
|
||||||
|
return c - 'a' + 10;
|
||||||
|
} else if (_BETWEEN('A', c, 'Z')) {
|
||||||
|
return c - 'A' + 10;
|
||||||
|
}
|
||||||
|
UNREACHABLE();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#undef _BETWEEN
|
||||||
|
|
||||||
static void eatString(Compiler* compiler, bool single_quote) {
|
static void eatString(Compiler* compiler, bool single_quote) {
|
||||||
Parser* parser = &compiler->parser;
|
Parser* parser = &compiler->parser;
|
||||||
|
|
||||||
@ -693,15 +715,15 @@ static void eatString(Compiler* compiler, bool single_quote) {
|
|||||||
if (parser->si_depth < MAX_STR_INTERP_DEPTH) {
|
if (parser->si_depth < MAX_STR_INTERP_DEPTH) {
|
||||||
tk_type = TK_STRING_INTERP;
|
tk_type = TK_STRING_INTERP;
|
||||||
|
|
||||||
char c = peekChar(parser);
|
char c2 = peekChar(parser);
|
||||||
if (c == '{') { // Expression interpolation (ie. "${expr}").
|
if (c2 == '{') { // Expression interpolation (ie. "${expr}").
|
||||||
eatChar(parser);
|
eatChar(parser);
|
||||||
parser->si_depth++;
|
parser->si_depth++;
|
||||||
parser->si_quote[parser->si_depth - 1] = quote;
|
parser->si_quote[parser->si_depth - 1] = quote;
|
||||||
parser->si_open_brace[parser->si_depth - 1] = 0;
|
parser->si_open_brace[parser->si_depth - 1] = 0;
|
||||||
|
|
||||||
} else { // Name Interpolation.
|
} else { // Name Interpolation.
|
||||||
if (!utilIsName(c)) {
|
if (!utilIsName(c2)) {
|
||||||
syntaxError(compiler, makeErrToken(parser),
|
syntaxError(compiler, makeErrToken(parser),
|
||||||
"Expected '{' or identifier after '$'.");
|
"Expected '{' or identifier after '$'.");
|
||||||
return;
|
return;
|
||||||
@ -740,8 +762,34 @@ static void eatString(Compiler* compiler, bool single_quote) {
|
|||||||
// '$' In pocketlang string is used for interpolation.
|
// '$' In pocketlang string is used for interpolation.
|
||||||
case '$': pkByteBufferWrite(&buff, parser->vm, '$'); break;
|
case '$': pkByteBufferWrite(&buff, parser->vm, '$'); break;
|
||||||
|
|
||||||
|
// Hex literal in string should match `\x[0-9a-zA-Z][0-9a-zA-Z]`
|
||||||
|
case 'x': {
|
||||||
|
uint8_t val = 0;
|
||||||
|
|
||||||
|
c = eatChar(parser);
|
||||||
|
if (!_isCharHex(c)) {
|
||||||
|
semanticError(compiler, makeErrToken(parser),
|
||||||
|
"Invalid hex escape.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = _charHexVal(c);
|
||||||
|
|
||||||
|
c = eatChar(parser);
|
||||||
|
if (!_isCharHex(c)) {
|
||||||
|
semanticError(compiler, makeErrToken(parser),
|
||||||
|
"Invalid hex escape.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = (val << 4) | _charHexVal(c);
|
||||||
|
|
||||||
|
pkByteBufferWrite(&buff, parser->vm, val);
|
||||||
|
|
||||||
|
} break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
syntaxError(compiler, makeErrToken(parser),
|
semanticError(compiler, makeErrToken(parser),
|
||||||
"Invalid escape character.");
|
"Invalid escape character.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -807,10 +855,6 @@ static void eatName(Parser* parser) {
|
|||||||
static void eatNumber(Compiler* compiler) {
|
static void eatNumber(Compiler* compiler) {
|
||||||
Parser* parser = &compiler->parser;
|
Parser* parser = &compiler->parser;
|
||||||
|
|
||||||
#define IS_HEX_CHAR(c) \
|
|
||||||
(('0' <= (c) && (c) <= '9') || \
|
|
||||||
('a' <= (c) && (c) <= 'f'))
|
|
||||||
|
|
||||||
#define IS_BIN_CHAR(c) (((c) == '0') || ((c) == '1'))
|
#define IS_BIN_CHAR(c) (((c) == '0') || ((c) == '1'))
|
||||||
|
|
||||||
Var value = VAR_NULL; // The number value.
|
Var value = VAR_NULL; // The number value.
|
||||||
@ -855,8 +899,8 @@ static void eatNumber(Compiler* compiler) {
|
|||||||
uint64_t hex = 0;
|
uint64_t hex = 0;
|
||||||
c = peekChar(parser);
|
c = peekChar(parser);
|
||||||
|
|
||||||
// The first digit should be either hex digit.
|
// The first digit should be hex digit.
|
||||||
if (!IS_HEX_CHAR(c)) {
|
if (!_isCharHex(c)) {
|
||||||
syntaxError(compiler, makeErrToken(parser), "Invalid hex literal.");
|
syntaxError(compiler, makeErrToken(parser), "Invalid hex literal.");
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -864,7 +908,7 @@ static void eatNumber(Compiler* compiler) {
|
|||||||
do {
|
do {
|
||||||
// Consume the next digit.
|
// Consume the next digit.
|
||||||
c = peekChar(parser);
|
c = peekChar(parser);
|
||||||
if (!IS_HEX_CHAR(c)) break;
|
if (!_isCharHex(c)) break;
|
||||||
eatChar(parser);
|
eatChar(parser);
|
||||||
|
|
||||||
// Check the length of the binary literal.
|
// Check the length of the binary literal.
|
||||||
@ -876,10 +920,7 @@ static void eatNumber(Compiler* compiler) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// "Append" the next digit at the end.
|
// "Append" the next digit at the end.
|
||||||
uint8_t append_val = ('0' <= c && c <= '9')
|
hex = (hex << 4) | _charHexVal(c);
|
||||||
? (uint8_t)(c - '0')
|
|
||||||
: (uint8_t)((c - 'a') + 10);
|
|
||||||
hex = (hex << 4) | append_val;
|
|
||||||
|
|
||||||
} while (true);
|
} while (true);
|
||||||
|
|
||||||
@ -930,7 +971,6 @@ static void eatNumber(Compiler* compiler) {
|
|||||||
|
|
||||||
setNextValueToken(parser, TK_NUMBER, value);
|
setNextValueToken(parser, TK_NUMBER, value);
|
||||||
#undef IS_BIN_CHAR
|
#undef IS_BIN_CHAR
|
||||||
#undef IS_HEX_CHAR
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read and ignore chars till it reach new line or EOF.
|
// Read and ignore chars till it reach new line or EOF.
|
||||||
@ -1337,7 +1377,6 @@ static int findBuiltinFunction(const PKVM* vm,
|
|||||||
static int findBuiltinClass(const PKVM* vm,
|
static int findBuiltinClass(const PKVM* vm,
|
||||||
const char* name, uint32_t length) {
|
const char* name, uint32_t length) {
|
||||||
for (int i = 0; i < PK_INSTANCE; i++) {
|
for (int i = 0; i < PK_INSTANCE; i++) {
|
||||||
uint32_t bfn_length = vm->builtin_classes[i]->name->length;
|
|
||||||
if (IS_CSTR_EQ(vm->builtin_classes[i]->name, name, length)) {
|
if (IS_CSTR_EQ(vm->builtin_classes[i]->name, name, length)) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
@ -2344,8 +2383,6 @@ static void compilerAddForward(Compiler* compiler, int instruction, Fn* fn,
|
|||||||
|
|
||||||
// Add a literal constant to module literals and return it's index.
|
// Add a literal constant to module literals and return it's index.
|
||||||
static int compilerAddConstant(Compiler* compiler, Var value) {
|
static int compilerAddConstant(Compiler* compiler, Var value) {
|
||||||
pkVarBuffer* constants = &compiler->module->constants;
|
|
||||||
|
|
||||||
uint32_t index = moduleAddConstant(compiler->parser.vm,
|
uint32_t index = moduleAddConstant(compiler->parser.vm,
|
||||||
compiler->module, value);
|
compiler->module, value);
|
||||||
checkMaxConstantsReached(compiler, index);
|
checkMaxConstantsReached(compiler, index);
|
||||||
@ -2899,7 +2936,7 @@ static Token compileImportPath(Compiler* compiler) {
|
|||||||
// Create constant pool entry for the path string.
|
// Create constant pool entry for the path string.
|
||||||
int index = 0;
|
int index = 0;
|
||||||
moduleAddString(compiler->module, compiler->parser.vm,
|
moduleAddString(compiler->module, compiler->parser.vm,
|
||||||
buff.data, buff.count - 1, &index);
|
(const char*) buff.data, buff.count - 1, &index);
|
||||||
|
|
||||||
pkByteBufferClear(&buff, vm);
|
pkByteBufferClear(&buff, vm);
|
||||||
|
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
#ifndef PK_AMALGAMATED
|
#ifndef PK_AMALGAMATED
|
||||||
#include "core.h"
|
#include "core.h"
|
||||||
@ -40,9 +39,6 @@
|
|||||||
/* VALIDATORS */
|
/* VALIDATORS */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
// Evaluated to true of the [num] is in byte range.
|
|
||||||
#define IS_NUM_BYTE(num) ((CHAR_MIN <= (num)) && ((num) <= CHAR_MAX))
|
|
||||||
|
|
||||||
// Check if [var] is a numeric value (bool/number) and set [value].
|
// Check if [var] is a numeric value (bool/number) and set [value].
|
||||||
static inline bool isNumeric(Var var, double* value) {
|
static inline bool isNumeric(Var var, double* value) {
|
||||||
if (IS_NUM(var)) {
|
if (IS_NUM(var)) {
|
||||||
@ -396,8 +392,8 @@ DEF(coreChr,
|
|||||||
int64_t num;
|
int64_t num;
|
||||||
if (!validateInteger(vm, ARG(1), &num, "Argument 1")) return;
|
if (!validateInteger(vm, ARG(1), &num, "Argument 1")) return;
|
||||||
|
|
||||||
if (!IS_NUM_BYTE(num)) {
|
if (!(0 <= num && num <= 0xff)) {
|
||||||
RET_ERR(newString(vm, "The number is not in a byte range."));
|
RET_ERR(newString(vm, "The number should be in range 0x00 to 0xff."));
|
||||||
}
|
}
|
||||||
|
|
||||||
char c = (char) num;
|
char c = (char) num;
|
||||||
@ -462,7 +458,7 @@ DEF(coreInput,
|
|||||||
}
|
}
|
||||||
|
|
||||||
String* line = newString(vm, str);
|
String* line = newString(vm, str);
|
||||||
pkDeAllocString(vm, str);
|
pkRealloc(vm, str, 0);
|
||||||
RET(VAR_OBJ(line));
|
RET(VAR_OBJ(line));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -655,14 +651,6 @@ void moduleAddFunctionInternal(PKVM* vm, Module* module,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 'lang' library methods.
|
// 'lang' library methods.
|
||||||
// -----------------------
|
|
||||||
|
|
||||||
DEF(stdLangClock,
|
|
||||||
"clock() -> num\n"
|
|
||||||
"Returns the number of seconds since the application started") {
|
|
||||||
|
|
||||||
RET(VAR_NUM((double)clock() / CLOCKS_PER_SEC));
|
|
||||||
}
|
|
||||||
|
|
||||||
DEF(stdLangGC,
|
DEF(stdLangGC,
|
||||||
"gc() -> num\n"
|
"gc() -> num\n"
|
||||||
@ -734,7 +722,6 @@ static void initializeCoreModules(PKVM* vm) {
|
|||||||
vmPopTempRef(vm) /* module */
|
vmPopTempRef(vm) /* module */
|
||||||
|
|
||||||
NEW_MODULE(lang, "lang");
|
NEW_MODULE(lang, "lang");
|
||||||
MODULE_ADD_FN(lang, "clock", stdLangClock, 0);
|
|
||||||
MODULE_ADD_FN(lang, "gc", stdLangGC, 0);
|
MODULE_ADD_FN(lang, "gc", stdLangGC, 0);
|
||||||
MODULE_ADD_FN(lang, "disas", stdLangDisas, 1);
|
MODULE_ADD_FN(lang, "disas", stdLangDisas, 1);
|
||||||
MODULE_ADD_FN(lang, "write", stdLangWrite, -1);
|
MODULE_ADD_FN(lang, "write", stdLangWrite, -1);
|
||||||
@ -760,13 +747,13 @@ static void _ctorBool(PKVM* vm) {
|
|||||||
|
|
||||||
static void _ctorNumber(PKVM* vm) {
|
static void _ctorNumber(PKVM* vm) {
|
||||||
double value;
|
double value;
|
||||||
|
|
||||||
if (isNumeric(ARG(1), &value)) {
|
if (isNumeric(ARG(1), &value)) {
|
||||||
RET(VAR_NUM(value));
|
RET(VAR_NUM(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_OBJ_TYPE(ARG(1), OBJ_STRING)) {
|
if (IS_OBJ_TYPE(ARG(1), OBJ_STRING)) {
|
||||||
String* str = (String*) AS_OBJ(ARG(1));
|
String* str = (String*) AS_OBJ(ARG(1));
|
||||||
double value;
|
|
||||||
const char* err = utilToNumber(str->data, &value);
|
const char* err = utilToNumber(str->data, &value);
|
||||||
if (err == NULL) RET(VAR_NUM(value));
|
if (err == NULL) RET(VAR_NUM(value));
|
||||||
VM_SET_ERROR(vm, newString(vm, err));
|
VM_SET_ERROR(vm, newString(vm, err));
|
||||||
@ -919,6 +906,7 @@ static void initializePrimitiveClasses(PKVM* vm) {
|
|||||||
ADD_CTOR(PK_BOOL, "@ctorBool", _ctorBool, 1);
|
ADD_CTOR(PK_BOOL, "@ctorBool", _ctorBool, 1);
|
||||||
ADD_CTOR(PK_NUMBER, "@ctorNumber", _ctorNumber, 1);
|
ADD_CTOR(PK_NUMBER, "@ctorNumber", _ctorNumber, 1);
|
||||||
ADD_CTOR(PK_STRING, "@ctorString", _ctorString, -1);
|
ADD_CTOR(PK_STRING, "@ctorString", _ctorString, -1);
|
||||||
|
ADD_CTOR(PK_RANGE, "@ctorRange", _ctorRange, 2);
|
||||||
ADD_CTOR(PK_LIST, "@ctorList", _ctorList, -1);
|
ADD_CTOR(PK_LIST, "@ctorList", _ctorList, -1);
|
||||||
ADD_CTOR(PK_MAP, "@ctorMap", _ctorMap, 0);
|
ADD_CTOR(PK_MAP, "@ctorMap", _ctorMap, 0);
|
||||||
ADD_CTOR(PK_FIBER, "@ctorFiber", _ctorFiber, 1);
|
ADD_CTOR(PK_FIBER, "@ctorFiber", _ctorFiber, 1);
|
||||||
@ -945,8 +933,6 @@ static void initializePrimitiveClasses(PKVM* vm) {
|
|||||||
#undef ADD_METHOD
|
#undef ADD_METHOD
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef IS_NUM_BYTE
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* OPERATORS */
|
/* OPERATORS */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
@ -1176,6 +1162,8 @@ Var varAdd(PKVM* vm, Var v1, Var v2, bool inplace) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
default: break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CHECK_INST_BINARY_OP("+");
|
CHECK_INST_BINARY_OP("+");
|
||||||
@ -1353,6 +1341,8 @@ bool varContains(PKVM* vm, Var elem, Var container) {
|
|||||||
Map* map = (Map*)AS_OBJ(container);
|
Map* map = (Map*)AS_OBJ(container);
|
||||||
return !IS_UNDEF(mapGet(map, elem));
|
return !IS_UNDEF(mapGet(map, elem));
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
default: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define v1 container
|
#define v1 container
|
||||||
|
@ -15,6 +15,23 @@
|
|||||||
#include "vm.h"
|
#include "vm.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// TODO: Document this or Find a better way.
|
||||||
|
//
|
||||||
|
// Pocketlang core doesn't implement path resolving funcionality. Rather it
|
||||||
|
// should be provided the host application. By default we're using an
|
||||||
|
// implementation from the path library. However pocket core cannot be depend
|
||||||
|
// on its libs, otherwise it'll breaks the encapsulation.
|
||||||
|
//
|
||||||
|
// As a workaround we declare the default path resolver here and use it.
|
||||||
|
// But if someone wants to compile just the core pocketlang without libs
|
||||||
|
// they have to define PK_NO_LIBS to prevent the compiler from not be able
|
||||||
|
// to find functions when linking.
|
||||||
|
#ifndef PK_NO_LIBS
|
||||||
|
void registerLibs(PKVM* vm);
|
||||||
|
void cleanupLibs(PKVM* vm);
|
||||||
|
char* pathResolveImport(PKVM* vm, const char* from, const char* path);
|
||||||
|
#endif
|
||||||
|
|
||||||
#define CHECK_ARG_NULL(name) \
|
#define CHECK_ARG_NULL(name) \
|
||||||
ASSERT((name) != NULL, "Argument " #name " was NULL.");
|
ASSERT((name) != NULL, "Argument " #name " was NULL.");
|
||||||
|
|
||||||
@ -66,41 +83,17 @@ static void stdoutWrite(PKVM* vm, const char* text);
|
|||||||
static char* stdinRead(PKVM* vm);
|
static char* stdinRead(PKVM* vm);
|
||||||
static char* loadScript(PKVM* vm, const char* path);
|
static char* loadScript(PKVM* vm, const char* path);
|
||||||
|
|
||||||
char* pkAllocString(PKVM* vm, size_t size) {
|
PK_PUBLIC void* pkRealloc(PKVM* vm, void* ptr, size_t size) {
|
||||||
ASSERT(vm->config.realloc_fn != NULL, "PKVM's allocator was NULL.");
|
ASSERT(vm->config.realloc_fn != NULL, "PKVM's allocator was NULL.");
|
||||||
|
|
||||||
#if TRACE_MEMORY
|
#if TRACE_MEMORY
|
||||||
void* ptr = vm->config.realloc_fn(NULL, size, vm->config.user_data);
|
void* newptr = vm->config.realloc_fn(ptr, size, vm->config.user_data);
|
||||||
printf("[alloc string] alloc : %p = %+li bytes\n", ptr, (long) size);
|
printf("[pkRealloc] %p -> %p %+li bytes\n", ptr, newptr, (long) size);
|
||||||
return (char*) ptr;
|
return ptr;
|
||||||
#else
|
#else
|
||||||
return (char*) vm->config.realloc_fn(NULL, size, vm->config.user_data);
|
return vm->config.realloc_fn(ptr, size, vm->config.user_data);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void pkDeAllocString(PKVM* vm, char* str) {
|
|
||||||
ASSERT(vm->config.realloc_fn != NULL, "PKVM's allocator was NULL.");
|
|
||||||
#if TRACE_MEMORY
|
|
||||||
printf("[alloc string] dealloc : %p\n", str);
|
|
||||||
#endif
|
|
||||||
vm->config.realloc_fn(str, 0, vm->config.user_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Document this or Find a better way.
|
|
||||||
//
|
|
||||||
// Pocketlang core doesn't implement path resolving funcionality. Rather it
|
|
||||||
// should be provided the host application. By default we're using an
|
|
||||||
// implementation from the path library. However pocket core cannot be depend
|
|
||||||
// on its libs, otherwise it'll breaks the encapsulation.
|
|
||||||
//
|
|
||||||
// As a workaround we declare the default path resolver here and use it.
|
|
||||||
// But if someone wants to compile just the core pocketlang without libs
|
|
||||||
// they have to define PK_NO_LIBS to prevent the compiler from not be able
|
|
||||||
// to find functions when linking.
|
|
||||||
#if !defined(PK_NO_LIBS)
|
|
||||||
char* pathResolveImport(PKVM* vm, const char* from, const char* path);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
PkConfiguration pkNewConfiguration() {
|
PkConfiguration pkNewConfiguration() {
|
||||||
PkConfiguration config;
|
PkConfiguration config;
|
||||||
memset(&config, 0, sizeof(config));
|
memset(&config, 0, sizeof(config));
|
||||||
@ -110,7 +103,7 @@ PkConfiguration pkNewConfiguration() {
|
|||||||
config.stdout_write = stdoutWrite;
|
config.stdout_write = stdoutWrite;
|
||||||
config.stderr_write = stderrWrite;
|
config.stderr_write = stderrWrite;
|
||||||
config.stdin_read = stdinRead;
|
config.stdin_read = stdinRead;
|
||||||
#if !defined(PK_NO_LIBS)
|
#ifndef PK_NO_LIBS
|
||||||
config.resolve_path_fn = pathResolveImport;
|
config.resolve_path_fn = pathResolveImport;
|
||||||
#endif
|
#endif
|
||||||
config.load_script_fn = loadScript;
|
config.load_script_fn = loadScript;
|
||||||
@ -146,11 +139,20 @@ PKVM* pkNewVM(PkConfiguration* config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
initializeCore(vm);
|
initializeCore(vm);
|
||||||
|
|
||||||
|
#ifndef PK_NO_LIBS
|
||||||
|
registerLibs(vm);
|
||||||
|
#endif
|
||||||
|
|
||||||
return vm;
|
return vm;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pkFreeVM(PKVM* vm) {
|
void pkFreeVM(PKVM* vm) {
|
||||||
|
|
||||||
|
#ifndef PK_NO_LIBS
|
||||||
|
cleanupLibs(vm);
|
||||||
|
#endif
|
||||||
|
|
||||||
Object* obj = vm->first;
|
Object* obj = vm->first;
|
||||||
while (obj != NULL) {
|
while (obj != NULL) {
|
||||||
Object* next = obj->next;
|
Object* next = obj->next;
|
||||||
@ -334,7 +336,7 @@ PkResult pkRunFile(PKVM* vm, const char* path) {
|
|||||||
// Set module path and and deallocate resolved.
|
// Set module path and and deallocate resolved.
|
||||||
String* script_path = newString(vm, resolved_);
|
String* script_path = newString(vm, resolved_);
|
||||||
vmPushTempRef(vm, &script_path->_super); // script_path.
|
vmPushTempRef(vm, &script_path->_super); // script_path.
|
||||||
pkDeAllocString(vm, resolved_);
|
pkRealloc(vm, resolved_, 0);
|
||||||
module->path = script_path;
|
module->path = script_path;
|
||||||
vmPopTempRef(vm); // script_path.
|
vmPopTempRef(vm); // script_path.
|
||||||
|
|
||||||
@ -352,7 +354,7 @@ PkResult pkRunFile(PKVM* vm, const char* path) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
result = compile(vm, module, source, NULL);
|
result = compile(vm, module, source, NULL);
|
||||||
pkDeAllocString(vm, source);
|
pkRealloc(vm, source, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result == PK_RESULT_SUCCESS) {
|
if (result == PK_RESULT_SUCCESS) {
|
||||||
@ -449,21 +451,21 @@ PkResult pkRunREPL(PKVM* vm) {
|
|||||||
if (line_length >= 1 && *(line + line_length - 1) == EOF) {
|
if (line_length >= 1 && *(line + line_length - 1) == EOF) {
|
||||||
printfn(vm, "\n");
|
printfn(vm, "\n");
|
||||||
result = PK_RESULT_SUCCESS;
|
result = PK_RESULT_SUCCESS;
|
||||||
pkDeAllocString(vm, line);
|
pkRealloc(vm, line, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the line is empty, we don't have to compile it.
|
// If the line is empty, we don't have to compile it.
|
||||||
if (isStringEmpty(line)) {
|
if (isStringEmpty(line)) {
|
||||||
if (need_more_lines) ASSERT(lines.count != 0, OOPS);
|
if (need_more_lines) ASSERT(lines.count != 0, OOPS);
|
||||||
pkDeAllocString(vm, line);
|
pkRealloc(vm, line, 0);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the line to the lines buffer.
|
// Add the line to the lines buffer.
|
||||||
if (lines.count != 0) pkByteBufferWrite(&lines, vm, '\n');
|
if (lines.count != 0) pkByteBufferWrite(&lines, vm, '\n');
|
||||||
pkByteBufferAddString(&lines, vm, line, (uint32_t) line_length);
|
pkByteBufferAddString(&lines, vm, line, (uint32_t) line_length);
|
||||||
pkDeAllocString(vm, line);
|
pkRealloc(vm, line, 0);
|
||||||
pkByteBufferWrite(&lines, vm, '\0');
|
pkByteBufferWrite(&lines, vm, '\0');
|
||||||
|
|
||||||
// Compile the buffer to the module.
|
// Compile the buffer to the module.
|
||||||
@ -546,11 +548,11 @@ bool pkCheckArgcRange(PKVM* vm, int argc, int min, int max) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set error for incompatible type provided as an argument. (TODO: got type).
|
// Set error for incompatible type provided as an argument. (TODO: got type).
|
||||||
#define ERR_INVALID_ARG_TYPE(ty_name) \
|
#define ERR_INVALID_SLOT_TYPE(ty_name) \
|
||||||
do { \
|
do { \
|
||||||
char buff[STR_INT_BUFF_SIZE]; \
|
char buff[STR_INT_BUFF_SIZE]; \
|
||||||
sprintf(buff, "%d", arg); \
|
sprintf(buff, "%d", arg); \
|
||||||
VM_SET_ERROR(vm, stringFormat(vm, "Expected a '$' at argument $.", \
|
VM_SET_ERROR(vm, stringFormat(vm, "Expected a '$' at slot $.", \
|
||||||
ty_name, buff)); \
|
ty_name, buff)); \
|
||||||
} while (false)
|
} while (false)
|
||||||
|
|
||||||
@ -562,7 +564,7 @@ PK_PUBLIC bool pkValidateSlotBool(PKVM* vm, int arg, bool* value) {
|
|||||||
|
|
||||||
Var val = ARG(arg);
|
Var val = ARG(arg);
|
||||||
if (!IS_BOOL(val)) {
|
if (!IS_BOOL(val)) {
|
||||||
ERR_INVALID_ARG_TYPE("Boolean");
|
ERR_INVALID_SLOT_TYPE("Boolean");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -576,7 +578,7 @@ PK_PUBLIC bool pkValidateSlotNumber(PKVM* vm, int arg, double* value) {
|
|||||||
|
|
||||||
Var val = ARG(arg);
|
Var val = ARG(arg);
|
||||||
if (!IS_NUM(val)) {
|
if (!IS_NUM(val)) {
|
||||||
ERR_INVALID_ARG_TYPE("Number");
|
ERR_INVALID_SLOT_TYPE("Number");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -591,7 +593,7 @@ PK_PUBLIC bool pkValidateSlotString(PKVM* vm, int arg, const char** value,
|
|||||||
|
|
||||||
Var val = ARG(arg);
|
Var val = ARG(arg);
|
||||||
if (!IS_OBJ_TYPE(val, OBJ_STRING)) {
|
if (!IS_OBJ_TYPE(val, OBJ_STRING)) {
|
||||||
ERR_INVALID_ARG_TYPE("String");
|
ERR_INVALID_SLOT_TYPE("String");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
String* str = (String*)AS_OBJ(val);
|
String* str = (String*)AS_OBJ(val);
|
||||||
@ -604,7 +606,7 @@ bool pkValidateSlotType(PKVM* vm, int arg, PkVarType type) {
|
|||||||
CHECK_FIBER_EXISTS(vm);
|
CHECK_FIBER_EXISTS(vm);
|
||||||
VALIDATE_ARGC(arg);
|
VALIDATE_ARGC(arg);
|
||||||
if (getVarType(ARG(arg)) != type) {
|
if (getVarType(ARG(arg)) != type) {
|
||||||
ERR_INVALID_ARG_TYPE(getPkVarTypeName(type));
|
ERR_INVALID_SLOT_TYPE(getPkVarTypeName(type));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -620,7 +622,7 @@ PK_PUBLIC bool pkValidateSlotInstanceOf(PKVM* vm, int arg, int cls) {
|
|||||||
if (!varIsType(vm, instance, class_)) {
|
if (!varIsType(vm, instance, class_)) {
|
||||||
// If [class_] is not a valid class, it's already an error.
|
// If [class_] is not a valid class, it's already an error.
|
||||||
if (VM_HAS_ERROR(vm)) return false;
|
if (VM_HAS_ERROR(vm)) return false;
|
||||||
ERR_INVALID_ARG_TYPE(((Class*)AS_OBJ(class_))->name->data);
|
ERR_INVALID_SLOT_TYPE(((Class*)AS_OBJ(class_))->name->data);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -632,7 +634,6 @@ bool pkIsSlotInstanceOf(PKVM* vm, int inst, int cls, bool* val) {
|
|||||||
VALIDATE_SLOT_INDEX(inst);
|
VALIDATE_SLOT_INDEX(inst);
|
||||||
VALIDATE_SLOT_INDEX(cls);
|
VALIDATE_SLOT_INDEX(cls);
|
||||||
|
|
||||||
Var instance = SLOT(inst), class_ = SLOT(cls);
|
|
||||||
*val = varIsType(vm, inst, cls);
|
*val = varIsType(vm, inst, cls);
|
||||||
return !VM_HAS_ERROR(vm);
|
return !VM_HAS_ERROR(vm);
|
||||||
}
|
}
|
||||||
@ -876,6 +877,19 @@ void pkPlaceSelf(PKVM* vm, int index) {
|
|||||||
SET_SLOT(index, vm->fiber->self);
|
SET_SLOT(index, vm->fiber->self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool pkImportModule(PKVM* vm, const char* path, int index) {
|
||||||
|
CHECK_FIBER_EXISTS(vm);
|
||||||
|
VALIDATE_SLOT_INDEX(index);
|
||||||
|
|
||||||
|
String* path_ = newString(vm, path);
|
||||||
|
vmPushTempRef(vm, &path_->_super); // path_
|
||||||
|
Var module = vmImportModule(vm, NULL, path_);
|
||||||
|
vmPopTempRef(vm); // path_
|
||||||
|
|
||||||
|
SET_SLOT(index, module);
|
||||||
|
return !VM_HAS_ERROR(vm);
|
||||||
|
}
|
||||||
|
|
||||||
void pkGetClass(PKVM* vm, int instance, int index) {
|
void pkGetClass(PKVM* vm, int instance, int index) {
|
||||||
CHECK_FIBER_EXISTS(vm);
|
CHECK_FIBER_EXISTS(vm);
|
||||||
VALIDATE_SLOT_INDEX(instance);
|
VALIDATE_SLOT_INDEX(instance);
|
||||||
@ -928,7 +942,7 @@ static char* stdinRead(PKVM* vm) {
|
|||||||
} while (c != EOF);
|
} while (c != EOF);
|
||||||
pkByteBufferWrite(&buff, vm, '\0');
|
pkByteBufferWrite(&buff, vm, '\0');
|
||||||
|
|
||||||
char* str = pkAllocString(vm, buff.count);
|
char* str = pkRealloc(vm, NULL, buff.count);
|
||||||
memcpy(str, buff.data, buff.count);
|
memcpy(str, buff.data, buff.count);
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
@ -946,8 +960,8 @@ static char* loadScript(PKVM* vm, const char* path) {
|
|||||||
fseek(file, 0, SEEK_SET);
|
fseek(file, 0, SEEK_SET);
|
||||||
|
|
||||||
// Allocate string + 1 for the NULL terminator.
|
// Allocate string + 1 for the NULL terminator.
|
||||||
char* buff = pkAllocString(vm, file_size + 1);
|
char* buff = pkRealloc(vm, NULL, file_size + 1);
|
||||||
ASSERT(buff != NULL, "pkAllocString failed.");
|
ASSERT(buff != NULL, "pkRealloc failed.");
|
||||||
|
|
||||||
clearerr(file);
|
clearerr(file);
|
||||||
size_t read = fread(buff, sizeof(char), file_size, file);
|
size_t read = fread(buff, sizeof(char), file_size, file);
|
||||||
|
@ -508,7 +508,7 @@ Instance* newInstance(PKVM* vm, Class* cls) {
|
|||||||
inst->attribs = newMap(vm);
|
inst->attribs = newMap(vm);
|
||||||
|
|
||||||
if (cls->new_fn != NULL) {
|
if (cls->new_fn != NULL) {
|
||||||
inst->native = cls->new_fn();
|
inst->native = cls->new_fn(vm);
|
||||||
} else {
|
} else {
|
||||||
inst->native = NULL;
|
inst->native = NULL;
|
||||||
}
|
}
|
||||||
@ -753,6 +753,8 @@ static uint32_t _hashObject(Object* obj) {
|
|||||||
Range* range = (Range*)obj;
|
Range* range = (Range*)obj;
|
||||||
return utilHashNumber(range->from) ^ utilHashNumber(range->to);
|
return utilHashNumber(range->from) ^ utilHashNumber(range->to);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
@ -1020,7 +1022,7 @@ void freeObject(PKVM* vm, Object* self) {
|
|||||||
case OBJ_INST: {
|
case OBJ_INST: {
|
||||||
Instance* inst = (Instance*)self;
|
Instance* inst = (Instance*)self;
|
||||||
if (inst->cls->delete_fn != NULL) {
|
if (inst->cls->delete_fn != NULL) {
|
||||||
inst->cls->delete_fn(inst->native);
|
inst->cls->delete_fn(vm, inst->native);
|
||||||
}
|
}
|
||||||
DEALLOCATE(vm, inst, Instance);
|
DEALLOCATE(vm, inst, Instance);
|
||||||
return;
|
return;
|
||||||
@ -1506,7 +1508,6 @@ static void _toStringInternal(PKVM* vm, const Var v, pkByteBuffer* buff,
|
|||||||
}
|
}
|
||||||
|
|
||||||
case OBJ_UPVALUE: {
|
case OBJ_UPVALUE: {
|
||||||
const Upvalue* upvalue = (const Upvalue*)obj;
|
|
||||||
pkByteBufferAddString(buff, vm, "[Upvalue]", 9);
|
pkByteBufferAddString(buff, vm, "[Upvalue]", 9);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -339,7 +339,7 @@ PkResult vmCallFunction(PKVM* vm, Closure* fn, int argc, Var* argv, Var* ret) {
|
|||||||
// Import and return the Module object with the [path] string. If the path
|
// Import and return the Module object with the [path] string. If the path
|
||||||
// starts with with './' or '../' we'll only try relative imports, otherwise
|
// starts with with './' or '../' we'll only try relative imports, otherwise
|
||||||
// we'll search native modules first and then at relative path.
|
// we'll search native modules first and then at relative path.
|
||||||
static inline Var importModule(PKVM* vm, String* from, String* path) {
|
Var vmImportModule(PKVM* vm, String* from, String* path) {
|
||||||
ASSERT((path != NULL) && (path->length > 0), OOPS);
|
ASSERT((path != NULL) && (path->length > 0), OOPS);
|
||||||
|
|
||||||
bool is_relative = path->data[0] == '.';
|
bool is_relative = path->data[0] == '.';
|
||||||
@ -362,19 +362,13 @@ static inline Var importModule(PKVM* vm, String* from, String* path) {
|
|||||||
(from) ? from->data : NULL, path->data);
|
(from) ? from->data : NULL, path->data);
|
||||||
|
|
||||||
if (_resolved == NULL) { // Can't resolve a relative module.
|
if (_resolved == NULL) { // Can't resolve a relative module.
|
||||||
pkDeAllocString(vm, _resolved);
|
pkRealloc(vm, _resolved, 0);
|
||||||
if (from) {
|
VM_SET_ERROR(vm, stringFormat(vm, "Cannot import module '@'", path));
|
||||||
VM_SET_ERROR(vm, stringFormat(vm, "Cannot resolve a relative import "
|
|
||||||
"path \"@\" from \"@\".", path, from));
|
|
||||||
} else {
|
|
||||||
VM_SET_ERROR(vm, stringFormat(vm, "Cannot resolve a relative import "
|
|
||||||
"path \"@\"", path));
|
|
||||||
}
|
|
||||||
return VAR_NULL;
|
return VAR_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
String* resolved = newString(vm, _resolved);
|
String* resolved = newString(vm, _resolved);
|
||||||
pkDeAllocString(vm, _resolved);
|
pkRealloc(vm, _resolved, 0);
|
||||||
|
|
||||||
// If the script already imported and cached, return it.
|
// If the script already imported and cached, return it.
|
||||||
Var entry = mapGet(vm->modules, VAR_OBJ(resolved));
|
Var entry = mapGet(vm->modules, VAR_OBJ(resolved));
|
||||||
@ -405,14 +399,14 @@ static inline Var importModule(PKVM* vm, String* from, String* path) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make a new module and to compile it.
|
// Make a new module, compile and cache it.
|
||||||
module = newModule(vm);
|
module = newModule(vm);
|
||||||
module->path = resolved;
|
module->path = resolved;
|
||||||
vmPushTempRef(vm, &module->_super); // module.
|
vmPushTempRef(vm, &module->_super); // module.
|
||||||
{
|
{
|
||||||
initializeScript(vm, module);
|
initializeScript(vm, module);
|
||||||
PkResult result = compile(vm, module, source, NULL);
|
PkResult result = compile(vm, module, source, NULL);
|
||||||
pkDeAllocString(vm, source);
|
pkRealloc(vm, source, 0);
|
||||||
if (result == PK_RESULT_SUCCESS) {
|
if (result == PK_RESULT_SUCCESS) {
|
||||||
vmRegisterModule(vm, module, resolved);
|
vmRegisterModule(vm, module, resolved);
|
||||||
} else {
|
} else {
|
||||||
@ -948,14 +942,14 @@ L_vm_main_loop:
|
|||||||
// Capture the vaupes.
|
// Capture the vaupes.
|
||||||
for (int i = 0; i < fn->upvalue_count; i++) {
|
for (int i = 0; i < fn->upvalue_count; i++) {
|
||||||
uint8_t is_immediate = READ_BYTE();
|
uint8_t is_immediate = READ_BYTE();
|
||||||
uint8_t index = READ_BYTE();
|
uint8_t idx = READ_BYTE();
|
||||||
|
|
||||||
if (is_immediate) {
|
if (is_immediate) {
|
||||||
// rbp[0] is the return value, rbp + 1 is the first local and so on.
|
// rbp[0] is the return value, rbp + 1 is the first local and so on.
|
||||||
closure->upvalues[i] = captureUpvalue(vm, fiber, (rbp + 1 + index));
|
closure->upvalues[i] = captureUpvalue(vm, fiber, (rbp + 1 + idx));
|
||||||
} else {
|
} else {
|
||||||
// The upvalue is already captured by the current function, reuse it.
|
// The upvalue is already captured by the current function, reuse it.
|
||||||
closure->upvalues[i] = frame->closure->upvalues[index];
|
closure->upvalues[i] = frame->closure->upvalues[idx];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1025,7 +1019,7 @@ L_vm_main_loop:
|
|||||||
String* name = moduleGetStringAt(module, (int)index);
|
String* name = moduleGetStringAt(module, (int)index);
|
||||||
ASSERT(name != NULL, OOPS);
|
ASSERT(name != NULL, OOPS);
|
||||||
|
|
||||||
Var _imported = importModule(vm, module->path, name);
|
Var _imported = vmImportModule(vm, module->path, name);
|
||||||
CHECK_ERROR();
|
CHECK_ERROR();
|
||||||
ASSERT(IS_OBJ_TYPE(_imported, OBJ_MODULE), OOPS);
|
ASSERT(IS_OBJ_TYPE(_imported, OBJ_MODULE), OOPS);
|
||||||
|
|
||||||
@ -1485,8 +1479,8 @@ L_do_call:
|
|||||||
OPCODE(POSITIVE):
|
OPCODE(POSITIVE):
|
||||||
{
|
{
|
||||||
// Don't pop yet, we need the reference for gc.
|
// Don't pop yet, we need the reference for gc.
|
||||||
Var self = PEEK(-1);
|
Var self_ = PEEK(-1);
|
||||||
Var result = varPositive(vm, self);
|
Var result = varPositive(vm, self_);
|
||||||
DROP(); // self
|
DROP(); // self
|
||||||
PUSH(result);
|
PUSH(result);
|
||||||
|
|
||||||
@ -1497,8 +1491,8 @@ L_do_call:
|
|||||||
OPCODE(NEGATIVE):
|
OPCODE(NEGATIVE):
|
||||||
{
|
{
|
||||||
// Don't pop yet, we need the reference for gc.
|
// Don't pop yet, we need the reference for gc.
|
||||||
Var self = PEEK(-1);
|
Var v = PEEK(-1);
|
||||||
Var result = varNegative(vm, self);
|
Var result = varNegative(vm, v);
|
||||||
DROP(); // self
|
DROP(); // self
|
||||||
PUSH(result);
|
PUSH(result);
|
||||||
|
|
||||||
@ -1509,8 +1503,8 @@ L_do_call:
|
|||||||
OPCODE(NOT):
|
OPCODE(NOT):
|
||||||
{
|
{
|
||||||
// Don't pop yet, we need the reference for gc.
|
// Don't pop yet, we need the reference for gc.
|
||||||
Var self = PEEK(-1);
|
Var v = PEEK(-1);
|
||||||
Var result = varNot(vm, self);
|
Var result = varNot(vm, v);
|
||||||
DROP(); // self
|
DROP(); // self
|
||||||
PUSH(result);
|
PUSH(result);
|
||||||
|
|
||||||
@ -1521,8 +1515,8 @@ L_do_call:
|
|||||||
OPCODE(BIT_NOT):
|
OPCODE(BIT_NOT):
|
||||||
{
|
{
|
||||||
// Don't pop yet, we need the reference for gc.
|
// Don't pop yet, we need the reference for gc.
|
||||||
Var self = PEEK(-1);
|
Var v = PEEK(-1);
|
||||||
Var result = varBitNot(vm, self);
|
Var result = varBitNot(vm, v);
|
||||||
DROP(); // self
|
DROP(); // self
|
||||||
PUSH(result);
|
PUSH(result);
|
||||||
|
|
||||||
|
@ -235,4 +235,10 @@ PkResult vmCallFunction(PKVM* vm, Closure* fn, int argc, Var* argv, Var* ret);
|
|||||||
PkResult vmCallMethod(PKVM* vm, Var self, Closure* fn,
|
PkResult vmCallMethod(PKVM* vm, Var self, Closure* fn,
|
||||||
int argc, Var* argv, Var* ret);
|
int argc, Var* argv, Var* ret);
|
||||||
|
|
||||||
|
// Import a module with the [path] and return it. The path sepearation should
|
||||||
|
// be '/' example: to import module "a.b" the [path] should be "a/b".
|
||||||
|
// If the [from] is not NULL, it'll be used for relative path search.
|
||||||
|
// On failure, it'll set an error and return VAR_NULL.
|
||||||
|
Var vmImportModule(PKVM* vm, String* from, String* path);
|
||||||
|
|
||||||
#endif // PK_VM_H
|
#endif // PK_VM_H
|
||||||
|
@ -94,13 +94,13 @@ typedef void (*pkWriteFn) (PKVM* vm, const char* text);
|
|||||||
|
|
||||||
// A function callback to read a line from stdin. The returned string shouldn't
|
// A function callback to read a line from stdin. The returned string shouldn't
|
||||||
// contain a line ending (\n or \r\n). The returned string **must** be
|
// contain a line ending (\n or \r\n). The returned string **must** be
|
||||||
// allocated with pkAllocString() and the VM will claim the ownership of the
|
// allocated with pkRealloc() and the VM will claim the ownership of the
|
||||||
// string.
|
// string.
|
||||||
typedef char* (*pkReadFn) (PKVM* vm);
|
typedef char* (*pkReadFn) (PKVM* vm);
|
||||||
|
|
||||||
// Load and return the script. Called by the compiler to fetch initial source
|
// Load and return the script. Called by the compiler to fetch initial source
|
||||||
// code and source for import statements. Return NULL to indicate failure to
|
// code and source for import statements. Return NULL to indicate failure to
|
||||||
// load. Otherwise the string **must** be allocated with pkAllocString() and
|
// load. Otherwise the string **must** be allocated with pkRealloc() and
|
||||||
// the VM will claim the ownership of the string.
|
// the VM will claim the ownership of the string.
|
||||||
typedef char* (*pkLoadScriptFn) (PKVM* vm, const char* path);
|
typedef char* (*pkLoadScriptFn) (PKVM* vm, const char* path);
|
||||||
|
|
||||||
@ -108,18 +108,20 @@ typedef char* (*pkLoadScriptFn) (PKVM* vm, const char* path);
|
|||||||
// be either path to a script or NULL if [path] is relative to cwd. The return
|
// be either path to a script or NULL if [path] is relative to cwd. The return
|
||||||
// value should be a normalized absolute path of the [path]. Return NULL to
|
// value should be a normalized absolute path of the [path]. Return NULL to
|
||||||
// indicate failure to resolve. Othrewise the string **must** be allocated with
|
// indicate failure to resolve. Othrewise the string **must** be allocated with
|
||||||
// pkAllocString() and the VM will claim the ownership of the string.
|
// pkRealloc() and the VM will claim the ownership of the string.
|
||||||
typedef char* (*pkResolvePathFn) (PKVM* vm, const char* from,
|
typedef char* (*pkResolvePathFn) (PKVM* vm, const char* from,
|
||||||
const char* path);
|
const char* path);
|
||||||
|
|
||||||
// A function callback to allocate and return a new instance of the registered
|
// A function callback to allocate and return a new instance of the registered
|
||||||
// class. Which will be called when the instance is constructed. The returned/
|
// class. Which will be called when the instance is constructed. The returned/
|
||||||
// data is expected to be alive till the delete callback occurs.
|
// data is expected to be alive till the delete callback occurs.
|
||||||
typedef void* (*pkNewInstanceFn) ();
|
typedef void* (*pkNewInstanceFn) (PKVM* vm);
|
||||||
|
|
||||||
// A function callback to de-allocate the aloocated native instance of the
|
// A function callback to de-allocate the allocated native instance of the
|
||||||
// registered class.
|
// registered class. This function is invoked at the GC execution. No object
|
||||||
typedef void (*pkDeleteInstanceFn) (void*);
|
// allocations are allowed during it, so **NEVER** allocate any objects
|
||||||
|
// inside them.
|
||||||
|
typedef void (*pkDeleteInstanceFn) (PKVM* vm, void*);
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* POCKETLANG TYPES */
|
/* POCKETLANG TYPES */
|
||||||
@ -197,26 +199,20 @@ PK_PUBLIC PKVM* pkNewVM(PkConfiguration* config);
|
|||||||
// Clean the VM and dispose all the resources allocated by the VM.
|
// Clean the VM and dispose all the resources allocated by the VM.
|
||||||
PK_PUBLIC void pkFreeVM(PKVM* vm);
|
PK_PUBLIC void pkFreeVM(PKVM* vm);
|
||||||
|
|
||||||
// This will register all the standard libraries of pocketlang to the VM. The
|
|
||||||
// libraries are not part of the core implementation, and one can use just the
|
|
||||||
// bare bone of the language without any libraries if they don't call this.
|
|
||||||
PK_PUBLIC void pkRegisterLibs(PKVM* vm);
|
|
||||||
|
|
||||||
// Update the user data of the vm.
|
// Update the user data of the vm.
|
||||||
PK_PUBLIC void pkSetUserData(PKVM* vm, void* user_data);
|
PK_PUBLIC void pkSetUserData(PKVM* vm, void* user_data);
|
||||||
|
|
||||||
// Returns the associated user data.
|
// Returns the associated user data.
|
||||||
PK_PUBLIC void* pkGetUserData(const PKVM* vm);
|
PK_PUBLIC void* pkGetUserData(const PKVM* vm);
|
||||||
|
|
||||||
// Allocate memory with [size] and return it. This function should be called
|
// Invoke pocketlang's allocator directly. This function should be called
|
||||||
// when the host application want to send strings to the PKVM that are claimed
|
// when the host application want to send strings to the PKVM that are claimed
|
||||||
// by the VM once the caller returned it.
|
// by the VM once the caller returned it. For other uses you **should** call
|
||||||
PK_PUBLIC char* pkAllocString(PKVM* vm, size_t size);
|
// pkRealloc with [size] 0 to cleanup, otherwise there will be a memory leak.
|
||||||
|
//
|
||||||
// Complementary function to pkAllocString. This should not be called if the
|
// Internally it'll call `pkReallocFn` function that was provided in the
|
||||||
// string is returned to the VM. Since PKVM will claim the ownership and
|
// configuration.
|
||||||
// deallocate the string itself.
|
PK_PUBLIC void* pkRealloc(PKVM* vm, void* ptr, size_t size);
|
||||||
PK_PUBLIC void pkDeAllocString(PKVM* vm, char* ptr);
|
|
||||||
|
|
||||||
// Release the handle and allow its value to be garbage collected. Always call
|
// Release the handle and allow its value to be garbage collected. Always call
|
||||||
// this for every handles before freeing the VM.
|
// this for every handles before freeing the VM.
|
||||||
@ -391,6 +387,11 @@ PK_PUBLIC bool pkGetAttribute(PKVM* vm, int instance, const char* name,
|
|||||||
// Place the [self] instance at the [index] slot.
|
// Place the [self] instance at the [index] slot.
|
||||||
PK_PUBLIC void pkPlaceSelf(PKVM* vm, int index);
|
PK_PUBLIC void pkPlaceSelf(PKVM* vm, int index);
|
||||||
|
|
||||||
|
// Import a module with the [path] and place it at [index] slot. The path
|
||||||
|
// sepearation should be '/'. Example: to import module "foo.bar" the [path]
|
||||||
|
// should be "foo/bar". On failure, it'll set an error and return false.
|
||||||
|
PK_PUBLIC bool pkImportModule(PKVM* vm, const char* path, int index);
|
||||||
|
|
||||||
// Set the [index] slot's value as the class of the [instance].
|
// Set the [index] slot's value as the class of the [instance].
|
||||||
PK_PUBLIC void pkGetClass(PKVM* vm, int instance, int index);
|
PK_PUBLIC void pkGetClass(PKVM* vm, int instance, int index);
|
||||||
|
|
||||||
|
@ -8,14 +8,20 @@
|
|||||||
#include "libs.h"
|
#include "libs.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void registerModuleDummy(PKVM* vm);
|
void registerModuleMath(PKVM* vm);
|
||||||
|
void registerModuleTime(PKVM* vm);
|
||||||
void registerModuleIO(PKVM* vm);
|
void registerModuleIO(PKVM* vm);
|
||||||
void registerModulePath(PKVM* vm);
|
void registerModulePath(PKVM* vm);
|
||||||
void registerModuleMath(PKVM* vm);
|
void registerModuleDummy(PKVM* vm);
|
||||||
|
|
||||||
void pkRegisterLibs(PKVM* vm) {
|
void registerLibs(PKVM* vm) {
|
||||||
registerModuleDummy(vm);
|
registerModuleMath(vm);
|
||||||
|
registerModuleTime(vm);
|
||||||
registerModuleIO(vm);
|
registerModuleIO(vm);
|
||||||
registerModulePath(vm);
|
registerModulePath(vm);
|
||||||
registerModuleMath(vm);
|
registerModuleDummy(vm);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cleanupLibs(PKVM* vm) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -113,13 +113,6 @@
|
|||||||
|
|
||||||
#endif // PK_AMALGAMATED
|
#endif // PK_AMALGAMATED
|
||||||
|
|
||||||
// Allocate a new module object of type [Ty].
|
|
||||||
#define NEW_OBJ(Ty) (Ty*) malloc(sizeof(Ty))
|
|
||||||
|
|
||||||
// Dellocate module object, allocated by NEW_OBJ(). Called by the freeObj
|
|
||||||
// callback.
|
|
||||||
#define FREE_OBJ(ptr) free(ptr)
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* SHARED FUNCTIONS */
|
/* SHARED FUNCTIONS */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
@ -133,4 +126,11 @@
|
|||||||
// inorder to use the import statements.
|
// inorder to use the import statements.
|
||||||
char* pathResolveImport(PKVM * vm, const char* from, const char* path);
|
char* pathResolveImport(PKVM * vm, const char* from, const char* path);
|
||||||
|
|
||||||
|
// Register all the the libraries to the PKVM.
|
||||||
|
void registerLibs(PKVM* vm);
|
||||||
|
|
||||||
|
// Cleanup registered libraries call this only if the libraries were registered
|
||||||
|
// with registerLibs() function.
|
||||||
|
void cleanupLibs(PKVM* vm);
|
||||||
|
|
||||||
#endif // LIBS_H
|
#endif // LIBS_H
|
||||||
|
@ -14,16 +14,15 @@ typedef struct {
|
|||||||
double val;
|
double val;
|
||||||
} Dummy;
|
} Dummy;
|
||||||
|
|
||||||
void* _newDummy() {
|
void* _newDummy(PKVM* vm) {
|
||||||
Dummy* dummy = NEW_OBJ(Dummy);
|
Dummy* dummy = pkRealloc(vm, NULL, sizeof(Dummy));
|
||||||
ASSERT(dummy != NULL, "malloc failed.");
|
ASSERT(dummy != NULL, "pkRealloc failed.");
|
||||||
dummy->val = 0;
|
dummy->val = 0;
|
||||||
return dummy;
|
return dummy;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _deleteDummy(void* ptr) {
|
void _deleteDummy(PKVM* vm, void* ptr) {
|
||||||
Dummy* dummy = (Dummy*)ptr;
|
pkRealloc(vm, ptr, 0);
|
||||||
FREE_OBJ(dummy);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DEF(_dummyInit, "") {
|
DEF(_dummyInit, "") {
|
||||||
@ -146,6 +145,7 @@ DEF(_dummyCallMethod,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void registerModuleDummy(PKVM* vm) {
|
void registerModuleDummy(PKVM* vm) {
|
||||||
|
|
||||||
PkHandle* dummy = pkNewModule(vm, "dummy");
|
PkHandle* dummy = pkNewModule(vm, "dummy");
|
||||||
|
|
||||||
pkModuleAddFunction(vm, dummy, "afunc", _dummyFunction, 2);
|
pkModuleAddFunction(vm, dummy, "afunc", _dummyFunction, 2);
|
||||||
|
@ -37,21 +37,22 @@ typedef struct {
|
|||||||
bool closed; // True if the file isn't closed yet.
|
bool closed; // True if the file isn't closed yet.
|
||||||
} File;
|
} File;
|
||||||
|
|
||||||
void* _newFile() {
|
void* _newFile(PKVM* vm) {
|
||||||
File* file = NEW_OBJ(File);
|
File* file = pkRealloc(vm, NULL, sizeof(File));
|
||||||
|
ASSERT(file != NULL, "pkRealloc failed.");
|
||||||
file->closed = true;
|
file->closed = true;
|
||||||
file->mode = FMODE_NONE;
|
file->mode = FMODE_NONE;
|
||||||
file->fp = NULL;
|
file->fp = NULL;
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _deleteFile(void* ptr) {
|
void _deleteFile(PKVM* vm, void* ptr) {
|
||||||
File* file = (File*)ptr;
|
File* file = (File*)ptr;
|
||||||
if (!file->closed) {
|
if (!file->closed) {
|
||||||
if (fclose(file->fp) != 0) { /* TODO: error! */ }
|
if (fclose(file->fp) != 0) { /* TODO: error! */ }
|
||||||
file->closed = true;
|
file->closed = true;
|
||||||
}
|
}
|
||||||
FREE_OBJ(file);
|
pkRealloc(vm, file, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
@ -123,8 +124,10 @@ DEF(_fileRead, "") {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: this is temporary.
|
// TODO: this is temporary.
|
||||||
|
|
||||||
char buff[2048];
|
char buff[2048];
|
||||||
fread((void*)buff, sizeof(char), sizeof(buff), file->fp);
|
size_t read = fread((void*)buff, sizeof(char), sizeof(buff), file->fp);
|
||||||
|
(void) read;
|
||||||
pkSetSlotString(vm, 0, (const char*)buff);
|
pkSetSlotString(vm, 0, (const char*)buff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#ifdef _WIN32
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -109,7 +109,7 @@ static char* tryImportPaths(PKVM* vm, char* path, char* buff) {
|
|||||||
|
|
||||||
char* ret = NULL;
|
char* ret = NULL;
|
||||||
if (path_size != 0) {
|
if (path_size != 0) {
|
||||||
ret = pkAllocString(vm, path_size + 1);
|
ret = pkRealloc(vm, NULL, path_size + 1);
|
||||||
memcpy(ret, buff, path_size + 1);
|
memcpy(ret, buff, path_size + 1);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
@ -138,7 +138,7 @@ char* pathResolveImport(PKVM* vm, const char* from, const char* path) {
|
|||||||
if (cwk_path_is_absolute(path)) {
|
if (cwk_path_is_absolute(path)) {
|
||||||
|
|
||||||
// buff1 = normalized path. +1 for null terminator.
|
// buff1 = normalized path. +1 for null terminator.
|
||||||
size_t size = cwk_path_normalize(path, buff1, sizeof(buff1)) + 1;
|
cwk_path_normalize(path, buff1, sizeof(buff1));
|
||||||
pathFixWindowsSeperator(buff1);
|
pathFixWindowsSeperator(buff1);
|
||||||
|
|
||||||
return tryImportPaths(vm, buff1, buff2);
|
return tryImportPaths(vm, buff1, buff2);
|
||||||
@ -150,7 +150,7 @@ char* pathResolveImport(PKVM* vm, const char* from, const char* path) {
|
|||||||
pathAbs(path, buff1, sizeof(buff1));
|
pathAbs(path, buff1, sizeof(buff1));
|
||||||
|
|
||||||
// buff2 = normalized path. +1 for null terminator.
|
// buff2 = normalized path. +1 for null terminator.
|
||||||
size_t size = cwk_path_normalize(buff1, buff2, sizeof(buff2)) + 1;
|
cwk_path_normalize(buff1, buff2, sizeof(buff2));
|
||||||
pathFixWindowsSeperator(buff2);
|
pathFixWindowsSeperator(buff2);
|
||||||
|
|
||||||
return tryImportPaths(vm, buff2, buff1);
|
return tryImportPaths(vm, buff2, buff1);
|
||||||
@ -173,7 +173,7 @@ char* pathResolveImport(PKVM* vm, const char* from, const char* path) {
|
|||||||
cwk_path_join(buff1, path, buff2, sizeof(buff2));
|
cwk_path_join(buff1, path, buff2, sizeof(buff2));
|
||||||
|
|
||||||
// buff1 = normalized absolute path. +1 for null terminator
|
// buff1 = normalized absolute path. +1 for null terminator
|
||||||
size_t size = cwk_path_normalize(buff2, buff1, sizeof(buff1)) + 1;
|
cwk_path_normalize(buff2, buff1, sizeof(buff1));
|
||||||
pathFixWindowsSeperator(buff1);
|
pathFixWindowsSeperator(buff1);
|
||||||
|
|
||||||
return tryImportPaths(vm, buff1, buff2);
|
return tryImportPaths(vm, buff1, buff2);
|
||||||
|
60
src/libs/std_time.c
Normal file
60
src/libs/std_time.c
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2022 Thakee Nathees
|
||||||
|
* Copyright (c) 2021-2022 Pocketlang Contributors
|
||||||
|
* Distributed Under The MIT License
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#ifndef PK_AMALGAMATED
|
||||||
|
#include "libs.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(_MSC_VER) && !(defined(_WIN32) && defined(__TINYC__))
|
||||||
|
#include <unistd.h> // usleep
|
||||||
|
#endif
|
||||||
|
|
||||||
|
DEF(_timeEpoch,
|
||||||
|
"time() -> num\n"
|
||||||
|
"Returns the number of seconds since the Epoch, 1970-01-01 "
|
||||||
|
"00:00:00 +0000 (UTC).") {
|
||||||
|
pkSetSlotNumber(vm, 0, (double) time(NULL));
|
||||||
|
}
|
||||||
|
|
||||||
|
DEF(_timeClock,
|
||||||
|
"clock() -> num\n"
|
||||||
|
"Returns the number of clocks passed divied by CLOCKS_PER_SEC.") {
|
||||||
|
pkSetSlotNumber(vm, 0, (double) clock() / CLOCKS_PER_SEC);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEF(_timeSleep,
|
||||||
|
"sleep(t:num) -> num\n"
|
||||||
|
"Sleep for [t] milliseconds.") {
|
||||||
|
|
||||||
|
double t;
|
||||||
|
pkValidateSlotNumber(vm, 1, &t);
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) || (defined(_WIN32) && defined(__TINYC__))
|
||||||
|
// Sleep(milli seconds)
|
||||||
|
Sleep((DWORD) t);
|
||||||
|
|
||||||
|
#else // usleep(micro seconds)
|
||||||
|
usleep(((useconds_t) (t)) * 1000);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void registerModuleTime(PKVM* vm) {
|
||||||
|
PkHandle* time = pkNewModule(vm, "time");
|
||||||
|
|
||||||
|
pkModuleAddFunction(vm, time, "epoch", _timeEpoch, 0);
|
||||||
|
pkModuleAddFunction(vm, time, "sleep", _timeSleep, 1);
|
||||||
|
pkModuleAddFunction(vm, time, "clock", _timeClock, 0);
|
||||||
|
|
||||||
|
pkRegisterModule(vm, time);
|
||||||
|
pkReleaseHandle(vm, time);
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
from lang import clock
|
from time import clock
|
||||||
|
|
||||||
start = clock()
|
start = clock()
|
||||||
N = 50000000; factors = []
|
N = 50000000; factors = []
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
from lang import clock
|
from time import clock
|
||||||
|
|
||||||
def fib(n)
|
def fib(n)
|
||||||
if n < 2 then return n end
|
if n < 2 then return n end
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from lang import clock
|
from time import clock
|
||||||
from math import floor
|
from math import floor
|
||||||
|
|
||||||
def reverse_list(list)
|
def reverse_list(list)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from lang import clock
|
from time import clock
|
||||||
start = clock()
|
start = clock()
|
||||||
|
|
||||||
l = []
|
l = []
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from lang import clock
|
from time import clock
|
||||||
|
|
||||||
def is_prime(n)
|
def is_prime(n)
|
||||||
if n < 2 then return false end
|
if n < 2 then return false end
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
## Run the script in pocketlang with
|
## Run the script in pocketlang with
|
||||||
## toc enabled VS toc disabled
|
## toc enabled VS toc disabled
|
||||||
|
|
||||||
from lang import clock
|
from time import clock
|
||||||
|
|
||||||
N = 20000
|
N = 20000
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ import lang
|
|||||||
import lang, path
|
import lang, path
|
||||||
import lang as o, path as p
|
import lang as o, path as p
|
||||||
from lang import write
|
from lang import write
|
||||||
from lang import clock as c
|
from time import sleep as s
|
||||||
|
|
||||||
import basics
|
import basics
|
||||||
import controlflow as if_test
|
import controlflow as if_test
|
||||||
|
Loading…
Reference in New Issue
Block a user