1
0
mirror of https://github.com/janet-lang/janet synced 2025-11-22 18:24:49 +00:00

Compare commits

...

69 Commits

Author SHA1 Message Date
Calvin Rose
0ce5acec89 Begin cleaning up string API.
Remove string/pretty in favor of buffer/format and string/format. Also
drop string/number, which is more verbose and less flexible than
string/format.
2019-02-16 15:12:34 -05:00
Calvin Rose
44e31cac5d Merge pull request #40 from jfcap/string-format
string/format
2019-02-16 15:02:47 -05:00
Calvin Rose
029394db31 Add buffer/format as well as string/format.
buffer/format uses the old string/format behavior. `string/format` no
longer requires a buffer, and returns a string.
2019-02-16 13:59:38 -05:00
Calvin Rose
00020ba8ab Whitspace and style changes. 2019-02-16 13:40:51 -05:00
Calvin Rose
1f91ee30fe Make require simpler and module/find more useful.
This replaces a lot of the functionality in require by moving
it to module/find. module/native-paths and module/image-paths are also
merged into the one module/paths to make it easier to extend. This of
course breaks some of the less important API - module/native-paths no
longer exists.
2019-02-16 13:21:29 -05:00
J.-F. Cap
0f0c415bcf Adde some tests for string/format 2019-02-16 16:28:10 +01:00
J.-F. Cap
a6f022a73d Added string/format function (snprintf like) 2019-02-16 03:29:04 +01:00
Calvin Rose
ec02d55145 Update README to show sourcehut build. 2019-02-15 19:58:25 -05:00
Calvin Rose
cb1a773ca8 Update sr.ht build. 2019-02-15 19:43:30 -05:00
Calvin Rose
0dc1217d69 Merge pull request #36 from charles-l/master
Update makefile for OpenBSD
2019-02-15 19:07:10 -05:00
charles
06f38d3380 Update makefile for OpenBSD 2019-02-15 19:02:14 -05:00
Calvin Rose
2e1ec3700d Fix compilier warning on -Os, gcc. 2019-02-15 19:01:47 -05:00
Calvin Rose
9e6b1d1b16 Add images.
Images are precompiled libraries. They can be created programmatically
via the `write-image` function and then loaded with `require` or
`import`. They can also be run by the command line tool - you must
specify the path to the image without the .jimage extension.
2019-02-15 18:56:41 -05:00
Calvin Rose
bdf03b4706 Fix unmarshalling integers directly, not through readint. 2019-02-15 14:01:32 -05:00
Calvin Rose
4d96ba3ba9 Merge branch 'master' of github.com:janet-lang/janet 2019-02-15 13:21:00 -05:00
Calvin Rose
f161002390 Address #35 2019-02-15 13:20:20 -05:00
Calvin Rose
eb576d6caf Merge pull request #33 from jfcap/master
Fix buffer (and string) used as callee for indexing.
2019-02-12 20:21:44 -05:00
J.-F. Cap
e0d26629e0 Fix buffer (and string) used as callee for indexing. 2019-02-12 23:40:59 +01:00
Calvin Rose
17783c3c3e Add tuple/brackets
Fix macro expansion via macex for bracketed tuples.
2019-02-11 18:37:59 -05:00
Calvin Rose
c64e92a5de Add some unused math functions.
Several functions from the C math library were
forgotten in the math module. These have been
added to the core library.
2019-02-10 12:03:22 -05:00
Calvin Rose
291c13bafc Merge pull request #32 from jfcap/master
Added math/abs binding
2019-02-10 11:57:28 -05:00
J.-F. Cap
c6672e62ac Added math/abs binding 2019-02-10 14:06:10 +01:00
Calvin Rose
eb9bd38256 Merge branch 'master' of github.com:janet-lang/janet 2019-02-09 12:24:20 -05:00
Calvin Rose
3ac6b2335a Merge pull request #31 from jfcap/crazy-brackets
Crazy brackets
2019-02-09 12:23:41 -05:00
Calvin Rose
c6edf03ae8 Fix some code style, add tuple/type function.
We need to be able to detect tuple type from janet code, otherwise
tuples will contain hidden state. The tuple/type function is able
to detect the flags in the tuple so the programmer can access them
if needed.
2019-02-09 12:21:11 -05:00
J.-F. Cap
5020a1bae9 Added marshalling code to save tuple_flag 2019-02-09 17:00:35 +01:00
J.-F. Cap
86ba69c16b Merge remote-tracking branch 'upstream/master' into crazy-brackets 2019-02-08 23:45:55 +01:00
J.-F. Cap
5f70024f87 Experimental stuffs with bracket syntax 2019-02-08 21:49:28 +01:00
Calvin Rose
9ff819a4a1 Fix build_win.bat 2019-02-08 15:02:36 -05:00
Calvin Rose
1244e2e93b Update changelog 2019-02-08 13:45:04 -05:00
Calvin Rose
b61d1a0a0e Try to update windows build for core image. 2019-02-08 13:37:14 -05:00
Calvin Rose
89ef4eb634 Update emscripten build. 2019-02-08 11:04:33 -05:00
Calvin Rose
114a45306d Add more specialization for marshaling integers.
This decreases the core image size by about 16.5k.
2019-02-08 10:14:36 -05:00
Calvin Rose
fe27df528c Boot core library from image rather than source
This should speed up start time and reduce malloc/free
usage to about 15% of what is what previously for startup.
The current cost is slightly larger binary as the representaion
of the image is currently less compact than source code.
2019-02-08 00:44:30 -05:00
J.-F. Cap
8ab60e475a typo in janet_indexed_view
(no consequence but look strange)
2019-02-08 01:10:07 +01:00
Calvin Rose
6321c30cb1 Add methods for file io. 2019-02-06 17:58:27 -05:00
Calvin Rose
8343c9edd1 Update example to use API. 2019-02-05 19:49:10 -05:00
Calvin Rose
74e1a3273f Add method syntax to parser. 2019-02-05 19:43:41 -05:00
Calvin Rose
1394dbbd57 Update license to include contributors.
Use 4 spaces for indentation.
2019-02-05 19:11:43 -05:00
Calvin Rose
f6a3853131 Merge pull request #30 from jfcap/get-set-abstract
Get set abstract
2019-02-05 19:09:56 -05:00
J.-F. Cap
49465f71f3 Added a simple C module to test getter/setter. 2019-02-05 18:45:04 +01:00
J.-F. Cap
960cf76eb5 Experimental getter/setter for abstract types 2019-02-05 17:14:13 +01:00
Calvin Rose
1b735564fa Update copyright. 2019-02-03 15:34:41 -05:00
Calvin Rose
7ae01d25dd Merge branch 'master' of github.com:janet-lang/janet 2019-02-03 15:32:53 -05:00
Calvin Rose
cb5263d2d8 Remove extra comment. 2019-02-03 15:32:39 -05:00
Calvin Rose
602092f6d5 Merge pull request #29 from honix/master
Gitter badge added
2019-02-02 18:06:06 -05:00
Fyodor Shchukin
d3a067a665 Gitter badge added 2019-02-02 10:30:15 +03:00
J.-F. Cap
98a26f5ce3 Merge remote-tracking branch 'upstream/master' 2019-02-02 00:38:29 +01:00
Calvin Rose
09d9dca5f5 Add Gitter channel to README.md 2019-02-01 13:43:16 -05:00
Calvin Rose
8a3f512746 Experimental changes to janet_call to make it faster.
Remove setjmp and fiber creationg from janet_call. This
adds the constraint to janet_call can only be called when there
is already a current fiber.
2019-02-01 11:56:25 -05:00
Calvin Rose
19e59705b9 Main rule in peg is always 0
After we changed peg bytecode emission to
preallocate space for an instruction before
emitting sub rules, the rules are numbered
in the order that they are compiled. This means
that the main rule is always 0.
We can remove the explicitly stored main rule in
the peg structure.
2019-01-31 23:39:33 -05:00
Calvin Rose
367c9da856 Fix some typos and update style.
Add bars.janet tool for templating arbitrary
strings, especially HTML.
2019-01-31 22:38:59 -05:00
Calvin Rose
4bcf6565cd Add parser/insert and bump to 0.4.0 2019-01-31 14:48:28 -05:00
Calvin Rose
0c950d0846 Fix emscripten build. 2019-01-31 13:02:09 -05:00
Calvin Rose
7ba925c50a Make getline more useful. 2019-01-31 12:34:22 -05:00
Calvin Rose
cb3b9dd76f Update changelog an fix typos. 2019-01-31 10:09:34 -05:00
Calvin Rose
f4fa55027b Merge pull request #27 from jfcap/master
Added :lflags option to cook/make-native
2019-01-31 09:39:59 -05:00
J.-F. Cap
0fe11adb9c typo in REAME.md 2019-01-31 13:52:57 +01:00
J.-F. Cap
b138ee6e8e Added :lflags option to cook/make-native 2019-01-31 13:30:37 +01:00
Calvin Rose
a66f19f636 Merge branch 'master' of github.com:janet-lang/janet 2019-01-30 23:11:42 -05:00
Calvin Rose
c76f4e89d8 Remove redundancies in stacktraces.
There was an implementation for stacktraces in both
run.c and in core.janet, status-pp. The commit removes
the one in core.janet in favor of the C based stacktrace, which
is exposed via debug/stacktrace. Lots of reshuffling of run-context
ensued as well, which resulted in an api that is a bit cleaner.
2019-01-30 23:11:12 -05:00
Calvin Rose
85a211b26b Remove extra vector function. 2019-01-30 21:22:40 -05:00
Calvin Rose
fe3620529f Merge pull request #26 from honix/master
Cooking on windows
2019-01-30 10:13:35 -05:00
Fyodor Shchukin
a7551e9b4e Cooking on windows 2019-01-30 17:31:53 +03:00
Calvin Rose
46c540b93e Add math headers for emscripten
We now check for NaN in table.c and struct.c
as we disallow NaN keys.
2019-01-29 18:18:14 -05:00
Calvin Rose
32c209ede9 Address #25 2019-01-29 13:59:08 -05:00
Calvin Rose
0d293cd3f5 Update require to use real path name rather than module name. 2019-01-28 21:48:13 -05:00
Calvin Rose
f284776490 Address #24 2019-01-28 20:30:45 -05:00
Calvin Rose
38a7e4faf1 Disallow NaN as table/struct key.
Fix bugs and add tests for denormalized tables
and structs.
2019-01-28 11:50:33 -05:00
54 changed files with 1385 additions and 533 deletions

