mirror of
https://github.com/zekexiao/pocketlang.git
synced 2025-02-11 07:00:58 +08:00
Merge pull request #42 from ThakeeNathees/fiber-docs
fiber documentations
This commit is contained in:
commit
3092118008
@ -9,6 +9,7 @@
|
|||||||
- In keyword.
|
- In keyword.
|
||||||
- Structs (maybe enums).
|
- Structs (maybe enums).
|
||||||
- Implement file IO (require structs).
|
- Implement file IO (require structs).
|
||||||
|
- Implement utf8 support.
|
||||||
- Implement gdb like debugger (add color print for readability).
|
- Implement gdb like debugger (add color print for readability).
|
||||||
- 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.
|
||||||
|
@ -23,7 +23,6 @@ true; false # Booleans.
|
|||||||
[42, 'foo', null] # Lists.
|
[42, 'foo', null] # Lists.
|
||||||
{ 'Key':'value' } # Maps.
|
{ 'Key':'value' } # Maps.
|
||||||
func(x) return x*x end # Lambda/literal functions.
|
func(x) return x*x end # Lambda/literal functions.
|
||||||
import lang # Module (imported scripts).
|
|
||||||
|
|
||||||
# Control flow.
|
# Control flow.
|
||||||
# -------------
|
# -------------
|
||||||
@ -71,9 +70,20 @@ end
|
|||||||
|
|
||||||
# Concanative call operator '->'
|
# Concanative call operator '->'
|
||||||
|
|
||||||
str_lower(str_strip('FOO ')) # This can be written as below
|
str_lower(str_strip('Foo ')) # This can be written as below
|
||||||
'FOO ' -> str_strip -> str_lower
|
'Foo ' -> str_strip -> str_lower
|
||||||
|
|
||||||
'foo' -> print # similer as print('foo')
|
'foo' -> print # similer as print('foo')
|
||||||
|
|
||||||
```
|
# Fibers & Coroutine
|
||||||
|
#-------------------
|
||||||
|
|
||||||
|
def fn(p1, p2)
|
||||||
|
print(yield(42)) # Prints 3.14
|
||||||
|
end
|
||||||
|
|
||||||
|
fb = fiber_new(fn)
|
||||||
|
val = fiber_run(fb, 1, 2)
|
||||||
|
print(val) ## Prints 42
|
||||||
|
fiber_resume(fb, 3.14)
|
||||||
|
```
|
||||||
|
@ -1,4 +1,88 @@
|
|||||||
|
|
||||||
# %% Fibers %%
|
# %% Fibers %%
|
||||||
|
|
||||||
TODO
|
Pocketlang support coroutines via [fibers](https://en.wikipedia.org/wiki/Fiber_(computer_science))
|
||||||
|
(light weight threads with cooperative multitask). A fiber object is a wrapper
|
||||||
|
around a function, contains the execution state (simply the stack and the
|
||||||
|
instruction pointer) for that function, which can be run and once yielded
|
||||||
|
resumed.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
def fn(h, w)
|
||||||
|
print(h, w)
|
||||||
|
end
|
||||||
|
|
||||||
|
fb = fiber_new(fn) # Create a fiber.
|
||||||
|
fiber_run(fb, 'hello', 'world') # Run the fiber.
|
||||||
|
```
|
||||||
|
|
||||||
|
## %% Yielding %%
|
||||||
|
|
||||||
|
When a function is yielded, it's state will be stored in the fiber it's
|
||||||
|
belongs to and will return from the function, to parent fiber it's running
|
||||||
|
from (not the caller of the function). And you can pass values between
|
||||||
|
fibers when they yield.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
def fn()
|
||||||
|
print('running')
|
||||||
|
yield()
|
||||||
|
print('resumed')
|
||||||
|
end
|
||||||
|
|
||||||
|
fb = fiber_new(fn)
|
||||||
|
fiber_run(fb) # Prints 'running'.
|
||||||
|
print('before resumed')
|
||||||
|
fiber_resume(fb) # Prints 'resumed'.
|
||||||
|
```
|
||||||
|
|
||||||
|
Yield from the fiber with a value.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
def fn()
|
||||||
|
print('running')
|
||||||
|
yield(42) # Return 42.
|
||||||
|
print('resumed')
|
||||||
|
end
|
||||||
|
|
||||||
|
fb = fiber_new(fn)
|
||||||
|
val = fiber_run(fb) # Prints 'running'.
|
||||||
|
print(val) # Prints 42.
|
||||||
|
fiber_resume(fb) # Prints 'resumed'.
|
||||||
|
```
|
||||||
|
|
||||||
|
Resume the fiber with a value.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
def fn()
|
||||||
|
print('running')
|
||||||
|
val = yield() # Resumed value.
|
||||||
|
print(val) # Prints 42.
|
||||||
|
print('resumed')
|
||||||
|
end
|
||||||
|
|
||||||
|
fb = fiber_new(fn)
|
||||||
|
val = fiber_run(fb) # Prints 'running'.
|
||||||
|
fiber_resume(fb, 42) # Resume with 42, Prints 'resumed'.
|
||||||
|
```
|
||||||
|
|
||||||
|
Once a fiber is done execution, trying to resume it will cause a runtime
|
||||||
|
error. To check if the fiber is finished it's execution use the function
|
||||||
|
`fiber_is_done` and use the function `fiber_get_func` to get it's function,
|
||||||
|
which could be used to create a new fiber to "re-start" the fiber.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
fiber_run(fb = fiber_new(
|
||||||
|
func()
|
||||||
|
for i in 0..5 do
|
||||||
|
yield(i)
|
||||||
|
end
|
||||||
|
end))
|
||||||
|
|
||||||
|
while not fiber_is_done(fb)
|
||||||
|
fiber_resume(fb)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Get the function from the fiber.
|
||||||
|
fn = fiber_get_func(fb)
|
||||||
|
```
|
||||||
|
@ -44,7 +44,10 @@ int runSource(const char* source) {
|
|||||||
config.resolve_path_fn = resolvePath;
|
config.resolve_path_fn = resolvePath;
|
||||||
|
|
||||||
PKVM* vm = pkNewVM(&config);
|
PKVM* vm = pkNewVM(&config);
|
||||||
PkInterpretResult result = pkInterpretSource(vm, source, "@try");
|
|
||||||
|
PkStringPtr src = { source, NULL, NULL };
|
||||||
|
PkStringPtr module = { "@try", NULL, NULL };
|
||||||
|
PkInterpretResult result = pkInterpretSource(vm, src, module);
|
||||||
|
|
||||||
pkFreeVM(vm);
|
pkFreeVM(vm);
|
||||||
|
|
||||||
|
@ -1,68 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2021 Thakee Nathees
|
|
||||||
* Licensed under: MIT License
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "buffers.h"
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
#include "vm.h"
|
|
||||||
|
|
||||||
// The buffer "template" implementation of diferent types, defined in the
|
|
||||||
// buffers.h header.
|
|
||||||
|
|
||||||
#define DEFINE_BUFFER(m_name, m_name_l, m_type) \
|
|
||||||
void m_name_l##BufferInit(m_name##Buffer* self) { \
|
|
||||||
self->data = NULL; \
|
|
||||||
self->count = 0; \
|
|
||||||
self->capacity = 0; \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
void m_name_l##BufferClear(m_name##Buffer* self, \
|
|
||||||
PKVM* vm) { \
|
|
||||||
vmRealloc(vm, self->data, self->capacity * sizeof(m_type), 0); \
|
|
||||||
self->data = NULL; \
|
|
||||||
self->count = 0; \
|
|
||||||
self->capacity = 0; \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
void m_name_l##BufferReserve(m_name##Buffer* self, PKVM* vm, size_t size) { \
|
|
||||||
if (self->capacity < size) { \
|
|
||||||
int capacity = utilPowerOf2Ceil((int)size); \
|
|
||||||
if (capacity < MIN_CAPACITY) capacity = MIN_CAPACITY; \
|
|
||||||
self->data = (m_type*)vmRealloc(vm, self->data, \
|
|
||||||
self->capacity * sizeof(m_type), capacity * sizeof(m_type)); \
|
|
||||||
self->capacity = capacity; \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
void m_name_l##BufferFill(m_name##Buffer* self, PKVM* vm, \
|
|
||||||
m_type data, int count) { \
|
|
||||||
\
|
|
||||||
m_name_l##BufferReserve(self, vm, self->count + count); \
|
|
||||||
\
|
|
||||||
for (int i = 0; i < count; i++) { \
|
|
||||||
self->data[self->count++] = data; \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
void m_name_l##BufferWrite(m_name##Buffer* self, \
|
|
||||||
PKVM* vm, m_type data) { \
|
|
||||||
m_name_l##BufferFill(self, vm, data, 1); \
|
|
||||||
} \
|
|
||||||
|
|
||||||
void byteBufferAddString(ByteBuffer* self, PKVM* vm, const char* str,
|
|
||||||
uint32_t length) {
|
|
||||||
byteBufferReserve(self, vm, self->count + length);
|
|
||||||
for (uint32_t i = 0; i < length; i++) {
|
|
||||||
self->data[self->count++] = *(str++);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DEFINE_BUFFER(Uint, uint, uint32_t)
|
|
||||||
DEFINE_BUFFER(Byte, byte, uint8_t)
|
|
||||||
DEFINE_BUFFER(Var, var, Var)
|
|
||||||
DEFINE_BUFFER(String, string, String*)
|
|
||||||
DEFINE_BUFFER(Function, function, Function*)
|
|
||||||
|
|
||||||
#undef DEFINE_BUFFER
|
|
@ -17,7 +17,6 @@
|
|||||||
// internal data array will be reallocate to a capacity of 'GROW_FACTOR' times
|
// internal data array will be reallocate to a capacity of 'GROW_FACTOR' times
|
||||||
// it's last capacity.
|
// it's last capacity.
|
||||||
|
|
||||||
|
|
||||||
#define DECLARE_BUFFER(m_name, m_name_l, m_type) \
|
#define DECLARE_BUFFER(m_name, m_name_l, m_type) \
|
||||||
typedef struct { \
|
typedef struct { \
|
||||||
m_type* data; \
|
m_type* data; \
|
||||||
@ -44,17 +43,46 @@
|
|||||||
PKVM* vm, m_type data); \
|
PKVM* vm, m_type data); \
|
||||||
|
|
||||||
|
|
||||||
DECLARE_BUFFER(Uint, uint, uint32_t)
|
// The buffer "template" implementation of diferent types.
|
||||||
DECLARE_BUFFER(Byte, byte, uint8_t)
|
|
||||||
DECLARE_BUFFER(Var, var, Var)
|
|
||||||
DECLARE_BUFFER(String, string, String*)
|
|
||||||
DECLARE_BUFFER(Function, function, Function*)
|
|
||||||
|
|
||||||
// Add all the characters to the buffer, byte buffer can also be used as a
|
#define DEFINE_BUFFER(m_name, m_name_l, m_type) \
|
||||||
// buffer to write string (like a string stream).
|
void m_name_l##BufferInit(m_name##Buffer* self) { \
|
||||||
void byteBufferAddString(ByteBuffer* self, PKVM* vm, const char* str,
|
self->data = NULL; \
|
||||||
uint32_t length);
|
self->count = 0; \
|
||||||
|
self->capacity = 0; \
|
||||||
#undef DECLARE_BUFFER
|
} \
|
||||||
|
\
|
||||||
|
void m_name_l##BufferClear(m_name##Buffer* self, \
|
||||||
|
PKVM* vm) { \
|
||||||
|
vmRealloc(vm, self->data, self->capacity * sizeof(m_type), 0); \
|
||||||
|
self->data = NULL; \
|
||||||
|
self->count = 0; \
|
||||||
|
self->capacity = 0; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
void m_name_l##BufferReserve(m_name##Buffer* self, PKVM* vm, size_t size) { \
|
||||||
|
if (self->capacity < size) { \
|
||||||
|
int capacity = utilPowerOf2Ceil((int)size); \
|
||||||
|
if (capacity < MIN_CAPACITY) capacity = MIN_CAPACITY; \
|
||||||
|
self->data = (m_type*)vmRealloc(vm, self->data, \
|
||||||
|
self->capacity * sizeof(m_type), capacity * sizeof(m_type)); \
|
||||||
|
self->capacity = capacity; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
void m_name_l##BufferFill(m_name##Buffer* self, PKVM* vm, \
|
||||||
|
m_type data, int count) { \
|
||||||
|
\
|
||||||
|
m_name_l##BufferReserve(self, vm, self->count + count); \
|
||||||
|
\
|
||||||
|
for (int i = 0; i < count; i++) { \
|
||||||
|
self->data[self->count++] = data; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
void m_name_l##BufferWrite(m_name##Buffer* self, \
|
||||||
|
PKVM* vm, m_type data) { \
|
||||||
|
m_name_l##BufferFill(self, vm, data, 1); \
|
||||||
|
} \
|
||||||
|
|
||||||
#endif // BUFFERS_TEMPLATE_H
|
#endif // BUFFERS_TEMPLATE_H
|
||||||
|
14
src/common.h
14
src/common.h
@ -168,19 +168,5 @@
|
|||||||
/* INTERNAL TYPE DEFINES */
|
/* INTERNAL TYPE DEFINES */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
#if VAR_NAN_TAGGING
|
|
||||||
typedef uint64_t Var;
|
|
||||||
#else
|
|
||||||
typedef struct Var Var;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct Object Object;
|
|
||||||
typedef struct String String;
|
|
||||||
typedef struct List List;
|
|
||||||
typedef struct Map Map;
|
|
||||||
typedef struct Range Range;
|
|
||||||
typedef struct Script Script;
|
|
||||||
typedef struct Function Function;
|
|
||||||
typedef struct Fiber Fiber;
|
|
||||||
|
|
||||||
#endif //PK_COMMON_H
|
#endif //PK_COMMON_H
|
||||||
|
@ -9,6 +9,12 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "var.h"
|
#include "var.h"
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
#define OPCODE(name, _, __) OP_##name,
|
||||||
|
#include "opcodes.h"
|
||||||
|
#undef OPCODE
|
||||||
|
} Opcode;
|
||||||
|
|
||||||
// Pocketlang compiler is a single pass compiler, which means it doesn't go
|
// Pocketlang compiler is a single pass compiler, which means it doesn't go
|
||||||
// throught the basic compilation pipline such as lexing, parsing (AST),
|
// throught the basic compilation pipline such as lexing, parsing (AST),
|
||||||
// analyzing, intermediate codegeneration, and target codegeneration one by one
|
// analyzing, intermediate codegeneration, and target codegeneration one by one
|
||||||
|
34
src/core.c
34
src/core.c
@ -195,20 +195,20 @@ void pkReturnValue(PKVM* vm, PkVar value) {
|
|||||||
|
|
||||||
// Check if a numeric value bool/number and set [value].
|
// Check if 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_BOOL(var)) {
|
|
||||||
*value = AS_BOOL(var);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (IS_NUM(var)) {
|
if (IS_NUM(var)) {
|
||||||
*value = AS_NUM(var);
|
*value = AS_NUM(var);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (IS_BOOL(var)) {
|
||||||
|
*value = AS_BOOL(var);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if [var] is bool/number. If not set error and return false.
|
// Check if [var] is bool/number. If not set error and return false.
|
||||||
static inline bool validateNumeric(PKVM* vm, Var var, double* value,
|
static inline bool validateNumeric(PKVM* vm, Var var, double* value,
|
||||||
const char* name) {
|
const char* name) {
|
||||||
if (isNumeric(var, value)) return true;
|
if (isNumeric(var, value)) return true;
|
||||||
vm->fiber->error = stringFormat(vm, "$ must be a numeric value.", name);
|
vm->fiber->error = stringFormat(vm, "$ must be a numeric value.", name);
|
||||||
return false;
|
return false;
|
||||||
@ -216,7 +216,7 @@ static inline bool validateNumeric(PKVM* vm, Var var, double* value,
|
|||||||
|
|
||||||
// Check if [var] is integer. If not set error and return false.
|
// Check if [var] is integer. If not set error and return false.
|
||||||
static inline bool validateInteger(PKVM* vm, Var var, int32_t* value,
|
static inline bool validateInteger(PKVM* vm, Var var, int32_t* value,
|
||||||
const char* name) {
|
const char* name) {
|
||||||
double number;
|
double number;
|
||||||
if (isNumeric(var, &number)) {
|
if (isNumeric(var, &number)) {
|
||||||
double truncated = floor(number);
|
double truncated = floor(number);
|
||||||
@ -298,19 +298,19 @@ Script* getCoreLib(const PKVM* vm, String* name) {
|
|||||||
/* CORE BUILTIN FUNCTIONS */
|
/* CORE BUILTIN FUNCTIONS */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
#define FN_IS_PRIMITE_TYPE(name, check) \
|
#define FN_IS_PRIMITE_TYPE(name, check) \
|
||||||
void coreIs##name(PKVM* vm) { \
|
void coreIs##name(PKVM* vm) { \
|
||||||
RET(VAR_BOOL(check(ARG1))); \
|
RET(VAR_BOOL(check(ARG1))); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define FN_IS_OBJ_TYPE(name, _enum) \
|
#define FN_IS_OBJ_TYPE(name, _enum) \
|
||||||
void coreIs##name(PKVM* vm) { \
|
void coreIs##name(PKVM* vm) { \
|
||||||
Var arg1 = ARG1; \
|
Var arg1 = ARG1; \
|
||||||
if (IS_OBJ_TYPE(arg1, _enum)) { \
|
if (IS_OBJ_TYPE(arg1, _enum)) { \
|
||||||
RET(VAR_TRUE); \
|
RET(VAR_TRUE); \
|
||||||
} else { \
|
} else { \
|
||||||
RET(VAR_FALSE); \
|
RET(VAR_FALSE); \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
FN_IS_PRIMITE_TYPE(Null, IS_NULL)
|
FN_IS_PRIMITE_TYPE(Null, IS_NULL)
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
#ifndef CORE_H
|
#ifndef CORE_H
|
||||||
#define CORE_H
|
#define CORE_H
|
||||||
|
|
||||||
#include "var.h"
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "var.h"
|
||||||
|
|
||||||
// Initialize core language, builtin function and core libs.
|
// Initialize core language, builtin function and core libs.
|
||||||
void initializeCore(PKVM* vm);
|
void initializeCore(PKVM* vm);
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#define DEBUG_H
|
#define DEBUG_H
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "var.h"
|
||||||
|
|
||||||
// Dump the value of the [value] without a new line at the end.
|
// Dump the value of the [value] without a new line at the end.
|
||||||
void dumpValue(PKVM* vm, Var value);
|
void dumpValue(PKVM* vm, Var value);
|
||||||
|
19
src/var.c
19
src/var.c
@ -75,6 +75,21 @@ const char* pkStringGetData(const PkVar value) {
|
|||||||
// capacity by the GROW_FACTOR.
|
// capacity by the GROW_FACTOR.
|
||||||
#define GROW_FACTOR 2
|
#define GROW_FACTOR 2
|
||||||
|
|
||||||
|
// Buffer implementations.
|
||||||
|
DEFINE_BUFFER(Uint, uint, uint32_t)
|
||||||
|
DEFINE_BUFFER(Byte, byte, uint8_t)
|
||||||
|
DEFINE_BUFFER(Var, var, Var)
|
||||||
|
DEFINE_BUFFER(String, string, String*)
|
||||||
|
DEFINE_BUFFER(Function, function, Function*)
|
||||||
|
|
||||||
|
void byteBufferAddString(ByteBuffer* self, PKVM* vm, const char* str,
|
||||||
|
uint32_t length) {
|
||||||
|
byteBufferReserve(self, vm, self->count + length);
|
||||||
|
for (uint32_t i = 0; i < length; i++) {
|
||||||
|
self->data[self->count++] = *(str++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void varInitObject(Object* self, PKVM* vm, ObjectType type) {
|
void varInitObject(Object* self, PKVM* vm, ObjectType type) {
|
||||||
self->type = type;
|
self->type = type;
|
||||||
self->is_marked = false;
|
self->is_marked = false;
|
||||||
@ -122,7 +137,6 @@ void grayVarBuffer(PKVM* vm, VarBuffer* self) {
|
|||||||
GRAY_OBJ_BUFFER(String)
|
GRAY_OBJ_BUFFER(String)
|
||||||
GRAY_OBJ_BUFFER(Function)
|
GRAY_OBJ_BUFFER(Function)
|
||||||
|
|
||||||
|
|
||||||
static void blackenObject(Object* obj, PKVM* vm) {
|
static void blackenObject(Object* obj, PKVM* vm) {
|
||||||
// TODO: trace here.
|
// TODO: trace here.
|
||||||
|
|
||||||
@ -1012,7 +1026,8 @@ static void toStringInternal(PKVM* vm, Var v, ByteBuffer* buff,
|
|||||||
case OBJ_FIBER: {
|
case OBJ_FIBER: {
|
||||||
const Fiber* fb = (const Fiber*)obj;
|
const Fiber* fb = (const Fiber*)obj;
|
||||||
byteBufferAddString(buff, vm, "[Fiber:", 7);
|
byteBufferAddString(buff, vm, "[Fiber:", 7);
|
||||||
byteBufferAddString(buff, vm, fb->func->name, strlen(fb->func->name));
|
byteBufferAddString(buff, vm, fb->func->name,
|
||||||
|
(uint32_t)strlen(fb->func->name));
|
||||||
byteBufferWrite(buff, vm, ']');
|
byteBufferWrite(buff, vm, ']');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
41
src/var.h
41
src/var.h
@ -6,6 +6,9 @@
|
|||||||
#ifndef VAR_H
|
#ifndef VAR_H
|
||||||
#define VAR_H
|
#define VAR_H
|
||||||
|
|
||||||
|
#include "buffers.h"
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
/** @file
|
/** @file
|
||||||
* A simple dynamic type system library for small dynamic typed languages using
|
* A simple dynamic type system library for small dynamic typed languages using
|
||||||
* a technique called NaN-tagging (optional). The method is inspired from the
|
* a technique called NaN-tagging (optional). The method is inspired from the
|
||||||
@ -20,9 +23,6 @@
|
|||||||
* programme inefficient for small types such null, bool, int and float.
|
* programme inefficient for small types such null, bool, int and float.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
#include "buffers.h"
|
|
||||||
|
|
||||||
// To use dynamic variably-sized struct with a tail array add an array at the
|
// To use dynamic variably-sized struct with a tail array add an array at the
|
||||||
// end of the struct with size \ref DYNAMIC_TAIL_ARRAY. This method was a
|
// end of the struct with size \ref DYNAMIC_TAIL_ARRAY. This method was a
|
||||||
// legacy standard called "struct hack".
|
// legacy standard called "struct hack".
|
||||||
@ -36,6 +36,14 @@
|
|||||||
// Number of maximum import statements in a script.
|
// Number of maximum import statements in a script.
|
||||||
#define MAX_IMPORT_SCRIPTS 16
|
#define MAX_IMPORT_SCRIPTS 16
|
||||||
|
|
||||||
|
// There are 2 main implemenation of Var's internal representation. First one
|
||||||
|
// is NaN-tagging, and the second one is union-tagging. (read below for more).
|
||||||
|
#if VAR_NAN_TAGGING
|
||||||
|
typedef uint64_t Var;
|
||||||
|
#else
|
||||||
|
typedef struct Var Var;
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The IEEE 754 double precision float bit representation.
|
* The IEEE 754 double precision float bit representation.
|
||||||
*
|
*
|
||||||
@ -160,7 +168,7 @@ typedef enum {
|
|||||||
VAR_OBJECT, //< Base type for all \ref var_Object types.
|
VAR_OBJECT, //< Base type for all \ref var_Object types.
|
||||||
} VarType;
|
} VarType;
|
||||||
|
|
||||||
typedef struct {
|
struct Var {
|
||||||
VarType type;
|
VarType type;
|
||||||
union {
|
union {
|
||||||
bool _bool;
|
bool _bool;
|
||||||
@ -168,10 +176,33 @@ typedef struct {
|
|||||||
double _float;
|
double _float;
|
||||||
Object* _obj;
|
Object* _obj;
|
||||||
};
|
};
|
||||||
} var;
|
};
|
||||||
|
|
||||||
#endif // VAR_NAN_TAGGING
|
#endif // VAR_NAN_TAGGING
|
||||||
|
|
||||||
|
// Type definition of pocketlang heap allocated types.
|
||||||
|
typedef struct Object Object;
|
||||||
|
typedef struct String String;
|
||||||
|
typedef struct List List;
|
||||||
|
typedef struct Map Map;
|
||||||
|
typedef struct Range Range;
|
||||||
|
typedef struct Script Script;
|
||||||
|
typedef struct Function Function;
|
||||||
|
typedef struct Fiber Fiber;
|
||||||
|
|
||||||
|
// Declaration of buffer objects of different types.
|
||||||
|
DECLARE_BUFFER(Uint, uint, uint32_t)
|
||||||
|
DECLARE_BUFFER(Byte, byte, uint8_t)
|
||||||
|
DECLARE_BUFFER(Var, var, Var)
|
||||||
|
DECLARE_BUFFER(String, string, String*)
|
||||||
|
DECLARE_BUFFER(Function, function, Function*)
|
||||||
|
|
||||||
|
// Add all the characters to the buffer, byte buffer can also be used as a
|
||||||
|
// buffer to write string (like a string stream).
|
||||||
|
void byteBufferAddString(ByteBuffer* self, PKVM* vm, const char* str,
|
||||||
|
uint32_t length);
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
OBJ_STRING,
|
OBJ_STRING,
|
||||||
OBJ_LIST,
|
OBJ_LIST,
|
||||||
|
6
src/vm.h
6
src/vm.h
@ -35,12 +35,6 @@
|
|||||||
// allocated so far plus the fill factor of it.
|
// allocated so far plus the fill factor of it.
|
||||||
#define HEAP_FILL_PERCENT 75
|
#define HEAP_FILL_PERCENT 75
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
#define OPCODE(name, _, __) OP_##name,
|
|
||||||
#include "opcodes.h"
|
|
||||||
#undef OPCODE
|
|
||||||
} Opcode;
|
|
||||||
|
|
||||||
// Builtin functions are stored in an array in the VM (unlike script functions
|
// Builtin functions are stored in an array in the VM (unlike script functions
|
||||||
// they're member of function buffer of the script) and this struct is a single
|
// they're member of function buffer of the script) and this struct is a single
|
||||||
// entry of the array.
|
// entry of the array.
|
||||||
|
Loading…
Reference in New Issue
Block a user