mirror of
https://github.com/janet-lang/janet
synced 2025-11-09 03:53:06 +00:00
Compare commits
93 Commits
v0.5.0
...
posix_spaw
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
26513a7a16 | ||
|
|
d005ac6888 | ||
|
|
7fdb098a20 | ||
|
|
a4a200e037 | ||
|
|
15d95d8803 | ||
|
|
46950a8cb3 | ||
|
|
4867cab569 | ||
|
|
c8cf7c2445 | ||
|
|
1b63215aad | ||
|
|
bcbe42ab23 | ||
|
|
c8c6419013 | ||
|
|
e8516c29e0 | ||
|
|
12247bd958 | ||
|
|
9d30d5f6e3 | ||
|
|
ba0956488d | ||
|
|
31f502b508 | ||
|
|
efaaead378 | ||
|
|
4d47d92a4a | ||
|
|
b39ad97a87 | ||
|
|
af23040d9c | ||
|
|
fd2d706e33 | ||
|
|
178d175bcf | ||
|
|
7a7f586094 | ||
|
|
5124587c96 | ||
|
|
6c897b1a37 | ||
|
|
c6ac53f4be | ||
|
|
2d7812a06c | ||
|
|
db55277b58 | ||
|
|
75818217a6 | ||
|
|
486b80fa7b | ||
|
|
873054d055 | ||
|
|
f12f896020 | ||
|
|
09ab391d13 | ||
|
|
7569930b0c | ||
|
|
e7189438dd | ||
|
|
3c304ddc35 | ||
|
|
1696de233c | ||
|
|
ce9cd4fcef | ||
|
|
698e89aba4 | ||
|
|
4c8dd4b96c | ||
|
|
11998b3913 | ||
|
|
840610facf | ||
|
|
0280deccae | ||
|
|
4d5a95784a | ||
|
|
b43d93cf55 | ||
|
|
3f137ed0b1 | ||
|
|
5deb13d73e | ||
|
|
82a1c8635e | ||
|
|
010e2e4652 | ||
|
|
ddedae6831 | ||
|
|
6c63c4f129 | ||
|
|
802686e3df | ||
|
|
3be79e8735 | ||
|
|
a303704a7d | ||
|
|
b5e6c0b8fc | ||
|
|
98c46fcfb1 | ||
|
|
409da697dd | ||
|
|
91c3685705 | ||
|
|
411fc77ecf | ||
|
|
0378ba78cc | ||
|
|
55d8e8b56b | ||
|
|
97ad4c4f89 | ||
|
|
8de999c8f7 | ||
|
|
f444bd25ef | ||
|
|
43c0db4b0e | ||
|
|
8f168c600d | ||
|
|
ec43afb426 | ||
|
|
880049c0ee | ||
|
|
2b7ac16784 | ||
|
|
56d903d75b | ||
|
|
7054e878fb | ||
|
|
dde5351d11 | ||
|
|
7d49e3e6f1 | ||
|
|
30cb01e2f0 | ||
|
|
018e836ef5 | ||
|
|
7b25125431 | ||
|
|
0aa2f68793 | ||
|
|
516e031f67 | ||
|
|
3331f2fa02 | ||
|
|
dd1a199ebd | ||
|
|
f35b5765d6 | ||
|
|
8359044408 | ||
|
|
9f3dde3cc7 | ||
|
|
ad0f7d9b0d | ||
|
|
f647ac5631 | ||
|
|
e4c5eb4c76 | ||
|
|
dc9fc9c3f5 | ||
|
|
3b6a51df24 | ||
|
|
f2313b9959 | ||
|
|
805b3bbb88 | ||
|
|
232ea22dc5 | ||
|
|
3388acd2db | ||
|
|
52ab9fb475 |
@@ -1,11 +1,11 @@
|
||||
image: freebsd/latest
|
||||
packages:
|
||||
- gmake
|
||||
- gcc
|
||||
tasks:
|
||||
- build: |
|
||||
cd janet
|
||||
gmake CC=gcc
|
||||
gmake test CC=gcc
|
||||
sudo gmake install CC=gcc
|
||||
gmake test-install CC=gcc
|
||||
gmake
|
||||
gmake test
|
||||
sudo gmake install
|
||||
gmake test-install
|
||||
gmake test-amalg
|
||||
|
||||
11
.builds/.openbsd.yaml
Normal file
11
.builds/.openbsd.yaml
Normal file
@@ -0,0 +1,11 @@
|
||||
image: openbsd/6.5
|
||||
packages:
|
||||
- gmake
|
||||
tasks:
|
||||
- build: |
|
||||
cd janet
|
||||
gmake
|
||||
gmake test
|
||||
doas gmake install
|
||||
gmake test-install
|
||||
gmake test-amalg
|
||||
@@ -4,6 +4,7 @@ script:
|
||||
- make test
|
||||
- sudo make install
|
||||
- make test-install
|
||||
- make test-amalg
|
||||
- make build/janet-${TRAVIS_TAG}-${TRAVIS_OS_NAME}.tar.gz
|
||||
compiler:
|
||||
- clang
|
||||
|
||||
29
CHANGELOG.md
29
CHANGELOG.md
@@ -1,6 +1,33 @@
|
||||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## Unreleased
|
||||
- Add API compatibility checking for modules. This will let native modules not load
|
||||
when the host program is not of a compatible version or configuration.
|
||||
- Change signature of `os/execute` to be much more flexible.
|
||||
|
||||
## 0.6.0 - 2019-05-29
|
||||
- `file/close` returns exit code when closing file opened with `file/popen`.
|
||||
- Add `os/rename`
|
||||
- Update windows installer to include tools like `jpm`.
|
||||
- Add `jpm` tool for building and managing projects.
|
||||
- Change interface to `cook` tool.
|
||||
- Add optional filters to `module/paths` to further refine import methods.
|
||||
- Add keyword arguments via `&keys` in parameter list.
|
||||
- Add `-k` flag for flychecking source.
|
||||
- Change signature to `compile` function.
|
||||
- Add `module/loaders` for custom loading functions.
|
||||
- Add external unification to `match` macro.
|
||||
- Add static library to main build.
|
||||
- Add `janet/*headerpath*` and change location of installed headers.
|
||||
- Let `partition` take strings.
|
||||
- Haiku OS support
|
||||
- Add `string/trim`, `string/trimr`, and `string/triml`.
|
||||
- Add `dofile` function.
|
||||
- Numbers require at least 1 significant digit.
|
||||
- `file/read` will return nil on end of file.
|
||||
- Fix various bugs.
|
||||
|
||||
## 0.5.0 - 2019-05-09
|
||||
- Fix some bugs with buffers.
|
||||
- Add `trace` and `untrace` to the core library.
|
||||
@@ -61,7 +88,7 @@ All notable changes to this project will be documented in this file.
|
||||
- Disallow NaNs as table or struct keys
|
||||
- Update module resolution paths and format
|
||||
|
||||
## 0.3.0 - 2019-26-01
|
||||
## 0.3.0 - 2019-01-26
|
||||
- Add amalgamated build to janet for easier embedding.
|
||||
- Add os/date function
|
||||
- Add slurp and spit to core library.
|
||||
|
||||
91
Makefile
91
Makefile
@@ -31,8 +31,10 @@ JANET_BUILD?="\"$(shell git log --pretty=format:'%h' -n 1)\""
|
||||
CLIBS=-lm
|
||||
JANET_TARGET=build/janet
|
||||
JANET_LIBRARY=build/libjanet.so
|
||||
JANET_STATIC_LIBRARY=build/libjanet.a
|
||||
JANET_PATH?=$(PREFIX)/lib/janet
|
||||
MANPATH?=$(PREFIX)/share/man/man1/
|
||||
PKG_CONFIG_PATH?=$(PREFIX)/lib/pkgconfig
|
||||
DEBUGGER=gdb
|
||||
|
||||
CFLAGS=-std=c99 -Wall -Wextra -Isrc/include -fpic -O2 -fvisibility=hidden \
|
||||
@@ -47,9 +49,12 @@ else ifeq ($(UNAME), Linux)
|
||||
CLIBS:=$(CLIBS) -lrt -ldl
|
||||
endif
|
||||
# For other unix likes, add flags here!
|
||||
ifeq ($(UNAME),Haiku)
|
||||
LDFLAGS=-Wl,--export-dynamic
|
||||
endif
|
||||
|
||||
$(shell mkdir -p build/core build/mainclient build/webclient build/boot)
|
||||
all: $(JANET_TARGET) $(JANET_LIBRARY)
|
||||
all: $(JANET_TARGET) $(JANET_LIBRARY) $(JANET_STATIC_LIBRARY)
|
||||
|
||||
######################
|
||||
##### Name Files #####
|
||||
@@ -130,7 +135,7 @@ build/janet_boot: $(JANET_BOOT_OBJECTS)
|
||||
|
||||
# Now the reason we bootstrap in the first place
|
||||
build/core_image.c: build/janet_boot
|
||||
build/janet_boot $@ JANET_PATH $(JANET_PATH)
|
||||
build/janet_boot $@ JANET_PATH $(JANET_PATH) JANET_HEADERPATH $(INCLUDEDIR)/janet
|
||||
|
||||
##########################################################
|
||||
##### The main interpreter program and shared object #####
|
||||
@@ -152,6 +157,9 @@ $(JANET_TARGET): $(JANET_CORE_OBJECTS) $(JANET_MAINCLIENT_OBJECTS)
|
||||
$(JANET_LIBRARY): $(JANET_CORE_OBJECTS)
|
||||
$(CC) $(LDFLAGS) $(CFLAGS) -shared -o $@ $^ $(CLIBS)
|
||||
|
||||
$(JANET_STATIC_LIBRARY): $(JANET_CORE_OBJECTS)
|
||||
$(AR) rcs $@ $^
|
||||
|
||||
######################
|
||||
##### Emscripten #####
|
||||
######################
|
||||
@@ -245,7 +253,7 @@ dist: build/janet-dist.tar.gz
|
||||
|
||||
build/janet-%.tar.gz: $(JANET_TARGET) \
|
||||
src/include/janet.h src/include/janetconf.h \
|
||||
janet.1 LICENSE CONTRIBUTING.md $(JANET_LIBRARY) \
|
||||
janet.1 LICENSE CONTRIBUTING.md $(JANET_LIBRARY) $(JANET_STATIC_LIBRARY) \
|
||||
build/doc.html README.md build/janet.c
|
||||
tar -czvf $@ $^
|
||||
|
||||
@@ -258,6 +266,47 @@ docs: build/doc.html
|
||||
build/doc.html: $(JANET_TARGET) tools/gendoc.janet
|
||||
$(JANET_TARGET) tools/gendoc.janet > build/doc.html
|
||||
|
||||
########################
|
||||
##### Installation #####
|
||||
########################
|
||||
|
||||
SONAME=libjanet.so.1
|
||||
|
||||
.PHONY: $(PKG_CONFIG_PATH)/janet.pc
|
||||
$(PKG_CONFIG_PATH)/janet.pc: $(JANET_TARGET)
|
||||
mkdir -p $(PKG_CONFIG_PATH)
|
||||
echo 'prefix=$(PREFIX)' > $@
|
||||
echo 'exec_prefix=$${prefix}' >> $@
|
||||
echo 'includedir=$(INCLUDEDIR)/janet' >> $@
|
||||
echo 'libdir=$(LIBDIR)' >> $@
|
||||
echo "" >> $@
|
||||
echo "Name: janet" >> $@
|
||||
echo "Url: https://janet-lang.org" >> $@
|
||||
echo "Description: Library for the Janet programming language." >> $@
|
||||
$(JANET_TARGET) -e '(print "Version: " janet/version)' >> $@
|
||||
echo 'Cflags: -I$${includedir}' >> $@
|
||||
echo 'Libs: -L$${libdir} -ljanet $(LDFLAGS)' >> $@
|
||||
echo 'Libs.private: $(CLIBS)' >> $@
|
||||
|
||||
install: $(JANET_TARGET) $(PKG_CONFIG_PATH)/janet.pc
|
||||
mkdir -p $(BINDIR)
|
||||
cp $(JANET_TARGET) $(BINDIR)/janet
|
||||
mkdir -p $(INCLUDEDIR)/janet
|
||||
cp -rf $(JANET_HEADERS) $(INCLUDEDIR)/janet
|
||||
mkdir -p $(JANET_PATH)
|
||||
mkdir -p $(LIBDIR)
|
||||
cp $(JANET_LIBRARY) $(LIBDIR)/libjanet.so.$(shell $(JANET_TARGET) -e '(print janet/version)')
|
||||
cp $(JANET_STATIC_LIBRARY) $(LIBDIR)/libjanet.a
|
||||
ln -sf $(SONAME) $(LIBDIR)/libjanet.so
|
||||
ln -sf libjanet.so.$(shell $(JANET_TARGET) -e '(print janet/version)') $(LIBDIR)/$(SONAME)
|
||||
cp tools/cook.janet $(JANET_PATH)
|
||||
cp tools/jpm $(BINDIR)/jpm
|
||||
cp tools/highlight.janet $(JANET_PATH)
|
||||
cp tools/bars.janet $(JANET_PATH)
|
||||
mkdir -p $(MANPATH)
|
||||
cp janet.1 $(MANPATH)
|
||||
-ldconfig $(LIBDIR)
|
||||
|
||||
#################
|
||||
##### Other #####
|
||||
#################
|
||||
@@ -272,32 +321,18 @@ build/janet.tmLanguage: tools/tm_lang_gen.janet $(JANET_TARGET)
|
||||
clean:
|
||||
-rm -rf build vgcore.* callgrind.*
|
||||
|
||||
build/version.txt: $(JANET_TARGET)
|
||||
$(JANET_TARGET) -e '(print janet/version)' > $@
|
||||
|
||||
SONAME=libjanet.so.0
|
||||
install: $(JANET_TARGET) build/version.txt
|
||||
mkdir -p $(BINDIR)
|
||||
cp $(JANET_TARGET) $(BINDIR)/janet
|
||||
mkdir -p $(INCLUDEDIR)
|
||||
cp $(JANET_HEADERS) $(INCLUDEDIR)
|
||||
mkdir -p $(LIBDIR)
|
||||
cp $(JANET_LIBRARY) $(LIBDIR)/libjanet.so.$(shell cat build/version.txt)
|
||||
ln -sf $(SONAME) $(LIBDIR)/libjanet.so
|
||||
ln -sf libjanet.so.$(shell cat build/version.txt) $(LIBDIR)/$(SONAME)
|
||||
mkdir -p $(INCLUDEDIR)/janet
|
||||
mkdir -p $(JANET_PATH)
|
||||
ln -sf $(INCLUDEDIR)/janet.h $(JANET_PATH)/janet.h
|
||||
ln -sf $(INCLUDEDIR)/janetconf.h $(JANET_PATH)/janetconf.h
|
||||
cp tools/cook.janet $(JANET_PATH)
|
||||
cp tools/highlight.janet $(JANET_PATH)
|
||||
cp tools/bars.janet $(JANET_PATH)
|
||||
mkdir -p $(MANPATH)
|
||||
cp janet.1 $(MANPATH)
|
||||
-ldconfig $(LIBDIR)
|
||||
|
||||
test-install:
|
||||
cd test/install && rm -rf build && janet build && janet build
|
||||
cd test/install && rm -rf build && jpm build && jpm test
|
||||
|
||||
build/embed_janet.o: build/janet.c $(JANET_HEADERS)
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
build/embed_main.o: test/amalg/main.c $(JANET_HEADERS)
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
build/embed_test: build/embed_janet.o build/embed_main.o
|
||||
$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $^ $(CLIBS)
|
||||
|
||||
test-amalg: build/embed_test
|
||||
./build/embed_test
|
||||
|
||||
uninstall:
|
||||
-rm $(BINDIR)/../$(JANET_TARGET)
|
||||
|
||||
34
README.md
34
README.md
@@ -3,6 +3,7 @@
|
||||
[](https://ci.appveyor.com/project/bakpakin/janet/branch/master)
|
||||
[](https://travis-ci.org/janet-lang/janet)
|
||||
[](https://builds.sr.ht/~bakpakin/janet/.freebsd.yaml?)
|
||||
[](https://builds.sr.ht/~bakpakin/janet/.openbsd.yaml?)
|
||||
|
||||
<img src="https://raw.githubusercontent.com/janet-lang/janet/master/assets/janet-w200.png" alt="Janet logo" width=200 align="left">
|
||||
|
||||
@@ -79,15 +80,28 @@ make test
|
||||
make repl
|
||||
```
|
||||
|
||||
### FreeBSD
|
||||
### 32-bit Haiku
|
||||
|
||||
FreeBSD build instructions are the same as the unix-like build instuctions,
|
||||
but you need `gmake` and `gcc` to compile.
|
||||
32-bit Haiku build instructions are the same as the unix-like build instructions,
|
||||
but you need to specify an alternative compiler, such as `gcc-x86`.
|
||||
|
||||
```
|
||||
cd somewhere/my/projects/janet
|
||||
gmake CC=gcc
|
||||
gmake test CC=gcc
|
||||
make CC=gcc-x86
|
||||
make test
|
||||
make repl
|
||||
```
|
||||
|
||||
### FreeBSD
|
||||
|
||||
FreeBSD build instructions are the same as the unix-like build instuctions,
|
||||
but you need `gmake` to compile. Alternatively, install directly from
|
||||
packages, using `pkg install lang/janet`.
|
||||
|
||||
```
|
||||
cd somewhere/my/projects/janet
|
||||
gmake
|
||||
gmake test
|
||||
gmake repl
|
||||
```
|
||||
|
||||
@@ -172,6 +186,16 @@ See the examples directory for some example janet code.
|
||||
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/)
|
||||
|
||||
## FAQ
|
||||
|
||||
### Why is my terminal is spitting out junk when I run the repl?
|
||||
|
||||
Make sure your terminal supports ANSI escape codes. Most modern terminals will
|
||||
support these, but some older terminals, windows consoles, or embedded terminals
|
||||
will not. If your terminal does not support ANSI escape codes, run the repl with
|
||||
the `-n` flag, which disables color output. You can also try the `-s` if further issues
|
||||
ensue.
|
||||
|
||||
## Why Janet
|
||||
|
||||
Janet is named after the almost omniscient and friendly artificial being in [The Good Place](https://en.wikipedia.org/wiki/The_Good_Place).
|
||||
|
||||
@@ -21,9 +21,8 @@ install:
|
||||
- build_win
|
||||
- build_win test
|
||||
- choco install nsis -y -pre
|
||||
- call "C:\Program Files (x86)\NSIS\makensis.exe" janet-installer.nsi
|
||||
- build_win dist
|
||||
- copy janet-install.exe dist\install.exe
|
||||
- call "C:\Program Files (x86)\NSIS\makensis.exe" janet-installer.nsi
|
||||
|
||||
build: off
|
||||
|
||||
@@ -33,9 +32,9 @@ only_commits:
|
||||
- src/
|
||||
|
||||
artifacts:
|
||||
- path: dist
|
||||
name: janet-windows
|
||||
type: Zip
|
||||
- path: janet-installer.exe
|
||||
name: janet-windows-installer.exe
|
||||
type: File
|
||||
|
||||
deploy:
|
||||
description: 'The Janet Programming Language.'
|
||||
|
||||
BIN
assets/icon.ico
Normal file
BIN
assets/icon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 100 KiB |
11
assets/icon_svg.svg
Normal file
11
assets/icon_svg.svg
Normal file
@@ -0,0 +1,11 @@
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg" width="64px" height="64px" viewBox="0 0 640 640" preserveAspectRatio="xMidYMid meet">
|
||||
<g id="layer101" fill="#d45500" stroke="none">
|
||||
<path d="M145 531 c-46 -31 -58 -75 -30 -118 21 -32 30 -22 44 47 7 30 19 62 27 71 26 29 1 29 -41 0z"/>
|
||||
<path d="M341 534 c-23 -29 -26 -50 -11 -88 10 -28 64 -60 86 -52 12 5 12 2 0 -22 -24 -47 -51 -64 -116 -71 -51 -6 -65 -12 -85 -37 -14 -16 -24 -32 -25 -36 0 -12 -35 -9 -48 4 -7 7 -12 24 -12 38 0 41 -11 43 -47 8 -47 -46 -46 -90 5 -138 20 -19 49 -51 63 -70 l27 -35 88 0 c49 0 106 4 127 8 46 10 106 62 143 125 25 42 28 58 30 142 0 52 4 103 9 113 11 27 -14 75 -49 93 -41 21 -115 44 -143 44 -12 0 -31 -12 -42 -26z m89 -119 c0 -3 -2 -5 -5 -5 -3 0 -5 2 -5 5 0 3 2 5 5 5 3 0 5 -2 5 -5z"/>
|
||||
</g>
|
||||
<g id="layer102" fill="#deaa87" stroke="none">
|
||||
<path d="M186 549 c-33 -31 -38 -43 -56 -137 -26 -135 -26 -163 3 -190 33 -31 49 -28 85 17 28 35 36 39 87 43 46 4 61 10 90 38 18 18 39 46 46 62 10 25 9 32 -5 46 -17 16 -19 16 -29 1 -8 -14 -15 -15 -34 -6 -27 12 -40 65 -24 96 10 17 8 23 -12 36 -13 8 -44 18 -69 21 -42 6 -49 4 -82 -27z"/>
|
||||
</g>
|
||||
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -53,7 +53,7 @@ for %%f in (src\boot\*.c) do (
|
||||
)
|
||||
%JANET_LINK% /out:build\janet_boot.exe build\boot\*.obj
|
||||
@if errorlevel 1 goto :BUILDFAIL
|
||||
build\janet_boot build\core_image.c JANET_PATH "C:/Janet/Library"
|
||||
build\janet_boot build\core_image.c
|
||||
|
||||
@rem Build the core image
|
||||
@%JANET_COMPILE% /Fobuild\core_image.obj build\core_image.c
|
||||
@@ -65,6 +65,9 @@ for %%f in (src\core\*.c) do (
|
||||
@if errorlevel 1 goto :BUILDFAIL
|
||||
)
|
||||
|
||||
@rem Build the resources
|
||||
rc /nologo /fobuild\janet_win.res janet_win.rc
|
||||
|
||||
@rem Build the main client
|
||||
for %%f in (src\mainclient\*.c) do (
|
||||
@%JANET_COMPILE% /Fobuild\mainclient\%%~nf.obj %%f
|
||||
@@ -72,9 +75,17 @@ for %%f in (src\mainclient\*.c) do (
|
||||
)
|
||||
|
||||
@rem Link everything to main client
|
||||
%JANET_LINK% /out:janet.exe build\core\*.obj build\mainclient\*.obj build\core_image.obj
|
||||
%JANET_LINK% /out:janet.exe build\core\*.obj build\mainclient\*.obj build\core_image.obj build\janet_win.res
|
||||
@if errorlevel 1 goto :BUILDFAIL
|
||||
|
||||
@rem Gen amlag
|
||||
setlocal enabledelayedexpansion
|
||||
set "amalg_files="
|
||||
for %%f in (src\core\*.c) do (
|
||||
set "amalg_files=!amalg_files! %%f"
|
||||
)
|
||||
janet.exe tools\amalg.janet src\core\util.h src\core\state.h src\core\gc.h src\core\vector.h src\core\fiber.h src\core\regalloc.h src\core\compile.h src\core\emit.h src\core\symcache.h %amalg_files% build\core_image.c > build\janet.c
|
||||
|
||||
echo === Successfully built janet.exe for Windows ===
|
||||
echo === Run 'build_win test' to run tests. ==
|
||||
echo === Run 'build_win clean' to delete build artifacts. ===
|
||||
@@ -113,13 +124,7 @@ exit /b 0
|
||||
mkdir dist
|
||||
janet.exe tools\gendoc.janet > dist\doc.html
|
||||
|
||||
@rem Gen amlag
|
||||
setlocal enabledelayedexpansion
|
||||
set "amalg_files="
|
||||
for %%f in (src\core\*.c) do (
|
||||
set "amalg_files=!amalg_files! %%f"
|
||||
)
|
||||
janet.exe tools\amalg.janet src\core\util.h src\core\state.h src\core\gc.h src\core\vector.h src\core\fiber.h src\core\regalloc.h src\core\compile.h src\core\emit.h src\core\symcache.h %amalg_files% build\core_image.c > dist\janet.c
|
||||
copy build\janet.c dist\janet.c
|
||||
copy janet.exe dist\janet.exe
|
||||
copy LICENSE dist\LICENSE
|
||||
copy README.md dist\README.md
|
||||
@@ -129,6 +134,8 @@ copy src\include\janet.h dist\janet.h
|
||||
copy src\include\janetconf.h dist\janetconf.h
|
||||
copy tools\cook.janet dist\cook.janet
|
||||
copy tools\highlight.janet dist\highlight.janet
|
||||
copy tools\jpm dist\jpm
|
||||
copy tools\jpm.bat dist\jpm.bat
|
||||
exit /b 0
|
||||
|
||||
:TESTFAIL
|
||||
|
||||
@@ -13,4 +13,4 @@
|
||||
(if isprime? (array/push list i)))
|
||||
list)
|
||||
|
||||
(print (string/pretty (primes 100)))
|
||||
(pp (primes 100))
|
||||
|
||||
29
examples/urlloader.janet
Normal file
29
examples/urlloader.janet
Normal file
@@ -0,0 +1,29 @@
|
||||
# An example of using Janet's extensible module system
|
||||
# to import files from URL. To try this, run `janet -l examples/urlloader.janet`
|
||||
# from the repl, and then:
|
||||
#
|
||||
# (import https://raw.githubusercontent.com/janet-lang/janet/master/examples/colors.janet :as c)
|
||||
#
|
||||
# This will import a file using curl. You can then try
|
||||
#
|
||||
# (print (c/color :green "Hello!"))
|
||||
#
|
||||
# This is a bit of a toy example (it just shells out to curl), but it is very
|
||||
# powerful and will work well in many cases.
|
||||
|
||||
(defn- load-url
|
||||
[url args]
|
||||
(def f (file/popen (string "curl " url)))
|
||||
(def res (dofile f :source url ;args))
|
||||
(try (file/close f) ([err] nil))
|
||||
res)
|
||||
|
||||
(defn- check-http-url
|
||||
[path]
|
||||
(if (or (string/has-prefix? "http://" path)
|
||||
(string/has-prefix? "https://" path))
|
||||
path))
|
||||
|
||||
# Add the module loader and path tuple to right places
|
||||
(array/push module/paths [check-http-url :janet-http])
|
||||
(put module/loaders :janet-http load-url)
|
||||
@@ -1,55 +1,157 @@
|
||||
# Version
|
||||
!define VERSION "0.6.0"
|
||||
!define PRODUCT_VERSION "${VERSION}.0"
|
||||
VIProductVersion "${PRODUCT_VERSION}"
|
||||
VIFileVersion "${PRODUCT_VERSION}"
|
||||
|
||||
# Use the modern UI
|
||||
!define MULTIUSER_EXECUTIONLEVEL Highest
|
||||
!define MULTIUSER_MUI
|
||||
!define MULTIUSER_INSTALLMODE_COMMANDLINE
|
||||
!define MULTIUSER_INSTALLMODE_INSTDIR "janet"
|
||||
!define MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_KEY "Software\Janet\${VERSION}"
|
||||
!define MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_VALUENAME ""
|
||||
!define MULTIUSER_INSTALLMODE_INSTDIR_REGISTRY_KEY "Software\Janet\${VERSION}"
|
||||
!define MULTIUSER_INSTALLMODE_INSTDIR_REGISTRY_VALUENAME ""
|
||||
!define MULTIUSER_INSTALLMODE_INSTDIR "Janet-${VERSION}"
|
||||
!include "MultiUser.nsh"
|
||||
!include "MUI2.nsh"
|
||||
|
||||
!include ".\tools\EnvVarUpdate.nsh"
|
||||
|
||||
# Basics
|
||||
Name "Janet"
|
||||
OutFile "janet-install.exe"
|
||||
|
||||
OutFile "janet-v${VERSION}-windows-installer.exe"
|
||||
|
||||
# Some Configuration
|
||||
!define APPNAME "Janet"
|
||||
!define DESCRIPTION "The Janet Programming Language"
|
||||
!define HELPURL "http://janet-lang.org"
|
||||
BrandingText "The Janet Programming Language"
|
||||
|
||||
# MUI Configuration
|
||||
!define MUI_ICON "assets\icon.ico"
|
||||
!define MUI_UNICON "assets\icon.ico"
|
||||
!define MUI_HEADERIMAGE
|
||||
!define MUI_HEADERIMAGE_BITMAP "assets\janet-w200.png"
|
||||
!define MUI_HEADERIMAGE_RIGHT
|
||||
!define MUI_ABORTWARNING
|
||||
|
||||
|
||||
# Show a welcome page first
|
||||
!insertmacro MUI_PAGE_WELCOME
|
||||
!insertmacro MUI_PAGE_LICENSE "LICENSE"
|
||||
!insertmacro MUI_PAGE_COMPONENTS
|
||||
|
||||
# Pick Install Directory
|
||||
!insertmacro MULTIUSER_PAGE_INSTALLMODE
|
||||
!insertmacro MUI_PAGE_DIRECTORY
|
||||
|
||||
!insertmacro MUI_PAGE_INSTFILES
|
||||
|
||||
# Done
|
||||
!insertmacro MUI_PAGE_FINISH
|
||||
|
||||
!insertmacro MUI_UNPAGE_CONFIRM
|
||||
!insertmacro MUI_UNPAGE_INSTFILES
|
||||
|
||||
# Need to set a language.
|
||||
!insertmacro MUI_LANGUAGE "English"
|
||||
|
||||
Section "Janet" BfWSection
|
||||
SetOutPath $INSTDIR
|
||||
File "janet.exe"
|
||||
WriteUninstaller "$INSTDIR\janet-uninstall.exe"
|
||||
|
||||
# Start Menu
|
||||
CreateShortCut "$SMPROGRAMS\Janet.lnk" "$INSTDIR\janet.exe" "" ""
|
||||
SectionEnd
|
||||
function .onInit
|
||||
!insertmacro MULTIUSER_INIT
|
||||
functionEnd
|
||||
|
||||
Function .onInit
|
||||
!insertmacro MULTIUSER_INIT
|
||||
!insertmacro MUI_LANGDLL_DISPLAY
|
||||
FunctionEnd
|
||||
section "Janet" BfWSection
|
||||
createDirectory "$INSTDIR\Library"
|
||||
createDirectory "$INSTDIR\C"
|
||||
createDirectory "$INSTDIR\bin"
|
||||
setOutPath "$INSTDIR"
|
||||
|
||||
file /oname=bin\janet.exe dist\janet.exe
|
||||
file /oname=logo.ico assets\icon.ico
|
||||
|
||||
file /oname=Library\cook.janet dist\cook.janet
|
||||
|
||||
file /oname=C\janet.h dist\janet.h
|
||||
file /oname=C\janetconf.h dist\janetconf.h
|
||||
file /oname=C\janet.lib dist\janet.lib
|
||||
file /oname=C\janet.exp dist\janet.exp
|
||||
file /oname=C\janet.c dist\janet.c
|
||||
|
||||
file /oname=bin\jpm.janet dist\jpm
|
||||
file /oname=bin\jpm.bat dist\jpm.bat
|
||||
|
||||
# Uninstaller - See function un.onInit and section "uninstall" for configuration
|
||||
writeUninstaller "$INSTDIR\uninstall.exe"
|
||||
|
||||
# Start Menu
|
||||
createShortCut "$SMPROGRAMS\Janet.lnk" "$INSTDIR\bin\janet.exe" "" "$INSTDIR\logo.ico"
|
||||
|
||||
# HKLM (all users) vs HKCU (current user)
|
||||
WriteRegExpandStr HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" JANET_PATH "$INSTDIR\Library"
|
||||
WriteRegExpandStr HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" JANET_HEADERPATH "$INSTDIR\C"
|
||||
WriteRegExpandStr HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" JANET_BINPATH "$INSTDIR\bin"
|
||||
|
||||
!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
|
||||
!insertmacro MUI_DESCRIPTION_TEXT ${BfWSection} "The Janet programming language."
|
||||
!insertmacro MUI_FUNCTION_DESCRIPTION_END
|
||||
WriteRegExpandStr HKCU "Environment" JANET_PATH "$INSTDIR\Library"
|
||||
WriteRegExpandStr HKCU "Environment" JANET_HEADERPATH "$INSTDIR\C"
|
||||
WriteRegExpandStr HKCU "Environment" JANET_BINPATH "$INSTDIR\bin"
|
||||
|
||||
SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
|
||||
|
||||
# Update path
|
||||
${EnvVarUpdate} $0 "PATH" "A" "HKCU" "$INSTDIR\bin" ; Append
|
||||
${EnvVarUpdate} $0 "PATH" "A" "HKLM" "$INSTDIR\bin" ; Append
|
||||
|
||||
Section "Uninstall"
|
||||
Delete "$INSTDIR\janet.exe"
|
||||
Delete "$INSTDIR\janet-uninstall.exe"
|
||||
RMDir "$INSTDIR"
|
||||
SectionEnd
|
||||
# Registry information for add/remove programs
|
||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Janet" "DisplayName" "Janet"
|
||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Janet" "UninstallString" "$INSTDIR\uninstall.exe"
|
||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Janet" "QuietUninstallString" "$INSTDIR\uninstall.exe /S"
|
||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Janet" "InstallLocation" "$INSTDIR"
|
||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Janet" "DisplayIcon" "$INSTDIR\logo.ico"
|
||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Janet" "Publisher" "Janet-Lang.org"
|
||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Janet" "HelpLink" "${HELPURL}"
|
||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Janet" "URLUpdateInfo" "${HELPURL}"
|
||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Janet" "URLInfoAbout" "${HELPURL}"
|
||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Janet" "DisplayVersion" "0.6.0"
|
||||
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Janet" "VersionMajor" 0
|
||||
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Janet" "VersionMinor" 6
|
||||
# There is no option for modifying or repairing the install
|
||||
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Janet" "NoModify" 1
|
||||
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Janet" "NoRepair" 1
|
||||
# Set the INSTALLSIZE constant (!defined at the top of this script) so Add/Remove Programs can accurately report the size
|
||||
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Janet" "EstimatedSize" 1000
|
||||
sectionEnd
|
||||
|
||||
Function un.onInit
|
||||
!insertmacro MULTIUSER_UNINIT
|
||||
!insertmacro MUI_UNGETLANGUAGE
|
||||
FunctionEnd
|
||||
# Uninstaller
|
||||
|
||||
function un.onInit
|
||||
!insertmacro MULTIUSER_UNINIT
|
||||
functionEnd
|
||||
|
||||
section "uninstall"
|
||||
|
||||
# Remove Start Menu launcher
|
||||
delete "$SMPROGRAMS\Janet.lnk"
|
||||
|
||||
# Remove files
|
||||
delete "$INSTDIR\logo.ico"
|
||||
rmdir /r "$INSTDIR\Library"
|
||||
rmdir /r "$INSTDIR\bin"
|
||||
rmdir /r "$INSTDIR\C"
|
||||
|
||||
# Remove env vars
|
||||
|
||||
DeleteRegValue HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" JANET_PATH
|
||||
DeleteRegValue HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" JANET_HEADERPATH
|
||||
DeleteRegValue HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" JANET_BINPATH
|
||||
|
||||
DeleteRegValue HKCU "Environment" JANET_PATH
|
||||
DeleteRegValue HKCU "Environment" JANET_HEADERPATH
|
||||
DeleteRegValue HKCU "Environment" JANET_BINPATH
|
||||
|
||||
# Unset PATH
|
||||
${un.EnvVarUpdate} $0 "PATH" "R" "HKCU" "$INSTDIR\bin" ; Remove
|
||||
${un.EnvVarUpdate} $0 "PATH" "R" "HKLM" "$INSTDIR\bin" ; Remove
|
||||
|
||||
# make sure windows knows about the change
|
||||
SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
|
||||
|
||||
# Always delete uninstaller as the last action
|
||||
delete "$INSTDIR\uninstall.exe"
|
||||
|
||||
# Remove uninstaller information from the registry
|
||||
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Janet"
|
||||
sectionEnd
|
||||
|
||||
6
janet.1
6
janet.1
@@ -3,7 +3,7 @@
|
||||
janet \- run the Janet language abstract machine
|
||||
.SH SYNOPSIS
|
||||
.B janet
|
||||
[\fB\-hvsrpnq\fR]
|
||||
[\fB\-hvsrpnqk\fR]
|
||||
[\fB\-e\fR \fISOURCE\fR]
|
||||
[\fB\-l\fR \fIMODULE\fR]
|
||||
[\fB\-m\fR \fIPATH\fR]
|
||||
@@ -67,6 +67,10 @@ after an error. Persistent mode can be good for debugging and testing.
|
||||
.BR \-q
|
||||
Quiet output. Don't print a repl prompt or expression results to stdout.
|
||||
|
||||
.TP
|
||||
.BR \-k
|
||||
Don't execute a script, only compile it to check for errors. Useful for linting scripts.
|
||||
|
||||
.TP
|
||||
.BR \-m\ syspath
|
||||
Set the variable module/*syspath* to the string syspath so that Janet will load system modules
|
||||
|
||||
1
janet_win.rc
Normal file
1
janet_win.rc
Normal file
@@ -0,0 +1 @@
|
||||
IDI_MYICON ICON "assets\icon.ico"
|
||||
10
meson.build
10
meson.build
@@ -22,6 +22,7 @@ project('janet', 'c', default_options : ['c_std=c99'])
|
||||
|
||||
# Global settings
|
||||
janet_path = join_paths(get_option('prefix'), get_option('libdir'), 'janet')
|
||||
header_path = join_paths(get_option('prefix'), get_option('includedir'), 'janet')
|
||||
|
||||
# Link math library on all systems
|
||||
cc = meson.get_compiler('c')
|
||||
@@ -29,7 +30,7 @@ m_dep = cc.find_library('m', required : false)
|
||||
dl_dep = cc.find_library('dl', required : false)
|
||||
|
||||
# Some options
|
||||
add_project_arguments('-DJANET_BUILD="meson"', language : 'c')
|
||||
add_project_link_arguments('-rdynamic', language : 'c')
|
||||
|
||||
# Include directories
|
||||
incdir = include_directories('src/include')
|
||||
@@ -119,7 +120,7 @@ janet_boot = executable('janet-boot', core_src, boot_src, boot_gen,
|
||||
core_image = custom_target('core_image',
|
||||
input : [janet_boot],
|
||||
output : 'core_image.gen.c',
|
||||
command : [janet_boot, '@OUTPUT@', 'JANET_PATH', janet_path])
|
||||
command : [janet_boot, '@OUTPUT@', 'JANET_PATH', janet_path, 'JANET_HEADERPATH', header_path])
|
||||
|
||||
libjanet = shared_library('janet', core_src, core_image,
|
||||
include_directories : incdir,
|
||||
@@ -129,6 +130,7 @@ janet_mainclient = executable('janet', core_src, core_image, init_gen, mainclien
|
||||
include_directories : incdir,
|
||||
dependencies : [m_dep, dl_dep],
|
||||
install : true)
|
||||
janet_jpm = install_data('tools/jpm', install_dir : 'bin')
|
||||
|
||||
# Documentation
|
||||
docs = custom_target('docs',
|
||||
@@ -169,10 +171,8 @@ run_target('repl', command : [janet_mainclient])
|
||||
|
||||
# Installation
|
||||
install_man('janet.1')
|
||||
install_headers('src/include/janet.h', 'src/include/janetconf.h')
|
||||
install_headers('src/include/janet.h', 'src/include/janetconf.h', subdir: 'janet')
|
||||
janet_libs = [
|
||||
'src/include/janet.h',
|
||||
'src/include/janetconf.h',
|
||||
'tools/bars.janet',
|
||||
'tools/cook.janet',
|
||||
'tools/highlight.janet'
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# The core janet library
|
||||
# Copyright 2019 (C) Calvin Rose
|
||||
# Copyright 2019 © Calvin Rose
|
||||
|
||||
###
|
||||
###
|
||||
@@ -136,12 +136,12 @@
|
||||
|
||||
(defmacro comment
|
||||
"Ignores the body of the comment."
|
||||
[])
|
||||
[&])
|
||||
|
||||
(defmacro if-not
|
||||
"Shorthand for (if (not ... "
|
||||
[condition exp-1 &opt exp-2]
|
||||
~(if ,condition ,exp-2 ,exp-1))
|
||||
"Shorthand for (if (not condition) else then)."
|
||||
[condition then &opt else]
|
||||
~(if ,condition ,else ,then))
|
||||
|
||||
(defmacro when
|
||||
"Evaluates the body when the condition is true. Otherwise returns nil."
|
||||
@@ -149,7 +149,7 @@
|
||||
~(if ,condition (do ,;body)))
|
||||
|
||||
(defmacro unless
|
||||
"Shorthand for (when (not ... "
|
||||
"Shorthand for (when (not condition) ;body). "
|
||||
[condition & body]
|
||||
~(if ,condition nil (do ,;body)))
|
||||
|
||||
@@ -171,7 +171,7 @@
|
||||
(defmacro case
|
||||
"Select the body that equals the dispatch value. When pairs
|
||||
has an odd number of arguments, the last is the default expression.
|
||||
If no match is found, returns nil"
|
||||
If no match is found, returns nil."
|
||||
[dispatch & pairs]
|
||||
(def atm (idempotent? dispatch))
|
||||
(def sym (if atm dispatch (gensym)))
|
||||
@@ -416,7 +416,7 @@
|
||||
~(fiber/new (fn [] (loop ,head (yield (do ,;body)))) :yi))
|
||||
|
||||
(defmacro coro
|
||||
"A wrapper for making fibers. Same as (fiber/new (fn [] ...body) :yi)."
|
||||
"A wrapper for making fibers. Same as (fiber/new (fn [] ;body) :yi)."
|
||||
[& body]
|
||||
(tuple fiber/new (tuple 'fn '[] ;body) :yi))
|
||||
|
||||
@@ -678,7 +678,7 @@
|
||||
|
||||
(defn find
|
||||
"Find the first value in an indexed collection that satisfies a predicate. Returns
|
||||
nil if not found. Note their is no way to differentiate a nil from the indexed collection
|
||||
nil if not found. Note there 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]
|
||||
(def i (find-index pred ind))
|
||||
@@ -1047,11 +1047,12 @@
|
||||
(var i 0) (var nextn n)
|
||||
(def len (length ind))
|
||||
(def ret (array/new (math/ceil (/ len n))))
|
||||
(def slicer (if (bytes? ind) string/slice tuple/slice))
|
||||
(while (<= nextn len)
|
||||
(array/push ret (tuple/slice ind i nextn))
|
||||
(array/push ret (slicer ind i nextn))
|
||||
(set i nextn)
|
||||
(+= nextn n))
|
||||
(if (not= i len) (array/push ret (tuple/slice ind i)))
|
||||
(if (not= i len) (array/push ret (slicer ind i)))
|
||||
ret)
|
||||
|
||||
###
|
||||
@@ -1126,10 +1127,13 @@
|
||||
~(if (= nil (def ,pattern ,expr)) ,sentinel ,(onmatch))))
|
||||
|
||||
(tuple? pattern)
|
||||
(match-1
|
||||
(get pattern 0) expr
|
||||
(fn []
|
||||
~(if (and ,;(tuple/slice pattern 1)) ,(onmatch) ,sentinel)) seen)
|
||||
(if (and (= (pattern 0) 'quote) (symbol? (pattern 1)))
|
||||
# Unification with external values
|
||||
~(if (= ,(pattern 1) ,expr) ,(onmatch) ,sentinel)
|
||||
(match-1
|
||||
(get pattern 0) expr
|
||||
(fn []
|
||||
~(if (and ,;(tuple/slice pattern 1)) ,(onmatch) ,sentinel)) seen))
|
||||
|
||||
(array? pattern)
|
||||
(do
|
||||
@@ -1454,6 +1458,7 @@
|
||||
:env - the environment to compile against - default is the current 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
|
||||
:compile-only - only compile the souce, do not execute it - default is false\n\t
|
||||
:on-status - callback when a value is evaluated - default is debug/stacktrace\n\t
|
||||
:fiber-flags - what flags to wrap the compilation fiber with. Default is :ia."
|
||||
[opts]
|
||||
@@ -1464,9 +1469,11 @@
|
||||
:on-compile-error on-compile-error
|
||||
:on-parse-error on-parse-error
|
||||
:fiber-flags guard
|
||||
:compile-only compile-only
|
||||
:source where} opts)
|
||||
(default env (fiber/getenv (fiber/current)))
|
||||
(default chunks getline)
|
||||
(default chunks (fn [buf p] (getline "" buf)))
|
||||
(default compile-only false)
|
||||
(default onstatus debug/stacktrace)
|
||||
(default on-compile-error bad-compile)
|
||||
(default on-parse-error bad-parse)
|
||||
@@ -1486,7 +1493,7 @@
|
||||
(fn []
|
||||
(def res (compile source env where))
|
||||
(if (= (type res) :function)
|
||||
(res)
|
||||
(unless compile-only (res))
|
||||
(do
|
||||
(set good false)
|
||||
(def {:error err :start start :end end :fiber errf} res)
|
||||
@@ -1578,8 +1585,13 @@
|
||||
:native: becomes the dynamic library file extension, usually dll
|
||||
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:" :source]
|
||||
require should load files found at these paths.\n\nA tuple can also
|
||||
contain a third element, specifying a filter that prevents module/find
|
||||
from searching that path template if the filter doesn't match the input
|
||||
path. The filter is often a file extension, including the period."
|
||||
@[[":all:" :native (if (= (os/which) :windows) ".dll" ".so")]
|
||||
[":all:" :image ".jimage"]
|
||||
[":all:" :source]
|
||||
["./:all:.janet" :source]
|
||||
["./:all:/init.janet" :source]
|
||||
[":sys:/:all:.janet" :source]
|
||||
@@ -1593,9 +1605,15 @@
|
||||
(var module/*syspath*
|
||||
"The path where globally installed libraries are located.
|
||||
The default is set at build time and is /usr/local/lib/janet on linux/posix, and
|
||||
on Windows is C:/Janet/Library."
|
||||
on Windows is the empty string."
|
||||
(or (process/opts "JANET_PATH") ""))
|
||||
|
||||
(var module/*headerpath*
|
||||
"The path where the janet headers are installed. Useful for building
|
||||
native modules or compiling code at runtime. Default on linux/posix is
|
||||
/usr/local/include/janet, and on Windows is the empty string."
|
||||
(or (process/opts "JANET_HEADERPATH") ""))
|
||||
|
||||
# Version of fexists that works even with a reduced OS
|
||||
(if-let [has-stat (_env 'os/stat)]
|
||||
(let [stat (has-stat :value)]
|
||||
@@ -1610,6 +1628,21 @@
|
||||
(file/close f)
|
||||
res))))
|
||||
|
||||
(def nati (if (= :windows (os/which)) "dll" "so"))
|
||||
(defn- expand-path-name
|
||||
[template name path]
|
||||
(->> template
|
||||
(string/replace ":name:" name)
|
||||
(string/replace ":sys:" module/*syspath*)
|
||||
(string/replace ":native:" nati)
|
||||
(string/replace ":all:" path)))
|
||||
(defn- mod-filter
|
||||
[x path]
|
||||
(case (type x)
|
||||
:nil path
|
||||
:string (string/has-suffix? x path)
|
||||
(x path)))
|
||||
|
||||
(defn module/find
|
||||
"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,
|
||||
@@ -1617,25 +1650,32 @@
|
||||
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 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)))]))
|
||||
(def name (last parts))
|
||||
(var ret nil)
|
||||
(each [p mod-kind checker] module/paths
|
||||
(when (mod-filter checker path)
|
||||
(if (function? p)
|
||||
(when-let [res (p path)]
|
||||
(set ret [res mod-kind])
|
||||
(break))
|
||||
(do
|
||||
(def fullpath (expand-path-name p name path))
|
||||
(when (fexists fullpath)
|
||||
(set ret [fullpath mod-kind])
|
||||
(break))))))
|
||||
(if ret ret
|
||||
(let [expander (fn [[t _ chk]]
|
||||
(when (string? t)
|
||||
(when (mod-filter chk path)
|
||||
(expand-path-name t name path))))
|
||||
paths (filter identity (map expander module/paths))
|
||||
str-parts (interpose "\n " paths)]
|
||||
[nil (string "could not find module " path ":\n " ;str-parts)])))
|
||||
|
||||
(put _env 'fexists nil)
|
||||
(put _env 'nati nil)
|
||||
(put _env 'expand-path-name nil)
|
||||
(put _env 'mod-filter nil)
|
||||
|
||||
(def module/cache
|
||||
"Table mapping loaded module identifiers to their environments."
|
||||
@@ -1646,47 +1686,64 @@
|
||||
circular dependencies."
|
||||
@{})
|
||||
|
||||
(defn dofile
|
||||
"Evaluate a file and return the resulting environment."
|
||||
[path & args]
|
||||
(def {:exit exit-on-error
|
||||
:source source
|
||||
:env env
|
||||
:compile-only compile-only} (table ;args))
|
||||
(def f (if (= (type path) :core/file)
|
||||
path
|
||||
(file/open path)))
|
||||
(default env (make-env))
|
||||
(defn chunks [buf _] (file/read f 2048 buf))
|
||||
(defn bp [&opt x y]
|
||||
(def ret (bad-parse x y))
|
||||
(if exit-on-error (os/exit 1))
|
||||
ret)
|
||||
(defn bc [&opt x y z]
|
||||
(def ret (bad-compile x y z))
|
||||
(if exit-on-error (os/exit 1))
|
||||
ret)
|
||||
(run-context {:env env
|
||||
:chunks chunks
|
||||
:on-parse-error bp
|
||||
:on-compile-error bc
|
||||
:on-status (fn [f x]
|
||||
(when (not= (fiber/status f) :dead)
|
||||
(debug/stacktrace f x)
|
||||
(if exit-on-error (os/exit 1))))
|
||||
:compile-only compile-only
|
||||
:source (or source (if (= f path) "<anonymous>" path))})
|
||||
(when (not= f path) (file/close f))
|
||||
env)
|
||||
|
||||
(def module/loaders
|
||||
"A table of loading method names to loading functions.
|
||||
This table lets require and import load many different kinds
|
||||
of files as module."
|
||||
@{:native (fn [path &] (native path (make-env)))
|
||||
:source (fn [path args]
|
||||
(put module/loading path true)
|
||||
(def newenv (dofile path ;args))
|
||||
(put module/loading path nil)
|
||||
newenv)
|
||||
:image (fn [path &] (load-image (slurp path)))})
|
||||
|
||||
(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]
|
||||
(def {:exit exit-on-error} (table ;args))
|
||||
(if-let [check (get module/cache path)]
|
||||
check
|
||||
(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))
|
||||
(defn bp [&opt x y]
|
||||
(def ret (bad-parse x y))
|
||||
(if exit-on-error (os/exit 1))
|
||||
ret)
|
||||
(defn bc [&opt x y z]
|
||||
(def ret (bad-compile x y z))
|
||||
(if exit-on-error (os/exit 1))
|
||||
ret)
|
||||
(run-context {:env newenv
|
||||
:chunks chunks
|
||||
:on-parse-error bp
|
||||
:on-compile-error bc
|
||||
: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))))
|
||||
(def loader (module/loaders mod-kind))
|
||||
(unless loader (error (string "module type " mod-kind " unknown")))
|
||||
(def env (loader fullpath args))
|
||||
(put module/cache fullpath env)
|
||||
(put module/cache path env)
|
||||
env)))
|
||||
@@ -1710,7 +1767,9 @@
|
||||
symbols into the current environment, prepending a given prefix as needed.
|
||||
(use the :as or :prefix option to set a prefix). If no prefix is provided,
|
||||
use the name of the module as a prefix. One can also use :export true
|
||||
to re-export the imported symbols."
|
||||
to re-export the imported symbols. If :exit true is given as an argument,
|
||||
any errors encountered at the top level in the module will cause (os/exit 1)
|
||||
to be called."
|
||||
[path & args]
|
||||
(def argm (map (fn [x]
|
||||
(if (keyword? x)
|
||||
@@ -1727,6 +1786,11 @@
|
||||
[&opt chunks onsignal env]
|
||||
(def level (+ (dyn :debug-level 0) 1))
|
||||
(default env (make-env))
|
||||
(default chunks (fn [buf p] (getline (string "repl:"
|
||||
(parser/where p)
|
||||
":"
|
||||
(parser/state p) "> ")
|
||||
buf)))
|
||||
(default onsignal (fn [f x]
|
||||
(case (fiber/status f)
|
||||
:dead (do
|
||||
|
||||
@@ -266,7 +266,7 @@ static const JanetReg array_cfuns[] = {
|
||||
{
|
||||
"array/ensure", cfun_array_ensure,
|
||||
JDOC("(array/ensure arr capacity)\n\n"
|
||||
"Ensures that the memory backing the array has enough memory for capacity "
|
||||
"Ensures that the memory backing the array is large enough for capacity "
|
||||
"items. Capacity must be an integer. If the backing capacity is already enough, "
|
||||
"then this function does nothing. Otherwise, the backing memory will be reallocated "
|
||||
"so that there is enough space.")
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "emit.h"
|
||||
#include "vector.h"
|
||||
#include "util.h"
|
||||
#include "state.h"
|
||||
#endif
|
||||
|
||||
JanetFopts janetc_fopts_default(JanetCompiler *c) {
|
||||
@@ -716,8 +717,12 @@ JanetCompileResult janet_compile(Janet source, JanetTable *env, const uint8_t *w
|
||||
|
||||
/* C Function for compiling */
|
||||
static Janet cfun(int32_t argc, Janet *argv) {
|
||||
janet_arity(argc, 2, 3);
|
||||
JanetTable *env = janet_gettable(argv, 1);
|
||||
janet_arity(argc, 1, 3);
|
||||
JanetTable *env = argc > 1 ? janet_gettable(argv, 1) : janet_vm_fiber->env;
|
||||
if (NULL == env) {
|
||||
env = janet_table(0);
|
||||
janet_vm_fiber->env = env;
|
||||
}
|
||||
const uint8_t *source = NULL;
|
||||
if (argc == 3) {
|
||||
source = janet_getstring(argv, 2);
|
||||
@@ -740,7 +745,7 @@ static Janet cfun(int32_t argc, Janet *argv) {
|
||||
static const JanetReg compile_cfuns[] = {
|
||||
{
|
||||
"compile", cfun,
|
||||
JDOC("(compile ast env [, source])\n\n"
|
||||
JDOC("(compile ast &opt env source)\n\n"
|
||||
"Compiles an Abstract Syntax Tree (ast) into a janet function. "
|
||||
"Pair the compile function with parsing functionality to implement "
|
||||
"eval. Returns a janet function and does not modify ast. Throws an "
|
||||
|
||||
@@ -57,13 +57,37 @@ typedef void *Clib;
|
||||
JanetModule janet_native(const char *name, const uint8_t **error) {
|
||||
Clib lib = load_clib(name);
|
||||
JanetModule init;
|
||||
JanetModconf getter;
|
||||
if (!lib) {
|
||||
*error = janet_cstring(error_clib());
|
||||
return NULL;
|
||||
}
|
||||
init = (JanetModule) symbol_clib(lib, "_janet_init");
|
||||
if (!init) {
|
||||
*error = janet_cstring("could not find _janet_init symbol");
|
||||
*error = janet_cstring("could not find the _janet_init symbol");
|
||||
return NULL;
|
||||
}
|
||||
getter = (JanetModconf) symbol_clib(lib, "_janet_mod_config");
|
||||
if (!getter) {
|
||||
*error = janet_cstring("could not find the _janet_mod_config symbol");
|
||||
return NULL;
|
||||
}
|
||||
JanetBuildConfig modconf = getter();
|
||||
JanetBuildConfig host = janet_config_current();
|
||||
if (host.major != modconf.major ||
|
||||
host.minor < modconf.minor ||
|
||||
host.bits != modconf.bits) {
|
||||
char errbuf[128];
|
||||
sprintf(errbuf, "config mismatch - host %d.%.d.%d(%.4x) vs. module %d.%d.%d(%.4x)",
|
||||
host.major,
|
||||
host.minor,
|
||||
host.patch,
|
||||
host.bits,
|
||||
modconf.major,
|
||||
modconf.minor,
|
||||
modconf.patch,
|
||||
modconf.bits);
|
||||
*error = janet_cstring(errbuf);
|
||||
return NULL;
|
||||
}
|
||||
return init;
|
||||
@@ -653,7 +677,7 @@ static void make_apply(JanetTable *env) {
|
||||
"be an array-like. Each element in this last argument is then also pushed as an argument to "
|
||||
"f. For example:\n\n"
|
||||
"\t(apply + 1000 (range 10))\n\n"
|
||||
"sums the first 10 integers and 1000.)"));
|
||||
"sums the first 10 integers and 1000."));
|
||||
}
|
||||
|
||||
static const uint32_t error_asm[] = {
|
||||
@@ -830,6 +854,9 @@ JanetTable *janet_core_env(JanetTable *replacements) {
|
||||
JDOC("The version number of the running janet program."));
|
||||
janet_def(env, "janet/build", janet_cstringv(JANET_BUILD),
|
||||
JDOC("The build identifier of the running janet program."));
|
||||
janet_def(env, "janet/config-bits", janet_wrap_integer(JANET_CURRENT_CONFIG_BITS),
|
||||
JDOC("The flag set of config options from janetconf.h which is used to check "
|
||||
"if native modules are compatible with the host program."));
|
||||
|
||||
/* Allow references to the environment */
|
||||
janet_def(env, "_env", janet_wrap_table(env), JDOC("The environment table for the current scope."));
|
||||
|
||||
@@ -239,11 +239,11 @@ void janetc_copy(
|
||||
return;
|
||||
}
|
||||
/* Process: src -> near -> dest */
|
||||
int32_t near = janetc_allocnear(c, JANETC_REGTEMP_3);
|
||||
janetc_movenear(c, near, src);
|
||||
janetc_moveback(c, dest, near);
|
||||
int32_t nearreg = janetc_allocnear(c, JANETC_REGTEMP_3);
|
||||
janetc_movenear(c, nearreg, src);
|
||||
janetc_moveback(c, dest, nearreg);
|
||||
/* Cleanup */
|
||||
janetc_regalloc_freetemp(&c->scope->ra, near, JANETC_REGTEMP_3);
|
||||
janetc_regalloc_freetemp(&c->scope->ra, nearreg, JANETC_REGTEMP_3);
|
||||
|
||||
}
|
||||
/* Instruction templated emitters */
|
||||
|
||||
@@ -127,6 +127,16 @@ void janet_fiber_pushn(JanetFiber *fiber, const Janet *arr, int32_t n) {
|
||||
fiber->stacktop = newtop;
|
||||
}
|
||||
|
||||
/* Create a struct with n values. If n is odd, the last value is ignored. */
|
||||
static Janet make_struct_n(const Janet *args, int32_t n) {
|
||||
int32_t i = 0;
|
||||
JanetKV *st = janet_struct_begin(n & (~1));
|
||||
for (; i < n; i += 2) {
|
||||
janet_struct_put(st, args[i], args[i + 1]);
|
||||
}
|
||||
return janet_wrap_struct(janet_struct_end(st));
|
||||
}
|
||||
|
||||
/* Push a stack frame to a fiber */
|
||||
int janet_fiber_funcframe(JanetFiber *fiber, JanetFunction *func) {
|
||||
JanetStackFrame *newframe;
|
||||
@@ -164,12 +174,19 @@ int janet_fiber_funcframe(JanetFiber *fiber, JanetFunction *func) {
|
||||
/* Check varargs */
|
||||
if (func->def->flags & JANET_FUNCDEF_FLAG_VARARG) {
|
||||
int32_t tuplehead = fiber->frame + func->def->arity;
|
||||
int st = func->def->flags & JANET_FUNCDEF_FLAG_STRUCTARG;
|
||||
if (tuplehead >= oldtop) {
|
||||
fiber->data[tuplehead] = janet_wrap_tuple(janet_tuple_n(NULL, 0));
|
||||
fiber->data[tuplehead] = st
|
||||
? make_struct_n(NULL, 0)
|
||||
: janet_wrap_tuple(janet_tuple_n(NULL, 0));
|
||||
} else {
|
||||
fiber->data[tuplehead] = janet_wrap_tuple(janet_tuple_n(
|
||||
fiber->data[tuplehead] = st
|
||||
? make_struct_n(
|
||||
fiber->data + tuplehead,
|
||||
oldtop - tuplehead));
|
||||
oldtop - tuplehead)
|
||||
: janet_wrap_tuple(janet_tuple_n(
|
||||
fiber->data + tuplehead,
|
||||
oldtop - tuplehead));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,14 +237,21 @@ int janet_fiber_funcframe_tail(JanetFiber *fiber, JanetFunction *func) {
|
||||
/* Check varargs */
|
||||
if (func->def->flags & JANET_FUNCDEF_FLAG_VARARG) {
|
||||
int32_t tuplehead = fiber->stackstart + func->def->arity;
|
||||
int st = func->def->flags & JANET_FUNCDEF_FLAG_STRUCTARG;
|
||||
if (tuplehead >= fiber->stacktop) {
|
||||
if (tuplehead >= fiber->capacity) janet_fiber_setcapacity(fiber, 2 * (tuplehead + 1));
|
||||
for (i = fiber->stacktop; i < tuplehead; ++i) fiber->data[i] = janet_wrap_nil();
|
||||
fiber->data[tuplehead] = janet_wrap_tuple(janet_tuple_n(NULL, 0));
|
||||
fiber->data[tuplehead] = st
|
||||
? make_struct_n(NULL, 0)
|
||||
: janet_wrap_tuple(janet_tuple_n(NULL, 0));
|
||||
} else {
|
||||
fiber->data[tuplehead] = janet_wrap_tuple(janet_tuple_n(
|
||||
fiber->data[tuplehead] = st
|
||||
? make_struct_n(
|
||||
fiber->data + tuplehead,
|
||||
fiber->stacktop - tuplehead));
|
||||
fiber->stacktop - tuplehead)
|
||||
: janet_wrap_tuple(janet_tuple_n(
|
||||
fiber->data + tuplehead,
|
||||
fiber->stacktop - tuplehead));
|
||||
}
|
||||
stacksize = tuplehead - fiber->stackstart + 1;
|
||||
} else {
|
||||
|
||||
@@ -32,6 +32,10 @@
|
||||
#include "util.h"
|
||||
#endif
|
||||
|
||||
#ifndef JANET_WINDOWS
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
#define IO_WRITE 1
|
||||
#define IO_READ 2
|
||||
#define IO_APPEND 4
|
||||
@@ -160,7 +164,7 @@ static Janet cfun_io_fopen(int32_t argc, Janet *argv) {
|
||||
return f ? makef(f, flags) : janet_wrap_nil();
|
||||
}
|
||||
|
||||
/* Read up to n bytes into buffer. Return error string if error. */
|
||||
/* Read up to n bytes into buffer. */
|
||||
static void read_chunk(IOFile *iof, JanetBuffer *buffer, int32_t nBytesMax) {
|
||||
if (!(iof->flags & (IO_READ | IO_UPDATE)))
|
||||
janet_panic("file is not readable");
|
||||
@@ -183,6 +187,7 @@ static Janet cfun_io_fread(int32_t argc, Janet *argv) {
|
||||
} else {
|
||||
buffer = janet_getbuffer(argv, 2);
|
||||
}
|
||||
int32_t bufstart = buffer->count;
|
||||
if (janet_checktype(argv[1], JANET_KEYWORD)) {
|
||||
const uint8_t *sym = janet_unwrap_keyword(argv[1]);
|
||||
if (!janet_cstrcmp(sym, "all")) {
|
||||
@@ -207,6 +212,8 @@ static Janet cfun_io_fread(int32_t argc, Janet *argv) {
|
||||
fseek(iof->file, 0, SEEK_SET);
|
||||
read_chunk(iof, buffer, (int32_t) fsize);
|
||||
}
|
||||
/* Never return nil for :all */
|
||||
return janet_wrap_buffer(buffer);
|
||||
} else if (!janet_cstrcmp(sym, "line")) {
|
||||
for (;;) {
|
||||
int x = fgetc(iof->file);
|
||||
@@ -221,6 +228,7 @@ static Janet cfun_io_fread(int32_t argc, Janet *argv) {
|
||||
if (len < 0) janet_panic("expected positive integer");
|
||||
read_chunk(iof, buffer, len);
|
||||
}
|
||||
if (bufstart == buffer->count) return janet_wrap_nil();
|
||||
return janet_wrap_buffer(buffer);
|
||||
}
|
||||
|
||||
@@ -281,13 +289,17 @@ static Janet cfun_io_fclose(int32_t argc, Janet *argv) {
|
||||
if (iof->flags & IO_PIPED) {
|
||||
#ifdef JANET_WINDOWS
|
||||
#define pclose _pclose
|
||||
#define WEXITSTATUS(x) x
|
||||
#endif
|
||||
if (pclose(iof->file)) janet_panic("could not close file");
|
||||
int status = pclose(iof->file);
|
||||
iof->flags |= IO_CLOSED;
|
||||
if (status == -1) janet_panic("could not close file");
|
||||
return janet_wrap_integer(WEXITSTATUS(status));
|
||||
} else {
|
||||
if (fclose(iof->file)) janet_panic("could not close file");
|
||||
iof->flags |= IO_CLOSED;
|
||||
return janet_wrap_nil();
|
||||
}
|
||||
iof->flags |= IO_CLOSED;
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
/* Seek a file */
|
||||
|
||||
243
src/core/os.c
243
src/core/os.c
@@ -41,7 +41,9 @@
|
||||
#include <direct.h>
|
||||
#include <sys/utime.h>
|
||||
#include <io.h>
|
||||
#include <process.h>
|
||||
#else
|
||||
#include <spawn.h>
|
||||
#include <utime.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
@@ -88,7 +90,7 @@ static Janet os_exit(int32_t argc, Janet *argv) {
|
||||
}
|
||||
|
||||
#ifdef JANET_REDUCED_OS
|
||||
/* Provide a dud os/getenv so init.janet works, but nothing else */
|
||||
/* Provide a dud os/getenv so boot.janet and init.janet work, but nothing else */
|
||||
|
||||
static Janet os_getenv(int32_t argc, Janet *argv) {
|
||||
(void) argv;
|
||||
@@ -99,97 +101,152 @@ static Janet os_getenv(int32_t argc, Janet *argv) {
|
||||
#else
|
||||
/* Provide full os functionality */
|
||||
|
||||
#ifdef JANET_WINDOWS
|
||||
static Janet os_execute(int32_t argc, Janet *argv) {
|
||||
janet_arity(argc, 1, -1);
|
||||
JanetBuffer *buffer = janet_buffer(10);
|
||||
for (int32_t i = 0; i < argc; i++) {
|
||||
const uint8_t *argstring = janet_getstring(argv, i);
|
||||
janet_buffer_push_bytes(buffer, argstring, janet_string_length(argstring));
|
||||
if (i != argc - 1) {
|
||||
janet_buffer_push_u8(buffer, ' ');
|
||||
#define JANET_OS_EFLAG_E 0x1
|
||||
#define JANET_OS_EFLAG_P 0x2
|
||||
|
||||
/* Get flags */
|
||||
/* Unfortunately, execvpe is linux (glibc) only. Instead, we can switch
|
||||
* between the more portable execve, execvp, or execv.
|
||||
* Use the :e or :p flag for execve and execvp respectively. Eventually
|
||||
* :ep or :pe could be execvpe. */
|
||||
static int os_execute_flags(int32_t argc, const Janet *argv) {
|
||||
if (argc < 2) return 0;
|
||||
int flags = 0;
|
||||
if (argc > 1) {
|
||||
const uint8_t *f = janet_getkeyword(argv, 1);
|
||||
int32_t len = janet_string_length(f);
|
||||
for (int32_t i = 0; i < len; i++) {
|
||||
if (f[i] == 'e') flags |= JANET_OS_EFLAG_E;
|
||||
if (f[i] == 'p') flags |= JANET_OS_EFLAG_P;
|
||||
}
|
||||
}
|
||||
janet_buffer_push_u8(buffer, 0);
|
||||
|
||||
/* Convert to wide chars */
|
||||
wchar_t *sys_str = malloc(buffer->count * sizeof(wchar_t));
|
||||
if (NULL == sys_str) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
int nwritten = MultiByteToWideChar(
|
||||
CP_UTF8,
|
||||
MB_PRECOMPOSED,
|
||||
buffer->data,
|
||||
buffer->count,
|
||||
sys_str,
|
||||
buffer->count);
|
||||
if (nwritten == 0) {
|
||||
free(sys_str);
|
||||
janet_panic("could not create process");
|
||||
}
|
||||
|
||||
STARTUPINFO si;
|
||||
PROCESS_INFORMATION pi;
|
||||
|
||||
ZeroMemory(&si, sizeof(si));
|
||||
si.cb = sizeof(si);
|
||||
ZeroMemory(&pi, sizeof(pi));
|
||||
|
||||
// Start the child process.
|
||||
if (!CreateProcess(NULL,
|
||||
(LPSTR) sys_str,
|
||||
NULL,
|
||||
NULL,
|
||||
FALSE,
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
&si,
|
||||
&pi)) {
|
||||
free(sys_str);
|
||||
janet_panic("could not create process");
|
||||
}
|
||||
free(sys_str);
|
||||
|
||||
// Wait until child process exits.
|
||||
WaitForSingleObject(pi.hProcess, INFINITE);
|
||||
|
||||
// Close process and thread handles.
|
||||
WORD status;
|
||||
GetExitCodeProcess(pi.hProcess, (LPDWORD)&status);
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
return janet_wrap_integer(status);
|
||||
return flags;
|
||||
}
|
||||
#else
|
||||
|
||||
/* Get env for os_execute (execv family of functions, as well as CreateProcess) */
|
||||
static char **os_execute_env(int32_t argc, const Janet *argv) {
|
||||
char **envp = NULL;
|
||||
if (argc > 2) {
|
||||
JanetDictView dict = janet_getdictionary(argv, 2);
|
||||
envp = malloc(sizeof(char *) * (dict.len + 1));
|
||||
if (NULL == envp) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
int32_t j = 0;
|
||||
for (int32_t i = 0; i < dict.cap; i++) {
|
||||
const JanetKV *kv = dict.kvs + i;
|
||||
if (!janet_checktype(kv->key, JANET_STRING)) continue;
|
||||
if (!janet_checktype(kv->value, JANET_STRING)) continue;
|
||||
const uint8_t *keys = janet_unwrap_string(kv->key);
|
||||
const uint8_t *vals = janet_unwrap_string(kv->value);
|
||||
int32_t klen = janet_string_length(keys);
|
||||
int32_t vlen = janet_string_length(vals);
|
||||
/* Check keys has no embedded 0s or =s. */
|
||||
int skip = 0;
|
||||
for (int32_t k = 0; k < klen; k++) {
|
||||
if (keys[k] == '\0' || keys[k] == '=') {
|
||||
skip = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (skip) continue;
|
||||
char *envitem = malloc(klen + vlen + 2);
|
||||
if (NULL == envitem) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
memcpy(envitem, keys, klen);
|
||||
envitem[klen] = '=';
|
||||
memcpy(envitem + klen + 1, vals, vlen);
|
||||
envitem[klen + vlen + 1] = 0;
|
||||
envp[j++] = envitem;
|
||||
}
|
||||
envp[j] = NULL;
|
||||
}
|
||||
return envp;
|
||||
}
|
||||
|
||||
/* Free memory from os_execute */
|
||||
static void os_execute_cleanup(char **envp, const char **child_argv) {
|
||||
free((void *)child_argv);
|
||||
if (NULL != envp) {
|
||||
char **envitem = envp;
|
||||
while (*envitem != NULL) {
|
||||
free(*envitem);
|
||||
envitem++;
|
||||
}
|
||||
}
|
||||
free(envp);
|
||||
}
|
||||
|
||||
static Janet os_execute(int32_t argc, Janet *argv) {
|
||||
janet_arity(argc, 1, -1);
|
||||
const char **child_argv = malloc(sizeof(char *) * (argc + 1));
|
||||
janet_arity(argc, 1, 3);
|
||||
|
||||
/* Get arguments */
|
||||
JanetView exargs = janet_getindexed(argv, 0);
|
||||
const char **child_argv = malloc(sizeof(char *) * (exargs.len + 1));
|
||||
int status = 0;
|
||||
if (NULL == child_argv) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
for (int32_t i = 0; i < argc; i++) {
|
||||
child_argv[i] = janet_getcstring(argv, i);
|
||||
for (int32_t i = 0; i < exargs.len; i++) {
|
||||
child_argv[i] = janet_getcstring(exargs.items, i);
|
||||
}
|
||||
child_argv[argc] = NULL;
|
||||
child_argv[exargs.len] = NULL;
|
||||
|
||||
/* Fork child process */
|
||||
pid_t pid = fork();
|
||||
if (pid < 0) {
|
||||
janet_panic("failed to execute");
|
||||
} else if (pid == 0) {
|
||||
if (-1 == execve(child_argv[0], (char **)child_argv, NULL)) {
|
||||
exit(1);
|
||||
}
|
||||
/* Get flags */
|
||||
int flags = os_execute_flags(argc, argv);
|
||||
|
||||
/* Get environment */
|
||||
char **envp = os_execute_env(argc, argv);
|
||||
|
||||
/* Coerce to form that works for spawn. I'm fairly confident no implementation
|
||||
* of posix_spawn would modify the argv array passed in. */
|
||||
char *const *cargv = (char *const *)child_argv;
|
||||
|
||||
#ifdef JANET_WINDOWS
|
||||
|
||||
/* Use _spawn family of functions. */
|
||||
/* Windows docs say do this before any spawns. */
|
||||
_flushall();
|
||||
|
||||
if (flags & (JANET_OS_EFLAG_P | JANET_OS_EFLAG_E)) {
|
||||
status = (int) _spawnvpe(_P_WAIT, child_argv[0], cargv, envp);
|
||||
} else if (flags & JANET_OS_EFLAG_P) {
|
||||
status = (int) _spawnvp(_P_WAIT, child_argv[0], cargv);
|
||||
} else if (flags & JANET_OS_EFLAG_E) {
|
||||
status = (int) _spawnve(_P_WAIT, child_argv[0], cargv, envp);
|
||||
} else {
|
||||
status = (int) _spawnv(_P_WAIT, child_argv[0], cargv);
|
||||
}
|
||||
|
||||
os_execute_cleanup(envp, child_argv);
|
||||
return janet_wrap_integer(status);
|
||||
#else
|
||||
|
||||
/* Use posix_spawn to spawn new process */
|
||||
pid_t pid;
|
||||
if (flags & JANET_OS_EFLAG_P) {
|
||||
status = posix_spawnp(&pid,
|
||||
child_argv[0], NULL, NULL, cargv,
|
||||
(flags & JANET_OS_EFLAG_E) ? envp : NULL);
|
||||
} else {
|
||||
status = posix_spawn(&pid,
|
||||
child_argv[0], NULL, NULL, cargv,
|
||||
(flags & JANET_OS_EFLAG_E) ? envp : NULL);
|
||||
}
|
||||
|
||||
/* Wait for child */
|
||||
if (status) {
|
||||
os_execute_cleanup(envp, child_argv);
|
||||
janet_panic(strerror(status));
|
||||
} else {
|
||||
waitpid(pid, &status, 0);
|
||||
}
|
||||
free(child_argv);
|
||||
return janet_wrap_integer(status);
|
||||
}
|
||||
|
||||
os_execute_cleanup(envp, child_argv);
|
||||
return janet_wrap_integer(WEXITSTATUS(status));
|
||||
#endif
|
||||
}
|
||||
|
||||
static Janet os_shell(int32_t argc, Janet *argv) {
|
||||
janet_arity(argc, 0, 1);
|
||||
@@ -607,6 +664,17 @@ static Janet os_dir(int32_t argc, Janet *argv) {
|
||||
return janet_wrap_array(paths);
|
||||
}
|
||||
|
||||
static Janet os_rename(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 2);
|
||||
const char *src = janet_getcstring(argv, 0);
|
||||
const char *dest = janet_getcstring(argv, 1);
|
||||
int status = rename(src, dest);
|
||||
if (status) {
|
||||
janet_panic(strerror(errno));
|
||||
}
|
||||
return janet_wrap_nil();
|
||||
}
|
||||
|
||||
#endif /* JANET_REDUCED_OS */
|
||||
|
||||
static const JanetReg os_cfuns[] = {
|
||||
@@ -632,7 +700,7 @@ static const JanetReg os_cfuns[] = {
|
||||
#ifndef JANET_REDUCED_OS
|
||||
{
|
||||
"os/dir", os_dir,
|
||||
JDOC("(os/stat dir [, array])\n\n"
|
||||
JDOC("(os/dir dir [, array])\n\n"
|
||||
"Iterate over files and subdirectories in a directory. Returns an array of paths parts, "
|
||||
"with only the filename or directory name and no prefix.")
|
||||
},
|
||||
@@ -690,9 +758,15 @@ static const JanetReg os_cfuns[] = {
|
||||
},
|
||||
{
|
||||
"os/execute", os_execute,
|
||||
JDOC("(os/execute program & args)\n\n"
|
||||
"Execute a program on the system and pass it string arguments. Returns "
|
||||
"the exit status of the program.")
|
||||
JDOC("(os/execute args &opts flags env)\n\n"
|
||||
"Execute a program on the system and pass it string arguments. Flags "
|
||||
"is a keyword that modifies how the program will execute.\n\n"
|
||||
"\t:e - enables passing an environment to the program. Without :e, the "
|
||||
"current environment is inherited.\n"
|
||||
"\t:p - allows searching the current PATH for the binary to execute. "
|
||||
"Without this flag, binaries must use absolute paths.\n\n"
|
||||
"env is a table or struct mapping environment variables to values. "
|
||||
"Returns the exit status of the program.")
|
||||
},
|
||||
{
|
||||
"os/shell", os_shell,
|
||||
@@ -742,6 +816,11 @@ static const JanetReg os_cfuns[] = {
|
||||
"\t:year-day - day of the year [0-365]\n"
|
||||
"\t:dst - If Day Light Savings is in effect")
|
||||
},
|
||||
{
|
||||
"os/rename", os_rename,
|
||||
JDOC("(os/rename oldname newname)\n\n"
|
||||
"Rename a file on disk to a new path. Returns nil.")
|
||||
},
|
||||
#endif
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
@@ -928,7 +928,7 @@ static const JanetReg parse_cfuns[] = {
|
||||
},
|
||||
{
|
||||
"parser/eof", cfun_parse_eof,
|
||||
JDOC("(parser/insert parser)\n\n"
|
||||
JDOC("(parser/eof parser)\n\n"
|
||||
"Indicate that the end of file was reached to the parser. This puts the parser in the :dead state.")
|
||||
},
|
||||
{
|
||||
|
||||
@@ -197,16 +197,15 @@ void janet_description_b(JanetBuffer *buffer, Janet x) {
|
||||
case JANET_STRING:
|
||||
janet_escape_string_b(buffer, janet_unwrap_string(x));
|
||||
return;
|
||||
case JANET_BUFFER:
|
||||
{
|
||||
JanetBuffer *b = janet_unwrap_buffer(x);
|
||||
if (b == buffer) {
|
||||
/* Ensures buffer won't resize while escaping */
|
||||
janet_buffer_ensure(b, 5 * b->count + 3, 1);
|
||||
}
|
||||
janet_escape_buffer_b(buffer, b);
|
||||
return;
|
||||
case JANET_BUFFER: {
|
||||
JanetBuffer *b = janet_unwrap_buffer(x);
|
||||
if (b == buffer) {
|
||||
/* Ensures buffer won't resize while escaping */
|
||||
janet_buffer_ensure(b, 5 * b->count + 3, 1);
|
||||
}
|
||||
janet_escape_buffer_b(buffer, b);
|
||||
return;
|
||||
}
|
||||
case JANET_ABSTRACT: {
|
||||
void *p = janet_unwrap_abstract(x);
|
||||
const JanetAbstractType *at = janet_abstract_type(p);
|
||||
|
||||
@@ -174,7 +174,7 @@ static int destructure(JanetCompiler *c,
|
||||
/* Create a source map for definitions. */
|
||||
static const Janet *janetc_make_sourcemap(JanetCompiler *c) {
|
||||
Janet *tup = janet_tuple_begin(3);
|
||||
tup[0] = janet_wrap_string(c->source);
|
||||
tup[0] = c->source ? janet_wrap_string(c->source) : janet_wrap_nil();
|
||||
tup[1] = janet_wrap_integer(c->current_mapping.start);
|
||||
tup[2] = janet_wrap_integer(c->current_mapping.end);
|
||||
return janet_tuple_end(tup);
|
||||
@@ -652,6 +652,7 @@ static JanetSlot janetc_fn(JanetFopts opts, int32_t argn, const Janet *argv) {
|
||||
|
||||
/* Function flags */
|
||||
int vararg = 0;
|
||||
int structarg = 0;
|
||||
int allow_extra = 0;
|
||||
int selfref = 0;
|
||||
int seenamp = 0;
|
||||
@@ -712,6 +713,19 @@ static JanetSlot janetc_fn(JanetFopts opts, int32_t argn, const Janet *argv) {
|
||||
min_arity = i;
|
||||
arity--;
|
||||
seenopt = 1;
|
||||
} else if (!janet_cstrcmp(janet_unwrap_symbol(param), "&keys")) {
|
||||
if (seenamp) {
|
||||
errmsg = "&keys in unexpected location";
|
||||
goto error;
|
||||
} else if (i == paramcount - 2) {
|
||||
vararg = 1;
|
||||
structarg = 1;
|
||||
arity -= 2;
|
||||
} else {
|
||||
errmsg = "&keys in unexpected location";
|
||||
goto error;
|
||||
}
|
||||
seenamp = 1;
|
||||
} else {
|
||||
janetc_nameslot(c, janet_unwrap_symbol(param), janetc_farslot(c));
|
||||
}
|
||||
@@ -749,6 +763,7 @@ static JanetSlot janetc_fn(JanetFopts opts, int32_t argn, const Janet *argv) {
|
||||
def->min_arity = min_arity;
|
||||
def->max_arity = max_arity;
|
||||
if (vararg) def->flags |= JANET_FUNCDEF_FLAG_VARARG;
|
||||
if (structarg) def->flags |= JANET_FUNCDEF_FLAG_STRUCTARG;
|
||||
|
||||
if (selfref) def->name = janet_unwrap_symbol(head);
|
||||
defindex = janetc_addfuncdef(c, def);
|
||||
|
||||
@@ -290,8 +290,8 @@ static Janet cfun_string_hassuffix(int32_t argc, Janet *argv) {
|
||||
return str.len < suffix.len
|
||||
? janet_wrap_false()
|
||||
: janet_wrap_boolean(memcmp(suffix.bytes,
|
||||
str.bytes + str.len - suffix.len,
|
||||
suffix.len) == 0);
|
||||
str.bytes + str.len - suffix.len,
|
||||
suffix.len) == 0);
|
||||
}
|
||||
|
||||
static Janet cfun_string_findall(int32_t argc, Janet *argv) {
|
||||
@@ -467,6 +467,60 @@ static Janet cfun_string_format(int32_t argc, Janet *argv) {
|
||||
return janet_stringv(buffer->data, buffer->count);
|
||||
}
|
||||
|
||||
static int trim_help_checkset(JanetByteView set, uint8_t x) {
|
||||
for (int32_t j = 0; j < set.len; j++)
|
||||
if (set.bytes[j] == x)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t trim_help_leftedge(JanetByteView str, JanetByteView set) {
|
||||
for (int32_t i = 0; i < str.len; i++)
|
||||
if (!trim_help_checkset(set, str.bytes[i]))
|
||||
return i;
|
||||
return str.len;
|
||||
}
|
||||
|
||||
static int32_t trim_help_rightedge(JanetByteView str, JanetByteView set) {
|
||||
for (int32_t i = str.len - 1; i >= 0; i--)
|
||||
if (!trim_help_checkset(set, str.bytes[i]))
|
||||
return i + 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void trim_help_args(int32_t argc, Janet *argv, JanetByteView *str, JanetByteView *set) {
|
||||
janet_arity(argc, 1, 2);
|
||||
*str = janet_getbytes(argv, 0);
|
||||
if (argc >= 2) {
|
||||
*set = janet_getbytes(argv, 1);
|
||||
} else {
|
||||
set->bytes = (const uint8_t *)(" \t\r\n\v\f");
|
||||
set->len = 6;
|
||||
}
|
||||
}
|
||||
|
||||
static Janet cfun_string_trim(int32_t argc, Janet *argv) {
|
||||
JanetByteView str, set;
|
||||
trim_help_args(argc, argv, &str, &set);
|
||||
int32_t left_edge = trim_help_leftedge(str, set);
|
||||
int32_t right_edge = trim_help_rightedge(str, set);
|
||||
return janet_stringv(str.bytes + left_edge, right_edge - left_edge);
|
||||
}
|
||||
|
||||
static Janet cfun_string_triml(int32_t argc, Janet *argv) {
|
||||
JanetByteView str, set;
|
||||
trim_help_args(argc, argv, &str, &set);
|
||||
int32_t left_edge = trim_help_leftedge(str, set);
|
||||
return janet_stringv(str.bytes + left_edge, str.len - left_edge);
|
||||
}
|
||||
|
||||
static Janet cfun_string_trimr(int32_t argc, Janet *argv) {
|
||||
JanetByteView str, set;
|
||||
trim_help_args(argc, argv, &str, &set);
|
||||
int32_t right_edge = trim_help_rightedge(str, set);
|
||||
return janet_stringv(str.bytes, right_edge);
|
||||
}
|
||||
|
||||
static const JanetReg string_cfuns[] = {
|
||||
{
|
||||
"string/slice", cfun_string_slice,
|
||||
@@ -488,8 +542,8 @@ static const JanetReg string_cfuns[] = {
|
||||
},
|
||||
{
|
||||
"string/from-bytes", cfun_string_frombytes,
|
||||
JDOC("(string/from-bytes byte-array)\n\n"
|
||||
"Creates a string from an array of integers with byte values. All integers "
|
||||
JDOC("(string/from-bytes &byte-vals)\n\n"
|
||||
"Creates a string from integer params with byte values. All integers "
|
||||
"will be coerced to the range of 1 byte 0-255.")
|
||||
},
|
||||
{
|
||||
@@ -574,6 +628,24 @@ static const JanetReg string_cfuns[] = {
|
||||
"Similar to snprintf, but specialized for operating with janet. Returns "
|
||||
"a new string.")
|
||||
},
|
||||
{
|
||||
"string/trim", cfun_string_trim,
|
||||
JDOC("(string/trim str [,set])\n\n"
|
||||
"Trim leading and trailing whitespace from a byte sequence. If the argument "
|
||||
"set is provided, consider only characters in set to be whitespace.")
|
||||
},
|
||||
{
|
||||
"string/triml", cfun_string_triml,
|
||||
JDOC("(string/triml str [,set])\n\n"
|
||||
"Trim leading whitespace from a byte sequence. If the argument "
|
||||
"set is provided, consider only characters in set to be whitespace.")
|
||||
},
|
||||
{
|
||||
"string/trimr", cfun_string_trimr,
|
||||
JDOC("(string/trimr str [,set])\n\n"
|
||||
"Trim trailing whitespace from a byte sequence. If the argument "
|
||||
"set is provided, consider only characters in set to be whitespace.")
|
||||
},
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
|
||||
@@ -291,8 +291,9 @@ int janet_scan_number(
|
||||
if (*str == '.') {
|
||||
if (seenpoint) goto error;
|
||||
seenpoint = 1;
|
||||
} else {
|
||||
seenadigit = 1;
|
||||
}
|
||||
seenadigit = 1;
|
||||
str++;
|
||||
}
|
||||
|
||||
|
||||
@@ -115,6 +115,23 @@ static Janet cfun_tuple_type(int32_t argc, Janet *argv) {
|
||||
}
|
||||
}
|
||||
|
||||
static Janet cfun_tuple_sourcemap(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 1);
|
||||
const Janet *tup = janet_gettuple(argv, 0);
|
||||
Janet contents[2];
|
||||
contents[0] = janet_wrap_integer(janet_tuple_head(tup)->sm_start);
|
||||
contents[1] = janet_wrap_integer(janet_tuple_head(tup)->sm_end);
|
||||
return janet_wrap_tuple(janet_tuple_n(contents, 2));
|
||||
}
|
||||
|
||||
static Janet cfun_tuple_setmap(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 3);
|
||||
const Janet *tup = janet_gettuple(argv, 0);
|
||||
janet_tuple_head(tup)->sm_start = janet_getinteger(argv, 1);
|
||||
janet_tuple_head(tup)->sm_end = janet_getinteger(argv, 2);
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
static const JanetReg tuple_cfuns[] = {
|
||||
{
|
||||
"tuple/brackets", cfun_tuple_brackets,
|
||||
@@ -138,6 +155,20 @@ static const JanetReg tuple_cfuns[] = {
|
||||
"the time, but will print differently and be treated differently by "
|
||||
"the compiler.")
|
||||
},
|
||||
{
|
||||
"tuple/sourcemap", cfun_tuple_sourcemap,
|
||||
JDOC("(tuple/sourcemap tup)\n\n"
|
||||
"Returns the sourcemap metadata attached to a tuple. "
|
||||
"The mapping is represented by a pair of byte offsets into the "
|
||||
"the source code representing the start and end byte indices where "
|
||||
"the tuple is. ")
|
||||
},
|
||||
{
|
||||
"tuple/setmap", cfun_tuple_setmap,
|
||||
JDOC("(tuple/setmap tup start end)\n\n"
|
||||
"Set the sourcemap metadata on a tuple. start and end should "
|
||||
"be integers representing byte offsets into the file. Returns tup.")
|
||||
},
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
#ifndef JANET_UTIL_H_defined
|
||||
#define JANET_UTIL_H_defined
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifndef JANET_AMALG
|
||||
#include <janet.h>
|
||||
#endif
|
||||
|
||||
149
src/core/vm.c
149
src/core/vm.c
@@ -57,83 +57,13 @@ JANET_THREAD_LOCAL jmp_buf *janet_vm_jmp_buf = NULL;
|
||||
/* How we dispatch instructions. By default, we use
|
||||
* a switch inside an infinite loop. For GCC/clang, we use
|
||||
* computed gotos. */
|
||||
#ifdef ____GNUC__
|
||||
#ifdef __GNUC__
|
||||
#define VM_START() { goto *op_lookup[first_opcode];
|
||||
#define VM_END() }
|
||||
#define VM_OP(op) label_##op :
|
||||
#define VM_DEFAULT() label_unknown_op:
|
||||
#define vm_next() goto *op_lookup[*pc & 0xFF]
|
||||
static void *op_lookup[255] = {
|
||||
&&label_JOP_NOOP,
|
||||
&&label_JOP_ERROR,
|
||||
&&label_JOP_TYPECHECK,
|
||||
&&label_JOP_RETURN,
|
||||
&&label_JOP_RETURN_NIL,
|
||||
&&label_JOP_ADD_IMMEDIATE,
|
||||
&&label_JOP_ADD,
|
||||
&&label_JOP_SUBTRACT,
|
||||
&&label_JOP_MULTIPLY_IMMEDIATE,
|
||||
&&label_JOP_MULTIPLY,
|
||||
&&label_JOP_DIVIDE_IMMEDIATE,
|
||||
&&label_JOP_DIVIDE,
|
||||
&&label_JOP_BAND,
|
||||
&&label_JOP_BOR,
|
||||
&&label_JOP_BXOR,
|
||||
&&label_JOP_BNOT,
|
||||
&&label_JOP_SHIFT_LEFT,
|
||||
&&label_JOP_SHIFT_LEFT_IMMEDIATE,
|
||||
&&label_JOP_SHIFT_RIGHT,
|
||||
&&label_JOP_SHIFT_RIGHT_IMMEDIATE,
|
||||
&&label_JOP_SHIFT_RIGHT_UNSIGNED,
|
||||
&&label_JOP_SHIFT_RIGHT_UNSIGNED_IMMEDIATE,
|
||||
&&label_JOP_MOVE_FAR,
|
||||
&&label_JOP_MOVE_NEAR,
|
||||
&&label_JOP_JUMP,
|
||||
&&label_JOP_JUMP_IF,
|
||||
&&label_JOP_JUMP_IF_NOT,
|
||||
&&label_JOP_GREATER_THAN,
|
||||
&&label_JOP_GREATER_THAN_IMMEDIATE,
|
||||
&&label_JOP_LESS_THAN,
|
||||
&&label_JOP_LESS_THAN_IMMEDIATE,
|
||||
&&label_JOP_EQUALS,
|
||||
&&label_JOP_EQUALS_IMMEDIATE,
|
||||
&&label_JOP_COMPARE,
|
||||
&&label_JOP_LOAD_NIL,
|
||||
&&label_JOP_LOAD_TRUE,
|
||||
&&label_JOP_LOAD_FALSE,
|
||||
&&label_JOP_LOAD_INTEGER,
|
||||
&&label_JOP_LOAD_CONSTANT,
|
||||
&&label_JOP_LOAD_UPVALUE,
|
||||
&&label_JOP_LOAD_SELF,
|
||||
&&label_JOP_SET_UPVALUE,
|
||||
&&label_JOP_CLOSURE,
|
||||
&&label_JOP_PUSH,
|
||||
&&label_JOP_PUSH_2,
|
||||
&&label_JOP_PUSH_3,
|
||||
&&label_JOP_PUSH_ARRAY,
|
||||
&&label_JOP_CALL,
|
||||
&&label_JOP_TAILCALL,
|
||||
&&label_JOP_RESUME,
|
||||
&&label_JOP_SIGNAL,
|
||||
&&label_JOP_GET,
|
||||
&&label_JOP_PUT,
|
||||
&&label_JOP_GET_INDEX,
|
||||
&&label_JOP_PUT_INDEX,
|
||||
&&label_JOP_LENGTH,
|
||||
&&label_JOP_MAKE_ARRAY,
|
||||
&&label_JOP_MAKE_BUFFER,
|
||||
&&label_JOP_MAKE_STRING,
|
||||
&&label_JOP_MAKE_STRUCT,
|
||||
&&label_JOP_MAKE_TABLE,
|
||||
&&label_JOP_MAKE_TUPLE,
|
||||
&&label_JOP_MAKE_BRACKET_TUPLE,
|
||||
&&label_JOP_NUMERIC_LESS_THAN,
|
||||
&&label_JOP_NUMERIC_LESS_THAN_EQUAL,
|
||||
&&label_JOP_NUMERIC_GREATER_THAN,
|
||||
&&label_JOP_NUMERIC_GREATER_THAN_EQUAL,
|
||||
&&label_JOP_NUMERIC_EQUAL,
|
||||
&&label_unknown_op
|
||||
};
|
||||
#define opcode (*pc & 0xFF)
|
||||
#else
|
||||
#define VM_START() uint8_t opcode = first_opcode; for (;;) {switch(opcode) {
|
||||
#define VM_END() }}
|
||||
@@ -261,6 +191,81 @@ static Janet call_nonfn(JanetFiber *fiber, Janet callee) {
|
||||
/* Interpreter main loop */
|
||||
static JanetSignal run_vm(JanetFiber *fiber, Janet in, JanetFiberStatus status) {
|
||||
|
||||
/* opcode -> label lookup if using clang/GCC */
|
||||
#ifdef __GNUC__
|
||||
static void *op_lookup[255] = {
|
||||
&&label_JOP_NOOP,
|
||||
&&label_JOP_ERROR,
|
||||
&&label_JOP_TYPECHECK,
|
||||
&&label_JOP_RETURN,
|
||||
&&label_JOP_RETURN_NIL,
|
||||
&&label_JOP_ADD_IMMEDIATE,
|
||||
&&label_JOP_ADD,
|
||||
&&label_JOP_SUBTRACT,
|
||||
&&label_JOP_MULTIPLY_IMMEDIATE,
|
||||
&&label_JOP_MULTIPLY,
|
||||
&&label_JOP_DIVIDE_IMMEDIATE,
|
||||
&&label_JOP_DIVIDE,
|
||||
&&label_JOP_BAND,
|
||||
&&label_JOP_BOR,
|
||||
&&label_JOP_BXOR,
|
||||
&&label_JOP_BNOT,
|
||||
&&label_JOP_SHIFT_LEFT,
|
||||
&&label_JOP_SHIFT_LEFT_IMMEDIATE,
|
||||
&&label_JOP_SHIFT_RIGHT,
|
||||
&&label_JOP_SHIFT_RIGHT_IMMEDIATE,
|
||||
&&label_JOP_SHIFT_RIGHT_UNSIGNED,
|
||||
&&label_JOP_SHIFT_RIGHT_UNSIGNED_IMMEDIATE,
|
||||
&&label_JOP_MOVE_FAR,
|
||||
&&label_JOP_MOVE_NEAR,
|
||||
&&label_JOP_JUMP,
|
||||
&&label_JOP_JUMP_IF,
|
||||
&&label_JOP_JUMP_IF_NOT,
|
||||
&&label_JOP_GREATER_THAN,
|
||||
&&label_JOP_GREATER_THAN_IMMEDIATE,
|
||||
&&label_JOP_LESS_THAN,
|
||||
&&label_JOP_LESS_THAN_IMMEDIATE,
|
||||
&&label_JOP_EQUALS,
|
||||
&&label_JOP_EQUALS_IMMEDIATE,
|
||||
&&label_JOP_COMPARE,
|
||||
&&label_JOP_LOAD_NIL,
|
||||
&&label_JOP_LOAD_TRUE,
|
||||
&&label_JOP_LOAD_FALSE,
|
||||
&&label_JOP_LOAD_INTEGER,
|
||||
&&label_JOP_LOAD_CONSTANT,
|
||||
&&label_JOP_LOAD_UPVALUE,
|
||||
&&label_JOP_LOAD_SELF,
|
||||
&&label_JOP_SET_UPVALUE,
|
||||
&&label_JOP_CLOSURE,
|
||||
&&label_JOP_PUSH,
|
||||
&&label_JOP_PUSH_2,
|
||||
&&label_JOP_PUSH_3,
|
||||
&&label_JOP_PUSH_ARRAY,
|
||||
&&label_JOP_CALL,
|
||||
&&label_JOP_TAILCALL,
|
||||
&&label_JOP_RESUME,
|
||||
&&label_JOP_SIGNAL,
|
||||
&&label_JOP_GET,
|
||||
&&label_JOP_PUT,
|
||||
&&label_JOP_GET_INDEX,
|
||||
&&label_JOP_PUT_INDEX,
|
||||
&&label_JOP_LENGTH,
|
||||
&&label_JOP_MAKE_ARRAY,
|
||||
&&label_JOP_MAKE_BUFFER,
|
||||
&&label_JOP_MAKE_STRING,
|
||||
&&label_JOP_MAKE_STRUCT,
|
||||
&&label_JOP_MAKE_TABLE,
|
||||
&&label_JOP_MAKE_TUPLE,
|
||||
&&label_JOP_MAKE_BRACKET_TUPLE,
|
||||
&&label_JOP_NUMERIC_LESS_THAN,
|
||||
&&label_JOP_NUMERIC_LESS_THAN_EQUAL,
|
||||
&&label_JOP_NUMERIC_GREATER_THAN,
|
||||
&&label_JOP_NUMERIC_GREATER_THAN_EQUAL,
|
||||
&&label_JOP_NUMERIC_EQUAL,
|
||||
&&label_unknown_op
|
||||
};
|
||||
#endif
|
||||
|
||||
/* Interpreter state */
|
||||
register Janet *stack;
|
||||
register uint32_t *pc;
|
||||
|
||||
@@ -51,6 +51,7 @@ extern "C" {
|
||||
|| defined(__FreeBSD__) || defined(__DragonFly__) \
|
||||
|| defined(__FreeBSD_kernel__) \
|
||||
|| defined(__GNU__) /* GNU/Hurd */ \
|
||||
|| defined(__HAIKU__) \
|
||||
|| defined(__linux__) \
|
||||
|| defined(__NetBSD__) \
|
||||
|| defined(__OpenBSD__) \
|
||||
@@ -183,15 +184,38 @@ extern "C" {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Alignment for pointers */
|
||||
#ifndef JANET_WALIGN
|
||||
#ifdef JANET_32
|
||||
#define JANET_WALIGN 4
|
||||
/* Runtime config constants */
|
||||
#ifdef JANET_NO_NANBOX
|
||||
#define JANET_NANBOX_BIT 0
|
||||
#else
|
||||
#define JANET_WALIGN 8
|
||||
#define JANET_NANBOX_BIT 0x1
|
||||
#endif
|
||||
|
||||
#ifdef JANET_SINGLE_THREADED
|
||||
#define JANET_SINGLE_THREADED_BIT 0x2
|
||||
#else
|
||||
#define JANET_SINGLE_THREADED_BIT 0
|
||||
#endif
|
||||
|
||||
#define JANET_CURRENT_CONFIG_BITS \
|
||||
(JANET_SINGLE_THREADED_BIT | \
|
||||
JANET_NANBOX_BIT)
|
||||
|
||||
/* Represents the settings used to compile Janet, as well as the version */
|
||||
typedef struct {
|
||||
unsigned major;
|
||||
unsigned minor;
|
||||
unsigned patch;
|
||||
unsigned bits;
|
||||
} JanetBuildConfig;
|
||||
|
||||
/* Get config of current compilation unit. */
|
||||
#define janet_config_current() ((JanetBuildConfig){ \
|
||||
JANET_VERSION_MAJOR, \
|
||||
JANET_VERSION_MINOR, \
|
||||
JANET_VERSION_PATCH, \
|
||||
JANET_CURRENT_CONFIG_BITS })
|
||||
|
||||
/***** END SECTION CONFIG *****/
|
||||
|
||||
/***** START SECTION TYPES *****/
|
||||
@@ -326,12 +350,12 @@ typedef enum JanetType {
|
||||
#define JANET_TFLAG_ABSTRACT (1 << JANET_ABSTRACT)
|
||||
#define JANET_TFLAG_POINTER (1 << JANET_POINTER)
|
||||
|
||||
/* Some abstractions */
|
||||
#define JANET_TFLAG_BYTES (JANET_TFLAG_STRING | JANET_TFLAG_SYMBOL | JANET_TFLAG_BUFFER | JANET_TFLAG_KEYWORD)
|
||||
#define JANET_TFLAG_INDEXED (JANET_TFLAG_ARRAY | JANET_TFLAG_TUPLE)
|
||||
#define JANET_TFLAG_DICTIONARY (JANET_TFLAG_TABLE | JANET_TFLAG_STRUCT)
|
||||
#define JANET_TFLAG_LENGTHABLE (JANET_TFLAG_BYTES | JANET_TFLAG_INDEXED | JANET_TFLAG_DICTIONARY)
|
||||
#define JANET_TFLAG_CALLABLE (JANET_TFLAG_FUNCTION | JANET_TFLAG_CFUNCTION)
|
||||
#define JANET_TFLAG_CALLABLE (JANET_TFLAG_FUNCTION | JANET_TFLAG_CFUNCTION | \
|
||||
JANET_TFLAG_LENGTHABLE | JANET_TFLAG_ABSTRACT)
|
||||
|
||||
/* We provide three possible implementations of Janets. The preferred
|
||||
* nanboxing approach, for 32 or 64 bits, and the standard C version. Code in the rest of the
|
||||
@@ -761,6 +785,7 @@ struct JanetAbstractHead {
|
||||
#define JANET_FUNCDEF_FLAG_HASDEFS 0x200000
|
||||
#define JANET_FUNCDEF_FLAG_HASENVS 0x400000
|
||||
#define JANET_FUNCDEF_FLAG_HASSOURCEMAP 0x800000
|
||||
#define JANET_FUNCDEF_FLAG_STRUCTARG 0x1000000
|
||||
#define JANET_FUNCDEF_FLAG_TAG 0xFFFF
|
||||
|
||||
/* Source mapping structure for a bytecode instruction */
|
||||
@@ -1191,6 +1216,7 @@ JANET_API void *janet_abstract(const JanetAbstractType *type, size_t size);
|
||||
|
||||
/* Native */
|
||||
typedef void (*JanetModule)(JanetTable *);
|
||||
typedef JanetBuildConfig(*JanetModconf)(void);
|
||||
JANET_API JanetModule janet_native(const char *name, const uint8_t **error);
|
||||
|
||||
/* Marshaling */
|
||||
@@ -1261,7 +1287,12 @@ JANET_API void janet_register(const char *name, JanetCFunction cfun);
|
||||
|
||||
/* New C API */
|
||||
|
||||
#define JANET_MODULE_ENTRY JANET_API void _janet_init
|
||||
#define JANET_MODULE_ENTRY \
|
||||
JANET_API JanetBuildConfig _janet_mod_config(void) { \
|
||||
return janet_config_current(); \
|
||||
} \
|
||||
JANET_API void _janet_init
|
||||
|
||||
JANET_API void janet_panicv(Janet message);
|
||||
JANET_API void janet_panic(const char *message);
|
||||
JANET_API void janet_panics(const uint8_t *message);
|
||||
|
||||
@@ -25,23 +25,29 @@
|
||||
#ifndef JANETCONF_H
|
||||
#define JANETCONF_H
|
||||
|
||||
#define JANET_VERSION "0.5.0"
|
||||
#define JANET_VERSION_MAJOR 0
|
||||
#define JANET_VERSION_MINOR 6
|
||||
#define JANET_VERSION_PATCH 0
|
||||
#define JANET_VERSION_EXTRA "-dev"
|
||||
#define JANET_VERSION "0.6.0-dev"
|
||||
|
||||
/* #define JANET_BUILD "local" */
|
||||
|
||||
/* These settings all affect linking, so use cautiously. */
|
||||
/* #define JANET_SINGLE_THREADED */
|
||||
/* #define JANET_NO_DYNAMIC_MODULES */
|
||||
/* #define JANET_NO_NANBOX */
|
||||
/* #define JANET_API __attribute__((visibility ("default"))) */
|
||||
|
||||
/* #define JANET_NO_ASSEMBLER */
|
||||
/* #define JANET_NO_PEG */
|
||||
/* #define JANET_NO_TYPED_ARRAY */
|
||||
/* #define JANET_NO_INT_TYPES */
|
||||
/* #define JANET_REDUCED_OS */
|
||||
/* #define JANET_API __attribute__((visibility ("default"))) */
|
||||
/* #define JANET_OUT_OF_MEMORY do { printf("janet out of memory\n"); exit(1); } while (0) */
|
||||
/* #define JANET_RECURSION_GUARD 1024 */
|
||||
/* #define JANET_MAX_PROTO_DEPTH 200 */
|
||||
/* #define JANET_MAX_MACRO_EXPAND 200 */
|
||||
/* #define JANET_STACK_MAX 16384 */
|
||||
/* #define JANET_NO_NANBOX */
|
||||
/* #define JANET_WALIGN 8 */
|
||||
|
||||
#endif /* end of include guard: JANETCONF_H */
|
||||
|
||||
@@ -9,8 +9,10 @@
|
||||
(var *handleopts* true)
|
||||
(var *exit-on-error* true)
|
||||
(var *colorize* true)
|
||||
(var *compile-only* false)
|
||||
|
||||
(if-let [jp (os/getenv "JANET_PATH")] (set module/*syspath* jp))
|
||||
(if-let [jp (os/getenv "JANET_HEADERPATH")] (set module/*headerpath* jp))
|
||||
|
||||
# Flag handlers
|
||||
(def handlers :private
|
||||
@@ -25,6 +27,7 @@
|
||||
-r : Enter the repl after running all scripts
|
||||
-p : Keep on executing if there is a top level error (persistent)
|
||||
-q : Hide prompt, logo, and repl output (quiet)
|
||||
-k : Compile scripts but do not execute
|
||||
-m syspath : Set system path for loading global modules
|
||||
-c source output : Compile janet source code into an image
|
||||
-n : Disable ANSI color output in the repl
|
||||
@@ -37,6 +40,7 @@
|
||||
"r" (fn [&] (set *should-repl* true) 1)
|
||||
"p" (fn [&] (set *exit-on-error* false) 1)
|
||||
"q" (fn [&] (set *quiet* true) 1)
|
||||
"k" (fn [&] (set *compile-only* true) (set *exit-on-error* false) 1)
|
||||
"n" (fn [&] (set *colorize* false) 1)
|
||||
"m" (fn [i &] (set module/*syspath* (get process/args (+ i 1))) 2)
|
||||
"c" (fn [i &]
|
||||
@@ -67,10 +71,10 @@
|
||||
(+= i (dohandler (string/slice arg 1 2) i))
|
||||
(do
|
||||
(set *no-file* false)
|
||||
(import* arg :prefix "" :exit *exit-on-error*)
|
||||
(import* arg :prefix "" :exit *exit-on-error* :compile-only *compile-only*)
|
||||
(set i lenargs))))
|
||||
|
||||
(when (or *should-repl* *no-file*)
|
||||
(when (and (not *compile-only*) (or *should-repl* *no-file*))
|
||||
(if-not *quiet*
|
||||
(print "Janet " janet/version "-" janet/build " Copyright (C) 2017-2019 Calvin Rose"))
|
||||
(defn noprompt [_] "")
|
||||
|
||||
@@ -23,6 +23,13 @@
|
||||
#include <janet.h>
|
||||
#include "line.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
|
||||
#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
|
||||
#endif
|
||||
#endif
|
||||
|
||||
extern const unsigned char *janet_gen_init;
|
||||
extern int32_t janet_gen_init_size;
|
||||
|
||||
@@ -31,6 +38,15 @@ int main(int argc, char **argv) {
|
||||
JanetArray *args;
|
||||
JanetTable *env;
|
||||
|
||||
/* Enable color console on windows 10 console. */
|
||||
#ifdef _WIN32
|
||||
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
DWORD dwMode = 0;
|
||||
GetConsoleMode(hOut, &dwMode);
|
||||
dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
||||
SetConsoleMode(hOut, dwMode);
|
||||
#endif
|
||||
|
||||
/* Set up VM */
|
||||
janet_init();
|
||||
|
||||
|
||||
36
test/amalg/main.c
Normal file
36
test/amalg/main.c
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* A simple client for checking if the amalgamated Janet source compiles
|
||||
* correctly. */
|
||||
|
||||
#include <janet.h>
|
||||
|
||||
int main(int argc, const char *argv[]) {
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
janet_init();
|
||||
JanetTable *env = janet_core_env(NULL);
|
||||
janet_dostring(env, "(print `hello, world!`)", "main", NULL);
|
||||
janet_deinit();
|
||||
return 0;
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
(import cook)
|
||||
|
||||
(cook/make-native
|
||||
:name "testmod"
|
||||
:source @["testmod.c"])
|
||||
|
||||
(import build/testmod :as testmod)
|
||||
|
||||
(if (not= 5 (testmod/get5)) (error "testmod/get5 failed"))
|
||||
|
||||
(print "OK!")
|
||||
7
test/install/project.janet
Normal file
7
test/install/project.janet
Normal file
@@ -0,0 +1,7 @@
|
||||
(declare-project
|
||||
:name "testmod")
|
||||
|
||||
(declare-native
|
||||
:name "testmod"
|
||||
:source @["testmod.c"])
|
||||
|
||||
3
test/install/test/test1.janet
Normal file
3
test/install/test/test1.janet
Normal file
@@ -0,0 +1,3 @@
|
||||
(import build/testmod :as testmod)
|
||||
|
||||
(if (not= 5 (testmod/get5)) (error "testmod/get5 failed"))
|
||||
@@ -300,5 +300,8 @@
|
||||
(assert (= (length {1 2 3 nil}) 1) "nil value struct literal")
|
||||
(assert (= (length @{1 2 3 nil}) 1) "nil value table literal")
|
||||
|
||||
# Regression Test
|
||||
(assert (= 1 (((compile '(fn [] 1) @{})))) "regression test")
|
||||
|
||||
(end-suite)
|
||||
|
||||
|
||||
@@ -83,6 +83,16 @@
|
||||
(assert (= (string/join @["one" "two" "three"] ", ") "one, two, three") "string/join 2")
|
||||
(assert (= (string/join @["one" "two" "three"]) "onetwothree") "string/join 3")
|
||||
(assert (= (string/join @[] "hi") "") "string/join 4")
|
||||
(assert (= (string/trim " abcd ") "abcd") "string/trim 1")
|
||||
(assert (= (string/trim "abcd \t\t\r\f") "abcd") "string/trim 2")
|
||||
(assert (= (string/trim "\n\n\t abcd") "abcd") "string/trim 3")
|
||||
(assert (= (string/trim "") "") "string/trim 4")
|
||||
(assert (= (string/triml " abcd ") "abcd ") "string/triml 1")
|
||||
(assert (= (string/triml "\tabcd \t\t\r\f") "abcd \t\t\r\f") "string/triml 2")
|
||||
(assert (= (string/triml "abcd ") "abcd ") "string/triml 3")
|
||||
(assert (= (string/trimr " abcd ") " abcd") "string/trimr 1")
|
||||
(assert (= (string/trimr "\tabcd \t\t\r\f") "\tabcd") "string/trimr 2")
|
||||
(assert (= (string/trimr " abcd") " abcd") "string/trimr 3")
|
||||
(assert (deep= (string/split "," "one,two,three") @["one" "two" "three"]) "string/split 1")
|
||||
(assert (deep= (string/split "," "onetwothree") @["onetwothree"]) "string/split 2")
|
||||
(assert (deep= (string/find-all "e" "onetwothree") @[2 9 10]) "string/find-all 1")
|
||||
|
||||
@@ -96,4 +96,17 @@
|
||||
(setdyn :a 100)
|
||||
(assert (= 100 (dyn :a)) "dyn usage 4")
|
||||
|
||||
# Keyword arguments
|
||||
(defn myfn [x y z &keys {:a a :b b :c c}]
|
||||
(+ x y z a b c))
|
||||
|
||||
(assert (= (+ ;(range 6)) (myfn 0 1 2 :a 3 :b 4 :c 5)) "keyword args 1")
|
||||
(assert (= (+ ;(range 6)) (myfn 0 1 2 :a 1 :b 6 :c 5 :d 11)) "keyword args 2")
|
||||
|
||||
# Comment macro
|
||||
(comment 1)
|
||||
(comment 1 2)
|
||||
(comment 1 2 3)
|
||||
(comment 1 2 3 4)
|
||||
|
||||
(end-suite)
|
||||
|
||||
327
tools/EnvVarUpdate.nsh
Normal file
327
tools/EnvVarUpdate.nsh
Normal file
@@ -0,0 +1,327 @@
|
||||
/**
|
||||
* EnvVarUpdate.nsh
|
||||
* : Environmental Variables: append, prepend, and remove entries
|
||||
*
|
||||
* WARNING: If you use StrFunc.nsh header then include it before this file
|
||||
* with all required definitions. This is to avoid conflicts
|
||||
*
|
||||
* Usage:
|
||||
* ${EnvVarUpdate} "ResultVar" "EnvVarName" "Action" "RegLoc" "PathString"
|
||||
*
|
||||
* Credits:
|
||||
* Version 1.0
|
||||
* * Cal Turney (turnec2)
|
||||
* * Amir Szekely (KiCHiK) and e-circ for developing the forerunners of this
|
||||
* function: AddToPath, un.RemoveFromPath, AddToEnvVar, un.RemoveFromEnvVar,
|
||||
* WriteEnvStr, and un.DeleteEnvStr
|
||||
* * Diego Pedroso (deguix) for StrTok
|
||||
* * Kevin English (kenglish_hi) for StrContains
|
||||
* * Hendri Adriaens (Smile2Me), Diego Pedroso (deguix), and Dan Fuhry
|
||||
* (dandaman32) for StrReplace
|
||||
*
|
||||
* Version 1.1 (compatibility with StrFunc.nsh)
|
||||
* * techtonik
|
||||
*
|
||||
* http://nsis.sourceforge.net/Environmental_Variables:_append%2C_prepend%2C_and_remove_entries
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
!ifndef ENVVARUPDATE_FUNCTION
|
||||
!define ENVVARUPDATE_FUNCTION
|
||||
!verbose push
|
||||
!verbose 3
|
||||
!include "LogicLib.nsh"
|
||||
!include "WinMessages.NSH"
|
||||
!include "StrFunc.nsh"
|
||||
|
||||
; ---- Fix for conflict if StrFunc.nsh is already includes in main file -----------------------
|
||||
!macro _IncludeStrFunction StrFuncName
|
||||
!ifndef ${StrFuncName}_INCLUDED
|
||||
${${StrFuncName}}
|
||||
!endif
|
||||
!ifndef Un${StrFuncName}_INCLUDED
|
||||
${Un${StrFuncName}}
|
||||
!endif
|
||||
!define un.${StrFuncName} "${Un${StrFuncName}}"
|
||||
!macroend
|
||||
|
||||
!insertmacro _IncludeStrFunction StrTok
|
||||
!insertmacro _IncludeStrFunction StrStr
|
||||
!insertmacro _IncludeStrFunction StrRep
|
||||
|
||||
; ---------------------------------- Macro Definitions ----------------------------------------
|
||||
!macro _EnvVarUpdateConstructor ResultVar EnvVarName Action Regloc PathString
|
||||
Push "${EnvVarName}"
|
||||
Push "${Action}"
|
||||
Push "${RegLoc}"
|
||||
Push "${PathString}"
|
||||
Call EnvVarUpdate
|
||||
Pop "${ResultVar}"
|
||||
!macroend
|
||||
!define EnvVarUpdate '!insertmacro "_EnvVarUpdateConstructor"'
|
||||
|
||||
!macro _unEnvVarUpdateConstructor ResultVar EnvVarName Action Regloc PathString
|
||||
Push "${EnvVarName}"
|
||||
Push "${Action}"
|
||||
Push "${RegLoc}"
|
||||
Push "${PathString}"
|
||||
Call un.EnvVarUpdate
|
||||
Pop "${ResultVar}"
|
||||
!macroend
|
||||
!define un.EnvVarUpdate '!insertmacro "_unEnvVarUpdateConstructor"'
|
||||
; ---------------------------------- Macro Definitions end-------------------------------------
|
||||
|
||||
;----------------------------------- EnvVarUpdate start----------------------------------------
|
||||
!define hklm_all_users 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"'
|
||||
!define hkcu_current_user 'HKCU "Environment"'
|
||||
|
||||
!macro EnvVarUpdate UN
|
||||
|
||||
Function ${UN}EnvVarUpdate
|
||||
|
||||
Push $0
|
||||
Exch 4
|
||||
Exch $1
|
||||
Exch 3
|
||||
Exch $2
|
||||
Exch 2
|
||||
Exch $3
|
||||
Exch
|
||||
Exch $4
|
||||
Push $5
|
||||
Push $6
|
||||
Push $7
|
||||
Push $8
|
||||
Push $9
|
||||
Push $R0
|
||||
|
||||
/* After this point:
|
||||
-------------------------
|
||||
$0 = ResultVar (returned)
|
||||
$1 = EnvVarName (input)
|
||||
$2 = Action (input)
|
||||
$3 = RegLoc (input)
|
||||
$4 = PathString (input)
|
||||
$5 = Orig EnvVar (read from registry)
|
||||
$6 = Len of $0 (temp)
|
||||
$7 = tempstr1 (temp)
|
||||
$8 = Entry counter (temp)
|
||||
$9 = tempstr2 (temp)
|
||||
$R0 = tempChar (temp) */
|
||||
|
||||
; Step 1: Read contents of EnvVarName from RegLoc
|
||||
;
|
||||
; Check for empty EnvVarName
|
||||
${If} $1 == ""
|
||||
SetErrors
|
||||
DetailPrint "ERROR: EnvVarName is blank"
|
||||
Goto EnvVarUpdate_Restore_Vars
|
||||
${EndIf}
|
||||
|
||||
; Check for valid Action
|
||||
${If} $2 != "A"
|
||||
${AndIf} $2 != "P"
|
||||
${AndIf} $2 != "R"
|
||||
SetErrors
|
||||
DetailPrint "ERROR: Invalid Action - must be A, P, or R"
|
||||
Goto EnvVarUpdate_Restore_Vars
|
||||
${EndIf}
|
||||
|
||||
${If} $3 == HKLM
|
||||
ReadRegStr $5 ${hklm_all_users} $1 ; Get EnvVarName from all users into $5
|
||||
${ElseIf} $3 == HKCU
|
||||
ReadRegStr $5 ${hkcu_current_user} $1 ; Read EnvVarName from current user into $5
|
||||
${Else}
|
||||
SetErrors
|
||||
DetailPrint 'ERROR: Action is [$3] but must be "HKLM" or HKCU"'
|
||||
Goto EnvVarUpdate_Restore_Vars
|
||||
${EndIf}
|
||||
|
||||
; Check for empty PathString
|
||||
${If} $4 == ""
|
||||
SetErrors
|
||||
DetailPrint "ERROR: PathString is blank"
|
||||
Goto EnvVarUpdate_Restore_Vars
|
||||
${EndIf}
|
||||
|
||||
; Make sure we've got some work to do
|
||||
${If} $5 == ""
|
||||
${AndIf} $2 == "R"
|
||||
SetErrors
|
||||
DetailPrint "$1 is empty - Nothing to remove"
|
||||
Goto EnvVarUpdate_Restore_Vars
|
||||
${EndIf}
|
||||
|
||||
; Step 2: Scrub EnvVar
|
||||
;
|
||||
StrCpy $0 $5 ; Copy the contents to $0
|
||||
; Remove spaces around semicolons (NOTE: spaces before the 1st entry or
|
||||
; after the last one are not removed here but instead in Step 3)
|
||||
${If} $0 != "" ; If EnvVar is not empty ...
|
||||
${Do}
|
||||
${${UN}StrStr} $7 $0 " ;"
|
||||
${If} $7 == ""
|
||||
${ExitDo}
|
||||
${EndIf}
|
||||
${${UN}StrRep} $0 $0 " ;" ";" ; Remove '<space>;'
|
||||
${Loop}
|
||||
${Do}
|
||||
${${UN}StrStr} $7 $0 "; "
|
||||
${If} $7 == ""
|
||||
${ExitDo}
|
||||
${EndIf}
|
||||
${${UN}StrRep} $0 $0 "; " ";" ; Remove ';<space>'
|
||||
${Loop}
|
||||
${Do}
|
||||
${${UN}StrStr} $7 $0 ";;"
|
||||
${If} $7 == ""
|
||||
${ExitDo}
|
||||
${EndIf}
|
||||
${${UN}StrRep} $0 $0 ";;" ";"
|
||||
${Loop}
|
||||
|
||||
; Remove a leading or trailing semicolon from EnvVar
|
||||
StrCpy $7 $0 1 0
|
||||
${If} $7 == ";"
|
||||
StrCpy $0 $0 "" 1 ; Change ';<EnvVar>' to '<EnvVar>'
|
||||
${EndIf}
|
||||
StrLen $6 $0
|
||||
IntOp $6 $6 - 1
|
||||
StrCpy $7 $0 1 $6
|
||||
${If} $7 == ";"
|
||||
StrCpy $0 $0 $6 ; Change ';<EnvVar>' to '<EnvVar>'
|
||||
${EndIf}
|
||||
; DetailPrint "Scrubbed $1: [$0]" ; Uncomment to debug
|
||||
${EndIf}
|
||||
|
||||
/* Step 3. Remove all instances of the target path/string (even if "A" or "P")
|
||||
$6 = bool flag (1 = found and removed PathString)
|
||||
$7 = a string (e.g. path) delimited by semicolon(s)
|
||||
$8 = entry counter starting at 0
|
||||
$9 = copy of $0
|
||||
$R0 = tempChar */
|
||||
|
||||
${If} $5 != "" ; If EnvVar is not empty ...
|
||||
StrCpy $9 $0
|
||||
StrCpy $0 ""
|
||||
StrCpy $8 0
|
||||
StrCpy $6 0
|
||||
|
||||
${Do}
|
||||
${${UN}StrTok} $7 $9 ";" $8 "0" ; $7 = next entry, $8 = entry counter
|
||||
|
||||
${If} $7 == "" ; If we've run out of entries,
|
||||
${ExitDo} ; were done
|
||||
${EndIf} ;
|
||||
|
||||
; Remove leading and trailing spaces from this entry (critical step for Action=Remove)
|
||||
${Do}
|
||||
StrCpy $R0 $7 1
|
||||
${If} $R0 != " "
|
||||
${ExitDo}
|
||||
${EndIf}
|
||||
StrCpy $7 $7 "" 1 ; Remove leading space
|
||||
${Loop}
|
||||
${Do}
|
||||
StrCpy $R0 $7 1 -1
|
||||
${If} $R0 != " "
|
||||
${ExitDo}
|
||||
${EndIf}
|
||||
StrCpy $7 $7 -1 ; Remove trailing space
|
||||
${Loop}
|
||||
${If} $7 == $4 ; If string matches, remove it by not appending it
|
||||
StrCpy $6 1 ; Set 'found' flag
|
||||
${ElseIf} $7 != $4 ; If string does NOT match
|
||||
${AndIf} $0 == "" ; and the 1st string being added to $0,
|
||||
StrCpy $0 $7 ; copy it to $0 without a prepended semicolon
|
||||
${ElseIf} $7 != $4 ; If string does NOT match
|
||||
${AndIf} $0 != "" ; and this is NOT the 1st string to be added to $0,
|
||||
StrCpy $0 $0;$7 ; append path to $0 with a prepended semicolon
|
||||
${EndIf} ;
|
||||
|
||||
IntOp $8 $8 + 1 ; Bump counter
|
||||
${Loop} ; Check for duplicates until we run out of paths
|
||||
${EndIf}
|
||||
|
||||
; Step 4: Perform the requested Action
|
||||
;
|
||||
${If} $2 != "R" ; If Append or Prepend
|
||||
${If} $6 == 1 ; And if we found the target
|
||||
DetailPrint "Target is already present in $1. It will be removed and"
|
||||
${EndIf}
|
||||
${If} $0 == "" ; If EnvVar is (now) empty
|
||||
StrCpy $0 $4 ; just copy PathString to EnvVar
|
||||
${If} $6 == 0 ; If found flag is either 0
|
||||
${OrIf} $6 == "" ; or blank (if EnvVarName is empty)
|
||||
DetailPrint "$1 was empty and has been updated with the target"
|
||||
${EndIf}
|
||||
${ElseIf} $2 == "A" ; If Append (and EnvVar is not empty),
|
||||
StrCpy $0 $0;$4 ; append PathString
|
||||
${If} $6 == 1
|
||||
DetailPrint "appended to $1"
|
||||
${Else}
|
||||
DetailPrint "Target was appended to $1"
|
||||
${EndIf}
|
||||
${Else} ; If Prepend (and EnvVar is not empty),
|
||||
StrCpy $0 $4;$0 ; prepend PathString
|
||||
${If} $6 == 1
|
||||
DetailPrint "prepended to $1"
|
||||
${Else}
|
||||
DetailPrint "Target was prepended to $1"
|
||||
${EndIf}
|
||||
${EndIf}
|
||||
${Else} ; If Action = Remove
|
||||
${If} $6 == 1 ; and we found the target
|
||||
DetailPrint "Target was found and removed from $1"
|
||||
${Else}
|
||||
DetailPrint "Target was NOT found in $1 (nothing to remove)"
|
||||
${EndIf}
|
||||
${If} $0 == ""
|
||||
DetailPrint "$1 is now empty"
|
||||
${EndIf}
|
||||
${EndIf}
|
||||
|
||||
; Step 5: Update the registry at RegLoc with the updated EnvVar and announce the change
|
||||
;
|
||||
ClearErrors
|
||||
${If} $3 == HKLM
|
||||
WriteRegExpandStr ${hklm_all_users} $1 $0 ; Write it in all users section
|
||||
${ElseIf} $3 == HKCU
|
||||
WriteRegExpandStr ${hkcu_current_user} $1 $0 ; Write it to current user section
|
||||
${EndIf}
|
||||
|
||||
IfErrors 0 +4
|
||||
MessageBox MB_OK|MB_ICONEXCLAMATION "Could not write updated $1 to $3"
|
||||
DetailPrint "Could not write updated $1 to $3"
|
||||
Goto EnvVarUpdate_Restore_Vars
|
||||
|
||||
; "Export" our change
|
||||
SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
|
||||
|
||||
EnvVarUpdate_Restore_Vars:
|
||||
;
|
||||
; Restore the user's variables and return ResultVar
|
||||
Pop $R0
|
||||
Pop $9
|
||||
Pop $8
|
||||
Pop $7
|
||||
Pop $6
|
||||
Pop $5
|
||||
Pop $4
|
||||
Pop $3
|
||||
Pop $2
|
||||
Pop $1
|
||||
Push $0 ; Push my $0 (ResultVar)
|
||||
Exch
|
||||
Pop $0 ; Restore his $0
|
||||
|
||||
FunctionEnd
|
||||
|
||||
!macroend ; EnvVarUpdate UN
|
||||
!insertmacro EnvVarUpdate ""
|
||||
!insertmacro EnvVarUpdate "un."
|
||||
;----------------------------------- EnvVarUpdate end----------------------------------------
|
||||
|
||||
!verbose pop
|
||||
!endif
|
||||
366
tools/cook.janet
366
tools/cook.janet
@@ -1,5 +1,13 @@
|
||||
# Library to help build janet natives and other
|
||||
# build artifacts.
|
||||
### cook.janet
|
||||
###
|
||||
### Library to help build janet natives and other
|
||||
### build artifacts.
|
||||
###
|
||||
### Copyright 2019 © Calvin Rose
|
||||
|
||||
#
|
||||
# Basic Path Settings
|
||||
#
|
||||
|
||||
# Windows is the OS outlier
|
||||
(def- is-win (= (os/which) :windows))
|
||||
@@ -8,18 +16,142 @@
|
||||
(def- objext (if is-win ".obj" ".o"))
|
||||
(def- modext (if is-win ".dll" ".so"))
|
||||
|
||||
(def prefix (or (os/getenv "PREFIX") "/usr/local"))
|
||||
#
|
||||
# Rule Engine
|
||||
#
|
||||
|
||||
(defn- getrules []
|
||||
(def rules (dyn :rules))
|
||||
(if rules rules (setdyn :rules @{})))
|
||||
|
||||
(defn- gettarget [target]
|
||||
(def item ((getrules) target))
|
||||
(unless item (error (string "No rule for target " target)))
|
||||
item)
|
||||
|
||||
(defn- rule-impl
|
||||
[target deps thunk &opt phony]
|
||||
(put (getrules) target @[(array/slice deps) thunk phony]))
|
||||
|
||||
(defmacro rule
|
||||
"Add a rule to the rule graph."
|
||||
[target deps & body]
|
||||
~(,rule-impl ,target ,deps (fn [] nil ,;body)))
|
||||
|
||||
(defmacro phony
|
||||
"Add a phony rule to the rule graph. A phony rule will run every time
|
||||
(it is always considered out of date). Phony rules are good for defining
|
||||
user facing tasks."
|
||||
[target deps & body]
|
||||
~(,rule-impl ,target ,deps (fn [] nil ,;body) true))
|
||||
|
||||
(defn add-dep
|
||||
"Add a dependency to an existing rule. Useful for extending phony
|
||||
rules or extending the dependency graph of existing rules."
|
||||
[target dep]
|
||||
(def [deps] (gettarget target))
|
||||
(array/push deps dep))
|
||||
|
||||
(defn- add-thunk
|
||||
[target more]
|
||||
(def item (gettarget target))
|
||||
(def [_ thunk] item)
|
||||
(put item 1 (fn [] (more) (thunk))))
|
||||
|
||||
(defmacro add-body
|
||||
"Add recipe code to an existing rule. This makes existing rules do more but
|
||||
does not modify the dependency graph."
|
||||
[target & body]
|
||||
~(,add-thunk ,target (fn [] ,;body)))
|
||||
|
||||
(defn- needs-build
|
||||
[dest src]
|
||||
(let [mod-dest (os/stat dest :modified)
|
||||
mod-src (os/stat src :modified)]
|
||||
(< mod-dest mod-src)))
|
||||
|
||||
(defn- needs-build-some
|
||||
[dest sources]
|
||||
(def f (file/open dest))
|
||||
(if (not f) (break true))
|
||||
(file/close f)
|
||||
(some (partial needs-build dest) sources))
|
||||
|
||||
(defn do-rule
|
||||
"Evaluate a given rule."
|
||||
[target]
|
||||
(def item ((getrules) target))
|
||||
(unless item
|
||||
(if (os/stat target :mode)
|
||||
(break target)
|
||||
(error (string "No rule for file " target " found."))))
|
||||
(def [deps thunk phony] item)
|
||||
(def realdeps (seq [dep :in deps :let [x (do-rule dep)] :when x] x))
|
||||
(when (or phony (needs-build-some target realdeps))
|
||||
(thunk))
|
||||
(unless phony target))
|
||||
|
||||
(def- _env (fiber/getenv (fiber/current)))
|
||||
(defn- import-rules*
|
||||
[path & args]
|
||||
(def [realpath] (module/find path))
|
||||
(def env (make-env))
|
||||
(loop [k :keys _env :when (symbol? k)]
|
||||
(unless ((_env k) :private) (put env k (_env k))))
|
||||
(def currenv (fiber/getenv (fiber/current)))
|
||||
(loop [k :keys currenv :when (keyword? k)]
|
||||
(put env k (currenv k)))
|
||||
(require path :env env ;args)
|
||||
(when-let [rules (env :rules)] (merge-into (getrules) rules)))
|
||||
|
||||
(defmacro import-rules
|
||||
"Import another file that defines more cook rules. This ruleset
|
||||
is merged into the current ruleset."
|
||||
[path & args]
|
||||
~(,import-rules* ,(string path) ,;args))
|
||||
|
||||
#
|
||||
# Configuration
|
||||
#
|
||||
|
||||
# Installation settings
|
||||
(def JANET_MODPATH (or (os/getenv "JANET_MODPATH") module/*syspath*))
|
||||
(def JANET_HEADERPATH (or (os/getenv "JANET_HEADERPATH") module/*headerpath*))
|
||||
(def JANET_BINPATH (or (os/getenv "JANET_BINPATH") (unless is-win "/usr/local/bin")))
|
||||
|
||||
# Compilation settings
|
||||
(def OPTIMIZE (or (os/getenv "OPTIMIZE") 2))
|
||||
(def CC (or (os/getenv "CC") (if is-win "cl" "cc")))
|
||||
(def LD (or (os/getenv "LINKER") (if is-win "link" CC)))
|
||||
(def LDFLAGS (or (os/getenv "LFLAGS")
|
||||
(if is-win " /nologo"
|
||||
(string " -shared"
|
||||
(if is-mac " -undefined dynamic_lookup" "")))))
|
||||
(def CFLAGS (or (os/getenv "CFLAGS") (if is-win "" " -std=c99 -Wall -Wextra -fpic")))
|
||||
|
||||
(defn- opt
|
||||
"Get an option, allowing overrides via dynamic bindings AND some
|
||||
default value dflt if no dynamic binding is set."
|
||||
[opts key dflt]
|
||||
(def ret (or (opts key) (dyn key dflt)))
|
||||
(if (= nil ret)
|
||||
(error (string "option :" key " not set")))
|
||||
ret)
|
||||
|
||||
#
|
||||
# OS and shell helpers
|
||||
#
|
||||
|
||||
(defn shell
|
||||
"Do a shell command"
|
||||
[& args]
|
||||
(def cmd (string ;args))
|
||||
(def cmd (string/join args))
|
||||
(print cmd)
|
||||
(def res (os/shell cmd))
|
||||
(unless (zero? res)
|
||||
(error (string "command exited with status " res))))
|
||||
|
||||
(defn- rm
|
||||
(defn rm
|
||||
"Remove a directory and all sub directories."
|
||||
[path]
|
||||
(if (= (os/stat path :mode) :directory)
|
||||
@@ -29,19 +161,14 @@
|
||||
(os/rmdir path))
|
||||
(os/rm path)))
|
||||
|
||||
(defn- needs-build
|
||||
[dest src]
|
||||
"Check if dest is older than src. Used for checking if a file should be updated."
|
||||
(def f (file/open dest))
|
||||
(if (not f) (break true))
|
||||
(file/close f)
|
||||
(let [mod-dest (os/stat dest :modified)
|
||||
mod-src (os/stat src :modified)]
|
||||
(< mod-dest mod-src)))
|
||||
(defn copy
|
||||
"Copy a file or directory recursively from one location to another."
|
||||
[src dest]
|
||||
(shell (if is-win "xcopy " "cp -rf ") `"` src `" "` dest (if is-win `" /y /e` `"`)))
|
||||
|
||||
(defn- needs-build-some
|
||||
[f others]
|
||||
(some (partial needs-build f) others))
|
||||
#
|
||||
# C Compilation
|
||||
#
|
||||
|
||||
(defn- embed-name
|
||||
"Rename a janet symbol for embedding."
|
||||
@@ -82,10 +209,10 @@
|
||||
(defn- make-define
|
||||
"Generate strings for adding custom defines to the compiler."
|
||||
[define value]
|
||||
(def prefix (if is-win "/D" "-D"))
|
||||
(def pre (if is-win "/D" "-D"))
|
||||
(if value
|
||||
(string prefix define "=" value)
|
||||
(string prefix define)))
|
||||
(string pre define "=" value)
|
||||
(string pre define)))
|
||||
|
||||
(defn- make-defines
|
||||
"Generate many defines. Takes a dictionary of defines. If a value is
|
||||
@@ -93,102 +220,149 @@
|
||||
[defines]
|
||||
(seq [[d v] :pairs defines] (make-define d (if (not= v true) v))))
|
||||
|
||||
# Defaults
|
||||
(def OPTIMIZE 2)
|
||||
(def CC (if is-win "cl" "cc"))
|
||||
(def LD (if is-win
|
||||
"link"
|
||||
(string CC
|
||||
" -shared"
|
||||
(if is-mac " -undefined dynamic_lookup" ""))))
|
||||
(def CFLAGS (string
|
||||
(if is-win "/I" "-I")
|
||||
module/*syspath*
|
||||
(if is-win " /O" " -std=c99 -Wall -Wextra -fpic -O")
|
||||
OPTIMIZE))
|
||||
(defn- getcflags
|
||||
"Generate the c flags from the input options."
|
||||
[opts]
|
||||
(string (opt opts :cflags CFLAGS)
|
||||
(if is-win " /I\"" " \"-I")
|
||||
(opt opts :headerpath JANET_HEADERPATH)
|
||||
`"`
|
||||
(if is-win " /O\"" " \"-O")
|
||||
(opt opts :optimize OPTIMIZE)
|
||||
`"`))
|
||||
|
||||
(defn- compile-c
|
||||
"Compile a C file into an object file."
|
||||
[opts src dest]
|
||||
(def cc (or (opts :compiler) CC))
|
||||
(def cflags (or (opts :cflags) CFLAGS))
|
||||
(def defines (interpose " " (make-defines (or (opts :defines) {}))))
|
||||
(if (needs-build dest src)
|
||||
(if is-win
|
||||
(shell cc " " ;defines " /nologo /c " cflags " /Fo" dest " " src)
|
||||
(shell cc " -c " src " " ;defines " " cflags " -o " dest))))
|
||||
(def cc (opt opts :compiler CC))
|
||||
(def cflags (getcflags opts))
|
||||
(def defines (interpose " " (make-defines (opt opts :defines {}))))
|
||||
(rule dest [src]
|
||||
(if is-win
|
||||
(shell cc " " ;defines " /nologo /c " cflags " /Fo\"" dest `" "` src `"`)
|
||||
(shell cc " -c '" src "' " ;defines " " cflags " -o '" dest `'`))))
|
||||
|
||||
(defn- link-c
|
||||
"Link a number of object files together."
|
||||
[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 (needs-build-some target objects)
|
||||
(if is-win
|
||||
(shell ld " /DLL /OUT:" target " " olist " %JANET_PATH%\\janet.lib")
|
||||
(shell ld " " cflags " -o " target " " olist " " lflags))))
|
||||
(def ld (opt opts :linker LD))
|
||||
(def cflags (getcflags opts))
|
||||
(def lflags (opt opts :lflags LDFLAGS))
|
||||
(def olist (string/join objects `" "`))
|
||||
(rule target objects
|
||||
(if is-win
|
||||
(shell ld " " lflags " /DLL /OUT:" target ` "` olist `" "` (opt opts :headerpath JANET_HEADERPATH) `"\\janet.lib`)
|
||||
(shell ld " " cflags ` -o "` target `" "` olist `" ` lflags))))
|
||||
|
||||
(defn- create-buffer-c
|
||||
"Inline raw byte file as a c file."
|
||||
[source dest name]
|
||||
(when (needs-build dest source)
|
||||
(def f (file/open source :r))
|
||||
(if (not f) (error (string "file " f " not found")))
|
||||
(def out (file/open dest :w))
|
||||
(def chunks (seq [b :in (file/read f :all)] (string b)))
|
||||
(file/write out
|
||||
"#include <janet/janet.h>\n"
|
||||
"static const unsigned char bytes[] = {"
|
||||
;(interpose ", " chunks)
|
||||
"};\n\n"
|
||||
"const unsigned char *" name "_embed = bytes;\n"
|
||||
"size_t " name "_embed_size = sizeof(bytes);\n")
|
||||
(file/close out)
|
||||
(file/close f)))
|
||||
(rule dest [source]
|
||||
(def f (file/open source :r))
|
||||
(if (not f) (error (string "file " f " not found")))
|
||||
(def out (file/open dest :w))
|
||||
(def chunks (seq [b :in (file/read f :all)] (string b)))
|
||||
(file/write out
|
||||
"#include <janet.h>\n"
|
||||
"static const unsigned char bytes[] = {"
|
||||
;(interpose ", " chunks)
|
||||
"};\n\n"
|
||||
"const unsigned char *" name "_embed = bytes;\n"
|
||||
"size_t " name "_embed_size = sizeof(bytes);\n")
|
||||
(file/close out)
|
||||
(file/close f)))
|
||||
|
||||
# Public
|
||||
#
|
||||
# Declaring Artifacts - used in project.janet, targets specifically
|
||||
# tailored for janet.
|
||||
#
|
||||
|
||||
(defn make-native
|
||||
"Build a native binary. This is a shared library that can be loaded
|
||||
(defn- install-rule
|
||||
"Add install and uninstall rule for moving file from src into destdir."
|
||||
[src destdir]
|
||||
(def parts (string/split sep src))
|
||||
(def name (last parts))
|
||||
(add-body "install"
|
||||
(try (os/mkdir destdir) ([err] nil))
|
||||
(copy src destdir))
|
||||
(add-body "uninstall"
|
||||
(def path (string destdir sep name))
|
||||
(print "removing " path)
|
||||
(try (rm path) ([err]
|
||||
(unless (= err "No such file or directory")
|
||||
(error err))))))
|
||||
|
||||
(defn declare-native
|
||||
"Declare a native binary. This is a shared library that can be loaded
|
||||
dynamically by a janet runtime."
|
||||
[& opts]
|
||||
(def opt-table (table ;opts))
|
||||
(os/mkdir "build")
|
||||
(def sources (opt-table :source))
|
||||
(def name (opt-table :name))
|
||||
[&keys opts]
|
||||
(def sources (opts :source))
|
||||
(def name (opts :name))
|
||||
(def lname (lib-name name))
|
||||
(loop [src :in sources]
|
||||
(compile-c opt-table src (object-name src)))
|
||||
(compile-c opts src (object-name src)))
|
||||
(def objects (map object-name sources))
|
||||
(when-let [embedded (opt-table :embedded)]
|
||||
(loop [src :in embedded]
|
||||
(def c-src (embed-c-name src))
|
||||
(def o-src (embed-o-name src))
|
||||
(array/push objects o-src)
|
||||
(create-buffer-c src c-src (embed-name src))
|
||||
(compile-c opt-table c-src o-src)))
|
||||
(link-c opt-table (lib-name name) ;objects))
|
||||
(when-let [embedded (opts :embedded)]
|
||||
(loop [src :in embedded]
|
||||
(def c-src (embed-c-name src))
|
||||
(def o-src (embed-o-name src))
|
||||
(array/push objects o-src)
|
||||
(create-buffer-c src c-src (embed-name src))
|
||||
(compile-c opts c-src o-src)))
|
||||
(link-c opts lname ;objects)
|
||||
(add-dep "build" lname)
|
||||
(def path (opt opts :modpath JANET_MODPATH))
|
||||
(install-rule lname path))
|
||||
|
||||
(defn clean
|
||||
"Remove all built artifacts."
|
||||
[]
|
||||
(rm "build"))
|
||||
(defn declare-source
|
||||
"Create a Janet modules. This does not actually build the module(s),
|
||||
but registers it for packaging and installation."
|
||||
[&keys opts]
|
||||
(def sources (opts :source))
|
||||
(def path (opt opts :modpath JANET_MODPATH))
|
||||
(each s sources
|
||||
(install-rule s path)))
|
||||
|
||||
(defn make-archive
|
||||
(defn declare-binscript
|
||||
"Declare a janet file to be installed as an executable script."
|
||||
[&keys opts]
|
||||
(def main (opts :main))
|
||||
(def binpath (opt opts :binpath JANET_BINPATH))
|
||||
(install-rule main binpath))
|
||||
|
||||
(defn declare-archive
|
||||
"Build a janet archive. This is a file that bundles together many janet
|
||||
scripts into a janet image. This file can the be moved to any machine with
|
||||
a janet vm and the required dependencies and run there."
|
||||
[& opts]
|
||||
(def opt-table (table ;opts))
|
||||
(os/mkdir "build")
|
||||
(def entry (opt-table :entry))
|
||||
(def name (opt-table :name))
|
||||
(spit (string name ".jimage") (make-image (require entry))))
|
||||
[&keys opts]
|
||||
(def entry (opts :entry))
|
||||
(def name (opts :name))
|
||||
(def iname (string "build" sep name ".jimage"))
|
||||
(rule iname (or (opts :deps) [])
|
||||
(spit iname (make-image (require entry))))
|
||||
(def path (opt opts :modpath JANET_MODPATH))
|
||||
(install-rule iname path))
|
||||
|
||||
(defn make-binary
|
||||
"Make a binary executable that can be run on the current platform. This function
|
||||
generates a self contained binary that can be run of the same architecture as the
|
||||
build machine, as the current janet vm will be packaged with the output binary."
|
||||
[& opts]
|
||||
(error "Not Yet Implemented."))
|
||||
(defn declare-project
|
||||
"Define your project metadata. This should
|
||||
be the first declaration in a project.janet file.
|
||||
Also sets up basic phony targets like clean, build, test, etc."
|
||||
[&keys meta]
|
||||
(setdyn :project meta)
|
||||
(try (os/mkdir "build") ([err] nil))
|
||||
(phony "build" [])
|
||||
(phony "install" ["build"] (print "Installed."))
|
||||
(phony "uninstall" [] (print "Uninstalled."))
|
||||
(phony "clean" [] (rm "build") (print "Deleted build directory."))
|
||||
(phony "test" ["build"]
|
||||
(defn dodir
|
||||
[dir]
|
||||
(each sub (os/dir dir)
|
||||
(def ndir (string dir sep sub))
|
||||
(case (os/stat ndir :mode)
|
||||
:file (when (string/has-suffix? ".janet" ndir)
|
||||
(print "running " ndir " ...")
|
||||
(dofile ndir :exit true))
|
||||
:directory (dodir ndir))))
|
||||
(dodir "test")
|
||||
(print "All tests passed.")))
|
||||
|
||||
41
tools/jpm
Executable file
41
tools/jpm
Executable file
@@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env janet
|
||||
|
||||
# CLI tool for building janet projects. Wraps cook.
|
||||
|
||||
(import cook)
|
||||
|
||||
(def- argpeg
|
||||
(peg/compile
|
||||
'(* "--" '(some (if-not "=" 1)) "=" '(any 1))))
|
||||
|
||||
(defn- help
|
||||
[]
|
||||
(print "usage: jpm [targets]... --key=value ...")
|
||||
(print "Available targets are:")
|
||||
(each k (sort (keys (dyn :rules @{})))
|
||||
(print " " k))
|
||||
(print `
|
||||
|
||||
Keys are:
|
||||
--modpath : The directory to install modules to. Defaults to $JANET_MODPATH or module/*syspath*
|
||||
--headerpath : The directory containing janet headers. Defaults to $JANET_HEADERPATH or module/*headerpath*
|
||||
--binpath : The directory to install binaries and scripts. Defaults to $JANET_BINPATH.
|
||||
--optimize : Optimization level for natives. Defaults to $OPTIMIZE or 2.
|
||||
--compiler : C compiler to use for natives. Defaults to $CC or cc.
|
||||
--linker : C linker to use for linking natives. Defaults to $LINKER or cc.
|
||||
--cflags : Extra compiler flags for native modules. Defaults to $CFLAGS if set.
|
||||
--lflags : Extra linker flags for native modules. Defaults to $LFLAGS if set.
|
||||
`))
|
||||
|
||||
(def args (tuple/slice process/args 2))
|
||||
(def todo @[])
|
||||
(each arg args
|
||||
(if (string/has-prefix? "--" arg)
|
||||
(let [[key value] (peg/match argpeg arg)]
|
||||
(setdyn (keyword key) value))
|
||||
(array/push todo arg)))
|
||||
|
||||
(cook/import-rules "./project.janet")
|
||||
|
||||
(if (empty? todo) (help))
|
||||
(each rule todo (cook/do-rule rule))
|
||||
4
tools/jpm.bat
Normal file
4
tools/jpm.bat
Normal file
@@ -0,0 +1,4 @@
|
||||
@echo off
|
||||
@rem Wrapper arounf jpm
|
||||
|
||||
janet %~dp0\jpm.janet %*
|
||||
Reference in New Issue
Block a user