mirror of
https://github.com/janet-lang/janet
synced 2024-12-01 04:19:55 +00:00
Huge number of changes. Still WIP. Refactoring and
changing C API model. This commit is not i a working state.
This commit is contained in:
parent
3ccd688438
commit
3efd400025
4
.gitignore
vendored
4
.gitignore
vendored
@ -1,6 +1,6 @@
|
|||||||
# Target
|
# Target
|
||||||
/client/gst
|
/client/dst
|
||||||
gst
|
dst
|
||||||
|
|
||||||
# Generated files
|
# Generated files
|
||||||
*.gen.h
|
*.gen.h
|
||||||
|
86
Makefile
86
Makefile
@ -1,87 +1,81 @@
|
|||||||
# GST
|
# DST
|
||||||
|
|
||||||
######################################################
|
################################
|
||||||
##### Set global variables for all gst Makefiles #####
|
##### Set global variables #####
|
||||||
######################################################
|
################################
|
||||||
|
|
||||||
PREFIX?=/usr/local
|
PREFIX?=/usr/local
|
||||||
BINDIR=$(PREFIX)/bin
|
BINDIR=$(PREFIX)/bin
|
||||||
VERSION=\"0.0.0-beta\"
|
VERSION=\"0.0.0-beta\"
|
||||||
|
|
||||||
CFLAGS=-std=c99 -Wall -Wextra -I./include -I./libs -g -DGST_VERSION=$(VERSION)
|
CFLAGS=-std=c99 -Wall -Wextra -I./include -I./libs -g -DDST_VERSION=$(VERSION)
|
||||||
PREFIX=/usr/local
|
PREFIX=/usr/local
|
||||||
GST_TARGET=gst
|
DST_TARGET=dst
|
||||||
GST_XXD=xxd
|
DST_XXD=xxd
|
||||||
# Use gdb. On mac use lldb
|
# Use gdb. On mac use lldb
|
||||||
DEBUGGER=gdb
|
DEBUGGER=gdb
|
||||||
GST_INTERNAL_HEADERS=$(addprefix core/, cache.h)
|
DST_INTERNAL_HEADERS=$(addprefix core/, internal.h bootstrap.h)
|
||||||
GST_HEADERS=$(addprefix include/gst/, gst.h)
|
DST_HEADERS=$(addprefix include/dst/, dst.h)
|
||||||
|
|
||||||
#############################
|
#############################
|
||||||
##### Generated headers #####
|
##### Generated headers #####
|
||||||
#############################
|
#############################
|
||||||
GST_LANG_SOURCES=$(addprefix libs/, bootstrap.gst)
|
DST_LANG_SOURCES=$(addprefix libs/, bootstrap.dst)
|
||||||
GST_LANG_HEADERS=$(patsubst %.gst,%.gen.h,$(GST_LANG_SOURCES))
|
DST_LANG_HEADERS=$(patsubst %.dst,%.gen.h,$(DST_LANG_SOURCES))
|
||||||
|
|
||||||
all: $(GST_TARGET)
|
all: $(DST_TARGET)
|
||||||
|
|
||||||
#######################
|
#######################
|
||||||
##### Build tools #####
|
##### Build tools #####
|
||||||
#######################
|
#######################
|
||||||
$(GST_XXD): libs/xxd.c
|
$(DST_XXD): libs/xxd.c
|
||||||
$(CC) -o $(GST_XXD) libs/xxd.c
|
$(CC) -o $(DST_XXD) libs/xxd.c
|
||||||
|
|
||||||
%.gen.h : %.gst $(GST_XXD)
|
%.gen.h: %.dst $(DST_XXD)
|
||||||
./$(GST_XXD) $< $@ $(basename $(notdir $<))
|
./$(DST_XXD) $< $@ $(basename $(notdir $<))
|
||||||
|
|
||||||
###################################
|
###################################
|
||||||
##### The core vm and runtime #####
|
##### The core vm and runtime #####
|
||||||
###################################
|
###################################
|
||||||
GST_CORE_SOURCES=$(addprefix core/,\
|
DST_CORE_SOURCES=$(addprefix core/,\
|
||||||
compile.c parse.c stl.c ids.c util.c env.c module.c\
|
util.c wrap.c\
|
||||||
value.c vm.c ds.c gc.c thread.c serialize.c\
|
value.c vm.c ds.c gc.c thread.c serialize.c\
|
||||||
string.c)
|
string.c bootstrap_parse.c client.c)
|
||||||
GST_CORE_OBJECTS=$(patsubst %.c,%.o,$(GST_CORE_SOURCES))
|
DST_CORE_OBJECTS=$(patsubst %.c,%.o,$(DST_CORE_SOURCES))
|
||||||
|
|
||||||
######################
|
$(DST_TARGET): $(DST_CORE_OBJECTS) $(DST_LANG_HEADERS)
|
||||||
##### The client #####
|
$(CC) $(CFLAGS) -o $(DST_TARGET) $(DST_CORE_OBJECTS)
|
||||||
######################
|
|
||||||
GST_CLIENT_SOURCES=client/main.c
|
|
||||||
GST_CLIENT_OBJECTS=$(patsubst %.c,%.o,$(GST_CLIENT_SOURCES))
|
|
||||||
$(GST_TARGET): $(GST_CLIENT_OBJECTS) $(GST_CORE_OBJECTS) $(GST_LANG_HEADERS)
|
|
||||||
$(CC) $(CFLAGS) -o $(GST_TARGET) $(GST_CLIENT_OBJECTS) $(GST_CORE_OBJECTS)
|
|
||||||
|
|
||||||
# Compile all .c to .o
|
# Compile all .c to .o
|
||||||
%.o : %.c $(GST_HEADERS) $(GST_INTERNAL_HEADERS) $(GST_LANG_HEADERS)
|
%.o: %.c $(DST_HEADERS) $(DST_INTERNAL_HEADERS) $(DST_LANG_HEADERS)
|
||||||
$(CC) $(CFLAGS) -o $@ -c $<
|
$(CC) $(CFLAGS) -o $@ -c $<
|
||||||
|
|
||||||
run: $(GST_TARGET)
|
run: $(DST_TARGET)
|
||||||
@ ./$(GST_TARGET)
|
@ ./$(DST_TARGET)
|
||||||
|
|
||||||
debug: $(GST_TARGET)
|
debug: $(DST_TARGET)
|
||||||
@ $(DEBUGGER) ./$(GST_TARGET)
|
@ $(DEBUGGER) ./$(DST_TARGET)
|
||||||
|
|
||||||
valgrind: $(GST_TARGET)
|
valgrind: $(DST_TARGET)
|
||||||
@ valgrind --leak-check=full -v ./$(GST_TARGET)
|
@ valgrind --leak-check=full -v ./$(DST_TARGET)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm $(GST_TARGET) || true
|
rm $(DST_TARGET) || true
|
||||||
rm $(GST_CORE_OBJECTS) || true
|
rm $(DST_CORE_OBJECTS) || true
|
||||||
rm $(GST_CLIENT_OBJECTS) || true
|
rm $(DST_LANG_HEADERS) || true
|
||||||
rm $(GST_LANG_HEADERS) || true
|
|
||||||
rm vgcore.* || true
|
rm vgcore.* || true
|
||||||
rm $(GST_XXD) || true
|
rm $(DST_XXD) || true
|
||||||
|
|
||||||
test: $(GST_TARGET)
|
test: $(DST_TARGET)
|
||||||
@ ./$(GST_TARGET) gsttests/basic.gst
|
@ ./$(DST_TARGET) dsttests/basic.dst
|
||||||
|
|
||||||
valtest: $(GST_TARGET)
|
valtest: $(DST_TARGET)
|
||||||
valgrind --leak-check=full -v ./$(GST_TARGET) gsttests/basic.gst
|
valgrind --leak-check=full -v ./$(DST_TARGET) dsttests/basic.dst
|
||||||
|
|
||||||
install: $(GST_TARGET)
|
install: $(DST_TARGET)
|
||||||
cp $(GST_TARGET) $(BINDIR)/gst
|
cp $(DST_TARGET) $(BINDIR)/dst
|
||||||
|
|
||||||
uninstall:
|
uninstall:
|
||||||
rm $(BINDIR)/gst
|
rm $(BINDIR)/dst
|
||||||
|
|
||||||
.PHONY: clean install run debug valgrind test valtest install uninstall
|
.PHONY: clean install run debug valgrind test valtest install uninstall
|
||||||
|
14
README.md
14
README.md
@ -1,8 +1,8 @@
|
|||||||
# gst
|
# dst
|
||||||
|
|
||||||
[![Build Status](https://travis-ci.org/bakpakin/gst.svg?branch=master)](https://travis-ci.org/bakpakin/gst)
|
[![Build Status](https://travis-ci.org/bakpakin/dst.svg?branch=master)](https://travis-ci.org/bakpakin/dst)
|
||||||
|
|
||||||
gst is a language and vm that is small and embeddable, has metaprogramming
|
dst is a language and vm that is small and embeddable, has metaprogramming
|
||||||
facilities, can interoperate with C, and has enough features to make it
|
facilities, can interoperate with C, and has enough features to make it
|
||||||
a useful general purpose programming language. It is a variant of
|
a useful general purpose programming language. It is a variant of
|
||||||
Lisp with several native useful datatypes. Some of the more interesting and
|
Lisp with several native useful datatypes. Some of the more interesting and
|
||||||
@ -18,7 +18,7 @@ defined, like the module system and macros.
|
|||||||
|
|
||||||
There is a repl for trying out the language, as well as the ability
|
There is a repl for trying out the language, as well as the ability
|
||||||
to run script files. This client program is separate from the core runtime, so
|
to run script files. This client program is separate from the core runtime, so
|
||||||
gst could be embedded into other programs.
|
dst could be embedded into other programs.
|
||||||
|
|
||||||
## Compiling and Running
|
## Compiling and Running
|
||||||
|
|
||||||
@ -32,10 +32,10 @@ To build the runtime and launch a repl.
|
|||||||
|
|
||||||
To run some basic programs, run the client with one argument, the name of the
|
To run some basic programs, run the client with one argument, the name of the
|
||||||
file to run. For example, the client that is built will be located in the
|
file to run. For example, the client that is built will be located in the
|
||||||
client directory, so running a program `script.gst` from the project directory
|
client directory, so running a program `script.dst` from the project directory
|
||||||
would be
|
would be
|
||||||
```bash
|
```bash
|
||||||
client/gst script.gst
|
client/dst script.dst
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also use the `--help` option to see more usage information for the vm.
|
You can also use the `--help` option to see more usage information for the vm.
|
||||||
@ -56,7 +56,7 @@ Simply run `make test` to run the currently minimal test suite.
|
|||||||
formating functions.
|
formating functions.
|
||||||
* Macro/specials system that happens before compilation
|
* Macro/specials system that happens before compilation
|
||||||
* Module system. Something similar to node's require.
|
* Module system. Something similar to node's require.
|
||||||
* Change name (gst is the name of many projects, including GNU Smalltalk).
|
* Change name (dst is the name of many projects, including GNU Smalltalk).
|
||||||
Maybe make logo :)?
|
Maybe make logo :)?
|
||||||
* Change C API to be stack based for fewer potential memory management
|
* Change C API to be stack based for fewer potential memory management
|
||||||
problems. This could mean making current C API internal and use separate
|
problems. This could mean making current C API internal and use separate
|
||||||
|
146
client/main.c
146
client/main.c
@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <gst/gst.h>
|
#include <dst/dst.h>
|
||||||
|
|
||||||
static int client_strequal(const char *a, const char *b) {
|
static int client_strequal(const char *a, const char *b) {
|
||||||
while (*a)
|
while (*a)
|
||||||
@ -36,23 +36,23 @@ static int client_strequal_witharg(const char *a, const char *b) {
|
|||||||
return *a == '=';
|
return *a == '=';
|
||||||
}
|
}
|
||||||
|
|
||||||
#define GST_CLIENT_HELP 1
|
#define DST_CLIENT_HELP 1
|
||||||
#define GST_CLIENT_VERBOSE 2
|
#define DST_CLIENT_VERBOSE 2
|
||||||
#define GST_CLIENT_VERSION 4
|
#define DST_CLIENT_VERSION 4
|
||||||
#define GST_CLIENT_REPL 8
|
#define DST_CLIENT_REPL 8
|
||||||
#define GST_CLIENT_NOCOLOR 16
|
#define DST_CLIENT_NOCOLOR 16
|
||||||
#define GST_CLIENT_UNKNOWN 32
|
#define DST_CLIENT_UNKNOWN 32
|
||||||
|
|
||||||
static void printf_flags(int64_t flags, const char *col, const char *fmt, const char *arg) {
|
static void printf_flags(int64_t flags, const char *col, const char *fmt, const char *arg) {
|
||||||
if (!(flags & GST_CLIENT_NOCOLOR))
|
if (!(flags & DST_CLIENT_NOCOLOR))
|
||||||
printf("\x1B[%sm", col);
|
printf("\x1B[%sm", col);
|
||||||
printf(fmt, arg);
|
printf(fmt, arg);
|
||||||
if (!(flags & GST_CLIENT_NOCOLOR))
|
if (!(flags & DST_CLIENT_NOCOLOR))
|
||||||
printf("\x1B[0m");
|
printf("\x1B[0m");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Simple read line functionality */
|
/* Simple read line functionality */
|
||||||
static char *gst_getline() {
|
static char *dst_getline() {
|
||||||
char *line = malloc(100);
|
char *line = malloc(100);
|
||||||
char *linep = line;
|
char *linep = line;
|
||||||
size_t lenmax = 100;
|
size_t lenmax = 100;
|
||||||
@ -82,34 +82,64 @@ static char *gst_getline() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Compile and run an ast */
|
/* Compile and run an ast */
|
||||||
static int debug_compile_and_run(Gst *vm, GstValue ast, int64_t flags) {
|
static int debug_compile_and_run(Dst *vm, DstValue ast, int64_t flags) {
|
||||||
GstValue func = gst_compile(vm, vm->env, ast);
|
DstValue func = dst_compile(vm, vm->env, ast);
|
||||||
/* Check for compilation errors */
|
/* Check for compilation errors */
|
||||||
if (func.type != GST_FUNCTION) {
|
if (func.type != DST_FUNCTION) {
|
||||||
printf_flags(flags, "31", "compiler error: %s\n", (const char *)gst_to_string(vm, func));
|
printf_flags(flags, "31", "compiler error: %s\n", (const char *)dst_to_string(vm, func));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
/* Execute function */
|
/* Execute function */
|
||||||
if (gst_run(vm, func)) {
|
if (dst_run(vm, func)) {
|
||||||
printf_flags(flags, "31", "vm error: %s\n", (const char *)gst_to_string(vm, vm->ret));
|
printf_flags(flags, "31", "vm error: %s\n", (const char *)dst_to_string(vm, vm->ret));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parse a file and execute it */
|
/* Parse a file and execute it */
|
||||||
static int debug_run(Gst *vm, FILE *in, int64_t flags) {
|
static int debug_run(Dst *vm, FILE *in, int64_t flags) {
|
||||||
|
uint8_t *source = NULL;
|
||||||
|
uint32_t sourceSize = 0;
|
||||||
|
long bufsize;
|
||||||
|
|
||||||
|
/* Read file into memory */
|
||||||
|
if (!fseek(in, 0L, SEEK_END) == 0) goto file_error;
|
||||||
|
bufsize = ftell(in);
|
||||||
|
if (bufsize == -1) goto file_error;
|
||||||
|
sourceSize = (uint32_t) bufsize;
|
||||||
|
source = malloc(bufsize);
|
||||||
|
if (!source) goto file_error;
|
||||||
|
if (fseek(in, 0L, SEEK_SET) != 0) goto file_error;
|
||||||
|
fread(source, sizeof(char), bufsize, in);
|
||||||
|
if (ferror(in) != 0) goto file_error;
|
||||||
|
|
||||||
|
while (source) {
|
||||||
|
source = dst_parseb(vm, 0, source, sourceSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Finish up */
|
||||||
|
fclose(in);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Handle errors */
|
||||||
|
file_error:
|
||||||
|
if (source) {
|
||||||
|
free(source);
|
||||||
|
}
|
||||||
|
printf_flags(flags, "31", "parse error: could not read file%s\n", "");
|
||||||
|
fclose(in);
|
||||||
|
return 1;
|
||||||
|
|
||||||
char buffer[2048] = {0};
|
char buffer[2048] = {0};
|
||||||
const char *reader = buffer;
|
const char *reader = buffer;
|
||||||
GstParser p;
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
/* Init parser */
|
int status = dst_parsec(vm, )
|
||||||
gst_parser(&p, vm);
|
while (p.status != DST_PARSER_ERROR && p.status != DST_PARSER_FULL) {
|
||||||
while (p.status != GST_PARSER_ERROR && p.status != GST_PARSER_FULL) {
|
|
||||||
if (*reader == '\0') {
|
if (*reader == '\0') {
|
||||||
if (!fgets(buffer, sizeof(buffer), in)) {
|
if (!fgets(buffer, sizeof(buffer), in)) {
|
||||||
/* Check that parser is complete */
|
/* Check that parser is complete */
|
||||||
if (p.status != GST_PARSER_FULL && p.status != GST_PARSER_ROOT) {
|
if (p.status != DST_PARSER_FULL && p.status != DST_PARSER_ROOT) {
|
||||||
printf_flags(flags, "31", "parse error: unexpected end of source%s\n", "");
|
printf_flags(flags, "31", "parse error: unexpected end of source%s\n", "");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -118,7 +148,7 @@ static int debug_run(Gst *vm, FILE *in, int64_t flags) {
|
|||||||
}
|
}
|
||||||
reader = buffer;
|
reader = buffer;
|
||||||
}
|
}
|
||||||
reader += gst_parse_cstring(&p, reader);
|
reader += dst_parse_cstring(&p, reader);
|
||||||
}
|
}
|
||||||
/* Check if file read in correctly */
|
/* Check if file read in correctly */
|
||||||
if (p.error) {
|
if (p.error) {
|
||||||
@ -126,11 +156,11 @@ static int debug_run(Gst *vm, FILE *in, int64_t flags) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* Check that parser is complete */
|
/* Check that parser is complete */
|
||||||
if (p.status != GST_PARSER_FULL && p.status != GST_PARSER_ROOT) {
|
if (p.status != DST_PARSER_FULL && p.status != DST_PARSER_ROOT) {
|
||||||
printf_flags(flags, "31", "parse error: unexpected end of source%s\n", "");
|
printf_flags(flags, "31", "parse error: unexpected end of source%s\n", "");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (debug_compile_and_run(vm, gst_parse_consume(&p), flags)) {
|
if (debug_compile_and_run(vm, dst_parse_consume(&p), flags)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -138,26 +168,26 @@ static int debug_run(Gst *vm, FILE *in, int64_t flags) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* A simple repl */
|
/* A simple repl */
|
||||||
static int debug_repl(Gst *vm, uint64_t flags) {
|
static int debug_repl(Dst *vm, uint64_t flags) {
|
||||||
char *buffer, *reader;
|
char *buffer, *reader;
|
||||||
GstParser p;
|
DstParser p;
|
||||||
buffer = reader = NULL;
|
buffer = reader = NULL;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
/* Init parser */
|
/* Init parser */
|
||||||
gst_parser(&p, vm);
|
dst_parser(&p, vm);
|
||||||
while (p.status != GST_PARSER_ERROR && p.status != GST_PARSER_FULL) {
|
while (p.status != DST_PARSER_ERROR && p.status != DST_PARSER_FULL) {
|
||||||
if (p.status == GST_PARSER_ERROR || p.status == GST_PARSER_FULL)
|
if (p.status == DST_PARSER_ERROR || p.status == DST_PARSER_FULL)
|
||||||
break;
|
break;
|
||||||
if (!reader || *reader == '\0') {
|
if (!reader || *reader == '\0') {
|
||||||
printf_flags(flags, "33", "> %s", "");
|
printf_flags(flags, "33", "> %s", "");
|
||||||
if (buffer)
|
if (buffer)
|
||||||
free(buffer);
|
free(buffer);
|
||||||
buffer = gst_getline();
|
buffer = dst_getline();
|
||||||
if (!buffer || *buffer == '\0')
|
if (!buffer || *buffer == '\0')
|
||||||
return 0;
|
return 0;
|
||||||
reader = buffer;
|
reader = buffer;
|
||||||
}
|
}
|
||||||
reader += gst_parse_cstring(&p, reader);
|
reader += dst_parse_cstring(&p, reader);
|
||||||
}
|
}
|
||||||
/* Check if file read in correctly */
|
/* Check if file read in correctly */
|
||||||
if (p.error) {
|
if (p.error) {
|
||||||
@ -166,20 +196,20 @@ static int debug_repl(Gst *vm, uint64_t flags) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* Check that parser is complete */
|
/* Check that parser is complete */
|
||||||
if (p.status != GST_PARSER_FULL && p.status != GST_PARSER_ROOT) {
|
if (p.status != DST_PARSER_FULL && p.status != DST_PARSER_ROOT) {
|
||||||
printf_flags(flags, "31", "parse error: unexpected end of source%s\n", "");
|
printf_flags(flags, "31", "parse error: unexpected end of source%s\n", "");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
gst_env_putc(vm, vm->env, "_", vm->ret);
|
dst_env_putc(vm, vm->env, "_", vm->ret);
|
||||||
gst_env_putc(vm, vm->env, "-env-", gst_wrap_table(vm->env));
|
dst_env_putc(vm, vm->env, "-env-", dst_wrap_table(vm->env));
|
||||||
if (!debug_compile_and_run(vm, gst_parse_consume(&p), flags)) {
|
if (!debug_compile_and_run(vm, dst_parse_consume(&p), flags)) {
|
||||||
printf_flags(flags, "36", "%s\n", (const char *) gst_description(vm, vm->ret));
|
printf_flags(flags, "36", "%s\n", (const char *) dst_description(vm, vm->ret));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, const char **argv) {
|
int main(int argc, const char **argv) {
|
||||||
Gst vm;
|
Dst vm;
|
||||||
int status = -1;
|
int status = -1;
|
||||||
int i;
|
int i;
|
||||||
int fileRead = 0;
|
int fileRead = 0;
|
||||||
@ -194,20 +224,20 @@ int main(int argc, const char **argv) {
|
|||||||
if (arg[1] == '-') {
|
if (arg[1] == '-') {
|
||||||
/* Option */
|
/* Option */
|
||||||
if (client_strequal(arg + 2, "help")) {
|
if (client_strequal(arg + 2, "help")) {
|
||||||
flags |= GST_CLIENT_HELP;
|
flags |= DST_CLIENT_HELP;
|
||||||
} else if (client_strequal(arg + 2, "version")) {
|
} else if (client_strequal(arg + 2, "version")) {
|
||||||
flags |= GST_CLIENT_VERSION;
|
flags |= DST_CLIENT_VERSION;
|
||||||
} else if (client_strequal(arg + 2, "verbose")) {
|
} else if (client_strequal(arg + 2, "verbose")) {
|
||||||
flags |= GST_CLIENT_VERBOSE;
|
flags |= DST_CLIENT_VERBOSE;
|
||||||
} else if (client_strequal(arg + 2, "repl")) {
|
} else if (client_strequal(arg + 2, "repl")) {
|
||||||
flags |= GST_CLIENT_REPL;
|
flags |= DST_CLIENT_REPL;
|
||||||
} else if (client_strequal(arg + 2, "nocolor")) {
|
} else if (client_strequal(arg + 2, "nocolor")) {
|
||||||
flags |= GST_CLIENT_NOCOLOR;
|
flags |= DST_CLIENT_NOCOLOR;
|
||||||
} else if (client_strequal_witharg(arg + 2, "memchunk")) {
|
} else if (client_strequal_witharg(arg + 2, "memchunk")) {
|
||||||
int64_t val = memoryInterval;
|
int64_t val = memoryInterval;
|
||||||
const uint8_t *end = (const uint8_t *)(arg + 2);
|
const uint8_t *end = (const uint8_t *)(arg + 2);
|
||||||
while (*end) ++end;
|
while (*end) ++end;
|
||||||
int status = gst_read_integer((const uint8_t *)arg + 11, end, &val);
|
int status = dst_read_integer((const uint8_t *)arg + 11, end, &val);
|
||||||
if (status) {
|
if (status) {
|
||||||
if (val > 0xFFFFFFFF) {
|
if (val > 0xFFFFFFFF) {
|
||||||
memoryInterval = 0xFFFFFFFF;
|
memoryInterval = 0xFFFFFFFF;
|
||||||
@ -218,7 +248,7 @@ int main(int argc, const char **argv) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
flags |= GST_CLIENT_UNKNOWN;
|
flags |= DST_CLIENT_UNKNOWN;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Flag */
|
/* Flag */
|
||||||
@ -226,22 +256,22 @@ int main(int argc, const char **argv) {
|
|||||||
while (*(++c)) {
|
while (*(++c)) {
|
||||||
switch (*c) {
|
switch (*c) {
|
||||||
case 'h':
|
case 'h':
|
||||||
flags |= GST_CLIENT_HELP;
|
flags |= DST_CLIENT_HELP;
|
||||||
break;
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
flags |= GST_CLIENT_VERSION;
|
flags |= DST_CLIENT_VERSION;
|
||||||
break;
|
break;
|
||||||
case 'V':
|
case 'V':
|
||||||
flags |= GST_CLIENT_VERBOSE;
|
flags |= DST_CLIENT_VERBOSE;
|
||||||
break;
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
flags |= GST_CLIENT_REPL;
|
flags |= DST_CLIENT_REPL;
|
||||||
break;
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
flags |= GST_CLIENT_NOCOLOR;
|
flags |= DST_CLIENT_NOCOLOR;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
flags |= GST_CLIENT_UNKNOWN;
|
flags |= DST_CLIENT_UNKNOWN;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -250,7 +280,7 @@ int main(int argc, const char **argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Handle flags and options */
|
/* Handle flags and options */
|
||||||
if ((flags & GST_CLIENT_HELP) || (flags & GST_CLIENT_UNKNOWN)) {
|
if ((flags & DST_CLIENT_HELP) || (flags & DST_CLIENT_UNKNOWN)) {
|
||||||
printf( "Usage:\n"
|
printf( "Usage:\n"
|
||||||
"%s -opts --fullopt1 --fullopt2 file1 file2...\n"
|
"%s -opts --fullopt1 --fullopt2 file1 file2...\n"
|
||||||
"\n"
|
"\n"
|
||||||
@ -265,15 +295,15 @@ int main(int argc, const char **argv) {
|
|||||||
argv[0]);
|
argv[0]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (flags & GST_CLIENT_VERSION) {
|
if (flags & DST_CLIENT_VERSION) {
|
||||||
printf("%s\n", GST_VERSION);
|
printf("%s\n", DST_VERSION);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set up VM */
|
/* Set up VM */
|
||||||
gst_init(&vm);
|
dst_init(&vm);
|
||||||
vm.memoryInterval = memoryInterval;
|
vm.memoryInterval = memoryInterval;
|
||||||
gst_stl_load(&vm);
|
dst_stl_load(&vm);
|
||||||
|
|
||||||
/* Read the arguments. Only process files. */
|
/* Read the arguments. Only process files. */
|
||||||
for (i = 1; i < argc; ++i) {
|
for (i = 1; i < argc; ++i) {
|
||||||
@ -286,11 +316,11 @@ int main(int argc, const char **argv) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fileRead || (flags & GST_CLIENT_REPL)) {
|
if (!fileRead || (flags & DST_CLIENT_REPL)) {
|
||||||
status = debug_repl(&vm, flags);
|
status = debug_repl(&vm, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
gst_deinit(&vm);
|
dst_deinit(&vm);
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
@ -20,13 +20,19 @@
|
|||||||
* IN THE SOFTWARE.
|
* IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef CACHE_H_LVYZMBLR
|
#ifndef DST_BOOTSTRAP_H_defined
|
||||||
#define CACHE_H_LVYZMBLR
|
#define DST_BOOTSTRAP_H_defined
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#define PARSE_OK 0
|
||||||
|
#define PARSE_ERROR 1
|
||||||
|
#define PARSE_UNEXPECTED_EOS 2
|
||||||
|
|
||||||
void gst_cache_remove_string(Gst *vm, char *strmem);
|
int dst_parseb(Dst *vm, uint32_t dest, const uint8_t *src, const uint8_t **newsrc, uint32_t len);
|
||||||
void gst_cache_remove_tuple(Gst *vm, char *tuplemem);
|
|
||||||
void gst_cache_remove_struct(Gst *vm, char *structmem);
|
|
||||||
|
|
||||||
#endif /* end of include guard: CACHE_H_LVYZMBLR */
|
/* Parse a c string */
|
||||||
|
int dst_parsec(Dst *vm, uint32_t dest, const char *src);
|
||||||
|
|
||||||
|
/* Parse a DST char seq (Buffer, String, Symbol) */
|
||||||
|
int dst_parse(Dst *vm, uint32_t dest, uint32_t src);
|
||||||
|
|
||||||
|
#endif /* DST_BOOTSTRAP_H_defined */
|
331
core/bootstrap_parse.c
Normal file
331
core/bootstrap_parse.c
Normal file
@ -0,0 +1,331 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017 Calvin Rose
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to
|
||||||
|
* deal in the Software without restriction, including without limitation the
|
||||||
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
* sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
* IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
|
#include "bootstrap.h"
|
||||||
|
|
||||||
|
/* Checks if a string slice is equal to a string constant */
|
||||||
|
static int check_str_const(const char *ref, const uint8_t *start, const uint8_t *end) {
|
||||||
|
while (*ref && start < end) {
|
||||||
|
if (*ref != *(char *)start) return 0;
|
||||||
|
++ref;
|
||||||
|
++start;
|
||||||
|
}
|
||||||
|
return !*ref && start == end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Quote a value */
|
||||||
|
static DstValue quote(Dst *vm, DstValue x) {
|
||||||
|
DstValue *tuple = dst_tuple_begin(vm, 2);
|
||||||
|
tuple[0] = dst_string_cvs(vm, "quote");
|
||||||
|
tuple[1] = x;
|
||||||
|
return dst_wrap_tuple(dst_tuple_end(vm, tuple));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if a character is whitespace */
|
||||||
|
static int is_whitespace(uint8_t c) {
|
||||||
|
return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\0' || c == ',';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if a character is a valid symbol character */
|
||||||
|
static int is_symbol_char(uint8_t c) {
|
||||||
|
if (c >= 'a' && c <= 'z') return 1;
|
||||||
|
if (c >= 'A' && c <= 'Z') return 1;
|
||||||
|
if (c >= '0' && c <= ':') return 1;
|
||||||
|
if (c >= '<' && c <= '@') return 1;
|
||||||
|
if (c >= '*' && c <= '/') return 1;
|
||||||
|
if (c >= '#' && c <= '&') return 1;
|
||||||
|
if (c == '_') return 1;
|
||||||
|
if (c == '^') return 1;
|
||||||
|
if (c == '!') return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get hex digit from a letter */
|
||||||
|
static int to_hex(uint8_t c) {
|
||||||
|
if (c >= '0' && c <= '9') {
|
||||||
|
return c - '0';
|
||||||
|
} else if (c >= 'a' && c <= 'f') {
|
||||||
|
return 10 + c - 'a';
|
||||||
|
} else if (c >= 'A' && c <= 'F') {
|
||||||
|
return 10 + c - 'A';
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Dst *vm;
|
||||||
|
const uint8_t *end;
|
||||||
|
const char **errmsg;
|
||||||
|
int status;
|
||||||
|
} ParseArgs;
|
||||||
|
|
||||||
|
/* Entry point of recursive descent parser */
|
||||||
|
static const uint8_t *parse(
|
||||||
|
ParseArgs *args,
|
||||||
|
const uint8_t *src,
|
||||||
|
uint32_t recur) {
|
||||||
|
|
||||||
|
Dst *vm = args->vm;
|
||||||
|
const uint8_t *end = args->end;
|
||||||
|
uint32_t qcount = 0;
|
||||||
|
uint32_t retindex = dst_args(vm);
|
||||||
|
|
||||||
|
/* Prevent stack overflow */
|
||||||
|
if (recur == 0) goto too_much_recur;
|
||||||
|
|
||||||
|
/* Trim leading whitespace and count quotes */
|
||||||
|
while (src < end && (is_whitespace(*src) || *src == '\'')) {
|
||||||
|
if (*src == '\'') {
|
||||||
|
++qcount;
|
||||||
|
}
|
||||||
|
++src;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for end of source */
|
||||||
|
if (src >= end) goto unexpected_eos;
|
||||||
|
|
||||||
|
/* Detect token type based on first character */
|
||||||
|
switch (*src) {
|
||||||
|
|
||||||
|
/* Numbers, symbols, simple literals */
|
||||||
|
default: {
|
||||||
|
DstReal real;
|
||||||
|
DstInteger integer;
|
||||||
|
const uint8_t *tokenend = src;
|
||||||
|
if (!is_symbol_char(*src)) goto unexpected_character;
|
||||||
|
dst_setsize(vm, retindex + 1);
|
||||||
|
while (tokenend < end && is_symbol_char(*tokenend))
|
||||||
|
tokenend++;
|
||||||
|
if (tokenend >= end) goto unexpected_eos;
|
||||||
|
if (dst_read_integer(src, tokenend, &integer)) {
|
||||||
|
dst_set_integer(vm, retindex, integer);
|
||||||
|
} else if (dst_read_real(src, tokenend, &real, 0)) {
|
||||||
|
dst_set_real(vm, retindex, real);
|
||||||
|
} else if (check_str_const("nil", src, tokenend)) {
|
||||||
|
dst_nil(vm, retindex);
|
||||||
|
} else if (check_str_const("false", src, tokenend)) {
|
||||||
|
dst_false(vm, retindex);
|
||||||
|
} else if (check_str_const("true", src, tokenend)) {
|
||||||
|
dst_true(vm, retindex);
|
||||||
|
} else {
|
||||||
|
if (*src >= '0' && *src <= '9') {
|
||||||
|
goto sym_nodigits;
|
||||||
|
} else {
|
||||||
|
dst_symbol(vm, retindex, src, tokenend - src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
src = tokenend;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ':': {
|
||||||
|
const uint8_t *tokenend = ++src;
|
||||||
|
dst_setsize(vm, retindex + 1);
|
||||||
|
while (tokenend < end && is_symbol_char(*tokenend))
|
||||||
|
tokenend++;
|
||||||
|
if (tokenend >= end) goto unexpected_eos;
|
||||||
|
dst_string(vm, retindex, src, tokenend - src);
|
||||||
|
src = tokenend;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* String literals */
|
||||||
|
case '"': {
|
||||||
|
const uint8_t *strend = ++src;
|
||||||
|
uint32_t len = 0;
|
||||||
|
int containsEscape = 0;
|
||||||
|
/* Preprocess string to check for escapes and string end */
|
||||||
|
while (strend < end && *strend != '"') {
|
||||||
|
len++;
|
||||||
|
if (*strend++ == '\\') {
|
||||||
|
constainsEscape = 1;
|
||||||
|
if (strend >= end) goto unexpected_eos;
|
||||||
|
if (*strend == 'h') {
|
||||||
|
strend += 2;
|
||||||
|
if (strend >= end) goto unexpected_eos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (containsEscape) {
|
||||||
|
uint8_t *buf = dst_string_begin(vm, len);
|
||||||
|
uint8_t *write = buf;
|
||||||
|
const uint8_t *scan = src;
|
||||||
|
while (scan < strend) {
|
||||||
|
if (*scan == '\\') {
|
||||||
|
scan++;
|
||||||
|
switch (*++scan) {
|
||||||
|
case 'n': *write++ = '\n'; break;
|
||||||
|
case 'r': *write++ = '\r'; break;
|
||||||
|
case 't': *write++ = '\t'; break;
|
||||||
|
case 'f': *write++ = '\f'; break;
|
||||||
|
case '0': *write++ = '\0'; break;
|
||||||
|
case '"': *write++ = '"'; break;
|
||||||
|
case '\'': *write++ = '\''; break;
|
||||||
|
case 'z': *write++ = '\0'; break;
|
||||||
|
case 'e': *write++ = 27; break;
|
||||||
|
case 'h': {
|
||||||
|
int d1 = to_hex(scan[0]);
|
||||||
|
int d2 = to_hex(scan[1]);
|
||||||
|
if (d1 < 0 || d2 < 0) goto invalid_hex;
|
||||||
|
*write = 16 * d1 + d2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
goto unknown_strescape;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
*write++ = *scan++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dst_string_end(vm, retindex, buf);
|
||||||
|
} else {
|
||||||
|
dst_string(vm, retindex, src, strend - src);
|
||||||
|
}
|
||||||
|
src = strend + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Data Structure literals */
|
||||||
|
case: '(':
|
||||||
|
case: '[':
|
||||||
|
case: '{': {
|
||||||
|
uint8_t close;
|
||||||
|
uint32_t tmpindex;
|
||||||
|
switch (*src++) {
|
||||||
|
case '(': close = ')'; break;
|
||||||
|
case '[': close = ']'; break;
|
||||||
|
case '{': close = '}'; break;
|
||||||
|
default: close = ')'; break;
|
||||||
|
}
|
||||||
|
/* Recursively parse inside literal */
|
||||||
|
while (*src != close) {
|
||||||
|
src = parse(args, src, recur - 1);
|
||||||
|
if (*(args->errmsg) || !src) return src;
|
||||||
|
}
|
||||||
|
src++;
|
||||||
|
tmpindex = dst_args(vm);
|
||||||
|
dst_push_space(vm, 1);
|
||||||
|
switch (close) {
|
||||||
|
case ')':
|
||||||
|
dst_tuple_n(vm, tmpindex, retindex, tmpindex - retindex);
|
||||||
|
break;
|
||||||
|
case ']':
|
||||||
|
dst_array_n(vm, tmpindex, retindex, tmpindex - retindex);
|
||||||
|
break;
|
||||||
|
case '}':
|
||||||
|
if ((tmpindex - retindex) % 2) goto struct_oddargs;
|
||||||
|
dst_struct_n(vm, tmpindex, retindex, tmpindex - retindex);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
dst_move(vm, retindex, tmpindex);
|
||||||
|
dst_setsize(vm, retindex + 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Quote the returned value qcount times */
|
||||||
|
while (qcount--) {
|
||||||
|
dst_set_arg(vm, retindex, quote(vm, dst_arg(vm, retindex)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the new source position for further calls */
|
||||||
|
return src;
|
||||||
|
|
||||||
|
/* Errors below */
|
||||||
|
|
||||||
|
unexpected_eos:
|
||||||
|
*(args->errmsg) = "unexpected end of source";
|
||||||
|
args->status = PARSE_UNEXPECTED_EOS;
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
unexpected_character:
|
||||||
|
*(args->errmsg) = "unexpected character";
|
||||||
|
args->status = PARSE_ERROR;
|
||||||
|
return src;
|
||||||
|
|
||||||
|
sym_nodigits:
|
||||||
|
*(args->errmsg) = "symbols cannot start with digits";
|
||||||
|
args->status = PARSE_ERROR;
|
||||||
|
return src;
|
||||||
|
|
||||||
|
struct_oddargs:
|
||||||
|
*(args->errmsg) = "struct literal needs an even number of arguments";
|
||||||
|
args->status = PARSE_ERROR;
|
||||||
|
return src;
|
||||||
|
|
||||||
|
unknown_strescape:
|
||||||
|
*(args->errmsg) = "unknown string escape sequence";
|
||||||
|
args->status = PARSE_ERROR;
|
||||||
|
return src;
|
||||||
|
|
||||||
|
invalid_hex:
|
||||||
|
*(args->errmsg) = "invalid hex escape in string";
|
||||||
|
args->status = PARSE_ERROR;
|
||||||
|
return src;
|
||||||
|
|
||||||
|
too_much_recur:
|
||||||
|
*(args->errmsg) = "recursed too deeply in parsing";
|
||||||
|
args->status = PARSE_ERROR;
|
||||||
|
return src;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse an array of bytes */
|
||||||
|
int dst_parseb(Dst *vm, uint32_t dest, const uint8_t *src, const uint8_t **newsrc, uint32_t len) {
|
||||||
|
ParseArgs args;
|
||||||
|
uint32_t toploc = dst_args(vm);
|
||||||
|
const uint8_t *srcrest;
|
||||||
|
|
||||||
|
args.vm = vm;
|
||||||
|
args.status = PARSE_OK;
|
||||||
|
args.end = src + len;
|
||||||
|
args.errmsg = NULL;
|
||||||
|
|
||||||
|
srcrest = parse(&args, src, 2048) || src;
|
||||||
|
if (newsrc) {
|
||||||
|
*newsrc = srcrest;
|
||||||
|
}
|
||||||
|
if (args.errmsg) {
|
||||||
|
/* Error */
|
||||||
|
dst_cstring(vm, dest, args.errmsg);
|
||||||
|
} else {
|
||||||
|
/* Success */
|
||||||
|
dst_move(vm, dest, toploc);
|
||||||
|
}
|
||||||
|
dst_setsize(vm, toploc);
|
||||||
|
return args.status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse a c string */
|
||||||
|
int dst_parsec(Dst *vm, uint32_t dest, const char *src) {
|
||||||
|
uint32_t len = 0;
|
||||||
|
while (src[len]) ++len;
|
||||||
|
return dst_parseb(vm, dest, (const uint8_t *)src, NULL, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse a DST char seq (Buffer, String, Symbol) */
|
||||||
|
int dst_parse(Dst *vm, uint32_t dest, uint32_t src) {
|
||||||
|
uint32_t len;
|
||||||
|
const uint8_t *bytes = dst_bytes(vm, src, &len);
|
||||||
|
return dst_parseb(vm, dest, bytes, NULL, len);
|
||||||
|
}
|
82
core/client.c
Normal file
82
core/client.c
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017 Calvin Rose
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to
|
||||||
|
* deal in the Software without restriction, including without limitation the
|
||||||
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
* sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
* IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <dst/dst.h>
|
||||||
|
#include "bootstrap.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* Simple read line functionality */
|
||||||
|
static char *dst_getline() {
|
||||||
|
char *line = malloc(100);
|
||||||
|
char *linep = line;
|
||||||
|
size_t lenmax = 100;
|
||||||
|
size_t len = lenmax;
|
||||||
|
int c;
|
||||||
|
if (line == NULL)
|
||||||
|
return NULL;
|
||||||
|
for (;;) {
|
||||||
|
c = fgetc(stdin);
|
||||||
|
if (c == EOF)
|
||||||
|
break;
|
||||||
|
if (--len == 0) {
|
||||||
|
len = lenmax;
|
||||||
|
char *linen = realloc(linep, lenmax *= 2);
|
||||||
|
if (linen == NULL) {
|
||||||
|
free(linep);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
line = linen + (line - linep);
|
||||||
|
linep = linen;
|
||||||
|
}
|
||||||
|
if ((*line++ = c) == '\n')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*line = '\0';
|
||||||
|
return linep;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, const char **argv) {
|
||||||
|
|
||||||
|
Dst *vm = dst_init();
|
||||||
|
for (;;) {
|
||||||
|
char *line = dst_getline();
|
||||||
|
if (line) {
|
||||||
|
uint32_t len = 0;
|
||||||
|
int status = dst_parsec(vm, 0, line);
|
||||||
|
if (status == PARSE_OK) {
|
||||||
|
dst_description(vm, 0, 0);
|
||||||
|
}
|
||||||
|
const uint8_t *b = dst_bytes(vm, 0, &len);
|
||||||
|
for (uint32_t i = 0; i < len; ++i) {
|
||||||
|
putc(b[i]);
|
||||||
|
}
|
||||||
|
putc('\n');
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dst_deinit(vm);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
680
core/compile.c
680
core/compile.c
File diff suppressed because it is too large
Load Diff
102
core/env.c
102
core/env.c
@ -20,59 +20,59 @@
|
|||||||
* IN THE SOFTWARE.
|
* IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include "internal.h"
|
||||||
|
|
||||||
static GstTable *gst_env_keytab(Gst *vm, GstTable *env, const char *keyword) {
|
static DstTable *dst_env_keytab(Dst *vm, DstTable *env, const char *keyword) {
|
||||||
GstTable *tab;
|
DstTable *tab;
|
||||||
GstValue key = gst_string_cv(vm, keyword);
|
DstValue key = dst_string_cv(vm, keyword);
|
||||||
GstValue maybeTab = gst_table_get(env, key);
|
DstValue maybeTab = dst_table_get(env, key);
|
||||||
if (maybeTab.type != GST_TABLE) {
|
if (maybeTab.type != DST_TABLE) {
|
||||||
tab = gst_table(vm, 10);
|
tab = dst_table(vm, 10);
|
||||||
gst_table_put(vm, env, key, gst_wrap_table(tab));
|
dst_table_put(vm, env, key, dst_wrap_table(tab));
|
||||||
} else {
|
} else {
|
||||||
tab = maybeTab.data.table;
|
tab = maybeTab.data.table;
|
||||||
}
|
}
|
||||||
return tab;
|
return tab;
|
||||||
}
|
}
|
||||||
|
|
||||||
GstTable *gst_env_nils(Gst *vm, GstTable *env) {
|
DstTable *dst_env_nils(Dst *vm, DstTable *env) {
|
||||||
return gst_env_keytab(vm, env, "nils");
|
return dst_env_keytab(vm, env, "nils");
|
||||||
}
|
}
|
||||||
|
|
||||||
GstTable *gst_env_meta(Gst *vm, GstTable *env) {
|
DstTable *dst_env_meta(Dst *vm, DstTable *env) {
|
||||||
return gst_env_keytab(vm, env, "meta");
|
return dst_env_keytab(vm, env, "meta");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add many global variables and bind to nil */
|
/* Add many global variables and bind to nil */
|
||||||
static void mergenils(Gst *vm, GstTable *destEnv, GstTable *nils) {
|
static void mergenils(Dst *vm, DstTable *destEnv, DstTable *nils) {
|
||||||
const GstValue *data = nils->data;
|
const DstValue *data = nils->data;
|
||||||
uint32_t len = nils->capacity;
|
uint32_t len = nils->capacity;
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
GstTable *destNils = gst_env_nils(vm, destEnv);
|
DstTable *destNils = dst_env_nils(vm, destEnv);
|
||||||
for (i = 0; i < len; i += 2) {
|
for (i = 0; i < len; i += 2) {
|
||||||
if (data[i].type == GST_SYMBOL) {
|
if (data[i].type == DST_SYMBOL) {
|
||||||
gst_table_put(vm, destEnv, data[i], gst_wrap_nil());
|
dst_table_put(vm, destEnv, data[i], dst_wrap_nil());
|
||||||
gst_table_put(vm, destNils, data[i], gst_wrap_boolean(1));
|
dst_table_put(vm, destNils, data[i], dst_wrap_boolean(1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add many global variable metadata */
|
/* Add many global variable metadata */
|
||||||
static void mergemeta(Gst *vm, GstTable *destEnv, GstTable *meta) {
|
static void mergemeta(Dst *vm, DstTable *destEnv, DstTable *meta) {
|
||||||
const GstValue *data = meta->data;
|
const DstValue *data = meta->data;
|
||||||
uint32_t len = meta->capacity;
|
uint32_t len = meta->capacity;
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
GstTable *destMeta = gst_env_meta(vm, destEnv);
|
DstTable *destMeta = dst_env_meta(vm, destEnv);
|
||||||
for (i = 0; i < len; i += 2) {
|
for (i = 0; i < len; i += 2) {
|
||||||
if (data[i].type == GST_SYMBOL) {
|
if (data[i].type == DST_SYMBOL) {
|
||||||
gst_table_put(vm, destMeta, data[i], data[i + 1]);
|
dst_table_put(vm, destMeta, data[i], data[i + 1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Simple strequal between gst string ans c string, no 0s in b allowed */
|
/* Simple strequal between dst string ans c string, no 0s in b allowed */
|
||||||
static int streq(const char *str, const uint8_t *b) {
|
static int streq(const char *str, const uint8_t *b) {
|
||||||
uint32_t len = gst_string_length(b);
|
uint32_t len = dst_string_length(b);
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
const uint8_t *ustr = (const uint8_t *)str;
|
const uint8_t *ustr = (const uint8_t *)str;
|
||||||
for (i = 0; i < len; ++i) {
|
for (i = 0; i < len; ++i) {
|
||||||
@ -83,52 +83,52 @@ static int streq(const char *str, const uint8_t *b) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Add many global variables */
|
/* Add many global variables */
|
||||||
void gst_env_merge(Gst *vm, GstTable *destEnv, GstTable *srcEnv) {
|
void dst_env_merge(Dst *vm, DstTable *destEnv, DstTable *srcEnv) {
|
||||||
const GstValue *data = srcEnv->data;
|
const DstValue *data = srcEnv->data;
|
||||||
uint32_t len = srcEnv->capacity;
|
uint32_t len = srcEnv->capacity;
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
for (i = 0; i < len; i += 2) {
|
for (i = 0; i < len; i += 2) {
|
||||||
if (data[i].type == GST_SYMBOL) {
|
if (data[i].type == DST_SYMBOL) {
|
||||||
gst_table_put(vm, destEnv, data[i], data[i + 1]);
|
dst_table_put(vm, destEnv, data[i], data[i + 1]);
|
||||||
} else if (data[i].type == GST_STRING) {
|
} else if (data[i].type == DST_STRING) {
|
||||||
const uint8_t *k = data[i].data.string;
|
const uint8_t *k = data[i].data.string;
|
||||||
if (streq("nils", k)) {
|
if (streq("nils", k)) {
|
||||||
if (data[i + 1].type == GST_TABLE)
|
if (data[i + 1].type == DST_TABLE)
|
||||||
mergenils(vm, destEnv, data[i + 1].data.table);
|
mergenils(vm, destEnv, data[i + 1].data.table);
|
||||||
} else if (streq("meta", k)) {
|
} else if (streq("meta", k)) {
|
||||||
if (data[i + 1].type == GST_TABLE)
|
if (data[i + 1].type == DST_TABLE)
|
||||||
mergemeta(vm, destEnv, data[i + 1].data.table);
|
mergemeta(vm, destEnv, data[i + 1].data.table);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void gst_env_put(Gst *vm, GstTable *env, GstValue key, GstValue value) {
|
void dst_env_put(Dst *vm, DstTable *env, DstValue key, DstValue value) {
|
||||||
GstTable *meta = gst_env_meta(vm, env);
|
DstTable *meta = dst_env_meta(vm, env);
|
||||||
gst_table_put(vm, meta, key, gst_wrap_nil());
|
dst_table_put(vm, meta, key, dst_wrap_nil());
|
||||||
gst_table_put(vm, env, key, value);
|
dst_table_put(vm, env, key, value);
|
||||||
if (value.type == GST_NIL) {
|
if (value.type == DST_NIL) {
|
||||||
gst_table_put(vm, gst_env_nils(vm, env), key, gst_wrap_boolean(1));
|
dst_table_put(vm, dst_env_nils(vm, env), key, dst_wrap_boolean(1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void gst_env_putc(Gst *vm, GstTable *env, const char *key, GstValue value) {
|
void dst_env_putc(Dst *vm, DstTable *env, const char *key, DstValue value) {
|
||||||
GstValue keyv = gst_string_cvs(vm, key);
|
DstValue keyv = dst_string_cvs(vm, key);
|
||||||
gst_env_put(vm, env, keyv, value);
|
dst_env_put(vm, env, keyv, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void gst_env_putvar(Gst *vm, GstTable *env, GstValue key, GstValue value) {
|
void dst_env_putvar(Dst *vm, DstTable *env, DstValue key, DstValue value) {
|
||||||
GstTable *meta = gst_env_meta(vm, env);
|
DstTable *meta = dst_env_meta(vm, env);
|
||||||
GstTable *newmeta = gst_table(vm, 4);
|
DstTable *newmeta = dst_table(vm, 4);
|
||||||
GstArray *ref = gst_array(vm, 1);
|
DstArray *ref = dst_array(vm, 1);
|
||||||
ref->count = 1;
|
ref->count = 1;
|
||||||
ref->data[0] = value;
|
ref->data[0] = value;
|
||||||
gst_table_put(vm, env, key, gst_wrap_array(ref));
|
dst_table_put(vm, env, key, dst_wrap_array(ref));
|
||||||
gst_table_put(vm, newmeta, gst_string_cv(vm, "mutable"), gst_wrap_boolean(1));
|
dst_table_put(vm, newmeta, dst_string_cv(vm, "mutable"), dst_wrap_boolean(1));
|
||||||
gst_table_put(vm, meta, key, gst_wrap_table(newmeta));
|
dst_table_put(vm, meta, key, dst_wrap_table(newmeta));
|
||||||
}
|
}
|
||||||
|
|
||||||
void gst_env_putvarc(Gst *vm, GstTable *env, const char *key, GstValue value) {
|
void dst_env_putvarc(Dst *vm, DstTable *env, const char *key, DstValue value) {
|
||||||
GstValue keyv = gst_string_cvs(vm, key);
|
DstValue keyv = dst_string_cvs(vm, key);
|
||||||
gst_env_putvar(vm, env, keyv, value);
|
dst_env_putvar(vm, env, keyv, value);
|
||||||
}
|
}
|
211
core/gc.c
211
core/gc.c
@ -20,8 +20,7 @@
|
|||||||
* IN THE SOFTWARE.
|
* IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include "internal.h"
|
||||||
#include "cache.h"
|
|
||||||
|
|
||||||
/* The metadata header associated with an allocated block of memory */
|
/* The metadata header associated with an allocated block of memory */
|
||||||
#define gc_header(mem) ((GCMemoryHeader *)(mem) - 1)
|
#define gc_header(mem) ((GCMemoryHeader *)(mem) - 1)
|
||||||
@ -35,31 +34,31 @@ struct GCMemoryHeader {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* Mark a chunk of memory as reachable for the gc */
|
/* Mark a chunk of memory as reachable for the gc */
|
||||||
void gst_mark_mem(Gst *vm, void *mem) {
|
void dst_mark_mem(Dst *vm, void *mem) {
|
||||||
gc_header(mem)->color = vm->black;
|
gc_header(mem)->color = vm->black;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Helper to mark function environments */
|
/* Helper to mark function environments */
|
||||||
static void gst_mark_funcenv(Gst *vm, GstFuncEnv *env) {
|
static void dst_mark_funcenv(Dst *vm, DstFuncEnv *env) {
|
||||||
if (gc_header(env)->color != vm->black) {
|
if (gc_header(env)->color != vm->black) {
|
||||||
gc_header(env)->color = vm->black;
|
gc_header(env)->color = vm->black;
|
||||||
if (env->thread) {
|
if (env->thread) {
|
||||||
GstValueUnion x;
|
DstValueUnion x;
|
||||||
x.thread = env->thread;
|
x.thread = env->thread;
|
||||||
gst_mark(vm, x, GST_THREAD);
|
dst_mark(vm, x, DST_THREAD);
|
||||||
}
|
}
|
||||||
if (env->values) {
|
if (env->values) {
|
||||||
uint32_t count = env->stackOffset;
|
uint32_t count = env->stackOffset;
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
gc_header(env->values)->color = vm->black;
|
gc_header(env->values)->color = vm->black;
|
||||||
for (i = 0; i < count; ++i)
|
for (i = 0; i < count; ++i)
|
||||||
gst_mark_value(vm, env->values[i]);
|
dst_mark_value(vm, env->values[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* GC helper to mark a FuncDef */
|
/* GC helper to mark a FuncDef */
|
||||||
static void gst_mark_funcdef(Gst *vm, GstFuncDef *def) {
|
static void dst_mark_funcdef(Dst *vm, DstFuncDef *def) {
|
||||||
if (gc_header(def)->color != vm->black) {
|
if (gc_header(def)->color != vm->black) {
|
||||||
gc_header(def)->color = vm->black;
|
gc_header(def)->color = vm->black;
|
||||||
gc_header(def->byteCode)->color = vm->black;
|
gc_header(def->byteCode)->color = vm->black;
|
||||||
@ -68,140 +67,140 @@ static void gst_mark_funcdef(Gst *vm, GstFuncDef *def) {
|
|||||||
count = def->literalsLen;
|
count = def->literalsLen;
|
||||||
gc_header(def->literals)->color = vm->black;
|
gc_header(def->literals)->color = vm->black;
|
||||||
for (i = 0; i < count; ++i)
|
for (i = 0; i < count; ++i)
|
||||||
gst_mark_value(vm, def->literals[i]);
|
dst_mark_value(vm, def->literals[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Helper to mark a stack frame. Returns the next stackframe. */
|
/* Helper to mark a stack frame. Returns the next stackframe. */
|
||||||
static GstValue *gst_mark_stackframe(Gst *vm, GstValue *stack) {
|
static DstValue *dst_mark_stackframe(Dst *vm, DstValue *stack) {
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
gst_mark_value(vm, gst_frame_callee(stack));
|
dst_mark_value(vm, dst_frame_callee(stack));
|
||||||
if (gst_frame_env(stack) != NULL)
|
if (dst_frame_env(stack) != NULL)
|
||||||
gst_mark_funcenv(vm, gst_frame_env(stack));
|
dst_mark_funcenv(vm, dst_frame_env(stack));
|
||||||
for (i = 0; i < gst_frame_size(stack); ++i)
|
for (i = 0; i < dst_frame_size(stack); ++i)
|
||||||
gst_mark_value(vm, stack[i]);
|
dst_mark_value(vm, stack[i]);
|
||||||
return stack + gst_frame_size(stack) + GST_FRAME_SIZE;
|
return stack + dst_frame_size(stack) + DST_FRAME_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Wrapper for marking values */
|
/* Wrapper for marking values */
|
||||||
void gst_mark_value(Gst *vm, GstValue x) {
|
void dst_mark_value(Dst *vm, DstValue x) {
|
||||||
gst_mark(vm, x.data, x.type);
|
dst_mark(vm, x.data, x.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mark allocated memory associated with a value. This is
|
/* Mark allocated memory associated with a value. This is
|
||||||
* the main function for doing the garbage collection mark phase. */
|
* the main function for doing the garbage collection mark phase. */
|
||||||
void gst_mark(Gst *vm, GstValueUnion x, GstType type) {
|
void dst_mark(Dst *vm, DstValueUnion x, DstType type) {
|
||||||
|
/* Allow for explicit tail recursion */
|
||||||
|
begin:
|
||||||
switch (type) {
|
switch (type) {
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GST_STRING:
|
case DST_STRING:
|
||||||
case GST_SYMBOL:
|
case DST_SYMBOL:
|
||||||
gc_header(gst_string_raw(x.string))->color = vm->black;
|
gc_header(dst_string_raw(x.string))->color = vm->black;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GST_BYTEBUFFER:
|
case DST_BYTEBUFFER:
|
||||||
gc_header(x.buffer)->color = vm->black;
|
gc_header(x.buffer)->color = vm->black;
|
||||||
gc_header(x.buffer->data)->color = vm->black;
|
gc_header(x.buffer->data)->color = vm->black;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GST_ARRAY:
|
case DST_ARRAY:
|
||||||
if (gc_header(x.array)->color != vm->black) {
|
if (gc_header(x.array)->color != vm->black) {
|
||||||
uint32_t i, count;
|
uint32_t i, count;
|
||||||
count = x.array->count;
|
count = x.array->count;
|
||||||
gc_header(x.array)->color = vm->black;
|
gc_header(x.array)->color = vm->black;
|
||||||
gc_header(x.array->data)->color = vm->black;
|
gc_header(x.array->data)->color = vm->black;
|
||||||
for (i = 0; i < count; ++i)
|
for (i = 0; i < count; ++i)
|
||||||
gst_mark_value(vm, x.array->data[i]);
|
dst_mark_value(vm, x.array->data[i]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GST_TUPLE:
|
case DST_TUPLE:
|
||||||
if (gc_header(gst_tuple_raw(x.tuple))->color != vm->black) {
|
if (gc_header(dst_tuple_raw(x.tuple))->color != vm->black) {
|
||||||
uint32_t i, count;
|
uint32_t i, count;
|
||||||
count = gst_tuple_length(x.tuple);
|
count = dst_tuple_length(x.tuple);
|
||||||
gc_header(gst_tuple_raw(x.tuple))->color = vm->black;
|
gc_header(dst_tuple_raw(x.tuple))->color = vm->black;
|
||||||
for (i = 0; i < count; ++i)
|
for (i = 0; i < count; ++i)
|
||||||
gst_mark_value(vm, x.tuple[i]);
|
dst_mark_value(vm, x.tuple[i]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GST_STRUCT:
|
case DST_STRUCT:
|
||||||
if (gc_header(gst_struct_raw(x.st))->color != vm->black) {
|
if (gc_header(dst_struct_raw(x.st))->color != vm->black) {
|
||||||
uint32_t i, count;
|
uint32_t i, count;
|
||||||
count = gst_struct_capacity(x.st);
|
count = dst_struct_capacity(x.st);
|
||||||
gc_header(gst_struct_raw(x.st))->color = vm->black;
|
gc_header(dst_struct_raw(x.st))->color = vm->black;
|
||||||
for (i = 0; i < count; ++i)
|
for (i = 0; i < count; ++i)
|
||||||
gst_mark_value(vm, x.st[i]);
|
dst_mark_value(vm, x.st[i]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GST_THREAD:
|
case DST_THREAD:
|
||||||
if (gc_header(x.thread)->color != vm->black) {
|
if (gc_header(x.thread)->color != vm->black) {
|
||||||
GstThread *thread = x.thread;
|
DstThread *thread = x.thread;
|
||||||
GstValue *frame = thread->data + GST_FRAME_SIZE;
|
DstValue *frame = thread->data + DST_FRAME_SIZE;
|
||||||
GstValue *end = thread->data + thread->count;
|
DstValue *end = thread->data + thread->count;
|
||||||
gc_header(thread)->color = vm->black;
|
gc_header(thread)->color = vm->black;
|
||||||
gc_header(thread->data)->color = vm->black;
|
gc_header(thread->data)->color = vm->black;
|
||||||
while (frame <= end)
|
while (frame <= end)
|
||||||
frame = gst_mark_stackframe(vm, frame);
|
frame = dst_mark_stackframe(vm, frame);
|
||||||
if (thread->parent)
|
if (thread->parent) {
|
||||||
gst_mark_value(vm, gst_wrap_thread(thread->parent));
|
x.thread = thread->parent;
|
||||||
if (thread->errorParent)
|
goto begin;
|
||||||
gst_mark_value(vm, gst_wrap_thread(thread->errorParent));
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GST_FUNCTION:
|
case DST_FUNCTION:
|
||||||
if (gc_header(x.function)->color != vm->black) {
|
if (gc_header(x.function)->color != vm->black) {
|
||||||
GstFunction *f = x.function;
|
DstFunction *f = x.function;
|
||||||
gc_header(f)->color = vm->black;
|
gc_header(f)->color = vm->black;
|
||||||
gst_mark_funcdef(vm, f->def);
|
dst_mark_funcdef(vm, f->def);
|
||||||
if (f->env)
|
if (f->env)
|
||||||
gst_mark_funcenv(vm, f->env);
|
dst_mark_funcenv(vm, f->env);
|
||||||
if (f->parent) {
|
if (f->parent) {
|
||||||
GstValueUnion pval;
|
DstValueUnion pval;
|
||||||
pval.function = f->parent;
|
pval.function = f->parent;
|
||||||
gst_mark(vm, pval, GST_FUNCTION);
|
dst_mark(vm, pval, DST_FUNCTION);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GST_TABLE:
|
case DST_TABLE:
|
||||||
if (gc_header(x.table)->color != vm->black) {
|
if (gc_header(x.table)->color != vm->black) {
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
gc_header(x.table)->color = vm->black;
|
gc_header(x.table)->color = vm->black;
|
||||||
gc_header(x.table->data)->color = vm->black;
|
gc_header(x.table->data)->color = vm->black;
|
||||||
for (i = 0; i < x.table->capacity; i += 2) {
|
for (i = 0; i < x.table->capacity; i += 2) {
|
||||||
gst_mark_value(vm, x.table->data[i]);
|
dst_mark_value(vm, x.table->data[i]);
|
||||||
gst_mark_value(vm, x.table->data[i + 1]);
|
dst_mark_value(vm, x.table->data[i + 1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GST_USERDATA:
|
case DST_USERDATA:
|
||||||
if (gc_header(gst_udata_header(x.pointer))->color != vm->black) {
|
{
|
||||||
GstUserdataHeader *h = gst_udata_header(x.pointer);
|
DstUserdataHeader *h = dst_udata_header(x.pointer);
|
||||||
gc_header(h)->color = vm->black;
|
gc_header(h)->color = vm->black;
|
||||||
if (h->type->gcmark)
|
|
||||||
h->type->gcmark(vm, x.pointer, h->size);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GST_FUNCENV:
|
case DST_FUNCENV:
|
||||||
gst_mark_funcenv(vm, x.env);
|
dst_mark_funcenv(vm, x.env);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GST_FUNCDEF:
|
case DST_FUNCDEF:
|
||||||
gst_mark_funcdef(vm, x.def);
|
dst_mark_funcdef(vm, x.def);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Iterate over all allocated memory, and free memory that is not
|
/* Iterate over all allocated memory, and free memory that is not
|
||||||
* marked as reachable. Flip the gc color flag for next sweep. */
|
* marked as reachable. Flip the gc color flag for next sweep. */
|
||||||
void gst_sweep(Gst *vm) {
|
void dst_sweep(Dst *vm) {
|
||||||
GCMemoryHeader *previous = NULL;
|
GCMemoryHeader *previous = NULL;
|
||||||
GCMemoryHeader *current = vm->blocks;
|
GCMemoryHeader *current = vm->blocks;
|
||||||
GCMemoryHeader *next;
|
GCMemoryHeader *next;
|
||||||
@ -214,20 +213,20 @@ void gst_sweep(Gst *vm) {
|
|||||||
vm->blocks = next;
|
vm->blocks = next;
|
||||||
}
|
}
|
||||||
if (current->tags) {
|
if (current->tags) {
|
||||||
if (current->tags & GST_MEMTAG_STRING)
|
if (current->tags & DST_MEMTAG_STRING)
|
||||||
gst_cache_remove_string(vm, (char *)(current + 1));
|
dst_cache_remove_string(vm, (char *)(current + 1));
|
||||||
if (current->tags & GST_MEMTAG_STRUCT)
|
if (current->tags & DST_MEMTAG_STRUCT)
|
||||||
gst_cache_remove_struct(vm, (char *)(current + 1));
|
dst_cache_remove_struct(vm, (char *)(current + 1));
|
||||||
if (current->tags & GST_MEMTAG_TUPLE)
|
if (current->tags & DST_MEMTAG_TUPLE)
|
||||||
gst_cache_remove_tuple(vm, (char *)(current + 1));
|
dst_cache_remove_tuple(vm, (char *)(current + 1));
|
||||||
if (current->tags & GST_MEMTAG_USER) {
|
if (current->tags & DST_MEMTAG_USER) {
|
||||||
GstUserdataHeader *h = (GstUserdataHeader *)(current + 1);
|
DstUserdataHeader *h = (DstUserdataHeader *)(current + 1);
|
||||||
if (h->type->finalize) {
|
if (h->type->finalize) {
|
||||||
h->type->finalize(vm, h + 1, h->size);
|
h->type->finalize(vm, h + 1, h->size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
gst_raw_free(current);
|
dst_raw_free(current);
|
||||||
} else {
|
} else {
|
||||||
previous = current;
|
previous = current;
|
||||||
}
|
}
|
||||||
@ -238,10 +237,10 @@ void gst_sweep(Gst *vm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Prepare a memory block */
|
/* Prepare a memory block */
|
||||||
static void *gst_alloc_prepare(Gst *vm, char *rawBlock, uint32_t size) {
|
static void *dst_alloc_prepare(Dst *vm, char *rawBlock, uint32_t size) {
|
||||||
GCMemoryHeader *mdata;
|
GCMemoryHeader *mdata;
|
||||||
if (rawBlock == NULL) {
|
if (rawBlock == NULL) {
|
||||||
GST_OUT_OF_MEMORY;
|
return NULL;
|
||||||
}
|
}
|
||||||
vm->nextCollection += size;
|
vm->nextCollection += size;
|
||||||
mdata = (GCMemoryHeader *)rawBlock;
|
mdata = (GCMemoryHeader *)rawBlock;
|
||||||
@ -253,48 +252,78 @@ static void *gst_alloc_prepare(Gst *vm, char *rawBlock, uint32_t size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate some memory that is tracked for garbage collection */
|
/* Allocate some memory that is tracked for garbage collection */
|
||||||
void *gst_alloc(Gst *vm, uint32_t size) {
|
void *dst_alloc(Dst *vm, uint32_t size) {
|
||||||
uint32_t totalSize = size + sizeof(GCMemoryHeader);
|
uint32_t totalSize = size + sizeof(GCMemoryHeader);
|
||||||
return gst_alloc_prepare(vm, gst_raw_alloc(totalSize), totalSize);
|
void *mem = dst_alloc_prepare(vm, dst_raw_alloc(totalSize), totalSize);
|
||||||
|
if (!mem) {
|
||||||
|
DST_LOW_MEMORY;
|
||||||
|
dst_collect(vm);
|
||||||
|
mem = dst_alloc_prepare(vm, dst_raw_alloc(totalSize), totalSize);
|
||||||
|
if (!mem) {
|
||||||
|
DST_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate some zeroed memory that is tracked for garbage collection */
|
/* Allocate some zeroed memory that is tracked for garbage collection */
|
||||||
void *gst_zalloc(Gst *vm, uint32_t size) {
|
void *dst_zalloc(Dst *vm, uint32_t size) {
|
||||||
uint32_t totalSize = size + sizeof(GCMemoryHeader);
|
uint32_t totalSize = size + sizeof(GCMemoryHeader);
|
||||||
return gst_alloc_prepare(vm, gst_raw_calloc(1, totalSize), totalSize);
|
void *mem = dst_alloc_prepare(vm, dst_raw_calloc(1, totalSize), totalSize);
|
||||||
|
if (!mem) {
|
||||||
|
DST_LOW_MEMORY;
|
||||||
|
dst_collect(vm);
|
||||||
|
mem = dst_alloc_prepare(vm, dst_raw_calloc(1, totalSize), totalSize);
|
||||||
|
if (!mem) {
|
||||||
|
DST_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Tag some memory to mark it with special properties */
|
/* Tag some memory to mark it with special properties */
|
||||||
void gst_mem_tag(void *mem, uint32_t tags) {
|
void dst_mem_tag(void *mem, uint32_t tags) {
|
||||||
GCMemoryHeader *mh = (GCMemoryHeader *)mem - 1;
|
GCMemoryHeader *mh = (GCMemoryHeader *)mem - 1;
|
||||||
mh->tags |= tags;
|
mh->tags |= tags;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Run garbage collection */
|
/* Run garbage collection */
|
||||||
void gst_collect(Gst *vm) {
|
void dst_collect(Dst *vm) {
|
||||||
|
DstValue x;
|
||||||
/* Thread can be null */
|
/* Thread can be null */
|
||||||
if (vm->thread)
|
if (vm->thread) {
|
||||||
gst_mark_value(vm, gst_wrap_thread(vm->thread));
|
x.type = DST_THREAD;
|
||||||
gst_mark_value(vm, gst_wrap_table(vm->modules));
|
x.data.thread = vm->thread;
|
||||||
gst_mark_value(vm, gst_wrap_table(vm->registry));
|
dst_mark_value(vm, x);
|
||||||
gst_mark_value(vm, gst_wrap_table(vm->env));
|
}
|
||||||
gst_mark_value(vm, vm->ret);
|
x.type = DST_TABLE;
|
||||||
gst_sweep(vm);
|
|
||||||
|
x.data.table = vm->modules;
|
||||||
|
dst_mark_value(vm, x);
|
||||||
|
|
||||||
|
x.data.table = vm->registry;
|
||||||
|
dst_mark_value(vm, x);
|
||||||
|
|
||||||
|
x.data.table = vm->env;
|
||||||
|
dst_mark_value(vm, x);
|
||||||
|
|
||||||
|
dst_mark_value(vm, vm->ret);
|
||||||
|
dst_sweep(vm);
|
||||||
vm->nextCollection = 0;
|
vm->nextCollection = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Run garbage collection if needed */
|
/* Run garbage collection if needed */
|
||||||
void gst_maybe_collect(Gst *vm) {
|
void dst_maybe_collect(Dst *vm) {
|
||||||
if (vm->nextCollection >= vm->memoryInterval)
|
if (vm->nextCollection >= vm->memoryInterval)
|
||||||
gst_collect(vm);
|
dst_collect(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Free all allocated memory */
|
/* Free all allocated memory */
|
||||||
void gst_clear_memory(Gst *vm) {
|
void dst_clear_memory(Dst *vm) {
|
||||||
GCMemoryHeader *current = vm->blocks;
|
GCMemoryHeader *current = vm->blocks;
|
||||||
while (current) {
|
while (current) {
|
||||||
GCMemoryHeader *next = current->next;
|
GCMemoryHeader *next = current->next;
|
||||||
gst_raw_free(current);
|
dst_raw_free(current);
|
||||||
current = next;
|
current = next;
|
||||||
}
|
}
|
||||||
vm->blocks = NULL;
|
vm->blocks = NULL;
|
||||||
|
583
core/ids.c
583
core/ids.c
@ -1,583 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2017 Calvin Rose
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to
|
|
||||||
* deal in the Software without restriction, including without limitation the
|
|
||||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
||||||
* sell copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
||||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
||||||
* IN THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <gst/gst.h>
|
|
||||||
#include "cache.h"
|
|
||||||
|
|
||||||
/****/
|
|
||||||
/* Cache */
|
|
||||||
/****/
|
|
||||||
|
|
||||||
/* Calculate hash for string */
|
|
||||||
static uint32_t gst_string_calchash(const uint8_t *str, uint32_t len) {
|
|
||||||
const uint8_t *end = str + len;
|
|
||||||
uint32_t hash = 5381;
|
|
||||||
while (str < end)
|
|
||||||
hash = (hash << 5) + hash + *str++;
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Calculate hash for tuple (and struct) */
|
|
||||||
static uint32_t gst_tuple_calchash(const GstValue *tuple, uint32_t len) {
|
|
||||||
const GstValue *end = tuple + len;
|
|
||||||
uint32_t hash = 5381;
|
|
||||||
while (tuple < end)
|
|
||||||
hash = (hash << 5) + hash + gst_hash(*tuple++);
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check if two not necesarrily finalized immutable values
|
|
||||||
* are equal. Does caching logic */
|
|
||||||
static int gst_cache_equal(GstValue x, GstValue y) {
|
|
||||||
uint32_t i, len;
|
|
||||||
if (x.type != y.type) return 0;
|
|
||||||
switch (x.type) {
|
|
||||||
/* Don't bother implementing equality checks for all types. We only care
|
|
||||||
* about immutable data structures */
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
case GST_STRING:
|
|
||||||
if (gst_string_hash(x.data.string) != gst_string_hash(y.data.string)) return 0;
|
|
||||||
if (gst_string_length(x.data.string) != gst_string_length(y.data.string)) return 0;
|
|
||||||
len = gst_string_length(x.data.string);
|
|
||||||
for (i = 0; i < len; ++i)
|
|
||||||
if (x.data.string[i] != y.data.string[i])
|
|
||||||
return 0;
|
|
||||||
return 1;
|
|
||||||
case GST_STRUCT:
|
|
||||||
if (gst_struct_hash(x.data.st) != gst_struct_hash(y.data.st)) return 0;
|
|
||||||
if (gst_struct_length(x.data.st) != gst_struct_length(y.data.st)) return 0;
|
|
||||||
len = gst_struct_capacity(x.data.st);
|
|
||||||
for (i = 0; i < len; ++i)
|
|
||||||
if (!gst_equals(x.data.st[i], y.data.st[i]))
|
|
||||||
return 0;
|
|
||||||
return 1;
|
|
||||||
case GST_TUPLE:
|
|
||||||
if (gst_tuple_hash(x.data.tuple) != gst_tuple_hash(y.data.tuple)) return 0;
|
|
||||||
if (gst_tuple_length(x.data.tuple) != gst_tuple_length(y.data.tuple)) return 0;
|
|
||||||
len = gst_tuple_length(x.data.tuple);
|
|
||||||
for (i = 0; i < len; ++i)
|
|
||||||
if (!gst_equals(x.data.tuple[i], y.data.tuple[i]))
|
|
||||||
return 0;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check if a value x is equal to a string. Special version of
|
|
||||||
* gst_cache_equal */
|
|
||||||
static int gst_cache_strequal(GstValue x, const uint8_t *str, uint32_t len, uint32_t hash) {
|
|
||||||
uint32_t i;
|
|
||||||
if (x.type != GST_STRING) return 0;
|
|
||||||
if (gst_string_hash(x.data.string) != hash) return 0;
|
|
||||||
if (gst_string_length(x.data.string) != len) return 0;
|
|
||||||
for (i = 0; i < len; ++i)
|
|
||||||
if (x.data.string[i] != str[i])
|
|
||||||
return 0;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find an item in the cache and return its location.
|
|
||||||
* If the item is not found, return the location
|
|
||||||
* where one would put it. */
|
|
||||||
static GstValue *gst_cache_find(Gst *vm, GstValue key, int *success) {
|
|
||||||
uint32_t bounds[4];
|
|
||||||
uint32_t i, j, index;
|
|
||||||
uint32_t hash = gst_hash(key);
|
|
||||||
GstValue *firstEmpty = NULL;
|
|
||||||
index = hash % vm->cache_capacity;
|
|
||||||
bounds[0] = index;
|
|
||||||
bounds[1] = vm->cache_capacity;
|
|
||||||
bounds[2] = 0;
|
|
||||||
bounds[3] = index;
|
|
||||||
for (j = 0; j < 4; j += 2)
|
|
||||||
for (i = bounds[j]; i < bounds[j+1]; ++i) {
|
|
||||||
GstValue test = vm->cache[i];
|
|
||||||
/* Check empty spots */
|
|
||||||
if (test.type == GST_NIL) {
|
|
||||||
if (firstEmpty == NULL)
|
|
||||||
firstEmpty = vm->cache + i;
|
|
||||||
goto notfound;
|
|
||||||
}
|
|
||||||
/* Check for marked deleted - use booleans as deleted */
|
|
||||||
if (test.type == GST_BOOLEAN) {
|
|
||||||
if (firstEmpty == NULL)
|
|
||||||
firstEmpty = vm->cache + i;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (gst_cache_equal(test, key)) {
|
|
||||||
/* Replace first deleted */
|
|
||||||
*success = 1;
|
|
||||||
if (firstEmpty != NULL) {
|
|
||||||
*firstEmpty = test;
|
|
||||||
vm->cache[i].type = GST_BOOLEAN;
|
|
||||||
return firstEmpty;
|
|
||||||
}
|
|
||||||
return vm->cache + i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
notfound:
|
|
||||||
*success = 0;
|
|
||||||
return firstEmpty;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find an item in the cache and return its location.
|
|
||||||
* If the item is not found, return the location
|
|
||||||
* where one would put it. Special case of gst_cache_find */
|
|
||||||
static GstValue *gst_cache_strfind(Gst *vm,
|
|
||||||
const uint8_t *str,
|
|
||||||
uint32_t len,
|
|
||||||
uint32_t hash,
|
|
||||||
int *success) {
|
|
||||||
uint32_t bounds[4];
|
|
||||||
uint32_t i, j, index;
|
|
||||||
GstValue *firstEmpty = NULL;
|
|
||||||
index = hash % vm->cache_capacity;
|
|
||||||
bounds[0] = index;
|
|
||||||
bounds[1] = vm->cache_capacity;
|
|
||||||
bounds[2] = 0;
|
|
||||||
bounds[3] = index;
|
|
||||||
for (j = 0; j < 4; j += 2)
|
|
||||||
for (i = bounds[j]; i < bounds[j+1]; ++i) {
|
|
||||||
GstValue test = vm->cache[i];
|
|
||||||
/* Check empty spots */
|
|
||||||
if (test.type == GST_NIL) {
|
|
||||||
if (firstEmpty == NULL)
|
|
||||||
firstEmpty = vm->cache + i;
|
|
||||||
goto notfound;
|
|
||||||
}
|
|
||||||
/* Check for marked deleted - use booleans as deleted */
|
|
||||||
if (test.type == GST_BOOLEAN) {
|
|
||||||
if (firstEmpty == NULL)
|
|
||||||
firstEmpty = vm->cache + i;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (gst_cache_strequal(test, str, len, hash)) {
|
|
||||||
/* Replace first deleted */
|
|
||||||
*success = 1;
|
|
||||||
if (firstEmpty != NULL) {
|
|
||||||
*firstEmpty = test;
|
|
||||||
vm->cache[i].type = GST_BOOLEAN;
|
|
||||||
return firstEmpty;
|
|
||||||
}
|
|
||||||
return vm->cache + i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
notfound:
|
|
||||||
*success = 0;
|
|
||||||
return firstEmpty;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Resize the cache. */
|
|
||||||
static void gst_cache_resize(Gst *vm, uint32_t newCapacity) {
|
|
||||||
uint32_t i, oldCapacity;
|
|
||||||
GstValue *oldCache = vm->cache;
|
|
||||||
GstValue *newCache = gst_raw_calloc(1, newCapacity * sizeof(GstValue));
|
|
||||||
if (newCache == NULL)
|
|
||||||
GST_OUT_OF_MEMORY;
|
|
||||||
oldCapacity = vm->cache_capacity;
|
|
||||||
vm->cache = newCache;
|
|
||||||
vm->cache_capacity = newCapacity;
|
|
||||||
vm->cache_deleted = 0;
|
|
||||||
/* Add all of the old strings back */
|
|
||||||
for (i = 0; i < oldCapacity; ++i) {
|
|
||||||
int status;
|
|
||||||
GstValue *bucket;
|
|
||||||
GstValue x = oldCache[i];
|
|
||||||
if (x.type != GST_NIL && x.type != GST_BOOLEAN) {
|
|
||||||
bucket = gst_cache_find(vm, x, &status);
|
|
||||||
if (status || bucket == NULL) {
|
|
||||||
/* there was a problem with the algorithm. */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
*bucket = x;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Free the old cache */
|
|
||||||
gst_raw_free(oldCache);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add a value to the cache given we know it is not
|
|
||||||
* already in the cache and we have a bucket. */
|
|
||||||
static GstValue gst_cache_add_bucket(Gst *vm, GstValue x, GstValue *bucket) {
|
|
||||||
if ((vm->cache_count + vm->cache_deleted) * 2 > vm->cache_capacity) {
|
|
||||||
int status;
|
|
||||||
gst_cache_resize(vm, vm->cache_count * 4);
|
|
||||||
bucket = gst_cache_find(vm, x, &status);
|
|
||||||
}
|
|
||||||
/* Mark the memory for the gc */
|
|
||||||
switch (x.type) {
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
case GST_STRING:
|
|
||||||
gst_mem_tag(gst_string_raw(x.data.string), GST_MEMTAG_STRING);
|
|
||||||
break;
|
|
||||||
case GST_STRUCT:
|
|
||||||
gst_mem_tag(gst_struct_raw(x.data.st), GST_MEMTAG_STRUCT);
|
|
||||||
break;
|
|
||||||
case GST_TUPLE:
|
|
||||||
gst_mem_tag(gst_tuple_raw(x.data.tuple), GST_MEMTAG_TUPLE);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* Add x to the cache */
|
|
||||||
vm->cache_count++;
|
|
||||||
*bucket = x;
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add a value to the cache */
|
|
||||||
static GstValue gst_cache_add(Gst *vm, GstValue x) {
|
|
||||||
int status = 0;
|
|
||||||
GstValue *bucket = gst_cache_find(vm, x, &status);
|
|
||||||
if (!status) {
|
|
||||||
return gst_cache_add_bucket(vm, x, bucket);
|
|
||||||
} else {
|
|
||||||
return *bucket;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Remove a value from the cache */
|
|
||||||
static void gst_cache_remove(Gst *vm, GstValue x) {
|
|
||||||
int status = 0;
|
|
||||||
GstValue *bucket = gst_cache_find(vm, x, &status);
|
|
||||||
if (status) {
|
|
||||||
vm->cache_count--;
|
|
||||||
vm->cache_deleted++;
|
|
||||||
bucket->type = GST_BOOLEAN;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Remove a string from cache (called from gc) */
|
|
||||||
void gst_cache_remove_string(Gst *vm, char *strmem) {
|
|
||||||
GstValue x;
|
|
||||||
x.type = GST_STRING;
|
|
||||||
x.data.string = (const uint8_t *)(strmem + 2 * sizeof(uint32_t));
|
|
||||||
gst_cache_remove(vm, x);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Remove a tuple from cache (called from gc) */
|
|
||||||
void gst_cache_remove_tuple(Gst *vm, char *tuplemem) {
|
|
||||||
GstValue x;
|
|
||||||
x.type = GST_TUPLE;
|
|
||||||
x.data.tuple = (const GstValue *)(tuplemem + 2 * sizeof(uint32_t));
|
|
||||||
gst_cache_remove(vm, x);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Remove a struct from cache (called from gc) */
|
|
||||||
void gst_cache_remove_struct(Gst *vm, char *structmem) {
|
|
||||||
GstValue x;
|
|
||||||
x.type = GST_STRUCT;
|
|
||||||
x.data.st = (const GstValue *)(structmem + 2 * sizeof(uint32_t));
|
|
||||||
gst_cache_remove(vm, x);
|
|
||||||
}
|
|
||||||
|
|
||||||
/****/
|
|
||||||
/* Struct Functions */
|
|
||||||
/****/
|
|
||||||
|
|
||||||
/* Begin creation of a struct */
|
|
||||||
GstValue *gst_struct_begin(Gst *vm, uint32_t count) {
|
|
||||||
char *data = gst_zalloc(vm, sizeof(uint32_t) * 2 + 4 * count * sizeof(GstValue));
|
|
||||||
GstValue *st = (GstValue *) (data + 2 * sizeof(uint32_t));
|
|
||||||
gst_struct_length(st) = count;
|
|
||||||
return st;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find an item in a struct */
|
|
||||||
static const GstValue *gst_struct_find(const GstValue *st, GstValue key) {
|
|
||||||
uint32_t cap = gst_struct_capacity(st);
|
|
||||||
uint32_t index = (gst_hash(key) % (cap / 2)) * 2;
|
|
||||||
uint32_t i;
|
|
||||||
for (i = index; i < cap; i += 2)
|
|
||||||
if (st[i].type == GST_NIL || gst_equals(st[i], key))
|
|
||||||
return st + i;
|
|
||||||
for (i = 0; i < index; i += 2)
|
|
||||||
if (st[i].type == GST_NIL || gst_equals(st[i], key))
|
|
||||||
return st + i;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Put a kv pair into a struct that has not yet been fully constructed.
|
|
||||||
* Behavior is undefined if too many keys are added, or if a key is added
|
|
||||||
* twice. Nil keys and values are ignored. */
|
|
||||||
void gst_struct_put(GstValue *st, GstValue key, GstValue value) {
|
|
||||||
uint32_t cap = gst_struct_capacity(st);
|
|
||||||
uint32_t hash = gst_hash(key);
|
|
||||||
uint32_t index = (hash % (cap / 2)) * 2;
|
|
||||||
uint32_t i, j, dist;
|
|
||||||
uint32_t bounds[4] = {index, cap, 0, index};
|
|
||||||
if (key.type == GST_NIL || value.type == GST_NIL) return;
|
|
||||||
for (dist = 0, j = 0; j < 4; j += 2)
|
|
||||||
for (i = bounds[j]; i < bounds[j + 1]; i += 2, dist += 2) {
|
|
||||||
int status;
|
|
||||||
uint32_t otherhash, otherindex, otherdist;
|
|
||||||
/* We found an empty slot, so just add key and value */
|
|
||||||
if (st[i].type == GST_NIL) {
|
|
||||||
st[i] = key;
|
|
||||||
st[i + 1] = value;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/* Robinhood hashing - check if colliding kv pair
|
|
||||||
* is closer to their source than current. */
|
|
||||||
otherhash = gst_hash(st[i]);
|
|
||||||
otherindex = (otherhash % (cap / 2)) * 2;
|
|
||||||
otherdist = (i + cap - otherindex) % cap;
|
|
||||||
if (dist < otherdist)
|
|
||||||
status = -1;
|
|
||||||
else if (otherdist < dist)
|
|
||||||
status = 1;
|
|
||||||
else if (hash < otherhash)
|
|
||||||
status = -1;
|
|
||||||
else if (otherhash < hash)
|
|
||||||
status = 1;
|
|
||||||
else
|
|
||||||
status = gst_compare(key, st[i]);
|
|
||||||
/* If other is closer to their ideal slot */
|
|
||||||
if (status == 1) {
|
|
||||||
/* Swap current kv pair with pair in slot */
|
|
||||||
GstValue t1, t2;
|
|
||||||
t1 = st[i];
|
|
||||||
t2 = st[i + 1];
|
|
||||||
st[i] = key;
|
|
||||||
st[i + 1] = value;
|
|
||||||
key = t1;
|
|
||||||
value = t2;
|
|
||||||
/* Save dist and hash of new kv pair */
|
|
||||||
dist = otherdist;
|
|
||||||
hash = otherhash;
|
|
||||||
} else if (status == 0) {
|
|
||||||
/* This should not happen - it means
|
|
||||||
* than a key was added to the struct more than once */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Finish building a struct */
|
|
||||||
const GstValue *gst_struct_end(Gst *vm, GstValue *st) {
|
|
||||||
GstValue cached;
|
|
||||||
GstValue check;
|
|
||||||
gst_struct_hash(st) = gst_tuple_calchash(st, gst_struct_capacity(st));
|
|
||||||
check.type = GST_STRUCT;
|
|
||||||
check.data.st = (const GstValue *) st;
|
|
||||||
cached = gst_cache_add(vm, check);
|
|
||||||
return cached.data.st;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get an item from a struct */
|
|
||||||
GstValue gst_struct_get(const GstValue *st, GstValue key) {
|
|
||||||
const GstValue *bucket = gst_struct_find(st, key);
|
|
||||||
if (!bucket || bucket[0].type == GST_NIL) {
|
|
||||||
GstValue ret;
|
|
||||||
ret.type = GST_NIL;
|
|
||||||
return ret;
|
|
||||||
} else {
|
|
||||||
return bucket[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get the next key in a struct */
|
|
||||||
GstValue gst_struct_next(const GstValue *st, GstValue key) {
|
|
||||||
const GstValue *bucket, *end;
|
|
||||||
end = st + gst_struct_capacity(st);
|
|
||||||
if (key.type == GST_NIL) {
|
|
||||||
bucket = st;
|
|
||||||
} else {
|
|
||||||
bucket = gst_struct_find(st, key);
|
|
||||||
if (!bucket || bucket[0].type == GST_NIL)
|
|
||||||
return gst_wrap_nil();
|
|
||||||
bucket += 2;
|
|
||||||
}
|
|
||||||
for (; bucket < end; bucket += 2) {
|
|
||||||
if (bucket[0].type != GST_NIL)
|
|
||||||
return bucket[0];
|
|
||||||
}
|
|
||||||
return gst_wrap_nil();
|
|
||||||
}
|
|
||||||
|
|
||||||
/****/
|
|
||||||
/* Tuple functions */
|
|
||||||
/****/
|
|
||||||
|
|
||||||
/* Create a new empty tuple of the given size. Expected to be
|
|
||||||
* mutated immediately */
|
|
||||||
GstValue *gst_tuple_begin(Gst *vm, uint32_t length) {
|
|
||||||
char *data = gst_alloc(vm, 2 * sizeof(uint32_t) + length * sizeof(GstValue));
|
|
||||||
GstValue *tuple = (GstValue *)(data + (2 * sizeof(uint32_t)));
|
|
||||||
gst_tuple_length(tuple) = length;
|
|
||||||
return tuple;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Finish building a tuple */
|
|
||||||
const GstValue *gst_tuple_end(Gst *vm, GstValue *tuple) {
|
|
||||||
GstValue cached;
|
|
||||||
GstValue check;
|
|
||||||
gst_tuple_hash(tuple) = gst_tuple_calchash(tuple, gst_tuple_length(tuple));
|
|
||||||
check.type = GST_TUPLE;
|
|
||||||
check.data.tuple = (const GstValue *) tuple;
|
|
||||||
cached = gst_cache_add(vm, check);
|
|
||||||
return cached.data.tuple;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****/
|
|
||||||
/* String Functions */
|
|
||||||
/****/
|
|
||||||
|
|
||||||
/* Begin building a string */
|
|
||||||
uint8_t *gst_string_begin(Gst *vm, uint32_t length) {
|
|
||||||
char *data = gst_alloc(vm, 2 * sizeof(uint32_t) + length + 1);
|
|
||||||
uint8_t *str = (uint8_t *) (data + 2 * sizeof(uint32_t));
|
|
||||||
gst_string_length(str) = length;
|
|
||||||
str[length] = 0;
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Finish building a string */
|
|
||||||
const uint8_t *gst_string_end(Gst *vm, uint8_t *str) {
|
|
||||||
GstValue cached;
|
|
||||||
GstValue check;
|
|
||||||
gst_string_hash(str) = gst_string_calchash(str, gst_string_length(str));
|
|
||||||
check.type = GST_STRING;
|
|
||||||
check.data.string = (const uint8_t *) str;
|
|
||||||
cached = gst_cache_add(vm, check);
|
|
||||||
return cached.data.string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Load a buffer as a string */
|
|
||||||
const uint8_t *gst_string_b(Gst *vm, const uint8_t *buf, uint32_t len) {
|
|
||||||
uint32_t hash = gst_string_calchash(buf, len);
|
|
||||||
int status = 0;
|
|
||||||
GstValue *bucket = gst_cache_strfind(vm, buf, len, hash, &status);
|
|
||||||
if (status) {
|
|
||||||
return bucket->data.string;
|
|
||||||
} else {
|
|
||||||
uint32_t newbufsize = len + 2 * sizeof(uint32_t) + 1;
|
|
||||||
uint8_t *str = (uint8_t *)(gst_alloc(vm, newbufsize) + 2 * sizeof(uint32_t));
|
|
||||||
gst_memcpy(str, buf, len);
|
|
||||||
gst_string_length(str) = len;
|
|
||||||
gst_string_hash(str) = hash;
|
|
||||||
str[len] = 0;
|
|
||||||
return gst_cache_add_bucket(vm, gst_wrap_string(str), bucket).data.string;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void inc_counter(uint8_t *digits, int base, int len) {
|
|
||||||
int i;
|
|
||||||
uint8_t carry = 1;
|
|
||||||
for (i = len - 1; i >= 0; --i) {
|
|
||||||
digits[i] += carry;
|
|
||||||
carry = 0;
|
|
||||||
if (digits[i] == base) {
|
|
||||||
digits[i] = 0;
|
|
||||||
carry = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Generate a unique symbol */
|
|
||||||
const uint8_t *gst_string_bu(Gst *vm, const uint8_t *buf, uint32_t len) {
|
|
||||||
static const char base64[] =
|
|
||||||
"0123456789"
|
|
||||||
"abcdefghijklmnopqrstuvwxyz"
|
|
||||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
||||||
"+-";
|
|
||||||
GstValue *bucket;
|
|
||||||
uint32_t hash;
|
|
||||||
uint8_t counter[6] = {63, 63, 63, 63, 63, 63};
|
|
||||||
/* Leave spaces for 6 base 64 digits and two dashes. That means 64^6 possible symbols, which
|
|
||||||
* is enough */
|
|
||||||
uint32_t newlen = len + 8;
|
|
||||||
uint32_t newbufsize = newlen + 2 * sizeof(uint32_t) + 1;
|
|
||||||
uint8_t *str = (uint8_t *)(gst_alloc(vm, newbufsize) + 2 * sizeof(uint32_t));
|
|
||||||
gst_string_length(str) = newlen;
|
|
||||||
gst_memcpy(str, buf, len);
|
|
||||||
str[len] = '-';
|
|
||||||
str[len + 1] = '-';
|
|
||||||
str[newlen] = 0;
|
|
||||||
uint8_t *saltbuf = str + len + 2;
|
|
||||||
int status = 1;
|
|
||||||
while (status) {
|
|
||||||
int i;
|
|
||||||
inc_counter(counter, 64, 6);
|
|
||||||
for (i = 0; i < 6; ++i)
|
|
||||||
saltbuf[i] = base64[counter[i]];
|
|
||||||
hash = gst_string_calchash(str, newlen);
|
|
||||||
bucket = gst_cache_strfind(vm, str, newlen, hash, &status);
|
|
||||||
}
|
|
||||||
gst_string_hash(str) = hash;
|
|
||||||
return gst_cache_add_bucket(vm, gst_wrap_string(str), bucket).data.string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Generate a unique string from a cstring */
|
|
||||||
const uint8_t *gst_string_cu(Gst *vm, const char *s) {
|
|
||||||
uint32_t len = 0;
|
|
||||||
while (s[len]) ++len;
|
|
||||||
return gst_string_bu(vm, (const uint8_t *)s, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Load a c string */
|
|
||||||
const uint8_t *gst_string_c(Gst *vm, const char *str) {
|
|
||||||
uint32_t len = 0;
|
|
||||||
while (str[len]) ++len;
|
|
||||||
return gst_string_b(vm, (const uint8_t *)str, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Load a c string and return it as a GstValue */
|
|
||||||
GstValue gst_string_cv(Gst *vm, const char *str) {
|
|
||||||
GstValue ret;
|
|
||||||
const uint8_t *data = gst_string_c(vm, str);
|
|
||||||
ret.type = GST_STRING;
|
|
||||||
ret.data.string = data;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Load a c string and return it as a GstValue. Return the symbol. */
|
|
||||||
GstValue gst_string_cvs(Gst *vm, const char *str) {
|
|
||||||
GstValue ret;
|
|
||||||
/* Only put strings in cache */
|
|
||||||
const uint8_t *data = gst_string_c(vm, str);
|
|
||||||
ret.type = GST_SYMBOL;
|
|
||||||
ret.data.string = data;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Compares two strings */
|
|
||||||
int gst_string_compare(const uint8_t *lhs, const uint8_t *rhs) {
|
|
||||||
uint32_t xlen = gst_string_length(lhs);
|
|
||||||
uint32_t ylen = gst_string_length(rhs);
|
|
||||||
uint32_t len = xlen > ylen ? ylen : xlen;
|
|
||||||
uint32_t i;
|
|
||||||
for (i = 0; i < len; ++i) {
|
|
||||||
if (lhs[i] == rhs[i]) {
|
|
||||||
continue;
|
|
||||||
} else if (lhs[i] < rhs[i]) {
|
|
||||||
return -1; /* x is less than y */
|
|
||||||
} else {
|
|
||||||
return 1; /* y is less than x */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (xlen == ylen) {
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
return xlen < ylen ? -1 : 1;
|
|
||||||
}
|
|
||||||
}
|
|
537
core/internal.h
Normal file
537
core/internal.h
Normal file
@ -0,0 +1,537 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017 Calvin Rose
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to
|
||||||
|
* deal in the Software without restriction, including without limitation the
|
||||||
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
* sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
* IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DST_INTERNAL_H_defined
|
||||||
|
#define DST_INTERNAL_H_defined
|
||||||
|
|
||||||
|
#include <dst/dst.h>
|
||||||
|
#include <setjmp.h>
|
||||||
|
|
||||||
|
/* String utils */
|
||||||
|
#define dst_string_raw(s) ((uint32_t *)(s) - 2)
|
||||||
|
#define dst_string_length(s) (dst_string_raw(s)[0])
|
||||||
|
#define dst_string_hash(s) (dst_string_raw(s)[1])
|
||||||
|
|
||||||
|
/* Tuple utils */
|
||||||
|
#define dst_tuple_raw(t) ((uint32_t *)(t) - 2)
|
||||||
|
#define dst_tuple_length(t) (dst_tuple_raw(t)[0])
|
||||||
|
#define dst_tuple_hash(t) (dst_tuple_raw(t)[1])
|
||||||
|
|
||||||
|
/* Struct utils */
|
||||||
|
#define dst_struct_raw(t) ((uint32_t *)(t) - 2)
|
||||||
|
#define dst_struct_length(t) (dst_struct_raw(t)[0])
|
||||||
|
#define dst_struct_capacity(t) (dst_struct_length(t) * 4)
|
||||||
|
#define dst_struct_hash(t) (dst_struct_raw(t)[1])
|
||||||
|
|
||||||
|
/* Userdata utils */
|
||||||
|
#define dst_udata_header(u) ((DstUserdataHeader *)(u) - 1)
|
||||||
|
#define dst_udata_type(u) (dst_udata_header(u)->type)
|
||||||
|
#define dst_udata_size(u) (dst_udata_header(u)->size)
|
||||||
|
|
||||||
|
/* Memcpy for moving memory */
|
||||||
|
#ifndef dst_memcpy
|
||||||
|
#include <string.h>
|
||||||
|
#define dst_memcpy memcpy
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Allocation */
|
||||||
|
#ifndef dst_raw_alloc
|
||||||
|
#include <stdlib.h>
|
||||||
|
#define dst_raw_alloc malloc
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Zero allocation */
|
||||||
|
#ifndef dst_raw_calloc
|
||||||
|
#include <stdlib.h>
|
||||||
|
#define dst_raw_calloc calloc
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Realloc */
|
||||||
|
#ifndef dst_raw_realloc
|
||||||
|
#include <stdlib.h>
|
||||||
|
#define dst_raw_realloc realloc
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Free */
|
||||||
|
#ifndef dst_raw_free
|
||||||
|
#include <stdlib.h>
|
||||||
|
#define dst_raw_free free
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Null */
|
||||||
|
#ifndef NULL
|
||||||
|
#define NULL ((void *)0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Stack frame manipulation */
|
||||||
|
|
||||||
|
/* Size of stack frame in number of values */
|
||||||
|
#define DST_FRAME_SIZE 5
|
||||||
|
|
||||||
|
/* Prevent some recursive functions from recursing too deeply
|
||||||
|
* ands crashing. */
|
||||||
|
#define DST_RECURSION_GUARD 2056
|
||||||
|
|
||||||
|
/* Macros for referencing a stack frame given a stack */
|
||||||
|
#define dst_frame_callee(s) (*(s - 1))
|
||||||
|
#define dst_frame_size(s) ((s - 2)->data.dwords[0])
|
||||||
|
#define dst_frame_prevsize(s) ((s - 2)->data.dwords[1])
|
||||||
|
#define dst_frame_args(s) ((s - 3)->data.dwords[0])
|
||||||
|
#define dst_frame_ret(s) ((s - 3)->data.dwords[1])
|
||||||
|
#define dst_frame_pc(s) ((s - 4)->data.u16p)
|
||||||
|
#define dst_frame_env(s) ((s - 5)->data.env)
|
||||||
|
|
||||||
|
/* C function helpers */
|
||||||
|
|
||||||
|
/* Return in a c function */
|
||||||
|
#define dst_c_return(vm, x) do { (vm)->ret = (x); return DST_RETURN_OK; } while (0)
|
||||||
|
|
||||||
|
/* Throw error from a c function */
|
||||||
|
#define dst_c_throw(vm, e) do { (vm)->ret = (e); return DST_RETURN_ERROR; } while (0)
|
||||||
|
|
||||||
|
/* Throw c string error from a c function */
|
||||||
|
#define dst_c_throwc(vm, e) dst_c_throw((vm), dst_string_cv((vm), (e)))
|
||||||
|
|
||||||
|
/* Assert from a c function */
|
||||||
|
#define dst_c_assert(vm, cond, e) do { if (cond) dst_c_throw((vm), (e)); } while (0)
|
||||||
|
|
||||||
|
/* What to do when out of memory */
|
||||||
|
#ifndef DST_OUT_OF_MEMORY
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#define DST_OUT_OF_MEMORY do { printf("out of memory\n"); exit(1); } while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* What to do when memory is low */
|
||||||
|
#ifndef DST_LOW_MEMORY
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#define DST_LOW_MEMORY do { printf("low memory\n"); } while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* A general dst value type */
|
||||||
|
typedef struct DstValue DstValue;
|
||||||
|
|
||||||
|
/* All of the dst types */
|
||||||
|
typedef double DstReal;
|
||||||
|
typedef int64_t DstInteger;
|
||||||
|
typedef int DstBoolean;
|
||||||
|
typedef struct DstFunction DstFunction;
|
||||||
|
typedef struct DstArray DstArray;
|
||||||
|
typedef struct DstBuffer DstBuffer;
|
||||||
|
typedef struct DstTable DstTable;
|
||||||
|
typedef struct DstThread DstThread;
|
||||||
|
|
||||||
|
/* Other structs */
|
||||||
|
typedef struct DstUserdataHeader DstUserdataHeader;
|
||||||
|
typedef struct DstFuncDef DstFuncDef;
|
||||||
|
typedef struct DstFuncEnv DstFuncEnv;
|
||||||
|
typedef union DstValueUnion DstValueUnion;
|
||||||
|
typedef struct DstModuleItem DstModuleItem;
|
||||||
|
typedef struct DstUserType DstUserType;
|
||||||
|
typedef struct DstParser DstParser;
|
||||||
|
typedef struct DstParseState DstParseState;
|
||||||
|
|
||||||
|
/* C Api data types */
|
||||||
|
struct DstModuleItem {
|
||||||
|
const char *name;
|
||||||
|
DstCFunction data;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Union datatype */
|
||||||
|
union DstValueUnion {
|
||||||
|
DstBoolean boolean;
|
||||||
|
DstReal real;
|
||||||
|
DstInteger integer;
|
||||||
|
DstArray *array;
|
||||||
|
DstBuffer *buffer;
|
||||||
|
DstTable *table;
|
||||||
|
DstThread *thread;
|
||||||
|
const DstValue *tuple;
|
||||||
|
DstCFunction cfunction;
|
||||||
|
DstFunction *function;
|
||||||
|
DstFuncEnv *env;
|
||||||
|
DstFuncDef *def;
|
||||||
|
const DstValue *st;
|
||||||
|
const uint8_t *string;
|
||||||
|
/* Indirectly used union members */
|
||||||
|
uint16_t *u16p;
|
||||||
|
uint32_t dwords[2];
|
||||||
|
uint16_t words[4];
|
||||||
|
uint8_t bytes[8];
|
||||||
|
void *pointer;
|
||||||
|
const char *cstring;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* The general dst value type. Contains a large union and
|
||||||
|
* the type information of the value */
|
||||||
|
struct DstValue {
|
||||||
|
DstType type;
|
||||||
|
DstValueUnion data;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* A lightweight green thread in dst. Does not correspond to
|
||||||
|
* operating system threads. */
|
||||||
|
struct DstThread {
|
||||||
|
uint32_t count;
|
||||||
|
uint32_t capacity;
|
||||||
|
DstValue *data;
|
||||||
|
DstThread *parent;
|
||||||
|
enum {
|
||||||
|
DST_THREAD_PENDING = 0,
|
||||||
|
DST_THREAD_ALIVE,
|
||||||
|
DST_THREAD_DEAD,
|
||||||
|
DST_THREAD_ERROR
|
||||||
|
} status;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* A dynamic array type. */
|
||||||
|
struct DstArray {
|
||||||
|
uint32_t count;
|
||||||
|
uint32_t capacity;
|
||||||
|
DstValue *data;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* A bytebuffer type. Used as a mutable string or string builder. */
|
||||||
|
struct DstBuffer {
|
||||||
|
uint32_t count;
|
||||||
|
uint32_t capacity;
|
||||||
|
uint8_t *data;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* A mutable associative data type. Backed by a hashtable. */
|
||||||
|
struct DstTable {
|
||||||
|
uint32_t count;
|
||||||
|
uint32_t capacity;
|
||||||
|
uint32_t deleted;
|
||||||
|
DstValue *data;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Some function defintion flags */
|
||||||
|
#define DST_FUNCDEF_FLAG_VARARG 1
|
||||||
|
#define DST_FUNCDEF_FLAG_NEEDSPARENT 2
|
||||||
|
#define DST_FUNCDEF_FLAG_NEEDSENV 4
|
||||||
|
|
||||||
|
/* A function definition. Contains information need to instantiate closures. */
|
||||||
|
struct DstFuncDef {
|
||||||
|
uint32_t locals;
|
||||||
|
uint32_t arity; /* Not including varargs */
|
||||||
|
uint32_t literalsLen;
|
||||||
|
uint32_t byteCodeLen;
|
||||||
|
uint32_t flags;
|
||||||
|
DstValue *literals; /* Contains strings, FuncDefs, etc. */
|
||||||
|
uint16_t *byteCode;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* A fuction environment */
|
||||||
|
struct DstFuncEnv {
|
||||||
|
DstThread *thread; /* When nil, index the local values */
|
||||||
|
uint32_t stackOffset; /* Used as environment size when off stack */
|
||||||
|
DstValue *values;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* A function */
|
||||||
|
struct DstFunction {
|
||||||
|
DstFuncDef *def;
|
||||||
|
DstFuncEnv *env;
|
||||||
|
DstFunction *parent;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Defines a type for userdata */
|
||||||
|
struct DstUserType {
|
||||||
|
const char *name;
|
||||||
|
int (*serialize)(Dst *vm, void *data, uint32_t len);
|
||||||
|
int (*deserialize)(Dst *vm);
|
||||||
|
void (*finalize)(Dst *vm, void *data, uint32_t len);
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Contains information about userdata */
|
||||||
|
struct DstUserdataHeader {
|
||||||
|
uint32_t size;
|
||||||
|
const DstUserType *type;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* The VM state */
|
||||||
|
struct Dst {
|
||||||
|
/* Garbage collection */
|
||||||
|
void *blocks;
|
||||||
|
uint32_t memoryInterval;
|
||||||
|
uint32_t nextCollection;
|
||||||
|
uint32_t black : 1;
|
||||||
|
/* Immutable value cache */
|
||||||
|
DstValue *cache;
|
||||||
|
uint32_t cache_capacity;
|
||||||
|
uint32_t cache_count;
|
||||||
|
uint32_t cache_deleted;
|
||||||
|
/* GC roots */
|
||||||
|
DstThread *thread;
|
||||||
|
DstTable *modules;
|
||||||
|
DstTable *registry;
|
||||||
|
DstTable *env;
|
||||||
|
/* Return state */
|
||||||
|
DstValue ret;
|
||||||
|
uint32_t flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Bytecode */
|
||||||
|
enum DstOpCode {
|
||||||
|
DST_OP_FLS, /* Load false */
|
||||||
|
DST_OP_TRU, /* Load true */
|
||||||
|
DST_OP_NIL, /* Load nil */
|
||||||
|
DST_OP_UPV, /* Load upvalue */
|
||||||
|
DST_OP_JIF, /* Jump if */
|
||||||
|
DST_OP_JMP, /* Jump */
|
||||||
|
DST_OP_SUV, /* Set upvalue */
|
||||||
|
DST_OP_CST, /* Load constant */
|
||||||
|
DST_OP_I16, /* Load 16 bit signed integer */
|
||||||
|
DST_OP_I32, /* Load 32 bit signed integer */
|
||||||
|
DST_OP_I64, /* Load 64 bit signed integer */
|
||||||
|
DST_OP_F64, /* Load 64 bit IEEE double */
|
||||||
|
DST_OP_MOV, /* Move value */
|
||||||
|
DST_OP_CLN, /* Create a closure */
|
||||||
|
DST_OP_ARR, /* Create array */
|
||||||
|
DST_OP_DIC, /* Create object */
|
||||||
|
DST_OP_TUP, /* Create tuple */
|
||||||
|
DST_OP_RET, /* Return from function */
|
||||||
|
DST_OP_RTN, /* Return nil */
|
||||||
|
DST_OP_PSK, /* Push stack */
|
||||||
|
DST_OP_PAR, /* Push array or tuple */
|
||||||
|
DST_OP_CAL, /* Call function */
|
||||||
|
DST_OP_TCL, /* Tail call */
|
||||||
|
DST_OP_TRN /* Transfer to new thread */
|
||||||
|
};
|
||||||
|
|
||||||
|
/****/
|
||||||
|
/* Internal buffer functions */
|
||||||
|
/****/
|
||||||
|
void dst_value_buffer_ensure(Dst *vm, DstBuffer *buffer, uint32_t capacity);
|
||||||
|
void dst_buffer_append_bytes(Dst *vm, DstBuffer *buffer, const uint8_t *string, uint32_t length);
|
||||||
|
void dst_buffer_append_cstring(Dst *vm, DstBuffer *buffer, const char *cstring);
|
||||||
|
|
||||||
|
/* Define a push function for pushing a certain type to the buffer */
|
||||||
|
#define BUFFER_DEFINE(name, type) \
|
||||||
|
static void dst_buffer_push_##name(Dst *vm, DstBuffer *buffer, type x) { \
|
||||||
|
union { type t; uint8_t bytes[sizeof(type)]; } u; \
|
||||||
|
u.t = x; dst_buffer_append(vm, buffer, u.bytes, sizeof(type)); \
|
||||||
|
}
|
||||||
|
|
||||||
|
/****/
|
||||||
|
/* Table functions */
|
||||||
|
/****/
|
||||||
|
DstArray *dst_make_array(Dst *vm, uint32_t capacity);
|
||||||
|
|
||||||
|
/****/
|
||||||
|
/* Tuple functions */
|
||||||
|
/****/
|
||||||
|
|
||||||
|
DstValue *dst_tuple_begin(Dst *vm, uint32_t length);
|
||||||
|
const DstValue *dst_tuple_end(Dst *vm, DstValue *tuple);
|
||||||
|
|
||||||
|
/****/
|
||||||
|
/* String/Symbol functions */
|
||||||
|
/****/
|
||||||
|
|
||||||
|
uint8_t *dst_string_begin(Dst *vm, uint32_t len);
|
||||||
|
void dst_string_end(Dst *vm, uint32_t dest, uint8_t *str);
|
||||||
|
const uint8_t *dst_string_b(Dst *vm, const uint8_t *buf, uint32_t len);
|
||||||
|
const uint8_t *dst_string_c(Dst *vm, const char *cstring);
|
||||||
|
DstValue dst_string_cv(Dst *vm, const char *string);
|
||||||
|
DstValue dst_string_cvs(Dst *vm, const char *string);
|
||||||
|
int dst_string_compare(const uint8_t *lhs, const uint8_t *rhs);
|
||||||
|
const uint8_t *dst_string_bu(Dst *vm, const uint8_t *buf, uint32_t len);
|
||||||
|
const uint8_t *dst_string_cu(Dst *vm, const char *s);
|
||||||
|
|
||||||
|
/****/
|
||||||
|
/* Struct functions */
|
||||||
|
/****/
|
||||||
|
|
||||||
|
DstValue *dst_struct_begin(Dst *vm, uint32_t count);
|
||||||
|
void dst_struct_put(DstValue *st, DstValue key, DstValue value);
|
||||||
|
const DstValue *dst_struct_end(Dst *vm, DstValue *st);
|
||||||
|
DstValue dst_struct_get(const DstValue *st, DstValue key);
|
||||||
|
DstValue dst_struct_next(const DstValue *st, DstValue key);
|
||||||
|
|
||||||
|
/****/
|
||||||
|
/* Table functions */
|
||||||
|
/****/
|
||||||
|
|
||||||
|
DstTable *dst_make_table(Dst *vm, uint32_t capacity);
|
||||||
|
DstValue dst_table_get(DstTable *t, DstValue key);
|
||||||
|
DstValue dst_table_remove(DstTable *t, DstValue key);
|
||||||
|
void dst_table_put(Dst *vm, DstTable *t, DstValue key, DstValue value);
|
||||||
|
DstValue dst_table_next(DstTable *o, DstValue key);
|
||||||
|
|
||||||
|
/****/
|
||||||
|
/* Threads */
|
||||||
|
/****/
|
||||||
|
|
||||||
|
#define dst_thread_stack(t) ((t)->data + (t)->count)
|
||||||
|
DstThread *dst_thread(Dst *vm, DstValue callee, uint32_t capacity);
|
||||||
|
DstThread *dst_thread_reset(Dst *vm, DstThread *thread, DstValue callee);
|
||||||
|
void dst_thread_ensure_extra(Dst *vm, DstThread *thread, uint32_t extra);
|
||||||
|
void dst_thread_push(Dst *vm, DstThread *thread, DstValue x);
|
||||||
|
void dst_thread_pushnil(Dst *vm, DstThread *thread, uint32_t n);
|
||||||
|
void dst_thread_tuplepack(Dst *vm, DstThread *thread, uint32_t n);
|
||||||
|
DstValue *dst_thread_beginframe(Dst *vm, DstThread *thread, DstValue callee, uint32_t arity);
|
||||||
|
void dst_thread_endframe(Dst *vm, DstThread *thread);
|
||||||
|
DstValue *dst_thread_popframe(Dst *vm, DstThread *thread);
|
||||||
|
uint32_t dst_thread_countframes(DstThread *thread);
|
||||||
|
|
||||||
|
/****/
|
||||||
|
/* Serialization */
|
||||||
|
/****/
|
||||||
|
|
||||||
|
const char *dst_deserialize_internal(
|
||||||
|
Dst *vm,
|
||||||
|
const uint8_t *data,
|
||||||
|
uint32_t len,
|
||||||
|
DstValue *out,
|
||||||
|
const uint8_t **nextData);
|
||||||
|
|
||||||
|
const char *dst_serialize_internal(Dst *vm, DstBuffer *buffer, DstValue x);
|
||||||
|
|
||||||
|
/****/
|
||||||
|
/* GC */
|
||||||
|
/****/
|
||||||
|
|
||||||
|
#define DST_MEMTAG_STRING 4
|
||||||
|
#define DST_MEMTAG_TUPLE 8
|
||||||
|
#define DST_MEMTAG_STRUCT 16
|
||||||
|
#define DST_MEMTAG_USER 32
|
||||||
|
|
||||||
|
void dst_mark_value(Dst *vm, DstValue x);
|
||||||
|
void dst_mark(Dst *vm, DstValueUnion x, DstType type);
|
||||||
|
void dst_sweep(Dst *vm);
|
||||||
|
void *dst_alloc(Dst *vm, uint32_t size);
|
||||||
|
void *dst_zalloc(Dst *vm, uint32_t size);
|
||||||
|
void dst_mem_tag(void *mem, uint32_t tags);
|
||||||
|
void dst_collect(Dst *vm);
|
||||||
|
void dst_maybe_collect(Dst *vm);
|
||||||
|
void dst_clear_memory(Dst *vm);
|
||||||
|
void dst_mark_mem(Dst *vm, void *mem);
|
||||||
|
|
||||||
|
/****/
|
||||||
|
/* VM */
|
||||||
|
/****/
|
||||||
|
|
||||||
|
DstValue dst_arg(Dst *vm, uint32_t index);
|
||||||
|
void dst_set_arg(Dst *vm, uint32_t index, DstValue x);
|
||||||
|
uint32_t dst_args(Dst *vm);
|
||||||
|
|
||||||
|
/***/
|
||||||
|
/* Stl */
|
||||||
|
/***/
|
||||||
|
|
||||||
|
void dst_stl_load(Dst *vm);
|
||||||
|
|
||||||
|
/****/
|
||||||
|
/* C Api */
|
||||||
|
/****/
|
||||||
|
|
||||||
|
void dst_module(Dst *vm, const char *name, const DstModuleItem *mod);
|
||||||
|
void dst_module_mutable(Dst *vm, const char *name, const DstModuleItem *mod);
|
||||||
|
void dst_module_put(Dst *vm, const char *packagename, const char *name, DstValue x);
|
||||||
|
DstValue dst_module_get(Dst *vm, const char *packagename);
|
||||||
|
void dst_register_put(Dst *vm, const char *packagename, DstValue mod);
|
||||||
|
DstValue dst_register_get(Dst *vm, const char *name);
|
||||||
|
int dst_callc(Dst *vm, DstCFunction fn, int numargs, ...);
|
||||||
|
|
||||||
|
/* Treat similar types through uniform interfaces for iteration */
|
||||||
|
int dst_seq_view(DstValue seq, const DstValue **data, uint32_t *len);
|
||||||
|
int dst_chararray_view(DstValue str, const uint8_t **data, uint32_t *len);
|
||||||
|
int dst_hashtable_view(DstValue tab, const DstValue **data, uint32_t *cap);
|
||||||
|
|
||||||
|
/****/
|
||||||
|
/* Caching for immutable data */
|
||||||
|
/****/
|
||||||
|
|
||||||
|
void dst_cache_remove_string(Dst *vm, char *strmem);
|
||||||
|
void dst_cache_remove_tuple(Dst *vm, char *tuplemem);
|
||||||
|
void dst_cache_remove_struct(Dst *vm, char *structmem);
|
||||||
|
|
||||||
|
/****/
|
||||||
|
/* Misc */
|
||||||
|
/****/
|
||||||
|
|
||||||
|
uint32_t dst_index(Dst *vm, int i);
|
||||||
|
int dst_read_real(const uint8_t *string, const uint8_t *end, double *ret, int forceInt);
|
||||||
|
int dst_read_integer(const uint8_t *string, const uint8_t *end, int64_t *ret);
|
||||||
|
DstReal dst_integer_to_real(DstInteger x);
|
||||||
|
DstInteger dst_real_to_integer(DstReal x);
|
||||||
|
uint32_t dst_startrange(DstInteger raw, uint32_t len);
|
||||||
|
uint32_t dst_endrange(DstInteger raw, uint32_t len);
|
||||||
|
void dst_env_merge(Dst *vm, DstTable *destEnv, DstTable *srcEnv);
|
||||||
|
DstTable *dst_env_nils(Dst *vm, DstTable *env);
|
||||||
|
DstTable *dst_env_meta(Dst *vm, DstTable *env);
|
||||||
|
void dst_env_put(Dst *vm, DstTable *env, DstValue key, DstValue value);
|
||||||
|
void dst_env_putc(Dst *vm, DstTable *env, const char *key, DstValue value);
|
||||||
|
void dst_env_putvar(Dst *vm, DstTable *env, DstValue key, DstValue value);
|
||||||
|
void dst_env_putvarc(Dst *vm, DstTable *env, const char *key, DstValue value);
|
||||||
|
|
||||||
|
/****/
|
||||||
|
/* Value functions */
|
||||||
|
/****/
|
||||||
|
|
||||||
|
int dst_value_truthy(DstValue v);
|
||||||
|
int dst_value_equals(DstValue x, DstValue y);
|
||||||
|
uint32_t dst_value_hash(DstValue x);
|
||||||
|
int dst_value_compare(DstValue x, DstValue y);
|
||||||
|
|
||||||
|
/* Wrap data in GstValue */
|
||||||
|
DstValue dst_wrap_nil();
|
||||||
|
DstValue dst_wrap_real(DstReal x);
|
||||||
|
DstValue dst_wrap_integer(DstInteger x);
|
||||||
|
DstValue dst_wrap_boolean(int x);
|
||||||
|
DstValue dst_wrap_string(const uint8_t *x);
|
||||||
|
DstValue dst_wrap_symbol(const uint8_t *x);
|
||||||
|
DstValue dst_wrap_array(DstArray *x);
|
||||||
|
DstValue dst_wrap_tuple(const DstValue *x);
|
||||||
|
DstValue dst_wrap_struct(const DstValue *x);
|
||||||
|
DstValue dst_wrap_thread(DstThread *x);
|
||||||
|
DstValue dst_wrap_buffer(DstBuffer *x);
|
||||||
|
DstValue dst_wrap_function(DstFunction *x);
|
||||||
|
DstValue dst_wrap_cfunction(DstCFunction x);
|
||||||
|
DstValue dst_wrap_table(DstTable *x);
|
||||||
|
DstValue dst_wrap_userdata(void *x);
|
||||||
|
DstValue dst_wrap_funcenv(DstFuncEnv *x);
|
||||||
|
DstValue dst_wrap_funcdef(DstFuncDef *x);
|
||||||
|
|
||||||
|
/* Check data from arguments */
|
||||||
|
int dst_check_nil(Dst *vm, uint32_t i);
|
||||||
|
int dst_check_real(Dst *vm, uint32_t i);
|
||||||
|
int dst_check_integer(Dst *vm, uint32_t i);
|
||||||
|
int dst_check_boolean(Dst *vm, uint32_t i);
|
||||||
|
int dst_check_string(Dst *vm, uint32_t i);
|
||||||
|
int dst_check_symbol(Dst *vm, uint32_t i);
|
||||||
|
int dst_check_array(Dst *vm, uint32_t i);
|
||||||
|
int dst_check_tuple(Dst *vm, uint32_t i);
|
||||||
|
int dst_check_struct(Dst *vm, uint32_t i);
|
||||||
|
int dst_check_thread(Dst *vm, uint32_t i);
|
||||||
|
int dst_check_buffer(Dst *vm, uint32_t i);
|
||||||
|
int dst_check_function(Dst *vm, uint32_t i);
|
||||||
|
int dst_check_cfunction(Dst *vm, uint32_t i);
|
||||||
|
int dst_check_table(Dst *vm, uint32_t i);
|
||||||
|
int dst_check_funcenv(Dst *vm, uint32_t i);
|
||||||
|
int dst_check_funcdef(Dst *vm, uint32_t i);
|
||||||
|
void dst_check_userdata(Dst *vm, uint32_t i;
|
||||||
|
|
||||||
|
#endif /* DST_INTERNAL_H_defined */
|
@ -20,82 +20,82 @@
|
|||||||
* IN THE SOFTWARE.
|
* IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include "internal.h"
|
||||||
|
|
||||||
static void gst_cmodule_register(Gst *vm, const char *name, const GstModuleItem *mod) {
|
static void dst_cmodule_register(Dst *vm, const char *name, const DstModuleItem *mod) {
|
||||||
uint32_t startLength;
|
uint32_t startLength;
|
||||||
GstBuffer *buffer = gst_buffer(vm, 10);
|
DstBuffer *buffer = dst_buffer(vm, 10);
|
||||||
gst_buffer_append_cstring(vm, buffer, name);
|
dst_buffer_append_cstring(vm, buffer, name);
|
||||||
gst_buffer_push(vm, buffer, '.');
|
dst_buffer_push(vm, buffer, '.');
|
||||||
startLength = buffer->count;
|
startLength = buffer->count;
|
||||||
while (mod->name != NULL) {
|
while (mod->name != NULL) {
|
||||||
GstValue key;
|
DstValue key;
|
||||||
buffer->count = startLength;
|
buffer->count = startLength;
|
||||||
gst_buffer_append_cstring(vm, buffer, mod->name);
|
dst_buffer_append_cstring(vm, buffer, mod->name);
|
||||||
key = gst_wrap_symbol(gst_buffer_to_string(vm, buffer));
|
key = dst_wrap_symbol(dst_buffer_to_string(vm, buffer));
|
||||||
gst_table_put(vm, vm->registry, key, gst_wrap_cfunction(mod->data));
|
dst_table_put(vm, vm->registry, key, dst_wrap_cfunction(mod->data));
|
||||||
gst_table_put(vm, vm->registry, gst_wrap_cfunction(mod->data), key);
|
dst_table_put(vm, vm->registry, dst_wrap_cfunction(mod->data), key);
|
||||||
mod++;
|
mod++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstValue gst_cmodule_table(Gst *vm, const GstModuleItem *mod) {
|
static DstValue dst_cmodule_table(Dst *vm, const DstModuleItem *mod) {
|
||||||
GstTable *module = gst_table(vm, 10);
|
DstTable *module = dst_table(vm, 10);
|
||||||
while (mod->name != NULL) {
|
while (mod->name != NULL) {
|
||||||
GstValue key = gst_string_cvs(vm, mod->name);
|
DstValue key = dst_string_cvs(vm, mod->name);
|
||||||
gst_table_put(vm, module, key, gst_wrap_cfunction(mod->data));
|
dst_table_put(vm, module, key, dst_wrap_cfunction(mod->data));
|
||||||
mod++;
|
mod++;
|
||||||
}
|
}
|
||||||
return gst_wrap_table(module);
|
return dst_wrap_table(module);
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstValue gst_cmodule_struct(Gst *vm, const GstModuleItem *mod) {
|
static DstValue dst_cmodule_struct(Dst *vm, const DstModuleItem *mod) {
|
||||||
uint32_t count = 0;
|
uint32_t count = 0;
|
||||||
const GstModuleItem *m = mod;
|
const DstModuleItem *m = mod;
|
||||||
GstValue *st;
|
DstValue *st;
|
||||||
while (m->name != NULL) {
|
while (m->name != NULL) {
|
||||||
++count;
|
++count;
|
||||||
++m;
|
++m;
|
||||||
}
|
}
|
||||||
st = gst_struct_begin(vm, count);
|
st = dst_struct_begin(vm, count);
|
||||||
m = mod;
|
m = mod;
|
||||||
while (m->name != NULL) {
|
while (m->name != NULL) {
|
||||||
gst_struct_put(st,
|
dst_struct_put(st,
|
||||||
gst_string_cvs(vm, m->name),
|
dst_string_cvs(vm, m->name),
|
||||||
gst_wrap_cfunction(m->data));
|
dst_wrap_cfunction(m->data));
|
||||||
++m;
|
++m;
|
||||||
}
|
}
|
||||||
return gst_wrap_struct(gst_struct_end(vm, st));
|
return dst_wrap_struct(dst_struct_end(vm, st));
|
||||||
}
|
}
|
||||||
|
|
||||||
void gst_module(Gst *vm, const char *packagename, const GstModuleItem *mod) {
|
void dst_module(Dst *vm, const char *packagename, const DstModuleItem *mod) {
|
||||||
gst_table_put(vm, vm->modules, gst_string_cvs(vm, packagename), gst_cmodule_struct(vm, mod));
|
dst_table_put(vm, vm->modules, dst_string_cvs(vm, packagename), dst_cmodule_struct(vm, mod));
|
||||||
gst_cmodule_register(vm, packagename, mod);
|
dst_cmodule_register(vm, packagename, mod);
|
||||||
}
|
}
|
||||||
|
|
||||||
void gst_module_mutable(Gst *vm, const char *packagename, const GstModuleItem *mod) {
|
void dst_module_mutable(Dst *vm, const char *packagename, const DstModuleItem *mod) {
|
||||||
gst_table_put(vm, vm->modules, gst_string_cvs(vm, packagename), gst_cmodule_table(vm, mod));
|
dst_table_put(vm, vm->modules, dst_string_cvs(vm, packagename), dst_cmodule_table(vm, mod));
|
||||||
gst_cmodule_register(vm, packagename, mod);
|
dst_cmodule_register(vm, packagename, mod);
|
||||||
}
|
}
|
||||||
|
|
||||||
void gst_module_put(Gst *vm, const char *packagename, const char *name, GstValue v) {
|
void dst_module_put(Dst *vm, const char *packagename, const char *name, DstValue v) {
|
||||||
GstValue modtable = gst_table_get(vm->modules, gst_string_cvs(vm, packagename));
|
DstValue modtable = dst_table_get(vm->modules, dst_string_cvs(vm, packagename));
|
||||||
if (modtable.type == GST_TABLE) {
|
if (modtable.type == DST_TABLE) {
|
||||||
GstTable *table = modtable.data.table;
|
DstTable *table = modtable.data.table;
|
||||||
if (v.type == GST_CFUNCTION) {
|
if (v.type == DST_CFUNCTION) {
|
||||||
GstValue key;
|
DstValue key;
|
||||||
GstBuffer *buffer = gst_buffer(vm, 10);
|
DstBuffer *buffer = dst_buffer(vm, 10);
|
||||||
gst_buffer_append_cstring(vm, buffer, packagename);
|
dst_buffer_append_cstring(vm, buffer, packagename);
|
||||||
gst_buffer_push(vm, buffer, '.');
|
dst_buffer_push(vm, buffer, '.');
|
||||||
gst_buffer_append_cstring(vm, buffer, name);
|
dst_buffer_append_cstring(vm, buffer, name);
|
||||||
key = gst_wrap_string(gst_buffer_to_string(vm, buffer));
|
key = dst_wrap_string(dst_buffer_to_string(vm, buffer));
|
||||||
gst_table_put(vm, vm->registry, key, v);
|
dst_table_put(vm, vm->registry, key, v);
|
||||||
gst_table_put(vm, vm->registry, v, key);
|
dst_table_put(vm, vm->registry, v, key);
|
||||||
}
|
}
|
||||||
gst_table_put(vm, table, gst_string_cvs(vm, name), v);
|
dst_table_put(vm, table, dst_string_cvs(vm, name), v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GstValue gst_module_get(Gst *vm, const char *packagename) {
|
DstValue dst_module_get(Dst *vm, const char *packagename) {
|
||||||
return gst_table_get(vm->modules, gst_string_cvs(vm, packagename));
|
return dst_table_get(vm->modules, dst_string_cvs(vm, packagename));
|
||||||
}
|
}
|
431
core/parse.c
431
core/parse.c
@ -1,431 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2017 Calvin Rose
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to
|
|
||||||
* deal in the Software without restriction, including without limitation the
|
|
||||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
||||||
* sell copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
||||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
||||||
* IN THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <gst/gst.h>
|
|
||||||
|
|
||||||
static const char UNEXPECTED_CLOSING_DELIM[] = "unexpected closing delimiter";
|
|
||||||
|
|
||||||
/* Handle error in parsing */
|
|
||||||
#define p_error(p, e) ((p)->error = (e), (p)->status = GST_PARSER_ERROR)
|
|
||||||
|
|
||||||
/* Get the top ParseState in the parse stack */
|
|
||||||
static GstParseState *parser_peek(GstParser *p) {
|
|
||||||
if (!p->count) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return p->data + (p->count - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Remove the top state from the ParseStack */
|
|
||||||
static GstParseState *parser_pop(GstParser * p) {
|
|
||||||
if (!p->count) {
|
|
||||||
p_error(p, "parser stack underflow");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return p->data + --p->count;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Quote a value */
|
|
||||||
static GstValue quote(GstParser *p, GstValue x) {
|
|
||||||
GstValue *tuple = gst_tuple_begin(p->vm, 2);
|
|
||||||
tuple[0] = gst_string_cvs(p->vm, "quote");
|
|
||||||
tuple[1] = x;
|
|
||||||
return gst_wrap_tuple(gst_tuple_end(p->vm, tuple));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add a new, empty ParseState to the ParseStack. */
|
|
||||||
static void parser_push(GstParser *p, ParseType type, uint8_t character) {
|
|
||||||
GstParseState *top;
|
|
||||||
if (p->count >= p->cap) {
|
|
||||||
uint32_t newCap = 2 * p->count + 2;
|
|
||||||
GstParseState *data = gst_alloc(p->vm, newCap * sizeof(GstParseState));
|
|
||||||
gst_memcpy(data, p->data, p->cap * sizeof(GstParseState));
|
|
||||||
p->data = data;
|
|
||||||
p->cap = newCap;
|
|
||||||
}
|
|
||||||
++p->count;
|
|
||||||
top = parser_peek(p);
|
|
||||||
if (!top) return;
|
|
||||||
top->type = type;
|
|
||||||
top->quoteCount = p->quoteCount;
|
|
||||||
p->quoteCount = 0;
|
|
||||||
switch (type) {
|
|
||||||
case PTYPE_STRING:
|
|
||||||
top->buf.string.state = STRING_STATE_BASE;
|
|
||||||
top->buf.string.buffer = gst_buffer(p->vm, 10);
|
|
||||||
break;
|
|
||||||
case PTYPE_TOKEN:
|
|
||||||
top->buf.string.buffer = gst_buffer(p->vm, 10);
|
|
||||||
break;
|
|
||||||
case PTYPE_FORM:
|
|
||||||
top->buf.form.array = gst_array(p->vm, 10);
|
|
||||||
if (character == '(') top->buf.form.endDelimiter = ')';
|
|
||||||
if (character == '[') top->buf.form.endDelimiter = ']';
|
|
||||||
if (character == '{') top->buf.form.endDelimiter = '}';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Append a value to the top-most state in the Parser's stack. */
|
|
||||||
static void parser_append(GstParser *p, GstValue x) {
|
|
||||||
GstParseState *oldtop = parser_pop(p);
|
|
||||||
GstParseState *top = parser_peek(p);
|
|
||||||
while (oldtop->quoteCount--)
|
|
||||||
x = quote(p, x);
|
|
||||||
if (!top) {
|
|
||||||
p->value = x;
|
|
||||||
p->status = GST_PARSER_FULL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
switch (top->type) {
|
|
||||||
case PTYPE_FORM:
|
|
||||||
gst_array_push(p->vm, top->buf.form.array, x);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
p_error(p, "expected container type");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check if a character is whitespace */
|
|
||||||
static int is_whitespace(uint8_t c) {
|
|
||||||
return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\0' || c == ',';
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check if a character is a valid symbol character */
|
|
||||||
static int is_symbol_char(uint8_t c) {
|
|
||||||
if (c >= 'a' && c <= 'z') return 1;
|
|
||||||
if (c >= 'A' && c <= 'Z') return 1;
|
|
||||||
if (c >= '0' && c <= ':') return 1;
|
|
||||||
if (c >= '<' && c <= '@') return 1;
|
|
||||||
if (c >= '*' && c <= '/') return 1;
|
|
||||||
if (c >= '#' && c <= '&') return 1;
|
|
||||||
if (c == '_') return 1;
|
|
||||||
if (c == '^') return 1;
|
|
||||||
if (c == '!') return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Checks if a string slice is equal to a string constant */
|
|
||||||
static int check_str_const(const char *ref, const uint8_t *start, const uint8_t *end) {
|
|
||||||
while (*ref && start < end) {
|
|
||||||
if (*ref != *(char *)start) return 0;
|
|
||||||
++ref;
|
|
||||||
++start;
|
|
||||||
}
|
|
||||||
return !*ref && start == end;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Build from the token buffer */
|
|
||||||
static GstValue build_token(GstParser *p, GstBuffer *buf) {
|
|
||||||
GstValue x;
|
|
||||||
GstReal real;
|
|
||||||
GstInteger integer;
|
|
||||||
uint8_t *data = buf->data;
|
|
||||||
uint8_t *back = data + buf->count;
|
|
||||||
if (gst_read_integer(data, back, &integer)) {
|
|
||||||
x.type = GST_INTEGER;
|
|
||||||
x.data.integer = integer;
|
|
||||||
} else if (gst_read_real(data, back, &real, 0)) {
|
|
||||||
x.type = GST_REAL;
|
|
||||||
x.data.real = real;
|
|
||||||
} else if (check_str_const("nil", data, back)) {
|
|
||||||
x.type = GST_NIL;
|
|
||||||
x.data.boolean = 0;
|
|
||||||
} else if (check_str_const("false", data, back)) {
|
|
||||||
x.type = GST_BOOLEAN;
|
|
||||||
x.data.boolean = 0;
|
|
||||||
} else if (check_str_const("true", data, back)) {
|
|
||||||
x.type = GST_BOOLEAN;
|
|
||||||
x.data.boolean = 1;
|
|
||||||
} else {
|
|
||||||
if (buf->data[0] >= '0' && buf->data[0] <= '9') {
|
|
||||||
p_error(p, "symbols cannot start with digits");
|
|
||||||
x.type = GST_NIL;
|
|
||||||
} else if (buf->data[0] == ':' && buf->count >= 2) {
|
|
||||||
x.type = GST_STRING;
|
|
||||||
x.data.string = gst_string_b(p->vm, buf->data + 1, buf->count - 1);
|
|
||||||
} else {
|
|
||||||
x.type = GST_SYMBOL;
|
|
||||||
x.data.string = gst_buffer_to_string(p->vm, buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Handle parsing a token */
|
|
||||||
static int token_state(GstParser *p, uint8_t c) {
|
|
||||||
GstParseState *top = parser_peek(p);
|
|
||||||
GstBuffer *buf = top->buf.string.buffer;
|
|
||||||
if (is_whitespace(c) || c == ')' || c == ']' || c == '}') {
|
|
||||||
parser_append(p, build_token(p, buf));
|
|
||||||
return !(c == ')' || c == ']' || c == '}');
|
|
||||||
} else if (is_symbol_char(c)) {
|
|
||||||
gst_buffer_push(p->vm, buf, c);
|
|
||||||
return 1;
|
|
||||||
} else {
|
|
||||||
p_error(p, "expected symbol character");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get hex digit from a letter */
|
|
||||||
static int to_hex(uint8_t c) {
|
|
||||||
if (c >= '0' && c <= '9') {
|
|
||||||
return c - '0';
|
|
||||||
} else if (c >= 'a' && c <= 'f') {
|
|
||||||
return 10 + c - 'a';
|
|
||||||
} else if (c >= 'A' && c <= 'F') {
|
|
||||||
return 10 + c - 'A';
|
|
||||||
} else {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Handle parsing a string literal */
|
|
||||||
static int string_state(GstParser *p, uint8_t c) {
|
|
||||||
int digit;
|
|
||||||
GstParseState *top = parser_peek(p);
|
|
||||||
switch (top->buf.string.state) {
|
|
||||||
case STRING_STATE_BASE:
|
|
||||||
if (c == '\\') {
|
|
||||||
top->buf.string.state = STRING_STATE_ESCAPE;
|
|
||||||
} else if (c == '"') {
|
|
||||||
GstValue x;
|
|
||||||
x.type = GST_STRING;
|
|
||||||
x.data.string = gst_buffer_to_string(p->vm, top->buf.string.buffer);
|
|
||||||
parser_append(p, x);
|
|
||||||
} else {
|
|
||||||
gst_buffer_push(p->vm, top->buf.string.buffer, c);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case STRING_STATE_ESCAPE:
|
|
||||||
{
|
|
||||||
uint8_t next;
|
|
||||||
switch (c) {
|
|
||||||
case 'n': next = '\n'; break;
|
|
||||||
case 'r': next = '\r'; break;
|
|
||||||
case 't': next = '\t'; break;
|
|
||||||
case 'f': next = '\f'; break;
|
|
||||||
case '0': next = '\0'; break;
|
|
||||||
case '"': next = '"'; break;
|
|
||||||
case '\'': next = '\''; break;
|
|
||||||
case 'z': next = '\0'; break;
|
|
||||||
case 'e': next = 27; break;
|
|
||||||
case 'h':
|
|
||||||
top->buf.string.state = STRING_STATE_ESCAPE_HEX;
|
|
||||||
top->buf.string.count = 0;
|
|
||||||
top->buf.string.accum = 0;
|
|
||||||
return 1;
|
|
||||||
default:
|
|
||||||
p_error(p, "unknown string escape sequence");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
gst_buffer_push(p->vm, top->buf.string.buffer, next);
|
|
||||||
top->buf.string.state = STRING_STATE_BASE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case STRING_STATE_ESCAPE_HEX:
|
|
||||||
digit = to_hex(c);
|
|
||||||
if (digit < 0) {
|
|
||||||
p_error(p, "invalid hexidecimal digit");
|
|
||||||
return 1;
|
|
||||||
} else {
|
|
||||||
top->buf.string.accum *= 16;
|
|
||||||
top->buf.string.accum += digit;
|
|
||||||
}
|
|
||||||
top->buf.string.accum += digit;
|
|
||||||
if (++top->buf.string.count == 2) {
|
|
||||||
gst_buffer_push(p->vm, top->buf.string.buffer, top->buf.string.accum);
|
|
||||||
top->buf.string.state = STRING_STATE_BASE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case STRING_STATE_ESCAPE_UNICODE:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Root state of the parser */
|
|
||||||
static int root_state(GstParser *p, uint8_t c) {
|
|
||||||
if (is_whitespace(c)) return 1;
|
|
||||||
p->status = GST_PARSER_PENDING;
|
|
||||||
if (c == ']' || c == ')' || c == '}') {
|
|
||||||
p_error(p, UNEXPECTED_CLOSING_DELIM);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (c == '(' || c == '[' || c == '{') {
|
|
||||||
parser_push(p, PTYPE_FORM, c);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (c == '"') {
|
|
||||||
parser_push(p, PTYPE_STRING, c);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (c == '\'') {
|
|
||||||
p->quoteCount++;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (is_symbol_char(c)) {
|
|
||||||
parser_push(p, PTYPE_TOKEN, c);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
p_error(p, "unexpected character");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Handle parsing a form */
|
|
||||||
static int form_state(GstParser *p, uint8_t c) {
|
|
||||||
GstParseState *top = parser_peek(p);
|
|
||||||
if (c == top->buf.form.endDelimiter) {
|
|
||||||
GstArray *array = top->buf.form.array;
|
|
||||||
GstValue x;
|
|
||||||
if (c == ']') {
|
|
||||||
x.type = GST_ARRAY;
|
|
||||||
x.data.array = array;
|
|
||||||
} else if (c == ')') {
|
|
||||||
GstValue *tup;
|
|
||||||
tup = gst_tuple_begin(p->vm, array->count);
|
|
||||||
gst_memcpy(tup, array->data, array->count * sizeof(GstValue));
|
|
||||||
x.type = GST_TUPLE;
|
|
||||||
x.data.tuple = gst_tuple_end(p->vm, tup);
|
|
||||||
} else { /* c == '{' */
|
|
||||||
uint32_t i;
|
|
||||||
if (array->count % 2 != 0) {
|
|
||||||
p_error(p, "table literal must have even number of elements");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
x.type = GST_TABLE;
|
|
||||||
x.data.table = gst_table(p->vm, array->count);
|
|
||||||
for (i = 0; i < array->count; i += 2) {
|
|
||||||
gst_table_put(p->vm, x.data.table, array->data[i], array->data[i + 1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
parser_append(p, x);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return root_state(p, c);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Handle a character */
|
|
||||||
void gst_parse_byte(GstParser *p, uint8_t c) {
|
|
||||||
int done = 0;
|
|
||||||
/* Update position in source */
|
|
||||||
if (c == '\n') {
|
|
||||||
p->line++;
|
|
||||||
p->index = 0;
|
|
||||||
p->comment = GST_PCOMMENT_EXPECTING;
|
|
||||||
} else {
|
|
||||||
++p->index;
|
|
||||||
}
|
|
||||||
/* Check comments */
|
|
||||||
switch (p->comment) {
|
|
||||||
case GST_PCOMMENT_NOT:
|
|
||||||
break;
|
|
||||||
case GST_PCOMMENT_EXPECTING:
|
|
||||||
if (c == '#') {
|
|
||||||
p->comment = GST_PCOMMENT_INSIDE;
|
|
||||||
return;
|
|
||||||
} else if (!is_whitespace(c)) {
|
|
||||||
p->comment = GST_PCOMMENT_NOT;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case GST_PCOMMENT_INSIDE:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/* Dispatch character to state */
|
|
||||||
while (!done) {
|
|
||||||
GstParseState *top = parser_peek(p);
|
|
||||||
if (!top) {
|
|
||||||
done = root_state(p, c);
|
|
||||||
} else {
|
|
||||||
switch (top->type) {
|
|
||||||
case PTYPE_TOKEN:
|
|
||||||
done = token_state(p, c);
|
|
||||||
break;
|
|
||||||
case PTYPE_FORM:
|
|
||||||
done = form_state(p, c);
|
|
||||||
break;
|
|
||||||
case PTYPE_STRING:
|
|
||||||
done = string_state(p, c);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Parse a C style string. The first value encountered when parsed is put
|
|
||||||
* in p->value. The string variable is then updated to the next char that
|
|
||||||
* was not read. Returns 1 if any values were read, otherwise returns 0.
|
|
||||||
* Returns the number of bytes read.
|
|
||||||
*/
|
|
||||||
int gst_parse_cstring(GstParser *p, const char *string) {
|
|
||||||
int bytesRead = 0;
|
|
||||||
if (!string)
|
|
||||||
return 0;
|
|
||||||
while ((p->status == GST_PARSER_PENDING || p->status == GST_PARSER_ROOT)
|
|
||||||
&& (string[bytesRead] != '\0')) {
|
|
||||||
gst_parse_byte(p, string[bytesRead++]);
|
|
||||||
}
|
|
||||||
return bytesRead;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Parse a gst string */
|
|
||||||
int gst_parse_string(GstParser *p, const uint8_t *string) {
|
|
||||||
uint32_t i;
|
|
||||||
if (!string)
|
|
||||||
return 0;
|
|
||||||
for (i = 0; i < gst_string_length(string); ++i) {
|
|
||||||
if (p->status != GST_PARSER_PENDING && p->status != GST_PARSER_ROOT) break;
|
|
||||||
gst_parse_byte(p, string[i]);
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check if a parser has a value that needs to be handled. If
|
|
||||||
* so, the parser will not parse any more input until that value
|
|
||||||
* is consumed. */
|
|
||||||
int gst_parse_hasvalue(GstParser *p) {
|
|
||||||
return p->status == GST_PARSER_FULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Gets a value from the parser */
|
|
||||||
GstValue gst_parse_consume(GstParser *p) {
|
|
||||||
p->status = GST_PARSER_ROOT;
|
|
||||||
return p->value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Parser initialization (memory allocation) */
|
|
||||||
void gst_parser(GstParser *p, Gst *vm) {
|
|
||||||
p->vm = vm;
|
|
||||||
GstParseState *data = gst_alloc(vm, sizeof(GstParseState) * 10);
|
|
||||||
p->cap = 10;
|
|
||||||
p->data = data;
|
|
||||||
p->count = 0;
|
|
||||||
p->index = 0;
|
|
||||||
p->line = 1;
|
|
||||||
p->quoteCount = 0;
|
|
||||||
p->error = NULL;
|
|
||||||
p->status = GST_PARSER_ROOT;
|
|
||||||
p->value.type = GST_NIL;
|
|
||||||
p->comment = GST_PCOMMENT_EXPECTING;
|
|
||||||
}
|
|
421
core/serialize.c
421
core/serialize.c
@ -20,7 +20,8 @@
|
|||||||
* IN THE SOFTWARE.
|
* IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include <dst/dst.h>
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Data format
|
* Data format
|
||||||
@ -37,7 +38,7 @@
|
|||||||
* Byte 207: Buffer - [u32 capacity][u32 length]*[u8... characters]
|
* Byte 207: Buffer - [u32 capacity][u32 length]*[u8... characters]
|
||||||
* Byte 208: Array - [u32 length]*[value... elements]
|
* Byte 208: Array - [u32 length]*[value... elements]
|
||||||
* Byte 209: Tuple - [u32 length]*[value... elements]
|
* Byte 209: Tuple - [u32 length]*[value... elements]
|
||||||
* Byte 210: Thread - [value parent][value errorParent][u8 state][u32 frames]*[[value callee][value env]
|
* Byte 210: Thread - [value parent][u8 state][u32 frames]*[[value callee][value env]
|
||||||
* [u32 pcoffset][u32 ret][u32 args][u32 size]*[value ...stack]]
|
* [u32 pcoffset][u32 ret][u32 args][u32 size]*[value ...stack]]
|
||||||
* Byte 211: Table - [u32 length]*2*[value... kvs]
|
* Byte 211: Table - [u32 length]*2*[value... kvs]
|
||||||
* Byte 212: FuncDef - [u32 locals][u32 arity][u32 flags][u32 literallen]*[value...
|
* Byte 212: FuncDef - [u32 locals][u32 arity][u32 flags][u32 literallen]*[value...
|
||||||
@ -62,7 +63,7 @@ static uint32_t bytes2u32(const uint8_t *bytes) {
|
|||||||
uint8_t bytes[4];
|
uint8_t bytes[4];
|
||||||
uint32_t u32;
|
uint32_t u32;
|
||||||
} u;
|
} u;
|
||||||
gst_memcpy(u.bytes, bytes, 4 * sizeof(uint8_t));
|
dst_memcpy(u.bytes, bytes, 4 * sizeof(uint8_t));
|
||||||
return u.u32;
|
return u.u32;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,7 +73,7 @@ static uint16_t bytes2u16(const uint8_t *bytes) {
|
|||||||
uint8_t bytes[2];
|
uint8_t bytes[2];
|
||||||
uint16_t u16;
|
uint16_t u16;
|
||||||
} u;
|
} u;
|
||||||
gst_memcpy(u.bytes, bytes, 2 * sizeof(uint8_t));
|
dst_memcpy(u.bytes, bytes, 2 * sizeof(uint8_t));
|
||||||
return u.u16;
|
return u.u16;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,7 +83,7 @@ static double bytes2dbl(const uint8_t *bytes) {
|
|||||||
uint8_t bytes[8];
|
uint8_t bytes[8];
|
||||||
double dbl;
|
double dbl;
|
||||||
} u;
|
} u;
|
||||||
gst_memcpy(u.bytes, bytes, 8 * sizeof(uint8_t));
|
dst_memcpy(u.bytes, bytes, 8 * sizeof(uint8_t));
|
||||||
return u.dbl;
|
return u.dbl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,26 +93,26 @@ static int64_t bytes2int(const uint8_t *bytes) {
|
|||||||
uint8_t bytes[8];
|
uint8_t bytes[8];
|
||||||
int64_t i;
|
int64_t i;
|
||||||
} u;
|
} u;
|
||||||
gst_memcpy(u.bytes, bytes, 8 * sizeof(uint8_t));
|
dst_memcpy(u.bytes, bytes, 8 * sizeof(uint8_t));
|
||||||
return u.i;
|
return u.i;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read a string and turn it into a gst value. Returns
|
/* Read a string and turn it into a dst value. Returns
|
||||||
* an error message if there is an error message during
|
* an error message if there is an error message during
|
||||||
* deserialization. If successful, the resulting value is
|
* deserialization. If successful, the resulting value is
|
||||||
* passed by reference. */
|
* passed by reference. */
|
||||||
static const char *gst_deserialize_impl(
|
static const char *dst_deserialize_impl(
|
||||||
Gst *vm,
|
Dst *vm,
|
||||||
const uint8_t *data,
|
const uint8_t *data,
|
||||||
const uint8_t *end,
|
const uint8_t *end,
|
||||||
const uint8_t **newData,
|
const uint8_t **newData,
|
||||||
GstArray *visited,
|
DstArray *visited,
|
||||||
GstValue *out,
|
DstValue *out,
|
||||||
int depth) {
|
int depth) {
|
||||||
|
|
||||||
GstValue ret;
|
DstValue ret;
|
||||||
ret.type = GST_NIL;
|
ret.type = DST_NIL;
|
||||||
GstValue *buffer;
|
DstValue *buffer;
|
||||||
uint32_t length, i;
|
uint32_t length, i;
|
||||||
const char *err;
|
const char *err;
|
||||||
|
|
||||||
@ -140,7 +141,7 @@ static const char *gst_deserialize_impl(
|
|||||||
|
|
||||||
/* Small integer */
|
/* Small integer */
|
||||||
if (*data < 201) {
|
if (*data < 201) {
|
||||||
ret.type = GST_INTEGER;
|
ret.type = DST_INTEGER;
|
||||||
ret.data.integer = *data - 100;
|
ret.data.integer = *data - 100;
|
||||||
*newData = data + 1;
|
*newData = data + 1;
|
||||||
*out = ret;
|
*out = ret;
|
||||||
@ -154,119 +155,110 @@ static const char *gst_deserialize_impl(
|
|||||||
return "unable to deserialize";
|
return "unable to deserialize";
|
||||||
|
|
||||||
case 201: /* Nil */
|
case 201: /* Nil */
|
||||||
ret.type = GST_NIL;
|
ret.type = DST_NIL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 202: /* True */
|
case 202: /* True */
|
||||||
ret.type = GST_BOOLEAN;
|
ret.type = DST_BOOLEAN;
|
||||||
ret.data.boolean = 1;
|
ret.data.boolean = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 203: /* False */
|
case 203: /* False */
|
||||||
ret.type = GST_BOOLEAN;
|
ret.type = DST_BOOLEAN;
|
||||||
ret.data.boolean = 0;
|
ret.data.boolean = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 204: /* Long number (double) */
|
case 204: /* Long number (double) */
|
||||||
ret.type = GST_REAL;
|
ret.type = DST_REAL;
|
||||||
read_dbl(ret.data.real);
|
read_dbl(ret.data.real);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 205: /* String */
|
case 205: /* String */
|
||||||
case 219: /* Symbol */
|
case 219: /* Symbol */
|
||||||
ret.type = data[-1] == 205 ? GST_STRING : GST_SYMBOL;
|
ret.type = data[-1] == 205 ? DST_STRING : DST_SYMBOL;
|
||||||
read_u32(length);
|
read_u32(length);
|
||||||
deser_datacheck(length);
|
deser_datacheck(length);
|
||||||
ret.data.string = gst_string_b(vm, data, length);
|
ret.data.string = dst_string_b(vm, data, length);
|
||||||
data += length;
|
data += length;
|
||||||
gst_array_push(vm, visited, ret);
|
dst_array_push(vm, visited, ret);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 206: /* Struct */
|
case 206: /* Struct */
|
||||||
ret.type = GST_STRUCT;
|
ret.type = DST_STRUCT;
|
||||||
read_u32(length);
|
read_u32(length);
|
||||||
buffer = gst_struct_begin(vm, length);
|
buffer = dst_struct_begin(vm, length);
|
||||||
for (i = 0; i < length; ++i) {
|
for (i = 0; i < length; ++i) {
|
||||||
GstValue k, v;
|
DstValue k, v;
|
||||||
if ((err = gst_deserialize_impl(vm, data, end, &data, visited, &k, depth)))
|
if ((err = dst_deserialize_impl(vm, data, end, &data, visited, &k, depth)))
|
||||||
return err;
|
return err;
|
||||||
if ((err = gst_deserialize_impl(vm, data, end, &data, visited, &v, depth)))
|
if ((err = dst_deserialize_impl(vm, data, end, &data, visited, &v, depth)))
|
||||||
return err;
|
return err;
|
||||||
gst_struct_put(buffer, k, v);
|
dst_struct_put(buffer, k, v);
|
||||||
}
|
}
|
||||||
ret.data.st = gst_struct_end(vm, buffer);
|
ret.data.st = dst_struct_end(vm, buffer);
|
||||||
gst_array_push(vm, visited, ret);
|
dst_array_push(vm, visited, ret);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 207: /* Buffer */
|
case 207: /* Buffer */
|
||||||
{
|
{
|
||||||
uint32_t cap;
|
uint32_t cap;
|
||||||
ret.type = GST_BYTEBUFFER;
|
ret.type = DST_BYTEBUFFER;
|
||||||
read_u32(cap);
|
read_u32(cap);
|
||||||
read_u32(length);
|
read_u32(length);
|
||||||
deser_datacheck(length);
|
deser_datacheck(length);
|
||||||
ret.data.buffer = gst_alloc(vm, sizeof(GstBuffer));
|
ret.data.buffer = dst_alloc(vm, sizeof(DstBuffer));
|
||||||
ret.data.buffer->data = gst_alloc(vm, cap);
|
ret.data.buffer->data = dst_alloc(vm, cap);
|
||||||
gst_memcpy(ret.data.buffer->data, data, length);
|
dst_memcpy(ret.data.buffer->data, data, length);
|
||||||
ret.data.buffer->count = length;
|
ret.data.buffer->count = length;
|
||||||
ret.data.buffer->capacity = cap;
|
ret.data.buffer->capacity = cap;
|
||||||
gst_array_push(vm, visited, ret);
|
dst_array_push(vm, visited, ret);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 208: /* Array */
|
case 208: /* Array */
|
||||||
ret.type = GST_ARRAY;
|
ret.type = DST_ARRAY;
|
||||||
read_u32(length);
|
read_u32(length);
|
||||||
buffer = gst_alloc(vm, length * sizeof(GstValue));
|
buffer = dst_alloc(vm, length * sizeof(DstValue));
|
||||||
ret.data.array = gst_alloc(vm, sizeof(GstArray));
|
ret.data.array = dst_alloc(vm, sizeof(DstArray));
|
||||||
ret.data.array->data = buffer;
|
ret.data.array->data = buffer;
|
||||||
ret.data.array->count = length;
|
ret.data.array->count = length;
|
||||||
ret.data.array->capacity = length;
|
ret.data.array->capacity = length;
|
||||||
gst_array_push(vm, visited, ret);
|
dst_array_push(vm, visited, ret);
|
||||||
for (i = 0; i < length; ++i)
|
for (i = 0; i < length; ++i)
|
||||||
if ((err = gst_deserialize_impl(vm, data, end, &data, visited, buffer + i, depth)))
|
if ((err = dst_deserialize_impl(vm, data, end, &data, visited, buffer + i, depth)))
|
||||||
return err;
|
return err;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 209: /* Tuple */
|
case 209: /* Tuple */
|
||||||
ret.type = GST_TUPLE;
|
ret.type = DST_TUPLE;
|
||||||
read_u32(length);
|
read_u32(length);
|
||||||
buffer = gst_tuple_begin(vm, length);
|
buffer = dst_tuple_begin(vm, length);
|
||||||
for (i = 0; i < length; ++i)
|
for (i = 0; i < length; ++i)
|
||||||
if ((err = gst_deserialize_impl(vm, data, end, &data, visited, buffer + i, depth)))
|
if ((err = dst_deserialize_impl(vm, data, end, &data, visited, buffer + i, depth)))
|
||||||
return err;
|
return err;
|
||||||
ret.type = GST_TUPLE;
|
ret.type = DST_TUPLE;
|
||||||
ret.data.tuple = gst_tuple_end(vm, buffer);
|
ret.data.tuple = dst_tuple_end(vm, buffer);
|
||||||
gst_array_push(vm, visited, ret);
|
dst_array_push(vm, visited, ret);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 210: /* Thread */
|
case 210: /* Thread */
|
||||||
{
|
{
|
||||||
GstThread *t;
|
DstThread *t;
|
||||||
GstValue *stack;
|
DstValue *stack;
|
||||||
uint16_t prevsize = 0;
|
uint16_t prevsize = 0;
|
||||||
uint8_t statusbyte;
|
uint8_t statusbyte;
|
||||||
t = gst_thread(vm, gst_wrap_nil(), 64);
|
t = dst_thread(vm, dst_wrap_nil(), 64);
|
||||||
ret = gst_wrap_thread(t);
|
ret = dst_wrap_thread(t);
|
||||||
gst_array_push(vm, visited, ret);
|
dst_array_push(vm, visited, ret);
|
||||||
err = gst_deserialize_impl(vm, data, end, &data, visited, &ret, depth);
|
err = dst_deserialize_impl(vm, data, end, &data, visited, &ret, depth);
|
||||||
if (err != NULL) return err;
|
if (err != NULL) return err;
|
||||||
if (ret.type == GST_NIL) {
|
if (ret.type == DST_NIL) {
|
||||||
t->parent = NULL;
|
t->parent = NULL;
|
||||||
} else if (ret.type == GST_THREAD) {
|
} else if (ret.type == DST_THREAD) {
|
||||||
t->parent = ret.data.thread;
|
t->parent = ret.data.thread;
|
||||||
} else {
|
} else {
|
||||||
return "expected thread parent to be thread";
|
return "expected thread parent to be thread";
|
||||||
}
|
}
|
||||||
err = gst_deserialize_impl(vm, data, end, &data, visited, &ret, depth);
|
|
||||||
if (err != NULL) return err;
|
|
||||||
if (ret.type == GST_NIL) {
|
|
||||||
t->errorParent = NULL;
|
|
||||||
} else if (ret.type == GST_THREAD) {
|
|
||||||
t->errorParent = ret.data.thread;
|
|
||||||
} else {
|
|
||||||
return "expected thread error parent to be thread";
|
|
||||||
}
|
|
||||||
deser_assert(data < end, UEB);
|
deser_assert(data < end, UEB);
|
||||||
statusbyte = *data++;
|
statusbyte = *data++;
|
||||||
read_u32(length);
|
read_u32(length);
|
||||||
@ -274,43 +266,43 @@ static const char *gst_deserialize_impl(
|
|||||||
t->status = statusbyte % 4;
|
t->status = statusbyte % 4;
|
||||||
/* Add frames */
|
/* Add frames */
|
||||||
for (i = 0; i < length; ++i) {
|
for (i = 0; i < length; ++i) {
|
||||||
GstValue callee, env;
|
DstValue callee, env;
|
||||||
uint32_t pcoffset;
|
uint32_t pcoffset;
|
||||||
uint16_t ret, args, size, j;
|
uint16_t ret, args, size, j;
|
||||||
/* Read the stack */
|
/* Read the stack */
|
||||||
err = gst_deserialize_impl(vm, data, end, &data, visited, &callee, depth);
|
err = dst_deserialize_impl(vm, data, end, &data, visited, &callee, depth);
|
||||||
if (err != NULL) return err;
|
if (err != NULL) return err;
|
||||||
err = gst_deserialize_impl(vm, data, end, &data, visited, &env, depth);
|
err = dst_deserialize_impl(vm, data, end, &data, visited, &env, depth);
|
||||||
if (err != NULL) return err;
|
if (err != NULL) return err;
|
||||||
if (env.type != GST_FUNCENV && env.type != GST_NIL)
|
if (env.type != DST_FUNCENV && env.type != DST_NIL)
|
||||||
return "expected funcenv in stackframe";
|
return "expected funcenv in stackframe";
|
||||||
/* Create a new frame */
|
/* Create a new frame */
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
gst_thread_beginframe(vm, t, gst_wrap_nil(), 0);
|
dst_thread_beginframe(vm, t, dst_wrap_nil(), 0);
|
||||||
read_u32(pcoffset);
|
read_u32(pcoffset);
|
||||||
read_u32(ret);
|
read_u32(ret);
|
||||||
read_u32(args);
|
read_u32(args);
|
||||||
read_u32(size);
|
read_u32(size);
|
||||||
/* Set up the stack */
|
/* Set up the stack */
|
||||||
stack = gst_thread_stack(t);
|
stack = dst_thread_stack(t);
|
||||||
if (callee.type == GST_FUNCTION) {
|
if (callee.type == DST_FUNCTION) {
|
||||||
gst_frame_pc(stack) = callee.data.function->def->byteCode + pcoffset;
|
dst_frame_pc(stack) = callee.data.function->def->byteCode + pcoffset;
|
||||||
}
|
}
|
||||||
gst_frame_ret(stack) = ret;
|
dst_frame_ret(stack) = ret;
|
||||||
gst_frame_args(stack) = args;
|
dst_frame_args(stack) = args;
|
||||||
gst_frame_size(stack) = size;
|
dst_frame_size(stack) = size;
|
||||||
gst_frame_prevsize(stack) = prevsize;
|
dst_frame_prevsize(stack) = prevsize;
|
||||||
gst_frame_callee(stack) = callee;
|
dst_frame_callee(stack) = callee;
|
||||||
if (env.type == GST_NIL)
|
if (env.type == DST_NIL)
|
||||||
gst_frame_env(stack) = NULL;
|
dst_frame_env(stack) = NULL;
|
||||||
else
|
else
|
||||||
gst_frame_env(stack) = env.data.env;
|
dst_frame_env(stack) = env.data.env;
|
||||||
prevsize = size;
|
prevsize = size;
|
||||||
/* Push stack args */
|
/* Push stack args */
|
||||||
for (j = 0; j < size; ++j) {
|
for (j = 0; j < size; ++j) {
|
||||||
GstValue temp;
|
DstValue temp;
|
||||||
err = gst_deserialize_impl(vm, data, end, &data, visited, &temp, depth);
|
err = dst_deserialize_impl(vm, data, end, &data, visited, &temp, depth);
|
||||||
gst_thread_push(vm, t, temp);
|
dst_thread_push(vm, t, temp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -318,45 +310,45 @@ static const char *gst_deserialize_impl(
|
|||||||
|
|
||||||
case 211: /* Table */
|
case 211: /* Table */
|
||||||
read_u32(length);
|
read_u32(length);
|
||||||
ret = gst_wrap_table(gst_table(vm, 2 * length));
|
ret = dst_wrap_table(dst_table(vm, 2 * length));
|
||||||
gst_array_push(vm, visited, ret);
|
dst_array_push(vm, visited, ret);
|
||||||
for (i = 0; i < length; ++i) {
|
for (i = 0; i < length; ++i) {
|
||||||
GstValue key, value;
|
DstValue key, value;
|
||||||
err = gst_deserialize_impl(vm, data, end, &data, visited, &key, depth);
|
err = dst_deserialize_impl(vm, data, end, &data, visited, &key, depth);
|
||||||
if (err != NULL) return err;
|
if (err != NULL) return err;
|
||||||
err = gst_deserialize_impl(vm, data, end, &data, visited, &value, depth);
|
err = dst_deserialize_impl(vm, data, end, &data, visited, &value, depth);
|
||||||
if (err != NULL) return err;
|
if (err != NULL) return err;
|
||||||
gst_table_put(vm, ret.data.table, key, value);
|
dst_table_put(vm, ret.data.table, key, value);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 212: /* Funcdef */
|
case 212: /* Funcdef */
|
||||||
{
|
{
|
||||||
GstFuncDef *def;
|
DstFuncDef *def;
|
||||||
uint32_t locals, arity, literalsLen, byteCodeLen, flags;
|
uint32_t locals, arity, literalsLen, byteCodeLen, flags;
|
||||||
read_u32(locals);
|
read_u32(locals);
|
||||||
read_u32(arity);
|
read_u32(arity);
|
||||||
read_u32(flags);
|
read_u32(flags);
|
||||||
read_u32(literalsLen);
|
read_u32(literalsLen);
|
||||||
def = gst_alloc(vm, sizeof(GstFuncDef));
|
def = dst_alloc(vm, sizeof(DstFuncDef));
|
||||||
ret = gst_wrap_funcdef(def);
|
ret = dst_wrap_funcdef(def);
|
||||||
gst_array_push(vm, visited, ret);
|
dst_array_push(vm, visited, ret);
|
||||||
def->locals = locals;
|
def->locals = locals;
|
||||||
def->arity = arity;
|
def->arity = arity;
|
||||||
def->flags = flags;
|
def->flags = flags;
|
||||||
def->literalsLen = literalsLen;
|
def->literalsLen = literalsLen;
|
||||||
if (literalsLen > 0) {
|
if (literalsLen > 0) {
|
||||||
def->literals = gst_alloc(vm, literalsLen * sizeof(GstValue));
|
def->literals = dst_alloc(vm, literalsLen * sizeof(DstValue));
|
||||||
} else {
|
} else {
|
||||||
def->literals = NULL;
|
def->literals = NULL;
|
||||||
}
|
}
|
||||||
for (i = 0; i < literalsLen; ++i) {
|
for (i = 0; i < literalsLen; ++i) {
|
||||||
err = gst_deserialize_impl(vm, data, end, &data, visited, def->literals + i, depth);
|
err = dst_deserialize_impl(vm, data, end, &data, visited, def->literals + i, depth);
|
||||||
if (err != NULL) return err;
|
if (err != NULL) return err;
|
||||||
}
|
}
|
||||||
read_u32(byteCodeLen);
|
read_u32(byteCodeLen);
|
||||||
deser_datacheck(byteCodeLen * sizeof(uint16_t));
|
deser_datacheck(byteCodeLen * sizeof(uint16_t));
|
||||||
def->byteCode = gst_alloc(vm, byteCodeLen * sizeof(uint16_t));
|
def->byteCode = dst_alloc(vm, byteCodeLen * sizeof(uint16_t));
|
||||||
def->byteCodeLen = byteCodeLen;
|
def->byteCodeLen = byteCodeLen;
|
||||||
for (i = 0; i < byteCodeLen; ++i) {
|
for (i = 0; i < byteCodeLen; ++i) {
|
||||||
read_u16(def->byteCode[i]);
|
read_u16(def->byteCode[i]);
|
||||||
@ -366,22 +358,22 @@ static const char *gst_deserialize_impl(
|
|||||||
|
|
||||||
case 213: /* Funcenv */
|
case 213: /* Funcenv */
|
||||||
{
|
{
|
||||||
GstValue thread;
|
DstValue thread;
|
||||||
ret.type = GST_FUNCENV;
|
ret.type = DST_FUNCENV;
|
||||||
ret.data.env = gst_alloc(vm, sizeof(GstFuncEnv));
|
ret.data.env = dst_alloc(vm, sizeof(DstFuncEnv));
|
||||||
gst_array_push(vm, visited, ret);
|
dst_array_push(vm, visited, ret);
|
||||||
err = gst_deserialize_impl(vm, data, end, &data, visited, &thread, depth);
|
err = dst_deserialize_impl(vm, data, end, &data, visited, &thread, depth);
|
||||||
if (err != NULL) return err;
|
if (err != NULL) return err;
|
||||||
read_u32(length);
|
read_u32(length);
|
||||||
ret.data.env->stackOffset = length;
|
ret.data.env->stackOffset = length;
|
||||||
if (thread.type == GST_THREAD) {
|
if (thread.type == DST_THREAD) {
|
||||||
ret.data.env->thread = thread.data.thread;
|
ret.data.env->thread = thread.data.thread;
|
||||||
} else {
|
} else {
|
||||||
ret.data.env->thread = NULL;
|
ret.data.env->thread = NULL;
|
||||||
ret.data.env->values = gst_alloc(vm, sizeof(GstValue) * length);
|
ret.data.env->values = dst_alloc(vm, sizeof(DstValue) * length);
|
||||||
for (i = 0; i < length; ++i) {
|
for (i = 0; i < length; ++i) {
|
||||||
GstValue item;
|
DstValue item;
|
||||||
err = gst_deserialize_impl(vm, data, end, &data, visited, &item, depth);
|
err = dst_deserialize_impl(vm, data, end, &data, visited, &item, depth);
|
||||||
if (err != NULL) return err;
|
if (err != NULL) return err;
|
||||||
ret.data.env->values[i] = item;
|
ret.data.env->values[i] = item;
|
||||||
}
|
}
|
||||||
@ -391,29 +383,29 @@ static const char *gst_deserialize_impl(
|
|||||||
|
|
||||||
case 214: /* Function */
|
case 214: /* Function */
|
||||||
{
|
{
|
||||||
GstValue parent, def, env;
|
DstValue parent, def, env;
|
||||||
ret.type = GST_FUNCTION;
|
ret.type = DST_FUNCTION;
|
||||||
ret.data.function = gst_alloc(vm, sizeof(GstFunction));
|
ret.data.function = dst_alloc(vm, sizeof(DstFunction));
|
||||||
gst_array_push(vm, visited, ret);
|
dst_array_push(vm, visited, ret);
|
||||||
err = gst_deserialize_impl(vm, data, end, &data, visited, &parent, depth);
|
err = dst_deserialize_impl(vm, data, end, &data, visited, &parent, depth);
|
||||||
if (err != NULL) return err;
|
if (err != NULL) return err;
|
||||||
err = gst_deserialize_impl(vm, data, end, &data, visited, &env, depth);
|
err = dst_deserialize_impl(vm, data, end, &data, visited, &env, depth);
|
||||||
if (err != NULL) return err;
|
if (err != NULL) return err;
|
||||||
err = gst_deserialize_impl(vm, data, end, &data, visited, &def, depth);
|
err = dst_deserialize_impl(vm, data, end, &data, visited, &def, depth);
|
||||||
if (err != NULL) return err;
|
if (err != NULL) return err;
|
||||||
if (parent.type == GST_NIL) {
|
if (parent.type == DST_NIL) {
|
||||||
ret.data.function->parent = NULL;
|
ret.data.function->parent = NULL;
|
||||||
} else if (parent.type == GST_FUNCTION) {
|
} else if (parent.type == DST_FUNCTION) {
|
||||||
ret.data.function->parent = parent.data.function;
|
ret.data.function->parent = parent.data.function;
|
||||||
} else {
|
} else {
|
||||||
deser_error("expected function");
|
deser_error("expected function");
|
||||||
}
|
}
|
||||||
deser_assert(def.type == GST_FUNCDEF, "expected funcdef");
|
deser_assert(def.type == DST_FUNCDEF, "expected funcdef");
|
||||||
ret.data.function->def = def.data.def;
|
ret.data.function->def = def.data.def;
|
||||||
if (env.type == GST_NIL) {
|
if (env.type == DST_NIL) {
|
||||||
ret.data.function->env = NULL;
|
ret.data.function->env = NULL;
|
||||||
} else {
|
} else {
|
||||||
deser_assert(env.type == GST_FUNCENV, "expected funcenv");
|
deser_assert(env.type == DST_FUNCENV, "expected funcenv");
|
||||||
ret.data.function->env = env.data.env;
|
ret.data.function->env = env.data.env;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -428,13 +420,13 @@ static const char *gst_deserialize_impl(
|
|||||||
|
|
||||||
case 216: /* C function */
|
case 216: /* C function */
|
||||||
{
|
{
|
||||||
GstValue id;
|
DstValue id;
|
||||||
read_u32(length);
|
read_u32(length);
|
||||||
deser_datacheck(length);
|
deser_datacheck(length);
|
||||||
id = gst_wrap_string(gst_string_b(vm, data, length));
|
id = dst_wrap_string(dst_string_b(vm, data, length));
|
||||||
data += length;
|
data += length;
|
||||||
ret = gst_table_get(vm->registry, id);
|
ret = dst_table_get(vm->registry, id);
|
||||||
if (ret.type != GST_CFUNCTION) {
|
if (ret.type != DST_CFUNCTION) {
|
||||||
deser_error("unabled to deserialize c function");
|
deser_error("unabled to deserialize c function");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -448,7 +440,7 @@ static const char *gst_deserialize_impl(
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 218: /* Integer */
|
case 218: /* Integer */
|
||||||
ret.type = GST_INTEGER;
|
ret.type = DST_INTEGER;
|
||||||
read_i64(ret.data.integer);
|
read_i64(ret.data.integer);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -458,46 +450,46 @@ static const char *gst_deserialize_impl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Load a value from data */
|
/* Load a value from data */
|
||||||
const char *gst_deserialize(
|
const char *dst_deserialize_internal(
|
||||||
Gst *vm,
|
Dst *vm,
|
||||||
const uint8_t *data,
|
const uint8_t *data,
|
||||||
uint32_t len,
|
uint32_t len,
|
||||||
GstValue *out,
|
DstValue *out,
|
||||||
const uint8_t **nextData) {
|
const uint8_t **nextData) {
|
||||||
GstValue ret;
|
DstValue ret;
|
||||||
const char *err;
|
const char *err;
|
||||||
GstArray *visited = gst_array(vm, 10);
|
DstArray *visited = dst_array(vm, 10);
|
||||||
err = gst_deserialize_impl(vm, data, data + len, nextData, visited, &ret, GST_RECURSION_GUARD);
|
err = dst_deserialize_impl(vm, data, data + len, nextData, visited, &ret, DST_RECURSION_GUARD);
|
||||||
if (err != NULL) return err;
|
if (err != NULL) return err;
|
||||||
*out = ret;
|
*out = ret;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allow appending other types to buffers */
|
/* Allow appending other types to buffers */
|
||||||
BUFFER_DEFINE(real, GstReal)
|
BUFFER_DEFINE(real, DstReal)
|
||||||
BUFFER_DEFINE(integer, GstInteger)
|
BUFFER_DEFINE(integer, DstInteger)
|
||||||
BUFFER_DEFINE(u32, uint32_t)
|
BUFFER_DEFINE(u32, uint32_t)
|
||||||
BUFFER_DEFINE(u16, uint16_t)
|
BUFFER_DEFINE(u16, uint16_t)
|
||||||
|
|
||||||
/* Serialize a value and write to a buffer. Returns possible
|
/* Serialize a value and write to a buffer. Returns possible
|
||||||
* error messages. */
|
* error messages. */
|
||||||
static const char *gst_serialize_impl(
|
static const char *dst_serialize_impl(
|
||||||
Gst *vm,
|
Dst *vm,
|
||||||
GstBuffer *buffer,
|
DstBuffer *buffer,
|
||||||
GstTable *visited,
|
DstTable *visited,
|
||||||
uint32_t *nextId,
|
uint32_t *nextId,
|
||||||
GstValue x,
|
DstValue x,
|
||||||
int depth) {
|
int depth) {
|
||||||
|
|
||||||
uint32_t i, count;
|
uint32_t i, count;
|
||||||
const char *err;
|
const char *err;
|
||||||
GstValue check;
|
DstValue check;
|
||||||
|
|
||||||
#define write_byte(b) gst_buffer_push(vm, buffer, (b))
|
#define write_byte(b) dst_buffer_push(vm, buffer, (b))
|
||||||
#define write_u32(b) gst_buffer_push_u32(vm, buffer, (b))
|
#define write_u32(b) dst_buffer_push_u32(vm, buffer, (b))
|
||||||
#define write_u16(b) gst_buffer_push_u16(vm, buffer, (b))
|
#define write_u16(b) dst_buffer_push_u16(vm, buffer, (b))
|
||||||
#define write_dbl(b) gst_buffer_push_real(vm, buffer, (b))
|
#define write_dbl(b) dst_buffer_push_real(vm, buffer, (b))
|
||||||
#define write_int(b) gst_buffer_push_integer(vm, buffer, (b))
|
#define write_int(b) dst_buffer_push_integer(vm, buffer, (b))
|
||||||
/*printf("Type: %d\n", x.type);*/
|
/*printf("Type: %d\n", x.type);*/
|
||||||
|
|
||||||
/* Check if we have gone too deep */
|
/* Check if we have gone too deep */
|
||||||
@ -507,18 +499,18 @@ static const char *gst_serialize_impl(
|
|||||||
|
|
||||||
/* Check non reference types - if successful, return NULL */
|
/* Check non reference types - if successful, return NULL */
|
||||||
switch (x.type) {
|
switch (x.type) {
|
||||||
case GST_USERDATA:
|
case DST_USERDATA:
|
||||||
case GST_NIL:
|
case DST_NIL:
|
||||||
write_byte(201);
|
write_byte(201);
|
||||||
return NULL;
|
return NULL;
|
||||||
case GST_BOOLEAN:
|
case DST_BOOLEAN:
|
||||||
write_byte(x.data.boolean ? 202 : 203);
|
write_byte(x.data.boolean ? 202 : 203);
|
||||||
return NULL;
|
return NULL;
|
||||||
case GST_REAL:
|
case DST_REAL:
|
||||||
write_byte(204);
|
write_byte(204);
|
||||||
write_dbl(x.data.real);
|
write_dbl(x.data.real);
|
||||||
return NULL;
|
return NULL;
|
||||||
case GST_INTEGER:
|
case DST_INTEGER:
|
||||||
if (x.data.integer <= 100 && x.data.integer >= -100) {
|
if (x.data.integer <= 100 && x.data.integer >= -100) {
|
||||||
write_byte(x.data.integer + 100);
|
write_byte(x.data.integer + 100);
|
||||||
} else {
|
} else {
|
||||||
@ -531,8 +523,8 @@ static const char *gst_serialize_impl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Check if already seen - if so, use reference */
|
/* Check if already seen - if so, use reference */
|
||||||
check = gst_table_get(visited, x);
|
check = dst_table_get(visited, x);
|
||||||
if (check.type == GST_INTEGER) {
|
if (check.type == DST_INTEGER) {
|
||||||
write_byte(217);
|
write_byte(217);
|
||||||
write_u32((uint32_t) check.data.integer);
|
write_u32((uint32_t) check.data.integer);
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -544,37 +536,37 @@ static const char *gst_serialize_impl(
|
|||||||
* if they are treated like other reference types because they cannot
|
* if they are treated like other reference types because they cannot
|
||||||
* be added to the visited table before recursing into serializing their
|
* be added to the visited table before recursing into serializing their
|
||||||
* arguments */
|
* arguments */
|
||||||
if (x.type == GST_STRUCT || x.type == GST_TUPLE) {
|
if (x.type == DST_STRUCT || x.type == DST_TUPLE) {
|
||||||
if (x.type == GST_STRUCT) {
|
if (x.type == DST_STRUCT) {
|
||||||
const GstValue *data;
|
const DstValue *data;
|
||||||
write_byte(206);
|
write_byte(206);
|
||||||
gst_hashtable_view(x, &data, &count);
|
dst_hashtable_view(x, &data, &count);
|
||||||
write_u32(gst_struct_length(x.data.st));
|
write_u32(dst_struct_length(x.data.st));
|
||||||
for (i = 0; i < count; i += 2) {
|
for (i = 0; i < count; i += 2) {
|
||||||
if (data[i].type != GST_NIL) {
|
if (data[i].type != DST_NIL) {
|
||||||
err = gst_serialize_impl(vm, buffer, visited, nextId, data[i], depth);
|
err = dst_serialize_impl(vm, buffer, visited, nextId, data[i], depth);
|
||||||
if (err != NULL) return err;
|
if (err != NULL) return err;
|
||||||
err = gst_serialize_impl(vm, buffer, visited, nextId, data[i + 1], depth);
|
err = dst_serialize_impl(vm, buffer, visited, nextId, data[i + 1], depth);
|
||||||
if (err != NULL) return err;
|
if (err != NULL) return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
write_byte(209);
|
write_byte(209);
|
||||||
count = gst_tuple_length(x.data.tuple);
|
count = dst_tuple_length(x.data.tuple);
|
||||||
write_u32(count);
|
write_u32(count);
|
||||||
for (i = 0; i < count; ++i) {
|
for (i = 0; i < count; ++i) {
|
||||||
err = gst_serialize_impl(vm, buffer, visited, nextId, x.data.tuple[i], depth);
|
err = dst_serialize_impl(vm, buffer, visited, nextId, x.data.tuple[i], depth);
|
||||||
if (err != NULL) return err;
|
if (err != NULL) return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Record reference after serialization */
|
/* Record reference after serialization */
|
||||||
gst_table_put(vm, visited, x, gst_wrap_integer(*nextId));
|
dst_table_put(vm, visited, x, dst_wrap_integer(*nextId));
|
||||||
*nextId = *nextId + 1;
|
*nextId = *nextId + 1;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Record reference before serialization */
|
/* Record reference before serialization */
|
||||||
gst_table_put(vm, visited, x, gst_wrap_integer(*nextId));
|
dst_table_put(vm, visited, x, dst_wrap_integer(*nextId));
|
||||||
*nextId = *nextId + 1;
|
*nextId = *nextId + 1;
|
||||||
|
|
||||||
/* Check reference types */
|
/* Check reference types */
|
||||||
@ -582,21 +574,21 @@ static const char *gst_serialize_impl(
|
|||||||
default:
|
default:
|
||||||
return "unable to serialize type";
|
return "unable to serialize type";
|
||||||
|
|
||||||
case GST_STRING:
|
case DST_STRING:
|
||||||
case GST_SYMBOL:
|
case DST_SYMBOL:
|
||||||
write_byte(x.type == GST_STRING ? 205 : 219);
|
write_byte(x.type == DST_STRING ? 205 : 219);
|
||||||
count = gst_string_length(x.data.string);
|
count = dst_string_length(x.data.string);
|
||||||
write_u32(count);
|
write_u32(count);
|
||||||
for (i = 0; i < count; ++i) {
|
for (i = 0; i < count; ++i) {
|
||||||
write_byte(x.data.string[i]);
|
write_byte(x.data.string[i]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GST_CFUNCTION:
|
case DST_CFUNCTION:
|
||||||
write_byte(216);
|
write_byte(216);
|
||||||
{
|
{
|
||||||
GstValue id = gst_table_get(vm->registry, x);
|
DstValue id = dst_table_get(vm->registry, x);
|
||||||
count = gst_string_length(id.data.string);
|
count = dst_string_length(id.data.string);
|
||||||
write_u32(count);
|
write_u32(count);
|
||||||
for (i = 0; i < count; ++i) {
|
for (i = 0; i < count; ++i) {
|
||||||
write_byte(id.data.string[i]);
|
write_byte(id.data.string[i]);
|
||||||
@ -604,24 +596,24 @@ static const char *gst_serialize_impl(
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GST_TABLE:
|
case DST_TABLE:
|
||||||
{
|
{
|
||||||
const GstValue *data;
|
const DstValue *data;
|
||||||
write_byte(211);
|
write_byte(211);
|
||||||
gst_hashtable_view(x, &data, &count);
|
dst_hashtable_view(x, &data, &count);
|
||||||
write_u32(x.data.table->count);
|
write_u32(x.data.table->count);
|
||||||
for (i = 0; i < count; i += 2) {
|
for (i = 0; i < count; i += 2) {
|
||||||
if (data[i].type != GST_NIL) {
|
if (data[i].type != DST_NIL) {
|
||||||
err = gst_serialize_impl(vm, buffer, visited, nextId, data[i], depth);
|
err = dst_serialize_impl(vm, buffer, visited, nextId, data[i], depth);
|
||||||
if (err != NULL) return err;
|
if (err != NULL) return err;
|
||||||
err = gst_serialize_impl(vm, buffer, visited, nextId, data[i + 1], depth);
|
err = dst_serialize_impl(vm, buffer, visited, nextId, data[i + 1], depth);
|
||||||
if (err != NULL) return err;
|
if (err != NULL) return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GST_BYTEBUFFER:
|
case DST_BYTEBUFFER:
|
||||||
write_byte(207);
|
write_byte(207);
|
||||||
count = x.data.buffer->count;
|
count = x.data.buffer->count;
|
||||||
write_u32(x.data.buffer->capacity);
|
write_u32(x.data.buffer->capacity);
|
||||||
@ -631,32 +623,27 @@ static const char *gst_serialize_impl(
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GST_ARRAY:
|
case DST_ARRAY:
|
||||||
write_byte(208);
|
write_byte(208);
|
||||||
count = x.data.array->count;
|
count = x.data.array->count;
|
||||||
write_u32(count);
|
write_u32(count);
|
||||||
for (i = 0; i < count; ++i) {
|
for (i = 0; i < count; ++i) {
|
||||||
err = gst_serialize_impl(vm, buffer, visited, nextId, x.data.array->data[i], depth);
|
err = dst_serialize_impl(vm, buffer, visited, nextId, x.data.array->data[i], depth);
|
||||||
if (err != NULL) return err;
|
if (err != NULL) return err;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GST_THREAD:
|
case DST_THREAD:
|
||||||
{
|
{
|
||||||
GstThread *t = x.data.thread;
|
DstThread *t = x.data.thread;
|
||||||
const GstValue *stack = t->data + GST_FRAME_SIZE;
|
const DstValue *stack = t->data + DST_FRAME_SIZE;
|
||||||
uint32_t framecount = gst_thread_countframes(t);
|
uint32_t framecount = dst_thread_countframes(t);
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
write_byte(210);
|
write_byte(210);
|
||||||
if (t->parent)
|
if (t->parent)
|
||||||
err = gst_serialize_impl(vm, buffer, visited, nextId, gst_wrap_thread(t->parent), depth);
|
err = dst_serialize_impl(vm, buffer, visited, nextId, dst_wrap_thread(t->parent), depth);
|
||||||
else
|
else
|
||||||
err = gst_serialize_impl(vm, buffer, visited, nextId, gst_wrap_nil(), depth);
|
err = dst_serialize_impl(vm, buffer, visited, nextId, dst_wrap_nil(), depth);
|
||||||
if (t->errorParent)
|
|
||||||
err = gst_serialize_impl(vm, buffer, visited, nextId,
|
|
||||||
gst_wrap_thread(t->errorParent), depth);
|
|
||||||
else
|
|
||||||
err = gst_serialize_impl(vm, buffer, visited, nextId, gst_wrap_nil(), depth);
|
|
||||||
if (err != NULL) return err;
|
if (err != NULL) return err;
|
||||||
/* Write the status byte */
|
/* Write the status byte */
|
||||||
write_byte(t->status);
|
write_byte(t->status);
|
||||||
@ -665,44 +652,44 @@ static const char *gst_serialize_impl(
|
|||||||
/* Write stack frames */
|
/* Write stack frames */
|
||||||
for (i = 0; i < framecount; ++i) {
|
for (i = 0; i < framecount; ++i) {
|
||||||
uint32_t j, size;
|
uint32_t j, size;
|
||||||
GstValue callee = gst_frame_callee(stack);
|
DstValue callee = dst_frame_callee(stack);
|
||||||
GstFuncEnv *env = gst_frame_env(stack);
|
DstFuncEnv *env = dst_frame_env(stack);
|
||||||
err = gst_serialize_impl(vm, buffer, visited, nextId, callee, depth);
|
err = dst_serialize_impl(vm, buffer, visited, nextId, callee, depth);
|
||||||
if (err != NULL) return err;
|
if (err != NULL) return err;
|
||||||
if (env)
|
if (env)
|
||||||
err = gst_serialize_impl(vm, buffer, visited, nextId, gst_wrap_funcenv(env), depth);
|
err = dst_serialize_impl(vm, buffer, visited, nextId, dst_wrap_funcenv(env), depth);
|
||||||
else
|
else
|
||||||
err = gst_serialize_impl(vm, buffer, visited, nextId, gst_wrap_nil(), depth);
|
err = dst_serialize_impl(vm, buffer, visited, nextId, dst_wrap_nil(), depth);
|
||||||
if (err != NULL) return err;
|
if (err != NULL) return err;
|
||||||
if (callee.type == GST_FUNCTION) {
|
if (callee.type == DST_FUNCTION) {
|
||||||
write_u32(gst_frame_pc(stack) - callee.data.function->def->byteCode);
|
write_u32(dst_frame_pc(stack) - callee.data.function->def->byteCode);
|
||||||
} else {
|
} else {
|
||||||
write_u32(0);
|
write_u32(0);
|
||||||
}
|
}
|
||||||
write_u32(gst_frame_ret(stack));
|
write_u32(dst_frame_ret(stack));
|
||||||
write_u32(gst_frame_args(stack));
|
write_u32(dst_frame_args(stack));
|
||||||
size = gst_frame_size(stack);
|
size = dst_frame_size(stack);
|
||||||
write_u32(size);
|
write_u32(size);
|
||||||
for (j = 0; j < size; ++j) {
|
for (j = 0; j < size; ++j) {
|
||||||
err = gst_serialize_impl(vm, buffer, visited, nextId, stack[j], depth);
|
err = dst_serialize_impl(vm, buffer, visited, nextId, stack[j], depth);
|
||||||
if (err != NULL) return err;
|
if (err != NULL) return err;
|
||||||
}
|
}
|
||||||
/* Next stack frame */
|
/* Next stack frame */
|
||||||
stack += size + GST_FRAME_SIZE;
|
stack += size + DST_FRAME_SIZE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GST_FUNCDEF: /* Funcdef */
|
case DST_FUNCDEF: /* Funcdef */
|
||||||
{
|
{
|
||||||
GstFuncDef *def = x.data.def;
|
DstFuncDef *def = x.data.def;
|
||||||
write_byte(212);
|
write_byte(212);
|
||||||
write_u32(def->locals);
|
write_u32(def->locals);
|
||||||
write_u32(def->arity);
|
write_u32(def->arity);
|
||||||
write_u32(def->flags);
|
write_u32(def->flags);
|
||||||
write_u32(def->literalsLen);
|
write_u32(def->literalsLen);
|
||||||
for (i = 0; i < def->literalsLen; ++i) {
|
for (i = 0; i < def->literalsLen; ++i) {
|
||||||
err = gst_serialize_impl(vm, buffer, visited, nextId, def->literals[i], depth);
|
err = dst_serialize_impl(vm, buffer, visited, nextId, def->literals[i], depth);
|
||||||
if (err != NULL) return err;
|
if (err != NULL) return err;
|
||||||
}
|
}
|
||||||
write_u32(def->byteCodeLen);
|
write_u32(def->byteCodeLen);
|
||||||
@ -712,38 +699,38 @@ static const char *gst_serialize_impl(
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GST_FUNCENV: /* Funcenv */
|
case DST_FUNCENV: /* Funcenv */
|
||||||
{
|
{
|
||||||
GstFuncEnv *env = x.data.env;
|
DstFuncEnv *env = x.data.env;
|
||||||
write_byte(213);
|
write_byte(213);
|
||||||
if (env->thread) {
|
if (env->thread) {
|
||||||
err = gst_serialize_impl(vm, buffer, visited, nextId, gst_wrap_thread(env->thread), depth);
|
err = dst_serialize_impl(vm, buffer, visited, nextId, dst_wrap_thread(env->thread), depth);
|
||||||
if (err != NULL) return err;
|
if (err != NULL) return err;
|
||||||
write_u32(env->stackOffset);
|
write_u32(env->stackOffset);
|
||||||
} else {
|
} else {
|
||||||
write_byte(201); /* Write nil */
|
write_byte(201); /* Write nil */
|
||||||
write_u32(env->stackOffset);
|
write_u32(env->stackOffset);
|
||||||
for (i = 0; i < env->stackOffset; ++i) {
|
for (i = 0; i < env->stackOffset; ++i) {
|
||||||
err = gst_serialize_impl(vm, buffer, visited, nextId, env->values[i], depth);
|
err = dst_serialize_impl(vm, buffer, visited, nextId, env->values[i], depth);
|
||||||
if (err != NULL) return err;
|
if (err != NULL) return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GST_FUNCTION: /* Function */
|
case DST_FUNCTION: /* Function */
|
||||||
{
|
{
|
||||||
GstValue pv, ev, dv;
|
DstValue pv, ev, dv;
|
||||||
GstFunction *fn = x.data.function;
|
DstFunction *fn = x.data.function;
|
||||||
write_byte(214);
|
write_byte(214);
|
||||||
pv = fn->parent ? gst_wrap_function(fn->parent) : gst_wrap_nil();
|
pv = fn->parent ? dst_wrap_function(fn->parent) : dst_wrap_nil();
|
||||||
dv = gst_wrap_funcdef(fn->def);
|
dv = dst_wrap_funcdef(fn->def);
|
||||||
ev = fn->env ? gst_wrap_funcenv(fn->env) : gst_wrap_nil();
|
ev = fn->env ? dst_wrap_funcenv(fn->env) : dst_wrap_nil();
|
||||||
err = gst_serialize_impl(vm, buffer, visited, nextId, pv, depth);
|
err = dst_serialize_impl(vm, buffer, visited, nextId, pv, depth);
|
||||||
if (err != NULL) return err;
|
if (err != NULL) return err;
|
||||||
err = gst_serialize_impl(vm, buffer, visited, nextId, ev, depth);
|
err = dst_serialize_impl(vm, buffer, visited, nextId, ev, depth);
|
||||||
if (err != NULL) return err;
|
if (err != NULL) return err;
|
||||||
err = gst_serialize_impl(vm, buffer, visited, nextId, dv, depth);
|
err = dst_serialize_impl(vm, buffer, visited, nextId, dv, depth);
|
||||||
if (err != NULL) return err;
|
if (err != NULL) return err;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -754,12 +741,12 @@ static const char *gst_serialize_impl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Serialize an object */
|
/* Serialize an object */
|
||||||
const char *gst_serialize(Gst *vm, GstBuffer *buffer, GstValue x) {
|
const char *dst_serialize_internal(Dst *vm, DstBuffer *buffer, DstValue x) {
|
||||||
uint32_t nextId = 0;
|
uint32_t nextId = 0;
|
||||||
uint32_t oldCount = buffer->count;
|
uint32_t oldCount = buffer->count;
|
||||||
const char *err;
|
const char *err;
|
||||||
GstTable *visited = gst_table(vm, 10);
|
DstTable *visited = dst_table(vm, 10);
|
||||||
err = gst_serialize_impl(vm, buffer, visited, &nextId, x, GST_RECURSION_GUARD);
|
err = dst_serialize_impl(vm, buffer, visited, &nextId, x, DST_RECURSION_GUARD);
|
||||||
if (err != NULL) {
|
if (err != NULL) {
|
||||||
buffer->count = oldCount;
|
buffer->count = oldCount;
|
||||||
}
|
}
|
||||||
|
1211
core/stl.c
1211
core/stl.c
File diff suppressed because it is too large
Load Diff
209
core/string.c
209
core/string.c
@ -20,23 +20,23 @@
|
|||||||
* IN THE SOFTWARE.
|
* IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include "internal.h"
|
||||||
|
|
||||||
/* Temporary buffer size */
|
/* Temporary buffer size */
|
||||||
#define GST_BUFSIZE 36
|
#define DST_BUFSIZE 36
|
||||||
|
|
||||||
static const uint8_t *real_to_string(Gst *vm, GstReal x) {
|
static const uint8_t *real_to_string(Dst *vm, DstReal x) {
|
||||||
uint8_t buf[GST_BUFSIZE];
|
uint8_t buf[DST_BUFSIZE];
|
||||||
int count = snprintf((char *) buf, GST_BUFSIZE, "%.21gF", x);
|
int count = snprintf((char *) buf, DST_BUFSIZE, "%.21gF", x);
|
||||||
return gst_string_b(vm, buf, (uint32_t) count);
|
return dst_string_b(vm, buf, (uint32_t) count);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const uint8_t *integer_to_string(Gst *vm, GstInteger x) {
|
static const uint8_t *integer_to_string(Dst *vm, DstInteger x) {
|
||||||
uint8_t buf[GST_BUFSIZE];
|
uint8_t buf[DST_BUFSIZE];
|
||||||
int neg = 0;
|
int neg = 0;
|
||||||
uint8_t *hi, *low;
|
uint8_t *hi, *low;
|
||||||
uint32_t count = 0;
|
uint32_t count = 0;
|
||||||
if (x == 0) return gst_string_c(vm, "0");
|
if (x == 0) return dst_string_c(vm, "0");
|
||||||
if (x < 0) {
|
if (x < 0) {
|
||||||
neg = 1;
|
neg = 1;
|
||||||
x = -x;
|
x = -x;
|
||||||
@ -56,16 +56,16 @@ static const uint8_t *integer_to_string(Gst *vm, GstInteger x) {
|
|||||||
*low++ = *hi;
|
*low++ = *hi;
|
||||||
*hi-- = temp;
|
*hi-- = temp;
|
||||||
}
|
}
|
||||||
return gst_string_b(vm, buf, (uint32_t) count);
|
return dst_string_b(vm, buf, (uint32_t) count);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *HEX_CHARACTERS = "0123456789abcdef";
|
static const char *HEX_CHARACTERS = "0123456789abcdef";
|
||||||
#define HEX(i) (((uint8_t *) HEX_CHARACTERS)[(i)])
|
#define HEX(i) (((uint8_t *) HEX_CHARACTERS)[(i)])
|
||||||
|
|
||||||
/* Returns a string description for a pointer. Max titlelen is GST_BUFSIZE
|
/* Returns a string description for a pointer. Max titlelen is DST_BUFSIZE
|
||||||
* - 5 - 2 * sizeof(void *). */
|
* - 5 - 2 * sizeof(void *). */
|
||||||
static const uint8_t *string_description(Gst *vm, const char *title, void *pointer) {
|
static const uint8_t *string_description(Dst *vm, const char *title, void *pointer) {
|
||||||
uint8_t buf[GST_BUFSIZE];
|
uint8_t buf[DST_BUFSIZE];
|
||||||
uint8_t *c = buf;
|
uint8_t *c = buf;
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
union {
|
union {
|
||||||
@ -87,12 +87,12 @@ static const uint8_t *string_description(Gst *vm, const char *title, void *point
|
|||||||
*c++ = HEX(byte & 0xF);
|
*c++ = HEX(byte & 0xF);
|
||||||
}
|
}
|
||||||
*c++ = '>';
|
*c++ = '>';
|
||||||
return gst_string_b(vm, buf, c - buf);
|
return dst_string_b(vm, buf, c - buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Gets the string value of userdata. Allocates memory, so is slower than
|
/* Gets the string value of userdata. Allocates memory, so is slower than
|
||||||
* string_description. */
|
* string_description. */
|
||||||
static const uint8_t *string_udata(Gst *vm, const char *title, void *pointer) {
|
static const uint8_t *string_udata(Dst *vm, const char *title, void *pointer) {
|
||||||
uint32_t strlen = 0;
|
uint32_t strlen = 0;
|
||||||
uint8_t *c, *buf;
|
uint8_t *c, *buf;
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
@ -102,7 +102,7 @@ static const uint8_t *string_udata(Gst *vm, const char *title, void *pointer) {
|
|||||||
} pbuf;
|
} pbuf;
|
||||||
|
|
||||||
while (title[strlen]) ++strlen;
|
while (title[strlen]) ++strlen;
|
||||||
c = buf = gst_alloc(vm, strlen + 5 + 2 * sizeof(void *));
|
c = buf = dst_alloc(vm, strlen + 5 + 2 * sizeof(void *));
|
||||||
pbuf.p = pointer;
|
pbuf.p = pointer;
|
||||||
*c++ = '<';
|
*c++ = '<';
|
||||||
for (i = 0; title[i]; ++i)
|
for (i = 0; title[i]; ++i)
|
||||||
@ -117,180 +117,187 @@ static const uint8_t *string_udata(Gst *vm, const char *title, void *pointer) {
|
|||||||
*c++ = HEX(byte & 0xF);
|
*c++ = HEX(byte & 0xF);
|
||||||
}
|
}
|
||||||
*c++ = '>';
|
*c++ = '>';
|
||||||
return gst_string_b(vm, buf, c - buf);
|
return dst_string_b(vm, buf, c - buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef GST_BUFSIZE
|
#undef DST_BUFSIZE
|
||||||
|
|
||||||
void gst_escape_string(Gst *vm, GstBuffer *b, const uint8_t *str) {
|
void dst_escape_string(Dst *vm, DstBuffer *b, const uint8_t *str) {
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
gst_buffer_push(vm, b, '"');
|
dst_buffer_push(vm, b, '"');
|
||||||
for (i = 0; i < gst_string_length(str); ++i) {
|
for (i = 0; i < dst_string_length(str); ++i) {
|
||||||
uint8_t c = str[i];
|
uint8_t c = str[i];
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case '"':
|
case '"':
|
||||||
gst_buffer_push(vm, b, '\\');
|
dst_buffer_push(vm, b, '\\');
|
||||||
gst_buffer_push(vm, b, '"');
|
dst_buffer_push(vm, b, '"');
|
||||||
break;
|
break;
|
||||||
case '\n':
|
case '\n':
|
||||||
gst_buffer_push(vm, b, '\\');
|
dst_buffer_push(vm, b, '\\');
|
||||||
gst_buffer_push(vm, b, 'n');
|
dst_buffer_push(vm, b, 'n');
|
||||||
break;
|
break;
|
||||||
case '\r':
|
case '\r':
|
||||||
gst_buffer_push(vm, b, '\\');
|
dst_buffer_push(vm, b, '\\');
|
||||||
gst_buffer_push(vm, b, 'r');
|
dst_buffer_push(vm, b, 'r');
|
||||||
break;
|
break;
|
||||||
case '\0':
|
case '\0':
|
||||||
gst_buffer_push(vm, b, '\\');
|
dst_buffer_push(vm, b, '\\');
|
||||||
gst_buffer_push(vm, b, '0');
|
dst_buffer_push(vm, b, '0');
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
gst_buffer_push(vm, b, c);
|
dst_buffer_push(vm, b, c);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
gst_buffer_push(vm, b, '"');
|
dst_buffer_push(vm, b, '"');
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns a string pointer with the description of the string */
|
/* Returns a string pointer with the description of the string */
|
||||||
const uint8_t *gst_short_description(Gst *vm, GstValue x) {
|
const uint8_t *dst_short_description(Dst *vm, DstValue x) {
|
||||||
switch (x.type) {
|
switch (x.type) {
|
||||||
case GST_NIL:
|
case DST_NIL:
|
||||||
return gst_string_c(vm, "nil");
|
return dst_string_c(vm, "nil");
|
||||||
case GST_BOOLEAN:
|
case DST_BOOLEAN:
|
||||||
if (x.data.boolean)
|
if (x.data.boolean)
|
||||||
return gst_string_c(vm, "true");
|
return dst_string_c(vm, "true");
|
||||||
else
|
else
|
||||||
return gst_string_c(vm, "false");
|
return dst_string_c(vm, "false");
|
||||||
case GST_REAL:
|
case DST_REAL:
|
||||||
return real_to_string(vm, x.data.real);
|
return real_to_string(vm, x.data.real);
|
||||||
case GST_INTEGER:
|
case DST_INTEGER:
|
||||||
return integer_to_string(vm, x.data.integer);
|
return integer_to_string(vm, x.data.integer);
|
||||||
case GST_ARRAY:
|
case DST_ARRAY:
|
||||||
return string_description(vm, "array", x.data.pointer);
|
return string_description(vm, "array", x.data.pointer);
|
||||||
case GST_TUPLE:
|
case DST_TUPLE:
|
||||||
return string_description(vm, "tuple", x.data.pointer);
|
return string_description(vm, "tuple", x.data.pointer);
|
||||||
case GST_STRUCT:
|
case DST_STRUCT:
|
||||||
return string_description(vm, "struct", x.data.pointer);
|
return string_description(vm, "struct", x.data.pointer);
|
||||||
case GST_TABLE:
|
case DST_TABLE:
|
||||||
return string_description(vm, "table", x.data.pointer);
|
return string_description(vm, "table", x.data.pointer);
|
||||||
case GST_SYMBOL:
|
case DST_SYMBOL:
|
||||||
return x.data.string;
|
return x.data.string;
|
||||||
case GST_STRING:
|
case DST_STRING:
|
||||||
{
|
{
|
||||||
GstBuffer *buf = gst_buffer(vm, gst_string_length(x.data.string) + 4);
|
DstBuffer *buf = dst_buffer(vm, dst_string_length(x.data.string) + 4);
|
||||||
gst_escape_string(vm, buf, x.data.string);
|
dst_escape_string(vm, buf, x.data.string);
|
||||||
return gst_buffer_to_string(vm, buf);
|
return dst_buffer_to_string(vm, buf);
|
||||||
}
|
}
|
||||||
case GST_BYTEBUFFER:
|
case DST_BYTEBUFFER:
|
||||||
return string_description(vm, "buffer", x.data.pointer);
|
return string_description(vm, "buffer", x.data.pointer);
|
||||||
case GST_CFUNCTION:
|
case DST_CFUNCTION:
|
||||||
return string_description(vm, "cfunction", x.data.pointer);
|
return string_description(vm, "cfunction", x.data.pointer);
|
||||||
case GST_FUNCTION:
|
case DST_FUNCTION:
|
||||||
return string_description(vm, "function", x.data.pointer);
|
return string_description(vm, "function", x.data.pointer);
|
||||||
case GST_THREAD:
|
case DST_THREAD:
|
||||||
return string_description(vm, "thread", x.data.pointer);
|
return string_description(vm, "thread", x.data.pointer);
|
||||||
case GST_USERDATA:
|
case DST_USERDATA:
|
||||||
return string_udata(vm, gst_udata_type(x.data.pointer)->name, x.data.pointer);
|
return string_udata(vm, dst_udata_type(x.data.pointer)->name, x.data.pointer);
|
||||||
case GST_FUNCENV:
|
case DST_FUNCENV:
|
||||||
return string_description(vm, "funcenv", x.data.pointer);
|
return string_description(vm, "funcenv", x.data.pointer);
|
||||||
case GST_FUNCDEF:
|
case DST_FUNCDEF:
|
||||||
return string_description(vm, "funcdef", x.data.pointer);
|
return string_description(vm, "funcdef", x.data.pointer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static DstValue wrap_integer(DstInteger i) {
|
||||||
|
DstValue v;
|
||||||
|
v.type = DST_INTEGER;
|
||||||
|
v.data.integer = i;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
/* Static debug print helper */
|
/* Static debug print helper */
|
||||||
static GstInteger gst_description_helper(Gst *vm, GstBuffer *b, GstTable *seen, GstValue x, GstInteger next, int depth) {
|
static DstInteger dst_description_helper(Dst *vm, DstBuffer *b, DstTable *seen, DstValue x, DstInteger next, int depth) {
|
||||||
GstValue check = gst_table_get(seen, x);
|
DstValue check = dst_table_get(seen, x);
|
||||||
const uint8_t *str;
|
const uint8_t *str;
|
||||||
/* Prevent a stack overflow */
|
/* Prevent a stack overflow */
|
||||||
if (depth++ > GST_RECURSION_GUARD)
|
if (depth++ > DST_RECURSION_GUARD)
|
||||||
return -1;
|
return -1;
|
||||||
if (check.type == GST_INTEGER) {
|
if (check.type == DST_INTEGER) {
|
||||||
str = integer_to_string(vm, check.data.integer);
|
str = integer_to_string(vm, check.data.integer);
|
||||||
gst_buffer_append_cstring(vm, b, "<visited ");
|
dst_buffer_append_cstring(vm, b, "<visited ");
|
||||||
gst_buffer_append(vm, b, str, gst_string_length(str));
|
dst_buffer_append(vm, b, str, dst_string_length(str));
|
||||||
gst_buffer_append_cstring(vm, b, ">");
|
dst_buffer_append_cstring(vm, b, ">");
|
||||||
} else {
|
} else {
|
||||||
uint8_t open, close;
|
uint8_t open, close;
|
||||||
uint32_t len, i;
|
uint32_t len, i;
|
||||||
const GstValue *data;
|
const DstValue *data;
|
||||||
switch (x.type) {
|
switch (x.type) {
|
||||||
default:
|
default:
|
||||||
str = gst_short_description(vm, x);
|
str = dst_short_description(vm, x);
|
||||||
gst_buffer_append(vm, b, str, gst_string_length(str));
|
dst_buffer_append(vm, b, str, dst_string_length(str));
|
||||||
return next;
|
return next;
|
||||||
case GST_STRING:
|
case DST_STRING:
|
||||||
gst_escape_string(vm, b, x.data.string);
|
dst_escape_string(vm, b, x.data.string);
|
||||||
return next;
|
return next;
|
||||||
case GST_SYMBOL:
|
case DST_SYMBOL:
|
||||||
gst_buffer_append(vm, b, x.data.string, gst_string_length(x.data.string));
|
dst_buffer_append(vm, b, x.data.string, dst_string_length(x.data.string));
|
||||||
return next;
|
return next;
|
||||||
case GST_NIL:
|
case DST_NIL:
|
||||||
gst_buffer_append_cstring(vm, b, "nil");
|
dst_buffer_append_cstring(vm, b, "nil");
|
||||||
return next;
|
return next;
|
||||||
case GST_BOOLEAN:
|
case DST_BOOLEAN:
|
||||||
gst_buffer_append_cstring(vm, b, x.data.boolean ? "true" : "false");
|
dst_buffer_append_cstring(vm, b, x.data.boolean ? "true" : "false");
|
||||||
return next;
|
return next;
|
||||||
case GST_STRUCT:
|
case DST_STRUCT:
|
||||||
open = '<'; close = '>';
|
open = '<'; close = '>';
|
||||||
break;
|
break;
|
||||||
case GST_TABLE:
|
case DST_TABLE:
|
||||||
open = '{'; close = '}';
|
open = '{'; close = '}';
|
||||||
break;
|
break;
|
||||||
case GST_TUPLE:
|
case DST_TUPLE:
|
||||||
open = '('; close = ')';
|
open = '('; close = ')';
|
||||||
break;
|
break;
|
||||||
case GST_ARRAY:
|
case DST_ARRAY:
|
||||||
open = '['; close = ']';
|
open = '['; close = ']';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
gst_table_put(vm, seen, x, gst_wrap_integer(next++));
|
dst_table_put(vm, seen, x, wrap_integer(next++));
|
||||||
gst_buffer_push(vm, b, open);
|
dst_buffer_push(vm, b, open);
|
||||||
if (gst_hashtable_view(x, &data, &len)) {
|
if (dst_hashtable_view(x, &data, &len)) {
|
||||||
int isfirst = 1;
|
int isfirst = 1;
|
||||||
for (i = 0; i < len; i += 2) {
|
for (i = 0; i < len; i += 2) {
|
||||||
if (data[i].type != GST_NIL) {
|
if (data[i].type != DST_NIL) {
|
||||||
if (isfirst)
|
if (isfirst)
|
||||||
isfirst = 0;
|
isfirst = 0;
|
||||||
else
|
else
|
||||||
gst_buffer_push(vm, b, ' ');
|
dst_buffer_push(vm, b, ' ');
|
||||||
next = gst_description_helper(vm, b, seen, data[i], next, depth);
|
next = dst_description_helper(vm, b, seen, data[i], next, depth);
|
||||||
if (next == -1)
|
if (next == -1)
|
||||||
gst_buffer_append_cstring(vm, b, "...");
|
dst_buffer_append_cstring(vm, b, "...");
|
||||||
gst_buffer_push(vm, b, ' ');
|
dst_buffer_push(vm, b, ' ');
|
||||||
next = gst_description_helper(vm, b, seen, data[i + 1], next, depth);
|
next = dst_description_helper(vm, b, seen, data[i + 1], next, depth);
|
||||||
if (next == -1)
|
if (next == -1)
|
||||||
gst_buffer_append_cstring(vm, b, "...");
|
dst_buffer_append_cstring(vm, b, "...");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (gst_seq_view(x, &data, &len)) {
|
} else if (dst_seq_view(x, &data, &len)) {
|
||||||
for (i = 0; i < len; ++i) {
|
for (i = 0; i < len; ++i) {
|
||||||
next = gst_description_helper(vm, b, seen, data[i], next, depth);
|
next = dst_description_helper(vm, b, seen, data[i], next, depth);
|
||||||
if (next == -1)
|
if (next == -1)
|
||||||
return -1;
|
return -1;
|
||||||
if (i != len - 1)
|
if (i != len - 1)
|
||||||
gst_buffer_push(vm, b, ' ');
|
dst_buffer_push(vm, b, ' ');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
gst_buffer_push(vm, b, close);
|
dst_buffer_push(vm, b, close);
|
||||||
}
|
}
|
||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Debug print. Returns a description of an object as a buffer. */
|
/* Debug print. Returns a description of an object as a buffer. */
|
||||||
const uint8_t *gst_description(Gst *vm, GstValue x) {
|
const uint8_t *dst_description(Dst *vm, DstValue x) {
|
||||||
GstBuffer *buf = gst_buffer(vm, 10);
|
DstBuffer *buf = dst_buffer(vm, 10);
|
||||||
gst_description_helper(vm, buf, gst_table(vm, 10), x, 0, 0);
|
dst_description_helper(vm, buf, dst_table(vm, 10), x, 0, 0);
|
||||||
return gst_buffer_to_string(vm, buf);
|
return dst_buffer_to_string(vm, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint8_t *gst_to_string(Gst *vm, GstValue x) {
|
const uint8_t *dst_to_string(Dst *vm, DstValue x) {
|
||||||
if (x.type == GST_STRING || x.type == GST_SYMBOL) {
|
if (x.type == DST_STRING || x.type == DST_SYMBOL) {
|
||||||
return x.data.string;
|
return x.data.string;
|
||||||
} else if (x.type == GST_BYTEBUFFER) {
|
} else if (x.type == DST_BYTEBUFFER) {
|
||||||
return gst_buffer_to_string(vm, x.data.buffer);
|
return dst_buffer_to_string(vm, x.data.buffer);
|
||||||
} else {
|
} else {
|
||||||
return gst_description(vm, x);
|
return dst_description(vm, x);
|
||||||
}
|
}
|
||||||
}
|
}
|
155
core/thread.c
155
core/thread.c
@ -20,155 +20,154 @@
|
|||||||
* IN THE SOFTWARE.
|
* IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include "internal.h"
|
||||||
|
|
||||||
/* Create a new thread */
|
/* Create a new thread */
|
||||||
GstThread *gst_thread(Gst *vm, GstValue callee, uint32_t capacity) {
|
DstThread *dst_thread(Dst *vm, DstValue callee, uint32_t capacity) {
|
||||||
GstThread *thread = gst_alloc(vm, sizeof(GstThread));
|
DstThread *thread = dst_alloc(vm, sizeof(DstThread));
|
||||||
if (capacity < GST_FRAME_SIZE) capacity = GST_FRAME_SIZE;
|
if (capacity < DST_FRAME_SIZE) capacity = DST_FRAME_SIZE;
|
||||||
thread->data = gst_alloc(vm, sizeof(GstValue) * capacity);
|
thread->data = dst_alloc(vm, sizeof(DstValue) * capacity);
|
||||||
thread->capacity = capacity;
|
thread->capacity = capacity;
|
||||||
return gst_thread_reset(vm, thread, callee);
|
return dst_thread_reset(vm, thread, callee);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clear a thread (reset it) */
|
/* Clear a thread (reset it) */
|
||||||
GstThread *gst_thread_reset(Gst *vm, GstThread *thread, GstValue callee) {
|
DstThread *dst_thread_reset(Dst *vm, DstThread *thread, DstValue callee) {
|
||||||
GstValue *stack;
|
DstValue *stack;
|
||||||
thread->count = GST_FRAME_SIZE;
|
thread->count = DST_FRAME_SIZE;
|
||||||
thread->status = GST_THREAD_PENDING;
|
thread->status = DST_THREAD_PENDING;
|
||||||
stack = thread->data + GST_FRAME_SIZE;
|
stack = thread->data + DST_FRAME_SIZE;
|
||||||
gst_frame_size(stack) = 0;
|
dst_frame_size(stack) = 0;
|
||||||
gst_frame_prevsize(stack) = 0;
|
dst_frame_prevsize(stack) = 0;
|
||||||
gst_frame_ret(stack) = 0;
|
dst_frame_ret(stack) = 0;
|
||||||
gst_frame_args(stack) = 0;
|
dst_frame_args(stack) = 0;
|
||||||
gst_frame_pc(stack) = NULL;
|
dst_frame_pc(stack) = NULL;
|
||||||
gst_frame_env(stack) = NULL;
|
dst_frame_env(stack) = NULL;
|
||||||
gst_frame_callee(stack) = callee;
|
dst_frame_callee(stack) = callee;
|
||||||
gst_thread_endframe(vm, thread);
|
dst_thread_endframe(vm, thread);
|
||||||
thread->parent = NULL; /* Need to set parent manually */
|
thread->parent = NULL; /* Need to set parent manually */
|
||||||
thread->errorParent = NULL;
|
|
||||||
return thread;
|
return thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ensure that the thread has enough EXTRA capacity */
|
/* Ensure that the thread has enough EXTRA capacity */
|
||||||
void gst_thread_ensure_extra(Gst *vm, GstThread *thread, uint32_t extra) {
|
void dst_thread_ensure_extra(Dst *vm, DstThread *thread, uint32_t extra) {
|
||||||
GstValue *newData, *stack;
|
DstValue *newData, *stack;
|
||||||
uint32_t usedCapacity, neededCapacity, newCapacity;
|
uint32_t usedCapacity, neededCapacity, newCapacity;
|
||||||
stack = thread->data + thread->count;
|
stack = thread->data + thread->count;
|
||||||
usedCapacity = thread->count + gst_frame_size(stack) + GST_FRAME_SIZE;
|
usedCapacity = thread->count + dst_frame_size(stack) + DST_FRAME_SIZE;
|
||||||
neededCapacity = usedCapacity + extra;
|
neededCapacity = usedCapacity + extra;
|
||||||
if (thread->capacity >= neededCapacity) return;
|
if (thread->capacity >= neededCapacity) return;
|
||||||
newCapacity = 2 * neededCapacity;
|
newCapacity = 2 * neededCapacity;
|
||||||
newData = gst_alloc(vm, sizeof(GstValue) * newCapacity);
|
newData = dst_alloc(vm, sizeof(DstValue) * newCapacity);
|
||||||
gst_memcpy(newData, thread->data, sizeof(GstValue) * usedCapacity);
|
dst_memcpy(newData, thread->data, sizeof(DstValue) * usedCapacity);
|
||||||
thread->data = newData;
|
thread->data = newData;
|
||||||
thread->capacity = newCapacity;
|
thread->capacity = newCapacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Push a value on the current stack frame*/
|
/* Push a value on the current stack frame*/
|
||||||
void gst_thread_push(Gst *vm, GstThread *thread, GstValue x) {
|
void dst_thread_push(Dst *vm, DstThread *thread, DstValue x) {
|
||||||
GstValue *stack;
|
DstValue *stack;
|
||||||
gst_thread_ensure_extra(vm, thread, 1);
|
dst_thread_ensure_extra(vm, thread, 1);
|
||||||
stack = thread->data + thread->count;
|
stack = thread->data + thread->count;
|
||||||
stack[gst_frame_size(stack)++] = x;
|
stack[dst_frame_size(stack)++] = x;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Push n nils onto the stack */
|
/* Push n nils onto the stack */
|
||||||
void gst_thread_pushnil(Gst *vm, GstThread *thread, uint32_t n) {
|
void dst_thread_pushnil(Dst *vm, DstThread *thread, uint32_t n) {
|
||||||
GstValue *stack, *current, *end;
|
DstValue *stack, *current, *end;
|
||||||
gst_thread_ensure_extra(vm, thread, n);
|
dst_thread_ensure_extra(vm, thread, n);
|
||||||
stack = thread->data + thread->count;
|
stack = thread->data + thread->count;
|
||||||
current = stack + gst_frame_size(stack);
|
current = stack + dst_frame_size(stack);
|
||||||
end = current + n;
|
end = current + n;
|
||||||
for (; current < end; ++current) {
|
for (; current < end; ++current) {
|
||||||
current->type = GST_NIL;
|
current->type = DST_NIL;
|
||||||
}
|
}
|
||||||
gst_frame_size(stack) += n;
|
dst_frame_size(stack) += n;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Package up extra args after and including n into tuple at n*/
|
/* Package up extra args after and including n into tuple at n*/
|
||||||
void gst_thread_tuplepack(Gst *vm, GstThread *thread, uint32_t n) {
|
void dst_thread_tuplepack(Dst *vm, DstThread *thread, uint32_t n) {
|
||||||
GstValue *stack = thread->data + thread->count;
|
DstValue *stack = thread->data + thread->count;
|
||||||
uint32_t size = gst_frame_size(stack);
|
uint32_t size = dst_frame_size(stack);
|
||||||
if (n >= size) {
|
if (n >= size) {
|
||||||
/* Push one extra nil to ensure space for tuple */
|
/* Push one extra nil to ensure space for tuple */
|
||||||
gst_thread_pushnil(vm, thread, n - size + 1);
|
dst_thread_pushnil(vm, thread, n - size + 1);
|
||||||
stack = thread->data + thread->count;
|
stack = thread->data + thread->count;
|
||||||
stack[n].type = GST_TUPLE;
|
stack[n].type = DST_TUPLE;
|
||||||
stack[n].data.tuple = gst_tuple_end(vm, gst_tuple_begin(vm, 0));
|
stack[n].data.tuple = dst_tuple_end(vm, dst_tuple_begin(vm, 0));
|
||||||
gst_frame_size(stack) = n + 1;
|
dst_frame_size(stack) = n + 1;
|
||||||
} else {
|
} else {
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
GstValue *tuple = gst_tuple_begin(vm, size - n);
|
DstValue *tuple = dst_tuple_begin(vm, size - n);
|
||||||
for (i = n; i < size; ++i)
|
for (i = n; i < size; ++i)
|
||||||
tuple[i - n] = stack[i];
|
tuple[i - n] = stack[i];
|
||||||
stack[n].type = GST_TUPLE;
|
stack[n].type = DST_TUPLE;
|
||||||
stack[n].data.tuple = gst_tuple_end(vm, tuple);
|
stack[n].data.tuple = dst_tuple_end(vm, tuple);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Push a stack frame to a thread, with space for arity arguments. Returns the new
|
/* Push a stack frame to a thread, with space for arity arguments. Returns the new
|
||||||
* stack. */
|
* stack. */
|
||||||
GstValue *gst_thread_beginframe(Gst *vm, GstThread *thread, GstValue callee, uint32_t arity) {
|
DstValue *dst_thread_beginframe(Dst *vm, DstThread *thread, DstValue callee, uint32_t arity) {
|
||||||
uint32_t frameOffset;
|
uint32_t frameOffset;
|
||||||
GstValue *oldStack, *newStack;
|
DstValue *oldStack, *newStack;
|
||||||
|
|
||||||
/* Push the frame */
|
/* Push the frame */
|
||||||
gst_thread_ensure_extra(vm, thread, GST_FRAME_SIZE + arity + 4);
|
dst_thread_ensure_extra(vm, thread, DST_FRAME_SIZE + arity + 4);
|
||||||
oldStack = thread->data + thread->count;
|
oldStack = thread->data + thread->count;
|
||||||
frameOffset = gst_frame_size(oldStack) + GST_FRAME_SIZE;
|
frameOffset = dst_frame_size(oldStack) + DST_FRAME_SIZE;
|
||||||
newStack = oldStack + frameOffset;
|
newStack = oldStack + frameOffset;
|
||||||
gst_frame_prevsize(newStack) = gst_frame_size(oldStack);
|
dst_frame_prevsize(newStack) = dst_frame_size(oldStack);
|
||||||
gst_frame_env(newStack) = NULL;
|
dst_frame_env(newStack) = NULL;
|
||||||
gst_frame_size(newStack) = 0;
|
dst_frame_size(newStack) = 0;
|
||||||
gst_frame_callee(newStack) = callee;
|
dst_frame_callee(newStack) = callee;
|
||||||
thread->count += frameOffset;
|
thread->count += frameOffset;
|
||||||
|
|
||||||
/* Ensure the extra space and initialize to nil */
|
/* Ensure the extra space and initialize to nil */
|
||||||
gst_thread_pushnil(vm, thread, arity);
|
dst_thread_pushnil(vm, thread, arity);
|
||||||
|
|
||||||
/* Return ok */
|
/* Return ok */
|
||||||
return thread->data + thread->count;
|
return thread->data + thread->count;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* After pushing arguments to a stack frame created with gst_thread_beginframe, call this
|
/* After pushing arguments to a stack frame created with dst_thread_beginframe, call this
|
||||||
* to finalize the frame before starting a function call. */
|
* to finalize the frame before starting a function call. */
|
||||||
void gst_thread_endframe(Gst *vm, GstThread *thread) {
|
void dst_thread_endframe(Dst *vm, DstThread *thread) {
|
||||||
GstValue *stack = thread->data + thread->count;
|
DstValue *stack = thread->data + thread->count;
|
||||||
GstValue callee = gst_frame_callee(stack);
|
DstValue callee = dst_frame_callee(stack);
|
||||||
if (callee.type == GST_FUNCTION) {
|
if (callee.type == DST_FUNCTION) {
|
||||||
GstFunction *fn = callee.data.function;
|
DstFunction *fn = callee.data.function;
|
||||||
uint32_t locals = fn->def->locals;
|
uint32_t locals = fn->def->locals;
|
||||||
gst_frame_pc(stack) = fn->def->byteCode;
|
dst_frame_pc(stack) = fn->def->byteCode;
|
||||||
if (fn->def->flags & GST_FUNCDEF_FLAG_VARARG) {
|
if (fn->def->flags & DST_FUNCDEF_FLAG_VARARG) {
|
||||||
uint32_t arity = fn->def->arity;
|
uint32_t arity = fn->def->arity;
|
||||||
gst_thread_tuplepack(vm, thread, arity);
|
dst_thread_tuplepack(vm, thread, arity);
|
||||||
}
|
}
|
||||||
if (gst_frame_size(stack) < locals) {
|
if (dst_frame_size(stack) < locals) {
|
||||||
gst_thread_pushnil(vm, thread, locals - gst_frame_size(stack));
|
dst_thread_pushnil(vm, thread, locals - dst_frame_size(stack));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Pop a stack frame from the thread. Returns the new stack frame, or
|
/* Pop a stack frame from the thread. Returns the new stack frame, or
|
||||||
* NULL if there are no more frames */
|
* NULL if there are no more frames */
|
||||||
GstValue *gst_thread_popframe(Gst *vm, GstThread *thread) {
|
DstValue *dst_thread_popframe(Dst *vm, DstThread *thread) {
|
||||||
GstValue *stack = thread->data + thread->count;
|
DstValue *stack = thread->data + thread->count;
|
||||||
uint32_t prevsize = gst_frame_prevsize(stack);
|
uint32_t prevsize = dst_frame_prevsize(stack);
|
||||||
GstValue *nextstack = stack - GST_FRAME_SIZE - prevsize;
|
DstValue *nextstack = stack - DST_FRAME_SIZE - prevsize;
|
||||||
GstFuncEnv *env = gst_frame_env(stack);
|
DstFuncEnv *env = dst_frame_env(stack);
|
||||||
|
|
||||||
/* Check for closures */
|
/* Check for closures */
|
||||||
if (env != NULL) {
|
if (env != NULL) {
|
||||||
uint32_t size = gst_frame_size(stack);
|
uint32_t size = dst_frame_size(stack);
|
||||||
env->thread = NULL;
|
env->thread = NULL;
|
||||||
env->stackOffset = size;
|
env->stackOffset = size;
|
||||||
env->values = gst_alloc(vm, sizeof(GstValue) * size);
|
env->values = dst_alloc(vm, sizeof(DstValue) * size);
|
||||||
gst_memcpy(env->values, stack, sizeof(GstValue) * size);
|
dst_memcpy(env->values, stack, sizeof(DstValue) * size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Shrink stack */
|
/* Shrink stack */
|
||||||
thread->count -= GST_FRAME_SIZE + prevsize;
|
thread->count -= DST_FRAME_SIZE + prevsize;
|
||||||
|
|
||||||
/* Check if the stack is empty, and if so, return null */
|
/* Check if the stack is empty, and if so, return null */
|
||||||
if (thread->count)
|
if (thread->count)
|
||||||
@ -178,13 +177,13 @@ GstValue *gst_thread_popframe(Gst *vm, GstThread *thread) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Count the number of stack frames in a thread */
|
/* Count the number of stack frames in a thread */
|
||||||
uint32_t gst_thread_countframes(GstThread *thread) {
|
uint32_t dst_thread_countframes(DstThread *thread) {
|
||||||
uint32_t count = 0;
|
uint32_t count = 0;
|
||||||
const GstValue *stack = thread->data + GST_FRAME_SIZE;
|
const DstValue *stack = thread->data + DST_FRAME_SIZE;
|
||||||
const GstValue *laststack = thread->data + thread->count;
|
const DstValue *laststack = thread->data + thread->count;
|
||||||
while (stack <= laststack) {
|
while (stack <= laststack) {
|
||||||
++count;
|
++count;
|
||||||
stack += gst_frame_size(stack) + GST_FRAME_SIZE;
|
stack += dst_frame_size(stack) + DST_FRAME_SIZE;
|
||||||
}
|
}
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
276
core/util.c
276
core/util.c
@ -20,70 +20,7 @@
|
|||||||
* IN THE SOFTWARE.
|
* IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include "internal.h"
|
||||||
|
|
||||||
/* Wrapper functions wrap a data type that is used from C into a
|
|
||||||
* gst value, which can then be used in gst. */
|
|
||||||
|
|
||||||
GstValue gst_wrap_nil() {
|
|
||||||
GstValue y;
|
|
||||||
y.type = GST_NIL;
|
|
||||||
return y;
|
|
||||||
}
|
|
||||||
|
|
||||||
int gst_check_nil(Gst *vm, uint32_t i) {
|
|
||||||
GstValue a = gst_arg(vm, i);
|
|
||||||
return a.type == GST_NIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define GST_WRAP_DEFINE(NAME, TYPE, GTYPE, UM)\
|
|
||||||
GstValue gst_wrap_##NAME(TYPE x) {\
|
|
||||||
GstValue y;\
|
|
||||||
y.type = GTYPE;\
|
|
||||||
y.data.UM = x;\
|
|
||||||
return y;\
|
|
||||||
}\
|
|
||||||
\
|
|
||||||
int gst_check_##NAME(Gst *vm, uint32_t i, TYPE (*out)) {\
|
|
||||||
GstValue a = gst_arg(vm, i);\
|
|
||||||
if (a.type != GTYPE) return 0;\
|
|
||||||
*out = a.data.UM;\
|
|
||||||
return 1;\
|
|
||||||
}\
|
|
||||||
|
|
||||||
GST_WRAP_DEFINE(real, GstReal, GST_REAL, real)
|
|
||||||
GST_WRAP_DEFINE(integer, GstInteger, GST_INTEGER, integer)
|
|
||||||
GST_WRAP_DEFINE(boolean, int, GST_BOOLEAN, boolean)
|
|
||||||
GST_WRAP_DEFINE(string, const uint8_t *, GST_STRING, string)
|
|
||||||
GST_WRAP_DEFINE(symbol, const uint8_t *, GST_SYMBOL, string)
|
|
||||||
GST_WRAP_DEFINE(array, GstArray *, GST_ARRAY, array)
|
|
||||||
GST_WRAP_DEFINE(tuple, const GstValue *, GST_TUPLE, tuple)
|
|
||||||
GST_WRAP_DEFINE(struct, const GstValue *, GST_STRUCT, st)
|
|
||||||
GST_WRAP_DEFINE(thread, GstThread *, GST_THREAD, thread)
|
|
||||||
GST_WRAP_DEFINE(buffer, GstBuffer *, GST_BYTEBUFFER, buffer)
|
|
||||||
GST_WRAP_DEFINE(function, GstFunction *, GST_FUNCTION, function)
|
|
||||||
GST_WRAP_DEFINE(cfunction, GstCFunction, GST_CFUNCTION, cfunction)
|
|
||||||
GST_WRAP_DEFINE(table, GstTable *, GST_TABLE, table)
|
|
||||||
GST_WRAP_DEFINE(funcenv, GstFuncEnv *, GST_FUNCENV, env)
|
|
||||||
GST_WRAP_DEFINE(funcdef, GstFuncDef *, GST_FUNCDEF, def)
|
|
||||||
|
|
||||||
#undef GST_WRAP_DEFINE
|
|
||||||
|
|
||||||
GstValue gst_wrap_userdata(void *x) {
|
|
||||||
GstValue ret;
|
|
||||||
ret.type = GST_USERDATA;
|
|
||||||
ret.data.pointer = x;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *gst_check_userdata(Gst *vm, uint32_t i, const GstUserType *type) {
|
|
||||||
GstValue x = gst_arg(vm, i);
|
|
||||||
GstUserdataHeader *h;
|
|
||||||
if (x.type != GST_USERDATA) return NULL;
|
|
||||||
h = gst_udata_header(x.data.pointer);
|
|
||||||
if (h->type != type) return NULL;
|
|
||||||
return x.data.pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****/
|
/****/
|
||||||
/* Parsing utils */
|
/* Parsing utils */
|
||||||
@ -105,7 +42,7 @@ static double exp10(int power) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int gst_read_integer(const uint8_t *string, const uint8_t *end, int64_t *ret) {
|
int dst_read_integer(const uint8_t *string, const uint8_t *end, int64_t *ret) {
|
||||||
int sign = 1, x = 0;
|
int sign = 1, x = 0;
|
||||||
int64_t accum = 0;
|
int64_t accum = 0;
|
||||||
if (*string == '-') {
|
if (*string == '-') {
|
||||||
@ -129,7 +66,7 @@ int gst_read_integer(const uint8_t *string, const uint8_t *end, int64_t *ret) {
|
|||||||
/* Read a real from a string. Returns if successfuly
|
/* Read a real from a string. Returns if successfuly
|
||||||
* parsed a real from the enitre input string.
|
* parsed a real from the enitre input string.
|
||||||
* If returned 1, output is int ret.*/
|
* If returned 1, output is int ret.*/
|
||||||
int gst_read_real(const uint8_t *string, const uint8_t *end, double *ret, int forceInt) {
|
int dst_read_real(const uint8_t *string, const uint8_t *end, double *ret, int forceInt) {
|
||||||
int sign = 1, x = 0;
|
int sign = 1, x = 0;
|
||||||
double accum = 0, exp = 1, place = 1;
|
double accum = 0, exp = 1, place = 1;
|
||||||
/* Check the sign */
|
/* Check the sign */
|
||||||
@ -147,7 +84,7 @@ int gst_read_real(const uint8_t *string, const uint8_t *end, double *ret, int fo
|
|||||||
/* Read the exponent */
|
/* Read the exponent */
|
||||||
++string;
|
++string;
|
||||||
if (string >= end) return 0;
|
if (string >= end) return 0;
|
||||||
if (!gst_read_real(string, end, &exp, 1))
|
if (!dst_read_real(string, end, &exp, 1))
|
||||||
return 0;
|
return 0;
|
||||||
exp = exp10(exp);
|
exp = exp10(exp);
|
||||||
break;
|
break;
|
||||||
@ -173,14 +110,14 @@ int gst_read_real(const uint8_t *string, const uint8_t *end, double *ret, int fo
|
|||||||
|
|
||||||
/* Read both tuples and arrays as c pointers + uint32_t length. Return 1 if the
|
/* Read both tuples and arrays as c pointers + uint32_t length. Return 1 if the
|
||||||
* view can be constructed, 0 if an invalid type. */
|
* view can be constructed, 0 if an invalid type. */
|
||||||
int gst_seq_view(GstValue seq, const GstValue **data, uint32_t *len) {
|
int dst_seq_view(DstValue seq, const DstValue **data, uint32_t *len) {
|
||||||
if (seq.type == GST_ARRAY) {
|
if (seq.type == DST_ARRAY) {
|
||||||
*data = seq.data.array->data;
|
*data = seq.data.array->data;
|
||||||
*len = seq.data.array->count;
|
*len = seq.data.array->count;
|
||||||
return 1;
|
return 1;
|
||||||
} else if (seq.type == GST_TUPLE) {
|
} else if (seq.type == DST_TUPLE) {
|
||||||
*data = seq.data.st;
|
*data = seq.data.st;
|
||||||
*len = gst_tuple_length(seq.data.st);
|
*len = dst_tuple_length(seq.data.st);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -188,12 +125,12 @@ int gst_seq_view(GstValue seq, const GstValue **data, uint32_t *len) {
|
|||||||
|
|
||||||
/* Read both strings and buffer as unsigned character array + uint32_t len.
|
/* Read both strings and buffer as unsigned character array + uint32_t len.
|
||||||
* Returns 1 if the view can be constructed and 0 if the type is invalid. */
|
* Returns 1 if the view can be constructed and 0 if the type is invalid. */
|
||||||
int gst_chararray_view(GstValue str, const uint8_t **data, uint32_t *len) {
|
int dst_chararray_view(DstValue str, const uint8_t **data, uint32_t *len) {
|
||||||
if (str.type == GST_STRING || str.type == GST_SYMBOL) {
|
if (str.type == DST_STRING || str.type == DST_SYMBOL) {
|
||||||
*data = str.data.string;
|
*data = str.data.string;
|
||||||
*len = gst_string_length(str.data.string);
|
*len = dst_string_length(str.data.string);
|
||||||
return 1;
|
return 1;
|
||||||
} else if (str.type == GST_BYTEBUFFER) {
|
} else if (str.type == DST_BYTEBUFFER) {
|
||||||
*data = str.data.buffer->data;
|
*data = str.data.buffer->data;
|
||||||
*len = str.data.buffer->count;
|
*len = str.data.buffer->count;
|
||||||
return 1;
|
return 1;
|
||||||
@ -204,28 +141,28 @@ int gst_chararray_view(GstValue str, const uint8_t **data, uint32_t *len) {
|
|||||||
/* Read both structs and tables as the entries of a hashtable with
|
/* Read both structs and tables as the entries of a hashtable with
|
||||||
* identical structure. Returns 1 if the view can be constructed and
|
* identical structure. Returns 1 if the view can be constructed and
|
||||||
* 0 if the type is invalid. */
|
* 0 if the type is invalid. */
|
||||||
int gst_hashtable_view(GstValue tab, const GstValue **data, uint32_t *cap) {
|
int dst_hashtable_view(DstValue tab, const DstValue **data, uint32_t *cap) {
|
||||||
if (tab.type == GST_TABLE) {
|
if (tab.type == DST_TABLE) {
|
||||||
*data = tab.data.table->data;
|
*data = tab.data.table->data;
|
||||||
*cap = tab.data.table->capacity;
|
*cap = tab.data.table->capacity;
|
||||||
return 1;
|
return 1;
|
||||||
} else if (tab.type == GST_STRUCT) {
|
} else if (tab.type == DST_STRUCT) {
|
||||||
*data = tab.data.st;
|
*data = tab.data.st;
|
||||||
*cap = gst_struct_capacity(tab.data.st);
|
*cap = dst_struct_capacity(tab.data.st);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
GstReal gst_integer_to_real(GstInteger x) {
|
DstReal dst_integer_to_real(DstInteger x) {
|
||||||
return (GstReal) x;
|
return (DstReal) x;
|
||||||
}
|
}
|
||||||
|
|
||||||
GstInteger gst_real_to_integer(GstReal x) {
|
DstInteger dst_real_to_integer(DstReal x) {
|
||||||
return (GstInteger) x;
|
return (DstInteger) x;
|
||||||
}
|
}
|
||||||
|
|
||||||
GstInteger gst_startrange(GstInteger raw, uint32_t len) {
|
uint32_t dst_startrange(DstInteger raw, uint32_t len) {
|
||||||
if (raw >= len)
|
if (raw >= len)
|
||||||
return -1;
|
return -1;
|
||||||
if (raw < 0)
|
if (raw < 0)
|
||||||
@ -233,7 +170,7 @@ GstInteger gst_startrange(GstInteger raw, uint32_t len) {
|
|||||||
return raw;
|
return raw;
|
||||||
}
|
}
|
||||||
|
|
||||||
GstInteger gst_endrange(GstInteger raw, uint32_t len) {
|
uint32_t dst_endrange(DstInteger raw, uint32_t len) {
|
||||||
if (raw > len)
|
if (raw > len)
|
||||||
return -1;
|
return -1;
|
||||||
if (raw < 0)
|
if (raw < 0)
|
||||||
@ -241,17 +178,176 @@ GstInteger gst_endrange(GstInteger raw, uint32_t len) {
|
|||||||
return raw;
|
return raw;
|
||||||
}
|
}
|
||||||
|
|
||||||
int gst_callc(Gst *vm, GstCFunction fn, int numargs, ...) {
|
static DstValue cfunction(DstCFunction fn) {
|
||||||
|
DstValue n;
|
||||||
|
n.type = DST_CFUNCTION;
|
||||||
|
n.data.cfunction = fn;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dst_callc(Dst *vm, DstCFunction fn, int numargs, ...) {
|
||||||
int result, i;
|
int result, i;
|
||||||
va_list args;
|
va_list args;
|
||||||
GstValue *stack;
|
DstValue *stack;
|
||||||
va_start(args, numargs);
|
va_start(args, numargs);
|
||||||
stack = gst_thread_beginframe(vm, vm->thread, gst_wrap_cfunction(fn), numargs);
|
stack = dst_thread_beginframe(vm, vm->thread, cfunction(fn), numargs);
|
||||||
for (i = 0; i < numargs; ++i) {
|
for (i = 0; i < numargs; ++i) {
|
||||||
stack[i] = va_arg(args, GstValue);
|
stack[i] = va_arg(args, DstValue);
|
||||||
}
|
}
|
||||||
va_end(args);
|
va_end(args);
|
||||||
result = fn(vm);
|
result = fn(vm);
|
||||||
gst_thread_popframe(vm, vm->thread);
|
dst_thread_popframe(vm, vm->thread);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Stack manipulation functions */
|
||||||
|
int dst_checkerr(Dst *vm) {
|
||||||
|
return !!vm->flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get an argument from the stack */
|
||||||
|
DstValue dst_arg(Dst *vm, uint32_t index) {
|
||||||
|
DstValue *stack = dst_thread_stack(vm->thread);
|
||||||
|
uint32_t frameSize = dst_frame_size(stack);
|
||||||
|
if (frameSize <= index) {
|
||||||
|
DstValue ret;
|
||||||
|
ret.type = DST_NIL;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return stack[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Put a value on the stack */
|
||||||
|
void dst_set_arg(Dst* vm, uint32_t index, DstValue x) {
|
||||||
|
DstValue *stack = dst_thread_stack(vm->thread);
|
||||||
|
uint32_t frameSize = dst_frame_size(stack);
|
||||||
|
if (frameSize <= index) return;
|
||||||
|
stack[index] = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the size of the VMStack */
|
||||||
|
uint32_t dst_args(Dst *vm) {
|
||||||
|
DstValue *stack = dst_thread_stack(vm->thread);
|
||||||
|
return dst_frame_size(stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dst_addsize(Dst *vm, uint32_t n) {
|
||||||
|
dst_thread_pushnil(vm, vm->thread, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dst_setsize(Dst *vm, uint32_t n) {
|
||||||
|
DstValue *stack = dst_thread_stack(vm->thread);
|
||||||
|
uint32_t frameSize = dst_frame_size(stack);
|
||||||
|
if (frameSize < n) {
|
||||||
|
dst_thread_ensure_extra(vm, vm->thread, n - frameSize);
|
||||||
|
}
|
||||||
|
dst_frame_size(stack) = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dst_swap(Dst *vm, uint32_t x, uint32_t y) {
|
||||||
|
DstValue oldx = dst_arg(vm, x);
|
||||||
|
DstValue oldy = dst_arg(vm, y);
|
||||||
|
dst_set_arg(vm, x, oldy);
|
||||||
|
dst_set_arg(vm, y, oldx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dst_move(Dst *vm, uint32_t dest, uint32_t src) {
|
||||||
|
dst_set_arg(vm, dest, dst_arg(vm, src));
|
||||||
|
}
|
||||||
|
|
||||||
|
void dst_nil(Dst *vm, uint32_t dest) {
|
||||||
|
DstValue n;
|
||||||
|
n.type = DST_NIL;
|
||||||
|
dst_set_arg(vm, dest, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dst_true(Dst *vm, uint32_t dest) {
|
||||||
|
dst_set_boolean(vm, dest, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dst_false(Dst *vm, uint32_t dest) {
|
||||||
|
dst_set_boolean(vm, dest, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Boolean Functions */
|
||||||
|
void dst_set_boolean(Dst *vm, uint32_t dest, int val) {
|
||||||
|
DstValue n;
|
||||||
|
n.type = DST_BOOLEAN;
|
||||||
|
n.data.boolean = val;
|
||||||
|
dst_set_arg(vm, dest, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
int dst_get_boolean(Dst *vm, uint32_t b) {
|
||||||
|
DstValue x = dst_arg(vm, b);
|
||||||
|
if (x.type != DST_BOOLEAN) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return x.data.boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Integer functions */
|
||||||
|
void dst_set_integer(Dst *vm, uint32_t dest, int64_t val) {
|
||||||
|
DstValue n;
|
||||||
|
n.type = DST_INTEGER;
|
||||||
|
n.data.integer = val;
|
||||||
|
dst_set_arg(vm, dest, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t dst_get_integer(Dst *vm, uint32_t i) {
|
||||||
|
DstValue x = dst_arg(vm, i);
|
||||||
|
if (x.type != DST_INTEGER) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return x.data.integer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Real functions */
|
||||||
|
void dst_set_real(Dst *vm, uint32_t dest, double val) {
|
||||||
|
DstValue n;
|
||||||
|
n.type = DST_REAL;
|
||||||
|
n.data.real = val;
|
||||||
|
dst_set_arg(vm, dest, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
double dst_get_real(Dst *vm, uint32_t r) {
|
||||||
|
DstValue x = dst_arg(vm, r);
|
||||||
|
if (x.type != DST_REAL) {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
return x.data.real;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CFunction functions */
|
||||||
|
void dst_set_cfunction(Dst *vm, uint32_t dest, DstCFunction cfn) {
|
||||||
|
DstValue n;
|
||||||
|
n.type = DST_CFUNCTION;
|
||||||
|
n.data.cfunction = cfn;
|
||||||
|
dst_set_arg(vm, dest, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
DstCFunction dst_get_cfunction(Dst *vm, uint32_t cfn) {
|
||||||
|
DstValue x = dst_arg(vm, cfn);
|
||||||
|
if (x.type != DST_CFUNCTION) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return x.data.cfunction;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dst_return(Dst *vm, uint32_t index) {
|
||||||
|
vm->ret = dst_arg(vm, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dst_throw(Dst *vm, uint32_t index) {
|
||||||
|
vm->flags = 1;
|
||||||
|
vm->ret = dst_arg(vm, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dst_cerr(Dst *vm, const char *message) {
|
||||||
|
vm->flags = 1;
|
||||||
|
vm->ret = dst_string_cv(vm, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
int dst_checktype(Dst *vm, uint32_t n, DstType type) {
|
||||||
|
return dst_arg(vm, n).type == type;
|
||||||
|
}
|
198
core/value.c
198
core/value.c
@ -20,31 +20,30 @@
|
|||||||
* IN THE SOFTWARE.
|
* IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include "internal.h"
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
/* Boolean truth definition */
|
/* Boolean truth definition */
|
||||||
int gst_truthy(GstValue v) {
|
int dst_value_truthy(DstValue v) {
|
||||||
return v.type != GST_NIL && !(v.type == GST_BOOLEAN && !v.data.boolean);
|
return v.type != DST_NIL && !(v.type == DST_BOOLEAN && !v.data.boolean);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if two values are equal. This is strict equality with no conversion. */
|
/* Check if two values are equal. This is strict equality with no conversion. */
|
||||||
int gst_equals(GstValue x, GstValue y) {
|
int dst_value_equals(DstValue x, DstValue y) {
|
||||||
int result = 0;
|
int result = 0;
|
||||||
if (x.type != y.type) {
|
if (x.type != y.type) {
|
||||||
result = 0;
|
result = 0;
|
||||||
} else {
|
} else {
|
||||||
switch (x.type) {
|
switch (x.type) {
|
||||||
case GST_NIL:
|
case DST_NIL:
|
||||||
result = 1;
|
result = 1;
|
||||||
break;
|
break;
|
||||||
case GST_BOOLEAN:
|
case DST_BOOLEAN:
|
||||||
result = (x.data.boolean == y.data.boolean);
|
result = (x.data.boolean == y.data.boolean);
|
||||||
break;
|
break;
|
||||||
case GST_REAL:
|
case DST_REAL:
|
||||||
result = (x.data.real == y.data.real);
|
result = (x.data.real == y.data.real);
|
||||||
break;
|
break;
|
||||||
case GST_INTEGER:
|
case DST_INTEGER:
|
||||||
result = (x.data.integer == y.data.integer);
|
result = (x.data.integer == y.data.integer);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -57,24 +56,24 @@ int gst_equals(GstValue x, GstValue y) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Computes a hash value for a function */
|
/* Computes a hash value for a function */
|
||||||
uint32_t gst_hash(GstValue x) {
|
uint32_t dst_value_hash(DstValue x) {
|
||||||
uint32_t hash = 0;
|
uint32_t hash = 0;
|
||||||
switch (x.type) {
|
switch (x.type) {
|
||||||
case GST_NIL:
|
case DST_NIL:
|
||||||
hash = 0;
|
hash = 0;
|
||||||
break;
|
break;
|
||||||
case GST_BOOLEAN:
|
case DST_BOOLEAN:
|
||||||
hash = x.data.boolean;
|
hash = x.data.boolean;
|
||||||
break;
|
break;
|
||||||
case GST_STRING:
|
case DST_STRING:
|
||||||
case GST_SYMBOL:
|
case DST_SYMBOL:
|
||||||
hash = gst_string_hash(x.data.string);
|
hash = dst_string_hash(x.data.string);
|
||||||
break;
|
break;
|
||||||
case GST_TUPLE:
|
case DST_TUPLE:
|
||||||
hash = gst_tuple_hash(x.data.tuple);
|
hash = dst_tuple_hash(x.data.tuple);
|
||||||
break;
|
break;
|
||||||
case GST_STRUCT:
|
case DST_STRUCT:
|
||||||
hash = gst_struct_hash(x.data.st);
|
hash = dst_struct_hash(x.data.st);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (sizeof(double) == sizeof(void *)) {
|
if (sizeof(double) == sizeof(void *)) {
|
||||||
@ -92,40 +91,40 @@ uint32_t gst_hash(GstValue x) {
|
|||||||
/* Compares x to y. If they are equal retuns 0. If x is less, returns -1.
|
/* Compares x to y. If they are equal retuns 0. If x is less, returns -1.
|
||||||
* If y is less, returns 1. All types are comparable
|
* If y is less, returns 1. All types are comparable
|
||||||
* and should have strict ordering. */
|
* and should have strict ordering. */
|
||||||
int gst_compare(GstValue x, GstValue y) {
|
int dst_value_compare(DstValue x, DstValue y) {
|
||||||
if (x.type == y.type) {
|
if (x.type == y.type) {
|
||||||
switch (x.type) {
|
switch (x.type) {
|
||||||
case GST_NIL:
|
case DST_NIL:
|
||||||
return 0;
|
return 0;
|
||||||
case GST_BOOLEAN:
|
case DST_BOOLEAN:
|
||||||
if (x.data.boolean == y.data.boolean) {
|
if (x.data.boolean == y.data.boolean) {
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
return x.data.boolean ? 1 : -1;
|
return x.data.boolean ? 1 : -1;
|
||||||
}
|
}
|
||||||
case GST_REAL:
|
case DST_REAL:
|
||||||
if (x.data.real == y.data.real) {
|
if (x.data.real == y.data.real) {
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
return x.data.real > y.data.real ? 1 : -1;
|
return x.data.real > y.data.real ? 1 : -1;
|
||||||
}
|
}
|
||||||
case GST_INTEGER:
|
case DST_INTEGER:
|
||||||
if (x.data.integer == y.data.integer) {
|
if (x.data.integer == y.data.integer) {
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
return x.data.integer > y.data.integer ? 1 : -1;
|
return x.data.integer > y.data.integer ? 1 : -1;
|
||||||
}
|
}
|
||||||
case GST_STRING:
|
case DST_STRING:
|
||||||
return gst_string_compare(x.data.string, y.data.string);
|
return dst_string_compare(x.data.string, y.data.string);
|
||||||
/* Lower indices are most significant */
|
/* Lower indices are most significant */
|
||||||
case GST_TUPLE:
|
case DST_TUPLE:
|
||||||
{
|
{
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
uint32_t xlen = gst_tuple_length(x.data.tuple);
|
uint32_t xlen = dst_tuple_length(x.data.tuple);
|
||||||
uint32_t ylen = gst_tuple_length(y.data.tuple);
|
uint32_t ylen = dst_tuple_length(y.data.tuple);
|
||||||
uint32_t count = xlen < ylen ? xlen : ylen;
|
uint32_t count = xlen < ylen ? xlen : ylen;
|
||||||
for (i = 0; i < count; ++i) {
|
for (i = 0; i < count; ++i) {
|
||||||
int comp = gst_compare(x.data.tuple[i], y.data.tuple[i]);
|
int comp = dst_value_compare(x.data.tuple[i], y.data.tuple[i]);
|
||||||
if (comp != 0) return comp;
|
if (comp != 0) return comp;
|
||||||
}
|
}
|
||||||
if (xlen < ylen)
|
if (xlen < ylen)
|
||||||
@ -148,106 +147,77 @@ int gst_compare(GstValue x, GstValue y) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get a value out af an associated data structure.
|
int dst_truthy(Dst *vm, uint32_t x) {
|
||||||
* Returns possible c error message, and NULL for no error. The
|
return dst_value_truthy(dst_arg(vm, x));
|
||||||
* useful return value is written to out on success */
|
|
||||||
const char *gst_get(GstValue ds, GstValue key, GstValue *out) {
|
|
||||||
GstInteger index;
|
|
||||||
GstValue ret;
|
|
||||||
switch (ds.type) {
|
|
||||||
case GST_ARRAY:
|
|
||||||
if (key.type != GST_INTEGER) return "expected integer key";
|
|
||||||
index = gst_startrange(key.data.integer, ds.data.array->count);
|
|
||||||
if (index < 0) return "invalid array access";
|
|
||||||
ret = ds.data.array->data[index];
|
|
||||||
break;
|
|
||||||
case GST_TUPLE:
|
|
||||||
if (key.type != GST_INTEGER) return "expected integer key";
|
|
||||||
index = gst_startrange(key.data.integer, gst_tuple_length(ds.data.tuple));
|
|
||||||
if (index < 0) return "invalid tuple access";
|
|
||||||
ret = ds.data.tuple[index];
|
|
||||||
break;
|
|
||||||
case GST_BYTEBUFFER:
|
|
||||||
if (key.type != GST_INTEGER) return "expected integer key";
|
|
||||||
index = gst_startrange(key.data.integer, ds.data.buffer->count);
|
|
||||||
if (index < 0) return "invalid buffer access";
|
|
||||||
ret.type = GST_INTEGER;
|
|
||||||
ret.data.integer = ds.data.buffer->data[index];
|
|
||||||
break;
|
|
||||||
case GST_STRING:
|
|
||||||
case GST_SYMBOL:
|
|
||||||
if (key.type != GST_INTEGER) return "expected integer key";
|
|
||||||
index = gst_startrange(key.data.integer, gst_string_length(ds.data.string));
|
|
||||||
if (index < 0) return "invalid string access";
|
|
||||||
ret.type = GST_INTEGER;
|
|
||||||
ret.data.integer = ds.data.string[index];
|
|
||||||
break;
|
|
||||||
case GST_STRUCT:
|
|
||||||
ret = gst_struct_get(ds.data.st, key);
|
|
||||||
break;
|
|
||||||
case GST_TABLE:
|
|
||||||
ret = gst_table_get(ds.data.table, key);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return "cannot get";
|
|
||||||
}
|
|
||||||
*out = ret;
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
uint32_t dst_hash(Dst *vm, uint32_t x) {
|
||||||
/* Set a value in an associative data structure. Returns possible
|
return dst_value_hash(dst_arg(vm, x));
|
||||||
* error message, and NULL if no error. */
|
}
|
||||||
const char *gst_set(Gst *vm, GstValue ds, GstValue key, GstValue value) {
|
int dst_compare(Dst *vm, uint32_t x, uint32_t y) {
|
||||||
GstInteger index;
|
return dst_value_compare(dst_arg(vm, x), dst_arg(vm, y));
|
||||||
switch (ds.type) {
|
}
|
||||||
case GST_ARRAY:
|
int dst_equals(Dst *vm, uint32_t x, uint32_t y) {
|
||||||
if (key.type != GST_INTEGER) return "expected integer key";
|
return dst_value_equals(dst_arg(vm, x), dst_arg(vm, y));
|
||||||
index = gst_startrange(key.data.integer, ds.data.array->count);
|
|
||||||
if (index < 0) return "invalid array access";
|
|
||||||
ds.data.array->data[index] = value;
|
|
||||||
break;
|
|
||||||
case GST_BYTEBUFFER:
|
|
||||||
if (key.type != GST_INTEGER) return "expected integer key";
|
|
||||||
if (value.type != GST_INTEGER) return "expected integer value";
|
|
||||||
index = gst_startrange(key.data.integer, ds.data.buffer->count);
|
|
||||||
if (index < 0) return "invalid buffer access";
|
|
||||||
ds.data.buffer->data[index] = (uint8_t) value.data.integer;
|
|
||||||
break;
|
|
||||||
case GST_TABLE:
|
|
||||||
gst_table_put(vm, ds.data.table, key, value);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return "cannot set";
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the length of an object. Returns errors for invalid types */
|
/* Get the length of an object. Returns errors for invalid types */
|
||||||
GstInteger gst_length(Gst *vm, GstValue x) {
|
uint32_t dst_length(Dst *vm, uint32_t n) {
|
||||||
GstInteger length;
|
DstValue x = dst_arg(vm, n);
|
||||||
|
uint32_t length;
|
||||||
switch (x.type) {
|
switch (x.type) {
|
||||||
default:
|
default:
|
||||||
vm->ret = gst_string_cv(vm, "cannot get length");
|
vm->ret = dst_string_cv(vm, "cannot get length");
|
||||||
return GST_RETURN_ERROR;
|
vm->flags = 1;
|
||||||
case GST_STRING:
|
return 0;
|
||||||
length = gst_string_length(x.data.string);
|
case DST_STRING:
|
||||||
|
length = dst_string_length(x.data.string);
|
||||||
break;
|
break;
|
||||||
case GST_ARRAY:
|
case DST_ARRAY:
|
||||||
length = x.data.array->count;
|
length = x.data.array->count;
|
||||||
break;
|
break;
|
||||||
case GST_BYTEBUFFER:
|
case DST_BYTEBUFFER:
|
||||||
length = x.data.buffer->count;
|
length = x.data.buffer->count;
|
||||||
break;
|
break;
|
||||||
case GST_TUPLE:
|
case DST_TUPLE:
|
||||||
length = gst_tuple_length(x.data.tuple);
|
length = dst_tuple_length(x.data.tuple);
|
||||||
break;
|
break;
|
||||||
case GST_STRUCT:
|
case DST_STRUCT:
|
||||||
length = gst_struct_length(x.data.st);
|
length = dst_struct_length(x.data.st);
|
||||||
break;
|
break;
|
||||||
case GST_TABLE:
|
case DST_TABLE:
|
||||||
length = x.data.table->count;
|
length = x.data.table->count;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Get the capacity of an object. Returns errors for invalid types */
|
||||||
|
uint32_t dst_capacity(Dst *vm, uint32_t n) {
|
||||||
|
DstValue x = dst_arg(vm, n);
|
||||||
|
uint32_t cap;
|
||||||
|
switch (x.type) {
|
||||||
|
default:
|
||||||
|
vm->ret = dst_string_cv(vm, "cannot get capacity");
|
||||||
|
vm->flags = 1;
|
||||||
|
return 0;
|
||||||
|
case DST_STRING:
|
||||||
|
cap = dst_string_length(x.data.string);
|
||||||
|
break;
|
||||||
|
case DST_ARRAY:
|
||||||
|
cap = x.data.array->capacity;
|
||||||
|
break;
|
||||||
|
case DST_BYTEBUFFER:
|
||||||
|
cap = x.data.buffer->capacity;
|
||||||
|
break;
|
||||||
|
case DST_TUPLE:
|
||||||
|
cap = dst_tuple_length(x.data.tuple);
|
||||||
|
break;
|
||||||
|
case DST_STRUCT:
|
||||||
|
cap = dst_struct_length(x.data.st);
|
||||||
|
break;
|
||||||
|
case DST_TABLE:
|
||||||
|
cap = x.data.table->capacity;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return cap;
|
||||||
|
}
|
428
core/vm.c
428
core/vm.c
@ -20,28 +20,28 @@
|
|||||||
* IN THE SOFTWARE.
|
* IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include "internal.h"
|
||||||
|
|
||||||
static const char GST_NO_UPVALUE[] = "no upvalue";
|
static const char DST_NO_UPVALUE[] = "no upvalue";
|
||||||
static const char GST_EXPECTED_FUNCTION[] = "expected function";
|
static const char DST_EXPECTED_FUNCTION[] = "expected function";
|
||||||
|
|
||||||
/* Start running the VM from where it left off. */
|
/* Start running the VM from where it left off. */
|
||||||
int gst_continue(Gst *vm) {
|
int dst_continue(Dst *vm) {
|
||||||
/* VM state */
|
/* VM state */
|
||||||
GstValue *stack;
|
DstValue *stack;
|
||||||
uint16_t *pc;
|
uint16_t *pc;
|
||||||
|
|
||||||
/* Some temporary values */
|
/* Some temporary values */
|
||||||
GstValue temp, v1, v2;
|
DstValue temp, v1, v2;
|
||||||
|
|
||||||
#define gst_exit(vm, r) return ((vm)->ret = (r), GST_RETURN_OK)
|
#define dst_exit(vm, r) return ((vm)->ret = (r), DST_RETURN_OK)
|
||||||
#define gst_error(vm, e) do { (vm)->ret = gst_string_cv((vm), (e)); goto vm_error; } while (0)
|
#define dst_error(vm, e) do { (vm)->ret = dst_string_cv((vm), (e)); goto vm_error; } while (0)
|
||||||
#define gst_assert(vm, cond, e) do {if (!(cond)){gst_error((vm), (e));}} while (0)
|
#define dst_assert(vm, cond, e) do {if (!(cond)){dst_error((vm), (e));}} while (0)
|
||||||
|
|
||||||
/* Intialize local state */
|
/* Intialize local state */
|
||||||
vm->thread->status = GST_THREAD_ALIVE;
|
vm->thread->status = DST_THREAD_ALIVE;
|
||||||
stack = gst_thread_stack(vm->thread);
|
stack = dst_thread_stack(vm->thread);
|
||||||
pc = gst_frame_pc(stack);
|
pc = dst_frame_pc(stack);
|
||||||
|
|
||||||
/* Main interpreter loop */
|
/* Main interpreter loop */
|
||||||
for (;;) {
|
for (;;) {
|
||||||
@ -49,59 +49,59 @@ int gst_continue(Gst *vm) {
|
|||||||
switch (*pc) {
|
switch (*pc) {
|
||||||
|
|
||||||
default:
|
default:
|
||||||
gst_error(vm, "unknown opcode");
|
dst_error(vm, "unknown opcode");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GST_OP_FLS: /* Load False */
|
case DST_OP_FLS: /* Load False */
|
||||||
temp.type = GST_BOOLEAN;
|
temp.type = DST_BOOLEAN;
|
||||||
temp.data.boolean = 0;
|
temp.data.boolean = 0;
|
||||||
stack[pc[1]] = temp;
|
stack[pc[1]] = temp;
|
||||||
pc += 2;
|
pc += 2;
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case GST_OP_TRU: /* Load True */
|
case DST_OP_TRU: /* Load True */
|
||||||
temp.type = GST_BOOLEAN;
|
temp.type = DST_BOOLEAN;
|
||||||
temp.data.boolean = 1;
|
temp.data.boolean = 1;
|
||||||
stack[pc[1]] = temp;
|
stack[pc[1]] = temp;
|
||||||
pc += 2;
|
pc += 2;
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case GST_OP_NIL: /* Load Nil */
|
case DST_OP_NIL: /* Load Nil */
|
||||||
temp.type = GST_NIL;
|
temp.type = DST_NIL;
|
||||||
stack[pc[1]] = temp;
|
stack[pc[1]] = temp;
|
||||||
pc += 2;
|
pc += 2;
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case GST_OP_I16: /* Load Small Integer */
|
case DST_OP_I16: /* Load Small Integer */
|
||||||
temp.type = GST_INTEGER;
|
temp.type = DST_INTEGER;
|
||||||
temp.data.integer = ((int16_t *)(pc))[2];
|
temp.data.integer = ((int16_t *)(pc))[2];
|
||||||
stack[pc[1]] = temp;
|
stack[pc[1]] = temp;
|
||||||
pc += 3;
|
pc += 3;
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case GST_OP_UPV: /* Load Up Value */
|
case DST_OP_UPV: /* Load Up Value */
|
||||||
case GST_OP_SUV: /* Set Up Value */
|
case DST_OP_SUV: /* Set Up Value */
|
||||||
{
|
{
|
||||||
GstValue *upv;
|
DstValue *upv;
|
||||||
GstFunction *fn;
|
DstFunction *fn;
|
||||||
GstFuncEnv *env;
|
DstFuncEnv *env;
|
||||||
uint16_t level = pc[2];
|
uint16_t level = pc[2];
|
||||||
temp = gst_frame_callee(stack);
|
temp = dst_frame_callee(stack);
|
||||||
gst_assert(vm, temp.type == GST_FUNCTION, GST_EXPECTED_FUNCTION);
|
dst_assert(vm, temp.type == DST_FUNCTION, DST_EXPECTED_FUNCTION);
|
||||||
fn = temp.data.function;
|
fn = temp.data.function;
|
||||||
if (level == 0)
|
if (level == 0)
|
||||||
upv = stack + pc[3];
|
upv = stack + pc[3];
|
||||||
else {
|
else {
|
||||||
while (fn && --level)
|
while (fn && --level)
|
||||||
fn = fn->parent;
|
fn = fn->parent;
|
||||||
gst_assert(vm, fn, GST_NO_UPVALUE);
|
dst_assert(vm, fn, DST_NO_UPVALUE);
|
||||||
env = fn->env;
|
env = fn->env;
|
||||||
if (env->thread)
|
if (env->thread)
|
||||||
upv = env->thread->data + env->stackOffset + pc[3];
|
upv = env->thread->data + env->stackOffset + pc[3];
|
||||||
else
|
else
|
||||||
upv = env->values + pc[3];
|
upv = env->values + pc[3];
|
||||||
}
|
}
|
||||||
if (pc[0] == GST_OP_UPV) {
|
if (pc[0] == DST_OP_UPV) {
|
||||||
stack[pc[1]] = *upv;
|
stack[pc[1]] = *upv;
|
||||||
} else {
|
} else {
|
||||||
*upv = stack[pc[1]];
|
*upv = stack[pc[1]];
|
||||||
@ -110,107 +110,107 @@ int gst_continue(Gst *vm) {
|
|||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case GST_OP_JIF: /* Jump If */
|
case DST_OP_JIF: /* Jump If */
|
||||||
if (gst_truthy(stack[pc[1]])) {
|
if (dst_value_truthy(stack[pc[1]])) {
|
||||||
pc += 4;
|
pc += 4;
|
||||||
} else {
|
} else {
|
||||||
pc += *((int32_t *)(pc + 2));
|
pc += *((int32_t *)(pc + 2));
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case GST_OP_JMP: /* Jump */
|
case DST_OP_JMP: /* Jump */
|
||||||
pc += *((int32_t *)(pc + 1));
|
pc += *((int32_t *)(pc + 1));
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case GST_OP_CST: /* Load constant value */
|
case DST_OP_CST: /* Load constant value */
|
||||||
v1 = gst_frame_callee(stack);
|
v1 = dst_frame_callee(stack);
|
||||||
gst_assert(vm, v1.type == GST_FUNCTION, GST_EXPECTED_FUNCTION);
|
dst_assert(vm, v1.type == DST_FUNCTION, DST_EXPECTED_FUNCTION);
|
||||||
if (pc[2] > v1.data.function->def->literalsLen)
|
if (pc[2] > v1.data.function->def->literalsLen)
|
||||||
gst_error(vm, GST_NO_UPVALUE);
|
dst_error(vm, DST_NO_UPVALUE);
|
||||||
stack[pc[1]] = v1.data.function->def->literals[pc[2]];
|
stack[pc[1]] = v1.data.function->def->literals[pc[2]];
|
||||||
pc += 3;
|
pc += 3;
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case GST_OP_I32: /* Load 32 bit integer */
|
case DST_OP_I32: /* Load 32 bit integer */
|
||||||
temp.type = GST_INTEGER;
|
temp.type = DST_INTEGER;
|
||||||
temp.data.integer = *((int32_t *)(pc + 2));
|
temp.data.integer = *((int32_t *)(pc + 2));
|
||||||
stack[pc[1]] = temp;
|
stack[pc[1]] = temp;
|
||||||
pc += 4;
|
pc += 4;
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case GST_OP_I64: /* Load 64 bit integer */
|
case DST_OP_I64: /* Load 64 bit integer */
|
||||||
temp.type = GST_INTEGER;
|
temp.type = DST_INTEGER;
|
||||||
temp.data.integer = (GstInteger) *((int64_t *)(pc + 2));
|
temp.data.integer = (DstInteger) *((int64_t *)(pc + 2));
|
||||||
stack[pc[1]] = temp;
|
stack[pc[1]] = temp;
|
||||||
pc += 6;
|
pc += 6;
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case GST_OP_F64: /* Load 64 bit float */
|
case DST_OP_F64: /* Load 64 bit float */
|
||||||
temp.type = GST_REAL;
|
temp.type = DST_REAL;
|
||||||
temp.data.real = (GstReal) *((double *)(pc + 2));
|
temp.data.real = (DstReal) *((double *)(pc + 2));
|
||||||
stack[pc[1]] = temp;
|
stack[pc[1]] = temp;
|
||||||
pc += 6;
|
pc += 6;
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case GST_OP_MOV: /* Move Values */
|
case DST_OP_MOV: /* Move Values */
|
||||||
stack[pc[1]] = stack[pc[2]];
|
stack[pc[1]] = stack[pc[2]];
|
||||||
pc += 3;
|
pc += 3;
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case GST_OP_CLN: /* Create closure from constant FuncDef */
|
case DST_OP_CLN: /* Create closure from constant FuncDef */
|
||||||
{
|
{
|
||||||
GstFunction *fn;
|
DstFunction *fn;
|
||||||
v1 = gst_frame_callee(stack);
|
v1 = dst_frame_callee(stack);
|
||||||
temp = v1.data.function->def->literals[pc[2]];
|
temp = v1.data.function->def->literals[pc[2]];
|
||||||
if (temp.type != GST_FUNCDEF)
|
if (temp.type != DST_FUNCDEF)
|
||||||
gst_error(vm, "cannot create closure from non-funcdef");
|
dst_error(vm, "cannot create closure from non-funcdef");
|
||||||
fn = gst_alloc(vm, sizeof(GstFunction));
|
fn = dst_alloc(vm, sizeof(DstFunction));
|
||||||
fn->def = temp.data.def;
|
fn->def = temp.data.def;
|
||||||
if (temp.data.def->flags & GST_FUNCDEF_FLAG_NEEDSPARENT)
|
if (temp.data.def->flags & DST_FUNCDEF_FLAG_NEEDSPARENT)
|
||||||
fn->parent = v1.data.function;
|
fn->parent = v1.data.function;
|
||||||
else
|
else
|
||||||
fn->parent = NULL;
|
fn->parent = NULL;
|
||||||
if (v1.type != GST_FUNCTION)
|
if (v1.type != DST_FUNCTION)
|
||||||
gst_error(vm, GST_EXPECTED_FUNCTION);
|
dst_error(vm, DST_EXPECTED_FUNCTION);
|
||||||
if (gst_frame_env(stack) == NULL && (fn->def->flags & GST_FUNCDEF_FLAG_NEEDSENV)) {
|
if (dst_frame_env(stack) == NULL && (fn->def->flags & DST_FUNCDEF_FLAG_NEEDSENV)) {
|
||||||
gst_frame_env(stack) = gst_alloc(vm, sizeof(GstFuncEnv));
|
dst_frame_env(stack) = dst_alloc(vm, sizeof(DstFuncEnv));
|
||||||
gst_frame_env(stack)->thread = vm->thread;
|
dst_frame_env(stack)->thread = vm->thread;
|
||||||
gst_frame_env(stack)->stackOffset = vm->thread->count;
|
dst_frame_env(stack)->stackOffset = vm->thread->count;
|
||||||
gst_frame_env(stack)->values = NULL;
|
dst_frame_env(stack)->values = NULL;
|
||||||
}
|
}
|
||||||
if (pc[2] > v1.data.function->def->literalsLen)
|
if (pc[2] > v1.data.function->def->literalsLen)
|
||||||
gst_error(vm, GST_NO_UPVALUE);
|
dst_error(vm, DST_NO_UPVALUE);
|
||||||
if (fn->def->flags & GST_FUNCDEF_FLAG_NEEDSENV)
|
if (fn->def->flags & DST_FUNCDEF_FLAG_NEEDSENV)
|
||||||
fn->env = gst_frame_env(stack);
|
fn->env = dst_frame_env(stack);
|
||||||
else
|
else
|
||||||
fn->env = NULL;
|
fn->env = NULL;
|
||||||
temp.type = GST_FUNCTION;
|
temp.type = DST_FUNCTION;
|
||||||
temp.data.function = fn;
|
temp.data.function = fn;
|
||||||
stack[pc[1]] = temp;
|
stack[pc[1]] = temp;
|
||||||
pc += 3;
|
pc += 3;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GST_OP_RTN: /* Return nil */
|
case DST_OP_RTN: /* Return nil */
|
||||||
temp.type = GST_NIL;
|
temp.type = DST_NIL;
|
||||||
goto vm_return;
|
goto vm_return;
|
||||||
|
|
||||||
case GST_OP_RET: /* Return */
|
case DST_OP_RET: /* Return */
|
||||||
temp = stack[pc[1]];
|
temp = stack[pc[1]];
|
||||||
goto vm_return;
|
goto vm_return;
|
||||||
|
|
||||||
case GST_OP_PSK: /* Push stack */
|
case DST_OP_PSK: /* Push stack */
|
||||||
{
|
{
|
||||||
uint16_t arity = pc[1];
|
uint16_t arity = pc[1];
|
||||||
uint16_t i;
|
uint16_t i;
|
||||||
uint16_t newBase = gst_frame_size(stack) + GST_FRAME_SIZE;
|
uint16_t newBase = dst_frame_size(stack) + DST_FRAME_SIZE;
|
||||||
gst_frame_args(stack) = newBase;
|
dst_frame_args(stack) = newBase;
|
||||||
gst_thread_ensure_extra(vm, vm->thread, GST_FRAME_SIZE + arity);
|
dst_thread_ensure_extra(vm, vm->thread, DST_FRAME_SIZE + arity);
|
||||||
stack = gst_thread_stack(vm->thread);
|
stack = dst_thread_stack(vm->thread);
|
||||||
gst_frame_size(stack) += GST_FRAME_SIZE + arity;
|
dst_frame_size(stack) += DST_FRAME_SIZE + arity;
|
||||||
/* Nil stuff */
|
/* Nil stuff */
|
||||||
for (i = 0; i < GST_FRAME_SIZE; ++i)
|
for (i = 0; i < DST_FRAME_SIZE; ++i)
|
||||||
stack[newBase + i - GST_FRAME_SIZE].type = GST_NIL;
|
stack[newBase + i - DST_FRAME_SIZE].type = DST_NIL;
|
||||||
/* Write arguments */
|
/* Write arguments */
|
||||||
for (i = 0; i < arity; ++i)
|
for (i = 0; i < arity; ++i)
|
||||||
stack[newBase + i] = stack[pc[2 + i]];
|
stack[newBase + i] = stack[pc[2 + i]];
|
||||||
@ -218,214 +218,215 @@ int gst_continue(Gst *vm) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GST_OP_PAR: /* Push array or tuple */
|
case DST_OP_PAR: /* Push array or tuple */
|
||||||
{
|
{
|
||||||
uint32_t count, i, oldsize;
|
uint32_t count, i, oldsize;
|
||||||
const GstValue *data;
|
const DstValue *data;
|
||||||
temp = stack[pc[1]];
|
temp = stack[pc[1]];
|
||||||
if (temp.type == GST_TUPLE) {
|
if (temp.type == DST_TUPLE) {
|
||||||
count = gst_tuple_length(temp.data.tuple);
|
count = dst_tuple_length(temp.data.tuple);
|
||||||
data = temp.data.tuple;
|
data = temp.data.tuple;
|
||||||
} else if (temp.type == GST_ARRAY){
|
} else if (temp.type == DST_ARRAY){
|
||||||
count = temp.data.array->count;
|
count = temp.data.array->count;
|
||||||
data = temp.data.array->data;
|
data = temp.data.array->data;
|
||||||
} else {
|
} else {
|
||||||
gst_error(vm, "expected array or tuple");
|
dst_error(vm, "expected array or tuple");
|
||||||
}
|
}
|
||||||
oldsize = gst_frame_size(stack);
|
oldsize = dst_frame_size(stack);
|
||||||
gst_thread_pushnil(vm, vm->thread, count);
|
dst_thread_pushnil(vm, vm->thread, count);
|
||||||
stack = gst_thread_stack(vm->thread);
|
stack = dst_thread_stack(vm->thread);
|
||||||
for (i = 0; i < count; ++i)
|
for (i = 0; i < count; ++i)
|
||||||
stack[oldsize + i] = data[i];
|
stack[oldsize + i] = data[i];
|
||||||
/*gst_frame_size(stack) += count;*/
|
/*dst_frame_size(stack) += count;*/
|
||||||
pc += 2;
|
pc += 2;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GST_OP_CAL: /* Call */
|
case DST_OP_CAL: /* Call */
|
||||||
{
|
{
|
||||||
uint16_t newStackIndex = gst_frame_args(stack);
|
uint16_t newStackIndex = dst_frame_args(stack);
|
||||||
uint16_t size = gst_frame_size(stack);
|
uint16_t size = dst_frame_size(stack);
|
||||||
temp = stack[pc[1]];
|
temp = stack[pc[1]];
|
||||||
gst_frame_size(stack) = newStackIndex - GST_FRAME_SIZE;
|
dst_frame_size(stack) = newStackIndex - DST_FRAME_SIZE;
|
||||||
gst_frame_ret(stack) = pc[2];
|
dst_frame_ret(stack) = pc[2];
|
||||||
gst_frame_pc(stack) = pc + 3;
|
dst_frame_pc(stack) = pc + 3;
|
||||||
if (newStackIndex < GST_FRAME_SIZE)
|
if (newStackIndex < DST_FRAME_SIZE)
|
||||||
gst_error(vm, "invalid call instruction");
|
dst_error(vm, "invalid call instruction");
|
||||||
vm->thread->count += newStackIndex;
|
vm->thread->count += newStackIndex;
|
||||||
stack = gst_thread_stack(vm->thread);
|
stack = dst_thread_stack(vm->thread);
|
||||||
gst_frame_size(stack) = size - newStackIndex;
|
dst_frame_size(stack) = size - newStackIndex;
|
||||||
gst_frame_prevsize(stack) = newStackIndex - GST_FRAME_SIZE;
|
dst_frame_prevsize(stack) = newStackIndex - DST_FRAME_SIZE;
|
||||||
gst_frame_callee(stack) = temp;
|
dst_frame_callee(stack) = temp;
|
||||||
}
|
}
|
||||||
goto common_function_call;
|
goto common_function_call;
|
||||||
|
|
||||||
case GST_OP_TCL: /* Tail call */
|
case DST_OP_TCL: /* Tail call */
|
||||||
{
|
{
|
||||||
uint16_t newStackIndex = gst_frame_args(stack);
|
uint16_t newStackIndex = dst_frame_args(stack);
|
||||||
uint16_t size = gst_frame_size(stack);
|
uint16_t size = dst_frame_size(stack);
|
||||||
uint16_t i;
|
uint16_t i;
|
||||||
temp = stack[pc[1]];
|
temp = stack[pc[1]];
|
||||||
/* Check for closures */
|
/* Check for closures */
|
||||||
if (gst_frame_env(stack)) {
|
if (dst_frame_env(stack)) {
|
||||||
GstFuncEnv *env = gst_frame_env(stack);
|
DstFuncEnv *env = dst_frame_env(stack);
|
||||||
env->thread = NULL;
|
env->thread = NULL;
|
||||||
env->stackOffset = size;
|
env->stackOffset = size;
|
||||||
env->values = gst_alloc(vm, sizeof(GstValue) * size);
|
env->values = dst_alloc(vm, sizeof(DstValue) * size);
|
||||||
gst_memcpy(env->values, stack, sizeof(GstValue) * size);
|
dst_memcpy(env->values, stack, sizeof(DstValue) * size);
|
||||||
}
|
}
|
||||||
if (newStackIndex)
|
if (newStackIndex)
|
||||||
for (i = 0; i < size - newStackIndex; ++i)
|
for (i = 0; i < size - newStackIndex; ++i)
|
||||||
stack[i] = stack[newStackIndex + i];
|
stack[i] = stack[newStackIndex + i];
|
||||||
gst_frame_size(stack) = size - newStackIndex;
|
dst_frame_size(stack) = size - newStackIndex;
|
||||||
gst_frame_callee(stack) = temp;
|
dst_frame_callee(stack) = temp;
|
||||||
}
|
}
|
||||||
goto common_function_call;
|
goto common_function_call;
|
||||||
|
|
||||||
/* Code common to all function calls */
|
/* Code common to all function calls */
|
||||||
common_function_call:
|
common_function_call:
|
||||||
gst_frame_args(stack) = 0;
|
dst_frame_args(stack) = 0;
|
||||||
gst_frame_env(stack) = NULL;
|
dst_frame_env(stack) = NULL;
|
||||||
gst_thread_endframe(vm, vm->thread);
|
dst_thread_endframe(vm, vm->thread);
|
||||||
stack = vm->thread->data + vm->thread->count;
|
stack = vm->thread->data + vm->thread->count;
|
||||||
temp = gst_frame_callee(stack);
|
temp = dst_frame_callee(stack);
|
||||||
if (temp.type == GST_FUNCTION) {
|
if (temp.type == DST_FUNCTION) {
|
||||||
pc = temp.data.function->def->byteCode;
|
pc = temp.data.function->def->byteCode;
|
||||||
} else if (temp.type == GST_CFUNCTION) {
|
} else if (temp.type == DST_CFUNCTION) {
|
||||||
int status;
|
int status;
|
||||||
vm->ret.type = GST_NIL;
|
vm->ret.type = DST_NIL;
|
||||||
status = temp.data.cfunction(vm);
|
status = temp.data.cfunction(vm);
|
||||||
if (status == GST_RETURN_OK) {
|
if (status) {
|
||||||
|
goto vm_error;
|
||||||
|
} else {
|
||||||
temp = vm->ret;
|
temp = vm->ret;
|
||||||
goto vm_return;
|
goto vm_return;
|
||||||
} else {
|
|
||||||
goto vm_error;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
gst_error(vm, GST_EXPECTED_FUNCTION);
|
dst_error(vm, DST_EXPECTED_FUNCTION);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GST_OP_ARR: /* Array literal */
|
case DST_OP_ARR: /* Array literal */
|
||||||
{
|
{
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
uint32_t arrayLen = pc[2];
|
uint32_t arrayLen = pc[2];
|
||||||
GstArray *array = gst_array(vm, arrayLen);
|
DstArray *array = dst_make_array(vm, arrayLen);
|
||||||
array->count = arrayLen;
|
array->count = arrayLen;
|
||||||
for (i = 0; i < arrayLen; ++i)
|
for (i = 0; i < arrayLen; ++i)
|
||||||
array->data[i] = stack[pc[3 + i]];
|
array->data[i] = stack[pc[3 + i]];
|
||||||
temp.type = GST_ARRAY;
|
temp.type = DST_ARRAY;
|
||||||
temp.data.array = array;
|
temp.data.array = array;
|
||||||
stack[pc[1]] = temp;
|
stack[pc[1]] = temp;
|
||||||
pc += 3 + arrayLen;
|
pc += 3 + arrayLen;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GST_OP_DIC: /* Table literal */
|
case DST_OP_DIC: /* Table literal */
|
||||||
{
|
{
|
||||||
uint32_t i = 3;
|
uint32_t i = 3;
|
||||||
uint32_t kvs = pc[2];
|
uint32_t kvs = pc[2];
|
||||||
GstTable *t = gst_table(vm, 2 * kvs);
|
DstTable *t = dst_make_table(vm, 2 * kvs);
|
||||||
kvs = kvs + 3;
|
kvs = kvs + 3;
|
||||||
while (i < kvs) {
|
while (i < kvs) {
|
||||||
v1 = stack[pc[i++]];
|
v1 = stack[pc[i++]];
|
||||||
v2 = stack[pc[i++]];
|
v2 = stack[pc[i++]];
|
||||||
gst_table_put(vm, t, v1, v2);
|
dst_table_put(vm, t, v1, v2);
|
||||||
}
|
}
|
||||||
temp.type = GST_TABLE;
|
temp.type = DST_TABLE;
|
||||||
temp.data.table = t;
|
temp.data.table = t;
|
||||||
stack[pc[1]] = temp;
|
stack[pc[1]] = temp;
|
||||||
pc += kvs;
|
pc += kvs;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GST_OP_TUP: /* Tuple literal */
|
case DST_OP_TUP: /* Tuple literal */
|
||||||
{
|
{
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
uint32_t len = pc[2];
|
uint32_t len = pc[2];
|
||||||
GstValue *tuple = gst_tuple_begin(vm, len);
|
DstValue *tuple = dst_tuple_begin(vm, len);
|
||||||
for (i = 0; i < len; ++i)
|
for (i = 0; i < len; ++i)
|
||||||
tuple[i] = stack[pc[3 + i]];
|
tuple[i] = stack[pc[3 + i]];
|
||||||
temp.type = GST_TUPLE;
|
temp.type = DST_TUPLE;
|
||||||
temp.data.tuple = gst_tuple_end(vm, tuple);
|
temp.data.tuple = dst_tuple_end(vm, tuple);
|
||||||
stack[pc[1]] = temp;
|
stack[pc[1]] = temp;
|
||||||
pc += 3 + len;
|
pc += 3 + len;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GST_OP_TRN: /* Transfer */
|
case DST_OP_TRN: /* Transfer */
|
||||||
temp = stack[pc[2]]; /* The thread */
|
temp = stack[pc[2]]; /* The thread */
|
||||||
v1 = stack[pc[3]]; /* The value to pass in */
|
v1 = stack[pc[3]]; /* The value to pass in */
|
||||||
if (temp.type != GST_THREAD && temp.type != GST_NIL)
|
if (temp.type != DST_THREAD && temp.type != DST_NIL)
|
||||||
gst_error(vm, "expected thread");
|
dst_error(vm, "expected thread");
|
||||||
if (temp.type == GST_NIL && vm->thread->parent) {
|
if (temp.type == DST_NIL && vm->thread->parent) {
|
||||||
temp = gst_wrap_thread(vm->thread->parent);
|
temp.type = DST_THREAD;
|
||||||
|
temp.data.thread = vm->thread->parent;
|
||||||
}
|
}
|
||||||
if (temp.type == GST_THREAD) {
|
if (temp.type == DST_THREAD) {
|
||||||
if (temp.data.thread->status != GST_THREAD_PENDING)
|
if (temp.data.thread->status != DST_THREAD_PENDING)
|
||||||
gst_error(vm, "can only enter pending thread");
|
dst_error(vm, "can only enter pending thread");
|
||||||
}
|
}
|
||||||
gst_frame_ret(stack) = pc[1];
|
dst_frame_ret(stack) = pc[1];
|
||||||
vm->thread->status = GST_THREAD_PENDING;
|
vm->thread->status = DST_THREAD_PENDING;
|
||||||
gst_frame_pc(stack) = pc + 4;
|
dst_frame_pc(stack) = pc + 4;
|
||||||
if (temp.type == GST_NIL) {
|
if (temp.type == DST_NIL) {
|
||||||
vm->ret = v1;
|
vm->ret = v1;
|
||||||
return GST_RETURN_OK;
|
return 0;
|
||||||
}
|
}
|
||||||
temp.data.thread->status = GST_THREAD_ALIVE;
|
temp.data.thread->status = DST_THREAD_ALIVE;
|
||||||
vm->thread = temp.data.thread;
|
vm->thread = temp.data.thread;
|
||||||
stack = gst_thread_stack(temp.data.thread);
|
stack = dst_thread_stack(temp.data.thread);
|
||||||
if (gst_frame_callee(stack).type != GST_FUNCTION)
|
if (dst_frame_callee(stack).type != DST_FUNCTION)
|
||||||
goto vm_return;
|
goto vm_return;
|
||||||
stack[gst_frame_ret(stack)] = v1;
|
stack[dst_frame_ret(stack)] = v1;
|
||||||
pc = gst_frame_pc(stack);
|
pc = dst_frame_pc(stack);
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Handle returning from stack frame. Expect return value in temp. */
|
/* Handle returning from stack frame. Expect return value in temp. */
|
||||||
vm_return:
|
vm_return:
|
||||||
stack = gst_thread_popframe(vm, vm->thread);
|
stack = dst_thread_popframe(vm, vm->thread);
|
||||||
while (vm->thread->count < GST_FRAME_SIZE ||
|
while (vm->thread->count < DST_FRAME_SIZE ||
|
||||||
vm->thread->status == GST_THREAD_DEAD ||
|
vm->thread->status == DST_THREAD_DEAD ||
|
||||||
vm->thread->status == GST_THREAD_ERROR) {
|
vm->thread->status == DST_THREAD_ERROR) {
|
||||||
vm->thread->status = GST_THREAD_DEAD;
|
vm->thread->status = DST_THREAD_DEAD;
|
||||||
if (vm->thread->parent) {
|
if (vm->thread->parent) {
|
||||||
vm->thread = vm->thread->parent;
|
vm->thread = vm->thread->parent;
|
||||||
if (vm->thread->status == GST_THREAD_ALIVE) {
|
if (vm->thread->status == DST_THREAD_ALIVE) {
|
||||||
/* If the parent thread is still alive,
|
/* If the parent thread is still alive,
|
||||||
we are inside a cfunction */
|
we are inside a cfunction */
|
||||||
vm->ret = temp;
|
vm->ret = temp;
|
||||||
return GST_RETURN_OK;
|
return 0;
|
||||||
}
|
}
|
||||||
stack = vm->thread->data + vm->thread->count;
|
stack = vm->thread->data + vm->thread->count;
|
||||||
} else {
|
} else {
|
||||||
vm->ret = temp;
|
vm->ret = temp;
|
||||||
return GST_RETURN_OK;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
vm->thread->status = GST_THREAD_ALIVE;
|
vm->thread->status = DST_THREAD_ALIVE;
|
||||||
pc = gst_frame_pc(stack);
|
pc = dst_frame_pc(stack);
|
||||||
stack[gst_frame_ret(stack)] = temp;
|
stack[dst_frame_ret(stack)] = temp;
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Handle errors from c functions and vm opcodes */
|
/* Handle errors from c functions and vm opcodes */
|
||||||
vm_error:
|
vm_error:
|
||||||
vm->thread->status = GST_THREAD_ERROR;
|
vm->thread->status = DST_THREAD_ERROR;
|
||||||
while (vm->thread->count < GST_FRAME_SIZE ||
|
while (vm->thread->count < DST_FRAME_SIZE ||
|
||||||
vm->thread->status == GST_THREAD_DEAD ||
|
vm->thread->status == DST_THREAD_DEAD ||
|
||||||
vm->thread->status == GST_THREAD_ERROR) {
|
vm->thread->status == DST_THREAD_ERROR) {
|
||||||
if (vm->thread->errorParent == NULL)
|
if (vm->thread->parent == NULL)
|
||||||
return GST_RETURN_ERROR;
|
return 1;
|
||||||
vm->thread = vm->thread->errorParent;
|
vm->thread = vm->thread->parent;
|
||||||
if (vm->thread->status == GST_THREAD_ALIVE) {
|
if (vm->thread->status == DST_THREAD_ALIVE) {
|
||||||
/* If the parent thread is still alive,
|
/* If the parent thread is still alive,
|
||||||
we are inside a cfunction */
|
we are inside a cfunction */
|
||||||
return GST_RETURN_ERROR;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
vm->thread->status = GST_THREAD_ALIVE;
|
vm->thread->status = DST_THREAD_ALIVE;
|
||||||
stack = vm->thread->data + vm->thread->count;
|
stack = vm->thread->data + vm->thread->count;
|
||||||
stack[gst_frame_ret(stack)] = vm->ret;
|
stack[dst_frame_ret(stack)] = vm->ret;
|
||||||
pc = gst_frame_pc(stack);
|
pc = dst_frame_pc(stack);
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
} /* end switch */
|
} /* end switch */
|
||||||
@ -433,7 +434,7 @@ int gst_continue(Gst *vm) {
|
|||||||
/* Check for collection every cycle. If the instruction definitely does
|
/* Check for collection every cycle. If the instruction definitely does
|
||||||
* not allocate memory, it can use continue instead of break to
|
* not allocate memory, it can use continue instead of break to
|
||||||
* skip this check */
|
* skip this check */
|
||||||
gst_maybe_collect(vm);
|
dst_maybe_collect(vm);
|
||||||
|
|
||||||
} /* end for */
|
} /* end for */
|
||||||
|
|
||||||
@ -441,66 +442,41 @@ int gst_continue(Gst *vm) {
|
|||||||
|
|
||||||
/* Run the vm with a given function. This function is
|
/* Run the vm with a given function. This function is
|
||||||
* called to start the vm. */
|
* called to start the vm. */
|
||||||
int gst_run(Gst *vm, GstValue callee) {
|
int dst_run(Dst *vm, DstValue callee) {
|
||||||
int result;
|
int result;
|
||||||
if (vm->thread &&
|
if (vm->thread &&
|
||||||
(vm->thread->status == GST_THREAD_DEAD ||
|
(vm->thread->status == DST_THREAD_DEAD ||
|
||||||
vm->thread->status == GST_THREAD_ALIVE)) {
|
vm->thread->status == DST_THREAD_ALIVE)) {
|
||||||
/* Reuse old thread */
|
/* Reuse old thread */
|
||||||
gst_thread_reset(vm, vm->thread, callee);
|
dst_thread_reset(vm, vm->thread, callee);
|
||||||
} else {
|
} else {
|
||||||
/* Create new thread */
|
/* Create new thread */
|
||||||
vm->thread = gst_thread(vm, callee, 64);
|
vm->thread = dst_thread(vm, callee, 64);
|
||||||
}
|
}
|
||||||
if (callee.type == GST_CFUNCTION) {
|
if (callee.type == DST_CFUNCTION) {
|
||||||
vm->ret.type = GST_NIL;
|
vm->ret.type = DST_NIL;
|
||||||
result = callee.data.cfunction(vm);
|
result = callee.data.cfunction(vm);
|
||||||
} else if (callee.type == GST_FUNCTION) {
|
} else if (callee.type == DST_FUNCTION) {
|
||||||
result = gst_continue(vm);
|
result = dst_continue(vm);
|
||||||
} else {
|
} else {
|
||||||
vm->ret = gst_string_cv(vm, "expected function");
|
vm->ret = dst_string_cv(vm, "expected function");
|
||||||
return GST_RETURN_ERROR;
|
return 1;
|
||||||
}
|
}
|
||||||
/* Handle yields */
|
/* Handle yields */
|
||||||
while (result == GST_RETURN_OK && vm->thread->status == GST_THREAD_PENDING) {
|
while (!result && vm->thread->status == DST_THREAD_PENDING) {
|
||||||
/* Send back in the value yielded - TODO - do something useful with this */
|
/* Send back in the value yielded - TODO - do something useful with this */
|
||||||
GstValue *stack = gst_thread_stack(vm->thread);
|
DstValue *stack = dst_thread_stack(vm->thread);
|
||||||
stack[gst_frame_ret(stack)] = vm->ret;
|
stack[dst_frame_ret(stack)] = vm->ret;
|
||||||
/* Resume */
|
/* Resume */
|
||||||
result = gst_continue(vm);
|
result = dst_continue(vm);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get an argument from the stack */
|
/* Setup functions */
|
||||||
GstValue gst_arg(Gst *vm, uint32_t index) {
|
Dst *dst_init() {
|
||||||
GstValue *stack = gst_thread_stack(vm->thread);
|
Dst *vm = dst_raw_alloc(sizeof(Dst));
|
||||||
uint32_t frameSize = gst_frame_size(stack);
|
vm->ret.type = DST_NIL;
|
||||||
if (frameSize <= index) {
|
|
||||||
GstValue ret;
|
|
||||||
ret.type = GST_NIL;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
return stack[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Put a value on the stack */
|
|
||||||
void gst_set_arg(Gst* vm, uint32_t index, GstValue x) {
|
|
||||||
GstValue *stack = gst_thread_stack(vm->thread);
|
|
||||||
uint32_t frameSize = gst_frame_size(stack);
|
|
||||||
if (frameSize <= index) return;
|
|
||||||
stack[index] = x;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get the size of the VMStack */
|
|
||||||
uint32_t gst_count_args(Gst *vm) {
|
|
||||||
GstValue *stack = gst_thread_stack(vm->thread);
|
|
||||||
return gst_frame_size(stack);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Initialize the VM */
|
|
||||||
void gst_init(Gst *vm) {
|
|
||||||
vm->ret.type = GST_NIL;
|
|
||||||
/* Garbage collection */
|
/* Garbage collection */
|
||||||
vm->blocks = NULL;
|
vm->blocks = NULL;
|
||||||
vm->nextCollection = 0;
|
vm->nextCollection = 0;
|
||||||
@ -510,30 +486,34 @@ void gst_init(Gst *vm) {
|
|||||||
* there are no memory bugs during dev */
|
* there are no memory bugs during dev */
|
||||||
vm->memoryInterval = 0;
|
vm->memoryInterval = 0;
|
||||||
vm->black = 0;
|
vm->black = 0;
|
||||||
/* Add thread */
|
|
||||||
vm->thread = NULL;
|
|
||||||
/* Set up the cache */
|
/* Set up the cache */
|
||||||
vm->cache = gst_raw_calloc(1, 128 * sizeof(GstValue));
|
vm->cache = dst_raw_calloc(1, 128 * sizeof(DstValue));
|
||||||
vm->cache_capacity = vm->cache == NULL ? 0 : 128;
|
vm->cache_capacity = vm->cache == NULL ? 0 : 128;
|
||||||
vm->cache_count = 0;
|
vm->cache_count = 0;
|
||||||
vm->cache_deleted = 0;
|
vm->cache_deleted = 0;
|
||||||
/* Set up global env */
|
/* Set up global env */
|
||||||
vm->modules = gst_table(vm, 10);
|
vm->modules = dst_make_table(vm, 10);
|
||||||
vm->registry = gst_table(vm, 10);
|
vm->registry = dst_make_table(vm, 10);
|
||||||
vm->env = gst_table(vm, 10);
|
vm->env = dst_make_table(vm, 10);
|
||||||
|
/* Set thread */
|
||||||
|
vm->thread = dst_thread(vm, vm->ret, 100);
|
||||||
|
dst_thread_pushnil(vm, vm->thread, 10);
|
||||||
|
return vm;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clear all memory associated with the VM */
|
/* Clear all memory associated with the VM */
|
||||||
void gst_deinit(Gst *vm) {
|
void dst_deinit(Dst *vm) {
|
||||||
gst_clear_memory(vm);
|
dst_clear_memory(vm);
|
||||||
vm->thread = NULL;
|
vm->thread = NULL;
|
||||||
vm->modules = NULL;
|
vm->modules = NULL;
|
||||||
vm->registry = NULL;
|
vm->registry = NULL;
|
||||||
vm->ret.type = GST_NIL;
|
vm->ret.type = DST_NIL;
|
||||||
/* Deinit the cache */
|
/* Deinit the cache */
|
||||||
gst_raw_free(vm->cache);
|
dst_raw_free(vm->cache);
|
||||||
vm->cache = NULL;
|
vm->cache = NULL;
|
||||||
vm->cache_count = 0;
|
vm->cache_count = 0;
|
||||||
vm->cache_capacity = 0;
|
vm->cache_capacity = 0;
|
||||||
vm->cache_deleted = 0;
|
vm->cache_deleted = 0;
|
||||||
|
/* Free the vm */
|
||||||
|
dst_raw_free(vm);
|
||||||
}
|
}
|
||||||
|
84
core/wrap.c
Normal file
84
core/wrap.c
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017 Calvin Rose
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to
|
||||||
|
* deal in the Software without restriction, including without limitation the
|
||||||
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
* sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
* IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <dst/dst.h>
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
/* Wrapper functions wrap a data type that is used from C into a
|
||||||
|
* gst value, which can then be used in gst. */
|
||||||
|
|
||||||
|
DstValue dst_wrap_nil() {
|
||||||
|
GstValue y;
|
||||||
|
y.type = GST_NIL;
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dst_check_nil(Gst *vm, uint32_t i) {
|
||||||
|
DstValue a = dst_arg(vm, i);
|
||||||
|
return a.type == DST_NIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DST_WRAP_DEFINE(NAME, TYPE, DTYPE, UM)\
|
||||||
|
DstValue dst_wrap_##NAME(TYPE x) {\
|
||||||
|
DstValue y;\
|
||||||
|
y.type = DTYPE;\
|
||||||
|
y.data.UM = x;\
|
||||||
|
return y;\
|
||||||
|
}\
|
||||||
|
\
|
||||||
|
int dst_check_##NAME(Dst *vm, uint32_t i) {\
|
||||||
|
return dst_arg(vm, i).type == DTYPE;\
|
||||||
|
}\
|
||||||
|
|
||||||
|
DST_WRAP_DEFINE(real, DstReal, DST_REAL, real)
|
||||||
|
DST_WRAP_DEFINE(integer, DstInteger, DST_INTEGER, integer)
|
||||||
|
DST_WRAP_DEFINE(boolean, int, DST_BOOLEAN, boolean)
|
||||||
|
DST_WRAP_DEFINE(string, const uint8_t *, DST_STRING, string)
|
||||||
|
DST_WRAP_DEFINE(symbol, const uint8_t *, DST_SYMBOL, string)
|
||||||
|
DST_WRAP_DEFINE(array, DstArray *, DST_ARRAY, array)
|
||||||
|
DST_WRAP_DEFINE(tuple, const DstValue *, DST_TUPLE, tuple)
|
||||||
|
DST_WRAP_DEFINE(struct, const DstValue *, DST_STRUCT, st)
|
||||||
|
DST_WRAP_DEFINE(thread, DstThread *, DST_THREAD, thread)
|
||||||
|
DST_WRAP_DEFINE(buffer, DstBuffer *, DST_BYTEBUFFER, buffer)
|
||||||
|
DST_WRAP_DEFINE(function, DstFunction *, DST_FUNCTION, function)
|
||||||
|
DST_WRAP_DEFINE(cfunction, DstCFunction, DST_CFUNCTION, cfunction)
|
||||||
|
DST_WRAP_DEFINE(table, DstTable *, DST_TABLE, table)
|
||||||
|
DST_WRAP_DEFINE(funcenv, DstFuncEnv *, DST_FUNCENV, env)
|
||||||
|
DST_WRAP_DEFINE(funcdef, DstFuncDef *, DST_FUNCDEF, def)
|
||||||
|
|
||||||
|
#undef DST_WRAP_DEFINE
|
||||||
|
|
||||||
|
DstValue dst_wrap_userdata(void *x) {
|
||||||
|
DstValue ret;
|
||||||
|
ret.type = DST_USERDATA;
|
||||||
|
ret.data.pointer = x;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *dst_check_userdata(Dst *vm, uint32_t i, const DstUserType *type) {
|
||||||
|
DstValue x = dst_arg(vm, i);
|
||||||
|
DstUserdataHeader *h;
|
||||||
|
if (x.type != DST_USERDATA) return NULL;
|
||||||
|
h = dst_udata_header(x.data.pointer);
|
||||||
|
if (h->type != type) return NULL;
|
||||||
|
return x.data.pointer;
|
||||||
|
}
|
@ -1,653 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2017 Calvin Rose
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to
|
|
||||||
* deal in the Software without restriction, including without limitation the
|
|
||||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
||||||
* sell copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
||||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
||||||
* IN THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef GST_H_defined
|
|
||||||
#define GST_H_defined
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <setjmp.h>
|
|
||||||
|
|
||||||
/* String utils */
|
|
||||||
#define gst_string_raw(s) ((uint32_t *)(s) - 2)
|
|
||||||
#define gst_string_length(s) (gst_string_raw(s)[0])
|
|
||||||
#define gst_string_hash(s) (gst_string_raw(s)[1])
|
|
||||||
|
|
||||||
/* Tuple utils */
|
|
||||||
#define gst_tuple_raw(t) ((uint32_t *)(t) - 2)
|
|
||||||
#define gst_tuple_length(t) (gst_tuple_raw(t)[0])
|
|
||||||
#define gst_tuple_hash(t) (gst_tuple_raw(t)[1])
|
|
||||||
|
|
||||||
/* Struct utils */
|
|
||||||
#define gst_struct_raw(t) ((uint32_t *)(t) - 2)
|
|
||||||
#define gst_struct_length(t) (gst_struct_raw(t)[0])
|
|
||||||
#define gst_struct_capacity(t) (gst_struct_length(t) * 4)
|
|
||||||
#define gst_struct_hash(t) (gst_struct_raw(t)[1])
|
|
||||||
|
|
||||||
/* Userdata utils */
|
|
||||||
#define gst_udata_header(u) ((GstUserdataHeader *)(u) - 1)
|
|
||||||
#define gst_udata_type(u) (gst_udata_header(u)->type)
|
|
||||||
#define gst_udata_size(u) (gst_udata_header(u)->size)
|
|
||||||
|
|
||||||
/* Memcpy for moving memory */
|
|
||||||
#ifndef gst_memcpy
|
|
||||||
#include <string.h>
|
|
||||||
#define gst_memcpy memcpy
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Allocation */
|
|
||||||
#ifndef gst_raw_alloc
|
|
||||||
#include <stdlib.h>
|
|
||||||
#define gst_raw_alloc malloc
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Zero allocation */
|
|
||||||
#ifndef gst_raw_calloc
|
|
||||||
#include <stdlib.h>
|
|
||||||
#define gst_raw_calloc calloc
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Realloc */
|
|
||||||
#ifndef gst_raw_realloc
|
|
||||||
#include <stdlib.h>
|
|
||||||
#define gst_raw_realloc realloc
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Free */
|
|
||||||
#ifndef gst_raw_free
|
|
||||||
#include <stdlib.h>
|
|
||||||
#define gst_raw_free free
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Null */
|
|
||||||
#ifndef NULL
|
|
||||||
#define NULL ((void *)0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Stack frame manipulation */
|
|
||||||
|
|
||||||
/* Size of stack frame in number of values */
|
|
||||||
#define GST_FRAME_SIZE 5
|
|
||||||
|
|
||||||
/* Prevent some recursive functions from recursing too deeply
|
|
||||||
* ands crashing. */
|
|
||||||
#define GST_RECURSION_GUARD 2056
|
|
||||||
|
|
||||||
/* Macros for referencing a stack frame given a stack */
|
|
||||||
#define gst_frame_callee(s) (*(s - 1))
|
|
||||||
#define gst_frame_size(s) ((s - 2)->data.dwords[0])
|
|
||||||
#define gst_frame_prevsize(s) ((s - 2)->data.dwords[1])
|
|
||||||
#define gst_frame_args(s) ((s - 3)->data.dwords[0])
|
|
||||||
#define gst_frame_ret(s) ((s - 3)->data.dwords[1])
|
|
||||||
#define gst_frame_pc(s) ((s - 4)->data.u16p)
|
|
||||||
#define gst_frame_env(s) ((s - 5)->data.env)
|
|
||||||
|
|
||||||
/* C function helpers */
|
|
||||||
|
|
||||||
/* Return in a c function */
|
|
||||||
#define gst_c_return(vm, x) do { (vm)->ret = (x); return GST_RETURN_OK; } while (0)
|
|
||||||
|
|
||||||
/* Throw error from a c function */
|
|
||||||
#define gst_c_throw(vm, e) do { (vm)->ret = (e); return GST_RETURN_ERROR; } while (0)
|
|
||||||
|
|
||||||
/* Throw c string error from a c function */
|
|
||||||
#define gst_c_throwc(vm, e) gst_c_throw((vm), gst_string_cv((vm), (e)))
|
|
||||||
|
|
||||||
/* Assert from a c function */
|
|
||||||
#define gst_c_assert(vm, cond, e) do {if (cond) gst_c_throw((vm), (e)); } while (0)
|
|
||||||
|
|
||||||
/* What to do when out of memory */
|
|
||||||
#ifndef GST_OUT_OF_MEMORY
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#define GST_OUT_OF_MEMORY do { printf("out of memory\n"); exit(1); } while (0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Various types */
|
|
||||||
typedef enum GstType {
|
|
||||||
GST_NIL = 0,
|
|
||||||
GST_REAL,
|
|
||||||
GST_INTEGER,
|
|
||||||
GST_BOOLEAN,
|
|
||||||
GST_STRING,
|
|
||||||
GST_SYMBOL,
|
|
||||||
GST_ARRAY,
|
|
||||||
GST_TUPLE,
|
|
||||||
GST_TABLE,
|
|
||||||
GST_STRUCT,
|
|
||||||
GST_THREAD,
|
|
||||||
GST_BYTEBUFFER,
|
|
||||||
GST_FUNCTION,
|
|
||||||
GST_CFUNCTION,
|
|
||||||
GST_USERDATA,
|
|
||||||
GST_FUNCENV,
|
|
||||||
GST_FUNCDEF
|
|
||||||
} GstType;
|
|
||||||
|
|
||||||
/* The state of the virtual machine */
|
|
||||||
typedef struct Gst Gst;
|
|
||||||
|
|
||||||
/* A general gst value type */
|
|
||||||
typedef struct GstValue GstValue;
|
|
||||||
|
|
||||||
/* All of the gst types */
|
|
||||||
typedef double GstReal;
|
|
||||||
typedef int64_t GstInteger;
|
|
||||||
typedef int GstBoolean;
|
|
||||||
typedef struct GstFunction GstFunction;
|
|
||||||
typedef struct GstArray GstArray;
|
|
||||||
typedef struct GstBuffer GstBuffer;
|
|
||||||
typedef struct GstTable GstTable;
|
|
||||||
typedef struct GstThread GstThread;
|
|
||||||
typedef int (*GstCFunction)(Gst * vm);
|
|
||||||
|
|
||||||
/* Other structs */
|
|
||||||
typedef struct GstUserdataHeader GstUserdataHeader;
|
|
||||||
typedef struct GstFuncDef GstFuncDef;
|
|
||||||
typedef struct GstFuncEnv GstFuncEnv;
|
|
||||||
typedef union GstValueUnion GstValueUnion;
|
|
||||||
typedef struct GstModuleItem GstModuleItem;
|
|
||||||
typedef struct GstUserType GstUserType;
|
|
||||||
typedef struct GstParser GstParser;
|
|
||||||
typedef struct GstParseState GstParseState;
|
|
||||||
|
|
||||||
/* C Api data types */
|
|
||||||
struct GstModuleItem {
|
|
||||||
const char *name;
|
|
||||||
GstCFunction data;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Union datatype */
|
|
||||||
union GstValueUnion {
|
|
||||||
GstBoolean boolean;
|
|
||||||
GstReal real;
|
|
||||||
GstInteger integer;
|
|
||||||
GstArray *array;
|
|
||||||
GstBuffer *buffer;
|
|
||||||
GstTable *table;
|
|
||||||
GstThread *thread;
|
|
||||||
const GstValue *tuple;
|
|
||||||
GstCFunction cfunction;
|
|
||||||
GstFunction *function;
|
|
||||||
GstFuncEnv *env;
|
|
||||||
GstFuncDef *def;
|
|
||||||
const GstValue *st;
|
|
||||||
const uint8_t *string;
|
|
||||||
/* Indirectly used union members */
|
|
||||||
uint16_t *u16p;
|
|
||||||
uint32_t dwords[2];
|
|
||||||
uint16_t words[4];
|
|
||||||
uint8_t bytes[8];
|
|
||||||
void *pointer;
|
|
||||||
const char *cstring;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* The general gst value type. Contains a large union and
|
|
||||||
* the type information of the value */
|
|
||||||
struct GstValue {
|
|
||||||
GstType type;
|
|
||||||
GstValueUnion data;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* A lightweight green thread in gst. Does not correspond to
|
|
||||||
* operating system threads. */
|
|
||||||
struct GstThread {
|
|
||||||
uint32_t count;
|
|
||||||
uint32_t capacity;
|
|
||||||
GstValue *data;
|
|
||||||
GstThread *parent;
|
|
||||||
GstThread *errorParent;
|
|
||||||
enum {
|
|
||||||
GST_THREAD_PENDING = 0,
|
|
||||||
GST_THREAD_ALIVE,
|
|
||||||
GST_THREAD_DEAD,
|
|
||||||
GST_THREAD_ERROR
|
|
||||||
} status;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* A dynamic array type. */
|
|
||||||
struct GstArray {
|
|
||||||
uint32_t count;
|
|
||||||
uint32_t capacity;
|
|
||||||
GstValue *data;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* A bytebuffer type. Used as a mutable string or string builder. */
|
|
||||||
struct GstBuffer {
|
|
||||||
uint32_t count;
|
|
||||||
uint32_t capacity;
|
|
||||||
uint8_t *data;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* A mutable associative data type. Backed by a hashtable. */
|
|
||||||
struct GstTable {
|
|
||||||
uint32_t count;
|
|
||||||
uint32_t capacity;
|
|
||||||
uint32_t deleted;
|
|
||||||
GstValue *data;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Some function defintion flags */
|
|
||||||
#define GST_FUNCDEF_FLAG_VARARG 1
|
|
||||||
#define GST_FUNCDEF_FLAG_NEEDSPARENT 2
|
|
||||||
#define GST_FUNCDEF_FLAG_NEEDSENV 4
|
|
||||||
|
|
||||||
/* A function definition. Contains information need to instantiate closures. */
|
|
||||||
struct GstFuncDef {
|
|
||||||
uint32_t locals;
|
|
||||||
uint32_t arity; /* Not including varargs */
|
|
||||||
uint32_t literalsLen;
|
|
||||||
uint32_t byteCodeLen;
|
|
||||||
uint32_t flags;
|
|
||||||
GstValue *literals; /* Contains strings, FuncDefs, etc. */
|
|
||||||
uint16_t *byteCode;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* A fuction environment */
|
|
||||||
struct GstFuncEnv {
|
|
||||||
GstThread *thread; /* When nil, index the local values */
|
|
||||||
uint32_t stackOffset; /* Used as environment size when off stack */
|
|
||||||
GstValue *values;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* A function */
|
|
||||||
struct GstFunction {
|
|
||||||
GstFuncDef *def;
|
|
||||||
GstFuncEnv *env;
|
|
||||||
GstFunction *parent;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Defines a type for userdata */
|
|
||||||
struct GstUserType {
|
|
||||||
const char *name;
|
|
||||||
GstValue (*serialize)(Gst *vm, void *data, uint32_t len);
|
|
||||||
GstValue (*deserialize)(Gst *vm, GstValue in);
|
|
||||||
void (*finalize)(Gst *vm, void *data, uint32_t len);
|
|
||||||
void (*gcmark)(Gst *vm, void *data, uint32_t len);
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Contains information about userdata */
|
|
||||||
struct GstUserdataHeader {
|
|
||||||
uint32_t size;
|
|
||||||
const GstUserType *type;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* VM return status from c function */
|
|
||||||
#define GST_RETURN_OK 0
|
|
||||||
#define GST_RETURN_ERROR 1
|
|
||||||
|
|
||||||
/* The VM state */
|
|
||||||
struct Gst {
|
|
||||||
/* Garbage collection */
|
|
||||||
void *blocks;
|
|
||||||
uint32_t memoryInterval;
|
|
||||||
uint32_t nextCollection;
|
|
||||||
uint32_t black : 1;
|
|
||||||
/* Immutable value cache */
|
|
||||||
GstValue *cache;
|
|
||||||
uint32_t cache_capacity;
|
|
||||||
uint32_t cache_count;
|
|
||||||
uint32_t cache_deleted;
|
|
||||||
/* GC roots */
|
|
||||||
GstThread *thread;
|
|
||||||
GstTable *modules;
|
|
||||||
GstTable *registry;
|
|
||||||
GstTable *env;
|
|
||||||
/* Return state */
|
|
||||||
GstValue ret;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* The type of a ParseState */
|
|
||||||
typedef enum ParseType {
|
|
||||||
PTYPE_FORM,
|
|
||||||
PTYPE_STRING,
|
|
||||||
PTYPE_TOKEN
|
|
||||||
} ParseType;
|
|
||||||
|
|
||||||
/* Contain a parse state that goes on the parse stack */
|
|
||||||
struct GstParseState {
|
|
||||||
ParseType type;
|
|
||||||
uint32_t quoteCount;
|
|
||||||
union {
|
|
||||||
struct {
|
|
||||||
uint8_t endDelimiter;
|
|
||||||
GstArray *array;
|
|
||||||
} form;
|
|
||||||
struct {
|
|
||||||
GstBuffer *buffer;
|
|
||||||
uint32_t count;
|
|
||||||
uint32_t accum;
|
|
||||||
enum {
|
|
||||||
STRING_STATE_BASE,
|
|
||||||
STRING_STATE_ESCAPE,
|
|
||||||
STRING_STATE_ESCAPE_UNICODE,
|
|
||||||
STRING_STATE_ESCAPE_HEX
|
|
||||||
} state;
|
|
||||||
} string;
|
|
||||||
} buf;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Holds the parsing state */
|
|
||||||
struct GstParser {
|
|
||||||
Gst *vm;
|
|
||||||
const char *error;
|
|
||||||
GstParseState *data;
|
|
||||||
GstValue value;
|
|
||||||
uint32_t count;
|
|
||||||
uint32_t cap;
|
|
||||||
uint32_t index;
|
|
||||||
uint32_t line;
|
|
||||||
uint32_t quoteCount;
|
|
||||||
enum {
|
|
||||||
GST_PARSER_PENDING = 0,
|
|
||||||
GST_PARSER_FULL,
|
|
||||||
GST_PARSER_ERROR,
|
|
||||||
GST_PARSER_ROOT
|
|
||||||
} status;
|
|
||||||
enum {
|
|
||||||
GST_PCOMMENT_NOT,
|
|
||||||
GST_PCOMMENT_EXPECTING,
|
|
||||||
GST_PCOMMENT_INSIDE
|
|
||||||
} comment;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Bytecode */
|
|
||||||
enum GstOpCode {
|
|
||||||
GST_OP_FLS, /* Load false */
|
|
||||||
GST_OP_TRU, /* Load true */
|
|
||||||
GST_OP_NIL, /* Load nil */
|
|
||||||
GST_OP_UPV, /* Load upvalue */
|
|
||||||
GST_OP_JIF, /* Jump if */
|
|
||||||
GST_OP_JMP, /* Jump */
|
|
||||||
GST_OP_SUV, /* Set upvalue */
|
|
||||||
GST_OP_CST, /* Load constant */
|
|
||||||
GST_OP_I16, /* Load 16 bit signed integer */
|
|
||||||
GST_OP_I32, /* Load 32 bit signed integer */
|
|
||||||
GST_OP_I64, /* Load 64 bit signed integer */
|
|
||||||
GST_OP_F64, /* Load 64 bit IEEE double */
|
|
||||||
GST_OP_MOV, /* Move value */
|
|
||||||
GST_OP_CLN, /* Create a closure */
|
|
||||||
GST_OP_ARR, /* Create array */
|
|
||||||
GST_OP_DIC, /* Create object */
|
|
||||||
GST_OP_TUP, /* Create tuple */
|
|
||||||
GST_OP_RET, /* Return from function */
|
|
||||||
GST_OP_RTN, /* Return nil */
|
|
||||||
GST_OP_PSK, /* Push stack */
|
|
||||||
GST_OP_PAR, /* Push array or tuple */
|
|
||||||
GST_OP_CAL, /* Call function */
|
|
||||||
GST_OP_TCL, /* Tail call */
|
|
||||||
GST_OP_TRN /* Transfer to new thread */
|
|
||||||
};
|
|
||||||
|
|
||||||
/****/
|
|
||||||
/* Buffer functions */
|
|
||||||
/****/
|
|
||||||
|
|
||||||
GstBuffer *gst_buffer(Gst *vm, uint32_t capacity);
|
|
||||||
void gst_buffer_ensure(Gst *vm, GstBuffer *buffer, uint32_t capacity);
|
|
||||||
int gst_buffer_get(GstBuffer *buffer, uint32_t index);
|
|
||||||
void gst_buffer_push(Gst *vm, GstBuffer *buffer, uint8_t c);
|
|
||||||
void gst_buffer_append(Gst *vm, GstBuffer *buffer, const uint8_t *string, uint32_t length);
|
|
||||||
void gst_buffer_append_cstring(Gst *vm, GstBuffer *buffer, const char *cstring);
|
|
||||||
const uint8_t *gst_buffer_to_string(Gst *vm, GstBuffer *buffer);
|
|
||||||
|
|
||||||
/* Define a push function for pushing a certain type to the buffer */
|
|
||||||
#define BUFFER_DEFINE(name, type) \
|
|
||||||
static void gst_buffer_push_##name(Gst *vm, GstBuffer *buffer, type x) { \
|
|
||||||
union { type t; uint8_t bytes[sizeof(type)]; } u; \
|
|
||||||
u.t = x; gst_buffer_append(vm, buffer, u.bytes, sizeof(type)); \
|
|
||||||
}
|
|
||||||
|
|
||||||
/****/
|
|
||||||
/* Array functions */
|
|
||||||
/****/
|
|
||||||
|
|
||||||
GstArray *gst_array(Gst *vm, uint32_t capacity);
|
|
||||||
GstValue gst_array_get(GstArray *array, uint32_t index);
|
|
||||||
int gst_array_set(GstArray *array, uint32_t index, GstValue x);
|
|
||||||
void gst_array_ensure(Gst *vm, GstArray *array, uint32_t capacity);
|
|
||||||
void gst_array_push(Gst *vm, GstArray *array, GstValue x);
|
|
||||||
GstValue gst_array_pop(GstArray *array);
|
|
||||||
GstValue gst_array_peek(GstArray *array);
|
|
||||||
|
|
||||||
/****/
|
|
||||||
/* Userdata functions */
|
|
||||||
/****/
|
|
||||||
|
|
||||||
void *gst_userdata(Gst *vm, uint32_t size, const GstUserType *utype);
|
|
||||||
|
|
||||||
/****/
|
|
||||||
/* Tuple functions */
|
|
||||||
/****/
|
|
||||||
|
|
||||||
GstValue *gst_tuple_begin(Gst *vm, uint32_t length);
|
|
||||||
const GstValue *gst_tuple_end(Gst *vm, GstValue *tuple);
|
|
||||||
|
|
||||||
/****/
|
|
||||||
/* String/Symbol functions */
|
|
||||||
/****/
|
|
||||||
|
|
||||||
uint8_t *gst_string_begin(Gst *vm, uint32_t len);
|
|
||||||
const uint8_t *gst_string_end(Gst *vm, uint8_t *str);
|
|
||||||
const uint8_t *gst_string_b(Gst *vm, const uint8_t *buf, uint32_t len);
|
|
||||||
const uint8_t *gst_string_c(Gst *vm, const char *cstring);
|
|
||||||
GstValue gst_string_cv(Gst *vm, const char *string);
|
|
||||||
GstValue gst_string_cvs(Gst *vm, const char *string);
|
|
||||||
int gst_string_compare(const uint8_t *lhs, const uint8_t *rhs);
|
|
||||||
const uint8_t *gst_string_bu(Gst *vm, const uint8_t *buf, uint32_t len);
|
|
||||||
const uint8_t *gst_string_cu(Gst *vm, const char *s);
|
|
||||||
|
|
||||||
/****/
|
|
||||||
/* Struct functions */
|
|
||||||
/****/
|
|
||||||
|
|
||||||
GstValue *gst_struct_begin(Gst *vm, uint32_t count);
|
|
||||||
void gst_struct_put(GstValue *st, GstValue key, GstValue value);
|
|
||||||
const GstValue *gst_struct_end(Gst *vm, GstValue *st);
|
|
||||||
GstValue gst_struct_get(const GstValue *st, GstValue key);
|
|
||||||
GstValue gst_struct_next(const GstValue *st, GstValue key);
|
|
||||||
|
|
||||||
/****/
|
|
||||||
/* Table functions */
|
|
||||||
/****/
|
|
||||||
|
|
||||||
GstTable *gst_table(Gst *vm, uint32_t capacity);
|
|
||||||
GstValue gst_table_get(GstTable *t, GstValue key);
|
|
||||||
GstValue gst_table_remove(GstTable *t, GstValue key);
|
|
||||||
void gst_table_put(Gst *vm, GstTable *t, GstValue key, GstValue value);
|
|
||||||
void gst_table_clear(GstTable *t);
|
|
||||||
GstValue gst_table_next(GstTable *o, GstValue key);
|
|
||||||
|
|
||||||
/****/
|
|
||||||
/* Threads */
|
|
||||||
/****/
|
|
||||||
|
|
||||||
#define gst_thread_stack(t) ((t)->data + (t)->count)
|
|
||||||
GstThread *gst_thread(Gst *vm, GstValue callee, uint32_t capacity);
|
|
||||||
GstThread *gst_thread_reset(Gst *vm, GstThread *thread, GstValue callee);
|
|
||||||
void gst_thread_ensure_extra(Gst *vm, GstThread *thread, uint32_t extra);
|
|
||||||
void gst_thread_push(Gst *vm, GstThread *thread, GstValue x);
|
|
||||||
void gst_thread_pushnil(Gst *vm, GstThread *thread, uint32_t n);
|
|
||||||
void gst_thread_tuplepack(Gst *vm, GstThread *thread, uint32_t n);
|
|
||||||
GstValue *gst_thread_beginframe(Gst *vm, GstThread *thread, GstValue callee, uint32_t arity);
|
|
||||||
void gst_thread_endframe(Gst *vm, GstThread *thread);
|
|
||||||
GstValue *gst_thread_popframe(Gst *vm, GstThread *thread);
|
|
||||||
uint32_t gst_thread_countframes(GstThread *thread);
|
|
||||||
|
|
||||||
/****/
|
|
||||||
/* Value manipulation */
|
|
||||||
/****/
|
|
||||||
|
|
||||||
int gst_truthy(GstValue x);
|
|
||||||
int gst_compare(GstValue x, GstValue y);
|
|
||||||
int gst_equals(GstValue x, GstValue y);
|
|
||||||
const char *gst_get(GstValue ds, GstValue key, GstValue *out);
|
|
||||||
const char *gst_set(Gst *vm, GstValue ds, GstValue key, GstValue value);
|
|
||||||
const uint8_t *gst_to_string(Gst *vm, GstValue x);
|
|
||||||
const uint8_t *gst_description(Gst *vm, GstValue x);
|
|
||||||
const uint8_t *gst_short_description(Gst *vm, GstValue x);
|
|
||||||
uint32_t gst_hash(GstValue x);
|
|
||||||
GstInteger gst_length(Gst *vm, GstValue x);
|
|
||||||
|
|
||||||
/****/
|
|
||||||
/* Serialization */
|
|
||||||
/****/
|
|
||||||
|
|
||||||
const char *gst_deserialize(
|
|
||||||
Gst *vm,
|
|
||||||
const uint8_t *data,
|
|
||||||
uint32_t len,
|
|
||||||
GstValue *out,
|
|
||||||
const uint8_t **nextData);
|
|
||||||
|
|
||||||
const char *gst_serialize(Gst *vm, GstBuffer *buffer, GstValue x);
|
|
||||||
|
|
||||||
/***/
|
|
||||||
/* Parsing */
|
|
||||||
/***/
|
|
||||||
|
|
||||||
void gst_parser(GstParser *p, Gst *vm);
|
|
||||||
int gst_parse_cstring(GstParser *p, const char *string);
|
|
||||||
int gst_parse_string(GstParser *p, const uint8_t *string);
|
|
||||||
void gst_parse_byte(GstParser *p, uint8_t byte);
|
|
||||||
int gst_parse_hasvalue(GstParser *p);
|
|
||||||
GstValue gst_parse_consume(GstParser *p);
|
|
||||||
|
|
||||||
/***/
|
|
||||||
/* Compilation */
|
|
||||||
/***/
|
|
||||||
|
|
||||||
GstValue gst_compile(Gst *vm, GstTable *env, GstValue form);
|
|
||||||
|
|
||||||
/****/
|
|
||||||
/* GC */
|
|
||||||
/****/
|
|
||||||
|
|
||||||
#define GST_MEMTAG_STRING 4
|
|
||||||
#define GST_MEMTAG_TUPLE 8
|
|
||||||
#define GST_MEMTAG_STRUCT 16
|
|
||||||
#define GST_MEMTAG_USER 32
|
|
||||||
|
|
||||||
void gst_mark_value(Gst *vm, GstValue x);
|
|
||||||
void gst_mark(Gst *vm, GstValueUnion x, GstType type);
|
|
||||||
void gst_sweep(Gst *vm);
|
|
||||||
void *gst_alloc(Gst *vm, uint32_t size);
|
|
||||||
void *gst_zalloc(Gst *vm, uint32_t size);
|
|
||||||
void gst_mem_tag(void *mem, uint32_t tags);
|
|
||||||
void gst_collect(Gst *vm);
|
|
||||||
void gst_maybe_collect(Gst *vm);
|
|
||||||
void gst_clear_memory(Gst *vm);
|
|
||||||
void gst_mark_mem(Gst *vm, void *mem);
|
|
||||||
|
|
||||||
/****/
|
|
||||||
/* VM */
|
|
||||||
/****/
|
|
||||||
|
|
||||||
void gst_init(Gst *vm);
|
|
||||||
void gst_deinit(Gst *vm);
|
|
||||||
int gst_run(Gst *vm, GstValue func);
|
|
||||||
int gst_continue(Gst *vm);
|
|
||||||
GstValue gst_arg(Gst *vm, uint32_t index);
|
|
||||||
void gst_set_arg(Gst *vm, uint32_t index, GstValue x);
|
|
||||||
uint32_t gst_count_args(Gst *vm);
|
|
||||||
|
|
||||||
/***/
|
|
||||||
/* Stl */
|
|
||||||
/***/
|
|
||||||
|
|
||||||
void gst_stl_load(Gst *vm);
|
|
||||||
|
|
||||||
/****/
|
|
||||||
/* C Api */
|
|
||||||
/****/
|
|
||||||
|
|
||||||
void gst_module(Gst *vm, const char *name, const GstModuleItem *mod);
|
|
||||||
void gst_module_mutable(Gst *vm, const char *name, const GstModuleItem *mod);
|
|
||||||
void gst_module_put(Gst *vm, const char *packagename, const char *name, GstValue x);
|
|
||||||
GstValue gst_module_get(Gst *vm, const char *packagename);
|
|
||||||
void gst_register_put(Gst *vm, const char *packagename, GstValue mod);
|
|
||||||
GstValue gst_register_get(Gst *vm, const char *name);
|
|
||||||
int gst_callc(Gst *vm, GstCFunction fn, int numargs, ...);
|
|
||||||
|
|
||||||
/* Wrap data in GstValue */
|
|
||||||
GstValue gst_wrap_nil();
|
|
||||||
GstValue gst_wrap_real(GstReal x);
|
|
||||||
GstValue gst_wrap_integer(GstInteger x);
|
|
||||||
GstValue gst_wrap_boolean(int x);
|
|
||||||
GstValue gst_wrap_string(const uint8_t *x);
|
|
||||||
GstValue gst_wrap_symbol(const uint8_t *x);
|
|
||||||
GstValue gst_wrap_array(GstArray *x);
|
|
||||||
GstValue gst_wrap_tuple(const GstValue *x);
|
|
||||||
GstValue gst_wrap_struct(const GstValue *x);
|
|
||||||
GstValue gst_wrap_thread(GstThread *x);
|
|
||||||
GstValue gst_wrap_buffer(GstBuffer *x);
|
|
||||||
GstValue gst_wrap_function(GstFunction *x);
|
|
||||||
GstValue gst_wrap_cfunction(GstCFunction x);
|
|
||||||
GstValue gst_wrap_table(GstTable *x);
|
|
||||||
GstValue gst_wrap_userdata(void *x);
|
|
||||||
GstValue gst_wrap_funcenv(GstFuncEnv *x);
|
|
||||||
GstValue gst_wrap_funcdef(GstFuncDef *x);
|
|
||||||
|
|
||||||
/* Check data from arguments */
|
|
||||||
int gst_check_nil(Gst *vm, uint32_t i);
|
|
||||||
int gst_check_real(Gst *vm, uint32_t i, GstReal (*x));
|
|
||||||
int gst_check_integer(Gst *vm, uint32_t i, GstInteger (*x));
|
|
||||||
int gst_check_boolean(Gst *vm, uint32_t i, int (*x));
|
|
||||||
int gst_check_string(Gst *vm, uint32_t i, const uint8_t *(*x));
|
|
||||||
int gst_check_symbol(Gst *vm, uint32_t i, const uint8_t *(*x));
|
|
||||||
int gst_check_array(Gst *vm, uint32_t i, GstArray *(*x));
|
|
||||||
int gst_check_tuple(Gst *vm, uint32_t i, const GstValue *(*x));
|
|
||||||
int gst_check_struct(Gst *vm, uint32_t i, const GstValue *(*x));
|
|
||||||
int gst_check_thread(Gst *vm, uint32_t i, GstThread *(*x));
|
|
||||||
int gst_check_buffer(Gst *vm, uint32_t i, GstBuffer *(*x));
|
|
||||||
int gst_check_function(Gst *vm, uint32_t i, GstFunction *(*x));
|
|
||||||
int gst_check_cfunction(Gst *vm, uint32_t i, GstCFunction (*x));
|
|
||||||
int gst_check_table(Gst *vm, uint32_t i, GstTable *(*x));
|
|
||||||
int gst_check_funcenv(Gst *vm, uint32_t i, GstFuncEnv *(*x));
|
|
||||||
int gst_check_funcdef(Gst *vm, uint32_t i, GstFuncDef *(*x));
|
|
||||||
void *gst_check_userdata(Gst *vm, uint32_t i, const GstUserType *type);
|
|
||||||
|
|
||||||
/* Treat similar types through uniform interfaces */
|
|
||||||
int gst_seq_view(GstValue seq, const GstValue **data, uint32_t *len);
|
|
||||||
int gst_chararray_view(GstValue str, const uint8_t **data, uint32_t *len);
|
|
||||||
int gst_hashtable_view(GstValue tab, const GstValue **data, uint32_t *cap);
|
|
||||||
|
|
||||||
/****/
|
|
||||||
/* Misc */
|
|
||||||
/****/
|
|
||||||
|
|
||||||
int gst_read_real(const uint8_t *string, const uint8_t *end, double *ret, int forceInt);
|
|
||||||
int gst_read_integer(const uint8_t *string, const uint8_t *end, int64_t *ret);
|
|
||||||
GstReal gst_integer_to_real(GstInteger x);
|
|
||||||
GstInteger gst_real_to_integer(GstReal x);
|
|
||||||
GstInteger gst_startrange(GstInteger raw, uint32_t len);
|
|
||||||
GstInteger gst_endrange(GstInteger raw, uint32_t len);
|
|
||||||
void gst_env_merge(Gst *vm, GstTable *destEnv, GstTable *srcEnv);
|
|
||||||
GstTable *gst_env_nils(Gst *vm, GstTable *env);
|
|
||||||
GstTable *gst_env_meta(Gst *vm, GstTable *env);
|
|
||||||
void gst_env_put(Gst *vm, GstTable *env, GstValue key, GstValue value);
|
|
||||||
void gst_env_putc(Gst *vm, GstTable *env, const char *key, GstValue value);
|
|
||||||
void gst_env_putvar(Gst *vm, GstTable *env, GstValue key, GstValue value);
|
|
||||||
void gst_env_putvarc(Gst *vm, GstTable *env, const char *key, GstValue value);
|
|
||||||
const uint8_t *gst_description(Gst *vm, GstValue x);
|
|
||||||
|
|
||||||
#endif // GST_H_defined
|
|
@ -29,7 +29,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#define BUFSIZE 1024
|
#define BUFSIZE 1024
|
||||||
#define PERLINE 16
|
#define PERLINE 10
|
||||||
|
|
||||||
int main(int argc, const char **argv) {
|
int main(int argc, const char **argv) {
|
||||||
|
|
||||||
@ -60,7 +60,7 @@ int main(int argc, const char **argv) {
|
|||||||
/* Write the header */
|
/* Write the header */
|
||||||
fprintf(out, "/* Auto generated - DO NOT EDIT */\n\n");
|
fprintf(out, "/* Auto generated - DO NOT EDIT */\n\n");
|
||||||
fprintf(out, "#include <stdint.h>\n\n");
|
fprintf(out, "#include <stdint.h>\n\n");
|
||||||
fprintf(out, "const uint8_t gst_gen_%s[] = {", argv[3]);
|
fprintf(out, "const uint8_t dst_gen_%s[] = {", argv[3]);
|
||||||
|
|
||||||
/* Read in chunks from buffer */
|
/* Read in chunks from buffer */
|
||||||
while ((bytesRead = fread(buf, 1, sizeof(buf), in)) > 0) {
|
while ((bytesRead = fread(buf, 1, sizeof(buf), in)) > 0) {
|
||||||
|
Loading…
Reference in New Issue
Block a user