mirror of
https://github.com/zekexiao/pocketlang.git
synced 2025-02-11 07:00:58 +08:00
Merge pull request #33 from ThakeeNathees/build-docs
build docs implemented
This commit is contained in:
commit
c035abf0dd
@ -9,14 +9,12 @@ SOURCES = ../cli/*.c ../src/*.c
|
||||
|
||||
all: debug
|
||||
|
||||
init:
|
||||
debug:
|
||||
@mkdir -p debug/
|
||||
@mkdir -p release/
|
||||
|
||||
debug: init
|
||||
$(CC) -o debug/pocket $(SOURCES) $(INCLUDE_DIR) $(CFLAGS) -D DEBUG -g3 -Og
|
||||
|
||||
release: init
|
||||
release:
|
||||
@mkdir -p release/
|
||||
$(CC) -o release/pocket $(SOURCES) $(INCLUDE_DIR) $(CFLAGS) -g -O3
|
||||
|
||||
clean:
|
||||
|
@ -1,13 +0,0 @@
|
||||
|
||||
:: A convinent batch script to compile wasm
|
||||
:: generate pages and run the local server.
|
||||
|
||||
cd try
|
||||
call emsdk_env
|
||||
python compile.py
|
||||
|
||||
cd ..
|
||||
python generate.py local
|
||||
|
||||
cd build
|
||||
server
|
@ -176,6 +176,14 @@ def path_to_content(src):
|
||||
|
||||
content = markdown(text, extensions=['codehilite', 'fenced_code'])
|
||||
|
||||
## A wakey way to inject html overrides to highlight out language
|
||||
## I'm not focusing on generating the pages and this is a wakey way to
|
||||
## do so. This should be done with a good static page generater instead
|
||||
## of this script.
|
||||
return custom_html_override(src, content)
|
||||
|
||||
## Inject our custom html overrides.
|
||||
def custom_html_override(src, content):
|
||||
## FIXME: I should create a pygment lexer.
|
||||
## A dirty way to inject our keyword (to ruby's).
|
||||
addnl_keywords = [
|
||||
@ -193,6 +201,11 @@ def path_to_content(src):
|
||||
for nk in not_keyword:
|
||||
content = content.replace('<span class="k">%s</span>' % nk,
|
||||
'<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
|
||||
|
||||
def write_page(ctx, template, dst):
|
||||
|
@ -1,10 +1,45 @@
|
||||
|
||||
#Build From Source
|
||||
# Build From Source
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
||||
## Without a build script
|
||||
|
||||
## Platform 1
|
||||
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
||||
Pocketlang has zero dependencies and you don't even require a build system, just a c99 compiler is enought, and it can be compiled with the following command.
|
||||
|
||||
## Platform 2
|
||||
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
||||
Using gcc
|
||||
```
|
||||
gcc -o pocket cli/*.c src/*.c -Isrc/include -lm
|
||||
```
|
||||
|
||||
Using MSVC
|
||||
```
|
||||
cl /Fepocket cli/*.c src/*.c /Isrc/include && rm *.obj
|
||||
```
|
||||
|
||||
For other compilers it's the same (If you weren't able to compile it with any c99 compatible compiler, please report by [opening an issue](https://github.com/ThakeeNathees/pocketlang/issues/new)). And add ` -Wno-int-to-pointer-cast` for gcc to suppress those warnings emitted when nan-tagging is enabled.
|
||||
|
||||
## Using a build script
|
||||
|
||||
You could find some of the build script for different build system in the `build/` direcroty. If you don't find a scirpt for your prifered system, request on github by [opening an issue](https://github.com/ThakeeNathees/pocketlang/issues/new) or feel free to contribute one.
|
||||
|
||||
## Makefile
|
||||
|
||||
```
|
||||
cd build && make
|
||||
```
|
||||
|
||||
## Batch script with MSVC
|
||||
|
||||
```
|
||||
cd build && build
|
||||
```
|
||||
You don't require to run the script from a Visual Studio .NET Command Prompt, It'll search for the MSVS installation path and use it to compile. But if it can't, try running on VS command prompt.
|
||||
|
||||
## SCons
|
||||
|
||||
pocketlang mainly focused on [scons](https://www.scons.org/), and it's recommended to use it for contributions since it has various configurations and compiler support. It's a python based build system. You need to have python 3.6+ installed in your development environment. To install scons run `python3 -m pip install scons`. Make sure it's version is 3.0+ and for Visual Studio 2019 it require v3.1.1+. In Linux if scons using python2 instead of 3 you'll have to edit `/usr/local/bin/scons` or `~/.local/bin/scons` to ensure that it points to `/usr/bin/env python3` and not `python`
|
||||
|
||||
```
|
||||
cd build && scons
|
||||
```
|
||||
|
||||
You can specify the number of jobs scons to use to speed up the building process using the -j flag (-j6, -j8). To generate Visual Studio project files add `vsproj=true` argument when building. To compile using mingw in windows use `use_mingw=true` argument. If your build failed feel free to [open an issue](https://github.com/ThakeeNathees/pocketlang/issues/new).
|
||||
|
2
docs/static/main.css
vendored
2
docs/static/main.css
vendored
@ -40,7 +40,7 @@
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 980px;
|
||||
max-width: 1080px;
|
||||
margin: 0 auto;
|
||||
text-align: left;
|
||||
}
|
||||
|
111
src/vm.c
111
src/vm.c
@ -33,31 +33,13 @@
|
||||
// allocated so far plus the fill factor of it.
|
||||
#define HEAP_FILL_PERCENT 75
|
||||
|
||||
/*****************************************************************************/
|
||||
/* VM PUBLIC API */
|
||||
/*****************************************************************************/
|
||||
|
||||
// The default allocator that will be used to initialize the vm's configuration
|
||||
// if the host doesn't provided any allocators for us.
|
||||
static forceinline void* defaultRealloc(void* memory, size_t new_size, void* user_data) {
|
||||
if (new_size == 0) {
|
||||
free(memory);
|
||||
return NULL;
|
||||
}
|
||||
return realloc(memory, new_size);
|
||||
}
|
||||
|
||||
void* vmRealloc(PKVM* self, void* memory, size_t old_size, size_t new_size) {
|
||||
|
||||
// TODO: Debug trace allocations here.
|
||||
|
||||
// Track the total allocated memory of the VM to trigger the GC.
|
||||
// if vmRealloc is called for freeing, the old_size would be 0 since
|
||||
// deallocated bytes are traced by garbage collector.
|
||||
self->bytes_allocated += new_size - old_size;
|
||||
|
||||
if (new_size > 0 && self->bytes_allocated > self->next_gc) {
|
||||
vmCollectGarbage(self);
|
||||
}
|
||||
|
||||
return self->config.realloc_fn(memory, new_size, self->config.user_data);
|
||||
}
|
||||
static void* defaultRealloc(void* memory, size_t new_size, void* user_data);
|
||||
|
||||
pkConfiguration pkNewConfiguration() {
|
||||
pkConfiguration config;
|
||||
@ -118,6 +100,14 @@ void pkFreeVM(PKVM* self) {
|
||||
DEALLOCATE(self, self);
|
||||
}
|
||||
|
||||
void* pkGetUserData(PKVM* vm) {
|
||||
return vm->config.user_data;
|
||||
}
|
||||
|
||||
void pkSetUserData(PKVM* vm, void* user_data) {
|
||||
vm->config.user_data = user_data;
|
||||
}
|
||||
|
||||
PkHandle* pkNewHandle(PKVM* vm, PkVar value) {
|
||||
return vmNewHandle(vm, *((Var*)value));
|
||||
}
|
||||
@ -142,10 +132,6 @@ void pkReleaseHandle(PKVM* vm, PkHandle* handle) {
|
||||
DEALLOCATE(vm, handle);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* VM INTERNALS */
|
||||
/*****************************************************************************/
|
||||
|
||||
PkHandle* vmNewHandle(PKVM* self, Var value) {
|
||||
PkHandle* handle = (PkHandle*)ALLOCATE(self, PkHandle);
|
||||
handle->value = value;
|
||||
@ -156,6 +142,35 @@ PkHandle* vmNewHandle(PKVM* self, Var value) {
|
||||
return handle;
|
||||
}
|
||||
|
||||
|
||||
void* vmRealloc(PKVM* self, void* memory, size_t old_size, size_t new_size) {
|
||||
|
||||
// TODO: Debug trace allocations here.
|
||||
|
||||
// Track the total allocated memory of the VM to trigger the GC.
|
||||
// if vmRealloc is called for freeing, the old_size would be 0 since
|
||||
// deallocated bytes are traced by garbage collector.
|
||||
self->bytes_allocated += new_size - old_size;
|
||||
|
||||
if (new_size > 0 && self->bytes_allocated > self->next_gc) {
|
||||
vmCollectGarbage(self);
|
||||
}
|
||||
|
||||
return self->config.realloc_fn(memory, new_size, self->config.user_data);
|
||||
}
|
||||
|
||||
void vmPushTempRef(PKVM* self, Object* obj) {
|
||||
ASSERT(obj != NULL, "Cannot reference to NULL.");
|
||||
ASSERT(self->temp_reference_count < MAX_TEMP_REFERENCE,
|
||||
"Too many temp references");
|
||||
self->temp_reference[self->temp_reference_count++] = obj;
|
||||
}
|
||||
|
||||
void vmPopTempRef(PKVM* self) {
|
||||
ASSERT(self->temp_reference_count > 0, "Temporary reference is empty to pop.");
|
||||
self->temp_reference_count--;
|
||||
}
|
||||
|
||||
void vmCollectGarbage(PKVM* self) {
|
||||
|
||||
// Reset VM's bytes_allocated value and count it again so that we don't
|
||||
@ -194,7 +209,7 @@ void vmCollectGarbage(PKVM* self) {
|
||||
if (self->fiber != NULL) {
|
||||
grayObject(self, &self->fiber->_super);
|
||||
}
|
||||
|
||||
|
||||
blackenObjects(self);
|
||||
|
||||
// Now sweep all the un-marked objects in then link list and remove them
|
||||
@ -222,34 +237,36 @@ void vmCollectGarbage(PKVM* self) {
|
||||
// Next GC heap size will be change depends on the byte we've left with now,
|
||||
// and the [heap_fill_percent].
|
||||
self->next_gc = self->bytes_allocated + (
|
||||
(self->bytes_allocated * self->heap_fill_percent) / 100);
|
||||
(self->bytes_allocated * self->heap_fill_percent) / 100);
|
||||
if (self->next_gc < self->min_heap_size) self->next_gc = self->min_heap_size;
|
||||
}
|
||||
|
||||
void* pkGetUserData(PKVM* vm) {
|
||||
return vm->config.user_data;
|
||||
/*****************************************************************************/
|
||||
/* VM INTERNALS */
|
||||
/*****************************************************************************/
|
||||
|
||||
// The default allocator that will be used to initialize the vm's configuration
|
||||
// if the host doesn't provided any allocators for us.
|
||||
static void* defaultRealloc(void* memory, size_t new_size, void* user_data) {
|
||||
if (new_size == 0) {
|
||||
free(memory);
|
||||
return NULL;
|
||||
}
|
||||
return realloc(memory, new_size);
|
||||
}
|
||||
|
||||
void pkSetUserData(PKVM* vm, void* user_data) {
|
||||
vm->config.user_data = user_data;
|
||||
}
|
||||
|
||||
static forceinline Script* getScript(PKVM* vm, String* path) {
|
||||
static inline Script* getScript(PKVM* vm, String* path) {
|
||||
Var scr = mapGet(vm->scripts, VAR_OBJ(&path->_super));
|
||||
if (IS_UNDEF(scr)) return NULL;
|
||||
ASSERT(AS_OBJ(scr)->type == OBJ_SCRIPT, OOPS);
|
||||
return (Script*)AS_OBJ(scr);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* RUNTIME *
|
||||
*****************************************************************************/
|
||||
|
||||
// If failed to resolve it'll return false. Parameter [result] should be points
|
||||
// to the string which is the path that has to be resolved and once it resolved
|
||||
// the provided result's string's on_done() will be called and, it's string will
|
||||
// be updated with the new resolved path string.
|
||||
static forceinline bool resolveScriptPath(PKVM* vm, pkStringPtr* path_string) {
|
||||
static inline bool resolveScriptPath(PKVM* vm, pkStringPtr* path_string) {
|
||||
if (vm->config.resolve_path_fn == NULL) return true;
|
||||
|
||||
const char* path = path_string->string;
|
||||
@ -274,7 +291,7 @@ static forceinline bool resolveScriptPath(PKVM* vm, pkStringPtr* path_string) {
|
||||
// Import and return Script object as Var. If the script is imported and
|
||||
// compiled here it'll set [is_new_script] to true oterwise (using the cached
|
||||
// script) set to false.
|
||||
static forceinline Var importScript(PKVM* vm, String* path_name) {
|
||||
static inline Var importScript(PKVM* vm, String* path_name) {
|
||||
|
||||
// Check in the core libs.
|
||||
Script* scr = getCoreLib(vm, path_name);
|
||||
@ -293,7 +310,7 @@ static forceinline Var importScript(PKVM* vm, String* path_name) {
|
||||
return VAR_NULL;
|
||||
}
|
||||
|
||||
static forceinline void growStack(PKVM* vm, int size) {
|
||||
static inline void growStack(PKVM* vm, int size) {
|
||||
Fiber* fiber = vm->fiber;
|
||||
ASSERT(fiber->stack_size <= size, OOPS);
|
||||
int new_size = utilPowerOf2Ceil(size);
|
||||
@ -338,7 +355,7 @@ static forceinline void growStack(PKVM* vm, int size) {
|
||||
}
|
||||
}
|
||||
|
||||
static forceinline void pushCallFrame(PKVM* vm, Function* fn) {
|
||||
static inline void pushCallFrame(PKVM* vm, Function* fn) {
|
||||
ASSERT(!fn->is_native, "Native function shouldn't use call frames.");
|
||||
|
||||
/* Grow the stack frame if needed. */
|
||||
@ -385,7 +402,7 @@ void vmReportError(PKVM* vm) {
|
||||
|
||||
// This function is responsible to call on_done function if it's done with the
|
||||
// provided string pointers.
|
||||
static forceinline PkInterpretResult interpretSource(PKVM* vm, pkStringPtr source,
|
||||
static inline PkInterpretResult interpretSource(PKVM* vm, pkStringPtr source,
|
||||
pkStringPtr path) {
|
||||
String* path_name = newString(vm, path.string);
|
||||
if (path.on_done) path.on_done(vm, path);
|
||||
@ -449,6 +466,10 @@ PkInterpretResult pkInterpret(PKVM* vm, const char* path) {
|
||||
return interpretSource(vm, source, resolved);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* RUNTIME *
|
||||
*****************************************************************************/
|
||||
|
||||
PkInterpretResult vmRunScript(PKVM* vm, Script* _script) {
|
||||
|
||||
// Reference to the instruction pointer in the call frame.
|
||||
|
20
src/vm.h
20
src/vm.h
@ -103,20 +103,6 @@ struct PKVM {
|
||||
Fiber* fiber;
|
||||
};
|
||||
|
||||
// Push the object to temporary references stack.
|
||||
forceinline void vmPushTempRef(PKVM* self, Object* obj) {
|
||||
ASSERT(obj != NULL, "Cannot reference to NULL.");
|
||||
ASSERT(self->temp_reference_count < MAX_TEMP_REFERENCE,
|
||||
"Too many temp references");
|
||||
self->temp_reference[self->temp_reference_count++] = obj;
|
||||
}
|
||||
|
||||
// Pop the top most object from temporary reference stack.
|
||||
forceinline void vmPopTempRef(PKVM* self) {
|
||||
ASSERT(self->temp_reference_count > 0, "Temporary reference is empty to pop.");
|
||||
self->temp_reference_count--;
|
||||
}
|
||||
|
||||
// A realloc wrapper which handles memory allocations of the VM.
|
||||
// - To allocate new memory pass NULL to parameter [memory] and 0 to
|
||||
// parameter [old_size] on failure it'll return NULL.
|
||||
@ -134,6 +120,12 @@ PkHandle* vmNewHandle(PKVM* self, Var value);
|
||||
// Trigger garbage collection manually.
|
||||
void vmCollectGarbage(PKVM* self);
|
||||
|
||||
// Push the object to temporary references stack.
|
||||
void vmPushTempRef(PKVM* self, Object* obj);
|
||||
|
||||
// Pop the top most object from temporary reference stack.
|
||||
void vmPopTempRef(PKVM* self);
|
||||
|
||||
// Runs the script and return result.
|
||||
PkInterpretResult vmRunScript(PKVM* vm, Script* script);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user