mirror of
https://github.com/janet-lang/janet
synced 2025-11-22 18:24:49 +00:00
Compare commits
69 Commits
0.3.0
...
clean-stri
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0ce5acec89 | ||
|
|
44e31cac5d | ||
|
|
029394db31 | ||
|
|
00020ba8ab | ||
|
|
1f91ee30fe | ||
|
|
0f0c415bcf | ||
|
|
a6f022a73d | ||
|
|
ec02d55145 | ||
|
|
cb1a773ca8 | ||
|
|
0dc1217d69 | ||
|
|
06f38d3380 | ||
|
|
2e1ec3700d | ||
|
|
9e6b1d1b16 | ||
|
|
bdf03b4706 | ||
|
|
4d96ba3ba9 | ||
|
|
f161002390 | ||
|
|
eb576d6caf | ||
|
|
e0d26629e0 | ||
|
|
17783c3c3e | ||
|
|
c64e92a5de | ||
|
|
291c13bafc | ||
|
|
c6672e62ac | ||
|
|
eb9bd38256 | ||
|
|
3ac6b2335a | ||
|
|
c6edf03ae8 | ||
|
|
5020a1bae9 | ||
|
|
86ba69c16b | ||
|
|
5f70024f87 | ||
|
|
9ff819a4a1 | ||
|
|
1244e2e93b | ||
|
|
b61d1a0a0e | ||
|
|
89ef4eb634 | ||
|
|
114a45306d | ||
|
|
fe27df528c | ||
|
|
8ab60e475a | ||
|
|
6321c30cb1 | ||
|
|
8343c9edd1 | ||
|
|
74e1a3273f | ||
|
|
1394dbbd57 | ||
|
|
f6a3853131 | ||
|
|
49465f71f3 | ||
|
|
960cf76eb5 | ||
|
|
1b735564fa | ||
|
|
7ae01d25dd | ||
|
|
cb5263d2d8 | ||
|
|
602092f6d5 | ||
|
|
d3a067a665 | ||
|
|
98a26f5ce3 | ||
|
|
09d9dca5f5 | ||
|
|
8a3f512746 | ||
|
|
19e59705b9 | ||
|
|
367c9da856 | ||
|
|
4bcf6565cd | ||
|
|
0c950d0846 | ||
|
|
7ba925c50a | ||
|
|
cb3b9dd76f | ||
|
|
f4fa55027b | ||
|
|
0fe11adb9c | ||
|
|
b138ee6e8e | ||
|
|
a66f19f636 | ||
|
|
c76f4e89d8 | ||
|
|
85a211b26b | ||
|
|
fe3620529f | ||
|
|
a7551e9b4e | ||
|
|
46c540b93e | ||
|
|
32c209ede9 | ||
|
|
0d293cd3f5 | ||
|
|
f284776490 | ||
|
|
38a7e4faf1 |
@@ -1,4 +1,4 @@
|
||||
image: freebsd
|
||||
image: freebsd/latest
|
||||
packages:
|
||||
- gmake
|
||||
- gcc
|
||||
|
||||
19
CHANGELOG.md
19
CHANGELOG.md
@@ -1,6 +1,25 @@
|
||||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## 0.4.0 - ??
|
||||
- `make-image` function creates pre compiled images for janet. These images
|
||||
link to the core library. They can be loaded via require or manually via
|
||||
`load-image`.
|
||||
- Add bracketed tuples as tuple constructor.
|
||||
- Add partition function to core library.
|
||||
- Pre-compile core library into an image for faster startup.
|
||||
- Add methods to parser values that mirror the api.
|
||||
- Add janet\_getmethod to CAPI for easier use of method like syntax.
|
||||
- Add get/set to abstract types to allow them to behave more
|
||||
like objects with methods.
|
||||
- Add parser/insert to modify parser state programmatically
|
||||
- Add debug/stacktrace for easy, pretty stacktraces
|
||||
- Remove the status-pp function
|
||||
- Update API to run-context to be much more sane
|
||||
- Add :lflags option to cook/make-native
|
||||
- Disallow NaNs as table or struct keys
|
||||
- Update module resolution paths and format
|
||||
|
||||
## 0.3.0 - 2019-26-01
|
||||
- Add amalgamated build to janet for easier embedding.
|
||||
- Add os/date function
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2019 Calvin Rose
|
||||
Copyright (c) 2019 Calvin Rose and contributors
|
||||
|
||||
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
|
||||
|
||||
46
Makefile
46
Makefile
@@ -31,7 +31,7 @@ JANET_BUILD?="\"$(shell git log --pretty=format:'%h' -n 1)\""
|
||||
|
||||
CFLAGS=-std=c99 -Wall -Wextra -Isrc/include -fpic -O2 -fvisibility=hidden \
|
||||
-DJANET_BUILD=$(JANET_BUILD)
|
||||
CLIBS=-lm -ldl
|
||||
CLIBS=-lm
|
||||
JANET_TARGET=build/janet
|
||||
JANET_LIBRARY=build/libjanet.so
|
||||
JANET_PATH?=/usr/local/lib/janet
|
||||
@@ -42,12 +42,15 @@ LDCONFIG:=ldconfig
|
||||
ifeq ($(UNAME), Darwin)
|
||||
# Add other macos/clang flags
|
||||
LDCONFIG:=
|
||||
CLIBS:=$(CLIBS) -ldl
|
||||
else ifeq ($(UNAME), OpenBSD)
|
||||
# pass ...
|
||||
else
|
||||
CFLAGS:=$(CFLAGS) -rdynamic
|
||||
CLIBS:=$(CLIBS) -lrt
|
||||
CLIBS:=$(CLIBS) -lrt -ldl
|
||||
endif
|
||||
|
||||
$(shell mkdir -p build/core build/mainclient build/webclient)
|
||||
$(shell mkdir -p build/core build/mainclient build/webclient build/boot)
|
||||
|
||||
# Source headers
|
||||
JANET_HEADERS=$(sort $(wildcard src/include/janet/*.h))
|
||||
@@ -60,14 +63,33 @@ JANET_WEBCLIENT_SOURCES=$(sort $(wildcard src/webclient/*.c))
|
||||
|
||||
all: $(JANET_TARGET) $(JANET_LIBRARY)
|
||||
|
||||
##################################################################
|
||||
##### The bootstrap interpreter that compiles the core image #####
|
||||
##################################################################
|
||||
|
||||
JANET_BOOT_OBJECTS=$(patsubst src/%.c,build/%.boot.o,$(JANET_CORE_SOURCES) src/boot/boot.c) \
|
||||
build/core.gen.o \
|
||||
build/boot.gen.o
|
||||
|
||||
build/%.boot.o: src/%.c
|
||||
$(CC) $(CFLAGS) -DJANET_BOOTSTRAP -o $@ -c $<
|
||||
|
||||
build/janet_boot: $(JANET_BOOT_OBJECTS)
|
||||
$(CC) $(CFLAGS) -DJANET_BOOTSTRAP -o $@ $^ $(CLIBS)
|
||||
|
||||
# Now the reason we bootstrap in the first place
|
||||
build/core_image.c: build/janet_boot
|
||||
build/janet_boot
|
||||
|
||||
##########################################################
|
||||
##### The main interpreter program and shared object #####
|
||||
##########################################################
|
||||
|
||||
JANET_CORE_OBJECTS=$(patsubst src/%.c,build/%.o,$(JANET_CORE_SOURCES)) build/core.gen.o
|
||||
JANET_CORE_OBJECTS=$(patsubst src/%.c,build/%.o,$(JANET_CORE_SOURCES)) build/core_image.o
|
||||
JANET_MAINCLIENT_OBJECTS=$(patsubst src/%.c,build/%.o,$(JANET_MAINCLIENT_SOURCES)) build/init.gen.o
|
||||
|
||||
%.gen.o: %.gen.c
|
||||
# Compile the core image generated by the bootstrap build
|
||||
build/core_image.o: build/core_image.c $(JANET_HEADERS) $(JANET_LOCAL_HEADERS)
|
||||
$(CC) $(CFLAGS) -o $@ -c $<
|
||||
|
||||
build/%.o: src/%.c $(JANET_HEADERS) $(JANET_LOCAL_HEADERS)
|
||||
@@ -92,11 +114,14 @@ EMCFLAGS=-std=c99 -Wall -Wextra -Isrc/include -O2 \
|
||||
JANET_EMTARGET=build/janet.js
|
||||
JANET_WEB_SOURCES=$(JANET_CORE_SOURCES) $(JANET_WEBCLIENT_SOURCES)
|
||||
JANET_EMOBJECTS=$(patsubst src/%.c,build/%.bc,$(JANET_WEB_SOURCES)) \
|
||||
build/webinit.gen.bc build/core.gen.bc
|
||||
build/webinit.gen.bc build/core_image.bc
|
||||
|
||||
%.gen.bc: %.gen.c
|
||||
$(EMCC) $(EMCFLAGS) -o $@ -c $<
|
||||
|
||||
build/core_image.bc: build/core_image.c $(JANET_HEADERS) $(JANET_LOCAL_HEADERS)
|
||||
$(EMCC) $(EMCFLAGS) -o $@ -c $<
|
||||
|
||||
build/%.bc: src/%.c $(JANET_HEADERS) $(JANET_LOCAL_HEADERS)
|
||||
$(EMCC) $(EMCFLAGS) -o $@ -c $<
|
||||
|
||||
@@ -109,6 +134,9 @@ emscripten: $(JANET_EMTARGET)
|
||||
##### Generated C files #####
|
||||
#############################
|
||||
|
||||
%.gen.o: %.gen.c
|
||||
$(CC) $(CFLAGS) -o $@ -c $<
|
||||
|
||||
build/xxd: tools/xxd.c
|
||||
$(CC) $< -o $@
|
||||
|
||||
@@ -118,12 +146,14 @@ build/init.gen.c: src/mainclient/init.janet build/xxd
|
||||
build/xxd $< $@ janet_gen_init
|
||||
build/webinit.gen.c: src/webclient/webinit.janet build/xxd
|
||||
build/xxd $< $@ janet_gen_webinit
|
||||
build/boot.gen.c: src/boot/boot.janet build/xxd
|
||||
build/xxd $< $@ janet_gen_boot
|
||||
|
||||
########################
|
||||
##### Amalgamation #####
|
||||
########################
|
||||
|
||||
amalg: build/janet.c build/janet.h
|
||||
amalg: build/janet.c build/janet.h build/core_image.c
|
||||
|
||||
build/janet.c: $(JANET_LOCAL_HEADERS) $(JANET_CORE_SOURCES) tools/amalg.janet $(JANET_TARGET)
|
||||
$(JANET_TARGET) tools/amalg.janet > $@
|
||||
@@ -165,7 +195,7 @@ dist: build/janet-dist.tar.gz
|
||||
|
||||
build/janet-%.tar.gz: $(JANET_TARGET) src/include/janet/janet.h \
|
||||
janet.1 LICENSE CONTRIBUTING.md $(JANET_LIBRARY) \
|
||||
build/doc.html README.md
|
||||
build/doc.html README.md build/janet.c
|
||||
tar -czvf $@ $^
|
||||
|
||||
#########################
|
||||
|
||||
10
README.md
10
README.md
@@ -1,5 +1,8 @@
|
||||
[](https://gitter.im/janet-language/community)
|
||||
|
||||
[](https://travis-ci.org/janet-lang/janet)
|
||||
[](https://ci.appveyor.com/project/janet-lang/janet)
|
||||
[](https://builds.sr.ht/~bakpakin/janet/.freebsd.yaml?)
|
||||
|
||||
<img src="https://raw.githubusercontent.com/janet-lang/janet/master/assets/janet-w200.png" alt="Janet logo" width=200 align="left">
|
||||
|
||||
@@ -85,7 +88,7 @@ A repl is launched when the binary is invoked with no arguments. Pass the -h fla
|
||||
to display the usage information. Individual scripts can be run with `./janet myscript.janet`
|
||||
|
||||
If you are looking to explore, you can print a list of all available macros, functions, and constants
|
||||
by entering the command `(all-symbols)` into the repl.
|
||||
by entering the command `(all-bindings)` into the repl.
|
||||
|
||||
```
|
||||
$ ./janet
|
||||
@@ -175,9 +178,10 @@ Building with emscripten on windows is currently unsupported.
|
||||
|
||||
See the examples directory for some example janet code.
|
||||
|
||||
## IRC
|
||||
## Discussion
|
||||
|
||||
Feel free to ask questions and join discussion on [the #janet channel on Freenode](https://webchat.freenode.net/)
|
||||
Feel free to ask questions and join discussion on the [Janet Gitter Channel](https://gitter.im/janet-language/community).
|
||||
Alternatively, check out [the #janet channel on Freenode](https://webchat.freenode.net/)
|
||||
|
||||
## Why Janet
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
mkdir build
|
||||
mkdir build\core
|
||||
mkdir build\mainclient
|
||||
mkdir build\boot
|
||||
|
||||
@rem Build the xxd tool for generating sources
|
||||
@cl /nologo /c tools/xxd.c /Fobuild\xxd.obj
|
||||
@@ -34,12 +35,33 @@ mkdir build\mainclient
|
||||
@if errorlevel 1 goto :BUILDFAIL
|
||||
@build\xxd.exe src\mainclient\init.janet build\init.gen.c janet_gen_init
|
||||
@if errorlevel 1 goto :BUILDFAIL
|
||||
@build\xxd.exe src\boot\boot.janet build\boot.gen.c janet_gen_boot
|
||||
@if errorlevel 1 goto :BUILDFAIL
|
||||
|
||||
@rem Build the generated sources
|
||||
@%JANET_COMPILE% /Fobuild\core\core.gen.obj build\core.gen.c
|
||||
@%JANET_COMPILE% /Fobuild\boot\core.gen.obj build\core.gen.c
|
||||
@if errorlevel 1 goto :BUILDFAIL
|
||||
@%JANET_COMPILE% /Fobuild\mainclient\init.gen.obj build\init.gen.c
|
||||
@if errorlevel 1 goto :BUILDFAIL
|
||||
@%JANET_COMPILE% /Fobuild\boot\boot.gen.obj build\boot.gen.c
|
||||
@if errorlevel 1 goto :BUILDFAIL
|
||||
|
||||
@rem Build the bootstrap interpretter
|
||||
for %%f in (src\core\*.c) do (
|
||||
@%JANET_COMPILE% /DJANET_BOOTSTRAP /Fobuild\boot\%%~nf.obj %%f
|
||||
@if errorlevel 1 goto :BUILDFAIL
|
||||
)
|
||||
for %%f in (src\boot\*.c) do (
|
||||
@%JANET_COMPILE% /DJANET_BOOTSTRAP /Fobuild\boot\%%~nf.obj %%f
|
||||
@if errorlevel 1 goto :BUILDFAIL
|
||||
)
|
||||
%JANET_LINK% /out:build\janet_boot.exe build\boot\*.obj
|
||||
@if errorlevel 1 goto :BUILDFAIL
|
||||
build\janet_boot
|
||||
|
||||
@rem Build the core image
|
||||
@%JANET_COMPILE% /Fobuild\core_image.obj build\core_image.c
|
||||
@if errorlevel 1 goto :BUILDFAIL
|
||||
|
||||
@rem Build the sources
|
||||
for %%f in (src\core\*.c) do (
|
||||
@@ -54,7 +76,7 @@ for %%f in (src\mainclient\*.c) do (
|
||||
)
|
||||
|
||||
@rem Link everything to main client
|
||||
%JANET_LINK% /out:janet.exe build\core\*.obj build\mainclient\*.obj
|
||||
%JANET_LINK% /out:janet.exe build\core\*.obj build\mainclient\*.obj build\core_image.obj
|
||||
@if errorlevel 1 goto :BUILDFAIL
|
||||
|
||||
echo === Successfully built janet.exe for Windows ===
|
||||
@@ -101,6 +123,8 @@ copy README.md dist\README.md
|
||||
copy janet.lib dist\janet.lib
|
||||
copy janet.exp dist\janet.exp
|
||||
copy src\include\janet\janet.h dist\janet.h
|
||||
copy tools\cook.janet dist\cook.janet
|
||||
copy tools\highlight.janet dist\highlight.janet
|
||||
exit /b 0
|
||||
|
||||
:TESTFAIL
|
||||
|
||||
23
examples/numarray/build.janet
Normal file
23
examples/numarray/build.janet
Normal file
@@ -0,0 +1,23 @@
|
||||
(import cook)
|
||||
|
||||
(cook/make-native
|
||||
:name "numarray"
|
||||
:source @["numarray.c"])
|
||||
|
||||
(import build/numarray :prefix "")
|
||||
|
||||
(def a (numarray/new 30))
|
||||
(print (get a 20))
|
||||
(print (a 20))
|
||||
|
||||
(put a 5 3.14)
|
||||
(print (a 5))
|
||||
(set (a 5) 100)
|
||||
(print (a 5))
|
||||
|
||||
# (numarray/scale a 5))
|
||||
# ((a :scale) a 5)
|
||||
(:scale a 5)
|
||||
(for i 0 10 (print (a i)))
|
||||
|
||||
(print "sum=" (:sum a))
|
||||
115
examples/numarray/numarray.c
Normal file
115
examples/numarray/numarray.c
Normal file
@@ -0,0 +1,115 @@
|
||||
#include <stdlib.h>
|
||||
#include <janet/janet.h>
|
||||
|
||||
typedef struct {
|
||||
double * data;
|
||||
size_t size;
|
||||
} num_array;
|
||||
|
||||
static num_array * num_array_init(num_array * array,size_t size) {
|
||||
array->data=(double *)calloc(size,sizeof(double));
|
||||
array->size=size;
|
||||
return array;
|
||||
}
|
||||
|
||||
static void num_array_deinit(num_array * array) {
|
||||
free(array->data);
|
||||
}
|
||||
|
||||
static int num_array_gc(void *p, size_t s) {
|
||||
(void) s;
|
||||
num_array * array=(num_array *)p;
|
||||
num_array_deinit(array);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Janet num_array_get(void *p, Janet key);
|
||||
void num_array_put(void *p, Janet key, Janet value);
|
||||
|
||||
static const JanetAbstractType num_array_type = {
|
||||
"numarray",
|
||||
num_array_gc,
|
||||
NULL,
|
||||
num_array_get,
|
||||
num_array_put
|
||||
};
|
||||
|
||||
static Janet num_array_new(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 1);
|
||||
int32_t size=janet_getinteger(argv,0);
|
||||
num_array * array = (num_array *)janet_abstract(&num_array_type,sizeof(num_array));
|
||||
num_array_init(array,size);
|
||||
return janet_wrap_abstract(array);
|
||||
}
|
||||
|
||||
static Janet num_array_scale(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 2);
|
||||
num_array * array = (num_array *)janet_getabstract(argv,0,&num_array_type);
|
||||
double factor = janet_getnumber(argv,1);
|
||||
size_t i;
|
||||
for (i=0;i<array->size;i++) {
|
||||
array->data[i]*=factor;
|
||||
}
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
static Janet num_array_sum(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 1);
|
||||
num_array * array = (num_array *)janet_getabstract(argv,0,&num_array_type);
|
||||
double sum = 0;
|
||||
for (size_t i=0;i<array->size;i++) sum+=array->data[i];
|
||||
return janet_wrap_number(sum);
|
||||
}
|
||||
|
||||
void num_array_put(void *p, Janet key, Janet value) {
|
||||
size_t index;
|
||||
num_array * array=(num_array *)p;
|
||||
if (!janet_checkint(key))
|
||||
janet_panic("expected integer key");
|
||||
if (!janet_checktype(value,JANET_NUMBER))
|
||||
janet_panic("expected number value");
|
||||
|
||||
index = (size_t)janet_unwrap_integer(key);
|
||||
if (index < array->size) {
|
||||
array->data[index]=janet_unwrap_number(value);
|
||||
}
|
||||
}
|
||||
|
||||
static const JanetMethod methods[] = {
|
||||
{"scale", num_array_scale},
|
||||
{"sum", num_array_sum},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
Janet num_array_get(void *p, Janet key) {
|
||||
size_t index;
|
||||
Janet value;
|
||||
num_array * array=(num_array *)p;
|
||||
if (janet_checktype(key, JANET_KEYWORD))
|
||||
return janet_getmethod(janet_unwrap_keyword(key), methods);
|
||||
if (!janet_checkint(key))
|
||||
janet_panic("expected integer key");
|
||||
index = (size_t)janet_unwrap_integer(key);
|
||||
if (index >= array->size) {
|
||||
value = janet_wrap_nil();
|
||||
} else {
|
||||
value = janet_wrap_number(array->data[index]);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
static const JanetReg cfuns[] = {
|
||||
{"numarray/new", num_array_new,
|
||||
"(numarray/new size)\n\n"
|
||||
"Create new numarray"
|
||||
},
|
||||
{"numarray/scale", num_array_scale,
|
||||
"(numarray/scale numarray factor)\n\n"
|
||||
"scale numarray by factor"
|
||||
},
|
||||
{NULL,NULL,NULL}
|
||||
};
|
||||
|
||||
JANET_MODULE_ENTRY(JanetTable *env) {
|
||||
janet_cfuns(env, "numarray", cfuns);
|
||||
}
|
||||
43
src/boot/boot.c
Normal file
43
src/boot/boot.c
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2019 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>
|
||||
|
||||
extern const unsigned char *janet_gen_boot;
|
||||
extern int32_t janet_gen_boot_size;
|
||||
|
||||
int main() {
|
||||
int status;
|
||||
JanetTable *env;
|
||||
|
||||
/* Set up VM */
|
||||
janet_init();
|
||||
env = janet_core_env();
|
||||
|
||||
/* Run bootstrap script to generate core image */
|
||||
status = janet_dobytes(env, janet_gen_boot, janet_gen_boot_size, "boot.janet", NULL);
|
||||
|
||||
/* Deinitialize vm */
|
||||
janet_deinit();
|
||||
|
||||
return status;
|
||||
}
|
||||
40
src/boot/boot.janet
Normal file
40
src/boot/boot.janet
Normal file
@@ -0,0 +1,40 @@
|
||||
# Copyright (C) Calvin Rose 2019
|
||||
|
||||
# The bootstrap script is used to produce the source file for
|
||||
# embedding the core image.
|
||||
|
||||
# Tool to dump a marshalled version of the janet core to stdout. The
|
||||
# image should eventually allow janet to be started from a pre-compiled
|
||||
# image rather than recompiled every time from the embedded source. More
|
||||
# work will go into shrinking the image (it isn't currently that large but
|
||||
# could be smaller), creating the mechanism to load the image, and modifying
|
||||
# the build process to compile janet with a built image rather than
|
||||
# embedded source.
|
||||
|
||||
# Get image. This image contains as much of the core library and documentation that
|
||||
# can be written to an image (no cfunctions, no abstracts (stdout, stdin, stderr)),
|
||||
# everything else goes. Cfunctions and abstracts will be referenced from a registry
|
||||
# table which will be generated on janet startup.
|
||||
(do
|
||||
(def image (let [env-pairs (pairs (env-lookup *env*))
|
||||
essential-pairs (filter (fn [[k v]] (or (cfunction? v) (abstract? v))) env-pairs)
|
||||
lookup (table ;(mapcat identity essential-pairs))
|
||||
reverse-lookup (invert lookup)]
|
||||
(marshal *env* reverse-lookup)))
|
||||
|
||||
# Create C source file that contains images a uint8_t buffer. This
|
||||
# can be compiled and linked statically into the main janet library
|
||||
# and example client.
|
||||
(def chunks (seq [b :in image] (string b)))
|
||||
(def image-file (file/open "build/core_image.c" :w))
|
||||
(file/write image-file
|
||||
"#include <janet/janet.h>\n"
|
||||
"static const unsigned char janet_core_image_bytes[] = {")
|
||||
(loop [line :in (partition 16 chunks)]
|
||||
(def str (string ;(interpose ", " line)))
|
||||
(file/write image-file str ",\n"))
|
||||
(file/write image-file
|
||||
"0};\n\n"
|
||||
"const unsigned char *janet_core_image = janet_core_image_bytes;\n"
|
||||
"size_t janet_core_image_size = sizeof(janet_core_image_bytes);\n")
|
||||
(file/close image-file))
|
||||
@@ -267,5 +267,5 @@ static const JanetReg array_cfuns[] = {
|
||||
|
||||
/* Load the array module */
|
||||
void janet_lib_array(JanetTable *env) {
|
||||
janet_cfuns(env, NULL, array_cfuns);
|
||||
janet_core_cfuns(env, NULL, array_cfuns);
|
||||
}
|
||||
|
||||
@@ -951,7 +951,7 @@ static const JanetReg asm_cfuns[] = {
|
||||
|
||||
/* Load the library */
|
||||
void janet_lib_asm(JanetTable *env) {
|
||||
janet_cfuns(env, NULL, asm_cfuns);
|
||||
janet_core_cfuns(env, NULL, asm_cfuns);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -317,6 +317,14 @@ static Janet cfun_buffer_blit(int32_t argc, Janet *argv) {
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
static Janet cfun_buffer_format(int32_t argc, Janet *argv) {
|
||||
janet_arity(argc, 2, -1);
|
||||
JanetBuffer *buffer = janet_getbuffer(argv, 0);
|
||||
const char *strfrmt = (const char *) janet_getstring(argv, 1);
|
||||
janet_buffer_format(buffer, strfrmt, 1, argc, argv);
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
static const JanetReg buffer_cfuns[] = {
|
||||
{"buffer/new", cfun_buffer_new,
|
||||
JDOC("(buffer/new capacity)\n\n"
|
||||
@@ -383,9 +391,14 @@ static const JanetReg buffer_cfuns[] = {
|
||||
"indicate which part of src to copy into which part of dest. Indices can be "
|
||||
"negative to index from the end of src or dest. Returns dest.")
|
||||
},
|
||||
{"buffer/format", cfun_buffer_format,
|
||||
JDOC("(buffer/format buffer format & args)\n\n"
|
||||
"Snprintf like functionality for printing values into a buffer. Returns "
|
||||
" the modified buffer.")
|
||||
},
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
void janet_lib_buffer(JanetTable *env) {
|
||||
janet_cfuns(env, NULL, buffer_cfuns);
|
||||
janet_core_cfuns(env, NULL, buffer_cfuns);
|
||||
}
|
||||
|
||||
@@ -27,9 +27,9 @@
|
||||
#endif
|
||||
|
||||
void janet_panicv(Janet message) {
|
||||
if (janet_vm_fiber != NULL) {
|
||||
janet_fiber_push(janet_vm_fiber, message);
|
||||
longjmp(janet_vm_fiber->buf, 1);
|
||||
if (janet_vm_return_reg != NULL) {
|
||||
*janet_vm_return_reg = message;
|
||||
longjmp(*janet_vm_jmp_buf, 1);
|
||||
} else {
|
||||
fputs((const char *)janet_formatc("janet top level panic - %v\n", message), stdout);
|
||||
exit(1);
|
||||
@@ -73,6 +73,16 @@ type janet_get##name(const Janet *argv, int32_t n) { \
|
||||
return janet_unwrap_##name(x); \
|
||||
}
|
||||
|
||||
Janet janet_getmethod(const uint8_t *method, const JanetMethod *methods) {
|
||||
while (methods->name) {
|
||||
if (!janet_cstrcmp(method, methods->name))
|
||||
return janet_wrap_cfunction(methods->cfun);
|
||||
methods++;
|
||||
}
|
||||
janet_panicf("unknown method %S invoked", method);
|
||||
return janet_wrap_nil();
|
||||
}
|
||||
|
||||
DEFINE_GETTER(number, NUMBER, double)
|
||||
DEFINE_GETTER(array, ARRAY, JanetArray *)
|
||||
DEFINE_GETTER(tuple, TUPLE, const Janet *)
|
||||
|
||||
@@ -101,8 +101,15 @@ static JanetSlot do_get(JanetFopts opts, JanetSlot *args) {
|
||||
return opreduce(opts, args, JOP_GET, janet_wrap_nil());
|
||||
}
|
||||
static JanetSlot do_put(JanetFopts opts, JanetSlot *args) {
|
||||
janetc_emit_sss(opts.compiler, JOP_PUT, args[0], args[1], args[2], 0);
|
||||
return args[0];
|
||||
if (opts.flags & JANET_FOPTS_DROP) {
|
||||
janetc_emit_sss(opts.compiler, JOP_PUT, args[0], args[1], args[2], 0);
|
||||
return janetc_cslot(janet_wrap_nil());
|
||||
} else {
|
||||
JanetSlot t = janetc_gettarget(opts);
|
||||
janetc_copy(opts.compiler, t, args[0]);
|
||||
janetc_emit_sss(opts.compiler, JOP_PUT, t, args[1], args[2], 0);
|
||||
return t;
|
||||
}
|
||||
}
|
||||
static JanetSlot do_length(JanetFopts opts, JanetSlot *args) {
|
||||
return genericSS(opts, JOP_LENGTH, args[0]);
|
||||
|
||||
@@ -438,6 +438,14 @@ static JanetSlot janetc_array(JanetFopts opts, Janet x) {
|
||||
JOP_MAKE_ARRAY);
|
||||
}
|
||||
|
||||
static JanetSlot janetc_tuple(JanetFopts opts, Janet x) {
|
||||
JanetCompiler *c = opts.compiler;
|
||||
const Janet *t = janet_unwrap_tuple(x);
|
||||
return janetc_maker(opts,
|
||||
janetc_toslots(c, t, janet_tuple_length(t)),
|
||||
JOP_MAKE_TUPLE);
|
||||
}
|
||||
|
||||
static JanetSlot janetc_tablector(JanetFopts opts, Janet x, int op) {
|
||||
JanetCompiler *c = opts.compiler;
|
||||
return janetc_maker(opts,
|
||||
@@ -547,6 +555,8 @@ JanetSlot janetc_value(JanetFopts opts, Janet x) {
|
||||
/* Empty tuple is tuple literal */
|
||||
if (janet_tuple_length(tup) == 0) {
|
||||
ret = janetc_cslot(x);
|
||||
} else if (janet_tuple_flag(tup) & JANET_TUPLE_FLAG_BRACKETCTOR) { /* [] tuples are not function call */
|
||||
ret = janetc_tuple(opts, x);
|
||||
} else {
|
||||
JanetSlot head = janetc_value(subopts, tup[0]);
|
||||
subopts.flags = JANET_FUNCTION | JANET_CFUNCTION;
|
||||
@@ -738,5 +748,5 @@ static const JanetReg compile_cfuns[] = {
|
||||
};
|
||||
|
||||
void janet_lib_compile(JanetTable *env) {
|
||||
janet_cfuns(env, NULL, compile_cfuns);
|
||||
janet_core_cfuns(env, NULL, compile_cfuns);
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
(def buf (buffer "(" name))
|
||||
(while (< index arglen)
|
||||
(buffer/push-string buf " ")
|
||||
(string/pretty (get args index) 4 buf)
|
||||
(buffer/format buf "%p" (get args index))
|
||||
(set index (+ index 1)))
|
||||
(array/push modifiers (string buf ")\n\n" docstr))
|
||||
# Build return value
|
||||
@@ -440,12 +440,12 @@
|
||||
(defmacro for
|
||||
"Do a c style for loop for side effects. Returns nil."
|
||||
[binding start end & body]
|
||||
(apply loop [tuple binding :range [tuple start end]] body))
|
||||
(apply loop (tuple binding :range (tuple start end)) body))
|
||||
|
||||
(defmacro each
|
||||
"Loop over each value in ind. Returns nil."
|
||||
[binding ind & body]
|
||||
(apply loop [tuple binding :in ind] body))
|
||||
(apply loop (tuple binding :in ind) body))
|
||||
|
||||
(defmacro coro
|
||||
"A wrapper for making fibers. Same as (fiber/new (fn [&] ...body))."
|
||||
@@ -723,7 +723,8 @@
|
||||
nil if not found. Note their is no way to differentiate a nil from the indexed collection
|
||||
and a not found. Consider find-index if this is an issue."
|
||||
[pred ind]
|
||||
(get ind (find-index pred ind)))
|
||||
(def i (find-index pred ind))
|
||||
(if (= i nil) nil (get ind i)))
|
||||
|
||||
(defn take-until
|
||||
"Given a predicate, take only elements from an indexed type that satisfy
|
||||
@@ -777,8 +778,8 @@
|
||||
[x & forms]
|
||||
(defn fop [last n]
|
||||
(def [h t] (if (= :tuple (type n))
|
||||
[tuple (get n 0) (array/slice n 1)]
|
||||
[tuple n @[]]))
|
||||
(tuple (get n 0) (array/slice n 1))
|
||||
(tuple n @[])))
|
||||
(def parts (array/concat @[h last] t))
|
||||
(tuple/slice parts 0))
|
||||
(reduce fop x forms))
|
||||
@@ -790,8 +791,8 @@
|
||||
[x & forms]
|
||||
(defn fop [last n]
|
||||
(def [h t] (if (= :tuple (type n))
|
||||
[tuple (get n 0) (array/slice n 1)]
|
||||
[tuple n @[]]))
|
||||
(tuple (get n 0) (array/slice n 1))
|
||||
(tuple n @[])))
|
||||
(def parts (array/concat @[h] t @[last]))
|
||||
(tuple/slice parts 0))
|
||||
(reduce fop x forms))
|
||||
@@ -805,8 +806,8 @@
|
||||
[x & forms]
|
||||
(defn fop [last n]
|
||||
(def [h t] (if (= :tuple (type n))
|
||||
[tuple (get n 0) (array/slice n 1)]
|
||||
[tuple n @[]]))
|
||||
(tuple (get n 0) (array/slice n 1))
|
||||
(tuple n @[])))
|
||||
(def sym (gensym))
|
||||
(def parts (array/concat @[h sym] t))
|
||||
~(let [,sym ,last] (if ,sym ,(tuple/slice parts 0))))
|
||||
@@ -821,8 +822,8 @@
|
||||
[x & forms]
|
||||
(defn fop [last n]
|
||||
(def [h t] (if (= :tuple (type n))
|
||||
[tuple (get n 0) (array/slice n 1)]
|
||||
[tuple n @[]]))
|
||||
(tuple (get n 0) (array/slice n 1))
|
||||
(tuple n @[])))
|
||||
(def sym (gensym))
|
||||
(def parts (array/concat @[h] t @[sym]))
|
||||
~(let [,sym ,last] (if ,sym ,(tuple/slice parts 0))))
|
||||
@@ -1066,6 +1067,47 @@ value, one key will be ignored."
|
||||
(++ i))
|
||||
ret)
|
||||
|
||||
(defn partition
|
||||
"Partition an indexed data structure into tuples
|
||||
of size n. Returns a new array."
|
||||
[n ind]
|
||||
(var i 0) (var nextn n)
|
||||
(def len (length ind))
|
||||
(def ret (array/new (math/ceil (/ len n))))
|
||||
(while (<= nextn len)
|
||||
(array/push ret (tuple/slice ind i nextn))
|
||||
(set i nextn)
|
||||
(+= nextn n))
|
||||
(if (not= i len) (array/push ret (tuple/slice ind i)))
|
||||
ret)
|
||||
|
||||
###
|
||||
###
|
||||
### IO Helpers
|
||||
###
|
||||
###
|
||||
|
||||
(defn slurp
|
||||
"Read all data from a file with name path
|
||||
and then close the file."
|
||||
[path]
|
||||
(def f (file/open path :r))
|
||||
(if-not f (error (string "could not open file " path)))
|
||||
(def contents (file/read f :all))
|
||||
(file/close f)
|
||||
contents)
|
||||
|
||||
(defn spit
|
||||
"Write contents to a file at path.
|
||||
Can optionally append to the file."
|
||||
[path contents mode &]
|
||||
(default mode :w)
|
||||
(def f (file/open path mode))
|
||||
(if-not f (error (string "could not open file " path " with mode " mode)))
|
||||
(file/write f contents)
|
||||
(file/close f)
|
||||
nil)
|
||||
|
||||
###
|
||||
###
|
||||
### Pattern Matching
|
||||
@@ -1309,7 +1351,9 @@ value, one key will be ignored."
|
||||
|
||||
(def ret
|
||||
(case (type x)
|
||||
:tuple (dotup x)
|
||||
:tuple (if (= (tuple/type x) :brackets)
|
||||
(tuple/brackets ;(map macex1 x))
|
||||
(dotup x))
|
||||
:array (map macex1 x)
|
||||
:struct (table/to-struct (dotable x macex1))
|
||||
:table (dotable x macex1)
|
||||
@@ -1367,7 +1411,7 @@ value, one key will be ignored."
|
||||
(defn pp
|
||||
"Pretty print to stdout."
|
||||
[x]
|
||||
(print (string/pretty x)))
|
||||
(print (buffer/format @"" "%p" x)))
|
||||
|
||||
###
|
||||
###
|
||||
@@ -1384,17 +1428,56 @@ value, one key will be ignored."
|
||||
(def newenv (table/setproto @{} parent))
|
||||
newenv)
|
||||
|
||||
(defn bad-parse
|
||||
"Default handler for a parse error."
|
||||
[p where]
|
||||
(file/write stderr
|
||||
"parse error in "
|
||||
where
|
||||
" around byte "
|
||||
(string (parser/where p))
|
||||
": "
|
||||
(or (parser/error p) "unmatched delimiter")
|
||||
"\n"))
|
||||
|
||||
(defn bad-compile
|
||||
"Default handler for a compile error."
|
||||
[msg macrof where]
|
||||
(file/write stderr "compile error: " msg " while compiling " where "\n")
|
||||
(when macrof (debug/stacktrace macrof)))
|
||||
|
||||
(defn getline
|
||||
"Read a line from stdin into a buffer."
|
||||
[buf p &]
|
||||
(default buf @"")
|
||||
(when p (file/write stdout p))
|
||||
(file/read stdin :line buf)
|
||||
buf)
|
||||
|
||||
(defn run-context
|
||||
"Run a context. This evaluates expressions of janet in an environment,
|
||||
and is encapsulates the parsing, compilation, and evaluation of janet.
|
||||
env is the environment to evaluate the code in, chunks is a function
|
||||
that returns strings or buffers of source code (from a repl, file,
|
||||
network connection, etc. onstatus is a callback that is
|
||||
invoked when a result is returned or any other signal is raised.
|
||||
and is encapsulates the parsing, compilation, and evaluation.
|
||||
opts is a table or struct of options. The options are as follows:\n\n\t
|
||||
:chunks - callback to read into a buffer - default is getline\n\t
|
||||
:on-parse-error - callback when parsing fails - default is bad-parse\n\t
|
||||
:env - the environment to compile against - default is *env*\n\t
|
||||
:source - string path of source for better errors - default is \"<anonymous>\"\n\t
|
||||
:on-compile-error - callback when compilation fails - default is bad-compile\n\t
|
||||
:on-status - callback when a value is evaluated - default is debug/stacktrace"
|
||||
[opts]
|
||||
|
||||
This function can be used to implement a repl very easily, simply
|
||||
pass a function that reads line from stdin to chunks, status-pp to onstatus"
|
||||
[env chunks onstatus where &]
|
||||
(def {:env env
|
||||
:chunks chunks
|
||||
:on-status onstatus
|
||||
:on-compile-error on-compile-error
|
||||
:on-parse-error on-parse-error
|
||||
:source where} opts)
|
||||
(default env *env*)
|
||||
(default chunks getline)
|
||||
(default onstatus debug/stacktrace)
|
||||
(default on-compile-error bad-compile)
|
||||
(default on-parse-error bad-parse)
|
||||
(default where "<anonymous>")
|
||||
|
||||
# Are we done yet?
|
||||
(var going true)
|
||||
@@ -1414,17 +1497,14 @@ value, one key will be ignored."
|
||||
(do
|
||||
(set good false)
|
||||
(def {:error err :start start :end end :fiber errf} res)
|
||||
(onstatus
|
||||
:compile
|
||||
(def msg
|
||||
(if (<= 0 start)
|
||||
(string err "\n at (" start ":" end ")")
|
||||
err)
|
||||
errf
|
||||
where))))
|
||||
(string "compile error: " err " at (" start ":" end ")")
|
||||
err))
|
||||
(on-compile-error msg errf where))))
|
||||
:a))
|
||||
(def res (resume f nil))
|
||||
(when good
|
||||
(if going (onstatus (fiber/status f) res f where))))
|
||||
(when good (if going (onstatus f res))))
|
||||
|
||||
(def oldenv *env*)
|
||||
(set *env* env)
|
||||
@@ -1443,73 +1523,19 @@ value, one key will be ignored."
|
||||
(while (parser/has-more p)
|
||||
(eval1 (parser/produce p)))
|
||||
(when (= (parser/status p) :error)
|
||||
(onstatus :parse
|
||||
(string (parser/error p)
|
||||
" around byte " (parser/where p))
|
||||
nil
|
||||
where))))
|
||||
(on-parse-error p where))))
|
||||
|
||||
(if (= (parser/status p) :pending)
|
||||
(onstatus :parse
|
||||
(string "unmatched delimiters " (parser/state p))
|
||||
nil
|
||||
where))
|
||||
(on-parse-error p where))
|
||||
|
||||
(set *env* oldenv)
|
||||
|
||||
env)
|
||||
|
||||
(defn status-pp
|
||||
"Pretty print a signal and associated state. Can be used as the
|
||||
onsignal argument to run-context."
|
||||
[sig x f source]
|
||||
(def title
|
||||
(case sig
|
||||
:parse "parse error"
|
||||
:compile "compile error"
|
||||
:error "error"
|
||||
(string "status " sig)))
|
||||
(file/write stderr
|
||||
(string title " in " source ": ")
|
||||
(if (bytes? x) x (string/pretty x))
|
||||
"\n")
|
||||
(when f
|
||||
(loop
|
||||
[nf :in (reverse (debug/lineage f))
|
||||
{:function func
|
||||
:tail tail
|
||||
:pc pc
|
||||
:c c
|
||||
:name name
|
||||
:source source
|
||||
:source-start start
|
||||
:source-end end} :in (debug/stack nf)]
|
||||
(file/write stderr " in")
|
||||
(when c (file/write stderr " cfunction"))
|
||||
(if name
|
||||
(file/write stderr " " name)
|
||||
(when func (file/write stderr " <anonymous>")))
|
||||
(if source
|
||||
(do
|
||||
(file/write stderr " [" source "]")
|
||||
(if start
|
||||
(file/write
|
||||
stderr
|
||||
" at ("
|
||||
(string start)
|
||||
":"
|
||||
(string end)
|
||||
")"))))
|
||||
(if (and (not start) pc)
|
||||
(file/write stderr " (pc=" (string pc) ")"))
|
||||
(when tail (file/write stderr " (tailcall)"))
|
||||
(file/write stderr "\n"))))
|
||||
|
||||
(defn eval-string
|
||||
"Evaluates a string in the current environment. If more control over the
|
||||
environment is needed, use run-context."
|
||||
[str env &]
|
||||
(default env *env*)
|
||||
(var state (string str))
|
||||
(defn chunks [buf _]
|
||||
(def ret state)
|
||||
@@ -1518,12 +1544,15 @@ value, one key will be ignored."
|
||||
(buffer/push-string buf str)
|
||||
(buffer/push-string buf "\n")))
|
||||
(var returnval nil)
|
||||
(run-context env chunks
|
||||
(fn [sig x f source]
|
||||
(if (= sig :dead)
|
||||
(set returnval x)
|
||||
(status-pp sig x f source)))
|
||||
"eval")
|
||||
(run-context {:env env
|
||||
:chunks chunks
|
||||
:on-compile-error error
|
||||
:on-parse-error error
|
||||
:on-status (fn [f val]
|
||||
(set returnval val)
|
||||
(if-not (= (fiber/status f) :dead)
|
||||
(debug/stacktrace f val)))
|
||||
:source "eval"})
|
||||
returnval)
|
||||
|
||||
(defn eval
|
||||
@@ -1536,24 +1565,39 @@ value, one key will be ignored."
|
||||
(res)
|
||||
(error (res :error))))
|
||||
|
||||
(defn make-image
|
||||
"Create an image from an environment returned by require.
|
||||
Returns the image source as a string."
|
||||
[env]
|
||||
(marshal env (invert (env-lookup _env))))
|
||||
|
||||
(defn load-image
|
||||
"The inverse operation to make-image. Returns an environment."
|
||||
[image]
|
||||
(unmarshal image (env-lookup _env)))
|
||||
|
||||
(def module/paths
|
||||
"The list of paths to look for modules. The followig
|
||||
"The list of paths to look for modules. The following
|
||||
substitutions are preformed on each path. :sys: becomes
|
||||
module/*syspath*, :name: becomes the last part of the module
|
||||
name after the last /, and :all: is the module name literally.
|
||||
:native: becomes the dynamic library file extension, usually dll
|
||||
or so."
|
||||
@["./:all:.janet"
|
||||
"./:all:/init.janet"
|
||||
":sys:/:all:.janet"
|
||||
":sys:/:all:/init.janet"])
|
||||
|
||||
(def module/native-paths
|
||||
"See doc for module/paths"
|
||||
@["./:all:.:native:"
|
||||
"./:all:/:name:.:native:"
|
||||
":sys:/:all:.:native:"
|
||||
":sys:/:all:/:name:.:native:"])
|
||||
or so. Each element is a two element tuple, containing the path
|
||||
template and a keyword :source, :native, or :image indicating how
|
||||
require should load files found at these paths."
|
||||
@[["./:all:.janet" :source]
|
||||
["./:all:/init.janet" :source]
|
||||
[":sys:/:all:.janet" :source]
|
||||
[":sys:/:all:/init.janet" :source]
|
||||
["./:all:.:native:" :native]
|
||||
["./:all:/:name:.:native:" :native]
|
||||
[":sys:/:all:.:native:" :native]
|
||||
[":sys:/:all:/:name:.:native:" :native]
|
||||
["./:all:.jimage" :image]
|
||||
["./:all:.:name:.jimage" :image]
|
||||
[":sys:/:all:.jimage" :image]
|
||||
[":sys:/:all:/:name:.jimage" :image]
|
||||
[":all:" :source]])
|
||||
|
||||
(var module/*syspath*
|
||||
"The path where globally installed libraries are located.
|
||||
@@ -1563,20 +1607,36 @@ value, one key will be ignored."
|
||||
(or (os/getenv "JANET_PATH")
|
||||
(if (= :windows (os/which)) "" "/usr/local/lib/janet")))
|
||||
|
||||
(defn- fexists [path]
|
||||
(def f (file/open path))
|
||||
(if f (do (file/close f) path)))
|
||||
|
||||
(defn module/find
|
||||
"Try to match a module or path name from the patterns in paths."
|
||||
[path paths]
|
||||
"Try to match a module or path name from the patterns in module/paths.
|
||||
Returns a tuple (fullpath kind) where the kind is one of :source, :native,
|
||||
or image if the module is found, otherise a tuple with nil followed by
|
||||
an error message."
|
||||
[path]
|
||||
(def parts (string/split "/" path))
|
||||
(def name (get parts (- (length parts) 1)))
|
||||
(def nati (if (= :windows (os/which)) "dll" "so"))
|
||||
(defn sub-path
|
||||
[p]
|
||||
(->> p
|
||||
(string/replace ":name:" name)
|
||||
(string/replace ":sys:" module/*syspath*)
|
||||
(string/replace ":native:" nati)
|
||||
(string/replace ":all:" path)))
|
||||
(array/push (map sub-path paths) path))
|
||||
(defn make-full
|
||||
[[p mod-kind]]
|
||||
(def fullpath (->> p
|
||||
(string/replace ":name:" name)
|
||||
(string/replace ":sys:" module/*syspath*)
|
||||
(string/replace ":native:" nati)
|
||||
(string/replace ":all:" path)))
|
||||
[fullpath mod-kind])
|
||||
(defn check-path [x] (if (fexists (x 0)) x))
|
||||
(def paths (map make-full module/paths))
|
||||
(def res (find check-path paths))
|
||||
(if res res [nil (string "could not find module "
|
||||
path
|
||||
":\n "
|
||||
;(interpose "\n " (map 0 paths)))]))
|
||||
|
||||
(put _env 'fexists nil)
|
||||
|
||||
(def module/cache
|
||||
"Table mapping loaded module identifiers to their environments."
|
||||
@@ -1587,63 +1647,39 @@ value, one key will be ignored."
|
||||
circular dependencies."
|
||||
@{})
|
||||
|
||||
# Require helpers
|
||||
(defn- check-mod
|
||||
[f testpath]
|
||||
(or f (file/open testpath)))
|
||||
(defn- find-mod [path]
|
||||
(def paths (module/find path module/paths))
|
||||
(reduce check-mod nil paths))
|
||||
(defn- check-native
|
||||
[p testpath]
|
||||
(or p
|
||||
(do
|
||||
(def f (file/open testpath))
|
||||
(if f (do (file/close f) testpath)))))
|
||||
(defn- find-native [path]
|
||||
(def paths (module/find path module/native-paths))
|
||||
(reduce check-native nil paths))
|
||||
|
||||
(defn require
|
||||
"Require a module with the given name. Will search all of the paths in
|
||||
module/paths, then the path as a raw file path. Returns the new environment
|
||||
returned from compiling and running the file."
|
||||
[path & args]
|
||||
(when (get module/loading path)
|
||||
(error (string "circular dependency: module " path " is loading")))
|
||||
(def {:exit exit-on-error} (table ;args))
|
||||
(if-let [check (get module/cache path)]
|
||||
check
|
||||
(if-let [f (find-mod path)]
|
||||
(do
|
||||
# Normal janet module
|
||||
(def newenv (make-env))
|
||||
(put module/loading path true)
|
||||
(defn chunks [buf _] (file/read f 2048 buf))
|
||||
(run-context newenv chunks
|
||||
(fn [sig x f source]
|
||||
(when (not= sig :dead)
|
||||
(status-pp sig x f source)
|
||||
(if exit-on-error (os/exit 1))))
|
||||
path)
|
||||
(file/close f)
|
||||
(put module/loading path false)
|
||||
(put module/cache path newenv)
|
||||
newenv)
|
||||
(do
|
||||
# Try native module
|
||||
(def n (find-native path))
|
||||
(if (not n)
|
||||
(error (string "could not open file for module " path)))
|
||||
(def e (make-env))
|
||||
(native n e)
|
||||
(put module/cache path e)
|
||||
e))))
|
||||
|
||||
(put _env 'find-native nil)
|
||||
(put _env 'check-native nil)
|
||||
(put _env 'find-mod nil)
|
||||
(put _env 'check-mod nil)
|
||||
(do
|
||||
(def [fullpath mod-kind] (module/find path))
|
||||
(unless fullpath (error mod-kind))
|
||||
(def env (case mod-kind
|
||||
:source (do
|
||||
# Normal janet module
|
||||
(def f (file/open fullpath))
|
||||
(def newenv (make-env))
|
||||
(put module/loading fullpath true)
|
||||
(defn chunks [buf _] (file/read f 2048 buf))
|
||||
(run-context {:env newenv
|
||||
:chunks chunks
|
||||
:on-status (fn [f x]
|
||||
(when (not= (fiber/status f) :dead)
|
||||
(debug/stacktrace f x)
|
||||
(if exit-on-error (os/exit 1))))
|
||||
:source fullpath})
|
||||
(file/close f)
|
||||
(put module/loading fullpath nil)
|
||||
(table/setproto newenv nil))
|
||||
:native (native fullpath (make-env))
|
||||
:image (load-image (slurp fullpath))))
|
||||
(put module/cache fullpath env)
|
||||
(put module/cache path env)
|
||||
env)))
|
||||
|
||||
(defn import*
|
||||
"Import a module into a given environment table. This is the
|
||||
@@ -1678,14 +1714,16 @@ value, one key will be ignored."
|
||||
caught."
|
||||
[chunks onsignal &]
|
||||
(def newenv (make-env))
|
||||
(default chunks (fn [buf _] (file/read stdin :line buf)))
|
||||
(default onsignal (fn [sig x f source]
|
||||
(case sig
|
||||
(default onsignal (fn [f x]
|
||||
(case (fiber/status f)
|
||||
:dead (do
|
||||
(put newenv '_ @{:value x})
|
||||
(print (string/pretty x 20)))
|
||||
(status-pp sig x f source))))
|
||||
(run-context newenv chunks onsignal "repl"))
|
||||
(print (buffer/format @"" "%.20p" x)))
|
||||
(debug/stacktrace f x))))
|
||||
(run-context {:env newenv
|
||||
:chunks chunks
|
||||
:on-status onsignal
|
||||
:source "repl"}))
|
||||
|
||||
(defmacro meta
|
||||
"Add metadata to the current environment."
|
||||
@@ -1707,26 +1745,5 @@ value, one key will be ignored."
|
||||
(put symbol-set k true))
|
||||
(sort (keys symbol-set)))
|
||||
|
||||
(defn slurp
|
||||
"Read all data from a file with name path
|
||||
and then close the file."
|
||||
[path]
|
||||
(def f (file/open path :r))
|
||||
(if-not f (error (string "could not open file " path)))
|
||||
(def contents (file/read f :all))
|
||||
(file/close f)
|
||||
contents)
|
||||
|
||||
(defn spit
|
||||
"Write contents to a file at path.
|
||||
Can optionally append to the file."
|
||||
[path contents mode &]
|
||||
(default mode :w)
|
||||
(def f (file/open path mode))
|
||||
(if-not f (error (string "could not open file " path " with mode " mode)))
|
||||
(file/write f contents)
|
||||
(file/close f)
|
||||
nil)
|
||||
|
||||
# Use dynamic *env* from now on
|
||||
(put _env '_env nil)
|
||||
|
||||
@@ -28,8 +28,13 @@
|
||||
#endif
|
||||
|
||||
/* Generated bytes */
|
||||
#ifdef JANET_BOOTSTRAP
|
||||
extern const unsigned char *janet_gen_core;
|
||||
extern int32_t janet_gen_core_size;
|
||||
#else
|
||||
extern const unsigned char *janet_core_image;
|
||||
extern size_t janet_core_image_size;
|
||||
#endif
|
||||
|
||||
/* Use LoadLibrary on windows or dlopen on posix to load dynamic libaries
|
||||
* with native code. */
|
||||
@@ -371,7 +376,7 @@ static const JanetReg corelib_cfuns[] = {
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
#ifndef JANET_NO_BOOTSTRAP
|
||||
#ifdef JANET_BOOTSTRAP
|
||||
|
||||
/* Utility for inline assembly */
|
||||
static void janet_quick_asm(
|
||||
@@ -595,12 +600,9 @@ static const uint32_t bnot_asm[] = {
|
||||
|
||||
JanetTable *janet_core_env(void) {
|
||||
JanetTable *env = janet_table(0);
|
||||
Janet ret = janet_wrap_table(env);
|
||||
janet_core_cfuns(env, NULL, corelib_cfuns);
|
||||
|
||||
/* Load main functions */
|
||||
janet_cfuns(env, NULL, corelib_cfuns);
|
||||
|
||||
#ifndef JANET_NO_BOOTSTRAP
|
||||
#ifdef JANET_BOOTSTRAP
|
||||
janet_quick_asm(env, JANET_FUN_YIELD, "debug", 0, 1, debug_asm, sizeof(debug_asm),
|
||||
JDOC("(debug)\n\n"
|
||||
"Throws a debug signal that can be caught by a parent fiber and used to inspect "
|
||||
@@ -731,11 +733,11 @@ JanetTable *janet_core_env(void) {
|
||||
JDOC("The build identifier of the running janet program."));
|
||||
|
||||
/* Allow references to the environment */
|
||||
janet_def(env, "_env", ret, JDOC("The environment table for the current scope."));
|
||||
#endif
|
||||
janet_def(env, "_env", janet_wrap_table(env), JDOC("The environment table for the current scope."));
|
||||
|
||||
/* Set as gc root */
|
||||
janet_gcroot(janet_wrap_table(env));
|
||||
#endif
|
||||
|
||||
/* Load auxiliary envs */
|
||||
janet_lib_io(env);
|
||||
@@ -756,9 +758,26 @@ JanetTable *janet_core_env(void) {
|
||||
janet_lib_asm(env);
|
||||
#endif
|
||||
|
||||
#ifndef JANET_NO_BOOTSTRAP
|
||||
#ifdef JANET_BOOTSTRAP
|
||||
/* Run bootstrap source */
|
||||
janet_dobytes(env, janet_gen_core, janet_gen_core_size, "core.janet", NULL);
|
||||
#else
|
||||
|
||||
/* Unmarshal from core image */
|
||||
Janet marsh_out;
|
||||
int status = janet_unmarshal(
|
||||
janet_core_image,
|
||||
janet_core_image_size,
|
||||
0,
|
||||
&marsh_out,
|
||||
env,
|
||||
NULL);
|
||||
if (status) {
|
||||
printf("error unmarshaling core image\n");
|
||||
exit(1);
|
||||
}
|
||||
janet_gcroot(marsh_out);
|
||||
env = janet_unwrap_table(marsh_out);
|
||||
#endif
|
||||
|
||||
return env;
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "gc.h"
|
||||
#include "state.h"
|
||||
#include "util.h"
|
||||
#include "vector.h"
|
||||
#endif
|
||||
|
||||
/* Implements functionality to build a debugger from within janet.
|
||||
@@ -90,6 +91,74 @@ void janet_debug_find(
|
||||
}
|
||||
}
|
||||
|
||||
/* Error reporting. This can be emulated from within Janet, but for
|
||||
* consitency with the top level code it is defined once. */
|
||||
void janet_stacktrace(JanetFiber *fiber, Janet err) {
|
||||
int32_t fi;
|
||||
const char *errstr = (const char *)janet_to_string(err);
|
||||
JanetFiber **fibers = NULL;
|
||||
int wrote_error = 0;
|
||||
|
||||
while (fiber) {
|
||||
janet_v_push(fibers, fiber);
|
||||
fiber = fiber->child;
|
||||
}
|
||||
|
||||
for (fi = janet_v_count(fibers) - 1; fi >= 0; fi--) {
|
||||
fiber = fibers[fi];
|
||||
int32_t i = fiber->frame;
|
||||
while (i > 0) {
|
||||
JanetStackFrame *frame = (JanetStackFrame *)(fiber->data + i - JANET_FRAME_SIZE);
|
||||
JanetFuncDef *def = NULL;
|
||||
i = frame->prevframe;
|
||||
|
||||
/* Print prelude to stack frame */
|
||||
if (!wrote_error) {
|
||||
JanetFiberStatus status = janet_fiber_status(fiber);
|
||||
const char *prefix = status == JANET_STATUS_ERROR ? "" : "status ";
|
||||
fprintf(stderr, "%s%s: %s\n",
|
||||
prefix,
|
||||
janet_status_names[status],
|
||||
errstr);
|
||||
wrote_error = 1;
|
||||
}
|
||||
|
||||
fprintf(stderr, " in");
|
||||
|
||||
if (frame->func) {
|
||||
def = frame->func->def;
|
||||
fprintf(stderr, " %s", def->name ? (const char *)def->name : "<anonymous>");
|
||||
if (def->source) {
|
||||
fprintf(stderr, " [%s]", (const char *)def->source);
|
||||
}
|
||||
} else {
|
||||
JanetCFunction cfun = (JanetCFunction)(frame->pc);
|
||||
if (cfun) {
|
||||
Janet name = janet_table_get(janet_vm_registry, janet_wrap_cfunction(cfun));
|
||||
if (!janet_checktype(name, JANET_NIL))
|
||||
fprintf(stderr, " %s", (const char *)janet_to_string(name));
|
||||
else
|
||||
fprintf(stderr, " <cfunction>");
|
||||
}
|
||||
}
|
||||
if (frame->flags & JANET_STACKFRAME_TAILCALL)
|
||||
fprintf(stderr, " (tailcall)");
|
||||
if (frame->func && frame->pc) {
|
||||
int32_t off = (int32_t) (frame->pc - def->bytecode);
|
||||
if (def->sourcemap) {
|
||||
JanetSourceMapping mapping = def->sourcemap[off];
|
||||
fprintf(stderr, " at (%d:%d)", mapping.start, mapping.end);
|
||||
} else {
|
||||
fprintf(stderr, " pc=%d", off);
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
janet_v_free(fibers);
|
||||
}
|
||||
|
||||
/*
|
||||
* CFuns
|
||||
*/
|
||||
@@ -218,6 +287,13 @@ static Janet cfun_debug_stack(int32_t argc, Janet *argv) {
|
||||
return janet_wrap_array(array);
|
||||
}
|
||||
|
||||
static Janet cfun_debug_stacktrace(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 2);
|
||||
JanetFiber *fiber = janet_getfiber(argv, 0);
|
||||
janet_stacktrace(fiber, argv[1]);
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
static Janet cfun_debug_argstack(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 1);
|
||||
JanetFiber *fiber = janet_getfiber(argv, 0);
|
||||
@@ -280,6 +356,13 @@ static const JanetReg debug_cfuns[] = {
|
||||
"\t:slots - array of all values in each slot\n"
|
||||
"\t:tail - boolean indicating a tail call")
|
||||
},
|
||||
{
|
||||
"debug/stacktrace", cfun_debug_stacktrace,
|
||||
JDOC("(debug/stacktrace fiber err)\n\n"
|
||||
"Prints a nice looking stacktrace for a fiber. The error message "
|
||||
"err must be passed to the function as fiber's do not keep track of "
|
||||
"the last error they have thrown. Returns the fiber.")
|
||||
},
|
||||
{
|
||||
"debug/lineage", cfun_debug_lineage,
|
||||
JDOC("(debug/lineage fib)\n\n"
|
||||
@@ -293,5 +376,5 @@ static const JanetReg debug_cfuns[] = {
|
||||
|
||||
/* Module entry point */
|
||||
void janet_lib_debug(JanetTable *env) {
|
||||
janet_cfuns(env, NULL, debug_cfuns);
|
||||
janet_core_cfuns(env, NULL, debug_cfuns);
|
||||
}
|
||||
|
||||
@@ -66,6 +66,7 @@ JanetFiber *janet_fiber_reset(JanetFiber *fiber, JanetFunction *callee, int32_t
|
||||
fiber->stacktop = newstacktop;
|
||||
}
|
||||
if (janet_fiber_funcframe(fiber, callee)) return NULL;
|
||||
janet_fiber_frame(fiber)->flags |= JANET_STACKFRAME_ENTRANCE;
|
||||
return fiber;
|
||||
}
|
||||
|
||||
@@ -432,5 +433,5 @@ static const JanetReg fiber_cfuns[] = {
|
||||
|
||||
/* Module entry point */
|
||||
void janet_lib_fiber(JanetTable *env) {
|
||||
janet_cfuns(env, NULL, fiber_cfuns);
|
||||
janet_core_cfuns(env, NULL, fiber_cfuns);
|
||||
}
|
||||
|
||||
@@ -49,10 +49,13 @@ struct IOFile {
|
||||
};
|
||||
|
||||
static int cfun_io_gc(void *p, size_t len);
|
||||
static Janet io_file_get(void *p, Janet);
|
||||
|
||||
JanetAbstractType cfun_io_filetype = {
|
||||
"core/file",
|
||||
cfun_io_gc,
|
||||
NULL,
|
||||
io_file_get,
|
||||
NULL
|
||||
};
|
||||
|
||||
@@ -192,6 +195,9 @@ static Janet cfun_io_fread(int32_t argc, Janet *argv) {
|
||||
} else {
|
||||
fseek(iof->file, 0, SEEK_END);
|
||||
long fsize = ftell(iof->file);
|
||||
if (fsize < 0) {
|
||||
janet_panicf("could not get file size of %v", argv[0]);
|
||||
}
|
||||
fseek(iof->file, 0, SEEK_SET);
|
||||
read_chunk(iof, buffer, (int32_t) fsize);
|
||||
}
|
||||
@@ -305,6 +311,22 @@ static Janet cfun_io_fseek(int32_t argc, Janet *argv) {
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
static JanetMethod io_file_methods[] = {
|
||||
{"close", cfun_io_fclose},
|
||||
{"read", cfun_io_fread},
|
||||
{"write", cfun_io_fwrite},
|
||||
{"flush", cfun_io_fflush},
|
||||
{"seek", cfun_io_fseek},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
static Janet io_file_get(void *p, Janet key) {
|
||||
(void) p;
|
||||
if (!janet_checktype(key, JANET_KEYWORD))
|
||||
janet_panicf("expected keyword, got %v", key);
|
||||
return janet_getmethod(janet_unwrap_keyword(key), io_file_methods);
|
||||
}
|
||||
|
||||
static const JanetReg io_cfuns[] = {
|
||||
{
|
||||
"file/open", cfun_io_fopen,
|
||||
@@ -375,18 +397,18 @@ static const JanetReg io_cfuns[] = {
|
||||
|
||||
/* Module entry point */
|
||||
void janet_lib_io(JanetTable *env) {
|
||||
janet_cfuns(env, NULL, io_cfuns);
|
||||
janet_core_cfuns(env, NULL, io_cfuns);
|
||||
|
||||
/* stdout */
|
||||
janet_def(env, "stdout",
|
||||
janet_core_def(env, "stdout",
|
||||
makef(stdout, IO_APPEND | IO_NOT_CLOSEABLE | IO_SERIALIZABLE),
|
||||
JDOC("The standard output file."));
|
||||
/* stderr */
|
||||
janet_def(env, "stderr",
|
||||
janet_core_def(env, "stderr",
|
||||
makef(stderr, IO_APPEND | IO_NOT_CLOSEABLE | IO_SERIALIZABLE),
|
||||
JDOC("The standard error file."));
|
||||
/* stdin */
|
||||
janet_def(env, "stdin",
|
||||
janet_core_def(env, "stdin",
|
||||
makef(stdin, IO_READ | IO_NOT_CLOSEABLE | IO_SERIALIZABLE),
|
||||
JDOC("The standard input file."));
|
||||
}
|
||||
|
||||
@@ -124,15 +124,20 @@ JanetTable *janet_env_lookup(JanetTable *env) {
|
||||
|
||||
/* Marshal an integer onto the buffer */
|
||||
static void pushint(MarshalState *st, int32_t x) {
|
||||
if (x >= 0 && x < 200) {
|
||||
if (x >= 0 && x < 128) {
|
||||
janet_buffer_push_u8(st->buf, x);
|
||||
} else if (x <= 8191 && x >= -8192) {
|
||||
uint8_t intbuf[2];
|
||||
intbuf[0] = ((x >> 8) & 0x3F) | 0x80;
|
||||
intbuf[1] = x & 0xFF;
|
||||
janet_buffer_push_bytes(st->buf, intbuf, 2);
|
||||
} else {
|
||||
uint8_t intbuf[5];
|
||||
intbuf[0] = LB_INTEGER;
|
||||
intbuf[1] = x & 0xFF;
|
||||
intbuf[2] = (x >> 8) & 0xFF;
|
||||
intbuf[3] = (x >> 16) & 0xFF;
|
||||
intbuf[4] = (x >> 24) & 0xFF;
|
||||
intbuf[1] = (x >> 24) & 0xFF;
|
||||
intbuf[2] = (x >> 16) & 0xFF;
|
||||
intbuf[3] = (x >> 8) & 0xFF;
|
||||
intbuf[4] = x & 0xFF;
|
||||
janet_buffer_push_bytes(st->buf, intbuf, 5);
|
||||
}
|
||||
}
|
||||
@@ -226,7 +231,7 @@ static void marshal_one_def(MarshalState *st, JanetFuncDef *def, int flags) {
|
||||
|
||||
/* marshal the environments if needed */
|
||||
for (int32_t i = 0; i < def->environments_length; i++)
|
||||
pushint(st, def->environments[i]);
|
||||
pushint(st, def->environments[i]);
|
||||
|
||||
/* marshal the sub funcdefs if needed */
|
||||
for (int32_t i = 0; i < def->defs_length; i++)
|
||||
@@ -234,10 +239,12 @@ static void marshal_one_def(MarshalState *st, JanetFuncDef *def, int flags) {
|
||||
|
||||
/* marshal source maps if needed */
|
||||
if (def->flags & JANET_FUNCDEF_FLAG_HASSOURCEMAP) {
|
||||
int32_t current = 0;
|
||||
for (int32_t i = 0; i < def->bytecode_length; i++) {
|
||||
JanetSourceMapping map = def->sourcemap[i];
|
||||
pushint(st, map.start);
|
||||
pushint(st, map.end);
|
||||
pushint(st, map.start - current);
|
||||
pushint(st, map.end - map.start);
|
||||
current = map.end;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -395,11 +402,13 @@ static void marshal_one(MarshalState *st, Janet x, int flags) {
|
||||
goto done;
|
||||
case JANET_TUPLE:
|
||||
{
|
||||
int32_t i, count;
|
||||
int32_t i, count, flag;
|
||||
const Janet *tup = janet_unwrap_tuple(x);
|
||||
count = janet_tuple_length(tup);
|
||||
flag = janet_tuple_flag(tup);
|
||||
pushbyte(st, LB_TUPLE);
|
||||
pushint(st, count);
|
||||
pushint(st, flag);
|
||||
for (i = 0; i < count; i++)
|
||||
marshal_one(st, tup[i], flags + 1);
|
||||
/* Mark as seen AFTER marshaling */
|
||||
@@ -546,14 +555,19 @@ static int32_t readint(UnmarshalState *st, const uint8_t **atdata) {
|
||||
const uint8_t *data = *atdata;
|
||||
int32_t ret;
|
||||
if (data >= st->end) longjmp(st->err, UMR_EOS);
|
||||
if (*data < 200) {
|
||||
if (*data < 128) {
|
||||
ret = *data++;
|
||||
} else if (*data < 192) {
|
||||
if (data + 2 > st->end) longjmp(st->err, UMR_EOS);
|
||||
ret = ((data[0] & 0x3F) << 8) + data[1];
|
||||
ret = ((ret << 18) >> 18);
|
||||
data += 2;
|
||||
} else if (*data == LB_INTEGER) {
|
||||
if (data + 5 > st->end) longjmp(st->err, UMR_EOS);
|
||||
ret = (data[1]) |
|
||||
(data[2] << 8) |
|
||||
(data[3] << 16) |
|
||||
(data[4] << 24);
|
||||
ret = ((int32_t)(data[1]) << 24) |
|
||||
((int32_t)(data[2]) << 16) |
|
||||
((int32_t)(data[3]) << 8) |
|
||||
(int32_t)(data[4]);
|
||||
data += 5;
|
||||
} else {
|
||||
longjmp(st->err, UMR_EXPECTED_INTEGER);
|
||||
@@ -748,13 +762,16 @@ static const uint8_t *unmarshal_one_def(
|
||||
|
||||
/* Unmarshal source maps if needed */
|
||||
if (def->flags & JANET_FUNCDEF_FLAG_HASSOURCEMAP) {
|
||||
int32_t current = 0;
|
||||
def->sourcemap = malloc(sizeof(JanetSourceMapping) * bytecode_length);
|
||||
if (!def->sourcemap) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
for (int32_t i = 0; i < bytecode_length; i++) {
|
||||
def->sourcemap[i].start = readint(st, &data);
|
||||
def->sourcemap[i].end = readint(st, &data);
|
||||
current += readint(st, &data);
|
||||
def->sourcemap[i].start = current;
|
||||
current += readint(st, &data);
|
||||
def->sourcemap[i].end = current;
|
||||
}
|
||||
} else {
|
||||
def->sourcemap = NULL;
|
||||
@@ -905,8 +922,8 @@ static const uint8_t *unmarshal_one(
|
||||
EXTRA(1);
|
||||
lead = data[0];
|
||||
if (lead < 200) {
|
||||
*out = janet_wrap_integer(lead);
|
||||
return data + 1;
|
||||
*out = janet_wrap_integer(readint(st, &data));
|
||||
return data;
|
||||
}
|
||||
switch (lead) {
|
||||
case LB_NIL:
|
||||
@@ -922,10 +939,10 @@ static const uint8_t *unmarshal_one(
|
||||
/* Long integer */
|
||||
EXTRA(5);
|
||||
*out = janet_wrap_integer(
|
||||
(data[1]) |
|
||||
(data[2] << 8) |
|
||||
(data[3] << 16) |
|
||||
(data[4] << 24));
|
||||
(data[4]) |
|
||||
(data[3] << 8) |
|
||||
(data[2] << 16) |
|
||||
(data[1] << 24));
|
||||
return data + 5;
|
||||
case LB_REAL:
|
||||
/* Real */
|
||||
@@ -998,7 +1015,7 @@ static const uint8_t *unmarshal_one(
|
||||
JanetFuncDef *def;
|
||||
data = unmarshal_one_def(st, data + 1, &def, flags + 1);
|
||||
func = janet_gcalloc(JANET_MEMORY_FUNCTION, sizeof(JanetFunction) +
|
||||
def->environments_length * sizeof(JanetFuncEnv));
|
||||
def->environments_length * sizeof(JanetFuncEnv));
|
||||
func->def = def;
|
||||
*out = janet_wrap_function(func);
|
||||
janet_array_push(&st->lookup, *out);
|
||||
@@ -1029,6 +1046,8 @@ static const uint8_t *unmarshal_one(
|
||||
} else if (lead == LB_TUPLE) {
|
||||
/* Tuple */
|
||||
Janet *tup = janet_tuple_begin(len);
|
||||
int32_t flag = readint(st, &data);
|
||||
janet_tuple_flag(tup) = flag;
|
||||
for (int32_t i = 0; i < len; i++) {
|
||||
data = unmarshal_one(st, data, tup + i, flags + 1);
|
||||
}
|
||||
@@ -1175,5 +1194,5 @@ static const JanetReg marsh_cfuns[] = {
|
||||
|
||||
/* Module entry point */
|
||||
void janet_lib_marsh(JanetTable *env) {
|
||||
janet_cfuns(env, NULL, marsh_cfuns);
|
||||
janet_core_cfuns(env, NULL, marsh_cfuns);
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#endif
|
||||
|
||||
/* Get a random number */
|
||||
Janet janet_rand(int32_t argc, Janet *argv) {
|
||||
static Janet janet_rand(int32_t argc, Janet *argv) {
|
||||
(void) argv;
|
||||
janet_fixarity(argc, 0);
|
||||
double r = (rand() % RAND_MAX) / ((double) RAND_MAX);
|
||||
@@ -36,14 +36,14 @@ Janet janet_rand(int32_t argc, Janet *argv) {
|
||||
}
|
||||
|
||||
/* Seed the random number generator */
|
||||
Janet janet_srand(int32_t argc, Janet *argv) {
|
||||
static Janet janet_srand(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 1);
|
||||
int32_t x = janet_getinteger(argv, 0);
|
||||
srand((unsigned) x);
|
||||
return janet_wrap_nil();
|
||||
}
|
||||
|
||||
Janet janet_remainder(int32_t argc, Janet *argv) {
|
||||
static Janet janet_remainder(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 2);
|
||||
double x = janet_getnumber(argv, 0);
|
||||
double y = janet_getnumber(argv, 1);
|
||||
@@ -51,7 +51,7 @@ Janet janet_remainder(int32_t argc, Janet *argv) {
|
||||
}
|
||||
|
||||
#define JANET_DEFINE_MATHOP(name, fop)\
|
||||
Janet janet_##name(int32_t argc, Janet *argv) {\
|
||||
static Janet janet_##name(int32_t argc, Janet *argv) {\
|
||||
janet_fixarity(argc, 1); \
|
||||
double x = janet_getnumber(argv, 0); \
|
||||
return janet_wrap_number(fop(x)); \
|
||||
@@ -75,7 +75,7 @@ JANET_DEFINE_MATHOP(fabs, fabs)
|
||||
JANET_DEFINE_MATHOP(floor, floor)
|
||||
|
||||
#define JANET_DEFINE_MATH2OP(name, fop)\
|
||||
Janet janet_##name(int32_t argc, Janet *argv) {\
|
||||
static Janet janet_##name(int32_t argc, Janet *argv) {\
|
||||
janet_fixarity(argc, 2); \
|
||||
double lhs = janet_getnumber(argv, 0); \
|
||||
double rhs = janet_getnumber(argv, 1); \
|
||||
@@ -176,13 +176,38 @@ static const JanetReg math_cfuns[] = {
|
||||
JDOC("(math/pow a x)\n\n"
|
||||
"Return a to the power of x.")
|
||||
},
|
||||
{
|
||||
"math/abs", janet_fabs,
|
||||
JDOC("(math/abs x)\n\n"
|
||||
"Return the absolute value of x.")
|
||||
},
|
||||
{
|
||||
"math/sinh", janet_sinh,
|
||||
JDOC("(math/sinh x)\n\n"
|
||||
"Return the hyperbolic sine of x.")
|
||||
},
|
||||
{
|
||||
"math/cosh", janet_cosh,
|
||||
JDOC("(math/cosh x)\n\n"
|
||||
"Return the hyperbolic cosine of x.")
|
||||
},
|
||||
{
|
||||
"math/tanh", janet_tanh,
|
||||
JDOC("(math/tanh x)\n\n"
|
||||
"Return the hyperbolic tangent of x.")
|
||||
},
|
||||
{
|
||||
"math/atan2", janet_atan2,
|
||||
JDOC("(math/atan2 y x)\n\n"
|
||||
"Return the arctangent of y/x. Works even when x is 0.")
|
||||
},
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
/* Module entry point */
|
||||
void janet_lib_math(JanetTable *env) {
|
||||
janet_cfuns(env, NULL, math_cfuns);
|
||||
#ifndef JANET_NO_BOOTSTRAP
|
||||
janet_core_cfuns(env, NULL, math_cfuns);
|
||||
#ifdef JANET_BOOTSTRAP
|
||||
janet_def(env, "math/pi", janet_wrap_number(3.1415926535897931),
|
||||
JDOC("The value pi."));
|
||||
janet_def(env, "math/e", janet_wrap_number(2.7182818284590451),
|
||||
|
||||
@@ -378,5 +378,5 @@ static const JanetReg os_cfuns[] = {
|
||||
|
||||
/* Module entry point */
|
||||
void janet_lib_os(JanetTable *env) {
|
||||
janet_cfuns(env, NULL, os_cfuns);
|
||||
janet_core_cfuns(env, NULL, os_cfuns);
|
||||
}
|
||||
|
||||
@@ -335,8 +335,9 @@ static int comment(JanetParser *p, JanetParseState *state, uint8_t c) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static Janet close_tuple(JanetParser *p, JanetParseState *state) {
|
||||
static Janet close_tuple(JanetParser *p, JanetParseState *state, int32_t flag) {
|
||||
Janet *ret = janet_tuple_begin(state->argn);
|
||||
janet_tuple_flag(ret) = flag;
|
||||
for (int32_t i = state->argn - 1; i >= 0; i--)
|
||||
ret[i] = p->args[--p->argcount];
|
||||
return janet_wrap_tuple(janet_tuple_end(ret));
|
||||
@@ -486,7 +487,7 @@ static int root(JanetParser *p, JanetParseState *state, uint8_t c) {
|
||||
if (state->flags & PFLAG_ATSYM) {
|
||||
ds = close_array(p, state);
|
||||
} else {
|
||||
ds = close_tuple(p, state);
|
||||
ds = close_tuple(p, state, c == ']' ? JANET_TUPLE_FLAG_BRACKETCTOR : 0);
|
||||
}
|
||||
} else if (c == '}' && (state->flags & PFLAG_CURLYBRACKETS)) {
|
||||
if (state->argn & 1) {
|
||||
@@ -609,10 +610,14 @@ static int parsergc(void *p, size_t size) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Janet parserget(void *p, Janet key);
|
||||
|
||||
static JanetAbstractType janet_parse_parsertype = {
|
||||
"core/parser",
|
||||
parsergc,
|
||||
parsermark
|
||||
parsermark,
|
||||
parserget,
|
||||
NULL
|
||||
};
|
||||
|
||||
/* C Function parser */
|
||||
@@ -649,6 +654,39 @@ static Janet cfun_parse_consume(int32_t argc, Janet *argv) {
|
||||
return janet_wrap_integer(i);
|
||||
}
|
||||
|
||||
static Janet cfun_parse_insert(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 2);
|
||||
JanetParser *p = janet_getabstract(argv, 0, &janet_parse_parsertype);
|
||||
JanetParseState *s = p->states + p->statecount - 1;
|
||||
if (s->consumer == tokenchar) {
|
||||
janet_parser_consume(p, ' ');
|
||||
p->offset--;
|
||||
s = p->states + p->statecount - 1;
|
||||
}
|
||||
if (s->flags & PFLAG_CONTAINER) {
|
||||
s->argn++;
|
||||
if (p->statecount == 1) p->pending++;
|
||||
push_arg(p, argv[1]);
|
||||
} else if (s->flags & (PFLAG_STRING | PFLAG_LONGSTRING)) {
|
||||
const uint8_t *str = janet_to_string(argv[1]);
|
||||
int32_t slen = janet_string_length(str);
|
||||
size_t newcount = p->bufcount + slen;
|
||||
if (p->bufcap > p->bufcount + slen) {
|
||||
size_t newcap = 2 * newcount;
|
||||
p->buf = realloc(p->buf, newcap);
|
||||
if (p->buf == NULL) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
p->bufcap = newcap;
|
||||
}
|
||||
memcpy(p->buf + p->bufcount, str, slen);
|
||||
p->bufcount = newcount;
|
||||
} else {
|
||||
janet_panic("cannot insert value into parser");
|
||||
}
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
static Janet cfun_parse_has_more(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 1);
|
||||
JanetParser *p = janet_getabstract(argv, 0, &janet_parse_parsertype);
|
||||
@@ -737,6 +775,26 @@ static Janet cfun_parse_state(int32_t argc, Janet *argv) {
|
||||
return janet_wrap_string(str);
|
||||
}
|
||||
|
||||
static const JanetMethod parser_methods[] = {
|
||||
{"byte", cfun_parse_byte},
|
||||
{"consume", cfun_parse_consume},
|
||||
{"error", cfun_parse_error},
|
||||
{"flush", cfun_parse_flush},
|
||||
{"has-more", cfun_parse_has_more},
|
||||
{"insert", cfun_parse_insert},
|
||||
{"produce", cfun_parse_produce},
|
||||
{"state", cfun_parse_state},
|
||||
{"status", cfun_parse_status},
|
||||
{"where", cfun_parse_where},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
static Janet parserget(void *p, Janet key) {
|
||||
(void) p;
|
||||
if (!janet_checktype(key, JANET_KEYWORD)) janet_panicf("expected keyword method");
|
||||
return janet_getmethod(janet_unwrap_keyword(key), parser_methods);
|
||||
}
|
||||
|
||||
static const JanetReg parse_cfuns[] = {
|
||||
{
|
||||
"parser/new", cfun_parse_parser,
|
||||
@@ -807,10 +865,17 @@ static const JanetReg parse_cfuns[] = {
|
||||
"in the byte stream as a tuple (line, column). Lines and columns are counted from "
|
||||
"1, (the first byte is line 1, column 1) and a newline is considered ASCII 0x0A.")
|
||||
},
|
||||
{
|
||||
"parser/insert", cfun_parse_insert,
|
||||
JDOC("(parser/insert parser value)\n\n"
|
||||
"Insert a value into the parser. This means that the parser state can be manipulated "
|
||||
"in between chunks of bytes. This would allow a user to add extra elements to arrays "
|
||||
"and tuples, for example. Returns the parser.")
|
||||
},
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
/* Load the library */
|
||||
void janet_lib_parse(JanetTable *env) {
|
||||
janet_cfuns(env, NULL, parse_cfuns);
|
||||
janet_core_cfuns(env, NULL, parse_cfuns);
|
||||
}
|
||||
|
||||
@@ -990,7 +990,6 @@ static uint32_t compile1(Builder *b, Janet peg) {
|
||||
typedef struct {
|
||||
uint32_t *bytecode;
|
||||
Janet *constants;
|
||||
uint32_t main_rule;
|
||||
uint32_t num_constants;
|
||||
} Peg;
|
||||
|
||||
@@ -1005,11 +1004,13 @@ static int peg_mark(void *p, size_t size) {
|
||||
static JanetAbstractType peg_type = {
|
||||
"core/peg",
|
||||
NULL,
|
||||
peg_mark
|
||||
peg_mark,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
/* Convert Builder to Peg (Janet Abstract Value) */
|
||||
static Peg *make_peg(Builder *b, uint32_t main_rule) {
|
||||
static Peg *make_peg(Builder *b) {
|
||||
size_t bytecode_size = janet_v_count(b->bytecode) * sizeof(uint32_t);
|
||||
size_t constants_size = janet_v_count(b->constants) * sizeof(Janet);
|
||||
size_t total_size = bytecode_size + constants_size + sizeof(Peg);
|
||||
@@ -1018,7 +1019,6 @@ static Peg *make_peg(Builder *b, uint32_t main_rule) {
|
||||
peg->bytecode = (uint32_t *)(mem + sizeof(Peg));
|
||||
peg->constants = (Janet *)(mem + sizeof(Peg) + bytecode_size);
|
||||
peg->num_constants = janet_v_count(b->constants);
|
||||
peg->main_rule = main_rule;
|
||||
memcpy(peg->bytecode, b->bytecode, bytecode_size);
|
||||
memcpy(peg->constants, b->constants, constants_size);
|
||||
return peg;
|
||||
@@ -1035,8 +1035,8 @@ static Peg *compile_peg(Janet x) {
|
||||
builder.nexttag = 1;
|
||||
builder.form = x;
|
||||
builder.depth = JANET_RECURSION_GUARD;
|
||||
uint32_t main_rule = compile1(&builder, x);
|
||||
Peg *peg = make_peg(&builder, main_rule);
|
||||
compile1(&builder, x);
|
||||
Peg *peg = make_peg(&builder);
|
||||
builder_cleanup(&builder);
|
||||
return peg;
|
||||
}
|
||||
@@ -1082,7 +1082,7 @@ static Janet cfun_peg_match(int32_t argc, Janet *argv) {
|
||||
|
||||
s.constants = peg->constants;
|
||||
s.bytecode = peg->bytecode;
|
||||
const uint8_t *result = peg_rule(&s, s.bytecode + peg->main_rule, bytes.bytes + start);
|
||||
const uint8_t *result = peg_rule(&s, s.bytecode, bytes.bytes + start);
|
||||
return result ? janet_wrap_array(s.captures) : janet_wrap_nil();
|
||||
}
|
||||
|
||||
@@ -1103,5 +1103,5 @@ static const JanetReg peg_cfuns[] = {
|
||||
|
||||
/* Load the peg module */
|
||||
void janet_lib_peg(JanetTable *env) {
|
||||
janet_cfuns(env, NULL, peg_cfuns);
|
||||
janet_core_cfuns(env, NULL, peg_cfuns);
|
||||
}
|
||||
|
||||
159
src/core/pp.c
159
src/core/pp.c
@@ -20,6 +20,9 @@
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#ifndef JANET_AMALG
|
||||
#include <janet/janet.h>
|
||||
#include "util.h"
|
||||
@@ -332,16 +335,19 @@ static void janet_pretty_one(struct pretty *S, Janet x, int is_dict_value) {
|
||||
case JANET_ARRAY:
|
||||
case JANET_TUPLE:
|
||||
{
|
||||
int32_t i, len;
|
||||
const Janet *arr;
|
||||
int isarray = janet_checktype(x, JANET_ARRAY);
|
||||
janet_buffer_push_cstring(S->buffer, isarray ? "@[" : "(");
|
||||
janet_indexed_view(x, &arr, &len);
|
||||
int hasbrackets = !isarray && (janet_tuple_flag(arr) & JANET_TUPLE_FLAG_BRACKETCTOR);
|
||||
const char *startstr = isarray ? "@[" : hasbrackets ? "[" : "(";
|
||||
const char endchar = isarray ? ']' : hasbrackets ? ']' : ')';
|
||||
janet_buffer_push_cstring(S->buffer, startstr);
|
||||
S->depth--;
|
||||
S->indent += 2;
|
||||
if (S->depth == 0) {
|
||||
janet_buffer_push_cstring(S->buffer, "...");
|
||||
} else {
|
||||
int32_t i, len;
|
||||
const Janet *arr;
|
||||
janet_indexed_view(x, &arr, &len);
|
||||
if (!isarray && len >= 5)
|
||||
janet_buffer_push_u8(S->buffer, ' ');
|
||||
if (is_dict_value && len >= 5) print_newline(S, 0);
|
||||
@@ -352,7 +358,7 @@ static void janet_pretty_one(struct pretty *S, Janet x, int is_dict_value) {
|
||||
}
|
||||
S->indent -= 2;
|
||||
S->depth++;
|
||||
janet_buffer_push_u8(S->buffer, isarray ? ']' : ')');
|
||||
janet_buffer_push_u8(S->buffer, endchar);
|
||||
break;
|
||||
}
|
||||
case JANET_STRUCT:
|
||||
@@ -546,3 +552,146 @@ const uint8_t *janet_formatc(const char *format, ...) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* code adapted from lua/lstrlib.c http://lua.org
|
||||
*/
|
||||
|
||||
#define MAX_ITEM 256
|
||||
#define FMT_FLAGS "-+ #0"
|
||||
#define MAX_FORMAT 32
|
||||
|
||||
static const char *scanformat(
|
||||
const char *strfrmt,
|
||||
char *form,
|
||||
char width[3],
|
||||
char precision[3]) {
|
||||
const char *p = strfrmt;
|
||||
memset(width, '\0', 3);
|
||||
memset(precision, '\0', 3);
|
||||
while (*p != '\0' && strchr(FMT_FLAGS, *p) != NULL)
|
||||
p++; /* skip flags */
|
||||
if ((size_t) (p - strfrmt) >= sizeof(FMT_FLAGS) / sizeof(char))
|
||||
janet_panic("invalid format (repeated flags)");
|
||||
if (isdigit((int) (*p)))
|
||||
width[0] = *p++; /* skip width */
|
||||
if (isdigit((int) (*p)))
|
||||
width[1] = *p++; /* (2 digits at most) */
|
||||
if (*p == '.') {
|
||||
p++;
|
||||
if (isdigit((int) (*p)))
|
||||
precision[0] = *p++; /* skip precision */
|
||||
if (isdigit((int) (*p)))
|
||||
precision[1] = *p++; /* (2 digits at most) */
|
||||
}
|
||||
if (isdigit((int) (*p)))
|
||||
janet_panic("invalid format (width or precision too long)");
|
||||
*(form++) = '%';
|
||||
memcpy(form, strfrmt, ((p - strfrmt) + 1) * sizeof(char));
|
||||
form += (p - strfrmt) + 1;
|
||||
*form = '\0';
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Shared implementation between string/format and
|
||||
* buffer/format */
|
||||
void janet_buffer_format(
|
||||
JanetBuffer *b,
|
||||
const char *strfrmt,
|
||||
int32_t argstart,
|
||||
int32_t argc,
|
||||
Janet *argv) {
|
||||
size_t sfl = strlen(strfrmt);
|
||||
const char *strfrmt_end = strfrmt + sfl;
|
||||
int32_t arg = argstart;
|
||||
while (strfrmt < strfrmt_end) {
|
||||
if (*strfrmt != '%')
|
||||
janet_buffer_push_u8(b, (uint8_t) * strfrmt++);
|
||||
else if (*++strfrmt == '%')
|
||||
janet_buffer_push_u8(b, (uint8_t) * strfrmt++); /* %% */
|
||||
else { /* format item */
|
||||
char form[MAX_FORMAT], item[MAX_ITEM];
|
||||
char width[3], precision[3];
|
||||
int nb = 0; /* number of bytes in added item */
|
||||
if (++arg >= argc)
|
||||
janet_panic("not enough values for format");
|
||||
strfrmt = scanformat(strfrmt, form, width, precision);
|
||||
switch (*strfrmt++) {
|
||||
case 'c':
|
||||
{
|
||||
nb = snprintf(item, MAX_ITEM, form, (int)
|
||||
janet_getinteger(argv, arg));
|
||||
break;
|
||||
}
|
||||
case 'd':
|
||||
case 'i':
|
||||
case 'o':
|
||||
case 'u':
|
||||
case 'x':
|
||||
case 'X':
|
||||
{
|
||||
int32_t n = janet_getinteger(argv, arg);
|
||||
nb = snprintf(item, MAX_ITEM, form, n);
|
||||
break;
|
||||
}
|
||||
case 'a':
|
||||
case 'A':
|
||||
case 'e':
|
||||
case 'E':
|
||||
case 'f':
|
||||
case 'g':
|
||||
case 'G':
|
||||
{
|
||||
double d = janet_getnumber(argv, arg);
|
||||
nb = snprintf(item, MAX_ITEM, form, d);
|
||||
break;
|
||||
}
|
||||
case 's':
|
||||
{
|
||||
const uint8_t *s = janet_getstring(argv, arg);
|
||||
size_t l = janet_string_length(s);
|
||||
if (form[2] == '\0')
|
||||
janet_buffer_push_bytes(b, s, l);
|
||||
else {
|
||||
if (l != strlen((const char *) s))
|
||||
janet_panic("string contains zeros");
|
||||
if (!strchr(form, '.') && l >= 100) {
|
||||
janet_panic
|
||||
("no precision and string is too long to be formatted");
|
||||
} else {
|
||||
nb = snprintf(item, MAX_ITEM, form, s);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'V':
|
||||
{
|
||||
janet_to_string_b(b, argv[arg]);
|
||||
break;
|
||||
}
|
||||
case 'v':
|
||||
{
|
||||
janet_description_b(b, argv[arg]);
|
||||
break;
|
||||
}
|
||||
case 'p': /* janet pretty , precision = depth */
|
||||
{
|
||||
int depth = atoi(precision);
|
||||
if (depth < 1)
|
||||
depth = 4;
|
||||
janet_pretty(b, depth, argv[arg]);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{ /* also treat cases 'nLlh' */
|
||||
janet_panicf("invalid conversion '%s' to 'format'",
|
||||
form);
|
||||
}
|
||||
}
|
||||
if (nb >= MAX_ITEM)
|
||||
janet_panicf("format buffer overflow", form);
|
||||
if (nb > 0)
|
||||
janet_buffer_push_bytes(b, (uint8_t *) item, nb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,63 +23,8 @@
|
||||
#ifndef JANET_AMALG
|
||||
#include <janet/janet.h>
|
||||
#include "state.h"
|
||||
#include "vector.h"
|
||||
#endif
|
||||
|
||||
/* Error reporting */
|
||||
void janet_stacktrace(JanetFiber *fiber, const char *errtype, Janet err) {
|
||||
int32_t fi;
|
||||
const char *errstr = (const char *)janet_to_string(err);
|
||||
JanetFiber **fibers = NULL;
|
||||
fprintf(stderr, "%s error: %s\n", errtype, errstr);
|
||||
|
||||
while (fiber) {
|
||||
janet_v_push(fibers, fiber);
|
||||
fiber = fiber->child;
|
||||
}
|
||||
|
||||
for (fi = janet_v_count(fibers) - 1; fi >= 0; fi--) {
|
||||
fiber = fibers[fi];
|
||||
int32_t i = fiber->frame;
|
||||
while (i > 0) {
|
||||
JanetStackFrame *frame = (JanetStackFrame *)(fiber->data + i - JANET_FRAME_SIZE);
|
||||
JanetFuncDef *def = NULL;
|
||||
i = frame->prevframe;
|
||||
fprintf(stderr, " in");
|
||||
if (frame->func) {
|
||||
def = frame->func->def;
|
||||
fprintf(stderr, " %s", def->name ? (const char *)def->name : "<anonymous>");
|
||||
if (def->source) {
|
||||
fprintf(stderr, " [%s]", (const char *)def->source);
|
||||
}
|
||||
} else {
|
||||
JanetCFunction cfun = (JanetCFunction)(frame->pc);
|
||||
if (cfun) {
|
||||
Janet name = janet_table_get(janet_vm_registry, janet_wrap_cfunction(cfun));
|
||||
if (!janet_checktype(name, JANET_NIL))
|
||||
fprintf(stderr, " %s", (const char *)janet_to_string(name));
|
||||
else
|
||||
fprintf(stderr, " <cfunction>");
|
||||
}
|
||||
}
|
||||
if (frame->flags & JANET_STACKFRAME_TAILCALL)
|
||||
fprintf(stderr, " (tailcall)");
|
||||
if (frame->func && frame->pc) {
|
||||
int32_t off = (int32_t) (frame->pc - def->bytecode);
|
||||
if (def->sourcemap) {
|
||||
JanetSourceMapping mapping = def->sourcemap[off];
|
||||
fprintf(stderr, " at (%d:%d)", mapping.start, mapping.end);
|
||||
} else {
|
||||
fprintf(stderr, " pc=%d", off);
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
janet_v_free(fibers);
|
||||
}
|
||||
|
||||
/* Run a string */
|
||||
int janet_dobytes(JanetTable *env, const uint8_t *bytes, int32_t len, const char *sourcePath, Janet *out) {
|
||||
JanetParser parser;
|
||||
@@ -90,6 +35,7 @@ int janet_dobytes(JanetTable *env, const uint8_t *bytes, int32_t len, const char
|
||||
Janet ret = janet_wrap_nil();
|
||||
const uint8_t *where = sourcePath ? janet_cstring(sourcePath) : NULL;
|
||||
if (where) janet_gcroot(janet_wrap_string(where));
|
||||
if (NULL == sourcePath) sourcePath = "<unknown>";
|
||||
janet_parser_init(&parser);
|
||||
|
||||
while (!errflags && !done) {
|
||||
@@ -103,13 +49,12 @@ int janet_dobytes(JanetTable *env, const uint8_t *bytes, int32_t len, const char
|
||||
JanetFiber *fiber = janet_fiber(f, 64, 0, NULL);
|
||||
JanetSignal status = janet_continue(fiber, janet_wrap_nil(), &ret);
|
||||
if (status != JANET_SIGNAL_OK) {
|
||||
janet_stacktrace(fiber, "runtime", ret);
|
||||
janet_stacktrace(fiber, ret);
|
||||
errflags |= 0x01;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "source path: %s\n", sourcePath);
|
||||
janet_stacktrace(cres.macrofiber, "compile",
|
||||
janet_wrap_string(cres.error));
|
||||
fprintf(stderr, "compile error in %s: %s\n", sourcePath,
|
||||
(const char *)cres.error);
|
||||
errflags |= 0x02;
|
||||
}
|
||||
}
|
||||
@@ -118,13 +63,15 @@ int janet_dobytes(JanetTable *env, const uint8_t *bytes, int32_t len, const char
|
||||
switch (janet_parser_status(&parser)) {
|
||||
case JANET_PARSE_ERROR:
|
||||
errflags |= 0x04;
|
||||
fprintf(stderr, "parse error: %s\n", janet_parser_error(&parser));
|
||||
fprintf(stderr, "parse error in %s: %s\n",
|
||||
sourcePath, janet_parser_error(&parser));
|
||||
break;
|
||||
case JANET_PARSE_PENDING:
|
||||
if (index >= len) {
|
||||
if (dudeol) {
|
||||
errflags |= 0x04;
|
||||
fprintf(stderr, "internal parse error: unexpected end of source\n");
|
||||
fprintf(stderr, "internal parse error in %s: unexpected end of source\n",
|
||||
sourcePath);
|
||||
} else {
|
||||
dudeol = 1;
|
||||
janet_parser_consume(&parser, '\n');
|
||||
|
||||
@@ -221,7 +221,6 @@ static JanetSlot janetc_varset(JanetFopts opts, int32_t argn, const Janet *argv)
|
||||
return rvalue;
|
||||
} else {
|
||||
/* Error */
|
||||
janet_inspect(argv[0]);
|
||||
janetc_cerror(opts.compiler, "expected symbol or tuple for l-value to set");
|
||||
return janetc_cslot(janet_wrap_nil());
|
||||
}
|
||||
|
||||
@@ -39,6 +39,11 @@ extern JANET_THREAD_LOCAL int janet_vm_stackn;
|
||||
* Set and unset by janet_run. */
|
||||
extern JANET_THREAD_LOCAL JanetFiber *janet_vm_fiber;
|
||||
|
||||
/* The current pointer to the inner most jmp_buf. The current
|
||||
* return point for panics. */
|
||||
extern JANET_THREAD_LOCAL jmp_buf *janet_vm_jmp_buf;
|
||||
extern JANET_THREAD_LOCAL Janet *janet_vm_return_reg;
|
||||
|
||||
/* The global registry for c functions. Used to store meta-data
|
||||
* along with otherwise bare c function pointers. */
|
||||
extern JANET_THREAD_LOCAL JanetTable *janet_vm_registry;
|
||||
|
||||
@@ -441,64 +441,12 @@ static Janet cfun_string_join(int32_t argc, Janet *argv) {
|
||||
return janet_wrap_string(janet_string_end(buf));
|
||||
}
|
||||
|
||||
static struct formatter {
|
||||
const char *lead;
|
||||
const char *f1;
|
||||
const char *f2;
|
||||
} formatters[] = {
|
||||
{"g", "%g", "%.*g"},
|
||||
{"G", "%G", "%.*G"},
|
||||
{"e", "%e", "%.*e"},
|
||||
{"E", "%E", "%.*E"},
|
||||
{"f", "%f", "%.*f"},
|
||||
{"F", "%F", "%.*F"}
|
||||
};
|
||||
|
||||
static Janet cfun_string_number(int32_t argc, Janet *argv) {
|
||||
janet_arity(argc, 1, 4);
|
||||
double x = janet_getnumber(argv, 0);
|
||||
struct formatter fmter = formatters[0];
|
||||
char buf[100];
|
||||
int formatNargs = 1;
|
||||
int32_t precision = 0;
|
||||
if (argc >= 2) {
|
||||
const uint8_t *flag = janet_getkeyword(argv, 1);
|
||||
int i;
|
||||
for (i = 0; i < 6; i++) {
|
||||
struct formatter fmttest = formatters[i];
|
||||
if (!janet_cstrcmp(flag, fmttest.lead)) {
|
||||
fmter = fmttest;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == 6)
|
||||
janet_panicf("unsupported formatter %v", argv[1]);
|
||||
}
|
||||
|
||||
if (argc >= 3) {
|
||||
precision = janet_getinteger(argv, 2);
|
||||
formatNargs++;
|
||||
}
|
||||
|
||||
if (formatNargs == 1) {
|
||||
snprintf(buf, sizeof(buf), fmter.f1, x);
|
||||
} else if (formatNargs == 2) {
|
||||
snprintf(buf, sizeof(buf), fmter.f2, precision, x);
|
||||
}
|
||||
|
||||
return janet_cstringv(buf);
|
||||
}
|
||||
|
||||
static Janet cfun_string_pretty(int32_t argc, Janet *argv) {
|
||||
janet_arity(argc, 1, 3);
|
||||
JanetBuffer *buffer = NULL;
|
||||
int32_t depth = 4;
|
||||
if (argc > 1)
|
||||
depth = janet_getinteger(argv, 1);
|
||||
if (argc > 2)
|
||||
buffer = janet_getbuffer(argv, 2);
|
||||
buffer = janet_pretty(buffer, depth, argv[0]);
|
||||
return janet_wrap_buffer(buffer);
|
||||
static Janet cfun_string_format(int32_t argc, Janet *argv) {
|
||||
janet_arity(argc, 1, -1);
|
||||
JanetBuffer *buffer = janet_buffer(0);
|
||||
const char *strfrmt = (const char *) janet_getstring(argv, 0);
|
||||
janet_buffer_format(buffer, strfrmt, 0, argc, argv);
|
||||
return janet_stringv(buffer->data, buffer->count);
|
||||
}
|
||||
|
||||
static const JanetReg string_cfuns[] = {
|
||||
@@ -592,32 +540,15 @@ static const JanetReg string_cfuns[] = {
|
||||
"Joins an array of strings into one string, optionally separated by "
|
||||
"a separator string sep.")
|
||||
},
|
||||
{
|
||||
"string/number", cfun_string_number,
|
||||
JDOC("(string/number x [,format [,maxlen [,precision]]])\n\n"
|
||||
"Formats a number as string. The format parameter indicates how "
|
||||
"to display the number, either as floating point, scientific, or "
|
||||
"whichever representation is shorter. format can be:\n\n"
|
||||
"\t:g - (default) shortest representation with lowercase e.\n"
|
||||
"\t:G - shortest representation with uppercase E.\n"
|
||||
"\t:e - scientific with lowercase e.\n"
|
||||
"\t:E - scientific with uppercase E.\n"
|
||||
"\t:f - floating point representation.\n"
|
||||
"\t:F - same as :f\n\n"
|
||||
"The programmer can also specify the max length of the output string "
|
||||
"and the precision (number of places after decimal) in the output number. "
|
||||
"Returns a string representation of x.")
|
||||
},
|
||||
{
|
||||
"string/pretty", cfun_string_pretty,
|
||||
JDOC("(string/pretty x [,depth=4 [,buffer=@\"\"]])\n\n"
|
||||
"Pretty prints a value to a buffer. Optionally allows setting max "
|
||||
"recursion depth, as well as writing to a buffer. Returns the buffer.")
|
||||
{ "string/format", cfun_string_format,
|
||||
JDOC("(string/format format & values)\n\n"
|
||||
"Similar to snprintf, but specialized for operating with janet. Returns "
|
||||
"a new string.")
|
||||
},
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
/* Module entry point */
|
||||
void janet_lib_string(JanetTable *env) {
|
||||
janet_cfuns(env, NULL, string_cfuns);
|
||||
janet_core_cfuns(env, NULL, string_cfuns);
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ static void bignat_div(struct BigNat *mant, uint32_t divisor) {
|
||||
int32_t i;
|
||||
uint32_t quotient, remainder;
|
||||
uint64_t dividend;
|
||||
remainder = 0;
|
||||
remainder = 0, quotient = 0;
|
||||
for (i = mant->n - 1; i >= 0; i--) {
|
||||
dividend = ((uint64_t)remainder * BIGNAT_BASE) + mant->digits[i];
|
||||
if (i < mant->n - 1) mant->digits[i + 1] = quotient;
|
||||
@@ -228,7 +228,7 @@ static double convert(
|
||||
bignat_lshift_n(mant, shamt);
|
||||
exponent2 -= shamt * BIGNAT_NBIT;
|
||||
for (;exponent < -3; exponent += 4) bignat_div(mant, base * base * base * base);
|
||||
for (;exponent < -2; exponent += 2) bignat_div(mant, base * base);
|
||||
for (;exponent < -1; exponent += 2) bignat_div(mant, base * base);
|
||||
for (;exponent < 0; exponent += 1) bignat_div(mant, base);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <janet/janet.h>
|
||||
#include "gc.h"
|
||||
#include "util.h"
|
||||
#include <math.h>
|
||||
#endif
|
||||
|
||||
/* Begin creation of a struct */
|
||||
@@ -73,6 +74,7 @@ void janet_struct_put(JanetKV *st, Janet key, Janet value) {
|
||||
int32_t i, j, dist;
|
||||
int32_t bounds[4] = {index, cap, 0, index};
|
||||
if (janet_checktype(key, JANET_NIL) || janet_checktype(value, JANET_NIL)) return;
|
||||
if (janet_checktype(key, JANET_NUMBER) && isnan(janet_unwrap_number(key))) return;
|
||||
/* Avoid extra items */
|
||||
if (janet_struct_hash(st) == janet_struct_length(st)) return;
|
||||
for (dist = 0, j = 0; j < 4; j += 2)
|
||||
@@ -120,9 +122,7 @@ void janet_struct_put(JanetKV *st, Janet key, Janet value) {
|
||||
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 */
|
||||
janet_exit("struct double put fail");
|
||||
/* A key was added to the struct more than once */
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -134,15 +134,8 @@ const JanetKV *janet_struct_end(JanetKV *st) {
|
||||
/* Error building struct, probably duplicate values. We need to rebuild
|
||||
* the struct using only the values that went in. The second creation should always
|
||||
* succeed. */
|
||||
int32_t i, realCount;
|
||||
JanetKV *newst;
|
||||
realCount = 0;
|
||||
for (i = 0; i < janet_struct_capacity(st); i++) {
|
||||
JanetKV *kv = st + i;
|
||||
realCount += janet_checktype(kv->key, JANET_NIL) ? 1 : 0;
|
||||
}
|
||||
newst = janet_struct_begin(realCount);
|
||||
for (i = 0; i < janet_struct_capacity(st); i++) {
|
||||
JanetKV *newst = janet_struct_begin(janet_struct_hash(st));
|
||||
for (int32_t i = 0; i < janet_struct_capacity(st); i++) {
|
||||
JanetKV *kv = st + i;
|
||||
if (!janet_checktype(kv->key, JANET_NIL)) {
|
||||
janet_struct_put(newst, kv->key, kv->value);
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <janet/janet.h>
|
||||
#include "gc.h"
|
||||
#include "util.h"
|
||||
#include <math.h>
|
||||
#endif
|
||||
|
||||
/* Initialize a table */
|
||||
@@ -131,6 +132,7 @@ Janet janet_table_remove(JanetTable *t, Janet key) {
|
||||
/* Put a value into the object */
|
||||
void janet_table_put(JanetTable *t, Janet key, Janet value) {
|
||||
if (janet_checktype(key, JANET_NIL)) return;
|
||||
if (janet_checktype(key, JANET_NUMBER) && isnan(janet_unwrap_number(key))) return;
|
||||
if (janet_checktype(value, JANET_NIL)) {
|
||||
janet_table_remove(t, key);
|
||||
} else {
|
||||
@@ -271,5 +273,5 @@ static const JanetReg table_cfuns[] = {
|
||||
|
||||
/* Load the table module */
|
||||
void janet_lib_table(JanetTable *env) {
|
||||
janet_cfuns(env, NULL, table_cfuns);
|
||||
janet_core_cfuns(env, NULL, table_cfuns);
|
||||
}
|
||||
|
||||
@@ -31,11 +31,12 @@
|
||||
* which should be filled with Janets. The memory will not be collected until
|
||||
* janet_tuple_end is called. */
|
||||
Janet *janet_tuple_begin(int32_t length) {
|
||||
char *data = janet_gcalloc(JANET_MEMORY_TUPLE, 4 * sizeof(int32_t) + length * sizeof(Janet));
|
||||
Janet *tuple = (Janet *)(data + (4 * sizeof(int32_t)));
|
||||
char *data = janet_gcalloc(JANET_MEMORY_TUPLE, 5 * sizeof(int32_t) + length * sizeof(Janet));
|
||||
Janet *tuple = (Janet *)(data + (5 * sizeof(int32_t)));
|
||||
janet_tuple_length(tuple) = length;
|
||||
janet_tuple_sm_start(tuple) = -1;
|
||||
janet_tuple_sm_end(tuple) = -1;
|
||||
janet_tuple_flag(tuple) = 0;
|
||||
return tuple;
|
||||
}
|
||||
|
||||
@@ -93,6 +94,12 @@ int janet_tuple_compare(const Janet *lhs, const Janet *rhs) {
|
||||
|
||||
/* C Functions */
|
||||
|
||||
static Janet cfun_tuple_brackets(int32_t argc, Janet *argv) {
|
||||
const Janet *tup = janet_tuple_n(argv, argc);
|
||||
janet_tuple_flag(tup) |= JANET_TUPLE_FLAG_BRACKETCTOR;
|
||||
return janet_wrap_tuple(tup);
|
||||
}
|
||||
|
||||
static Janet cfun_tuple_slice(int32_t argc, Janet *argv) {
|
||||
JanetRange range = janet_getslice(argc, argv);
|
||||
JanetView view = janet_getindexed(argv, 0);
|
||||
@@ -119,7 +126,22 @@ static Janet cfun_tuple_append(int32_t argc, Janet *argv) {
|
||||
return janet_wrap_tuple(janet_tuple_end(n));
|
||||
}
|
||||
|
||||
static Janet cfun_tuple_type(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 1);
|
||||
const Janet *tup = janet_gettuple(argv, 0);
|
||||
if (janet_tuple_flag(tup) & JANET_TUPLE_FLAG_BRACKETCTOR) {
|
||||
return janet_ckeywordv("brackets");
|
||||
} else {
|
||||
return janet_ckeywordv("parens");
|
||||
}
|
||||
}
|
||||
|
||||
static const JanetReg tuple_cfuns[] = {
|
||||
{
|
||||
"tuple/brackets", cfun_tuple_brackets,
|
||||
JDOC("(tuple/brackets & xs)\n\n"
|
||||
"Creates a new bracketed tuple containing the elements xs.")
|
||||
},
|
||||
{
|
||||
"tuple/slice", cfun_tuple_slice,
|
||||
JDOC("(tuple/slice arrtup [,start=0 [,end=(length arrtup)]])\n\n"
|
||||
@@ -141,10 +163,19 @@ static const JanetReg tuple_cfuns[] = {
|
||||
"returns a new tuple. Items are prepended such that the "
|
||||
"last element in items is the first element in the new tuple.")
|
||||
},
|
||||
{
|
||||
"tuple/type", cfun_tuple_type,
|
||||
JDOC("(tuple/type tup)\n\n"
|
||||
"Checks how the tuple was constructed. Will return the keyword "
|
||||
":brackets if the tuple was parsed with brackets, and :parens "
|
||||
"otherwise. The two types of tuples will behave the same most of "
|
||||
"the time, but will print differently and be treated differently by "
|
||||
"the compiler.")
|
||||
},
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
/* Load the tuple module */
|
||||
void janet_lib_tuple(JanetTable *env) {
|
||||
janet_cfuns(env, NULL, tuple_cfuns);
|
||||
janet_core_cfuns(env, NULL, tuple_cfuns);
|
||||
}
|
||||
|
||||
@@ -284,6 +284,24 @@ void janet_cfuns(JanetTable *env, const char *regprefix, const JanetReg *cfuns)
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef JANET_BOOTSTRAP
|
||||
void janet_core_def(JanetTable *env, const char *name, Janet x, const void *p) {
|
||||
(void) p;
|
||||
janet_table_put(env, janet_csymbolv(name), x);
|
||||
}
|
||||
|
||||
void janet_core_cfuns(JanetTable *env, const char *regprefix, const JanetReg *cfuns) {
|
||||
(void) regprefix;
|
||||
while (cfuns->name) {
|
||||
Janet name = janet_csymbolv(cfuns->name);
|
||||
Janet fun = janet_wrap_cfunction(cfuns->cfun);
|
||||
janet_core_def(env, cfuns->name, fun, cfuns->documentation);
|
||||
janet_table_put(janet_vm_registry, fun, name);
|
||||
cfuns++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Resolve a symbol in the environment */
|
||||
JanetBindingType janet_resolve(JanetTable *env, const uint8_t *sym, Janet *out) {
|
||||
Janet ref;
|
||||
@@ -316,7 +334,7 @@ int janet_indexed_view(Janet seq, const Janet **data, int32_t *len) {
|
||||
return 1;
|
||||
} else if (janet_checktype(seq, JANET_TUPLE)) {
|
||||
*data = janet_unwrap_tuple(seq);
|
||||
*len = janet_tuple_length(janet_unwrap_struct(seq));
|
||||
*len = janet_tuple_length(janet_unwrap_tuple(seq));
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
@@ -28,8 +28,9 @@
|
||||
#endif
|
||||
|
||||
/* Omit docstrings in some builds */
|
||||
#ifdef JANET_NO_BOOTSTRAP
|
||||
#ifndef JANET_BOOTSTRAP
|
||||
#define JDOC(x) NULL
|
||||
#define JANET_NO_BOOTSTRAP
|
||||
#else
|
||||
#define JDOC(x) x
|
||||
#endif
|
||||
@@ -51,6 +52,22 @@ const void *janet_strbinsearch(
|
||||
size_t tabcount,
|
||||
size_t itemsize,
|
||||
const uint8_t *key);
|
||||
void janet_buffer_format(
|
||||
JanetBuffer *b,
|
||||
const char *strfrmt,
|
||||
int32_t argstart,
|
||||
int32_t argc,
|
||||
Janet *argv);
|
||||
|
||||
/* Inside the janet core, defining globals is different
|
||||
* at bootstrap time and normal runtime */
|
||||
#ifdef JANET_BOOTSTRAP
|
||||
#define janet_core_def janet_def
|
||||
#define janet_core_cfuns janet_cfuns
|
||||
#else
|
||||
void janet_core_def(JanetTable *env, const char *name, Janet x, const void *p);
|
||||
void janet_core_cfuns(JanetTable *env, const char *regprefix, const JanetReg *cfuns);
|
||||
#endif
|
||||
|
||||
/* Initialize builtin libraries */
|
||||
void janet_lib_io(JanetTable *env);
|
||||
|
||||
@@ -219,6 +219,17 @@ Janet janet_get(Janet ds, Janet key) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JANET_ABSTRACT:
|
||||
{
|
||||
JanetAbstractType *type = (JanetAbstractType *)janet_abstract_type(janet_unwrap_abstract(ds));
|
||||
if (type->get) {
|
||||
value = (type->get)(janet_unwrap_abstract(ds),key);
|
||||
} else {
|
||||
janet_panicf("no getter for %T ", JANET_TFLAG_LENGTHABLE, ds);
|
||||
value = janet_wrap_nil();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
@@ -267,6 +278,17 @@ Janet janet_getindex(Janet ds, int32_t index) {
|
||||
case JANET_STRUCT:
|
||||
value = janet_struct_get(janet_unwrap_struct(ds), janet_wrap_integer(index));
|
||||
break;
|
||||
case JANET_ABSTRACT:
|
||||
{
|
||||
JanetAbstractType *type = (JanetAbstractType *)janet_abstract_type(janet_unwrap_abstract(ds));
|
||||
if (type->get) {
|
||||
value = (type->get)(janet_unwrap_abstract(ds),janet_wrap_integer(index));
|
||||
} else {
|
||||
janet_panicf("no getter for %T ", JANET_TFLAG_LENGTHABLE, ds);
|
||||
value = janet_wrap_nil();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
@@ -327,6 +349,16 @@ void janet_putindex(Janet ds, int32_t index, Janet value) {
|
||||
janet_table_put(table, janet_wrap_integer(index), value);
|
||||
break;
|
||||
}
|
||||
case JANET_ABSTRACT:
|
||||
{
|
||||
JanetAbstractType *type = (JanetAbstractType *)janet_abstract_type(janet_unwrap_abstract(ds));
|
||||
if (type->put) {
|
||||
(type->put)(janet_unwrap_abstract(ds),janet_wrap_integer(index),value);
|
||||
} else {
|
||||
janet_panicf("no setter for %T ", JANET_TFLAG_LENGTHABLE, ds);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -367,5 +399,16 @@ void janet_put(Janet ds, Janet key, Janet value) {
|
||||
case JANET_TABLE:
|
||||
janet_table_put(janet_unwrap_table(ds), key, value);
|
||||
break;
|
||||
case JANET_ABSTRACT:
|
||||
{
|
||||
JanetAbstractType *type = (JanetAbstractType *)janet_abstract_type(janet_unwrap_abstract(ds));
|
||||
if (type->put) {
|
||||
(type->put)(janet_unwrap_abstract(ds),key,value);
|
||||
} else {
|
||||
janet_panicf("no setter for %T ", JANET_TFLAG_LENGTHABLE, ds);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,22 +42,6 @@ void *janet_v_grow(void *v, int32_t increment, int32_t itemsize) {
|
||||
}
|
||||
}
|
||||
|
||||
/* Clone a buffer. */
|
||||
void *janet_v_copymem(void *v, int32_t itemsize) {
|
||||
int32_t *p;
|
||||
if (NULL == v) return NULL;
|
||||
p = malloc(2 * sizeof(int32_t) + itemsize * janet_v__cap(v));
|
||||
if (NULL != p) {
|
||||
memcpy(p, janet_v__raw(v), 2 * sizeof(int32_t) + itemsize * janet_v__cnt(v));
|
||||
return p + 2;
|
||||
} else {
|
||||
{
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
return (void *) (2 * sizeof(int32_t));
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert a buffer to normal allocated memory (forget capacity) */
|
||||
void *janet_v_flattenmem(void *v, int32_t itemsize) {
|
||||
int32_t *p;
|
||||
|
||||
@@ -33,6 +33,8 @@
|
||||
JANET_THREAD_LOCAL JanetTable *janet_vm_registry;
|
||||
JANET_THREAD_LOCAL int janet_vm_stackn = 0;
|
||||
JANET_THREAD_LOCAL JanetFiber *janet_vm_fiber = NULL;
|
||||
JANET_THREAD_LOCAL Janet *janet_vm_return_reg = NULL;
|
||||
JANET_THREAD_LOCAL jmp_buf *janet_vm_jmp_buf = NULL;
|
||||
|
||||
/* Virtual registers
|
||||
*
|
||||
@@ -148,7 +150,7 @@ static void *op_lookup[255] = {
|
||||
} while (0)
|
||||
#define vm_return(sig, val) do { \
|
||||
vm_commit(); \
|
||||
janet_fiber_push(fiber, (val)); \
|
||||
janet_vm_return_reg[0] = (val); \
|
||||
return (sig); \
|
||||
} while (0)
|
||||
|
||||
@@ -226,7 +228,8 @@ static Janet call_nonfn(JanetFiber *fiber, Janet callee) {
|
||||
int32_t argn = fiber->stacktop - fiber->stackstart;
|
||||
Janet ds, key;
|
||||
if (argn != 1) janet_panicf("%v called with arity %d, expected 1", callee, argn);
|
||||
if (janet_checktypes(callee, JANET_TFLAG_INDEXED | JANET_TFLAG_DICTIONARY)) {
|
||||
if (janet_checktypes(callee, JANET_TFLAG_INDEXED | JANET_TFLAG_DICTIONARY |
|
||||
JANET_TFLAG_STRING | JANET_TFLAG_BUFFER | JANET_TFLAG_ABSTRACT)) {
|
||||
ds = callee;
|
||||
key = fiber->data[fiber->stackstart];
|
||||
} else {
|
||||
@@ -283,8 +286,9 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in, JanetFiberStatus status)
|
||||
VM_OP(JOP_RETURN)
|
||||
{
|
||||
Janet retval = stack[D];
|
||||
int entrance_frame = janet_stack_frame(stack)->flags & JANET_STACKFRAME_ENTRANCE;
|
||||
janet_fiber_popframe(fiber);
|
||||
if (fiber->frame == 0) vm_return(JANET_SIGNAL_OK, retval);
|
||||
if (entrance_frame) vm_return(JANET_SIGNAL_OK, retval);
|
||||
vm_restore();
|
||||
stack[A] = retval;
|
||||
vm_checkgc_pcnext();
|
||||
@@ -293,8 +297,9 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in, JanetFiberStatus status)
|
||||
VM_OP(JOP_RETURN_NIL)
|
||||
{
|
||||
Janet retval = janet_wrap_nil();
|
||||
int entrance_frame = janet_stack_frame(stack)->flags & JANET_STACKFRAME_ENTRANCE;
|
||||
janet_fiber_popframe(fiber);
|
||||
if (fiber->frame == 0) vm_return(JANET_SIGNAL_OK, retval);
|
||||
if (entrance_frame) vm_return(JANET_SIGNAL_OK, retval);
|
||||
vm_restore();
|
||||
stack[A] = retval;
|
||||
vm_checkgc_pcnext();
|
||||
@@ -581,7 +586,7 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in, JanetFiberStatus status)
|
||||
janet_fiber_cframe(fiber, janet_unwrap_cfunction(callee));
|
||||
Janet ret = janet_unwrap_cfunction(callee)(argc, fiber->data + fiber->frame);
|
||||
janet_fiber_popframe(fiber);
|
||||
if (fiber->frame == 0) vm_return(JANET_SIGNAL_OK, ret);
|
||||
/*if (fiber->frame == 0) vm_return(JANET_SIGNAL_OK, ret);*/
|
||||
stack = fiber->data + fiber->frame;
|
||||
stack[A] = ret;
|
||||
vm_checkgc_pcnext();
|
||||
@@ -614,6 +619,7 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in, JanetFiberStatus status)
|
||||
vm_checkgc_next();
|
||||
} else {
|
||||
Janet retreg;
|
||||
int entrance_frame = janet_stack_frame(stack)->flags & JANET_STACKFRAME_ENTRANCE;
|
||||
vm_commit();
|
||||
if (janet_checktype(callee, JANET_CFUNCTION)) {
|
||||
int32_t argc = fiber->stacktop - fiber->stackstart;
|
||||
@@ -624,7 +630,7 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in, JanetFiberStatus status)
|
||||
retreg = call_nonfn(fiber, callee);
|
||||
}
|
||||
janet_fiber_popframe(fiber);
|
||||
if (fiber->frame == 0)
|
||||
if (entrance_frame)
|
||||
vm_return(JANET_SIGNAL_OK, retreg);
|
||||
vm_restore();
|
||||
stack[A] = retreg;
|
||||
@@ -755,39 +761,45 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in, JanetFiberStatus status)
|
||||
}
|
||||
|
||||
Janet janet_call(JanetFunction *fun, int32_t argc, const Janet *argv) {
|
||||
Janet ret;
|
||||
Janet *old_return_reg = janet_vm_return_reg;
|
||||
|
||||
/* Check entry conditions */
|
||||
if (!janet_vm_fiber)
|
||||
janet_panic("janet_call failed because there is no current fiber");
|
||||
if (janet_vm_stackn >= JANET_RECURSION_GUARD)
|
||||
janet_panic("C stack recursed too deeply");
|
||||
JanetFiber *fiber = janet_fiber(fun, 64, argc, argv);
|
||||
if (!fiber)
|
||||
janet_panic("arity mismatch");
|
||||
JanetFiber *old_fiber = janet_vm_fiber;
|
||||
janet_vm_fiber = fiber;
|
||||
janet_gcroot(janet_wrap_fiber(fiber));
|
||||
|
||||
/* Push frame */
|
||||
janet_fiber_pushn(janet_vm_fiber, argv, argc);
|
||||
if (janet_fiber_funcframe(janet_vm_fiber, fun)) {
|
||||
janet_panicf("arity mismatch in %v", fun);
|
||||
}
|
||||
janet_fiber_frame(janet_vm_fiber)->flags |= JANET_STACKFRAME_ENTRANCE;
|
||||
|
||||
/* Set up */
|
||||
int32_t oldn = janet_vm_stackn++;
|
||||
int handle = janet_gclock();
|
||||
janet_vm_return_reg = &ret;
|
||||
|
||||
JanetSignal signal;
|
||||
if (setjmp(fiber->buf)) {
|
||||
signal = JANET_SIGNAL_ERROR;
|
||||
} else {
|
||||
signal = run_vm(fiber, janet_wrap_nil(), JANET_STATUS_NEW);
|
||||
}
|
||||
/* Run vm */
|
||||
JanetSignal signal = run_vm(janet_vm_fiber,
|
||||
janet_wrap_nil(),
|
||||
JANET_STATUS_ALIVE);
|
||||
|
||||
/* Teardown */
|
||||
janet_vm_return_reg = old_return_reg;
|
||||
janet_vm_stackn = oldn;
|
||||
janet_vm_fiber = old_fiber;
|
||||
Janet ret = fiber->data[fiber->stacktop - 1];
|
||||
janet_gcunroot(janet_wrap_fiber(fiber));
|
||||
janet_gcunlock(handle);
|
||||
if (signal == JANET_SIGNAL_ERROR) {
|
||||
old_fiber->child = fiber;
|
||||
janet_fiber_set_status(fiber, signal);
|
||||
janet_panicv(ret);
|
||||
}
|
||||
|
||||
if (signal != JANET_SIGNAL_OK) janet_panicv(ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Enter the main vm loop */
|
||||
JanetSignal janet_continue(JanetFiber *fiber, Janet in, Janet *out) {
|
||||
jmp_buf buf;
|
||||
|
||||
/* Check conditions */
|
||||
JanetFiberStatus old_status = janet_fiber_status(fiber);
|
||||
@@ -820,15 +832,19 @@ JanetSignal janet_continue(JanetFiber *fiber, Janet in, Janet *out) {
|
||||
int32_t oldn = janet_vm_stackn++;
|
||||
int handle = janet_vm_gc_suspend;
|
||||
JanetFiber *old_vm_fiber = janet_vm_fiber;
|
||||
jmp_buf *old_vm_jmp_buf = janet_vm_jmp_buf;
|
||||
Janet *old_vm_return_reg = janet_vm_return_reg;
|
||||
|
||||
/* Setup fiber */
|
||||
janet_vm_fiber = fiber;
|
||||
janet_gcroot(janet_wrap_fiber(fiber));
|
||||
janet_fiber_set_status(fiber, JANET_STATUS_ALIVE);
|
||||
janet_vm_return_reg = out;
|
||||
janet_vm_jmp_buf = &buf;
|
||||
|
||||
/* Run loop */
|
||||
JanetSignal signal;
|
||||
if (setjmp(fiber->buf)) {
|
||||
if (setjmp(buf)) {
|
||||
signal = JANET_SIGNAL_ERROR;
|
||||
} else {
|
||||
signal = run_vm(fiber, in, old_status);
|
||||
@@ -842,9 +858,8 @@ JanetSignal janet_continue(JanetFiber *fiber, Janet in, Janet *out) {
|
||||
janet_vm_gc_suspend = handle;
|
||||
janet_vm_fiber = old_vm_fiber;
|
||||
janet_vm_stackn = oldn;
|
||||
|
||||
/* Pop error or return value from fiber stack */
|
||||
*out = fiber->data[--fiber->stacktop];
|
||||
janet_vm_return_reg = old_vm_return_reg;
|
||||
janet_vm_jmp_buf = old_vm_jmp_buf;
|
||||
|
||||
return signal;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,9 @@
|
||||
void *janet_memalloc_empty(int32_t count) {
|
||||
int32_t i;
|
||||
void *mem = malloc(count * sizeof(JanetKV));
|
||||
if (NULL == mem) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
JanetKV *mmem = (JanetKV *)mem;
|
||||
for (i = 0; i < count; i++) {
|
||||
JanetKV *kv = mmem + i;
|
||||
|
||||
@@ -29,7 +29,7 @@ extern "C" {
|
||||
|
||||
/***** START SECTION CONFIG *****/
|
||||
|
||||
#define JANET_VERSION "0.3.0"
|
||||
#define JANET_VERSION "0.4.0"
|
||||
|
||||
#ifndef JANET_BUILD
|
||||
#define JANET_BUILD "local"
|
||||
@@ -266,6 +266,7 @@ typedef struct JanetKV JanetKV;
|
||||
typedef struct JanetStackFrame JanetStackFrame;
|
||||
typedef struct JanetAbstractType JanetAbstractType;
|
||||
typedef struct JanetReg JanetReg;
|
||||
typedef struct JanetMethod JanetMethod;
|
||||
typedef struct JanetSourceMapping JanetSourceMapping;
|
||||
typedef struct JanetView JanetView;
|
||||
typedef struct JanetByteView JanetByteView;
|
||||
@@ -603,12 +604,14 @@ struct JanetFiber {
|
||||
int32_t capacity;
|
||||
int32_t maxstack; /* Arbitrary defined limit for stack overflow */
|
||||
int32_t flags; /* Various flags */
|
||||
jmp_buf buf; /* Handle errors */
|
||||
};
|
||||
|
||||
/* Mark if a stack frame is a tail call for debugging */
|
||||
#define JANET_STACKFRAME_TAILCALL 1
|
||||
|
||||
/* Mark if a stack frame is an entrance frame */
|
||||
#define JANET_STACKFRAME_ENTRANCE 2
|
||||
|
||||
/* A stack frame on the fiber. Is stored along with the stack values. */
|
||||
struct JanetStackFrame {
|
||||
JanetFunction *func;
|
||||
@@ -736,6 +739,8 @@ struct JanetAbstractType {
|
||||
const char *name;
|
||||
int (*gc)(void *data, size_t len);
|
||||
int (*gcmark)(void *data, size_t len);
|
||||
Janet (*get)(void *data, Janet key);
|
||||
void (*put)(void *data, Janet key, Janet value);
|
||||
};
|
||||
|
||||
/* Contains information about abstract types */
|
||||
@@ -750,6 +755,11 @@ struct JanetReg {
|
||||
const char *documentation;
|
||||
};
|
||||
|
||||
struct JanetMethod {
|
||||
const char *name;
|
||||
JanetCFunction cfun;
|
||||
};
|
||||
|
||||
struct JanetView {
|
||||
const Janet *items;
|
||||
int32_t len;
|
||||
@@ -970,11 +980,15 @@ JANET_API void janet_buffer_push_u32(JanetBuffer *buffer, uint32_t x);
|
||||
JANET_API void janet_buffer_push_u64(JanetBuffer *buffer, uint64_t x);
|
||||
|
||||
/* Tuple */
|
||||
#define janet_tuple_raw(t) ((int32_t *)(t) - 4)
|
||||
|
||||
#define JANET_TUPLE_FLAG_BRACKETCTOR 1
|
||||
|
||||
#define janet_tuple_raw(t) ((int32_t *)(t) - 5)
|
||||
#define janet_tuple_length(t) (janet_tuple_raw(t)[0])
|
||||
#define janet_tuple_hash(t) ((janet_tuple_raw(t)[1]))
|
||||
#define janet_tuple_sm_start(t) ((janet_tuple_raw(t)[2]))
|
||||
#define janet_tuple_sm_end(t) ((janet_tuple_raw(t)[3]))
|
||||
#define janet_tuple_flag(t) ((janet_tuple_raw(t)[4]))
|
||||
JANET_API Janet *janet_tuple_begin(int32_t length);
|
||||
JANET_API const Janet *janet_tuple_end(Janet *tuple);
|
||||
JANET_API const Janet *janet_tuple_n(const Janet *values, int32_t n);
|
||||
@@ -1106,7 +1120,6 @@ JANET_API Janet janet_getindex(Janet ds, int32_t index);
|
||||
JANET_API int32_t janet_length(Janet x);
|
||||
JANET_API void janet_put(Janet ds, Janet key, Janet value);
|
||||
JANET_API void janet_putindex(Janet ds, int32_t index, Janet value);
|
||||
JANET_API void janet_inspect(Janet x);
|
||||
|
||||
/* VM functions */
|
||||
JANET_API int janet_init(void);
|
||||
@@ -1114,7 +1127,7 @@ JANET_API void janet_deinit(void);
|
||||
JANET_API JanetSignal janet_continue(JanetFiber *fiber, Janet in, Janet *out);
|
||||
JANET_API JanetSignal janet_pcall(JanetFunction *fun, int32_t argn, const Janet *argv, Janet *out, JanetFiber **f);
|
||||
JANET_API Janet janet_call(JanetFunction *fun, int32_t argc, const Janet *argv);
|
||||
JANET_API void janet_stacktrace(JanetFiber *fiber, const char *errtype, Janet err);
|
||||
JANET_API void janet_stacktrace(JanetFiber *fiber, Janet err);
|
||||
|
||||
/* C Library helpers */
|
||||
typedef enum {
|
||||
@@ -1142,6 +1155,7 @@ JANET_API void janet_panic_abstract(Janet x, int32_t n, const JanetAbstractType
|
||||
JANET_API void janet_arity(int32_t arity, int32_t min, int32_t max);
|
||||
JANET_API void janet_fixarity(int32_t arity, int32_t fix);
|
||||
|
||||
JANET_API Janet janet_getmethod(const uint8_t *method, const JanetMethod *methods);
|
||||
JANET_API double janet_getnumber(const Janet *argv, int32_t n);
|
||||
JANET_API JanetArray *janet_getarray(const Janet *argv, int32_t n);
|
||||
JANET_API const Janet *janet_gettuple(const Janet *argv, int32_t n);
|
||||
|
||||
@@ -24,11 +24,11 @@
|
||||
|
||||
/* Common */
|
||||
Janet janet_line_getter(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 2);
|
||||
const uint8_t *str = janet_getstring(argv, 0);
|
||||
JanetBuffer *buf = janet_getbuffer(argv, 1);
|
||||
janet_arity(argc, 0, 2);
|
||||
const char *str = (argc >= 1) ? (const char *) janet_getstring(argv, 0) : "";
|
||||
JanetBuffer *buf = (argc >= 2) ? janet_getbuffer(argv, 1) : janet_buffer(10);
|
||||
janet_line_get(str, buf);
|
||||
return argv[0];
|
||||
return janet_wrap_buffer(buf);
|
||||
}
|
||||
|
||||
static void simpleline(JanetBuffer *buffer) {
|
||||
@@ -55,8 +55,8 @@ void janet_line_deinit() {
|
||||
;
|
||||
}
|
||||
|
||||
void janet_line_get(const uint8_t *p, JanetBuffer *buffer) {
|
||||
fputs((const char *)p, stdout);
|
||||
void janet_line_get(const char *p, JanetBuffer *buffer) {
|
||||
fputs(p, stdout);
|
||||
simpleline(buffer);
|
||||
}
|
||||
|
||||
@@ -444,8 +444,8 @@ static int checktermsupport() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void janet_line_get(const uint8_t *p, JanetBuffer *buffer) {
|
||||
prompt = (const char *)p;
|
||||
void janet_line_get(const char *p, JanetBuffer *buffer) {
|
||||
prompt = p;
|
||||
buffer->count = 0;
|
||||
historyi = 0;
|
||||
if (!isatty(STDIN_FILENO) || !checktermsupport()) {
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
void janet_line_init();
|
||||
void janet_line_deinit();
|
||||
|
||||
void janet_line_get(const uint8_t *p, JanetBuffer *buffer);
|
||||
void janet_line_get(const char *p, JanetBuffer *buffer);
|
||||
Janet janet_line_getter(int32_t argc, Janet *argv);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -44,7 +44,7 @@ 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_stacktrace(repl_fiber, ret);
|
||||
janet_deinit();
|
||||
repl_fiber = NULL;
|
||||
return 1;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Copyright 2017-2019 (C) Calvin Rose
|
||||
|
||||
(print (string "Janet " janet/version "-" janet/build " Copyright (C) 2017-2018 Calvin Rose"))
|
||||
(print (string "Janet " janet/version "-" janet/build " Copyright (C) 2017-2019 Calvin Rose"))
|
||||
|
||||
(fiber/new (fn webrepl []
|
||||
(repl (fn get-line [buf p]
|
||||
|
||||
@@ -283,5 +283,22 @@
|
||||
(++ i))
|
||||
(assert (= i 6) "when macro"))
|
||||
|
||||
# Denormal tables and structs
|
||||
|
||||
(assert (= (length {1 2 nil 3}) 1) "nil key struct literal")
|
||||
(assert (= (length @{1 2 nil 3}) 1) "nil key table literal")
|
||||
(assert (= (length (struct 1 2 nil 3)) 1) "nil key struct ctor")
|
||||
(assert (= (length (table 1 2 nil 3)) 1) "nil key table ctor")
|
||||
|
||||
(assert (= (length (struct (/ 0 0) 2 1 3)) 1) "nan key struct ctor")
|
||||
(assert (= (length (table (/ 0 0) 2 1 3)) 1) "nan key table ctor")
|
||||
(assert (= (length {1 2 nil 3}) 1) "nan key struct literal")
|
||||
(assert (= (length @{1 2 nil 3}) 1) "nan key table literal")
|
||||
|
||||
(assert (= (length (struct 2 1 3 nil)) 1) "nil value struct ctor")
|
||||
(assert (= (length (table 2 1 3 nil)) 1) "nil value table ctor")
|
||||
(assert (= (length {1 2 3 nil}) 1) "nil value struct literal")
|
||||
(assert (= (length @{1 2 3 nil}) 1) "nil value table literal")
|
||||
|
||||
(end-suite)
|
||||
|
||||
|
||||
@@ -154,6 +154,10 @@
|
||||
(testmarsh 1 "marshal small integers")
|
||||
(testmarsh -1 "marshal integers (-1)")
|
||||
(testmarsh 199 "marshal small integers (199)")
|
||||
(testmarsh 5000 "marshal medium integers (5000)")
|
||||
(testmarsh -5000 "marshal small integers (-5000)")
|
||||
(testmarsh 10000 "marshal large integers (10000)")
|
||||
(testmarsh -10000 "marshal large integers (-10000)")
|
||||
(testmarsh 1.0 "marshal double")
|
||||
(testmarsh "doctordolittle" "marshal string")
|
||||
(testmarsh :chickenshwarma "marshal symbol")
|
||||
|
||||
@@ -346,4 +346,17 @@
|
||||
(check-deep '(drop '"hello") "hello" @[])
|
||||
(check-deep '(drop "hello") "hello" @[])
|
||||
|
||||
# Regression #24
|
||||
|
||||
(def t (put @{} :hi 1))
|
||||
(assert (deep= t @{:hi 1}) "regression #24")
|
||||
|
||||
# Tuple types
|
||||
|
||||
(assert (= (tuple/type '(1 2 3)) :parens) "normal tuple")
|
||||
(assert (= (tuple/type [1 2 3]) :parens) "normal tuple 1")
|
||||
(assert (= (tuple/type '[1 2 3]) :brackets) "bracketed tuple 2")
|
||||
(assert (= (tuple/type (-> '(1 2 3) marshal unmarshal)) :parens) "normal tuple marshalled/unmarshalled")
|
||||
(assert (= (tuple/type (-> '[1 2 3] marshal unmarshal)) :brackets) "normal tuple marshalled/unmarshalled")
|
||||
|
||||
(end-suite)
|
||||
|
||||
42
test/suite4.janet
Normal file
42
test/suite4.janet
Normal file
@@ -0,0 +1,42 @@
|
||||
# Copyright (c) 2019 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.
|
||||
|
||||
(import test/helper :prefix "" :exit true)
|
||||
(start-suite 4)
|
||||
# some tests for string/format and buffer/format
|
||||
|
||||
(assert (= (string (buffer/format @"" "pi = %6.3f" math/pi)) "pi = 3.142") "%6.3f")
|
||||
(assert (= (string (buffer/format @"" "pi = %+6.3f" math/pi)) "pi = +3.142") "%6.3f")
|
||||
(assert (= (string (buffer/format @"" "pi = %40.20g" math/pi)) "pi = 3.141592653589793116") "%6.3f")
|
||||
|
||||
(assert (= (string (buffer/format @"" "🐼 = %6.3f" math/pi)) "🐼 = 3.142") "UTF-8")
|
||||
(assert (= (string (buffer/format @"" "π = %.8g" math/pi)) "π = 3.1415927") "π")
|
||||
(assert (= (string (buffer/format @"" "\xCF\x80 = %.8g" math/pi)) "\xCF\x80 = 3.1415927") "\xCF\x80")
|
||||
|
||||
(assert (= (string/format "pi = %6.3f" math/pi) "pi = 3.142") "%6.3f")
|
||||
(assert (= (string/format "pi = %+6.3f" math/pi) "pi = +3.142") "%6.3f")
|
||||
(assert (= (string/format "pi = %40.20g" math/pi) "pi = 3.141592653589793116") "%6.3f")
|
||||
|
||||
(assert (= (string/format "🐼 = %6.3f" math/pi) "🐼 = 3.142") "UTF-8")
|
||||
(assert (= (string/format "π = %.8g" math/pi) "π = 3.1415927") "π")
|
||||
(assert (= (string/format "\xCF\x80 = %.8g" math/pi) "\xCF\x80 = 3.1415927") "\xCF\x80")
|
||||
|
||||
(end-suite)
|
||||
|
||||
@@ -65,11 +65,12 @@
|
||||
# as the version being generated
|
||||
(print "#define JANET_BUILD \"" janet/build "\"")
|
||||
|
||||
(print ```#define JANET_AMALG
|
||||
#include "janet.h"```)
|
||||
(print ```#define JANET_AMALG```)
|
||||
(print ```#include "janet.h"```)
|
||||
|
||||
(each h headers (dofile h))
|
||||
(each s sources (dofile s))
|
||||
|
||||
# Relies on this file being built
|
||||
# Relies on these files being built
|
||||
(dofile "build/core.gen.c")
|
||||
(dofile "build/core_image.c")
|
||||
|
||||
55
tools/bars.janet
Normal file
55
tools/bars.janet
Normal file
@@ -0,0 +1,55 @@
|
||||
# A flexible templater for janet. Compiles
|
||||
# templates to janet functions that produce buffers.
|
||||
|
||||
(defn template
|
||||
"Compile a template string into a function"
|
||||
[source]
|
||||
|
||||
# State for compilation machine
|
||||
(def p (parser/new))
|
||||
(def forms @[])
|
||||
|
||||
(defn parse-chunk
|
||||
"Parse a string and push produced values to forms."
|
||||
[chunk]
|
||||
(parser/consume p chunk)
|
||||
(while (parser/has-more p)
|
||||
(array/push forms (parser/produce p)))
|
||||
(if (= :error (parser/status p))
|
||||
(error (parser/error p))))
|
||||
|
||||
(defn code-chunk
|
||||
"Parse all the forms in str and return them
|
||||
in a tuple prefixed with 'do."
|
||||
[str]
|
||||
(parse-chunk str)
|
||||
true)
|
||||
|
||||
(defn string-chunk
|
||||
"Insert string chunk into parser"
|
||||
[str]
|
||||
(parser/insert p str)
|
||||
(parse-chunk "")
|
||||
true)
|
||||
|
||||
# Run peg
|
||||
(def grammar
|
||||
~{:code-chunk (* "{%" (drop (cmt '(any (if-not "%}" 1)) ,code-chunk)) "%}")
|
||||
:main-chunk (drop (cmt '(any (if-not "{%" 1)) ,string-chunk))
|
||||
:main (any (+ :code-chunk :main-chunk (error "")))})
|
||||
(def parts (peg/match grammar source))
|
||||
|
||||
# Check errors in template and parser
|
||||
(unless parts (error "invalid template syntax"))
|
||||
(parse-chunk "\n")
|
||||
(case (parser/status p)
|
||||
:pending (error (string "unfinished parser state " (parser/state p)))
|
||||
:error (error (parser/error p)))
|
||||
|
||||
# Make ast from forms
|
||||
(def ast ~(fn [params &] (default params @{}) (,buffer ;forms)))
|
||||
|
||||
(def ctor (compile ast *env* source))
|
||||
(if-not (function? ctor)
|
||||
(error (string "could not compile template")))
|
||||
(ctor))
|
||||
@@ -79,14 +79,14 @@
|
||||
(defn- make-define
|
||||
"Generate strings for adding custom defines to the compiler."
|
||||
[define value]
|
||||
(def prefix (if is-win "\\D" "-D"))
|
||||
(def prefix (if is-win "/D" "-D"))
|
||||
(if value
|
||||
(string prefix define "=" value)
|
||||
(string prefix define)))
|
||||
|
||||
(defn- make-defines
|
||||
"Generate many defines. Takes a dictionary of defines. If a value is
|
||||
true, generates -DNAME (\\DNAME on windows), otherwise -DNAME=value."
|
||||
true, generates -DNAME (/DNAME on windows), otherwise -DNAME=value."
|
||||
[defines]
|
||||
(seq [[d v] :pairs defines] (make-define d (if (not= v true) v))))
|
||||
|
||||
@@ -94,7 +94,7 @@
|
||||
(def OPTIMIZE 2)
|
||||
(def CC (if is-win "cl" "cc"))
|
||||
(def LD (if is-win "link" (string CC " -shared")))
|
||||
(def CFLAGS (string (if is-win "/0" "-std=c99 -Wall -Wextra -fpic -O") OPTIMIZE))
|
||||
(def CFLAGS (string (if is-win "/O" "-std=c99 -Wall -Wextra -fpic -O") OPTIMIZE))
|
||||
|
||||
(defn- compile-c
|
||||
"Compile a C file into an object file."
|
||||
@@ -112,11 +112,12 @@
|
||||
[opts target & objects]
|
||||
(def ld (or (opts :linker) LD))
|
||||
(def cflags (or (opts :cflags) CFLAGS))
|
||||
(def lflags (or (opts :lflags) ""))
|
||||
(def olist (string/join objects " "))
|
||||
(if (older-than-some target objects)
|
||||
(if is-win
|
||||
(shell ld "/out:" target " " olist)
|
||||
(shell ld " " cflags " -o " target " " olist))))
|
||||
(shell ld " /DLL /OUT:" target " " olist " %JANET_PATH%\\janet.lib")
|
||||
(shell ld " " cflags " -o " target " " olist " " lflags))))
|
||||
|
||||
(defn- create-buffer-c
|
||||
"Inline raw byte file as a c file."
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
# Tool to dump a marshalled version of the janet core to stdout. The
|
||||
# image should eventually allow janet to be started from a pre-compiled
|
||||
# image rather than recompiled every time from the embedded source. More
|
||||
# work will go into shrinking the image (it isn't currently that large but
|
||||
# could be smaller), creating the mechanism to load the image, and modifying
|
||||
# the build process to compile janet with a built image rather than
|
||||
# embedded source.
|
||||
|
||||
# Get image. This image contains as much of the core library and documentation that
|
||||
# can be written to an image (no cfunctions, no abstracts (stdout, stdin, stderr)),
|
||||
# everything else goes. Cfunctions and abstracts will be referenced from a register
|
||||
# table which will be generated on janet startup.
|
||||
(def image (let [env-pairs (pairs (env-lookup *env*))
|
||||
essential-pairs (filter (fn [[k v]] (or (cfunction? v) (abstract? v))) env-pairs)
|
||||
lookup (table ;(mapcat identity essential-pairs))
|
||||
reverse-lookup (invert lookup)]
|
||||
(marshal (table/getproto *env*) reverse-lookup)))
|
||||
|
||||
# Write image
|
||||
(file/write stdout image)
|
||||
(file/flush stdout)
|
||||
Reference in New Issue
Block a user