View File

@@ -1,4 +1,4 @@
image: freebsd
image: freebsd/latest
packages:
- gmake
- gcc

View File

@@ -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

View File

@@ -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

View File

@@ -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 $@ $^
#########################

View File

@@ -1,5 +1,8 @@
[![Join the chat](https://badges.gitter.im/janet-language/community.svg)](https://gitter.im/janet-language/community)
&nbsp;
[![Build Status](https://travis-ci.org/janet-lang/janet.svg?branch=master)](https://travis-ci.org/janet-lang/janet)
[![Appveyor Status](https://ci.appveyor.com/api/projects/status/32r7s2skrgm9ubva?svg=true)](https://ci.appveyor.com/project/janet-lang/janet)
[![builds.sr.ht status](https://builds.sr.ht/~bakpakin/janet/.freebsd.yaml.svg)](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

View File

@@ -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

View 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))

View 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
View 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
View 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))

View 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);
}

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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 *)

View File

@@ -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]);

View File

@@ -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);
}

View File

@@ -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)

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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."));
}

View 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);
}

View File

@@ -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),

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}
}
}

View File

@@ -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');

View File

@@ -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());
}

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;
}
}
}

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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);

View File

@@ -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()) {

View File

@@ -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

View File

@@ -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;

View File

@@ -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]

View File

@@ -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)

View File

@@ -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")

View File

@@ -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
View 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)

View File

@@ -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
View 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))

View File

@@ -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."

View 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)