more comments written throught out the source

This commit is contained in:
Thakee Nathees 2021-06-03 02:14:01 +05:30
parent 2c1468f0e8
commit f9bf0c1b9c
18 changed files with 289 additions and 131 deletions

View File

@ -1,35 +1,35 @@
// To implement. // To implement.
- Implement resolve path in cli.
- Implement file IO
- Implement argparse. - Implement argparse.
- -v --version - -v --version
- emit opcodes - emit opcodes
- maybe write a similer .pyc file for pocket - maybe write a similer .pyc file for pocket
- --docs to generate docs from cstring. - --docs to generate docs from cstring.
- dump compiled code to a file.
- Ignore line with '\' character. - In keyword.
- Structs (maybe enums).
- Structs. - Implement file IO (require structs).
- Implement math library. - Implement gdb like debugger (add color print for readability).
- Single header for embedding.
- Implement fiber from script body and vm run fibers (not scripts). - Implement fiber from script body and vm run fibers (not scripts).
Then remove vm's root script. Then remove vm's root script.
- C Integration api (including add core lib from host application). - Initialize imported scripts (require fiber based vm).
- REPL. - REPL. compile expression for a script.
- compile expression for a script. - Hex, binary literals and floats like ".5".
- Var handler implement. - Docs build to a single directory, and replace url space (%20) with a hyphen.
- Complete all the TODO; macros.
// Low priority.
- Ignore line with '\' character.
- Make it possible to override function names. - Make it possible to override function names.
- To do so the functions and global variables should be in the same - To do so the functions and global variables should be in the same
buffer as the property of the script. buffer as the property of the script.
- Hex, binary literals and floats like ".5".
- Function docstring property. - Function docstring property.
- Union tagging alter in var. - Union tagging alter in var.
- (future) add structs and maybe enums. - Github actions.
// Add more. // Add more.
- Single header for embedding (script in pk, require file IO).
[ ] Compilte core methods. [ ] Compilte core methods.
[ ] Complete var methods. [ ] Complete var methods.
[ ] Complete core functions. [ ] Complete core functions.

View File

@ -4,7 +4,7 @@
*/ */
// This file will include all source files from the cli sub-directories here // This file will include all source files from the cli sub-directories here
// (thirdparty/modules). into a single file. That'll make it easy to compile // (thirdparty/modules) into a single file. That'll make it easy to compile
// with the command `gcc cli/*.c ...` instead of adding each sub-directory to // with the command `gcc cli/*.c ...` instead of adding each sub-directory to
// the list of source directory. // the list of source directory.

View File

