mirror of
https://github.com/janet-lang/janet
synced 2024-12-23 15:00:27 +00:00
Web assembly build with emscripten.
This commit is contained in:
parent
dde6218bff
commit
c1923c5ada
5
.gitignore
vendored
5
.gitignore
vendored
@ -10,6 +10,11 @@ janet
|
|||||||
/Emscripten
|
/Emscripten
|
||||||
/src/include/generated/*.h
|
/src/include/generated/*.h
|
||||||
|
|
||||||
|
# Emscripten
|
||||||
|
*.bc
|
||||||
|
janet.js
|
||||||
|
janet.wasm
|
||||||
|
|
||||||
# Generated files
|
# Generated files
|
||||||
*.gen.h
|
*.gen.h
|
||||||
*.gen.c
|
*.gen.c
|
||||||
|
32
Makefile
32
Makefile
@ -55,6 +55,7 @@ JANET_LOCAL_HEADERS=$(sort $(wildcard src/*/*.h))
|
|||||||
# Source files
|
# Source files
|
||||||
JANET_CORE_SOURCES=$(sort $(wildcard src/core/*.c))
|
JANET_CORE_SOURCES=$(sort $(wildcard src/core/*.c))
|
||||||
JANET_MAINCLIENT_SOURCES=$(sort $(wildcard src/mainclient/*.c))
|
JANET_MAINCLIENT_SOURCES=$(sort $(wildcard src/mainclient/*.c))
|
||||||
|
JANET_WEBCLIENT_SOURCES=$(sort $(wildcard src/webclient/*.c))
|
||||||
|
|
||||||
all: $(JANET_TARGET) $(JANET_LIBRARY)
|
all: $(JANET_TARGET) $(JANET_LIBRARY)
|
||||||
|
|
||||||
@ -72,6 +73,9 @@ xxd: src/tools/xxd.c
|
|||||||
src/include/generated/init.h: src/mainclient/init.janet xxd
|
src/include/generated/init.h: src/mainclient/init.janet xxd
|
||||||
./xxd $< $@ janet_gen_init
|
./xxd $< $@ janet_gen_init
|
||||||
|
|
||||||
|
src/include/generated/webinit.h: src/webclient/webinit.janet xxd
|
||||||
|
./xxd $< $@ janet_gen_webinit
|
||||||
|
|
||||||
src/include/generated/core.h: src/core/core.janet xxd
|
src/include/generated/core.h: src/core/core.janet xxd
|
||||||
./xxd $< $@ janet_gen_core
|
./xxd $< $@ janet_gen_core
|
||||||
|
|
||||||
@ -93,10 +97,30 @@ JANET_ALL_OBJECTS=$(patsubst %.c,%.o,$(JANET_ALL_SOURCES))
|
|||||||
$(CC) $(CFLAGS) -o $@ -c $<
|
$(CC) $(CFLAGS) -o $@ -c $<
|
||||||
|
|
||||||
$(JANET_TARGET): $(JANET_ALL_OBJECTS)
|
$(JANET_TARGET): $(JANET_ALL_OBJECTS)
|
||||||
$(CC) $(CFLAGS) -o $(JANET_TARGET) $^ $(CLIBS)
|
$(CC) $(CFLAGS) -o $@ $^ $(CLIBS)
|
||||||
|
|
||||||
$(JANET_LIBRARY): $(JANET_CORE_OBJECTS)
|
$(JANET_LIBRARY): $(JANET_CORE_OBJECTS)
|
||||||
$(CC) $(CFLAGS) -shared -o $(JANET_LIBRARY) $^ $(CLIBS)
|
$(CC) $(CFLAGS) -shared -o $@ $^ $(CLIBS)
|
||||||
|
|
||||||
|
######################
|
||||||
|
##### Emscripten #####
|
||||||
|
######################
|
||||||
|
|
||||||
|
EMCC=emcc
|
||||||
|
EMCCFLAGS=-std=c99 -Wall -Wextra -Isrc/include -fpic -O2 -s EXTRA_EXPORTED_RUNTIME_METHODS='["cwrap"]'
|
||||||
|
JANET_EMTARGET=janet.js
|
||||||
|
JANET_WEB_SOURCES=$(JANET_CORE_SOURCES) $(JANET_WEBCLIENT_SOURCES)
|
||||||
|
JANET_EMOBJECTS=$(patsubst %.c,%.bc,$(JANET_WEB_SOURCES))
|
||||||
|
|
||||||
|
# Only a few files depend on generated headers
|
||||||
|
src/core/corelib.bc: src/include/generated/core.h
|
||||||
|
src/webclient/main.bc: src/include/generated/webinit.h
|
||||||
|
|
||||||
|
%.bc: %.c $(JANET_HEADERS) $(JANET_LOCAL_HEADERS)
|
||||||
|
$(EMCC) $(EMCCFLAGS) -o $@ -c $<
|
||||||
|
|
||||||
|
$(JANET_EMTARGET): $(JANET_EMOBJECTS)
|
||||||
|
$(EMCC) $(EMCCFLAGS) -shared -o $@ $^
|
||||||
|
|
||||||
###################
|
###################
|
||||||
##### Testing #####
|
##### Testing #####
|
||||||
@ -139,8 +163,8 @@ clean-natives:
|
|||||||
|
|
||||||
clean:
|
clean:
|
||||||
-rm $(JANET_TARGET)
|
-rm $(JANET_TARGET)
|
||||||
-rm src/**/*.o
|
-rm $(JANET_LIBRARY)
|
||||||
-rm vgcore.*
|
-rm src/**/*.o src/**/*.bc vgcore.* *.js *.wasm *.html
|
||||||
-rm $(JANET_GENERATED_HEADERS)
|
-rm $(JANET_GENERATED_HEADERS)
|
||||||
|
|
||||||
install: $(JANET_TARGET)
|
install: $(JANET_TARGET)
|
||||||
|
@ -792,8 +792,9 @@
|
|||||||
(defn pp
|
(defn pp
|
||||||
"Pretty print a value. Displays values inside collections, and is safe
|
"Pretty print a value. Displays values inside collections, and is safe
|
||||||
to call on any table. Does not print table prototype information."
|
to call on any table. Does not print table prototype information."
|
||||||
[x]
|
@[x file]
|
||||||
|
|
||||||
|
(default file stdout)
|
||||||
(def buf @"")
|
(def buf @"")
|
||||||
(def indent @"\n")
|
(def indent @"\n")
|
||||||
(def seen @{})
|
(def seen @{})
|
||||||
@ -853,12 +854,11 @@
|
|||||||
(def complex? (> (length y) 4))
|
(def complex? (> (length y) 4))
|
||||||
((if complex? pp-dict-nested pp-dict-simple) y))
|
((if complex? pp-dict-nested pp-dict-simple) y))
|
||||||
|
|
||||||
(def printers {
|
(def printers
|
||||||
:array (fn [y] (do-ds y "@[" "]" true pp-seq))
|
{:array (fn [y] (do-ds y "@[" "]" true pp-seq))
|
||||||
:tuple (fn [y] (do-ds y "(" ")" false pp-seq))
|
:tuple (fn [y] (do-ds y "(" ")" false pp-seq))
|
||||||
:table (fn [y] (do-ds y "@{" "}" true pp-dict))
|
:table (fn [y] (do-ds y "@{" "}" true pp-dict))
|
||||||
:struct (fn [y] (do-ds y "{" "}" false pp-dict))
|
:struct (fn [y] (do-ds y "{" "}" false pp-dict))})
|
||||||
})
|
|
||||||
|
|
||||||
(:= recur (fn [y]
|
(:= recur (fn [y]
|
||||||
(def p (get printers (type y)))
|
(def p (get printers (type y)))
|
||||||
@ -869,7 +869,7 @@
|
|||||||
(recur x)
|
(recur x)
|
||||||
(buffer.push-string buf "\n")
|
(buffer.push-string buf "\n")
|
||||||
|
|
||||||
(file.write stdout buf)
|
(file.write file buf)
|
||||||
nil)
|
nil)
|
||||||
|
|
||||||
###
|
###
|
||||||
@ -1041,8 +1041,8 @@
|
|||||||
(def (line col) (parser.where p))
|
(def (line col) (parser.where p))
|
||||||
(onerr where "parse" (string (parser.error p) " on line " line ", column " col)))
|
(onerr where "parse" (string (parser.error p) " on line " line ", column " col)))
|
||||||
(case (fiber.status chars)
|
(case (fiber.status chars)
|
||||||
:new (parser.byte p (resume chars))
|
:new (parser.byte p (resume chars nil))
|
||||||
:pending (parser.byte p (resume chars))
|
:pending (parser.byte p (resume chars nil))
|
||||||
(:= going false))))
|
(:= going false))))
|
||||||
(when (not= :root (parser.status p))
|
(when (not= :root (parser.status p))
|
||||||
(onerr where "parse" "unexpected end of source"))))
|
(onerr where "parse" "unexpected end of source"))))
|
||||||
@ -1067,7 +1067,7 @@
|
|||||||
err)
|
err)
|
||||||
errf))))
|
errf))))
|
||||||
:a))
|
:a))
|
||||||
(def res (resume f))
|
(def res (resume f nil))
|
||||||
(when good
|
(when good
|
||||||
(def sig (fiber.status f))
|
(def sig (fiber.status f))
|
||||||
(if going
|
(if going
|
||||||
@ -1078,18 +1078,18 @@
|
|||||||
# Run loop
|
# Run loop
|
||||||
(def oldenv *env*)
|
(def oldenv *env*)
|
||||||
(:= *env* env)
|
(:= *env* env)
|
||||||
(while going (eval1 (resume vals)))
|
(while going (eval1 (resume vals nil)))
|
||||||
(:= *env* oldenv)
|
(:= *env* oldenv)
|
||||||
|
|
||||||
env)
|
env)
|
||||||
|
|
||||||
(defn default-error-handler
|
(defn default-error-handler
|
||||||
@[source t x f]
|
@[source t x f]
|
||||||
(file.write stdout (string t " error in " source ": "))
|
(file.write stderr (string t " error in " source ": "))
|
||||||
(if (bytes? x)
|
(if (bytes? x)
|
||||||
(do (file.write stdout x)
|
(do (file.write stderr x)
|
||||||
(file.write stdout "\n"))
|
(file.write stderr "\n"))
|
||||||
(pp x))
|
(pp x stderr))
|
||||||
(when f
|
(when f
|
||||||
(def st (fiber.stack f))
|
(def st (fiber.stack f))
|
||||||
(loop
|
(loop
|
||||||
@ -1101,25 +1101,25 @@
|
|||||||
:source source
|
:source source
|
||||||
:line source-line
|
:line source-line
|
||||||
:column source-col} :in st]
|
:column source-col} :in st]
|
||||||
(file.write stdout " in")
|
(file.write stderr " in")
|
||||||
(when c (file.write stdout " cfunction"))
|
(when c (file.write stderr " cfunction"))
|
||||||
(if name
|
(if name
|
||||||
(file.write stdout " " name)
|
(file.write stderr " " name)
|
||||||
(when func (file.write stdout " " (string func))))
|
(when func (file.write stderr " " (string func))))
|
||||||
(if source
|
(if source
|
||||||
(do
|
(do
|
||||||
(file.write stdout " [" source "]")
|
(file.write stderr " [" source "]")
|
||||||
(if source-line
|
(if source-line
|
||||||
(file.write
|
(file.write
|
||||||
stdout
|
stderr
|
||||||
" on line "
|
" on line "
|
||||||
(string source-line)
|
(string source-line)
|
||||||
", column "
|
", column "
|
||||||
(string source-col)))))
|
(string source-col)))))
|
||||||
(if (and (not source-line) pc)
|
(if (and (not source-line) pc)
|
||||||
(file.write stdout " (pc=" (string pc) ")"))
|
(file.write stderr " (pc=" (string pc) ")"))
|
||||||
(when tail (file.write stdout " (tailcall)"))
|
(when tail (file.write stderr " (tailcall)"))
|
||||||
(file.write stdout "\n"))))
|
(file.write stderr "\n"))))
|
||||||
|
|
||||||
(defn eval
|
(defn eval
|
||||||
"Evaluates a string in the current environment. If more control over the
|
"Evaluates a string in the current environment. If more control over the
|
||||||
@ -1237,10 +1237,8 @@
|
|||||||
|
|
||||||
(defn import* [env path & args]
|
(defn import* [env path & args]
|
||||||
(def targs (apply table args))
|
(def targs (apply table args))
|
||||||
(def {
|
(def {:as as
|
||||||
:as as
|
:prefix prefix} targs)
|
||||||
:prefix prefix
|
|
||||||
} targs)
|
|
||||||
(def newenv (require path targs))
|
(def newenv (require path targs))
|
||||||
(var k (next newenv nil))
|
(var k (next newenv nil))
|
||||||
(def {:meta meta} newenv)
|
(def {:meta meta} newenv)
|
||||||
|
@ -28,24 +28,19 @@
|
|||||||
/* Generated header */
|
/* Generated header */
|
||||||
#include <generated/core.h>
|
#include <generated/core.h>
|
||||||
|
|
||||||
/* Only include dynamic modules if enabled */
|
|
||||||
#ifdef JANET_DYNAMIC_MODULES
|
|
||||||
|
|
||||||
/* Use LoadLibrary on windows or dlopen on posix to load dynamic libaries
|
/* Use LoadLibrary on windows or dlopen on posix to load dynamic libaries
|
||||||
* with native code. */
|
* with native code. */
|
||||||
#ifdef JANET_WINDOWS
|
#if defined(JANET_NO_DYNAMIC_MODULES)
|
||||||
|
typedef int Clib;
|
||||||
|
#define load_clib(name) ((void) name, 0)
|
||||||
|
#define symbol_clib(lib, sym) ((void) lib, (void) sym, 0)
|
||||||
|
#define error_clib() "dynamic libraries not supported"
|
||||||
|
#elif defined(JANET_WINDOWS)
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
typedef HINSTANCE Clib;
|
typedef HINSTANCE Clib;
|
||||||
#define load_clib(name) LoadLibrary((name))
|
#define load_clib(name) LoadLibrary((name))
|
||||||
#define symbol_clib(lib, sym) GetProcAddress((lib), (sym))
|
#define symbol_clib(lib, sym) GetProcAddress((lib), (sym))
|
||||||
#define error_clib() "could not load dynamic library"
|
#define error_clib() "could not load dynamic library"
|
||||||
#elif defined(JANET_WEB)
|
|
||||||
#include <emscripten.h>
|
|
||||||
/* TODO - figure out how loading modules will work in JS */
|
|
||||||
typedef int Clib;
|
|
||||||
#define load_clib(name) 0
|
|
||||||
#define symbol_clib(lib, sym) 0
|
|
||||||
#define error_clib() "dynamic libraries not supported"
|
|
||||||
#else
|
#else
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
typedef void *Clib;
|
typedef void *Clib;
|
||||||
@ -82,9 +77,6 @@ static int janet_core_native(JanetArgs args) {
|
|||||||
JANET_RETURN_CFUNCTION(args, init);
|
JANET_RETURN_CFUNCTION(args, init);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
/* end JANET_DYNAMIC_MODULES */
|
|
||||||
|
|
||||||
static int janet_core_print(JanetArgs args) {
|
static int janet_core_print(JanetArgs args) {
|
||||||
int32_t i;
|
int32_t i;
|
||||||
for (i = 0; i < args.n; ++i) {
|
for (i = 0; i < args.n; ++i) {
|
||||||
@ -295,9 +287,7 @@ static int janet_core_hash(JanetArgs args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const JanetReg cfuns[] = {
|
static const JanetReg cfuns[] = {
|
||||||
#ifdef JANET_DYNAMIC_MODULES
|
|
||||||
{"native", janet_core_native},
|
{"native", janet_core_native},
|
||||||
#endif
|
|
||||||
{"print", janet_core_print},
|
{"print", janet_core_print},
|
||||||
{"describe", janet_core_describe},
|
{"describe", janet_core_describe},
|
||||||
{"string", janet_core_string},
|
{"string", janet_core_string},
|
||||||
@ -605,7 +595,7 @@ JanetTable *janet_core_env(void) {
|
|||||||
janet_def(env, "_env", ret);
|
janet_def(env, "_env", ret);
|
||||||
|
|
||||||
/* Run bootstrap source */
|
/* Run bootstrap source */
|
||||||
janet_dobytes(env, janet_gen_core, sizeof(janet_gen_core), "core.janet");
|
janet_dobytes(env, janet_gen_core, sizeof(janet_gen_core), "core.janet", NULL);
|
||||||
|
|
||||||
return env;
|
return env;
|
||||||
}
|
}
|
||||||
|
@ -158,6 +158,9 @@ static int janet_io_popen(JanetArgs args) {
|
|||||||
flags = (fmode[0] == 'r') ? IO_PIPED | IO_READ : IO_PIPED | IO_WRITE;
|
flags = (fmode[0] == 'r') ? IO_PIPED | IO_READ : IO_PIPED | IO_WRITE;
|
||||||
#ifdef JANET_WINDOWS
|
#ifdef JANET_WINDOWS
|
||||||
#define popen _popen
|
#define popen _popen
|
||||||
|
#endif
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
#define popen(A, B) (errno = 0, NULL)
|
||||||
#endif
|
#endif
|
||||||
f = popen((const char *)fname, (const char *)fmode);
|
f = popen((const char *)fname, (const char *)fmode);
|
||||||
if (!f) {
|
if (!f) {
|
||||||
|
@ -45,6 +45,8 @@ static int os_which(JanetArgs args) {
|
|||||||
JANET_RETURN_CSYMBOL(args, ":windows");
|
JANET_RETURN_CSYMBOL(args, ":windows");
|
||||||
#elif __APPLE__
|
#elif __APPLE__
|
||||||
JANET_RETURN_CSYMBOL(args, ":macos");
|
JANET_RETURN_CSYMBOL(args, ":macos");
|
||||||
|
#elif defined(__EMSCRIPTEN__)
|
||||||
|
JANET_RETURN_CSYMBOL(args, ":web");
|
||||||
#else
|
#else
|
||||||
JANET_RETURN_CSYMBOL(args, ":posix");
|
JANET_RETURN_CSYMBOL(args, ":posix");
|
||||||
#endif
|
#endif
|
||||||
|
@ -66,12 +66,13 @@ void janet_stacktrace(JanetFiber *fiber, const char *errtype, Janet err) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Run a string */
|
/* Run a string */
|
||||||
int janet_dobytes(JanetTable *env, const uint8_t *bytes, int32_t len, const char *sourcePath) {
|
int janet_dobytes(JanetTable *env, const uint8_t *bytes, int32_t len, const char *sourcePath, Janet *out) {
|
||||||
JanetParser parser;
|
JanetParser parser;
|
||||||
int errflags = 0;
|
int errflags = 0;
|
||||||
int32_t index = 0;
|
int32_t index = 0;
|
||||||
int dudeol = 0;
|
int dudeol = 0;
|
||||||
int done = 0;
|
int done = 0;
|
||||||
|
Janet ret = janet_wrap_nil();
|
||||||
const uint8_t *where = sourcePath ? janet_cstring(sourcePath) : NULL;
|
const uint8_t *where = sourcePath ? janet_cstring(sourcePath) : NULL;
|
||||||
if (where) janet_gcroot(janet_wrap_string(where));
|
if (where) janet_gcroot(janet_wrap_string(where));
|
||||||
janet_parser_init(&parser);
|
janet_parser_init(&parser);
|
||||||
@ -85,7 +86,6 @@ int janet_dobytes(JanetTable *env, const uint8_t *bytes, int32_t len, const char
|
|||||||
if (cres.status == JANET_COMPILE_OK) {
|
if (cres.status == JANET_COMPILE_OK) {
|
||||||
JanetFunction *f = janet_thunk(cres.funcdef);
|
JanetFunction *f = janet_thunk(cres.funcdef);
|
||||||
JanetFiber *fiber = janet_fiber(f, 64);
|
JanetFiber *fiber = janet_fiber(f, 64);
|
||||||
Janet ret = janet_wrap_nil();
|
|
||||||
JanetSignal status = janet_run(fiber, &ret);
|
JanetSignal status = janet_run(fiber, &ret);
|
||||||
if (status != JANET_SIGNAL_OK) {
|
if (status != JANET_SIGNAL_OK) {
|
||||||
janet_stacktrace(fiber, "runtime", ret);
|
janet_stacktrace(fiber, "runtime", ret);
|
||||||
@ -126,12 +126,13 @@ int janet_dobytes(JanetTable *env, const uint8_t *bytes, int32_t len, const char
|
|||||||
}
|
}
|
||||||
janet_parser_deinit(&parser);
|
janet_parser_deinit(&parser);
|
||||||
if (where) janet_gcunroot(janet_wrap_string(where));
|
if (where) janet_gcunroot(janet_wrap_string(where));
|
||||||
|
if (out) *out = ret;
|
||||||
return errflags;
|
return errflags;
|
||||||
}
|
}
|
||||||
|
|
||||||
int janet_dostring(JanetTable *env, const char *str, const char *sourcePath) {
|
int janet_dostring(JanetTable *env, const char *str, const char *sourcePath, Janet *out) {
|
||||||
int32_t len = 0;
|
int32_t len = 0;
|
||||||
while (str[len]) ++len;
|
while (str[len]) ++len;
|
||||||
return janet_dobytes(env, (const uint8_t *)str, len, sourcePath);
|
return janet_dobytes(env, (const uint8_t *)str, len, sourcePath, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ void janet_symcache_deinit() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Mark an entry in the table as deleted. */
|
/* Mark an entry in the table as deleted. */
|
||||||
#define JANET_SYMCACHE_DELETED ((const uint8_t *)0 + 1)
|
static const uint8_t JANET_SYMCACHE_DELETED[1] = {0};
|
||||||
|
|
||||||
/* Find an item in the cache and return its location.
|
/* Find an item in the cache and return its location.
|
||||||
* If the item is not found, return the location
|
* If the item is not found, return the location
|
||||||
|
@ -93,6 +93,11 @@ extern "C" {
|
|||||||
#define JANET_LITTLE_ENDIAN 1
|
#define JANET_LITTLE_ENDIAN 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Check emscripten */
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
#define JANET_NO_DYNAMIC_MODULES
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Define how global janet state is declared */
|
/* Define how global janet state is declared */
|
||||||
#ifdef JANET_SINGLE_THREADED
|
#ifdef JANET_SINGLE_THREADED
|
||||||
#define JANET_THREAD_LOCAL
|
#define JANET_THREAD_LOCAL
|
||||||
@ -893,8 +898,8 @@ JANET_API JanetCompileResult janet_compile(Janet source, JanetTable *env, const
|
|||||||
/* Get the default environment for janet */
|
/* Get the default environment for janet */
|
||||||
JANET_API JanetTable *janet_core_env(void);
|
JANET_API JanetTable *janet_core_env(void);
|
||||||
|
|
||||||
JANET_API int janet_dobytes(JanetTable *env, const uint8_t *bytes, int32_t len, const char *sourcePath);
|
JANET_API int janet_dobytes(JanetTable *env, const uint8_t *bytes, int32_t len, const char *sourcePath, Janet *out);
|
||||||
JANET_API int janet_dostring(JanetTable *env, const char *str, const char *sourcePath);
|
JANET_API int janet_dostring(JanetTable *env, const char *str, const char *sourcePath, Janet *out);
|
||||||
|
|
||||||
/* Number scanning */
|
/* Number scanning */
|
||||||
JANET_API Janet janet_scan_number(const uint8_t *src, int32_t len);
|
JANET_API Janet janet_scan_number(const uint8_t *src, int32_t len);
|
||||||
|
@ -46,7 +46,7 @@ int main(int argc, char **argv) {
|
|||||||
janet_line_init();
|
janet_line_init();
|
||||||
|
|
||||||
/* Run startup script */
|
/* Run startup script */
|
||||||
status = janet_dobytes(env, janet_gen_init, sizeof(janet_gen_init), "init.janet");
|
status = janet_dobytes(env, janet_gen_init, sizeof(janet_gen_init), "init.janet", NULL);
|
||||||
|
|
||||||
/* Deinitialize vm */
|
/* Deinitialize vm */
|
||||||
janet_deinit();
|
janet_deinit();
|
||||||
|
116
src/webclient/main.c
Normal file
116
src/webclient/main.c
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018 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 <janet/janet.h>
|
||||||
|
#include <generated/webinit.h>
|
||||||
|
#include <emscripten.h>
|
||||||
|
|
||||||
|
static JanetFiber *repl_fiber = NULL;
|
||||||
|
static JanetBuffer *line_buffer = NULL;
|
||||||
|
static const uint8_t *line_prompt = NULL;
|
||||||
|
|
||||||
|
/* Yield to JS event loop from janet. Takes a repl prompt
|
||||||
|
* and a buffer to fill with input data. */
|
||||||
|
static int repl_yield(JanetArgs args) {
|
||||||
|
JANET_FIXARITY(args, 2);
|
||||||
|
JANET_ARG_STRING(line_prompt, args, 0);
|
||||||
|
JANET_ARG_BUFFER(line_buffer, args, 1);
|
||||||
|
/* Suspend janet repl by throwing a user defined signal */
|
||||||
|
return JANET_SIGNAL_USER9;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Re-enter the loop */
|
||||||
|
static int enter_loop(void) {
|
||||||
|
Janet ret;
|
||||||
|
JanetSignal status = janet_continue(repl_fiber, janet_wrap_nil(), &ret);
|
||||||
|
if (status == JANET_SIGNAL_ERROR) {
|
||||||
|
janet_stacktrace(repl_fiber, "runtime", ret);
|
||||||
|
janet_deinit();
|
||||||
|
repl_fiber = NULL;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Intialize the repl */
|
||||||
|
EMSCRIPTEN_KEEPALIVE
|
||||||
|
void repl_init(void) {
|
||||||
|
int status;
|
||||||
|
JanetTable *env;
|
||||||
|
|
||||||
|
/* Set up VM */
|
||||||
|
janet_init();
|
||||||
|
env = janet_core_env();
|
||||||
|
|
||||||
|
/* Janet line getter */
|
||||||
|
janet_def(env, "repl-yield", janet_wrap_cfunction(repl_yield));
|
||||||
|
janet_register("repl-yield", janet_wrap_cfunction(repl_yield));
|
||||||
|
|
||||||
|
/* Run startup script */
|
||||||
|
Janet ret;
|
||||||
|
status = janet_dobytes(env, janet_gen_webinit, sizeof(janet_gen_webinit), "webinit.janet", &ret);
|
||||||
|
if (status == JANET_SIGNAL_ERROR) {
|
||||||
|
printf("start up error.\n");
|
||||||
|
janet_deinit();
|
||||||
|
repl_fiber = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
janet_gcroot(ret);
|
||||||
|
repl_fiber = janet_unwrap_fiber(ret);
|
||||||
|
|
||||||
|
/* Start repl */
|
||||||
|
if (enter_loop()) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Deinitialize the repl */
|
||||||
|
EMSCRIPTEN_KEEPALIVE
|
||||||
|
void repl_deinit(void) {
|
||||||
|
if (!repl_fiber) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
repl_fiber = NULL;
|
||||||
|
line_buffer = NULL;
|
||||||
|
janet_deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the prompt to show in the repl */
|
||||||
|
EMSCRIPTEN_KEEPALIVE
|
||||||
|
const char *repl_prompt(void) {
|
||||||
|
return line_prompt ? ((const char *)line_prompt) : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Restart the repl calling from JS. Pass in the input for the next line. */
|
||||||
|
EMSCRIPTEN_KEEPALIVE
|
||||||
|
void repl_input(char *input) {
|
||||||
|
|
||||||
|
/* Create the repl if we haven't yet */
|
||||||
|
if (!repl_fiber) {
|
||||||
|
printf("initialize the repl first");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now fill the pending line_buffer and resume the repl loop */
|
||||||
|
if (line_buffer) {
|
||||||
|
janet_buffer_push_cstring(line_buffer, input);
|
||||||
|
line_buffer = NULL;
|
||||||
|
enter_loop();
|
||||||
|
}
|
||||||
|
}
|
11
src/webclient/webinit.janet
Normal file
11
src/webclient/webinit.janet
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# Copyright 2017-2018 (C) Calvin Rose
|
||||||
|
(print (string "Janet " janet.version " Copyright (C) 2017-2018 Calvin Rose"))
|
||||||
|
|
||||||
|
(fiber.new
|
||||||
|
(fn @[]
|
||||||
|
(repl (fn [buf p]
|
||||||
|
(def [line] (parser.where p))
|
||||||
|
(def prompt (string "janet:" line ":" (parser.state p) "> "))
|
||||||
|
(repl-yield prompt buf)
|
||||||
|
buf)))
|
||||||
|
:9e) # stop fiber on error signals and user9 signals
|
Loading…
Reference in New Issue
Block a user