Merge pull request #38 from ThakeeNathees/more-docs

more comments written through out the source
This commit is contained in:
Thakee Nathees 2021-06-03 07:44:03 +05:30
commit 6ee8226a50
19 changed files with 293 additions and 134 deletions

View File

@ -5,9 +5,10 @@
**Pocketlang** is a small (~3000 semicollons) and fast functional programming
language written in C. It's syntactically similar to Ruby and it can be learned
in less than an hour. Including the compiler, bytecode VM and runtime, it's a
standalone executable with zero external dependecies just as it's self descriptive
name. The pocketlang VM can be embedded in another hosting program very easily.
in [less than an hour](https://thakeenathees.github.io/pocketlang/getting-started-learn-in-5-minutes.html).
Including the compiler, bytecode VM and runtime, it's a standalone executable
with zero external dependecies just as it's self descriptive name. The pocketlang
VM can be embedded in another hosting program very easily.
The language is written using [Wren Language](https://wren.io/) and their
wonderful book [craftinginterpreters](http://www.craftinginterpreters.com/) as

View File

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

View File

@ -4,7 +4,7 @@
*/
// 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
// 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 = 'home.md'
TRY_PAGE = 'try it now.html'
TRY_PAGE = 'try-it-now.html'
SOURCE_DIR = 'pages/'
TARGET_DIR = 'build/'
STATIC_DIR = 'static/'
@ -36,14 +36,16 @@ WASM_SOURCE_FILES = '''\
'''
## Navigation pages in order. Should match the path names.
## Any file/folder name shouldn't contain white space.
PAGES = [
('Getting Started', [
('Getting-Started', [
TRY_PAGE,
'build from source.md',
'learn-in-5-minutes.md',
'build-from-source.md',
'contributing.md',
]),
('Language API', [
('Language-API', [
'variables.md',
'functions.md',
'modules.md',
@ -85,15 +87,17 @@ def main():
ctx = generate_page_context(join(SOURCE_DIR, HOME_PAGE), index_html, navigation)
write_page(ctx, template, index_html)
for entry in PAGES:
for entry in PAGES: ## entry = ('dirname', [files...])
_dir = entry[0]
for file in entry[1]:
ext = get_validated_ext(file)
path = join(SOURCE_DIR, _dir, file)
dst = ''
if ext == '.md' : dst = join(TARGET_DIR, _dir, file.replace('.md', '.html'))
else: dst = join(TARGET_DIR, _dir, file)
dst = ''; path_prefix = _dir.lower().replace(' ', '-') + '-'
if ext == '.md':
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)
_template = template
@ -108,22 +112,27 @@ def generate_navigation():
for entry in PAGES:
_dir = entry[0]
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'
for file in entry[1]:
ext = get_validated_ext(file)
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('\\', '/')
title = file.replace(ext, '')
title = file.replace(ext, '').replace('-', ' ').title()
navigation += '<li><a href="%s">%s</a></li>\n' % (link, title)
navigation += '</ul>\n'
navigation += '</div>\n'
return navigation
@ -155,6 +164,9 @@ def path_to_title(path):
## Return the static dir relative path.
def relative_static_dir(dst):
return STATIC_DIR ## No more relative paths.
_dir = os.path.dirname(dst)
static_dir = os.path.relpath(join(TARGET_DIR, STATIC_DIR), _dir)
static_dir = static_dir.replace('\\', '/')
@ -203,7 +215,6 @@ def custom_html_override(src, content):
'<span class="n">%s</span>' % nk)
## codehilite mark the compilation command as error.
if 'build from source' in src:
content = content.replace('<span class="err">', '<span>')
return content
@ -227,8 +238,10 @@ if __name__ == '__main__':
_local = False
if len(sys.argv) >= 2:
if sys.argv[1] == 'local':
ROOT_URL = 'http://localhost:8000/'
_local = True
#ROOT_URL = 'http://localhost:8000/'
ROOT_URL = '' ## No more nested directory pages.
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 *
*****************************************************************************/
// Internal error report function of the parseError() function.
static void reportError(Compiler* compiler, const char* file, int line,
const char* fmt, va_list args) {
PKVM* vm = compiler->vm;

View File

@ -17,16 +17,22 @@
/* 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 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) {
Script* module = newModuleInternal(vm, name);
return vmNewHandle(vm, VAR_OBJ(&module->_super));
}
// pkModuleAddFunction implementation (see pocketlang.h for description).
void pkModuleAddFunction(PKVM* vm, PkHandle* module, const char* name,
pkNativeFn fptr, int arity) {
__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);
}
// 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]
// Convinent macros.
// Convinent macros to get the 1st, 2nd, 3rd arguments.
#define ARG1 ARG(1)
#define ARG2 ARG(2)
#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)
// Set return value and return.
// Set return value for the current native function and return.
#define RET(value) \
do { \
*(vm->fiber->ret) = value; \
@ -63,6 +69,7 @@ void pkModuleAddFunction(PKVM* vm, PkHandle* module, const char* name,
__ASSERT(value != NULL, "Parameter [value] was NULL."); \
((void*)0)
// Set error for incompatible type provided as an argument.
#define ERR_INVALID_ARG_TYPE(m_type) \
do { \
char buff[STR_INT_BUFF_SIZE]; \
@ -71,11 +78,13 @@ do { \
" at argument $.", buff); \
} while (false)
// pkGetArgc implementation (see pocketlang.h for description).
int pkGetArgc(PKVM* vm) {
__ASSERT(vm->fiber != NULL, "This function can only be called at runtime.");
return ARGC;
}
// pkGetArg implementation (see pocketlang.h for description).
PkVar pkGetArg(PKVM* vm, int arg) {
__ASSERT(vm->fiber != NULL, "This function can only be called at runtime.");
__ASSERT(arg > 0 || arg <= ARGC, "Invalid argument index.");
@ -83,6 +92,7 @@ PkVar pkGetArg(PKVM* vm, int arg) {
return &(ARG(arg));
}
// pkGetArgBool implementation (see pocketlang.h for description).
bool pkGetArgBool(PKVM* vm, int arg, bool* value) {
CHECK_GET_ARG_API_ERRORS();
@ -91,6 +101,7 @@ bool pkGetArgBool(PKVM* vm, int arg, bool* value) {
return true;
}
// pkGetArgNumber implementation (see pocketlang.h for description).
bool pkGetArgNumber(PKVM* vm, int arg, double* value) {
CHECK_GET_ARG_API_ERRORS();
@ -109,6 +120,7 @@ bool pkGetArgNumber(PKVM* vm, int arg, double* value) {
return true;
}
// pkGetArgString implementation (see pocketlang.h for description).
bool pkGetArgString(PKVM* vm, int arg, const char** value) {
CHECK_GET_ARG_API_ERRORS();
@ -124,6 +136,7 @@ bool pkGetArgString(PKVM* vm, int arg, const char** value) {
return true;
}
// pkGetArgValue implementation (see pocketlang.h for description).
bool pkGetArgValue(PKVM* vm, int arg, PkVarType type, PkVar* value) {
CHECK_GET_ARG_API_ERRORS();
@ -139,54 +152,36 @@ bool pkGetArgValue(PKVM* vm, int arg, PkVarType type, PkVar* value) {
return true;
}
// pkReturnNull implementation (see pocketlang.h for description).
void pkReturnNull(PKVM* vm) {
RET(VAR_NULL);
}
// pkReturnBool implementation (see pocketlang.h for description).
void pkReturnBool(PKVM* vm, bool value) {
RET(VAR_BOOL(value));
}
// pkReturnNumber implementation (see pocketlang.h for description).
void pkReturnNumber(PKVM* vm, double value) {
RET(VAR_NUM(value));
}
// pkReturnString implementation (see pocketlang.h for description).
void pkReturnString(PKVM* vm, const char* value) {
RET(VAR_OBJ(&newString(vm, value)->_super));
}
// pkReturnStringLength implementation (see pocketlang.h for description).
void pkReturnStringLength(PKVM* vm, const char* value, size_t length) {
RET(VAR_OBJ(&newStringLength(vm, value, (uint32_t)length)->_super));
}
// pkReturnValue implementation (see pocketlang.h for description).
void pkReturnValue(PKVM* vm, PkVar 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 */
/*****************************************************************************/
@ -259,16 +254,30 @@ static inline bool validateIndex(PKVM* vm, int32_t index, int32_t size,
/* 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) {
ASSERT_INDEX(index, vm->builtins_count);
return vm->builtins[index].fn;
}
// getBuiltinFunctionName implementation (see core.h for description).
const char* getBuiltinFunctionName(PKVM* vm, int index) {
ASSERT_INDEX(index, vm->builtins_count);
return vm->builtins[index].name;
}
// getCoreLib implementation (see core.h for description).
Script* getCoreLib(PKVM* vm, String* name) {
Var lib = mapGet(vm->core_libs, VAR_OBJ(&name->_super));
if (IS_UNDEF(lib)) return NULL;
@ -309,16 +318,14 @@ FN_IS_OBJ_TYPE(UserObj, OBJ_USER)
PK_DOC(coreTypeName,
"type_name(value:var) -> string\n"
"Returns the type name of the of the value.");
void coreTypeName(PKVM* vm) {
"Returns the type name of the of the value.") {
RET(VAR_OBJ(&newString(vm, varTypeName(ARG1))->_super));
}
PK_DOC(coreAssert,
"assert(condition:bool [, msg:string]) -> void\n"
"If the condition is false it'll terminate the current fiber with the "
"optional error message");
void coreAssert(PKVM* vm) {
"optional error message") {
int argc = ARGC;
if (argc != 1 && argc != 2) {
vm->fiber->error = newString(vm, "Invalid argument count.");
@ -345,16 +352,14 @@ void coreAssert(PKVM* vm) {
PK_DOC(coreToString,
"to_string(value:var) -> string\n"
"Returns the string representation of the value.");
void coreToString(PKVM* vm) {
"Returns the string representation of the value.") {
RET(VAR_OBJ(&toString(vm, ARG1)->_super));
}
PK_DOC(corePrint,
"print(...) -> void\n"
"Write each argument as comma seperated to the stdout and ends with a "
"newline.");
void corePrint(PKVM* vm) {
"newline.") {
// If the host appliaction donesn't provide any write function, discard the
// output.
if (vm->config.write_fn == NULL) return;
@ -379,8 +384,9 @@ void corePrint(PKVM* vm) {
// String functions.
// -----------------
void coreStrLower(PKVM* vm) {
PK_DOC(coreStrLower,
"str_lower(value:string) -> string\n"
"Returns a lower-case version of the given string.") {
String* str;
if (!validateArgString(vm, 1, &str)) return;
@ -393,7 +399,9 @@ void coreStrLower(PKVM* vm) {
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;
if (!validateArgString(vm, 1, &str)) return;
@ -406,7 +414,10 @@ void coreStrUpper(PKVM* vm) {
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;
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));
}
// Returns the ASCII string value of the integer argument.
void coreStrChr(PKVM* vm) {
PK_DOC(coreStrChr,
"str_chr(value:number) -> string\n"
"Returns the ASCII string value of the integer argument.") {
int32_t num;
if (!validateInteger(vm, ARG1, &num, "Argument 1"));
if (!validateInteger(vm, ARG1, &num, "Argument 1")) return;
char c = (char)num;
RET(VAR_OBJ(&newStringLength(vm, &c, 1)->_super));
}
// Returns integer value of the given ASCII character.
void coreStrOrd(PKVM* vm) {
PK_DOC(coreStrOrd,
"str_ord(value:string) -> number\n"
"Returns integer value of the given ASCII character.") {
String* c;
if (!validateArgString(vm, 1, &c));
if (!validateArgString(vm, 1, &c)) return;
if (c->length != 1) {
vm->fiber->error = newString(vm, "Expected a string of length 1.");
RET(VAR_NULL);
@ -442,10 +455,12 @@ void coreStrOrd(PKVM* vm) {
}
// 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;
if (!validateArgList(vm, 1, &list)) return;
Var elem = ARG(2);
@ -457,13 +472,15 @@ void coreListAppend(PKVM* vm) {
// 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;
if (!validateArgMap(vm, 1, &map)) return;
Var key = ARG(2);
mapRemoveKey(vm, map, key);
RET(VAR_OBJ(&map->_super));
RET(mapRemoveKey(vm, map, key));
}
/*****************************************************************************/
@ -497,8 +514,10 @@ static Script* newModuleInternal(PKVM* vm, const char* name) {
return scr;
}
// An internal function to add a function to the given [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.
if (scriptSearchFunc(script, name, (uint32_t)strlen(name)) != -1) {
@ -624,6 +643,17 @@ void stdMathHash(PKVM* vm) {
/*****************************************************************************/
/* 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) {
#define INITALIZE_BUILTIN_FN(name, fn, argc) \
@ -817,6 +847,7 @@ bool varLesser(Var v1, Var v2) {
#define IS_ATTRIB(name) \
(attrib->length == strlen(name) && strcmp(name, attrib->data) == 0)
// Set error for accessing non-existed attribute.
#define ERR_NO_ATTRIB() \
vm->fiber->error = stringFormat(vm, "'$' objects has no attribute " \
"named '$'", \

View File

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

View File

@ -57,10 +57,13 @@ extern "C" {
// A convinent macro to define documentation of funcions. Use it to document
// your native functions.
//
// PK_DOC(foo, "The function will print 'foo' on the console.");
// void foo(PKVM* vm) { printf("foo\n"); }
// PK_DOC(foo,
// "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 */

View File

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

View File

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

View File

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

View File

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