@ -18,7 +18,7 @@ ROOT_URL = 'https://thakeenathees.github.io/pocketlang/'
## Home page should be in the SOURCE_DIR. ## Home page should be in the SOURCE_DIR.
HOME_PAGE = 'home.md' HOME_PAGE = 'home.md'
TRY_PAGE = 'try it now.html' TRY_PAGE = 'try-it-now.html'
SOURCE_DIR = 'pages/' SOURCE_DIR = 'pages/'
TARGET_DIR = 'build/' TARGET_DIR = 'build/'
STATIC_DIR = 'static/' STATIC_DIR = 'static/'
@ -36,14 +36,16 @@ WASM_SOURCE_FILES = '''\
''' '''
## Navigation pages in order. Should match the path names. ## Navigation pages in order. Should match the path names.
## Any file/folder name shouldn't contain white space.
PAGES = [ PAGES = [
('Getting Started', [ ('Getting-Started', [
TRY_PAGE, TRY_PAGE,
'build from source.md', 'learn-in-5-minutes.md',
'build-from-source.md',
'contributing.md', 'contributing.md',
]), ]),
('Language API', [ ('Language-API', [
'variables.md', 'variables.md',
'functions.md', 'functions.md',
'modules.md', 'modules.md',
@ -85,15 +87,17 @@ def main():
ctx = generate_page_context(join(SOURCE_DIR, HOME_PAGE), index_html, navigation) ctx = generate_page_context(join(SOURCE_DIR, HOME_PAGE), index_html, navigation)
write_page(ctx, template, index_html) write_page(ctx, template, index_html)
for entry in PAGES: for entry in PAGES: ## entry = ('dirname', [files...])
_dir = entry[0] _dir = entry[0]
for file in entry[1]: for file in entry[1]:
ext = get_validated_ext(file) ext = get_validated_ext(file)
path = join(SOURCE_DIR, _dir, file) path = join(SOURCE_DIR, _dir, file)
dst = '' dst = ''; path_prefix = _dir.lower().replace(' ', '-') + '-'
if ext == '.md' : dst = join(TARGET_DIR, _dir, file.replace('.md', '.html')) if ext == '.md':
else: dst = join(TARGET_DIR, _dir, file) dst = join(TARGET_DIR, path_prefix + file.replace('.md', '.html'))
else:
dst = join(TARGET_DIR, path_prefix + file)
ctx = generate_page_context(path, dst, navigation) ctx = generate_page_context(path, dst, navigation)
_template = template _template = template
@ -108,22 +112,27 @@ def generate_navigation():
for entry in PAGES: for entry in PAGES:
_dir = entry[0] _dir = entry[0]
navigation += '<div class="navigation">\n' navigation += '<div class="navigation">\n'
navigation += '<h3><strong>%s</strong></h3>\n' % (_dir) navigation += '<h3><strong>%s</strong></h3>\n' % (_dir.replace('-', ' ').title())
navigation += '<ul class="menu">\n' navigation += '<ul class="menu">\n'
for file in entry[1]: for file in entry[1]:
ext = get_validated_ext(file) ext = get_validated_ext(file)
link = '' ## Assuming that file name don't contain '.md' at the middle. link = '' ## Assuming that file name don't contain '.md' at the middle.
if ext == '.md': link = join(ROOT_URL, _dir, file.replace('.md', '.html'))
else: link = join(ROOT_URL, _dir, file) path_prefix = _dir.lower().replace(' ', '-') + '-'
if ext == '.md':
link = join(ROOT_URL, path_prefix + file.replace('.md', '.html'))
else:
link = join(ROOT_URL, path_prefix + file)
link = link.replace('\\', '/') link = link.replace('\\', '/')
title = file.replace(ext, '') title = file.replace(ext, '').replace('-', ' ').title()
navigation += '<li><a href="%s">%s</a></li>\n' % (link, title) navigation += '<li><a href="%s">%s</a></li>\n' % (link, title)
navigation += '</ul>\n' navigation += '</ul>\n'
navigation += '</div>\n' navigation += '</div>\n'
return navigation return navigation
@ -155,6 +164,9 @@ def path_to_title(path):
## Return the static dir relative path. ## Return the static dir relative path.
def relative_static_dir(dst): def relative_static_dir(dst):
return STATIC_DIR ## No more relative paths.
_dir = os.path.dirname(dst) _dir = os.path.dirname(dst)
static_dir = os.path.relpath(join(TARGET_DIR, STATIC_DIR), _dir) static_dir = os.path.relpath(join(TARGET_DIR, STATIC_DIR), _dir)
static_dir = static_dir.replace('\\', '/') static_dir = static_dir.replace('\\', '/')
@ -203,7 +215,6 @@ def custom_html_override(src, content):
'<span class="n">%s</span>' % nk) '<span class="n">%s</span>' % nk)
## codehilite mark the compilation command as error. ## codehilite mark the compilation command as error.
if 'build from source' in src:
content = content.replace('<span class="err">', '<span>') content = content.replace('<span class="err">', '<span>')
return content return content
@ -227,8 +238,10 @@ if __name__ == '__main__':
_local = False _local = False
if len(sys.argv) >= 2: if len(sys.argv) >= 2:
if sys.argv[1] == 'local': if sys.argv[1] == 'local':
ROOT_URL = 'http://localhost:8000/'
_local = True _local = True
#ROOT_URL = 'http://localhost:8000/'
ROOT_URL = '' ## No more nested directory pages.
main() main()

View File

@ -0,0 +1,83 @@
# Learn pocketlang in 5 minutes
```ruby
# This is a comment.
x = 0 # Creating a variable.
# The value '0' is a type of number.
# In pocketlang statements should end with a new line
# or a semicollon. White space characters except for new
# lines are ignored in pocketlang.
a = 1; b = 2;
# Data types.
# -----------
# Primitive types
null # A null type.
true; false # Booleans.
42; 3.14 # Numbers.
0..10; 10..0 # Range (0..10 = 0 <= r < 10).
# Object types
"hello"; 'world' # Strings (support multiline).
[42, 'foo', null] # Lists.
{ 'Key':'value' } # Maps.
func(x) return x*x end # Lambda/literal functions.
import lang # Module (imported scripts).
# Control flow.
# -------------
# If condition.
if x == 'foo'
print('bar')
elif x == 'bar'
print('baz')
end
# In a single line (should add 'then' keyword).
if x == 'foo' then print('bar') end
# For loops, here 'do' keyword is optional if we have a
# newline after the sequence (like 'then' in if statements).
for i in 0..10 do
print(i)
end
# While statement.
while x > 0 do print(x -= 1) end
# In pocketlang variable's lifetime are scope based.
if true then
local = null
end
#print(local) # Error: Name 'local' is not defined.
# Functions.
#-----------
def add(a, b)
return a + b
end
# Functions can be assigned to a variable.
fn = func(x) return x*x end
# Functions can be passed as an argument and can be returned.
def call(fn, x)
fn(x)
return func print('foo') end
end
# Concanative call operator '->'
str_lower(str_strip('FOO ')) # This can be written as below
'FOO ' -> str_strip -> str_lower
'foo' -> print # similer as print('foo')
```

View File

@ -365,6 +365,7 @@ static OpInfo opcode_info[] = {
* ERROR HANDLERS * * ERROR HANDLERS *
*****************************************************************************/ *****************************************************************************/
// Internal error report function of the parseError() function.
static void reportError(Compiler* compiler, const char* file, int line, static void reportError(Compiler* compiler, const char* file, int line,
const char* fmt, va_list args) { const char* fmt, va_list args) {
PKVM* vm = compiler->vm; PKVM* vm = compiler->vm;

View File

@ -17,16 +17,22 @@
/* PUBLIC API */ /* PUBLIC API */
/*****************************************************************************/ /*****************************************************************************/
// Declare internal functions of public api. // Create a new module with the given [name] and returns as a Script* for
// internal. Which will be wrapped by pkNewModule to return a pkHandle*.
static Script* newModuleInternal(PKVM* vm, const char* name); static Script* newModuleInternal(PKVM* vm, const char* name);
static void moduleAddFunctionInternal(PKVM* vm, Script* script,
const char* name, pkNativeFn fptr, int arity);
// The internal function to add functions to a module.
static void moduleAddFunctionInternal(PKVM* vm, Script* script,
const char* name, pkNativeFn fptr,
int arity);
// pkNewModule implementation (see pocketlang.h for description).
PkHandle* pkNewModule(PKVM* vm, const char* name) { PkHandle* pkNewModule(PKVM* vm, const char* name) {
Script* module = newModuleInternal(vm, name); Script* module = newModuleInternal(vm, name);
return vmNewHandle(vm, VAR_OBJ(&module->_super)); return vmNewHandle(vm, VAR_OBJ(&module->_super));
} }
// pkModuleAddFunction implementation (see pocketlang.h for description).
void pkModuleAddFunction(PKVM* vm, PkHandle* module, const char* name, void pkModuleAddFunction(PKVM* vm, PkHandle* module, const char* name,
pkNativeFn fptr, int arity) { pkNativeFn fptr, int arity) {
__ASSERT(module != NULL, "Argument module was NULL."); __ASSERT(module != NULL, "Argument module was NULL.");
@ -38,18 +44,18 @@ void pkModuleAddFunction(PKVM* vm, PkHandle* module, const char* name,
moduleAddFunctionInternal(vm, (Script*)AS_OBJ(scr), name, fptr, arity); moduleAddFunctionInternal(vm, (Script*)AS_OBJ(scr), name, fptr, arity);
} }
// Argument getter (1 based). // A convinent macro to get the nth (1 based) argument of the current function.
#define ARG(n) vm->fiber->ret[n] #define ARG(n) vm->fiber->ret[n]
// Convinent macros. // Convinent macros to get the 1st, 2nd, 3rd arguments.
#define ARG1 ARG(1) #define ARG1 ARG(1)
#define ARG2 ARG(2) #define ARG2 ARG(2)
#define ARG3 ARG(3) #define ARG3 ARG(3)
// Argument count used in variadic functions. // Evaluvates to the current function's argument count.
#define ARGC ((int)(vm->fiber->sp - vm->fiber->ret) - 1) #define ARGC ((int)(vm->fiber->sp - vm->fiber->ret) - 1)
// Set return value and return. // Set return value for the current native function and return.
#define RET(value) \ #define RET(value) \
do { \ do { \
*(vm->fiber->ret) = value; \ *(vm->fiber->ret) = value; \
@ -63,6 +69,7 @@ void pkModuleAddFunction(PKVM* vm, PkHandle* module, const char* name,
__ASSERT(value != NULL, "Parameter [value] was NULL."); \ __ASSERT(value != NULL, "Parameter [value] was NULL."); \
((void*)0) ((void*)0)
// Set error for incompatible type provided as an argument.
#define ERR_INVALID_ARG_TYPE(m_type) \ #define ERR_INVALID_ARG_TYPE(m_type) \
do { \ do { \
char buff[STR_INT_BUFF_SIZE]; \ char buff[STR_INT_BUFF_SIZE]; \
@ -71,11 +78,13 @@ do { \
" at argument $.", buff); \ " at argument $.", buff); \
} while (false) } while (false)
// pkGetArgc implementation (see pocketlang.h for description).
int pkGetArgc(PKVM* vm) { int pkGetArgc(PKVM* vm) {
__ASSERT(vm->fiber != NULL, "This function can only be called at runtime."); __ASSERT(vm->fiber != NULL, "This function can only be called at runtime.");
return ARGC; return ARGC;
} }
// pkGetArg implementation (see pocketlang.h for description).
PkVar pkGetArg(PKVM* vm, int arg) { PkVar pkGetArg(PKVM* vm, int arg) {
__ASSERT(vm->fiber != NULL, "This function can only be called at runtime."); __ASSERT(vm->fiber != NULL, "This function can only be called at runtime.");
__ASSERT(arg > 0 || arg <= ARGC, "Invalid argument index."); __ASSERT(arg > 0 || arg <= ARGC, "Invalid argument index.");
@ -83,6 +92,7 @@ PkVar pkGetArg(PKVM* vm, int arg) {
return &(ARG(arg)); return &(ARG(arg));
} }
// pkGetArgBool implementation (see pocketlang.h for description).
bool pkGetArgBool(PKVM* vm, int arg, bool* value) { bool pkGetArgBool(PKVM* vm, int arg, bool* value) {
CHECK_GET_ARG_API_ERRORS(); CHECK_GET_ARG_API_ERRORS();
@ -91,6 +101,7 @@ bool pkGetArgBool(PKVM* vm, int arg, bool* value) {
return true; return true;
} }
// pkGetArgNumber implementation (see pocketlang.h for description).
bool pkGetArgNumber(PKVM* vm, int arg, double* value) { bool pkGetArgNumber(PKVM* vm, int arg, double* value) {
CHECK_GET_ARG_API_ERRORS(); CHECK_GET_ARG_API_ERRORS();
@ -109,6 +120,7 @@ bool pkGetArgNumber(PKVM* vm, int arg, double* value) {
return true; return true;
} }
// pkGetArgString implementation (see pocketlang.h for description).
bool pkGetArgString(PKVM* vm, int arg, const char** value) { bool pkGetArgString(PKVM* vm, int arg, const char** value) {
CHECK_GET_ARG_API_ERRORS(); CHECK_GET_ARG_API_ERRORS();
@ -124,6 +136,7 @@ bool pkGetArgString(PKVM* vm, int arg, const char** value) {
return true; return true;
} }
// pkGetArgValue implementation (see pocketlang.h for description).
bool pkGetArgValue(PKVM* vm, int arg, PkVarType type, PkVar* value) { bool pkGetArgValue(PKVM* vm, int arg, PkVarType type, PkVar* value) {
CHECK_GET_ARG_API_ERRORS(); CHECK_GET_ARG_API_ERRORS();
@ -139,54 +152,36 @@ bool pkGetArgValue(PKVM* vm, int arg, PkVarType type, PkVar* value) {
return true; return true;
} }
// pkReturnNull implementation (see pocketlang.h for description).
void pkReturnNull(PKVM* vm) { void pkReturnNull(PKVM* vm) {
RET(VAR_NULL); RET(VAR_NULL);
} }
// pkReturnBool implementation (see pocketlang.h for description).
void pkReturnBool(PKVM* vm, bool value) { void pkReturnBool(PKVM* vm, bool value) {
RET(VAR_BOOL(value)); RET(VAR_BOOL(value));
} }
// pkReturnNumber implementation (see pocketlang.h for description).
void pkReturnNumber(PKVM* vm, double value) { void pkReturnNumber(PKVM* vm, double value) {
RET(VAR_NUM(value)); RET(VAR_NUM(value));
} }
// pkReturnString implementation (see pocketlang.h for description).
void pkReturnString(PKVM* vm, const char* value) { void pkReturnString(PKVM* vm, const char* value) {
RET(VAR_OBJ(&newString(vm, value)->_super)); RET(VAR_OBJ(&newString(vm, value)->_super));
} }
// pkReturnStringLength implementation (see pocketlang.h for description).
void pkReturnStringLength(PKVM* vm, const char* value, size_t length) { void pkReturnStringLength(PKVM* vm, const char* value, size_t length) {
RET(VAR_OBJ(&newStringLength(vm, value, (uint32_t)length)->_super)); RET(VAR_OBJ(&newStringLength(vm, value, (uint32_t)length)->_super));
} }
// pkReturnValue implementation (see pocketlang.h for description).
void pkReturnValue(PKVM* vm, PkVar value) { void pkReturnValue(PKVM* vm, PkVar value) {
RET(*(Var*)value); RET(*(Var*)value);
} }
/*****************************************************************************/
/* CORE INTERNAL */
/*****************************************************************************/
static void initializeBuiltinFN(PKVM* vm, BuiltinFn* bfn, const char* name,
int length, int arity, pkNativeFn ptr) {
bfn->name = name;
bfn->length = length;
bfn->fn = newFunction(vm, name, length, NULL, true);
bfn->fn->arity = arity;
bfn->fn->native = ptr;
}
int findBuiltinFunction(PKVM* vm, const char* name, uint32_t length) {
for (int i = 0; i < vm->builtins_count; i++) {
if (length == vm->builtins[i].length &&
strncmp(name, vm->builtins[i].name, length) == 0) {
return i;
}
}
return -1;
}
/*****************************************************************************/ /*****************************************************************************/
/* VALIDATORS */ /* VALIDATORS */
/*****************************************************************************/ /*****************************************************************************/
@ -259,16 +254,30 @@ static inline bool validateIndex(PKVM* vm, int32_t index, int32_t size,
/* BUILTIN FUNCTIONS API */ /* BUILTIN FUNCTIONS API */
/*****************************************************************************/ /*****************************************************************************/
// findBuiltinFunction implementation (see core.h for description).
int findBuiltinFunction(PKVM* vm, const char* name, uint32_t length) {
for (int i = 0; i < vm->builtins_count; i++) {
if (length == vm->builtins[i].length &&
strncmp(name, vm->builtins[i].name, length) == 0) {
return i;
}
}
return -1;
}
// getBuiltinFunction implementation (see core.h for description).
Function* getBuiltinFunction(PKVM* vm, int index) { Function* getBuiltinFunction(PKVM* vm, int index) {
ASSERT_INDEX(index, vm->builtins_count); ASSERT_INDEX(index, vm->builtins_count);
return vm->builtins[index].fn; return vm->builtins[index].fn;
} }
// getBuiltinFunctionName implementation (see core.h for description).
const char* getBuiltinFunctionName(PKVM* vm, int index) { const char* getBuiltinFunctionName(PKVM* vm, int index) {
ASSERT_INDEX(index, vm->builtins_count); ASSERT_INDEX(index, vm->builtins_count);
return vm->builtins[index].name; return vm->builtins[index].name;
} }
// getCoreLib implementation (see core.h for description).
Script* getCoreLib(PKVM* vm, String* name) { Script* getCoreLib(PKVM* vm, String* name) {
Var lib = mapGet(vm->core_libs, VAR_OBJ(&name->_super)); Var lib = mapGet(vm->core_libs, VAR_OBJ(&name->_super));
if (IS_UNDEF(lib)) return NULL; if (IS_UNDEF(lib)) return NULL;
@ -309,16 +318,14 @@ FN_IS_OBJ_TYPE(UserObj, OBJ_USER)
PK_DOC(coreTypeName, PK_DOC(coreTypeName,
"type_name(value:var) -> string\n" "type_name(value:var) -> string\n"
"Returns the type name of the of the value."); "Returns the type name of the of the value.") {
void coreTypeName(PKVM* vm) {
RET(VAR_OBJ(&newString(vm, varTypeName(ARG1))->_super)); RET(VAR_OBJ(&newString(vm, varTypeName(ARG1))->_super));
} }
PK_DOC(coreAssert, PK_DOC(coreAssert,
"assert(condition:bool [, msg:string]) -> void\n" "assert(condition:bool [, msg:string]) -> void\n"
"If the condition is false it'll terminate the current fiber with the " "If the condition is false it'll terminate the current fiber with the "
"optional error message"); "optional error message") {
void coreAssert(PKVM* vm) {
int argc = ARGC; int argc = ARGC;
if (argc != 1 && argc != 2) { if (argc != 1 && argc != 2) {
vm->fiber->error = newString(vm, "Invalid argument count."); vm->fiber->error = newString(vm, "Invalid argument count.");
@ -345,16 +352,14 @@ void coreAssert(PKVM* vm) {
PK_DOC(coreToString, PK_DOC(coreToString,
"to_string(value:var) -> string\n" "to_string(value:var) -> string\n"
"Returns the string representation of the value."); "Returns the string representation of the value.") {
void coreToString(PKVM* vm) {
RET(VAR_OBJ(&toString(vm, ARG1)->_super)); RET(VAR_OBJ(&toString(vm, ARG1)->_super));
} }
PK_DOC(corePrint, PK_DOC(corePrint,
"print(...) -> void\n" "print(...) -> void\n"
"Write each argument as comma seperated to the stdout and ends with a " "Write each argument as comma seperated to the stdout and ends with a "
"newline."); "newline.") {
void corePrint(PKVM* vm) {
// If the host appliaction donesn't provide any write function, discard the // If the host appliaction donesn't provide any write function, discard the
// output. // output.
if (vm->config.write_fn == NULL) return; if (vm->config.write_fn == NULL) return;
@ -379,8 +384,9 @@ void corePrint(PKVM* vm) {
// String functions. // String functions.
// ----------------- // -----------------
PK_DOC(coreStrLower,
void coreStrLower(PKVM* vm) { "str_lower(value:string) -> string\n"
"Returns a lower-case version of the given string.") {
String* str; String* str;
if (!validateArgString(vm, 1, &str)) return; if (!validateArgString(vm, 1, &str)) return;
@ -393,7 +399,9 @@ void coreStrLower(PKVM* vm) {
RET(VAR_OBJ(&result->_super)); RET(VAR_OBJ(&result->_super));
} }
void coreStrUpper(PKVM* vm) { PK_DOC(coreStrUpper,
"str_upper(value:string) -> string\n"
"Returns a upper-case version of the given string.") {
String* str; String* str;
if (!validateArgString(vm, 1, &str)) return; if (!validateArgString(vm, 1, &str)) return;
@ -406,7 +414,10 @@ void coreStrUpper(PKVM* vm) {
RET(VAR_OBJ(&result->_super)); RET(VAR_OBJ(&result->_super));
} }
void coreStrStrip(PKVM* vm) { PK_DOC(coreStrStrip,
"str_strip(value:string) -> string\n"
"Returns a copy of the string as the leading and trailing white spaces are"
"trimed.") {
String* str; String* str;
if (!validateArgString(vm, 1, &str)) return; if (!validateArgString(vm, 1, &str)) return;
@ -420,19 +431,21 @@ void coreStrStrip(PKVM* vm) {
RET(VAR_OBJ(&newStringLength(vm, start, (uint32_t)(end - start + 1))->_super)); RET(VAR_OBJ(&newStringLength(vm, start, (uint32_t)(end - start + 1))->_super));
} }
// Returns the ASCII string value of the integer argument. PK_DOC(coreStrChr,
void coreStrChr(PKVM* vm) { "str_chr(value:number) -> string\n"
"Returns the ASCII string value of the integer argument.") {
int32_t num; int32_t num;
if (!validateInteger(vm, ARG1, &num, "Argument 1")); if (!validateInteger(vm, ARG1, &num, "Argument 1")) return;
char c = (char)num; char c = (char)num;
RET(VAR_OBJ(&newStringLength(vm, &c, 1)->_super)); RET(VAR_OBJ(&newStringLength(vm, &c, 1)->_super));
} }
// Returns integer value of the given ASCII character. PK_DOC(coreStrOrd,
void coreStrOrd(PKVM* vm) { "str_ord(value:string) -> number\n"
"Returns integer value of the given ASCII character.") {
String* c; String* c;
if (!validateArgString(vm, 1, &c)); if (!validateArgString(vm, 1, &c)) return;
if (c->length != 1) { if (c->length != 1) {
vm->fiber->error = newString(vm, "Expected a string of length 1."); vm->fiber->error = newString(vm, "Expected a string of length 1.");
RET(VAR_NULL); RET(VAR_NULL);
@ -442,10 +455,12 @@ void coreStrOrd(PKVM* vm) {
} }
// List functions. // List functions.
// --------------- // ---------------
void coreListAppend(PKVM* vm) {
PK_DOC(coreListAppend,
"list_append(self:List, value:var) -> List\n"
"Append the [value] to the list [self] and return the list.") {
List* list; List* list;
if (!validateArgList(vm, 1, &list)) return; if (!validateArgList(vm, 1, &list)) return;
Var elem = ARG(2); Var elem = ARG(2);
@ -457,13 +472,15 @@ void coreListAppend(PKVM* vm) {
// Map functions. // Map functions.
// -------------- // --------------
void coreMapRemove(PKVM* vm) { PK_DOC(coreMapRemove,
"map_remove(self:map, key:var) -> var\n"
"Remove the [key] from the map [self] and return it's value if the key "
"exists, otherwise it'll return null.") {
Map* map; Map* map;
if (!validateArgMap(vm, 1, &map)) return; if (!validateArgMap(vm, 1, &map)) return;
Var key = ARG(2); Var key = ARG(2);
mapRemoveKey(vm, map, key); RET(mapRemoveKey(vm, map, key));
RET(VAR_OBJ(&map->_super));
} }
/*****************************************************************************/ /*****************************************************************************/
@ -497,8 +514,10 @@ static Script* newModuleInternal(PKVM* vm, const char* name) {
return scr; return scr;
} }
// An internal function to add a function to the given [script].
static void moduleAddFunctionInternal(PKVM* vm, Script* script, static void moduleAddFunctionInternal(PKVM* vm, Script* script,
const char* name, pkNativeFn fptr, int arity) { const char* name, pkNativeFn fptr,
int arity) {
// Check if function with the same name already exists. // Check if function with the same name already exists.
if (scriptSearchFunc(script, name, (uint32_t)strlen(name)) != -1) { if (scriptSearchFunc(script, name, (uint32_t)strlen(name)) != -1) {
@ -624,6 +643,17 @@ void stdMathHash(PKVM* vm) {
/*****************************************************************************/ /*****************************************************************************/
/* CORE INITIALIZATION */ /* CORE INITIALIZATION */
/*****************************************************************************/ /*****************************************************************************/
static void initializeBuiltinFN(PKVM* vm, BuiltinFn* bfn, const char* name,
int length, int arity, pkNativeFn ptr) {
bfn->name = name;
bfn->length = length;
bfn->fn = newFunction(vm, name, length, NULL, true);
bfn->fn->arity = arity;
bfn->fn->native = ptr;
}
void initializeCore(PKVM* vm) { void initializeCore(PKVM* vm) {
#define INITALIZE_BUILTIN_FN(name, fn, argc) \ #define INITALIZE_BUILTIN_FN(name, fn, argc) \
@ -817,6 +847,7 @@ bool varLesser(Var v1, Var v2) {
#define IS_ATTRIB(name) \ #define IS_ATTRIB(name) \
(attrib->length == strlen(name) && strcmp(name, attrib->data) == 0) (attrib->length == strlen(name) && strcmp(name, attrib->data) == 0)
// Set error for accessing non-existed attribute.
#define ERR_NO_ATTRIB() \ #define ERR_NO_ATTRIB() \
vm->fiber->error = stringFormat(vm, "'$' objects has no attribute " \ vm->fiber->error = stringFormat(vm, "'$' objects has no attribute " \
"named '$'", \ "named '$'", \

View File

@ -30,19 +30,25 @@ Script* getCoreLib(PKVM* vm, String* name);
/* OPERATORS */ /* OPERATORS */
/*****************************************************************************/ /*****************************************************************************/
Var varAdd(PKVM* vm, Var v1, Var v2); Var varAdd(PKVM* vm, Var v1, Var v2); // Returns v1 + v2.
Var varSubtract(PKVM* vm, Var v1, Var v2); Var varSubtract(PKVM* vm, Var v1, Var v2); // Returns v1 - v2.
Var varMultiply(PKVM* vm, Var v1, Var v2); Var varMultiply(PKVM* vm, Var v1, Var v2); // Returns v1 * v2.
Var varDivide(PKVM* vm, Var v1, Var v2); Var varDivide(PKVM* vm, Var v1, Var v2); // Returns v1 / v2.
Var varModulo(PKVM* vm, Var v1, Var v2); Var varModulo(PKVM* vm, Var v1, Var v2); // Returns v1 % v2.
bool varGreater(Var v1, Var v2); bool varGreater(Var v1, Var v2); // Returns v1 > v2.
bool varLesser(Var v1, Var v2); bool varLesser(Var v1, Var v2); // Returns v1 < v2.
// Returns the attribute named [attrib] on the variable [on].
Var varGetAttrib(PKVM* vm, Var on, String* attrib); Var varGetAttrib(PKVM* vm, Var on, String* attrib);
// Set the attribute named [attrib] on the variable [on] with the given [value].
void varSetAttrib(PKVM* vm, Var on, String* name, Var value); void varSetAttrib(PKVM* vm, Var on, String* name, Var value);
// Returns the subscript value (ie. on[key]).
Var varGetSubscript(PKVM* vm, Var on, Var key); Var varGetSubscript(PKVM* vm, Var on, Var key);
// Set subscript [value] with the [key] (ie. on[key] = value).
void varsetSubscript(PKVM* vm, Var on, Var key, Var value); void varsetSubscript(PKVM* vm, Var on, Var key, Var value);
#endif // CORE_H #endif // CORE_H

View File

@ -57,10 +57,13 @@ extern "C" {
// A convinent macro to define documentation of funcions. Use it to document // A convinent macro to define documentation of funcions. Use it to document
// your native functions. // your native functions.
// //
// PK_DOC(foo, "The function will print 'foo' on the console."); // PK_DOC(foo,
// void foo(PKVM* vm) { printf("foo\n"); } // "The function will print 'foo' on the console.") {
// printf("foo\n");
// }
// //
#define PK_DOC(func, doc) static char __pkdoc__##func[] = doc #define PK_DOC(func, doc) \
static char __pkdoc__##func[] = doc; void func(PKVM* vm)
/*****************************************************************************/ /*****************************************************************************/
/* POCKETLANG TYPES */ /* POCKETLANG TYPES */

View File

@ -5,6 +5,7 @@
#include "utils.h" #include "utils.h"
// Function implementation, see utils.h for description.
int utilPowerOf2Ceil(int n) { int utilPowerOf2Ceil(int n) {
n--; n--;
n |= n >> 1; n |= n >> 1;
@ -17,10 +18,12 @@ int utilPowerOf2Ceil(int n) {
return n; return n;
} }
// Function implementation, see utils.h for description.
bool utilIsName(char c) { bool utilIsName(char c) {
return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || (c == '_'); return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || (c == '_');
} }
// Function implementation, see utils.h for description.
bool utilIsDigit(char c) { bool utilIsDigit(char c) {
return ('0' <= c && c <= '9'); return ('0' <= c && c <= '9');
} }
@ -32,18 +35,21 @@ typedef union {
double num; double num;
} _DoubleBitsConv; } _DoubleBitsConv;
// Function implementation, see utils.h for description.
uint64_t utilDoubleToBits(double value) { uint64_t utilDoubleToBits(double value) {
_DoubleBitsConv bits; _DoubleBitsConv bits;
bits.num = value; bits.num = value;
return bits.bits64; return bits.bits64;
} }
// Function implementation, see utils.h for description.
double utilDoubleFromBits(uint64_t value) { double utilDoubleFromBits(uint64_t value) {
_DoubleBitsConv bits; _DoubleBitsConv bits;
bits.bits64 = value; bits.bits64 = value;
return bits.num; return bits.num;
} }
// Function implementation, see utils.h for description.
uint32_t utilHashBits(uint64_t hash) { uint32_t utilHashBits(uint64_t hash) {
// From v8's ComputeLongHash() which in turn cites: // From v8's ComputeLongHash() which in turn cites:
// Thomas Wang, Integer Hash Functions. // Thomas Wang, Integer Hash Functions.
@ -57,11 +63,13 @@ uint32_t utilHashBits(uint64_t hash) {
return (uint32_t)(hash & 0x3fffffff); return (uint32_t)(hash & 0x3fffffff);
} }
// Function implementation, see utils.h for description.
uint32_t utilHashNumber(double num) { uint32_t utilHashNumber(double num) {
// Hash the raw bits of the value. // Hash the raw bits of the value.
return utilHashBits(utilDoubleToBits(num)); return utilHashBits(utilDoubleToBits(num));
} }
// Function implementation, see utils.h for description.
uint32_t utilHashString(const char* string) { uint32_t utilHashString(const char* string) {
// FNV-1a hash. See: http://www.isthe.com/chongo/tech/comp/fnv/ // FNV-1a hash. See: http://www.isthe.com/chongo/tech/comp/fnv/
@ -85,6 +93,7 @@ uint32_t utilHashString(const char* string) {
* UTF8 * * UTF8 *
****************************************************************************/ ****************************************************************************/
// Function implementation, see utils.h for description.
int utf8_encodeBytesCount(int value) { int utf8_encodeBytesCount(int value) {
if (value <= 0x7f) return 1; if (value <= 0x7f) return 1;
if (value <= 0x7ff) return 2; if (value <= 0x7ff) return 2;
@ -95,6 +104,7 @@ int utf8_encodeBytesCount(int value) {
return 0; return 0;
} }
// Function implementation, see utils.h for description.
int utf8_decodeBytesCount(uint8_t byte) { int utf8_decodeBytesCount(uint8_t byte) {
if ((byte >> 7) == 0b0) return 1; if ((byte >> 7) == 0b0) return 1;
@ -107,6 +117,7 @@ int utf8_decodeBytesCount(uint8_t byte) {
return 1; return 1;
} }
// Function implementation, see utils.h for description.
int utf8_encodeValue(int value, uint8_t* bytes) { int utf8_encodeValue(int value, uint8_t* bytes) {
if (value <= 0x7f) { if (value <= 0x7f) {
@ -145,6 +156,7 @@ int utf8_encodeValue(int value, uint8_t* bytes) {
return 0; return 0;
} }
// Function implementation, see utils.h for description.
int utf8_decodeBytes(uint8_t* bytes, int* value) { int utf8_decodeBytes(uint8_t* bytes, int* value) {
int continue_bytes = 0; int continue_bytes = 0;

View File

@ -32,6 +32,7 @@ PkVarType pkGetValueType(PkVar value) {
case OBJ_SCRIPT: return PK_SCRIPT; case OBJ_SCRIPT: return PK_SCRIPT;
case OBJ_FUNC: return PK_FUNCTION; case OBJ_FUNC: return PK_FUNCTION;
case OBJ_FIBER: return PK_FIBER; case OBJ_FIBER: return PK_FIBER;
case OBJ_USER: TODO; break;
} }
UNREACHABLE(); UNREACHABLE();

View File

@ -23,16 +23,13 @@ triangle = ">++++[<++++++++>-]>++++++++[>++++<-]>>++>>>+>>>+<<<<<<<<<<[-[->+<]>
[-]<]+++++" [-]<]+++++"
## Source: https://github.com/fabianishere/brainfuck/blob/master/examples/math/fib.bf ## Source: https://github.com/fabianishere/brainfuck/blob/master/examples/math/fib.bf
fibonacci = ">++++++++++>+>+[ fibonacci = ">++++++++++>+>+[[+++++[>++++++++<-]>.<++++++[>--------<-]+<<<]>.
[+++++[>++++++++<-]>.<++++++[>--------<-]+<<<]>.>>[ >>[[-]<[>+<-]>>[<<+>+>-]<[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+
[-]<[>+<-]>>[<<+>+>-]<[>+<-[>+<-[>+<-[>+<-[>+<-[>+<- <-[>+<-[>[-]>+>+<<<-[>+<-]]]]]]]]]]]+>>>]<<<]"
[>+<-[>+<-[>+<-[>[-]>+>+<<<-[>+<-]]]]]]]]]]]+>>>
]<<<
]"
execute(hello_world) execute(hello_world)
execute(triangle) execute(triangle)
execute(fibonacci) ##execute(fibonacci) This will run endlessly (cannot run test).
############################################################################### ###############################################################################
## INTERNAL ## ## INTERNAL ##

View File

@ -2,17 +2,22 @@ import subprocess, os, sys
import json, re import json, re
from os.path import join from os.path import join
FMT_PATH = "%-25s" ## All the test files.
INDENTATION = ' | '
test_files = [ test_files = [
"lang/basics.pk", "lang/basics.pk",
"lang/functions.pk", "lang/functions.pk",
"lang/controlflow.pk", "lang/controlflow.pk",
"lang/import.pk",
"examples/helloworld.pk",
"examples/brainfuck.pk",
"examples/fib.pk", "examples/fib.pk",
"examples/prime.pk", "examples/prime.pk",
"examples/fizzbuzz.pk",
"examples/pi.pk",
] ]
## All benchmark files. ## TODO: pass args for iterations.
benchmarks = { benchmarks = {
"factors" : ['.pk', '.py', '.rb', '.wren'], "factors" : ['.pk', '.py', '.rb', '.wren'],
"fib" : ['.pk', '.py', '.rb', '.wren'], "fib" : ['.pk', '.py', '.rb', '.wren'],
@ -21,10 +26,14 @@ benchmarks = {
"primes" : ['.pk', '.py', '.rb', ".wren"], "primes" : ['.pk', '.py', '.rb', ".wren"],
} }
def main():
run_all_tests()
run_all_benchmarks()
def run_all_benchmarks(): def run_all_benchmarks():
print("--------------------------------") print_title("BENCHMARKS")
print(" BENCHMARKS ")
print("--------------------------------")
def get_interpreter(file): def get_interpreter(file):
if file.endswith('.pk' ) : return 'pocket' if file.endswith('.pk' ) : return 'pocket'
@ -47,13 +56,11 @@ def run_all_benchmarks():
print('%10ss'%time[0]) print('%10ss'%time[0])
def run_all_tests(): def run_all_tests():
print("--------------------------------") print_title("TESTS")
print(" TESTS ")
print("--------------------------------")
for path in test_files:
run_file(path)
def run_file(path): FMT_PATH = "%-25s"
INDENTATION = ' | '
for path in test_files:
print(FMT_PATH % path, end='') print(FMT_PATH % path, end='')
result = run_command(['pocket', path]) result = run_command(['pocket', path])
if result.returncode != 0: if result.returncode != 0:
@ -71,6 +78,10 @@ def run_command(command):
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.PIPE) stderr=subprocess.PIPE)
def print_title(title):
print("--------------------------------")
print(" %s " % title)
print("--------------------------------")
run_all_tests() if __name__ == '__main__':
run_all_benchmarks() main()