1
0
mirror of https://github.com/janet-lang/janet synced 2025-11-05 10:03:06 +00:00

Compare commits

..

1 Commits
v1.1.0 ... jpm

Author SHA1 Message Date
Calvin Rose
be89d10004 Update NSIS installer. 2019-05-29 12:51:50 -04:00
63 changed files with 895 additions and 2371 deletions

View File

@@ -1,47 +1,8 @@
# Changelog
All notable changes to this project will be documented in this file.
## 1.1.0 - 2019-07-08
- Change semantics of `-l` flag to be import rather than dofile.
- Fix compiler regression in top level defs with destructuring.
- Add `table/clone`.
- Improve `jpm` tool with git and dependency capabilities, as well as better
module uninstalls.
## 0.6.0 - ??
## 1.0.0 - 2019-07-01
- Add `with` macro for resource handling.
- Add `propagate` function so we can "rethrow" signals after they are
intercepted. This makes signals even more flexible.
- Add `JANET_NO_DOCSTRINGS` and `JANET_NO_SOURCEMAPS` defines in janetconf.h
for shrinking binary size.
This seems to save about 50kB in most builds, so it's not usually worth it.
- Update module system to allow relative imports. The `:cur:` pattern
in `module/expand-path` will expand to the directory part of the current file, or
whatever the value of `(dyn :current-file)` is. The `:dir:` pattern gets
the directory part of the input path name.
- Remove `:native:` pattern in `module/paths`.
- Add `module/expand-path`
- Remove `module/*syspath*` and `module/*headerpath*` in favor of dynamic
bindings `:syspath` and `:headerpath`.
- Compiled PEGs can now be marshaled and unmarshaled.
- Change signature to `parser/state`
- Add `:until` verb to loop.
- Add `:p` flag to `fiber/new`.
- Add `file/{fdopen,fileno}` functions.
- Add `parser/clone` function.
- Add optional argument to `parser/where` to set parser byte index.
- Add optional `env` argument to `all-bindings` and `all-dynamics`.
- Add scratch memory C API functions for auto-released memory on next gc.
Scratch memory differs from normal GCed memory as it can also be freed normally
for better performance.
- 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.
@@ -120,7 +81,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-01-26
## 0.3.0 - 2019-26-01
- Add amalgamated build to janet for easier embedding.
- Add os/date function
- Add slurp and spit to core library.

View File

@@ -37,7 +37,7 @@ MANPATH?=$(PREFIX)/share/man/man1/
PKG_CONFIG_PATH?=$(PREFIX)/lib/pkgconfig
DEBUGGER=gdb
CFLAGS=-std=c99 -Wall -Wextra -Isrc/include -Isrc/conf -fpic -O2 -fvisibility=hidden \
CFLAGS=-std=c99 -Wall -Wextra -Isrc/include -fpic -O2 -fvisibility=hidden \
-DJANET_BUILD=$(JANET_BUILD)
LDFLAGS=-rdynamic
@@ -60,7 +60,7 @@ all: $(JANET_TARGET) $(JANET_LIBRARY) $(JANET_STATIC_LIBRARY)
##### Name Files #####
######################
JANET_HEADERS=src/include/janet.h src/conf/janetconf.h
JANET_HEADERS=src/include/janet.h src/include/janetconf.h
JANET_LOCAL_HEADERS=src/core/util.h \
src/core/state.h \
@@ -165,7 +165,7 @@ $(JANET_STATIC_LIBRARY): $(JANET_CORE_OBJECTS)
######################
EMCC=emcc
EMCFLAGS=-std=c99 -Wall -Wextra -Isrc/include -Isrc/conf -O2 \
EMCFLAGS=-std=c99 -Wall -Wextra -Isrc/include -O2 \
-s EXTRA_EXPORTED_RUNTIME_METHODS='["cwrap"]' \
-s ALLOW_MEMORY_GROWTH=1 \
-s AGGRESSIVE_VARIABLE_ELIMINATION=1 \
@@ -252,7 +252,7 @@ callgrind: $(JANET_TARGET)
dist: build/janet-dist.tar.gz
build/janet-%.tar.gz: $(JANET_TARGET) \
src/include/janet.h src/conf/janetconf.h \
src/include/janet.h src/include/janetconf.h \
janet.1 LICENSE CONTRIBUTING.md $(JANET_LIBRARY) $(JANET_STATIC_LIBRARY) \
build/doc.html README.md build/janet.c
tar -czvf $@ $^
@@ -299,21 +299,14 @@ install: $(JANET_TARGET) $(PKG_CONFIG_PATH)/janet.pc
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 -rf auxlib/* $(JANET_PATH)
cp -rf auxbin/* $(BINDIR)
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)
uninstall:
-rm $(BINDIR)/janet
-rm $(BINDIR)/jpm
-rm -rf $(INCLUDEDIR)/janet
-rm -rf $(LIBDIR)/libjanet.*
-rm $(PKG_CONFIG_PATH)/janet.pc
-rm $(MANPATH)/janet.1
# -rm -rf $(JANET_PATH)/* - err on the side of correctness here
#################
##### Other #####
#################
@@ -341,5 +334,9 @@ build/embed_test: build/embed_janet.o build/embed_main.o
test-amalg: build/embed_test
./build/embed_test
uninstall:
-rm $(BINDIR)/../$(JANET_TARGET)
-rm -rf $(INCLUDEDIR)
.PHONY: clean install repl debug valgrind test amalg \
valtest emscripten dist uninstall docs grammar format

View File

@@ -4,7 +4,6 @@
[![Build Status](https://travis-ci.org/janet-lang/janet.svg?branch=master)](https://travis-ci.org/janet-lang/janet)
[![builds.sr.ht status](https://builds.sr.ht/~bakpakin/janet/.freebsd.yaml.svg)](https://builds.sr.ht/~bakpakin/janet/.freebsd.yaml?)
[![builds.sr.ht status](https://builds.sr.ht/~bakpakin/janet/.openbsd.yaml.svg)](https://builds.sr.ht/~bakpakin/janet/.openbsd.yaml?)
<noscript><a href="https://liberapay.com/Janet-Language/donate"><img alt="Donate using Liberapay" src="https://liberapay.com/assets/widgets/donate.svg"></a></noscript>
<img src="https://raw.githubusercontent.com/janet-lang/janet/master/assets/janet-w200.png" alt="Janet logo" width=200 align="left">
@@ -74,8 +73,6 @@ the SourceHut mirror is actively maintained.
### macos and Unix-like
The Makefile is non-portable and requires GNU-flavored make.
```
cd somewhere/my/projects/janet
make
@@ -127,15 +124,12 @@ Building with emscripten on windows is currently unsupported.
### Meson
Janet also has a build file for [Meson](https://mesonbuild.com/), a cross platform build
system. Although Meson has a python dependency, Meson is a very complete build system that
is maybe more convenient and flexible for integrating into existing pipelines.
Meson also provides much better IDE integration than Make or batch files, as well as support
for cross compilation.
system. This is not currently the main supported build system, but should work on any
system that supports meson. Meson also provides much better IDE integration than Make or batch files.
## Installation
See [the Introduction](https://janet-lang.org/introduction.html) for more details. If you just want
to try out the language, you don't need to install anything. You can also simply move the `janet` executable wherever you want on your system and run it.
See [the Introduction](https://janet-lang.org/introduction.html) for more details.
## Usage
@@ -207,3 +201,4 @@ ensue.
Janet is named after the almost omniscient and friendly artificial being in [The Good Place](https://en.wikipedia.org/wiki/The_Good_Place).
<img src="https://raw.githubusercontent.com/janet-lang/janet/master/assets/janet-the-good-place.gif" alt="Janet logo" width="115px" align="left">

View File

@@ -33,7 +33,7 @@ only_commits:
artifacts:
- path: janet-installer.exe
name: janet-v1.1.0-windows-installer.exe
name: janet-windows-installer.exe
type: File
deploy:

View File

@@ -1,104 +0,0 @@
#!/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- local-rule
[rule]
(cook/import-rules "./project.janet")
(cook/do-rule rule))
(defn- help
[]
(print `
usage: jpm --key=value ... [subcommand] [args]...
Subcommands are:
build : build all artifacts
install (repo) : install artifacts. If a repo is given, install the contents of that
git repository, assuming that the repository is a jpm project. If not, build
and install the current project.
uninstall (module) : uninstall a module. If no module is given, uninstall the module
defined by the current directory.
clean : remove any generated files or artifacts
test : run tests
deps : install dependencies.
clear-cache : clear the git cache. Useful for updating dependencies.
Keys are:
--modpath : The directory to install modules to. Defaults to $JANET_MODPATH or (dyn :syspath)
--headerpath : The directory containing janet headers. Defaults to $JANET_HEADERPATH or (dyn :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 $COMPILER 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.
`))
(defn build
[]
(local-rule "build"))
(defn clean
[]
(local-rule "clean"))
(defn install
[&opt repo]
(if repo
(cook/install-git repo)
(local-rule "install")))
(defn test
[]
(local-rule "test"))
(defn uninstall
[&opt what]
(if what
(cook/uninstall what)
(local-rule "uninstall")))
(defn deps
[]
(local-rule "install-deps"))
(def subcommands
{"build" build
"clean" clean
"install" install
"test" test
"help" help
"deps" deps
"clear-cache" cook/clear-cache
"uninstall" uninstall})
(def args (tuple/slice process/args 2))
(def len (length args))
(var i 0)
# Get flags
(while (< i len)
(def arg (args i))
(unless (string/has-prefix? "--" arg) (break))
(if-let [m (peg/match argpeg arg)]
(let [[key value] m]
(setdyn (keyword key) value))
(print "invalid argument " arg))
(++ i))
# Run subcommand
(if (= i len)
(help)
(do
(if-let [com (subcommands (args i))]
(com ;(tuple/slice args (+ i 1)))
(do
(print "invalid command " (args i))
(help)))))

View File

@@ -1,149 +0,0 @@
### path.janet
###
### A library for path manipulation.
###
### Copyright 2019 © Calvin Rose
#
# Common
#
(def- ext-peg
(peg/compile ~{:back (> -1 (+ (* ($) (set "\\/.")) :back))
:main :back}))
(defn ext
"Get the file extension for a path."
[path]
(if-let [m (peg/match ext-peg path (length path))]
(let [i (m 0)]
(if (= (path i) 46)
(string/slice path (m 0) -1)))))
(defn- redef
"Redef a value, keeping all metadata."
[from to]
(setdyn (symbol to) (dyn (symbol from))))
#
# Generating Macros
#
(defmacro- decl-sep [pre sep] ~(def ,(symbol pre "/sep") ,sep))
(defmacro- decl-delim [pre d] ~(def ,(symbol pre "/delim") ,d))
(defmacro- decl-last-sep
[pre sep]
~(def- ,(symbol pre "/last-sep-peg")
(peg/compile ~{:back (> -1 (+ (* ,sep ($)) :back))
:main :back})))
(defmacro- decl-basename
[pre]
~(defn ,(symbol pre "/basename")
"Gets the base file name of a path."
[path]
(if-let [m (peg/match
,(symbol pre "/last-sep-peg")
path
(length path))]
(let [[p] m]
(string/slice path p -1))
path)))
(defmacro- decl-parts
[pre sep]
~(defn ,(symbol pre "/parts")
"Split a path into its parts."
[path]
(string/split ,sep path)))
(defmacro- decl-normalize
[pre sep lead]
~(defn ,(symbol pre "/normalize")
"Normalize a path. This removes . and .. in the
path, as well as empty path elements."
[path]
(def els (string/split ,sep path))
(def newparts @[])
(if (,(symbol pre "/abspath?") path) (array/push newparts ,lead))
(each part els
(case part
"" nil
"." nil
".." (array/pop newparts)
(array/push newparts part)))
(string/join newparts ,sep)))
(defmacro- decl-join
[pre sep]
~(defn ,(symbol pre "/join")
"Join path elements together."
[& els]
(,(symbol pre "/normalize") (string/join els ,sep))))
(defmacro- decl-abspath
[pre]
~(defn ,(symbol pre "/abspath")
"Coerce a path to be absolute."
[path]
(if (,(symbol pre "/abspath?") path)
path
(,(symbol pre "/join") (os/cwd) path))))
#
# Posix
#
(defn posix/abspath?
"Check if a path is absolute."
[path]
(string/has-prefix? "/" path))
(redef "ext" "posix/ext")
(decl-sep "posix" "/")
(decl-delim "posix" ":")
(decl-last-sep "posix" "/")
(decl-basename "posix")
(decl-parts "posix" "/")
(decl-normalize "posix" "/" "")
(decl-join "posix" "/")
(decl-abspath "posix")
#
# Windows
#
(def- abs-peg (peg/compile '(* (range "AZ") ":\\")))
(defn win32/abspath?
"Check if a path is absolute."
[path]
(peg/match abs-peg path))
(redef "ext" "win32/ext")
(decl-sep "win32" "\\")
(decl-delim "win32" ";")
(decl-last-sep "win32" "\\")
(decl-basename "win32")
(decl-parts "win32" "\\")
(decl-normalize "win32" "\\" "C:")
(decl-join "win32" "\\")
(decl-abspath "win32")
#
# Specialize for current OS
#
(def- syms
["ext"
"sep"
"delim"
"basename"
"abspath?"
"abspath"
"parts"
"normalize"
"join"])
(let [pre (if (= :windows (os/which)) "win32" "posix")]
(each sym syms
(redef (string pre "/" sym) sym)))

View File

@@ -16,7 +16,7 @@
@rem Set compile and link options here
@setlocal
@set JANET_COMPILE=cl /nologo /Isrc\include /Isrc\conf /c /O2 /W3 /LD /D_CRT_SECURE_NO_WARNINGS
@set JANET_COMPILE=cl /nologo /Isrc\include /c /O2 /W3 /LD /D_CRT_SECURE_NO_WARNINGS
@set JANET_LINK=link /nologo
mkdir build
@@ -128,15 +128,13 @@ copy build\janet.c dist\janet.c
copy janet.exe dist\janet.exe
copy LICENSE dist\LICENSE
copy README.md dist\README.md
copy janet.lib dist\janet.lib
copy janet.exp dist\janet.exp
copy src\include\janet.h dist\janet.h
copy src\conf\janetconf.h dist\janetconf.h
copy auxlib\cook.janet dist\cook.janet
copy auxbin\jpm dist\jpm
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

View File

@@ -1,51 +1,20 @@
# Version
!define VERSION "1.1.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_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}"
# Includes
!include "MultiUser.nsh"
!include "MUI2.nsh"
!include ".\tools\EnvVarUpdate.nsh"
!include "LogicLib.nsh"
# Basics
Name "Janet"
OutFile "janet-v${VERSION}-windows-installer.exe"
OutFile "janet-installer.exe"
# Some Configuration
!define APPNAME "Janet"
!define DESCRIPTION "The Janet Programming Language"
!define HELPURL "http://janet-lang.org"
BrandingText "The Janet Programming Language"
# Macros for setting registry values
!define UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\Janet-${VERSION}"
!macro WriteEnv key value
${If} $MultiUser.InstallMode == "AllUsers"
WriteRegExpandStr HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" "${key}" "${value}"
${Else}
WriteRegExpandStr HKCU "Environment" "${key}" "${value}"
${EndIf}
!macroend
!macro DelEnv key
${If} $MultiUser.InstallMode == "AllUsers"
DeleteRegValue HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" "${key}"
${Else}
DeleteRegValue HKCU "Environment" "${key}"
${EndIf}
!macroend
BrandingText "Janet Installer"
# MUI Configuration
!define MUI_ICON "assets\icon.ico"
@@ -53,128 +22,142 @@ BrandingText "The Janet Programming Language"
!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
# License page
!insertmacro MUI_PAGE_LICENSE "LICENSE"
# Pick Install Directory
!insertmacro MULTIUSER_PAGE_INSTALLMODE
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
# Done
!insertmacro MUI_PAGE_FINISH
page instfiles
# Need to set a language.
!insertmacro MUI_LANGUAGE "English"
function .onInit
!insertmacro MULTIUSER_INIT
setShellVarContext all
functionEnd
section "Janet" BfWSection
section "install"
createDirectory "$INSTDIR\Library"
createDirectory "$INSTDIR\C"
createDirectory "$INSTDIR\bin"
createDirectory "$INSTDIR\docs"
setOutPath "$INSTDIR"
# Bin files
setOutPath $INSTDIR
file /oname=bin\janet.exe dist\janet.exe
file /oname=logo.ico assets\icon.ico
file /oname=bin\jpm.janet auxbin\jpm
file /oname=bin\jpm.bat tools\jpm.bat
# Modules
file /oname=Library\cook.janet auxlib\cook.janet
file /oname=Library\path.janet auxlib\path.janet
# C headers
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
# Documentation
file /oname=docs\docs.html dist\doc.html
# Other
file README.md
file LICENSE
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_BINDIR "$INSTDIR\bin"
# Set up Environment variables
!insertmacro WriteEnv JANET_PATH "$INSTDIR\Library"
!insertmacro WriteEnv JANET_HEADERPATH "$INSTDIR\C"
!insertmacro WriteEnv JANET_BINPATH "$INSTDIR\bin"
WriteRegExpandStr HKCU "Environment" JANET_PATH "$INSTDIR\Library"
WriteRegExpandStr HKCU "Environment" JANET_HEADERPATH "$INSTDIR\C"
WriteRegExpandStr HKCU "Environment" JANET_BINDIR "$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
# Registry information for add/remove programs
WriteRegStr SHCTX "${UNINST_KEY}" "DisplayName" "Janet"
WriteRegStr SHCTX "${UNINST_KEY}" "InstallLocation" "$INSTDIR"
WriteRegStr SHCTX "${UNINST_KEY}" "DisplayIcon" "$INSTDIR\logo.ico"
WriteRegStr SHCTX "${UNINST_KEY}" "Publisher" "Janet-Lang.org"
WriteRegStr SHCTX "${UNINST_KEY}" "HelpLink" "${HELPURL}"
WriteRegStr SHCTX "${UNINST_KEY}" "URLUpdateInfo" "${HELPURL}"
WriteRegStr SHCTX "${UNINST_KEY}" "URLInfoAbout" "${HELPURL}"
WriteRegStr SHCTX "${UNINST_KEY}" "DisplayVersion" "${VERSION}"
WriteRegDWORD SHCTX "${UNINST_KEY}" "NoModify" 1
WriteRegDWORD SHCTX "${UNINST_KEY}" "NoRepair" 1
WriteRegDWORD SHCTX "${UNINST_KEY}" "EstimatedSize" 1000
# Add uninstall
WriteRegStr SHCTX "${UNINST_KEY}" "UninstallString" "$\"$INSTDIR\uninstall.exe$\" /$MultiUser.InstallMode"
WriteRegStr SHCTX "${UNINST_KEY}" "QuietUninstallString" "$\"$INSTDIR\uninstall.exe$\" /$MultiUser.InstallMode /S"
${EnvVarUpdate} $0 "PATH" "A" "HKLM" "$INSTDIR\bin" ; Append
# 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
# Uninstaller
function un.onInit
!insertmacro MULTIUSER_UNINIT
SetShellVarContext all
#Verify the uninstaller - last chance to back out
MessageBox MB_OKCANCEL "Permanantly remove Janet?" IDOK next
Abort
next:
functionEnd
section "uninstall"
# Remove Start Menu launcher
delete "$SMPROGRAMS\Janet.lnk"
# Remove files
delete "$INSTDIR\logo.ico"
delete "$INSTDIR\README.md"
delete "$INSTDIR\LICENSE"
rmdir /r "$INSTDIR\Library"
rmdir /r "$INSTDIR\bin"
rmdir /r "$INSTDIR\C"
rmdir /r "$INSTDIR\docs"
delete $INSTDIR\logo.ico
delete $INSTDIR\C\janet.c
delete $INSTDIR\C\janet.h
delete $INSTDIR\C\janet.lib
delete $INSTDIR\C\janet.exp
delete $INSTDIR\C\janetconf.h
delete $INSTDIR\bin\jpm.janet
delete $INSTDIR\bin\jpm.bat
delete $INSTDIR\bin\janet.exe
delete $INSTDIR\Library\cook.janet
# Remove env vars
!insertmacro DelEnv JANET_PATH
!insertmacro DelEnv JANET_HEADERPATH
!insertmacro DelEnv JANET_BINPATH
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_BINDIR
DeleteRegValue HKCU "Environment" JANET_PATH
DeleteRegValue HKCU "Environment" JANET_HEADERPATH
DeleteRegValue HKCU "Environment" JANET_BINDIR
# Unset PATH
${un.EnvVarUpdate} $0 "PATH" "R" "HKCU" "$INSTDIR\bin" ; Remove
${un.EnvVarUpdate} $0 "PATH" "R" "HKLM" "$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"
delete $INSTDIR\uninstall.exe
rmDir "$INSTDIR\Library"
rmDir "$INSTDIR\C"
rmDir "$INSTDIR\bin"
# Remove uninstaller information from the registry
DeleteRegKey SHCTX "${UNINST_KEY}"
sectionEnd
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Janet"
sectionEnd

View File

@@ -73,7 +73,7 @@ Don't execute a script, only compile it to check for errors. Useful for linting
.TP
.BR \-m\ syspath
Set the dynamic binding :syspath to the string syspath so that Janet will load system modules
Set the variable module/*syspath* to the string syspath so that Janet will load system modules
from a directory different than the default. The default is set when Janet is built, and defaults to
/usr/local/lib/janet on Linux/Posix, and C:/Janet/Library on Windows. This option supersedes JANET_PATH.

View File

@@ -18,9 +18,7 @@
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
project('janet', 'c',
default_options : ['c_std=c99', 'b_lundef=false', 'default_library=both'],
version : '1.1.0')
project('janet', 'c', default_options : ['c_std=c99'])
# Global settings
janet_path = join_paths(get_option('prefix'), get_option('libdir'), 'janet')
@@ -31,48 +29,14 @@ cc = meson.get_compiler('c')
m_dep = cc.find_library('m', required : false)
dl_dep = cc.find_library('dl', required : false)
# Link options
if build_machine.system() != 'windows'
add_project_link_arguments('-rdynamic', language : 'c')
endif
# Generate custom janetconf.h
conf = configuration_data()
version_parts = meson.project_version().split('.')
last_parts = version_parts[2].split('-')
if last_parts.length() > 1
conf.set_quoted('JANET_VERSION_EXTRA', '-' + last_parts[1])
else
conf.set_quoted('JANET_VERSION_EXTRA', '')
endif
conf.set('JANET_VERSION_MAJOR', version_parts[0].to_int())
conf.set('JANET_VERSION_MINOR', version_parts[1].to_int())
conf.set('JANET_VERSION_PATCH', last_parts[0].to_int())
conf.set_quoted('JANET_VERSION', meson.project_version())
# Use options
conf.set_quoted('JANET_BUILD', get_option('git_hash'))
conf.set('JANET_NO_NANBOX', not get_option('nanbox'))
conf.set('JANET_SINGLE_THREADED', not get_option('single_threaded'))
conf.set('JANET_NO_DYNAMIC_MODULES', not get_option('dynamic_modules'))
conf.set('JANET_NO_DOCSTRINGS', not get_option('docstrings'))
conf.set('JANET_NO_SOURCEMAPS', not get_option('sourcemaps'))
conf.set('JANET_NO_ASSEMBLER', not get_option('assembler'))
conf.set('JANET_NO_PEG', not get_option('peg'))
conf.set('JANET_REDUCED_OS', get_option('reduced_os'))
conf.set('JANET_NO_TYPED_ARRAY', not get_option('typed_array'))
conf.set('JANET_NO_INT_TYPES', not get_option('int_types'))
conf.set('JANET_RECURSION_GUARD', get_option('recursion_guard'))
conf.set('JANET_MAX_PROTO_DEPTH', get_option('max_proto_depth'))
conf.set('JANET_MAX_MACRO_EXPAND', get_option('max_macro_expand'))
conf.set('JANET_STACK_MAX', get_option('stack_max'))
jconf = configure_file(output : 'janetconf.h',
configuration : conf)
# Some options
add_project_link_arguments('-rdynamic', language : 'c')
# Include directories
incdir = include_directories(['src/include', '.'])
incdir = include_directories('src/include')
# Building generated sources
xxd = executable('xxd', 'tools/xxd.c', native : true)
xxd = executable('xxd', 'tools/xxd.c')
gen = generator(xxd,
output : '@BASENAME@.gen.c',
arguments : ['@INPUT@', '@OUTPUT@', '@EXTRA_ARGS@'])
@@ -150,8 +114,7 @@ mainclient_src = [
janet_boot = executable('janet-boot', core_src, boot_src, boot_gen,
include_directories : incdir,
c_args : '-DJANET_BOOTSTRAP',
dependencies : [m_dep, dl_dep],
native : true)
dependencies : [m_dep, dl_dep])
# Build core image
core_image = custom_target('core_image',
@@ -159,38 +122,29 @@ core_image = custom_target('core_image',
output : 'core_image.gen.c',
command : [janet_boot, '@OUTPUT@', 'JANET_PATH', janet_path, 'JANET_HEADERPATH', header_path])
libjanet = library('janet', core_src, core_image,
libjanet = shared_library('janet', core_src, core_image,
include_directories : incdir,
dependencies : [m_dep, dl_dep],
install : true)
janet_mainclient = executable('janet', core_src, core_image, init_gen, mainclient_src,
include_directories : incdir,
dependencies : [m_dep, dl_dep],
install : true)
if meson.is_cross_build()
janet_nativeclient = executable('janet-native', core_src, core_image, init_gen, mainclient_src,
include_directories : incdir,
dependencies : [m_dep, dl_dep],
native : true)
else
janet_nativeclient = janet_mainclient
endif
janet_jpm = install_data('tools/jpm', install_dir : 'bin')
# Documentation
docs = custom_target('docs',
input : ['tools/gendoc.janet'],
output : ['doc.html'],
capture : true,
command : [janet_nativeclient, '@INPUT@'])
command : [janet_mainclient, '@INPUT@'])
# Amalgamated source
amalg = custom_target('amalg',
input : ['tools/amalg.janet', core_headers, core_src, core_image],
output : ['janet.c'],
capture : true,
command : [janet_nativeclient, '@INPUT@'])
command : [janet_mainclient, '@INPUT@'])
# Amalgamated client
janet_amalgclient = executable('janet-amalg', amalg, init_gen, mainclient_src,
@@ -209,25 +163,18 @@ test_files = [
'test/suite6.janet'
]
foreach t : test_files
test(t, janet_nativeclient, args : files([t]), workdir : meson.current_source_dir())
test(t, janet_mainclient, args : files([t]), workdir : meson.current_source_dir())
endforeach
# Repl
run_target('repl', command : [janet_nativeclient])
# For use as meson subproject (wrap)
janet_dep = declare_dependency(include_directories : incdir,
link_with : libjanet)
run_target('repl', command : [janet_mainclient])
# Installation
install_man('janet.1')
install_headers(['src/include/janet.h', jconf], subdir: 'janet')
install_headers('src/include/janet.h', 'src/include/janetconf.h', subdir: 'janet')
janet_libs = [
'auxlib/cook.janet',
'auxlib/path.janet'
]
janet_binscripts = [
'auxbin/jpm'
'tools/bars.janet',
'tools/cook.janet',
'tools/highlight.janet'
]
install_data(sources : janet_libs, install_dir : janet_path)
install_data(sources : janet_binscripts, install_dir : 'bin')

View File

@@ -1,17 +0,0 @@
option('git_hash', type : 'string', value : 'meson')
option('single_threaded', type : 'boolean', value : false)
option('nanbox', type : 'boolean', value : true)
option('dynamic_modules', type : 'boolean', value : true)
option('docstrings', type : 'boolean', value : true)
option('sourcemaps', type : 'boolean', value : true)
option('reduced_os', type : 'boolean', value : false)
option('assembler', type : 'boolean', value : true)
option('peg', type : 'boolean', value : true)
option('typed_array', type : 'boolean', value : true)
option('int_types', type : 'boolean', value : true)
option('recursion_guard', type : 'integer', min : 10, max : 8000, value : 1024)
option('max_proto_depth', type : 'integer', min : 10, max : 8000, value : 200)
option('max_macro_expand', type : 'integer', min : 1, max : 8000, value : 200)
option('stack_max', type : 'integer', min : 8096, max : 1000000000, value : 16384)

View File

@@ -52,24 +52,8 @@ int main(int argc, const char **argv) {
janet_array_push(args, janet_cstringv(argv[i]));
janet_def(env, "process/args", janet_wrap_array(args), "Command line arguments.");
/* Add in options from janetconf.h so boot.janet can configure the image as needed. */
JanetTable *opts = janet_table(0);
#ifdef JANET_NO_DOCSTRINGS
janet_table_put(opts, janet_ckeywordv("no-docstrings"), janet_wrap_true());
#endif
#ifdef JANET_NO_SOURCEMAPS
janet_table_put(opts, janet_ckeywordv("no-sourcemaps"), janet_wrap_true());
#endif
janet_def(env, "process/config", janet_wrap_table(opts), "Boot options");
/* Run bootstrap script to generate core image */
const char *boot_file;
#ifdef JANET_NO_SOURCEMAPS
boot_file = NULL;
#else
boot_file = "boot.janet";
#endif
status = janet_dobytes(env, janet_gen_boot, janet_gen_boot_size, boot_file, NULL);
status = janet_dobytes(env, janet_gen_boot, janet_gen_boot_size, "boot.janet", NULL);
/* Deinitialize vm */
janet_deinit();

View File

@@ -8,7 +8,7 @@
###
(def defn :macro
"(defn name & more)\n\nDefine a function. Equivalent to (def name (fn name [args] ...))."
"(def name & more)\n\nDefine a function. Equivalent to (def name (fn name [args] ...))."
(fn defn [name & more]
(def len (length more))
(def modifiers @[])
@@ -263,21 +263,6 @@
(++ i))
~(let (,;accum) ,;body))
(defmacro with
"Evaluate body with some resource, which will be automatically cleaned up
if there is an error in body. binding is bound to the expression ctor, and
dtor is a function or callable that is passed the binding. If no destructor
(dtor) is given, will call :close on the resource."
[[binding ctor dtor] & body]
(with-syms [res f]
~(let [,binding ,ctor
,f (,fiber/new (fn [] ,;body) :ie)
,res (,resume ,f)]
(,(or dtor :close) ,binding)
(if (,= (,fiber/status ,f) :error)
(,propagate ,res ,f)
,res))))
(defn- for-template
[binding start stop step comparison delta body]
(with-syms [i s]
@@ -340,7 +325,6 @@
(keyword? binding)
(let [rest (loop1 body head (+ i 2))]
(case binding
:until ~(do (if ,verb (break) nil) ,rest)
:while ~(do (if ,verb nil (break)) ,rest)
:let ~(let ,verb (do ,rest))
:after ~(do ,rest ,verb nil)
@@ -403,7 +387,6 @@
where :modifier is one of a set of keywords, and argument is keyword dependent.
:modifier can be one of:\n\n
\t:while expression - breaks from the loop if expression is falsey.\n
\t:until expression - breaks from the loop if expression is truthy.\n
\t:let bindings - defines bindings inside the loop as passed to the let macro.\n
\t:before form - evaluates a form for a side effect before of the next inner loop.\n
\t:after form - same as :before, but the side effect happens after the next inner loop.\n
@@ -876,10 +859,12 @@
or signals, but the dynamic bindings will be properly
unset, as dynamic bindings are fiber local."
[bindings & body]
(def dyn-forms
(seq [i :range [0 (length bindings) 2]]
~(setdyn ,(bindings i) ,(bindings (+ i 1)))))
~(,resume (,fiber/new (fn [] ,;dyn-forms ,;body) :p)))
(with-syms [currenv env fib]
~(let [,currenv (,fiber/getenv (,fiber/current))
,env (,table/setproto (,table ,;bindings) ,currenv)
,fib (,fiber/new (fn [] ,;body) :)]
(,fiber/setenv ,fib ,env)
(,resume ,fib))))
(defn partial
"Partial function application."
@@ -1103,12 +1088,6 @@
[f & args]
(file/write stdout (buffer/format @"" f ;args)))
(defn pp
"Pretty print to stdout."
[x]
(print (buffer/format @"" (dyn :pretty-format "%p") x)))
###
###
### Pattern Matching
@@ -1147,8 +1126,8 @@
(put seen pattern true)
~(if (= nil (def ,pattern ,expr)) ,sentinel ,(onmatch))))
(and (tuple? pattern) (= :parens (tuple/type pattern)))
(if (and (= (pattern 0) '@) (symbol? (pattern 1)))
(tuple? pattern)
(if (and (= (pattern 0) 'quote) (symbol? (pattern 1)))
# Unification with external values
~(if (= ,(pattern 1) ,expr) ,(onmatch) ,sentinel)
(match-1
@@ -1156,7 +1135,7 @@
(fn []
~(if (and ,;(tuple/slice pattern 1)) ,(onmatch) ,sentinel)) seen))
(indexed? pattern)
(array? pattern)
(do
(def len (length pattern))
(var i -1)
@@ -1427,6 +1406,11 @@
(set current (macex1 current)))
current)
(defn pp
"Pretty print to stdout."
[x]
(print (buffer/format @"" (dyn :pretty-format "%p") x)))
###
###
### Evaluation and Compilation
@@ -1593,39 +1577,42 @@
[image]
(unmarshal image (env-lookup _env)))
(def- nati (if (= :windows (os/which)) ".dll" ".so"))
(defn- check-. [x] (if (string/has-prefix? "." x) x))
(defn- not-check-. [x] (unless (string/has-prefix? "." x) x))
(def module/paths
"The list of paths to look for modules, templated for module/expand-path.
Each element is a two element tuple, containing the path
"The list of paths to look for modules. The following
substitutions are preformed on each path. :sys: becomes
module/*syspath*, :name: becomes the last part of the module
name after the last /, and :all: is the module name literally.
:native: becomes the dynamic library file extension, usually dll
or so. 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.\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 can be a string or a predicate function, and
is often a file extension, including the period."
@[# Relative to (dyn :current-file "./."). Path must start with .
[":cur:/:all:.jimage" :image check-.]
[":cur:/:all:.janet" :source check-.]
[":cur:/:all:/init.janet" :source check-.]
[(string ":cur:/:all:" nati) :native check-.]
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]
[":sys:/:all:/init.janet" :source]
["./:all:.:native:" :native]
["./:all:/:name:.:native:" :native]
[":sys:/:all:.:native:" :native]
["./:all:.jimage" :image]
[":sys:/:all:.jimage" :image]])
# As a path from (os/cwd)
[":all:.jimage" :image not-check-.]
[":all:.janet" :source not-check-.]
[":all:/init.janet" :source not-check-.]
[(string ":all:" nati) :native not-check-.]
(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 the empty string."
(or (process/opts "JANET_PATH") ""))
# System paths
[":sys:/:all:.jimage" :image not-check-.]
[":sys:/:all:.janet" :source not-check-.]
[":sys:/:all:/init.janet" :source not-check-.]
[(string ":sys:/:all:" nati) :native not-check-.]])
(setdyn :syspath (process/opts "JANET_PATH"))
(setdyn :headerpath (process/opts "JANET_HEADERPATH"))
(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)]
@@ -1641,6 +1628,14 @@
(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)
@@ -1654,6 +1649,8 @@
or image if the module is found, otherwise a tuple with nil followed by
an error message."
[path]
(def parts (string/split "/" path))
(def name (last parts))
(var ret nil)
(each [p mod-kind checker] module/paths
(when (mod-filter checker path)
@@ -1662,7 +1659,7 @@
(set ret [res mod-kind])
(break))
(do
(def fullpath (string (module/expand-path path p)))
(def fullpath (expand-path-name p name path))
(when (fexists fullpath)
(set ret [fullpath mod-kind])
(break))))))
@@ -1670,16 +1667,15 @@
(let [expander (fn [[t _ chk]]
(when (string? t)
(when (mod-filter chk path)
(module/expand-path path t))))
(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)
(put _env 'check-. nil)
(put _env 'not-check-. nil)
(def module/cache
"Table mapping loaded module identifiers to their environments."
@@ -1701,7 +1697,6 @@
path
(file/open path)))
(default env (make-env))
(put env :current-file (string path))
(defn chunks [buf _] (file/read f 2048 buf))
(defn bp [&opt x y]
(def ret (bad-parse x y))
@@ -1741,15 +1736,16 @@
module/paths, then the path as a raw file path. Returns the new environment
returned from compiling and running the file."
[path & args]
(def [fullpath mod-kind] (module/find path))
(unless fullpath (error mod-kind))
(if-let [check (get module/cache fullpath)]
(if-let [check (get module/cache path)]
check
(do
(def [fullpath mod-kind] (module/find path))
(unless fullpath (error mod-kind))
(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)))
(defn import*
@@ -1793,7 +1789,7 @@
(default chunks (fn [buf p] (getline (string "repl:"
(parser/where p)
":"
(parser/state p :delimiters) "> ")
(parser/state p) "> ")
buf)))
(default onsignal (fn [f x]
(case (fiber/status f)
@@ -1811,7 +1807,7 @@ _fiber is bound to the suspended fiber
```)
(repl (fn [buf p]
(def status (parser/state p :delimiters))
(def status (parser/state p))
(def c (parser/where p))
(def prompt (string "debug[" level "]:" c ":" status "> "))
(getline prompt buf))
@@ -1823,8 +1819,8 @@ _fiber is bound to the suspended fiber
:source "repl"}))
(defn- env-walk
[pred &opt env]
(default env (fiber/getenv (fiber/current)))
[pred]
(def env (fiber/getenv (fiber/current)))
(def envs @[])
(do (var e env) (while e (array/push envs e) (set e (table/getproto e))))
(def ret-set @{})
@@ -1835,16 +1831,14 @@ _fiber is bound to the suspended fiber
(sort (keys ret-set)))
(defn all-bindings
"Get all symbols available in an enviroment. Defaults to the current
fiber's environment."
[&opt env]
(env-walk symbol? env))
"Get all symbols available in the current environment."
[]
(env-walk symbol?))
(defn all-dynamics
"Get all dynamic bindings in an environment. Defaults to the current
fiber's environment."
[&opt env]
(env-walk keyword? env))
"Get all dynamic bindings in the current fiber."
[]
(env-walk keyword?))
# Clean up some extra defs
(put _env 'process/opts nil)
@@ -1858,29 +1852,7 @@ _fiber is bound to the suspended fiber
###
(do
(defn proto-flatten
"Flatten a table and it's prototypes into a single table."
[into x]
(when x
(proto-flatten into (table/getproto x))
(loop [k :keys x]
(put into k (x k))))
into)
(def env (fiber/getenv (fiber/current)))
# Modify env based on some options.
(loop [[k v] :pairs env
:when (symbol? k)]
(def flat (proto-flatten @{} v))
(when (process/config :no-docstrings)
(put flat :doc nil))
(when (process/config :no-sourcemaps)
(put flat :source-map nil))
(put env k flat))
(put env 'process/config nil)
(def image (let [env-pairs (pairs (env-lookup env))
essential-pairs (filter (fn [[k v]] (or (cfunction? v) (abstract? v))) env-pairs)
lookup (table ;(mapcat identity essential-pairs))

View File

@@ -26,19 +26,10 @@
#endif
/* Create new userdata */
void *janet_abstract_begin(const JanetAbstractType *atype, size_t size) {
JanetAbstractHead *header = janet_gcalloc(JANET_MEMORY_NONE,
void *janet_abstract(const JanetAbstractType *atype, size_t size) {
JanetAbstractHead *header = janet_gcalloc(JANET_MEMORY_ABSTRACT,
sizeof(JanetAbstractHead) + size);
header->size = size;
header->type = atype;
return (void *) & (header->data);
}
void *janet_abstract_end(void *x) {
janet_gc_settype((void *)(janet_abstract_head(x)), JANET_MEMORY_ABSTRACT);
return x;
}
void *janet_abstract(const JanetAbstractType *atype, size_t size) {
return janet_abstract_end(janet_abstract_begin(atype, size));
}

View File

@@ -28,9 +28,8 @@
#include <string.h>
/* Creates a new array */
JanetArray *janet_array(int32_t capacity) {
JanetArray *array = janet_gcalloc(JANET_MEMORY_ARRAY, sizeof(JanetArray));
/* Initializes an array */
JanetArray *janet_array_init(JanetArray *array, int32_t capacity) {
Janet *data = NULL;
if (capacity > 0) {
data = (Janet *) malloc(sizeof(Janet) * capacity);
@@ -44,6 +43,16 @@ JanetArray *janet_array(int32_t capacity) {
return array;
}
void janet_array_deinit(JanetArray *array) {
free(array->data);
}
/* Creates a new array */
JanetArray *janet_array(int32_t capacity) {
JanetArray *array = janet_gcalloc(JANET_MEMORY_ARRAY, sizeof(JanetArray));
return janet_array_init(array, capacity);
}
/* Creates a new array from n elements. */
JanetArray *janet_array_n(const Janet *elements, int32_t n) {
JanetArray *array = janet_gcalloc(JANET_MEMORY_ARRAY, sizeof(JanetArray));
@@ -264,7 +273,7 @@ static const JanetReg array_cfuns[] = {
},
{
"array/slice", cfun_array_slice,
JDOC("(array/slice arrtup &opt start end)\n\n"
JDOC("(array/slice arrtup [, start=0 [, end=(length arrtup)]])\n\n"
"Takes a slice of array or tuple from start to end. The range is half open, "
"[start, end). Indexes can also be negative, indicating indexing from the end of the "
"end of the array. By default, start is 0 and end is the length of the array. "
@@ -288,10 +297,9 @@ static const JanetReg array_cfuns[] = {
},
{
"array/remove", cfun_array_remove,
JDOC("(array/remove arr at &opt n)\n\n"
JDOC("(array/remove arr at [, n=1])\n\n"
"Remove up to n elements starting at index at in array arr. at can index from "
"the end of the array with a negative index, and n must be a non-negative integer. "
"By default, n is 1. "
"Returns the array.")
},
{NULL, NULL, NULL}

View File

@@ -112,7 +112,6 @@ static const JanetInstructionDef janet_ops[] = {
{"mul", JOP_MULTIPLY},
{"mulim", JOP_MULTIPLY_IMMEDIATE},
{"noop", JOP_NOOP},
{"prop", JOP_PROPAGATE},
{"push", JOP_PUSH},
{"push2", JOP_PUSH_2},
{"push3", JOP_PUSH_3},

View File

@@ -346,8 +346,8 @@ static const JanetReg buffer_cfuns[] = {
},
{
"buffer/new-filled", cfun_buffer_new_filled,
JDOC("(buffer/new-filled count &opt byte)\n\n"
"Creates a new buffer of length count filled with byte. By default, byte is 0. "
JDOC("(buffer/new-filled count [, byte=0])\n\n"
"Creates a new buffer of length count filled with byte. "
"Returns the new buffer.")
},
{
@@ -383,7 +383,7 @@ static const JanetReg buffer_cfuns[] = {
},
{
"buffer/slice", cfun_buffer_slice,
JDOC("(buffer/slice bytes &opt start end)\n\n"
JDOC("(buffer/slice bytes [, start=0 [, end=(length bytes)]])\n\n"
"Takes a slice of a byte sequence from start to end. The range is half open, "
"[start, end). Indexes can also be negative, indicating indexing from the end of the "
"end of the array. By default, start is 0 and end is the length of the buffer. "
@@ -411,7 +411,7 @@ static const JanetReg buffer_cfuns[] = {
},
{
"buffer/blit", cfun_buffer_blit,
JDOC("(buffer/blit dest src & opt dest-start src-start src-end)\n\n"
JDOC("(buffer/blit dest src [, dest-start=0 [, src-start=0 [, src-end=-1]]])\n\n"
"Insert the contents of src into dest. Can optionally take indices that "
"indicate which part of src to copy into which part of dest. Indices can be "
"negative to index from the end of src or dest. Returns dest.")

View File

@@ -79,7 +79,6 @@ enum JanetInstructionType janet_instructions[JOP_INSTRUCTION_COUNT] = {
JINT_S, /* JOP_TAILCALL, */
JINT_SSS, /* JOP_RESUME, */
JINT_SSU, /* JOP_SIGNAL, */
JINT_SSS, /* JOP_PROPAGATE */
JINT_SSS, /* JOP_GET, */
JINT_SSS, /* JOP_PUT, */
JINT_SSU, /* JOP_GET_INDEX, */

View File

@@ -60,7 +60,7 @@ void janet_printf(const char *format, ...) {
va_start(args, format);
janet_formatb(&buffer, format, args);
va_end(args);
fwrite(buffer.data, buffer.count, 1, janet_dynfile("out", stdout));
fwrite(buffer.data, buffer.count, 1, stdout);
janet_buffer_deinit(&buffer);
}
@@ -250,28 +250,6 @@ void janet_setdyn(const char *name, Janet value) {
janet_table_put(janet_vm_fiber->env, janet_ckeywordv(name), value);
}
uint64_t janet_getflags(const Janet *argv, int32_t n, const char *flags) {
uint64_t ret = 0;
const uint8_t *keyw = janet_getkeyword(argv, n);
int32_t klen = janet_string_length(keyw);
int32_t flen = (int32_t) strlen(flags);
if (flen > 64) {
flen = 64;
}
for (int32_t j = 0; j < klen; j++) {
for (int32_t i = 0; i < flen; i++) {
if (((uint8_t) flags[i]) == keyw[j]) {
ret |= 1ULL << i;
goto found;
}
}
janet_panicf("unexpected flag %c, expected one of \"%s\"", (char) keyw[j], flags);
found:
;
}
return ret;
}
/* Some definitions for function-like macros */
JANET_API JanetStructHead *(janet_struct_head)(const JanetKV *st) {

View File

@@ -35,10 +35,6 @@ static int fixarity1(JanetFopts opts, JanetSlot *args) {
(void) opts;
return janet_v_count(args) == 1;
}
static int maxarity1(JanetFopts opts, JanetSlot *args) {
(void) opts;
return janet_v_count(args) <= 1;
}
static int minarity2(JanetFopts opts, JanetSlot *args) {
(void) opts;
return janet_v_count(args) >= 2;
@@ -92,9 +88,6 @@ static JanetSlot opreduce(
/* Function optimizers */
static JanetSlot do_propagate(JanetFopts opts, JanetSlot *args) {
return opreduce(opts, args, JOP_PROPAGATE, janet_wrap_nil());
}
static JanetSlot do_error(JanetFopts opts, JanetSlot *args) {
janetc_emit_s(opts.compiler, JOP_ERROR, args[0], 0);
return janetc_cslot(janet_wrap_nil());
@@ -122,11 +115,7 @@ static JanetSlot do_length(JanetFopts opts, JanetSlot *args) {
return genericSS(opts, JOP_LENGTH, args[0]);
}
static JanetSlot do_yield(JanetFopts opts, JanetSlot *args) {
if (janet_v_count(args) == 0) {
return genericSSI(opts, JOP_SIGNAL, janetc_cslot(janet_wrap_nil()), 3);
} else {
return genericSSI(opts, JOP_SIGNAL, args[0], 3);
}
return genericSSI(opts, JOP_SIGNAL, args[0], 3);
}
static JanetSlot do_resume(JanetFopts opts, JanetSlot *args) {
return opreduce(opts, args, JOP_RESUME, janet_wrap_nil());
@@ -273,7 +262,7 @@ static const JanetFunOptimizer optimizers[] = {
{fixarity0, do_debug},
{fixarity1, do_error},
{minarity2, do_apply},
{maxarity1, do_yield},
{fixarity1, do_yield},
{fixarity2, do_resume},
{fixarity2, do_get},
{fixarity3, do_put},
@@ -300,8 +289,7 @@ static const JanetFunOptimizer optimizers[] = {
{NULL, do_gte},
{NULL, do_lte},
{NULL, do_eq},
{NULL, do_neq},
{fixarity2, do_propagate}
{NULL, do_neq}
};
const JanetFunOptimizer *janetc_funopt(uint32_t flags) {

View File

@@ -629,7 +629,7 @@ JanetFuncDef *janetc_pop_funcdef(JanetCompiler *c) {
}
memcpy(def->bytecode, c->buffer + scope->bytecode_start, s);
janet_v__cnt(c->buffer) = scope->bytecode_start;
if (NULL != c->mapbuffer && c->source) {
if (NULL != c->mapbuffer) {
size_t s = sizeof(JanetSourceMapping) * def->bytecode_length;
def->sourcemap = malloc(s);
if (NULL == def->sourcemap) {

View File

@@ -60,7 +60,6 @@
#define JANET_FUN_LTE 29
#define JANET_FUN_EQ 30
#define JANET_FUN_NEQ 31
#define JANET_FUN_PROP 32
/* Compiler typedefs */
typedef struct JanetCompiler JanetCompiler;

View File

@@ -57,176 +57,18 @@ 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 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);
*error = janet_cstring("could not find _janet_init symbol");
return NULL;
}
return init;
}
static const char *janet_dyncstring(const char *name, const char *dflt) {
Janet x = janet_dyn(name);
if (janet_checktype(x, JANET_NIL)) return dflt;
if (!janet_checktype(x, JANET_STRING)) {
janet_panicf("expected string, got %v", x);
}
const uint8_t *jstr = janet_unwrap_string(x);
const char *cstr = (const char *)jstr;
if (strlen(cstr) != (size_t) janet_string_length(jstr)) {
janet_panicf("string %v contains embedded 0s");
}
return cstr;
}
static int is_path_sep(char c) {
#ifdef JANET_WINDOWS
if (c == '\\') return 1;
#endif
return c == '/';
}
/* Used for module system. */
static Janet janet_core_expand_path(int32_t argc, Janet *argv) {
janet_fixarity(argc, 2);
const char *input = janet_getcstring(argv, 0);
const char *template = janet_getcstring(argv, 1);
const char *curfile = janet_dyncstring("current-file", "");
const char *syspath = janet_dyncstring("syspath", "");
JanetBuffer *out = janet_buffer(0);
size_t tlen = strlen(template);
/* Calculate name */
const char *name = input + strlen(input);
while (name > input) {
if (is_path_sep(*(name - 1))) break;
name--;
}
/* Calculate dirpath from current file */
const char *curname = curfile + strlen(curfile);
while (curname > curfile) {
if (is_path_sep(*curname)) break;
curname--;
}
const char *curdir;
int32_t curlen;
if (curname == curfile) {
/* Current file has one or zero path segments, so
* we are in the . directory. */
curdir = ".";
curlen = 1;
} else {
/* Current file has 2 or more segments, so we
* can cut off the last segment. */
curdir = curfile;
curlen = (int32_t)(curname - curfile);
}
for (size_t i = 0; i < tlen; i++) {
if (template[i] == ':') {
if (strncmp(template + i, ":all:", 5) == 0) {
janet_buffer_push_cstring(out, input);
i += 4;
} else if (strncmp(template + i, ":cur:", 5) == 0) {
janet_buffer_push_bytes(out, (const uint8_t *)curdir, curlen);
i += 4;
} else if (strncmp(template + i, ":dir:", 5) == 0) {
janet_buffer_push_bytes(out, (const uint8_t *)input,
(int32_t)(name - input));
i += 4;
} else if (strncmp(template + i, ":sys:", 5) == 0) {
janet_buffer_push_cstring(out, syspath);
i += 4;
} else if (strncmp(template + i, ":name:", 6) == 0) {
janet_buffer_push_cstring(out, name);
i += 5;
} else {
janet_buffer_push_u8(out, (uint8_t) template[i]);
}
} else {
janet_buffer_push_u8(out, (uint8_t) template[i]);
}
}
/* Normalize */
uint8_t *scan = out->data;
uint8_t *print = scan;
uint8_t *scanend = scan + out->count;
int normal_section_count = 0;
int dot_count = 0;
while (scan < scanend) {
if (*scan == '.') {
if (dot_count >= 0) {
dot_count++;
} else {
*print++ = '.';
}
} else if (is_path_sep(*scan)) {
if (dot_count == 1) {
;
} else if (dot_count == 2) {
if (normal_section_count > 0) {
/* unprint last separator */
print--;
/* unprint last section */
while (print > out->data && !is_path_sep(*(print - 1)))
print--;
normal_section_count--;
} else {
*print++ = '.';
*print++ = '.';
*print++ = '/';
}
} else if (scan == out->data || dot_count != 0) {
while (dot_count > 0) {
--dot_count;
*print++ = '.';
}
if (scan > out->data) {
normal_section_count++;
}
*print++ = '/';
}
dot_count = 0;
} else {
dot_count = -1;
*print++ = *scan;
}
scan++;
}
out->count = (int32_t)(print - out->data);
return janet_wrap_buffer(out);
}
static Janet janet_core_dyn(int32_t argc, Janet *argv) {
janet_arity(argc, 1, 2);
Janet value;
@@ -409,21 +251,19 @@ static Janet janet_core_hash(int32_t argc, Janet *argv) {
}
static Janet janet_core_getline(int32_t argc, Janet *argv) {
FILE *in = janet_dynfile("in", stdin);
FILE *out = janet_dynfile("out", stdout);
janet_arity(argc, 0, 2);
JanetBuffer *buf = (argc >= 2) ? janet_getbuffer(argv, 1) : janet_buffer(10);
if (argc >= 1) {
const char *prompt = (const char *) janet_getstring(argv, 0);
fprintf(out, "%s", prompt);
fflush(out);
printf("%s", prompt);
fflush(stdout);
}
{
buf->count = 0;
int c;
for (;;) {
c = fgetc(in);
if (feof(in) || c < 0) {
c = fgetc(stdin);
if (feof(stdin) || c < 0) {
break;
}
janet_buffer_push_u8(buf, (uint8_t) c);
@@ -450,7 +290,7 @@ static Janet janet_core_untrace(int32_t argc, Janet *argv) {
static const JanetReg corelib_cfuns[] = {
{
"native", janet_core_native,
JDOC("(native path &opt env)\n\n"
JDOC("(native path [,env])\n\n"
"Load a native module from the given path. The path "
"must be an absolute or relative path on the file system, and is "
"usually a .so file on Unix systems, and a .dll file on Windows. "
@@ -576,7 +416,7 @@ static const JanetReg corelib_cfuns[] = {
},
{
"next", janet_core_next,
JDOC("(next dict &opt key)\n\n"
JDOC("(next dict key)\n\n"
"Gets the next key in a struct or table. Can be used to iterate through "
"the keys of a data structure in an unspecified order. Keys are guaranteed "
"to be seen only once per iteration if they data structure is not mutated "
@@ -592,14 +432,14 @@ static const JanetReg corelib_cfuns[] = {
},
{
"getline", janet_core_getline,
JDOC("(getline &opt prompt buf)\n\n"
JDOC("(getline [, prompt=\"\" [, buffer=@\"\"]])\n\n"
"Reads a line of input into a buffer, including the newline character, using a prompt. Returns the modified buffer. "
"Use this function to implement a simple interface for a terminal program.")
},
{
"dyn", janet_core_dyn,
JDOC("(dyn key &opt default)\n\n"
"Get a dynamic binding. Returns the default value (or nil) if no binding found.")
JDOC("(dyn key [, default=nil])\n\n"
"Get a dynamic binding. Returns the default value if no binding found.")
},
{
"setdyn", janet_core_setdyn,
@@ -616,14 +456,6 @@ static const JanetReg corelib_cfuns[] = {
JDOC("(untrace func)\n\n"
"Disables tracing on a function. Returns the function.")
},
{
"module/expand-path", janet_core_expand_path,
JDOC("(module/expand-path path template)\n\n"
"Expands a path template as found in module/paths for module/find. "
"This takes in a path (the argument to require) and a template string, template, "
"to expand the path to a path that can be "
"used for importing files.")
},
{NULL, NULL, NULL}
};
@@ -855,10 +687,6 @@ static const uint32_t bnot_asm[] = {
JOP_BNOT,
JOP_RETURN
};
static const uint32_t propagate_asm[] = {
JOP_PROPAGATE | (1 << 24),
JOP_RETURN
};
#endif /* ifndef JANET_NO_BOOTSTRAP */
JanetTable *janet_core_env(JanetTable *replacements) {
@@ -866,13 +694,6 @@ JanetTable *janet_core_env(JanetTable *replacements) {
janet_core_cfuns(env, NULL, corelib_cfuns);
#ifdef JANET_BOOTSTRAP
janet_quick_asm(env, JANET_FUN_PROP,
"propagate", 2, 2, 2, 2, propagate_asm, sizeof(propagate_asm),
JDOC("(propagate x fiber)\n\n"
"Propagate a signal from a fiber to the current fiber. The resulting "
"stack trace from the current fiber will include frames from fiber. If "
"fiber is in a state that can be resumed, resuming the current fiber will "
"first resume fiber."));
janet_quick_asm(env, JANET_FUN_DEBUG,
"debug", 0, 0, 0, 1, debug_asm, sizeof(debug_asm),
JDOC("(debug)\n\n"
@@ -1009,9 +830,6 @@ 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."));

View File

@@ -323,14 +323,14 @@ static const JanetReg debug_cfuns[] = {
},
{
"debug/fbreak", cfun_debug_fbreak,
JDOC("(debug/fbreak fun &opt pc)\n\n"
JDOC("(debug/fbreak fun [,pc=0])\n\n"
"Set a breakpoint in a given function. pc is an optional offset, which "
"is in bytecode instructions. fun is a function value. Will throw an error "
"if the offset is too large or negative.")
},
{
"debug/unfbreak", cfun_debug_unfbreak,
JDOC("(debug/unfbreak fun &opt pc)\n\n"
JDOC("(debug/unfbreak fun [,pc=0])\n\n"
"Unset a breakpoint set with debug/fbreak.")
},
{

View File

@@ -391,13 +391,6 @@ static Janet cfun_fiber_new(int32_t argc, Janet *argv) {
}
fiber->env = janet_vm_fiber->env;
break;
case 'p':
if (!janet_vm_fiber->env) {
janet_vm_fiber->env = janet_table(0);
}
fiber->env = janet_table(0);
fiber->env->proto = janet_vm_fiber->env;
break;
}
}
}
@@ -438,7 +431,7 @@ static Janet cfun_fiber_setmaxstack(int32_t argc, Janet *argv) {
static const JanetReg fiber_cfuns[] = {
{
"fiber/new", cfun_fiber_new,
JDOC("(fiber/new func &opt sigmask)\n\n"
JDOC("(fiber/new func [,sigmask])\n\n"
"Create a new fiber with function body func. Can optionally "
"take a set of signals to block from the current parent fiber "
"when called. The mask is specified as a keyword where each character "
@@ -452,11 +445,8 @@ static const JanetReg fiber_cfuns[] = {
"\te - block error signals\n"
"\tu - block user signals\n"
"\ty - block yield signals\n"
"\t0-9 - block a specific user signal\n\n"
"The sigmask argument also can take environment flags. If any mutually "
"exclusive flags are present, the last flag takes precedence.\n\n"
"\ti - inherit the environment from the current fiber\n"
"\tp - the environment table's prototype is the current environment table")
"\t0-9 - block a specific user signal\n"
"\ti - inherit the environment from the current fiber (not related to signals)")
},
{
"fiber/status", cfun_fiber_status,

View File

@@ -39,11 +39,6 @@ JANET_THREAD_LOCAL Janet *janet_vm_roots;
JANET_THREAD_LOCAL uint32_t janet_vm_root_count;
JANET_THREAD_LOCAL uint32_t janet_vm_root_capacity;
/* Scratch Memory */
JANET_THREAD_LOCAL void **janet_scratch_mem;
JANET_THREAD_LOCAL size_t janet_scratch_cap;
JANET_THREAD_LOCAL size_t janet_scratch_len;
/* Helpers for marking the various gc types */
static void janet_mark_funcenv(JanetFuncEnv *env);
static void janet_mark_funcdef(JanetFuncDef *def);
@@ -262,10 +257,10 @@ static void janet_deinit_block(JanetGCObject *mem) {
janet_symbol_deinit(((JanetStringHead *) mem)->data);
break;
case JANET_MEMORY_ARRAY:
free(((JanetArray *) mem)->data);
janet_array_deinit((JanetArray *) mem);
break;
case JANET_MEMORY_TABLE:
free(((JanetTable *) mem)->data);
janet_table_deinit((JanetTable *) mem);
break;
case JANET_MEMORY_FIBER:
free(((JanetFiber *)mem)->data);
@@ -347,13 +342,6 @@ void *janet_gcalloc(enum JanetMemoryType type, size_t size) {
return (void *)mem;
}
/* Free all allocated scratch memory */
static void janet_free_all_scratch(void) {
for (size_t i = 0; i < janet_scratch_len; i++)
free(janet_scratch_mem[i]);
janet_scratch_len = 0;
}
/* Run garbage collection */
void janet_collect(void) {
uint32_t i;
@@ -368,7 +356,6 @@ void janet_collect(void) {
}
janet_sweep();
janet_vm_next_collection = 0;
janet_free_all_scratch();
}
/* Add a root value to the GC. This prevents the GC from removing a value
@@ -442,8 +429,6 @@ void janet_clear_memory(void) {
current = next;
}
janet_vm_blocks = NULL;
janet_free_all_scratch();
free(janet_scratch_mem);
}
/* Primitives for suspending GC. */
@@ -453,56 +438,3 @@ int janet_gclock(void) {
void janet_gcunlock(int handle) {
janet_vm_gc_suspend = handle;
}
/* Scratch memory API */
void *janet_smalloc(size_t size) {
void *mem = malloc(size);
if (NULL == mem) {
JANET_OUT_OF_MEMORY;
}
if (janet_scratch_len == janet_scratch_cap) {
size_t newcap = 2 * janet_scratch_cap + 2;
void **newmem = (void **) realloc(janet_scratch_mem, newcap * sizeof(void *));
if (NULL == newmem) {
JANET_OUT_OF_MEMORY;
}
janet_scratch_cap = newcap;
janet_scratch_mem = newmem;
}
janet_scratch_mem[janet_scratch_len++] = mem;
return mem;
}
void *janet_srealloc(void *mem, size_t size) {
if (NULL == mem) return janet_smalloc(size);
if (janet_scratch_len) {
for (size_t i = janet_scratch_len - 1; ; i--) {
if (janet_scratch_mem[i] == mem) {
void *newmem = realloc(mem, size);
if (NULL == newmem) {
JANET_OUT_OF_MEMORY;
}
janet_scratch_mem[i] = newmem;
return newmem;
}
if (i == 0) break;
}
}
janet_exit("invalid janet_srealloc");
}
void janet_sfree(void *mem) {
if (NULL == mem) return;
if (janet_scratch_len) {
for (size_t i = janet_scratch_len - 1; ; i--) {
if (janet_scratch_mem[i] == mem) {
janet_scratch_mem[i] = janet_scratch_mem[--janet_scratch_len];
free(mem);
return;
}
if (i == 0) break;
}
}
janet_exit("invalid janet_sfree");
}

View File

@@ -32,10 +32,6 @@
#include "util.h"
#endif
#ifndef JANET_WINDOWS
#include <sys/wait.h>
#endif
#define IO_WRITE 1
#define IO_READ 2
#define IO_APPEND 4
@@ -164,36 +160,6 @@ static Janet cfun_io_fopen(int32_t argc, Janet *argv) {
return f ? makef(f, flags) : janet_wrap_nil();
}
static Janet cfun_io_fdopen(int32_t argc, Janet *argv) {
janet_arity(argc, 1, 2);
const int fd = janet_getinteger(argv, 0);
const uint8_t *fmode;
int flags;
if (argc == 2) {
fmode = janet_getkeyword(argv, 1);
flags = checkflags(fmode);
} else {
fmode = (const uint8_t *)"r";
flags = IO_READ;
}
#ifdef JANET_WINDOWS
#define fdopen _fdopen
#endif
FILE *f = fdopen(fd, (const char *)fmode);
return f ? makef(f, flags) : janet_wrap_nil();
}
static Janet cfun_io_fileno(int32_t argc, Janet *argv) {
janet_fixarity(argc, 1);
IOFile *iof = janet_getabstract(argv, 0, &cfun_io_filetype);
if (iof->flags & IO_CLOSED)
janet_panic("file is closed");
#ifdef JANET_WINDOWS
#define fileno _fileno
#endif
return janet_wrap_integer(fileno(iof->file));
}
/* 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)))
@@ -319,17 +285,13 @@ 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
int status = pclose(iof->file);
iof->flags |= IO_CLOSED;
if (status == -1) janet_panic("could not close file");
return janet_wrap_integer(WEXITSTATUS(status));
if (pclose(iof->file)) janet_panic("could not close file");
} 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 */
@@ -408,7 +370,7 @@ static const JanetReg io_cfuns[] = {
},
{
"file/open", cfun_io_fopen,
JDOC("(file/open path &opt mode)\n\n"
JDOC("(file/open path [,mode])\n\n"
"Open a file. path is an absolute or relative path, and "
"mode is a set of flags indicating the mode to open the file in. "
"mode is a keyword where each character represents a flag. If the file "
@@ -420,26 +382,6 @@ static const JanetReg io_cfuns[] = {
"\tb - open the file in binary mode (rather than text mode)\n"
"\t+ - append to the file instead of overwriting it")
},
{
"file/fdopen", cfun_io_fdopen,
JDOC("(file/fdopen fd &opt mode)\n\n"
"Create a file from an fd. fd is a platform specific file descriptor, and "
"mode is a set of flags indicating the mode to open the file in. "
"mode is a keyword where each character represents a flag. If the file "
"cannot be opened, returns nil, otherwise returns the new file handle. "
"Mode flags:\n\n"
"\tr - allow reading from the file\n"
"\tw - allow writing to the file\n"
"\ta - append to the file\n"
"\tb - open the file in binary mode (rather than text mode)\n"
"\t+ - append to the file instead of overwriting it")
},
{
"file/fileno", cfun_io_fileno,
JDOC("(file/fileno f)\n\n"
"Return the underlying file descriptor for the file as a number."
"The meaning of this number is platform specific.")
},
{
"file/close", cfun_io_fclose,
JDOC("(file/close f)\n\n"
@@ -449,7 +391,7 @@ static const JanetReg io_cfuns[] = {
},
{
"file/read", cfun_io_fread,
JDOC("(file/read f what &opt buf)\n\n"
JDOC("(file/read f what [,buf])\n\n"
"Read a number of bytes from a file into a buffer. A buffer can "
"be provided as an optional fourth argument, otherwise a new buffer "
"is created. 'what' can either be an integer or a keyword. Returns the "
@@ -473,7 +415,7 @@ static const JanetReg io_cfuns[] = {
},
{
"file/seek", cfun_io_fseek,
JDOC("(file/seek f &opt whence n)\n\n"
JDOC("(file/seek f [,whence [,n]])\n\n"
"Jump to a relative location in the file. 'whence' must be one of\n\n"
"\t:cur - jump relative to the current file location\n"
"\t:set - jump relative to the beginning of the file\n"
@@ -484,7 +426,7 @@ static const JanetReg io_cfuns[] = {
},
{
"file/popen", cfun_io_popen,
JDOC("(file/popen path &opt mode)\n\n"
JDOC("(file/popen path [,mode])\n\n"
"Open a file that is backed by a process. The file must be opened in either "
"the :r (read) or the :w (write) mode. In :r mode, the stdout of the "
"process can be read from the file. In :w mode, the stdin of the process "

View File

@@ -328,11 +328,11 @@ static void marshal_one_abstract(MarshalState *st, Janet x, int flags) {
void *abstract = janet_unwrap_abstract(x);
const JanetAbstractType *at = janet_abstract_type(abstract);
if (at->marshal) {
MARK_SEEN();
JanetMarshalContext context = {st, NULL, flags, NULL};
pushbyte(st, LB_ABSTRACT);
marshal_one(st, janet_csymbolv(at->name), flags + 1);
push64(st, (uint64_t) janet_abstract_size(abstract));
MARK_SEEN();
at->marshal(abstract, &context);
} else {
janet_panicf("try to marshal unregistered abstract type, cannot marshal %p", x);
@@ -535,6 +535,7 @@ void janet_marshal(
st.rreg = rreg;
janet_table_init(&st.seen, 0);
marshal_one(&st, x, flags);
/* Clean up. See comment in janet_unmarshal about autoreleasing memory on panics.*/
janet_table_deinit(&st.seen);
janet_v_free(st.seen_envs);
janet_v_free(st.seen_defs);
@@ -542,7 +543,7 @@ void janet_marshal(
typedef struct {
jmp_buf err;
Janet *lookup;
JanetArray lookup;
JanetTable *reg;
JanetFuncEnv **lookup_envs;
JanetFuncDef **lookup_defs;
@@ -848,7 +849,7 @@ static const uint8_t *unmarshal_one_fiber(
fiber->env = NULL;
/* Push fiber to seen stack */
janet_v_push(st->lookup, janet_wrap_fiber(fiber));
janet_array_push(&st->lookup, janet_wrap_fiber(fiber));
/* Set frame later so fiber can be GCed at anytime if unmarshalling fails */
int32_t frame = 0;
@@ -1008,11 +1009,10 @@ static const uint8_t *unmarshal_one_abstract(UnmarshalState *st, const uint8_t *
if (at == NULL) return NULL;
if (at->unmarshal) {
void *p = janet_abstract(at, (size_t) read64(st, &data));
*out = janet_wrap_abstract(p);
JanetMarshalContext context = {NULL, st, flags, data};
janet_v_push(st->lookup, *out);
at->unmarshal(p, &context);
return context.data;
*out = janet_wrap_abstract(p);
return data;
}
return NULL;
}
@@ -1071,7 +1071,7 @@ static const uint8_t *unmarshal_one(
memcpy(&u.bytes, data + 1, sizeof(double));
#endif
*out = janet_wrap_number(u.d);
janet_v_push(st->lookup, *out);
janet_array_push(&st->lookup, *out);
return data + 9;
}
case LB_STRING:
@@ -1104,7 +1104,7 @@ static const uint8_t *unmarshal_one(
memcpy(buffer->data, data, len);
*out = janet_wrap_buffer(buffer);
}
janet_v_push(st->lookup, *out);
janet_array_push(&st->lookup, *out);
return data + len;
}
case LB_FIBER: {
@@ -1121,7 +1121,7 @@ static const uint8_t *unmarshal_one(
def->environments_length * sizeof(JanetFuncEnv));
func->def = def;
*out = janet_wrap_function(func);
janet_v_push(st->lookup, *out);
janet_array_push(&st->lookup, *out);
for (int32_t i = 0; i < def->environments_length; i++) {
data = unmarshal_one_env(st, data, &(func->envs[i]), flags + 1);
}
@@ -1146,7 +1146,7 @@ static const uint8_t *unmarshal_one(
JanetArray *array = janet_array(len);
array->count = len;
*out = janet_wrap_array(array);
janet_v_push(st->lookup, *out);
janet_array_push(&st->lookup, *out);
for (int32_t i = 0; i < len; i++) {
data = unmarshal_one(st, data, array->data + i, flags + 1);
}
@@ -1159,7 +1159,7 @@ static const uint8_t *unmarshal_one(
data = unmarshal_one(st, data, tup + i, flags + 1);
}
*out = janet_wrap_tuple(janet_tuple_end(tup));
janet_v_push(st->lookup, *out);
janet_array_push(&st->lookup, *out);
} else if (lead == LB_STRUCT) {
/* Struct */
JanetKV *struct_ = janet_struct_begin(len);
@@ -1170,16 +1170,16 @@ static const uint8_t *unmarshal_one(
janet_struct_put(struct_, key, value);
}
*out = janet_wrap_struct(janet_struct_end(struct_));
janet_v_push(st->lookup, *out);
janet_array_push(&st->lookup, *out);
} else if (lead == LB_REFERENCE) {
if (len < 0 || len >= janet_v_count(st->lookup))
if (len < 0 || len >= st->lookup.count)
janet_panicf("invalid reference %d", len);
*out = st->lookup[len];
*out = st->lookup.data[len];
} else {
/* Table */
JanetTable *t = janet_table(len);
*out = janet_wrap_table(t);
janet_v_push(st->lookup, *out);
janet_array_push(&st->lookup, *out);
if (lead == LB_TABLE_PROTO) {
Janet proto;
data = unmarshal_one(st, data, &proto, flags + 1);
@@ -1216,14 +1216,17 @@ Janet janet_unmarshal(
st.end = bytes + len;
st.lookup_defs = NULL;
st.lookup_envs = NULL;
st.lookup = NULL;
st.reg = reg;
janet_array_init(&st.lookup, 0);
Janet out;
const uint8_t *nextbytes = unmarshal_one(&st, bytes, &out, flags);
if (next) *next = nextbytes;
/* Clean up - this should be auto released on panics, TODO. We should
* change the vector implementation to track allocations for auto release, and
* make st.lookup auto release as well, or move to heap. */
janet_array_deinit(&st.lookup);
janet_v_free(st.lookup_defs);
janet_v_free(st.lookup_envs);
janet_v_free(st.lookup);
return out;
}
@@ -1264,7 +1267,7 @@ static Janet cfun_unmarshal(int32_t argc, Janet *argv) {
static const JanetReg marsh_cfuns[] = {
{
"marshal", cfun_marshal,
JDOC("(marshal x &opt reverse-lookup buffer)\n\n"
JDOC("(marshal x [,reverse-lookup [,buffer]])\n\n"
"Marshal a janet value into a buffer and return the buffer. The buffer "
"can the later be unmarshalled to reconstruct the initial value. "
"Optionally, one can pass in a reverse lookup table to not marshal "
@@ -1274,7 +1277,7 @@ static const JanetReg marsh_cfuns[] = {
},
{
"unmarshal", cfun_unmarshal,
JDOC("(unmarshal buffer &opt lookup)\n\n"
JDOC("(unmarshal buffer [,lookup])\n\n"
"Unmarshal a janet value from a buffer. An optional lookup table "
"can be provided to allow for aliases to be resolved. Returns the value "
"unmarshalled from the buffer.")

View File

@@ -41,15 +41,12 @@
#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>
#include <sys/types.h>
#include <sys/wait.h>
extern char **environ;
#endif
/* For macos */
@@ -91,7 +88,7 @@ static Janet os_exit(int32_t argc, Janet *argv) {
}
#ifdef JANET_REDUCED_OS
/* Provide a dud os/getenv so boot.janet and init.janet work, but nothing else */
/* Provide a dud os/getenv so init.janet works, but nothing else */
static Janet os_getenv(int32_t argc, Janet *argv) {
(void) argv;
@@ -102,224 +99,97 @@ static Janet os_getenv(int32_t argc, Janet *argv) {
#else
/* Provide full os functionality */
/* Get env for os_execute */
static char **os_execute_env(int32_t argc, const Janet *argv) {
char **envp = NULL;
if (argc > 2) {
JanetDictView dict = janet_getdictionary(argv, 2);
envp = janet_smalloc(sizeof(char *) * (dict.len + 1));
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 = janet_smalloc(klen + vlen + 2);
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) {
#ifdef JANET_WINDOWS
(void) child_argv;
#else
janet_sfree((void *)child_argv);
#endif
if (NULL != envp) {
char **envitem = envp;
while (*envitem != NULL) {
janet_sfree(*envitem);
envitem++;
}
}
janet_sfree(envp);
}
#ifdef JANET_WINDOWS
/* Windows processes created via CreateProcess get only one command line argument string, and
* must parse this themselves. Each processes is free to do this however they like, but the
* standard parsing method is CommandLineToArgvW. We need to properly escape arguments into
* a single string of this format. Returns a buffer that can be cast into a c string. */
static JanetBuffer *os_exec_escape(JanetView args) {
JanetBuffer *b = janet_buffer(0);
for (int32_t i = 0; i < args.len; i++) {
const char *arg = janet_getcstring(args.items, i);
/* Push leading space if not first */
if (i) janet_buffer_push_u8(b, ' ');
/* Find first special character */
const char *first_spec = arg;
while (*first_spec) {
switch (*first_spec) {
case ' ':
case '\t':
case '\v':
case '\n':
case '"':
goto found;
case '\0':
janet_panic("embedded 0 not allowed in command line string");
default:
first_spec++;
break;
}
}
found:
/* Check if needs escape */
if (*first_spec == '\0') {
/* No escape needed */
janet_buffer_push_cstring(b, arg);
} else {
/* Escape */
janet_buffer_push_u8(b, '"');
for (const char *c = arg; ; c++) {
unsigned numBackSlashes = 0;
while (*c == '\\') {
c++;
numBackSlashes++;
}
if (*c == '"') {
/* Escape all backslashes and double quote mark */
int32_t n = 2 * numBackSlashes + 1;
janet_buffer_extra(b, n + 1);
memset(b->data + b->count, '\\', n);
b->count += n;
janet_buffer_push_u8(b, '"');
} else if (*c) {
/* Don't escape backslashes. */
int32_t n = numBackSlashes;
janet_buffer_extra(b, n + 1);
memset(b->data + b->count, '\\', n);
b->count += n;
janet_buffer_push_u8(b, *c);
} else {
/* we finished Escape all backslashes */
int32_t n = 2 * numBackSlashes;
janet_buffer_extra(b, n + 1);
memset(b->data + b->count, '\\', n);
b->count += n;
break;
}
}
janet_buffer_push_u8(b, '"');
}
}
janet_buffer_push_u8(b, 0);
return b;
}
#endif
static Janet os_execute(int32_t argc, Janet *argv) {
janet_arity(argc, 1, 3);
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, ' ');
}
}
janet_buffer_push_u8(buffer, 0);
/* Get flags */
uint64_t flags = 0;
if (argc > 1) {
flags = janet_getflags(argv, 1, "ep");
/* 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");
}
/* Get environment */
char **envp = os_execute_env(argc, argv);
STARTUPINFO si;
PROCESS_INFORMATION pi;
/* Get arguments */
JanetView exargs = janet_getindexed(argv, 0);
if (exargs.len < 1) {
janet_panic("expected at least 1 command line argument");
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);
/* Result */
int status = 0;
#ifdef JANET_WINDOWS
JanetBuffer *buf = os_exec_escape(exargs);
if (buf->count > 1025) {
janet_panic("command line string too long");
}
const char *path = (const char *) janet_unwrap_string(exargs.items[0]);
char *cargv[2] = {(char *) buf->data, NULL};
/* Use _spawn family of functions. */
/* Windows docs say do this before any spawns. */
_flushall();
/* Use an empty env instead when envp is NULL to be consistent with other implementation. */
char *empty_env[1] = {NULL};
char **envp1 = (NULL == envp) ? empty_env : envp;
if (janet_flag_at(flags, 1) && janet_flag_at(flags, 0)) {
status = (int) _spawnvpe(_P_WAIT, path, cargv, envp1);
} else if (janet_flag_at(flags, 1)) {
status = (int) _spawnvp(_P_WAIT, path, cargv);
} else if (janet_flag_at(flags, 0)) {
status = (int) _spawnve(_P_WAIT, path, cargv, envp1);
} else {
status = (int) _spawnv(_P_WAIT, path, cargv);
}
os_execute_cleanup(envp, NULL);
/* Check error */
if (-1 == status) {
janet_panic(strerror(errno));
}
// 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);
}
#else
const char **child_argv = janet_smalloc(sizeof(char *) * (exargs.len + 1));
for (int32_t i = 0; i < exargs.len; i++)
child_argv[i] = janet_getcstring(exargs.items, i);
child_argv[exargs.len] = NULL;
/* 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;
/* Use posix_spawn to spawn new process */
pid_t pid;
if (janet_flag_at(flags, 1)) {
status = posix_spawnp(&pid,
child_argv[0], NULL, NULL, cargv,
janet_flag_at(flags, 0) ? envp : environ);
} else {
status = posix_spawn(&pid,
child_argv[0], NULL, NULL, cargv,
janet_flag_at(flags, 0) ? envp : environ);
static Janet os_execute(int32_t argc, Janet *argv) {
janet_arity(argc, 1, -1);
const char **child_argv = malloc(sizeof(char *) * (argc + 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);
}
child_argv[argc] = NULL;
/* Wait for child */
if (status) {
os_execute_cleanup(envp, child_argv);
janet_panic(strerror(status));
/* 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);
}
} else {
waitpid(pid, &status, 0);
}
os_execute_cleanup(envp, child_argv);
return janet_wrap_integer(WEXITSTATUS(status));
#endif
free(child_argv);
return janet_wrap_integer(status);
}
#endif
static Janet os_shell(int32_t argc, Janet *argv) {
janet_arity(argc, 0, 1);
@@ -737,23 +607,12 @@ 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[] = {
{
"os/exit", os_exit,
JDOC("(os/exit &opt x)\n\n"
JDOC("(os/exit x)\n\n"
"Exit from janet with an exit code equal to x. If x is not an integer, "
"the exit with status equal the hash of x.")
},
@@ -773,13 +632,13 @@ static const JanetReg os_cfuns[] = {
#ifndef JANET_REDUCED_OS
{
"os/dir", os_dir,
JDOC("(os/dir dir &opt 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.")
},
{
"os/stat", os_stat,
JDOC("(os/stat path &opt tab|key)\n\n"
JDOC("(os/stat path [, tab|key])\n\n"
"Gets information about a file or directory. Returns a table If the third argument is a keyword, returns "
" only that information from stat. If the file or directory does not exist, returns nil. The keys are\n\n"
"\t:dev - the device that the file is on\n"
@@ -798,7 +657,7 @@ static const JanetReg os_cfuns[] = {
},
{
"os/touch", os_touch,
JDOC("(os/touch path &opt actime modtime)\n\n"
JDOC("(os/touch path [, actime [, modtime]])\n\n"
"Update the access time and modification times for a file. By default, sets "
"times to the current time.")
},
@@ -825,21 +684,15 @@ static const JanetReg os_cfuns[] = {
},
{
"os/link", os_link,
JDOC("(os/link oldpath newpath &opt symlink)\n\n"
JDOC("(os/link oldpath newpath [, symlink])\n\n"
"Create a symlink from oldpath to newpath. The 3 optional paramater "
"enables a hard link over a soft link. Does not work on Windows.")
},
{
"os/execute", os_execute,
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.")
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.")
},
{
"os/shell", os_shell,
@@ -876,7 +729,7 @@ static const JanetReg os_cfuns[] = {
},
{
"os/date", os_date,
JDOC("(os/date &opt time)\n\n"
JDOC("(os/date [,time])\n\n"
"Returns the given time as a date struct, or the current time if no time is given. "
"Returns a struct with following key values. Note that all numbers are 0-indexed.\n\n"
"\t:seconds - number of seconds [0-61]\n"
@@ -889,11 +742,6 @@ 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}
};

View File

@@ -144,8 +144,6 @@ DEF_PARSER_STACK(_pushstate, JanetParseState, states, statecount, statecap)
#define PFLAG_LONGSTRING 0x4000
#define PFLAG_READERMAC 0x8000
#define PFLAG_ATSYM 0x10000
#define PFLAG_COMMENT 0x20000
#define PFLAG_TOKEN 0x40000
static void pushstate(JanetParser *p, Consumer consumer, int flags) {
JanetParseState s;
@@ -359,12 +357,7 @@ static int tokenchar(JanetParser *p, JanetParseState *state, uint8_t c) {
static int comment(JanetParser *p, JanetParseState *state, uint8_t c) {
(void) state;
if (c == '\n') {
p->statecount--;
p->bufcount = 0;
} else {
push_buf(p, c);
}
if (c == '\n') p->statecount--;
return 1;
}
@@ -450,7 +443,7 @@ static int longstring(JanetParser *p, JanetParseState *state, uint8_t c) {
static int root(JanetParser *p, JanetParseState *state, uint8_t c);
static int atsign(JanetParser *p, JanetParseState *state, uint8_t c) {
static int ampersand(JanetParser *p, JanetParseState *state, uint8_t c) {
(void) state;
p->statecount--;
switch (c) {
@@ -472,8 +465,8 @@ static int atsign(JanetParser *p, JanetParseState *state, uint8_t c) {
default:
break;
}
pushstate(p, tokenchar, PFLAG_TOKEN);
push_buf(p, '@'); /* Push the leading at-sign that was dropped */
pushstate(p, tokenchar, 0);
push_buf(p, '@'); /* Push the leading ampersand that was dropped */
return 0;
}
@@ -486,7 +479,7 @@ static int root(JanetParser *p, JanetParseState *state, uint8_t c) {
p->error = "unexpected character";
return 1;
}
pushstate(p, tokenchar, PFLAG_TOKEN);
pushstate(p, tokenchar, 0);
return 0;
case '\'':
case ',':
@@ -498,10 +491,10 @@ static int root(JanetParser *p, JanetParseState *state, uint8_t c) {
pushstate(p, stringchar, PFLAG_STRING);
return 1;
case '#':
pushstate(p, comment, PFLAG_COMMENT);
pushstate(p, comment, 0);
return 1;
case '@':
pushstate(p, atsign, PFLAG_ATSYM);
pushstate(p, ampersand, 0);
return 1;
case '`':
pushstate(p, longstring, PFLAG_LONGSTRING);
@@ -641,51 +634,6 @@ void janet_parser_deinit(JanetParser *parser) {
free(parser->states);
}
void janet_parser_clone(const JanetParser *src, JanetParser *dest) {
/* Misc fields */
dest->flag = src->flag;
dest->pending = src->pending;
dest->lookback = src->lookback;
dest->offset = src->offset;
dest->error = src->error;
/* Keep counts */
dest->argcount = src->argcount;
dest->bufcount = src->bufcount;
dest->statecount = src->statecount;
/* Capacities are equal to counts */
dest->bufcap = dest->bufcount;
dest->statecap = dest->statecount;
dest->argcap = dest->argcount;
/* Deep cloned fields */
dest->args = NULL;
dest->states = NULL;
dest->buf = NULL;
if (dest->bufcap) {
dest->buf = malloc(dest->bufcap);
if (!dest->buf) goto nomem;
}
if (dest->argcap) {
dest->args = malloc(sizeof(Janet) * dest->argcap);
if (!dest->args) goto nomem;
}
if (dest->statecap) {
dest->states = malloc(sizeof(JanetParseState) * dest->statecap);
if (!dest->states) goto nomem;
}
memcpy(dest->buf, src->buf, dest->bufcap);
memcpy(dest->args, src->args, dest->argcap * sizeof(Janet));
memcpy(dest->states, src->states, dest->statecap * sizeof(JanetParseState));
return;
nomem:
JANET_OUT_OF_MEMORY;
}
int janet_parser_has_more(JanetParser *parser) {
return !!parser->pending;
}
@@ -853,179 +801,43 @@ static Janet cfun_parse_flush(int32_t argc, Janet *argv) {
}
static Janet cfun_parse_where(int32_t argc, Janet *argv) {
janet_arity(argc, 1, 2);
janet_fixarity(argc, 1);
JanetParser *p = janet_getabstract(argv, 0, &janet_parse_parsertype);
if (argc > 1) {
int32_t offset = janet_getinteger(argv, 1);
p->offset = offset;
return argv[0];
} else {
return janet_wrap_integer(p->offset);
}
return janet_wrap_integer(p->offset);
}
static Janet janet_wrap_parse_state(JanetParseState *s, Janet *args,
uint8_t *buff, uint32_t bufcount) {
JanetTable *state = janet_table(0);
const uint8_t *buffer;
int add_buffer = 0;
const char *type = NULL;
if (s->flags & PFLAG_CONTAINER) {
JanetArray *container_args = janet_array(s->argn);
container_args->count = s->argn;
memcpy(container_args->data, args, sizeof(args[0])*s->argn);
janet_table_put(state, janet_ckeywordv("args"),
janet_wrap_array(container_args));
}
if (s->flags & PFLAG_PARENS || s->flags & PFLAG_SQRBRACKETS) {
if (s->flags & PFLAG_ATSYM) {
type = "array";
} else {
type = "tuple";
}
} else if (s->flags & PFLAG_CURLYBRACKETS) {
if (s->flags & PFLAG_ATSYM) {
type = "table";
} else {
type = "struct";
}
} else if (s->flags & PFLAG_STRING || s->flags & PFLAG_LONGSTRING) {
if (s->flags & PFLAG_BUFFER) {
type = "buffer";
} else {
type = "string";
}
add_buffer = 1;
} else if (s->flags & PFLAG_COMMENT) {
type = "comment";
add_buffer = 1;
} else if (s->flags & PFLAG_TOKEN) {
type = "token";
add_buffer = 1;
} else if (s->flags & PFLAG_ATSYM) {
type = "at";
} else if (s->flags & PFLAG_READERMAC) {
int c = s->flags & 0xFF;
type = (c == '\'') ? "quote" :
(c == ',') ? "unquote" :
(c == ';') ? "splice" :
(c == '~') ? "quasiquote" : "<reader>";
} else {
type = "root";
}
if (type) {
janet_table_put(state, janet_ckeywordv("type"),
janet_ckeywordv(type));
}
if (add_buffer) {
buffer = janet_string(buff, bufcount);
janet_table_put(state, janet_ckeywordv("buffer"), janet_wrap_string(buffer));
}
janet_table_put(state, janet_ckeywordv("start"),
janet_wrap_integer(s->start));
return janet_wrap_table(state);
}
struct ParserStateGetter {
const char *name;
Janet(*fn)(const JanetParser *p);
};
static Janet parser_state_delimiters(const JanetParser *_p) {
JanetParser *clone = janet_abstract(&janet_parse_parsertype, sizeof(JanetParser));
janet_parser_clone(_p, clone);
static Janet cfun_parse_state(int32_t argc, Janet *argv) {
size_t i;
const uint8_t *str;
size_t oldcount;
oldcount = clone->bufcount;
for (i = 0; i < clone->statecount; i++) {
JanetParseState *s = clone->states + i;
janet_fixarity(argc, 1);
JanetParser *p = janet_getabstract(argv, 0, &janet_parse_parsertype);
oldcount = p->bufcount;
for (i = 0; i < p->statecount; i++) {
JanetParseState *s = p->states + i;
if (s->flags & PFLAG_PARENS) {
push_buf(clone, '(');
push_buf(p, '(');
} else if (s->flags & PFLAG_SQRBRACKETS) {
push_buf(clone, '[');
push_buf(p, '[');
} else if (s->flags & PFLAG_CURLYBRACKETS) {
push_buf(clone, '{');
push_buf(p, '{');
} else if (s->flags & PFLAG_STRING) {
push_buf(clone, '"');
push_buf(p, '"');
} else if (s->flags & PFLAG_LONGSTRING) {
int32_t i;
for (i = 0; i < s->argn; i++) {
push_buf(clone, '`');
push_buf(p, '`');
}
}
}
str = janet_string(clone->buf + oldcount, (int32_t)(clone->bufcount - oldcount));
clone->bufcount = oldcount;
str = janet_string(p->buf + oldcount, (int32_t)(p->bufcount - oldcount));
p->bufcount = oldcount;
return janet_wrap_string(str);
}
static Janet parser_state_frames(const JanetParser *p) {
int32_t count = (int32_t) p->statecount;
JanetArray *states = janet_array(count);
states->count = count;
uint8_t *buf = p->buf;
Janet *args = p->args;
for (int32_t i = count - 1; i >= 0; --i) {
JanetParseState *s = p->states + i;
states->data[i] = janet_wrap_parse_state(s, args, buf, (uint32_t) p->bufcount);
args -= s->argn;
}
return janet_wrap_array(states);
}
static const struct ParserStateGetter parser_state_getters[] = {
{"frames", parser_state_frames},
{"delimiters", parser_state_delimiters},
{NULL, NULL}
};
static Janet cfun_parse_state(int32_t argc, Janet *argv) {
janet_arity(argc, 1, 2);
const uint8_t *key = NULL;
JanetParser *p = janet_getabstract(argv, 0, &janet_parse_parsertype);
if (argc == 2) {
key = janet_getkeyword(argv, 1);
}
if (key) {
/* Get one result */
for (const struct ParserStateGetter *sg = parser_state_getters;
sg->name != NULL; sg++) {
if (janet_cstrcmp(key, sg->name)) continue;
return sg->fn(p);
}
janet_panicf("unexpected keyword %v", janet_wrap_keyword(key));
return janet_wrap_nil();
} else {
/* Put results in table */
JanetTable *tab = janet_table(0);
for (const struct ParserStateGetter *sg = parser_state_getters;
sg->name != NULL; sg++) {
janet_table_put(tab, janet_ckeywordv(sg->name), sg->fn(p));
}
return janet_wrap_table(tab);
}
}
static Janet cfun_parse_clone(int32_t argc, Janet *argv) {
janet_fixarity(argc, 1);
JanetParser *src = janet_getabstract(argv, 0, &janet_parse_parsertype);
JanetParser *dest = janet_abstract(&janet_parse_parsertype, sizeof(JanetParser));
janet_parser_clone(src, dest);
return janet_wrap_abstract(dest);
}
static const JanetMethod parser_methods[] = {
{"byte", cfun_parse_byte},
{"clone", cfun_parse_clone},
{"consume", cfun_parse_consume},
{"eof", cfun_parse_eof},
{"error", cfun_parse_error},
{"flush", cfun_parse_flush},
{"has-more", cfun_parse_has_more},
@@ -1034,6 +846,7 @@ static const JanetMethod parser_methods[] = {
{"state", cfun_parse_state},
{"status", cfun_parse_status},
{"where", cfun_parse_where},
{"eof", cfun_parse_eof},
{NULL, NULL}
};
@@ -1048,14 +861,7 @@ static const JanetReg parse_cfuns[] = {
"parser/new", cfun_parse_parser,
JDOC("(parser/new)\n\n"
"Creates and returns a new parser object. Parsers are state machines "
"that can receive bytes, and generate a stream of janet values.")
},
{
"parser/clone", cfun_parse_clone,
JDOC("(parser/clone p)\n\n"
"Creates a deep clone of a parser that is identical to the input parser. "
"This cloned parser can be used to continue parsing from a good checkpoint "
"if parsing later fails. Returns a new parser.")
"that can receive bytes, and generate a stream of janet values. ")
},
{
"parser/has-more", cfun_parse_has_more,
@@ -1071,7 +877,7 @@ static const JanetReg parse_cfuns[] = {
},
{
"parser/consume", cfun_parse_consume,
JDOC("(parser/consume parser bytes &opt index)\n\n"
JDOC("(parser/consume parser bytes [, index])\n\n"
"Input bytes into the parser and parse them. Will not throw errors "
"if there is a parse error. Starts at the byte index given by index. Returns "
"the number of bytes read.")
@@ -1107,22 +913,18 @@ static const JanetReg parse_cfuns[] = {
},
{
"parser/state", cfun_parse_state,
JDOC("(parser/state parser &opt key)\n\n"
"Returns a representation of the internal state of the parser. If a key is passed, "
"only that information about the state is returned. Allowed keys are:\n\n"
"\t:delimiters - Each byte in the string represents a nested data structure. For example, "
JDOC("(parser/state parser)\n\n"
"Returns a string representation of the internal state of the parser. "
"Each byte in the string represents a nested data structure. For example, "
"if the parser state is '([\"', then the parser is in the middle of parsing a "
"string inside of square brackets inside parentheses. Can be used to augment a REPL prompt."
"\t:frames - Each table in the array represents a 'frame' in the parser state. Frames "
"contain information about the start of the expression being parsed as well as the "
"type of that expression and some type-specific information.")
"string inside of square brackets inside parentheses. Can be used to augment a REPL prompt.")
},
{
"parser/where", cfun_parse_where,
JDOC("(parser/where parser &opt offset)\n\n"
JDOC("(parser/where parser)\n\n"
"Returns the current line number and column number of the parser's location "
"in the byte stream as an index, counted from 0. "
"If offset is supplied, then the byte offset is updated to that new value.")
"in the byte stream as a tuple (line, column). Lines and columns are counted from "
"1, (the first byte is line 1, column 1) and a newline is considered ASCII 0x0A.")
},
{
"parser/eof", cfun_parse_eof,

View File

@@ -447,7 +447,7 @@ static void builder_cleanup(Builder *b) {
janet_v_free(b->bytecode);
}
JANET_NO_RETURN static void peg_panic(Builder *b, const char *msg) {
static void peg_panic(Builder *b, const char *msg) {
builder_cleanup(b);
janet_panicf("grammar error in %p, %s", b->form, msg);
}
@@ -945,28 +945,27 @@ static uint32_t peg_compile1(Builder *b, Janet peg) {
typedef struct {
uint32_t *bytecode;
Janet *constants;
size_t bytecode_len;
uint32_t num_constants;
} Peg;
static int peg_mark(void *p, size_t size) {
(void) size;
Peg *peg = (Peg *)p;
if (NULL != peg->constants)
for (uint32_t i = 0; i < peg->num_constants; i++)
janet_mark(peg->constants[i]);
for (uint32_t i = 0; i < peg->num_constants; i++)
janet_mark(peg->constants[i]);
return 0;
}
static void peg_marshal(void *p, JanetMarshalContext *ctx) {
Peg *peg = (Peg *)p;
janet_marshal_size(ctx, peg->bytecode_len);
janet_marshal_int(ctx, (int32_t)peg->num_constants);
for (size_t i = 0; i < peg->bytecode_len; i++)
janet_marshal_int(ctx, (int32_t) peg->bytecode[i]);
for (uint32_t j = 0; j < peg->num_constants; j++)
janet_marshal_janet(ctx, peg->constants[j]);
}
static JanetAbstractType peg_type = {
"core/peg",
NULL,
peg_mark,
NULL,
NULL,
NULL,
NULL,
NULL
};
/* Used to ensure that if we place several arrays in one memory chunk, each
* array will be correctly aligned */
@@ -975,169 +974,6 @@ static size_t size_padded(size_t offset, size_t size) {
return x - (x % size);
}
static void peg_unmarshal(void *p, JanetMarshalContext *ctx) {
char *mem = p;
Peg *peg = (Peg *)p;
peg->bytecode_len = janet_unmarshal_size(ctx);
peg->num_constants = (uint32_t) janet_unmarshal_int(ctx);
/* Calculate offsets. Should match those in make_peg */
size_t bytecode_start = size_padded(sizeof(Peg), sizeof(uint32_t));
size_t bytecode_size = peg->bytecode_len * sizeof(uint32_t);
size_t constants_start = size_padded(bytecode_start + bytecode_size, sizeof(Janet));
uint32_t *bytecode = (uint32_t *)(mem + bytecode_start);
Janet *constants = (Janet *)(mem + constants_start);
peg->bytecode = NULL;
peg->constants = NULL;
/* Ensure not too large */
if (constants_start + sizeof(Janet) * peg->num_constants > janet_abstract_size(p)) {
janet_panic("size mismatch");
}
for (size_t i = 0; i < peg->bytecode_len; i++)
bytecode[i] = (uint32_t) janet_unmarshal_int(ctx);
for (uint32_t j = 0; j < peg->num_constants; j++)
constants[j] = janet_unmarshal_janet(ctx);
/* After here, no panics except for the bad: label. */
/* Keep track at each index if an instruction was
* reference (0x01) or is in a main bytecode position
* (0x02). This lets us do a linear scan and not
* need to a depth first traversal. It is stricter
* than a dfs by not allowing certain kinds of unused
* bytecode. */
uint32_t blen = (int32_t) peg->bytecode_len;
uint32_t clen = peg->num_constants;
uint8_t *op_flags = calloc(1, blen);
if (NULL == op_flags) {
JANET_OUT_OF_MEMORY;
}
/* verify peg bytecode */
uint32_t i = 0;
while (i < blen) {
uint32_t instr = bytecode[i];
uint32_t *rule = bytecode + i;
op_flags[i] |= 0x02;
switch (instr & 0x1F) {
case RULE_LITERAL:
i += 2 + ((rule[1] + 3) >> 2);
break;
case RULE_NCHAR:
case RULE_NOTNCHAR:
case RULE_RANGE:
case RULE_POSITION:
/* [1 word] */
i += 2;
break;
case RULE_SET:
/* [8 words] */
i += 9;
break;
case RULE_LOOK:
/* [offset, rule] */
if (rule[2] >= blen) goto bad;
op_flags[rule[2]] |= 0x1;
i += 3;
break;
case RULE_CHOICE:
case RULE_SEQUENCE:
/* [len, rules...] */
{
uint32_t len = rule[1];
for (uint32_t j = 0; j < len; j++) {
if (rule[2 + j] >= blen) goto bad;
op_flags[rule[2 + j]] |= 0x1;
}
i += 2 + len;
}
break;
case RULE_IF:
case RULE_IFNOT:
/* [rule_a, rule_b (b if not a)] */
if (rule[1] >= blen) goto bad;
if (rule[2] >= blen) goto bad;
op_flags[rule[1]] |= 0x01;
op_flags[rule[2]] |= 0x01;
i += 3;
break;
case RULE_BETWEEN:
/* [lo, hi, rule] */
if (rule[3] >= blen) goto bad;
op_flags[rule[3]] |= 0x01;
i += 4;
break;
case RULE_ARGUMENT:
case RULE_GETTAG:
/* [searchtag, tag] */
i += 3;
break;
case RULE_CONSTANT:
/* [constant, tag] */
if (rule[1] >= clen) goto bad;
i += 3;
break;
case RULE_ACCUMULATE:
case RULE_GROUP:
case RULE_CAPTURE:
/* [rule, tag] */
if (rule[1] >= blen) goto bad;
op_flags[rule[1]] |= 0x01;
i += 3;
break;
case RULE_REPLACE:
case RULE_MATCHTIME:
/* [rule, constant, tag] */
if (rule[1] >= blen) goto bad;
if (rule[2] >= clen) goto bad;
op_flags[rule[1]] |= 0x01;
i += 4;
break;
case RULE_ERROR:
case RULE_DROP:
case RULE_NOT:
/* [rule] */
if (rule[1] >= blen) goto bad;
op_flags[rule[1]] |= 0x01;
i += 2;
break;
default:
goto bad;
}
}
/* last instruction cannot overflow */
if (i != blen) goto bad;
/* Make sure all referenced instructions are actually
* in instruction positions. */
for (i = 0; i < blen; i++)
if (op_flags[i] == 0x01) goto bad;
/* Good return */
peg->bytecode = bytecode;
peg->constants = constants;
free(op_flags);
return;
bad:
free(op_flags);
janet_panic("invalid peg bytecode");
}
static const JanetAbstractType peg_type = {
"core/peg",
NULL,
peg_mark,
NULL,
NULL,
peg_marshal,
peg_unmarshal,
NULL
};
/* Convert Builder to Peg (Janet Abstract Value) */
static Peg *make_peg(Builder *b) {
size_t bytecode_start = size_padded(sizeof(Peg), sizeof(uint32_t));
@@ -1152,7 +988,6 @@ static Peg *make_peg(Builder *b) {
peg->num_constants = janet_v_count(b->constants);
memcpy(peg->bytecode, b->bytecode, bytecode_size);
memcpy(peg->constants, b->constants, constants_size);
peg->bytecode_len = janet_v_count(b->bytecode);
return peg;
}
@@ -1226,7 +1061,7 @@ static const JanetReg peg_cfuns[] = {
},
{
"peg/match", cfun_peg_match,
JDOC("(peg/match peg text &opt start & args)\n\n"
JDOC("(peg/match peg text [,start=0])\n\n"
"Match a Parsing Expression Grammar to a byte string and return an array of captured values. "
"Returns nil if text does not match the language defined by peg. The syntax of PEGs are very "
"similar to those defined by LPeg, and have similar capabilities.")
@@ -1237,7 +1072,6 @@ static const JanetReg peg_cfuns[] = {
/* Load the peg module */
void janet_lib_peg(JanetTable *env) {
janet_core_cfuns(env, NULL, peg_cfuns);
janet_register_abstract_type(&peg_type);
}
#endif /* ifdef JANET_PEG */

View File

@@ -28,7 +28,6 @@
/* Run a string */
int janet_dobytes(JanetTable *env, const uint8_t *bytes, int32_t len, const char *sourcePath, Janet *out) {
JanetParser parser;
FILE *errf = janet_dynfile("err", stderr);
int errflags = 0, done = 0;
int32_t index = 0;
Janet ret = janet_wrap_nil();
@@ -56,7 +55,7 @@ int janet_dobytes(JanetTable *env, const uint8_t *bytes, int32_t len, const char
done = 1;
}
} else {
fprintf(errf, "compile error in %s: %s\n", sourcePath,
fprintf(stderr, "compile error in %s: %s\n", sourcePath,
(const char *)cres.error);
errflags |= 0x02;
done = 1;
@@ -70,7 +69,7 @@ int janet_dobytes(JanetTable *env, const uint8_t *bytes, int32_t len, const char
break;
case JANET_PARSE_ERROR:
errflags |= 0x04;
fprintf(errf, "parse error in %s: %s\n",
fprintf(stderr, "parse error in %s: %s\n",
sourcePath, janet_parser_error(&parser));
done = 1;
break;

View File

@@ -116,7 +116,7 @@ static JanetSlot janetc_unquote(JanetFopts opts, int32_t argn, const Janet *argv
return janetc_cslot(janet_wrap_nil());
}
/* Perform destructuring. Be careful to
/* Preform destructuring. Be careful to
* keep the order registers are freed.
* Returns if the slot 'right' can be freed. */
static int destructure(JanetCompiler *c,
@@ -278,17 +278,18 @@ static int varleaf(
JanetCompiler *c,
const uint8_t *sym,
JanetSlot s,
JanetTable *reftab) {
JanetTable *attr) {
if (c->scope->flags & JANET_SCOPE_TOP) {
/* Global var, generate var */
JanetSlot refslot;
JanetTable *entry = janet_table_clone(reftab);
JanetTable *reftab = janet_table(1);
reftab->proto = attr;
JanetArray *ref = janet_array(1);
janet_array_push(ref, janet_wrap_nil());
janet_table_put(entry, janet_ckeywordv("ref"), janet_wrap_array(ref));
janet_table_put(entry, janet_ckeywordv("source-map"),
janet_table_put(reftab, janet_ckeywordv("ref"), janet_wrap_array(ref));
janet_table_put(reftab, janet_ckeywordv("source-map"),
janet_wrap_tuple(janetc_make_sourcemap(c)));
janet_table_put(c->env, janet_wrap_symbol(sym), janet_wrap_table(entry));
janet_table_put(c->env, janet_wrap_symbol(sym), janet_wrap_table(reftab));
refslot = janetc_cslot(janet_wrap_array(ref));
janetc_emit_ssu(c, JOP_PUT_INDEX, refslot, s, 0, 0);
return 1;
@@ -311,16 +312,17 @@ static int defleaf(
JanetCompiler *c,
const uint8_t *sym,
JanetSlot s,
JanetTable *tab) {
JanetTable *attr) {
if (c->scope->flags & JANET_SCOPE_TOP) {
JanetTable *entry = janet_table_clone(tab);
janet_table_put(entry, janet_ckeywordv("source-map"),
JanetTable *tab = janet_table(2);
janet_table_put(tab, janet_ckeywordv("source-map"),
janet_wrap_tuple(janetc_make_sourcemap(c)));
tab->proto = attr;
JanetSlot valsym = janetc_cslot(janet_ckeywordv("value"));
JanetSlot tabslot = janetc_cslot(janet_wrap_table(entry));
JanetSlot tabslot = janetc_cslot(janet_wrap_table(tab));
/* Add env entry to env */
janet_table_put(c->env, janet_wrap_symbol(sym), janet_wrap_table(entry));
janet_table_put(c->env, janet_wrap_symbol(sym), janet_wrap_table(tab));
/* Put value in table when evaulated */
janetc_emit_sss(c, JOP_PUT, tabslot, valsym, s, 0);
@@ -677,9 +679,6 @@ static JanetSlot janetc_fn(JanetFopts opts, int32_t argn, const Janet *argv) {
goto error;
}
/* Keep track of destructured parameters */
JanetSlot *destructed_params = NULL;
/* Compile function parameters */
params = janet_unwrap_tuple(argv[parami]);
paramcount = janet_tuple_length(params);
@@ -731,22 +730,10 @@ static JanetSlot janetc_fn(JanetFopts opts, int32_t argn, const Janet *argv) {
janetc_nameslot(c, janet_unwrap_symbol(param), janetc_farslot(c));
}
} else {
janet_v_push(destructed_params, janetc_farslot(c));
destructure(c, param, janetc_farslot(c), defleaf, NULL);
}
}
/* Compile destructed params */
int32_t j = 0;
for (i = 0; i < paramcount; i++) {
Janet param = params[i];
if (!janet_checktype(param, JANET_SYMBOL)) {
JanetSlot reg = destructed_params[j++];
destructure(c, param, reg, defleaf, NULL);
janetc_freeslot(c, reg);
}
}
janet_v_free(destructed_params);
max_arity = (vararg || allow_extra) ? INT32_MAX : arity;
if (!seenopt) min_arity = arity;

View File

@@ -65,9 +65,4 @@ extern JANET_THREAD_LOCAL Janet *janet_vm_roots;
extern JANET_THREAD_LOCAL uint32_t janet_vm_root_count;
extern JANET_THREAD_LOCAL uint32_t janet_vm_root_capacity;
/* Scratch memory */
extern JANET_THREAD_LOCAL void **janet_scratch_mem;
extern JANET_THREAD_LOCAL size_t janet_scratch_cap;
extern JANET_THREAD_LOCAL size_t janet_scratch_len;
#endif /* JANET_STATE_H_defined */

View File

@@ -393,20 +393,25 @@ static Janet cfun_string_split(int32_t argc, Janet *argv) {
static Janet cfun_string_checkset(int32_t argc, Janet *argv) {
uint32_t bitset[8] = {0, 0, 0, 0, 0, 0, 0, 0};
janet_fixarity(argc, 2);
janet_arity(argc, 2, 3);
JanetByteView set = janet_getbytes(argv, 0);
JanetByteView str = janet_getbytes(argv, 1);
/* Populate set */
for (int32_t i = 0; i < set.len; i++) {
int index = set.bytes[i] >> 5;
uint32_t mask = 1 << (set.bytes[i] & 0x1F);
uint32_t mask = 1 << (set.bytes[i] & 7);
bitset[index] |= mask;
}
if (argc == 3) {
if (janet_getboolean(argv, 2)) {
for (int i = 0; i < 8; i++)
bitset[i] = ~bitset[i];
}
}
/* Check set */
if (str.len == 0) return janet_wrap_false();
for (int32_t i = 0; i < str.len; i++) {
int index = str.bytes[i] >> 5;
uint32_t mask = 1 << (str.bytes[i] & 0x1F);
uint32_t mask = 1 << (str.bytes[i] & 7);
if (!(bitset[index] & mask)) {
return janet_wrap_false();
}
@@ -519,7 +524,7 @@ static Janet cfun_string_trimr(int32_t argc, Janet *argv) {
static const JanetReg string_cfuns[] = {
{
"string/slice", cfun_string_slice,
JDOC("(string/slice bytes &opt start end)\n\n"
JDOC("(string/slice bytes [,start=0 [,end=(length str)]])\n\n"
"Returns a substring from a byte sequence. The substring is from "
"index start inclusive to index end exclusive. All indexing "
"is from 0. 'start' and 'end' can also be negative to indicate indexing "
@@ -537,7 +542,7 @@ static const JanetReg string_cfuns[] = {
},
{
"string/from-bytes", cfun_string_frombytes,
JDOC("(string/from-bytes & byte-vals)\n\n"
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.")
},
@@ -613,7 +618,7 @@ static const JanetReg string_cfuns[] = {
},
{
"string/join", cfun_string_join,
JDOC("(string/join parts &opt sep)\n\n"
JDOC("(string/join parts [,sep])\n\n"
"Joins an array of strings into one string, optionally separated by "
"a separator string sep.")
},
@@ -625,19 +630,19 @@ static const JanetReg string_cfuns[] = {
},
{
"string/trim", cfun_string_trim,
JDOC("(string/trim str &opt set)\n\n"
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 &opt set)\n\n"
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 &opt set)\n\n"
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.")
},

View File

@@ -27,32 +27,14 @@
#include <math.h>
#endif
#define JANET_TABLE_FLAG_STACK 0x10000
static void *janet_memalloc_empty_local(int32_t count) {
int32_t i;
void *mem = janet_smalloc(count * sizeof(JanetKV));
JanetKV *mmem = (JanetKV *)mem;
for (i = 0; i < count; i++) {
JanetKV *kv = mmem + i;
kv->key = janet_wrap_nil();
kv->value = janet_wrap_nil();
}
return mem;
}
static JanetTable *janet_table_init_impl(JanetTable *table, int32_t capacity, int stackalloc) {
/* Initialize a table */
JanetTable *janet_table_init(JanetTable *table, int32_t capacity) {
JanetKV *data;
capacity = janet_tablen(capacity);
if (stackalloc) table->gc.flags = JANET_TABLE_FLAG_STACK;
if (capacity) {
if (stackalloc) {
data = janet_memalloc_empty_local(capacity);
} else {
data = (JanetKV *) janet_memalloc_empty(capacity);
if (NULL == data) {
JANET_OUT_OF_MEMORY;
}
data = (JanetKV *) janet_memalloc_empty(capacity);
if (NULL == data) {
JANET_OUT_OF_MEMORY;
}
table->data = data;
table->capacity = capacity;
@@ -66,20 +48,15 @@ static JanetTable *janet_table_init_impl(JanetTable *table, int32_t capacity, in
return table;
}
/* Initialize a table */
JanetTable *janet_table_init(JanetTable *table, int32_t capacity) {
return janet_table_init_impl(table, capacity, 1);
}
/* Deinitialize a table */
void janet_table_deinit(JanetTable *table) {
janet_sfree(table->data);
free(table->data);
}
/* Create a new table */
JanetTable *janet_table(int32_t capacity) {
JanetTable *table = janet_gcalloc(JANET_MEMORY_TABLE, sizeof(JanetTable));
return janet_table_init_impl(table, capacity, 0);
return janet_table_init(table, capacity);
}
/* Find the bucket that contains the given key. Will also return
@@ -91,15 +68,9 @@ JanetKV *janet_table_find(JanetTable *t, Janet key) {
/* Resize the dictionary table. */
static void janet_table_rehash(JanetTable *t, int32_t size) {
JanetKV *olddata = t->data;
JanetKV *newdata;
int islocal = t->gc.flags & JANET_TABLE_FLAG_STACK;
if (islocal) {
newdata = (JanetKV *) janet_memalloc_empty_local(size);
} else {
newdata = (JanetKV *) janet_memalloc_empty(size);
if (NULL == newdata) {
JANET_OUT_OF_MEMORY;
}
JanetKV *newdata = (JanetKV *) janet_memalloc_empty(size);
if (NULL == newdata) {
JANET_OUT_OF_MEMORY;
}
int32_t i, oldcapacity;
oldcapacity = t->capacity;
@@ -113,11 +84,7 @@ static void janet_table_rehash(JanetTable *t, int32_t size) {
*newkv = *kv;
}
}
if (islocal) {
janet_sfree(olddata);
} else {
free(olddata);
}
free(olddata);
}
/* Get a value out of the table */
@@ -208,18 +175,6 @@ const JanetKV *janet_table_to_struct(JanetTable *t) {
return janet_struct_end(st);
}
/* Clone a table. */
JanetTable *janet_table_clone(JanetTable *table) {
JanetTable *newTable = janet_gcalloc(JANET_MEMORY_TABLE, sizeof(JanetTable));
memcpy(newTable, table, sizeof(JanetTable));
newTable->data = malloc(newTable->capacity * sizeof(JanetKV));
if (NULL == newTable->data) {
JANET_OUT_OF_MEMORY;
}
memcpy(newTable->data, table->data, table->capacity * sizeof(JanetKV));
return newTable;
}
/* Merge a table or struct into a table */
static void janet_table_mergekv(JanetTable *table, const JanetKV *kvs, int32_t cap) {
int32_t i;
@@ -280,12 +235,6 @@ static Janet cfun_table_rawget(int32_t argc, Janet *argv) {
return janet_table_rawget(table, argv[1]);
}
static Janet cfun_table_clone(int32_t argc, Janet *argv) {
janet_fixarity(argc, 1);
JanetTable *table = janet_gettable(argv, 0);
return janet_wrap_table(janet_table_clone(table));
}
static const JanetReg table_cfuns[] = {
{
"table/new", cfun_table_new,
@@ -319,12 +268,6 @@ static const JanetReg table_cfuns[] = {
"If a table tab does not contain t directly, the function will return "
"nil without checking the prototype. Returns the value in the table.")
},
{
"table/clone", cfun_table_clone,
JDOC("(table/clone tab)\n\n"
"Create a copy of a table. Updates to the new table will not change the old table, "
"and vice versa.")
},
{NULL, NULL, NULL}
};

View File

@@ -508,41 +508,41 @@ static Janet cfun_typed_array_swap_bytes(int32_t argc, Janet *argv) {
static const JanetReg ta_cfuns[] = {
{
"tarray/new", cfun_typed_array_new,
JDOC("(tarray/new type size &opt stride offset tarray|buffer)\n\n"
JDOC("(tarray/new type size [stride = 1 [offset = 0 [tarray | buffer]]] )\n\n"
"Create new typed array.")
},
{
"tarray/buffer", cfun_typed_array_buffer,
JDOC("(tarray/buffer array|size)\n\n"
JDOC("(tarray/buffer (array | size) )\n\n"
"Return typed array buffer or create a new buffer.")
},
{
"tarray/length", cfun_typed_array_size,
JDOC("(tarray/length array|buffer)\n\n"
JDOC("(tarray/length (array | buffer) )\n\n"
"Return typed array or buffer size.")
},
{
"tarray/properties", cfun_typed_array_properties,
JDOC("(tarray/properties array)\n\n"
JDOC("(tarray/properties array )\n\n"
"Return typed array properties as a struct.")
},
{
"tarray/copy-bytes", cfun_typed_array_copy_bytes,
JDOC("(tarray/copy-bytes src sindex dst dindex &opt count)\n\n"
"Copy count elements (default 1) of src array from index sindex "
JDOC("(tarray/copy-bytes src sindex dst dindex [count=1])\n\n"
"Copy count elements of src array from index sindex "
"to dst array at position dindex "
"memory can overlap.")
},
{
"tarray/swap-bytes", cfun_typed_array_swap_bytes,
JDOC("(tarray/swap-bytes src sindex dst dindex &opt count)\n\n"
"Swap count elements (default 1) between src array from index sindex "
JDOC("(tarray/swap-bytes src sindex dst dindex [count=1])\n\n"
"Swap count elements between src array from index sindex "
"and dst array at position dindex "
"memory can overlap.")
},
{
"tarray/slice", cfun_typed_array_slice,
JDOC("(tarray/slice tarr &opt start end)\n\n"
JDOC("(tarray/slice tarr [, start=0 [, end=(size tarr)]])\n\n"
"Takes a slice of a typed array from start to end. The range is half "
"open, [start, end). Indexes can also be negative, indicating indexing "
"from the end of the end of the typed array. By default, start is 0 and end is "

View File

@@ -23,9 +23,6 @@
#ifndef JANET_UTIL_H_defined
#define JANET_UTIL_H_defined
#include <stdio.h>
#include <errno.h>
#ifndef JANET_AMALG
#include <janet.h>
#endif

View File

@@ -151,6 +151,7 @@ Janet janet_get(Janet ds, Janet key) {
switch (janet_type(ds)) {
default:
janet_panicf("expected %T, got %v", JANET_TFLAG_LENGTHABLE, ds);
value = janet_wrap_nil();
break;
case JANET_STRUCT:
value = janet_struct_get(janet_unwrap_struct(ds), key);
@@ -218,6 +219,7 @@ Janet janet_get(Janet ds, Janet key) {
value = (type->get)(janet_unwrap_abstract(ds), key);
} else {
janet_panicf("no getter for %v ", ds);
value = janet_wrap_nil();
}
break;
}
@@ -231,6 +233,7 @@ Janet janet_getindex(Janet ds, int32_t index) {
switch (janet_type(ds)) {
default:
janet_panicf("expected %T, got %v", JANET_TFLAG_LENGTHABLE, ds);
value = janet_wrap_nil();
break;
case JANET_STRING:
case JANET_SYMBOL:
@@ -274,6 +277,7 @@ Janet janet_getindex(Janet ds, int32_t index) {
value = (type->get)(janet_unwrap_abstract(ds), janet_wrap_integer(index));
} else {
janet_panicf("no getter for %v ", ds);
value = janet_wrap_nil();
}
break;
}
@@ -285,6 +289,7 @@ int32_t janet_length(Janet x) {
switch (janet_type(x)) {
default:
janet_panicf("expected %T, got %v", JANET_TFLAG_LENGTHABLE, x);
return 0;
case JANET_STRING:
case JANET_SYMBOL:
case JANET_KEYWORD:
@@ -307,6 +312,7 @@ void janet_putindex(Janet ds, int32_t index, Janet value) {
default:
janet_panicf("expected %T, got %v",
JANET_TFLAG_ARRAY | JANET_TFLAG_BUFFER | JANET_TFLAG_TABLE, ds);
break;
case JANET_ARRAY: {
JanetArray *array = janet_unwrap_array(ds);
if (index >= array->count) {
@@ -349,6 +355,7 @@ void janet_put(Janet ds, Janet key, Janet value) {
default:
janet_panicf("expected %T, got %v",
JANET_TFLAG_ARRAY | JANET_TFLAG_BUFFER | JANET_TFLAG_TABLE, ds);
break;
case JANET_ARRAY: {
int32_t index;
JanetArray *array = janet_unwrap_array(ds);

View File

@@ -30,10 +30,17 @@ void *janet_v_grow(void *v, int32_t increment, int32_t itemsize) {
int32_t dbl_cur = (NULL != v) ? 2 * janet_v__cap(v) : 0;
int32_t min_needed = janet_v_count(v) + increment;
int32_t m = dbl_cur > min_needed ? dbl_cur : min_needed;
int32_t *p = (int32_t *) janet_srealloc(v ? janet_v__raw(v) : 0, itemsize * m + sizeof(int32_t) * 2);
if (!v) p[1] = 0;
p[0] = m;
return p + 2;
int32_t *p = (int32_t *) realloc(v ? janet_v__raw(v) : 0, itemsize * m + sizeof(int32_t) * 2);
if (NULL != p) {
if (!v) p[1] = 0;
p[0] = m;
return p + 2;
} else {
{
JANET_OUT_OF_MEMORY;
}
return (void *)(2 * sizeof(int32_t));
}
}
/* Convert a buffer to normal allocated memory (forget capacity) */

View File

@@ -33,15 +33,16 @@
*/
/* This is mainly used code such as the assembler or compiler, which
* need vector like data structures that are only garbage collected in case
* of an error, and normally rely on malloc/free. */
* need vector like data structures that are not garbage collected
* and used only from C */
#define janet_v_free(v) (((v) != NULL) ? (janet_sfree(janet_v__raw(v)), 0) : 0)
#define janet_v_free(v) (((v) != NULL) ? (free(janet_v__raw(v)), 0) : 0)
#define janet_v_push(v, x) (janet_v__maybegrow(v, 1), (v)[janet_v__cnt(v)++] = (x))
#define janet_v_pop(v) (janet_v_count(v) ? janet_v__cnt(v)-- : 0)
#define janet_v_count(v) (((v) != NULL) ? janet_v__cnt(v) : 0)
#define janet_v_last(v) ((v)[janet_v__cnt(v) - 1])
#define janet_v_empty(v) (((v) != NULL) ? (janet_v__cnt(v) = 0) : 0)
#define janet_v_copy(v) (janet_v_copymem((v), sizeof(*(v))))
#define janet_v_flatten(v) (janet_v_flattenmem((v), sizeof(*(v))))
#define janet_v__raw(v) ((int32_t *)(v) - 2)
@@ -54,6 +55,7 @@
/* Actual functions defined in vector.c */
void *janet_v_grow(void *v, int32_t increment, int32_t itemsize);
void *janet_v_copymem(void *v, int32_t itemsize);
void *janet_v_flattenmem(void *v, int32_t itemsize);
#endif

View File

@@ -245,7 +245,6 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in, JanetFiberStatus status)
&&label_JOP_TAILCALL,
&&label_JOP_RESUME,
&&label_JOP_SIGNAL,
&&label_JOP_PROPAGATE,
&&label_JOP_GET,
&&label_JOP_PUT,
&&label_JOP_GET_INDEX,
@@ -278,9 +277,7 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in, JanetFiberStatus status)
* DO NOT use input when resuming a fiber that has been interrupted at a
* breakpoint. */
if (status != JANET_STATUS_NEW &&
((*pc & 0xFF) == JOP_SIGNAL ||
(*pc & 0xFF) == JOP_PROPAGATE ||
(*pc & 0xFF) == JOP_RESUME)) {
((*pc & 0xFF) == JOP_SIGNAL || (*pc & 0xFF) == JOP_RESUME)) {
stack[A] = in;
pc++;
}
@@ -676,18 +673,6 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in, JanetFiberStatus status)
vm_return(s, stack[B]);
}
VM_OP(JOP_PROPAGATE) {
Janet fv = stack[C];
vm_assert_type(fv, JANET_FIBER);
JanetFiber *f = janet_unwrap_fiber(fv);
JanetFiberStatus status = janet_fiber_status(f);
if (status > JANET_STATUS_USER9) {
vm_throw("cannot propagate from new or alive fiber");
}
janet_vm_fiber->child = f;
vm_return((int) status, stack[B]);
}
VM_OP(JOP_PUT)
vm_commit();
janet_put(stack[A], stack[B], stack[C]);
@@ -921,10 +906,6 @@ int janet_init(void) {
janet_vm_roots = NULL;
janet_vm_root_count = 0;
janet_vm_root_capacity = 0;
/* Scratch memory */
janet_scratch_mem = NULL;
janet_scratch_len = 0;
janet_scratch_cap = 0;
/* Initialize registry */
janet_vm_registry = janet_table(0);
janet_gcroot(janet_wrap_table(janet_vm_registry));

View File

@@ -152,15 +152,6 @@ extern "C" {
#endif
#endif
/* Tell complier some functions don't return */
#ifndef JANET_NO_RETURN
#ifdef JANET_WINDOWS
#define JANET_NO_RETURN __declspec(noreturn)
#else
#define JANET_NO_RETURN __attribute__ ((noreturn))
#endif
#endif
/* Prevent some recursive functions from recursing too deeply
* ands crashing (the parser). Instead, error out. */
#define JANET_RECURSION_GUARD 1024
@@ -193,38 +184,6 @@ extern "C" {
#endif
#endif
/* Runtime config constants */
#ifdef JANET_NO_NANBOX
#define JANET_NANBOX_BIT 0
#else
#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 *****/
@@ -238,9 +197,9 @@ typedef struct {
#include <stdio.h>
/* Names of all of the types */
JANET_API const char *const janet_type_names[16];
JANET_API const char *const janet_signal_names[14];
JANET_API const char *const janet_status_names[16];
extern const char *const janet_type_names[16];
extern const char *const janet_signal_names[14];
extern const char *const janet_status_names[16];
/* Fiber signals */
typedef enum {
@@ -1014,7 +973,6 @@ enum JanetOpCode {
JOP_TAILCALL,
JOP_RESUME,
JOP_SIGNAL,
JOP_PROPAGATE,
JOP_GET,
JOP_PUT,
JOP_GET_INDEX,
@@ -1106,6 +1064,8 @@ JANET_API void janet_debug_find(
/* Array functions */
JANET_API JanetArray *janet_array(int32_t capacity);
JANET_API JanetArray *janet_array_n(const Janet *elements, int32_t n);
JANET_API JanetArray *janet_array_init(JanetArray *array, int32_t capacity);
JANET_API void janet_array_deinit(JanetArray *array);
JANET_API void janet_array_ensure(JanetArray *array, int32_t capacity, int32_t growth);
JANET_API void janet_array_setcount(JanetArray *array, int32_t count);
JANET_API void janet_array_push(JanetArray *array, Janet x);
@@ -1202,7 +1162,6 @@ JANET_API const JanetKV *janet_table_to_struct(JanetTable *t);
JANET_API void janet_table_merge_table(JanetTable *table, JanetTable *other);
JANET_API void janet_table_merge_struct(JanetTable *table, const JanetKV *other);
JANET_API JanetKV *janet_table_find(JanetTable *t, Janet key);
JANET_API JanetTable *janet_table_clone(JanetTable *table);
/* Fiber */
JANET_API JanetFiber *janet_fiber(JanetFunction *callee, int32_t capacity, int32_t argc, const Janet *argv);
@@ -1221,13 +1180,10 @@ JANET_API const JanetKV *janet_dictionary_next(const JanetKV *kvs, int32_t cap,
#define janet_abstract_head(u) ((JanetAbstractHead *)((char *)u - offsetof(JanetAbstractHead, data)))
#define janet_abstract_type(u) (janet_abstract_head(u)->type)
#define janet_abstract_size(u) (janet_abstract_head(u)->size)
JANET_API void *janet_abstract_begin(const JanetAbstractType *type, size_t size);
JANET_API void *janet_abstract_end(void *);
JANET_API void *janet_abstract(const JanetAbstractType *type, size_t size); /* begin and end in one call */
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 */
@@ -1274,8 +1230,6 @@ JANET_API Janet janet_getindex(Janet ds, int32_t index);
JANET_API int32_t janet_length(Janet x);
JANET_API void janet_put(Janet ds, Janet key, Janet value);
JANET_API void janet_putindex(Janet ds, int32_t index, Janet value);
JANET_API uint64_t janet_getflags(const Janet *argv, int32_t n, const char *flags);
#define janet_flag_at(F, I) ((F) & ((1ULL) << (I)))
/* VM functions */
JANET_API int janet_init(void);
@@ -1285,11 +1239,6 @@ JANET_API JanetSignal janet_pcall(JanetFunction *fun, int32_t argn, const Janet
JANET_API Janet janet_call(JanetFunction *fun, int32_t argc, const Janet *argv);
JANET_API void janet_stacktrace(JanetFiber *fiber, Janet err);
/* Scratch Memory API */
JANET_API void *janet_smalloc(size_t size);
JANET_API void *janet_srealloc(void *mem, size_t size);
JANET_API void janet_sfree(void *mem);
/* C Library helpers */
typedef enum {
JANET_BINDING_NONE,
@@ -1305,19 +1254,14 @@ JANET_API void janet_register(const char *name, JanetCFunction cfun);
/* New C API */
#define JANET_MODULE_ENTRY \
JANET_API JanetBuildConfig _janet_mod_config(void) { \
return janet_config_current(); \
} \
JANET_API void _janet_init
JANET_NO_RETURN JANET_API void janet_panicv(Janet message);
JANET_NO_RETURN JANET_API void janet_panic(const char *message);
JANET_NO_RETURN JANET_API void janet_panics(const uint8_t *message);
JANET_NO_RETURN JANET_API void janet_panicf(const char *format, ...);
#define JANET_MODULE_ENTRY 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);
JANET_API void janet_panicf(const char *format, ...);
JANET_API void janet_printf(const char *format, ...);
JANET_NO_RETURN JANET_API void janet_panic_type(Janet x, int32_t n, int expected);
JANET_NO_RETURN JANET_API void janet_panic_abstract(Janet x, int32_t n, const JanetAbstractType *at);
JANET_API void janet_panic_type(Janet x, int32_t n, int expected);
JANET_API void janet_panic_abstract(Janet x, int32_t n, const JanetAbstractType *at);
JANET_API void janet_arity(int32_t arity, int32_t min, int32_t max);
JANET_API void janet_fixarity(int32_t arity, int32_t fix);

View File

@@ -20,17 +20,12 @@
* IN THE SOFTWARE.
*/
/* This is an example janetconf.h file. This will be usually generated
* by the build system. */
/* Configure Janet. Edit this file to customize the build */
#ifndef JANETCONF_H
#define JANETCONF_H
#define JANET_VERSION_MAJOR 1
#define JANET_VERSION_MINOR 1
#define JANET_VERSION_PATCH 0
#define JANET_VERSION_EXTRA "-dev"
#define JANET_VERSION "1.1.0-dev"
#define JANET_VERSION "0.6.0"
/* #define JANET_BUILD "local" */
@@ -40,17 +35,11 @@
/* #define JANET_NO_NANBOX */
/* #define JANET_API __attribute__((visibility ("default"))) */
/* These settings should be specified before amalgamation is
* built. */
/* #define JANET_NO_DOCSTRINGS */
/* #define JANET_NO_SOURCEMAPS */
/* #define JANET_REDUCED_OS */
/* Other settings */
/* #define JANET_NO_ASSEMBLER */
/* #define JANET_NO_PEG */
/* #define JANET_NO_TYPED_ARRAY */
/* #define JANET_NO_INT_TYPES */
/* #define JANET_REDUCED_OS */
/* #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 */

View File

@@ -11,8 +11,8 @@
(var *colorize* true)
(var *compile-only* false)
(if-let [jp (os/getenv "JANET_PATH")] (setdyn :syspath jp))
(if-let [jp (os/getenv "JANET_HEADERPATH")] (setdyn :headerpath jp))
(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
@@ -42,9 +42,9 @@
"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 &] (setdyn :syspath (get process/args (+ i 1))) 2)
"m" (fn [i &] (set module/*syspath* (get process/args (+ i 1))) 2)
"c" (fn [i &]
(def e (dofile (get process/args (+ i 1))))
(def e (require (get process/args (+ i 1))))
(spit (get process/args (+ i 2)) (make-image e))
(set *no-file* false)
3)
@@ -71,7 +71,7 @@
(+= i (dohandler (string/slice arg 1 2) i))
(do
(set *no-file* false)
(dofile arg :prefix "" :exit *exit-on-error* :compile-only *compile-only*)
(import* arg :prefix "" :exit *exit-on-error* :compile-only *compile-only*)
(set i lenargs))))
(when (and (not *compile-only*) (or *should-repl* *no-file*))
@@ -80,7 +80,7 @@
(defn noprompt [_] "")
(defn getprompt [p]
(def offset (parser/where p))
(string "janet:" offset ":" (parser/state p :delimiters) "> "))
(string "janet:" offset ":" (parser/state p) "> "))
(def prompter (if *quiet* noprompt getprompt))
(defn getstdin [prompt buf]
(file/write stdout prompt)

View File

@@ -32,12 +32,11 @@ Janet janet_line_getter(int32_t argc, Janet *argv) {
}
static void simpleline(JanetBuffer *buffer) {
FILE *in = janet_dynfile("in", stdin);
buffer->count = 0;
int c;
for (;;) {
c = fgetc(in);
if (feof(in) || c < 0) {
c = fgetc(stdin);
if (feof(stdin) || c < 0) {
break;
}
janet_buffer_push_u8(buffer, (uint8_t) c);
@@ -57,9 +56,7 @@ void janet_line_deinit() {
}
void janet_line_get(const char *p, JanetBuffer *buffer) {
FILE *out = janet_dynfile("out", stdout);
fputs(p, out);
fflush(out);
fputs(p, stdout);
simpleline(buffer);
}
@@ -453,7 +450,6 @@ void janet_line_get(const char *p, JanetBuffer *buffer) {
prompt = p;
buffer->count = 0;
historyi = 0;
FILE *out = janet_dynfile("out", stdout);
if (!isatty(STDIN_FILENO) || !checktermsupport()) {
simpleline(buffer);
return;
@@ -467,12 +463,12 @@ void janet_line_get(const char *p, JanetBuffer *buffer) {
if (sigint_flag) {
raise(SIGINT);
} else {
fputc('\n', out);
fputc('\n', stdout);
}
return;
}
norawmode();
fputc('\n', out);
fputc('\n', stdout);
janet_buffer_ensure(buffer, len + 1, 2);
memcpy(buffer->data, buf, len);
buffer->data[len] = '\n';

View File

@@ -38,14 +38,13 @@ int main(int argc, char **argv) {
JanetArray *args;
JanetTable *env;
/* Enable color console on windows 10 console and utf8 output. */
/* 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);
SetConsoleOutputCP(65001);
#endif
/* Set up VM */

View File

@@ -6,7 +6,7 @@
(setdyn :pretty-format "%.20P")
(repl (fn get-line [buf p]
(def offset (parser/where p))
(def prompt (string "janet:" offset ":" (parser/state p :delimiters) "> "))
(def prompt (string "janet:" offset ":" (parser/state p) "> "))
(repl-yield prompt buf)
(yield)
buf))))

View File

@@ -18,7 +18,7 @@
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
(import ./helper :prefix "" :exit true)
(import test/helper :prefix "" :exit true)
(start-suite 0)
(assert (= 10 (+ 1 2 3 4)) "addition")
@@ -303,16 +303,5 @@
# Regression Test
(assert (= 1 (((compile '(fn [] 1) @{})))) "regression test")
# Regression Test #137
(def [a b c] (range 10))
(assert (= a 0) "regression #137 (1)")
(assert (= b 1) "regression #137 (2)")
(assert (= c 2) "regression #137 (3)")
(var [x y z] (range 10))
(assert (= x 0) "regression #137 (4)")
(assert (= y 1) "regression #137 (5)")
(assert (= z 2) "regression #137 (6)")
(end-suite)

View File

@@ -18,7 +18,7 @@
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
(import ./helper :prefix "" :exit true)
(import test/helper :prefix "" :exit true)
(start-suite 1)
(assert (= 400 (math/sqrt 160000)) "sqrt(160000)=400")

View File

@@ -18,7 +18,7 @@
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
(import ./helper :prefix "" :exit true)
(import test/helper :prefix "" :exit true)
(start-suite 2)
# Buffer stuff

View File

@@ -18,7 +18,7 @@
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
(import ./helper :prefix "" :exit true)
(import test/helper :prefix "" :exit true)
(start-suite 3)
(assert (= (length (range 10)) 10) "(range 10)")

View File

@@ -18,7 +18,7 @@
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
(import ./helper :prefix "" :exit true)
(import test/helper :prefix "" :exit true)
(start-suite 4)
# some tests for string/format and buffer/format

View File

@@ -18,7 +18,7 @@
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
(import ./helper :prefix "" :exit true)
(import test/helper :prefix "" :exit true)
(start-suite 5)
# some tests typed array

View File

@@ -18,7 +18,7 @@
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
(import ./helper :prefix "" :exit true)
(import test/helper :prefix "" :exit true)
(start-suite 6)
# some tests for bigint
@@ -109,57 +109,4 @@
(comment 1 2 3)
(comment 1 2 3 4)
# Parser clone
(def p (parser/new))
(assert (= 7 (parser/consume p "(1 2 3 ")) "parser 1")
(def p2 (parser/clone p))
(parser/consume p2 ") 1 ")
(parser/consume p ") 1 ")
(assert (deep= (parser/status p) (parser/status p2)) "parser 2")
(assert (deep= (parser/state p) (parser/state p2)) "parser 3")
# String check-set
(assert (string/check-set "abc" "a") "string/check-set 1")
(assert (not (string/check-set "abc" "z")) "string/check-set 2")
(assert (string/check-set "abc" "abc") "string/check-set 3")
(assert (not (string/check-set "abc" "")) "string/check-set 4")
(assert (not (string/check-set "" "aabc")) "string/check-set 5")
# Marshal and unmarshal pegs
(def p (-> "abcd" peg/compile marshal unmarshal))
(assert (peg/match p "abcd") "peg marshal 1")
(assert (peg/match p "abcdefg") "peg marshal 2")
(assert (not (peg/match p "zabcdefg")) "peg marshal 3")
# This should be valgrind clean.
(var pegi 3)
(defn marshpeg [p]
(assert (-> p peg/compile marshal unmarshal) (string "peg marshal " (++ pegi))))
(marshpeg '(* 1 2 (set "abcd") "asdasd" (+ "." 3)))
(marshpeg '(% (* (+ 1 2 3) (* "drop" "bear") '"hi")))
(marshpeg '(> 123 "abcd"))
(marshpeg '{:main (* 1 "hello" :main)})
(marshpeg '(range "AZ"))
(marshpeg '(if-not "abcdf" 123))
(marshpeg '(error ($)))
(marshpeg '(* "abcd" (constant :hi)))
(marshpeg ~(/ "abc" ,identity))
(marshpeg '(if-not "abcdf" 123))
(marshpeg ~(cmt "abcdf" ,identity))
(marshpeg '(group "abc"))
# Module path expansion
(setdyn :current-file "some-dir/some-file")
(defn test-expand [path temp]
(string (module/expand-path path temp)))
(assert (= (test-expand "abc" ":cur:/:all:") "some-dir/abc") "module/expand-path 1")
(assert (= (test-expand "./abc" ":cur:/:all:") "some-dir/abc") "module/expand-path 2")
(assert (= (test-expand "abc/def.txt" ":cur:/:name:") "some-dir/def.txt") "module/expand-path 3")
(assert (= (test-expand "abc/def.txt" ":cur:/:dir:/sub/:name:") "some-dir/abc/sub/def.txt") "module/expand-path 4")
(assert (= (test-expand "/abc/../def.txt" ":all:") "/def.txt") "module/expand-path 5")
(assert (= (test-expand "abc/../def.txt" ":all:") "def.txt") "module/expand-path 6")
(assert (= (test-expand "../def.txt" ":all:") "../def.txt") "module/expand-path 7")
(assert (= (test-expand "../././././abcd/../def.txt" ":all:") "../def.txt") "module/expand-path 8")
(end-suite)

View File

@@ -1,116 +0,0 @@
# Copyright (c) 2019 Calvin Rose & contributors
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
(import ./helper :prefix "" :exit true)
(start-suite 7)
# Using a large test grammar
(def- core-env (table/getproto (fiber/getenv (fiber/current))))
(def- specials {'fn true
'var true
'do true
'while true
'def true
'splice true
'set true
'unquote true
'quasiquote true
'quote true
'if true})
(defn- check-number [text] (and (scan-number text) text))
(defn capture-sym
[text]
(def sym (symbol text))
[(if (or (core-env sym) (specials sym)) :coresym :symbol) text])
(def grammar
~{:ws (set " \v\t\r\f\n\0")
:readermac (set "';~,")
:symchars (+ (range "09" "AZ" "az" "\x80\xFF") (set "!$%&*+-./:<?=>@^_|"))
:token (some :symchars)
:hex (range "09" "af" "AF")
:escape (* "\\" (+ (set "ntrvzf0e\"\\")
(* "x" :hex :hex)
(error (constant "bad hex escape"))))
:comment (/ '(* "#" (any (if-not (+ "\n" -1) 1))) (constant :comment))
:symbol (/ ':token ,capture-sym)
:keyword (/ '(* ":" (any :symchars)) (constant :keyword))
:constant (/ '(+ "true" "false" "nil") (constant :constant))
:bytes (* "\"" (any (+ :escape (if-not "\"" 1))) "\"")
:string (/ ':bytes (constant :string))
:buffer (/ '(* "@" :bytes) (constant :string))
:long-bytes {:delim (some "`")
:open (capture :delim :n)
:close (cmt (* (not (> -1 "`")) (-> :n) ':delim) ,=)
:main (drop (* :open (any (if-not :close 1)) :close))}
:long-string (/ ':long-bytes (constant :string))
:long-buffer (/ '(* "@" :long-bytes) (constant :string))
:number (/ (cmt ':token ,check-number) (constant :number))
:raw-value (+ :comment :constant :number :keyword
:string :buffer :long-string :long-buffer
:parray :barray :ptuple :btuple :struct :dict :symbol)
:value (* (? '(some (+ :ws :readermac))) :raw-value '(any :ws))
:root (any :value)
:root2 (any (* :value :value))
:ptuple (* '"(" :root (+ '")" (error "")))
:btuple (* '"[" :root (+ '"]" (error "")))
:struct (* '"{" :root2 (+ '"}" (error "")))
:parray (* '"@" :ptuple)
:barray (* '"@" :btuple)
:dict (* '"@" :struct)
:main (+ :root (error ""))})
(def p (peg/compile grammar))
# Just make sure is valgrind clean.
(def p (-> p make-image load-image))
(assert (peg/match p "abc") "complex peg grammar 1")
(assert (peg/match p "[1 2 3 4]") "complex peg grammar 2")
#
# fn compilation special
#
(defn myfn1 [[x y z] & more]
more)
(defn myfn2 [head & more]
more)
(assert (= (myfn1 [1 2 3] 4 5 6) (myfn2 [:a :b :c] 4 5 6)) "destructuring and varargs")
#
# Test propagation of signals via fibers
#
(def f (fiber/new (fn [] (error :abc) 1) :ei))
(def res (resume f))
(assert-error :abc (propagate res f) "propagate 1")
# table/clone
(defn check-table-clone [x msg]
(assert (= (table/to-struct x) (table/to-struct (table/clone x))) msg))
(check-table-clone @{:a 123 :b 34 :c :hello : 945 0 1 2 3 4 5} "table/clone 1")
(check-table-clone @{} "table/clone 1")
(end-suite)

55
tools/bars.janet Normal file
View File

@@ -0,0 +1,55 @@
# A flexible templater for janet. Compiles
# templates to janet functions that produce buffers.
(defn template
"Compile a template string into a function"
[source]
# State for compilation machine
(def p (parser/new))
(def forms @[])
(defn parse-chunk
"Parse a string and push produced values to forms."
[chunk]
(parser/consume p chunk)
(while (parser/has-more p)
(array/push forms (parser/produce p)))
(if (= :error (parser/status p))
(error (parser/error p))))
(defn code-chunk
"Parse all the forms in str and return them
in a tuple prefixed with 'do."
[str]
(parse-chunk str)
true)
(defn string-chunk
"Insert string chunk into parser"
[str]
(parser/insert p str)
(parse-chunk "")
true)
# Run peg
(def grammar
~{:code-chunk (* "{%" (drop (cmt '(any (if-not "%}" 1)) ,code-chunk)) "%}")
:main-chunk (drop (cmt '(any (if-not "{%" 1)) ,string-chunk))
:main (any (+ :code-chunk :main-chunk (error "")))})
(def parts (peg/match grammar source))
# Check errors in template and parser
(unless parts (error "invalid template syntax"))
(parse-chunk "\n")
(case (parser/status p)
:pending (error (string "unfinished parser state " (parser/state p)))
:error (error (parser/error p)))
# Make ast from forms
(def ast ~(fn [&opt params] (default params @{}) (,buffer ,;forms)))
(def ctor (compile ast (fiber/getenv (fiber/current)) source))
(if-not (function? ctor)
(error (string "could not compile template")))
(ctor))

View File

@@ -15,14 +15,14 @@
(def- sep (if is-win "\\" "/"))
(def- objext (if is-win ".obj" ".o"))
(def- modext (if is-win ".dll" ".so"))
(def- absprefix (if is-win "C:\\" "/"))
#
# Rule Engine
#
(defn- getrules []
(if-let [rules (dyn :rules)] rules (setdyn :rules @{})))
(def rules (dyn :rules))
(if rules rules (setdyn :rules @{})))
(defn- gettarget [target]
(def item ((getrules) target))
@@ -92,54 +92,39 @@
(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))))
(require path :env env ;args)
(when-let [rules (env :rules)] (merge-into (getrules) rules)))
(defn import-rules
(defmacro import-rules
"Import another file that defines more cook rules. This ruleset
is merged into the current ruleset."
[path]
(def env (make-env))
(unless (os/stat path :mode)
(error (string "cannot open " path)))
(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)))
(dofile path :env env)
(when-let [rules (env :rules)] (merge-into (getrules) rules)))
[path & args]
~(,import-rules* ,(string path) ,;args))
#
# Configuration
#
# Installation settings
(def JANET_MODPATH (or (os/getenv "JANET_MODPATH") (dyn :syspath)))
(def JANET_HEADERPATH (os/getenv "JANET_HEADERPATH"))
(def JANET_BINPATH (or (os/getenv "JANET_BINPATH") (unless is-win "/usr/local/bin")))
(def BINDIR (os/getenv "JANET_BINDIR"))
(def LIBDIR (or (os/getenv "JANET_PATH") module/*syspath*))
(def INCLUDEDIR (or (os/getenv "JANET_HEADERPATH") module/*headerpath*))
# Compilation settings
(def- OPTIMIZE (or (os/getenv "OPTIMIZE") 2))
(def- COMPILER (or (os/getenv "COMPILER") (if is-win "cl" "cc")))
(def- LINKER (or (os/getenv "LINKER") (if is-win "link" COMPILER)))
(def- LFLAGS
(if-let [lflags (os/getenv "LFLAGS")]
(string/split " " lflags)
(if is-win ["/nologo" "/DLL"]
(if is-mac
["-shared" "-undefined" "dynamic_lookup"]
["-shared"]))))
(def- CFLAGS
(if-let [cflags (os/getenv "CFLAGS")]
(string/split " " cflags)
(if is-win
["/nologo"]
["-std=c99" "-Wall" "-Wextra" "-fpic"])))
# Some defaults
(def default-cflags CFLAGS)
(def default-lflags LFLAGS)
(def default-cc COMPILER)
(def default-ld LINKER)
(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
@@ -157,7 +142,9 @@
(defn shell
"Do a shell command"
[& args]
(def res (os/execute args :p))
(def cmd (string/join args))
(print cmd)
(def res (os/shell cmd))
(unless (zero? res)
(error (string "command exited with status " res))))
@@ -174,10 +161,7 @@
(defn copy
"Copy a file or directory recursively from one location to another."
[src dest]
(print "copying " src " to " dest "...")
(if is-win
(shell "xcopy" src dest "/y" "/e")
(shell "cp" "-rf" src dest)))
(shell (if is-win "xcopy " "cp -rf ") src " " dest (if is-win " /h /y /t /e" "")))
#
# C Compilation
@@ -236,40 +220,39 @@
(defn- getcflags
"Generate the c flags from the input options."
[opts]
@[;(opt opts :cflags CFLAGS)
(string (if is-win "/I" "-I") (opt opts :headerpath JANET_HEADERPATH))
(string (if is-win "/O" "-O") (opt opts :optimize OPTIMIZE))])
(string (opt opts :cflags CFLAGS)
(if is-win " /I" " -I")
(opt opts :includedir INCLUDEDIR)
(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 (opt opts :compiler COMPILER))
(def cc (opt opts :compiler CC))
(def cflags (getcflags opts))
(def defines (interpose " " (make-defines (opt opts :defines {}))))
(def headers (or (opts :headers) []))
(rule dest [src ;headers]
(print "compiling " dest "...")
(rule dest [src]
(if is-win
(shell cc ;defines "/c" ;cflags (string "/Fo" dest) src)
(shell cc "-c" src ;defines ;cflags "-o" dest))))
(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 (opt opts :linker LINKER))
(def ld (opt opts :linker LD))
(def cflags (getcflags opts))
(def lflags (opt opts :lflags LFLAGS))
(def lflags (opt opts :lflags LDFLAGS))
(def olist (string/join objects " "))
(rule target objects
(print "linking " target "...")
(if is-win
(shell ld ;lflags (string "/OUT:" target) ;objects (string (opt opts :headerpath JANET_HEADERPATH) `\\janet.lib`))
(shell ld ;cflags `-o` target ;objects ;lflags))))
(shell ld " " lflags " /DLL /OUT:" target " " olist " " (opt opts :includedir INCLUDEDIR) "\\janet.lib")
(shell ld " " cflags " -o " target " " olist " " lflags))))
(defn- create-buffer-c
"Inline raw byte file as a c file."
[source dest name]
(rule dest [source]
(print "generating " dest "...")
(def f (file/open source :r))
(if (not f) (error (string "file " f " not found")))
(def out (file/open dest :w))
@@ -284,99 +267,26 @@
(file/close out)
(file/close f)))
(defn- abspath
"Create an absolute path. Does not resolve . and .. (useful for
generating entries in install manifest file)."
[path]
(if (string/has-prefix? absprefix)
path
(string (os/cwd) sep path)))
#
# Public utilities
#
(defn repo-id
"Convert a repo url into a path component that serves as its id."
[repo]
(string/replace-all "\\" "_" (string/replace-all "/" "_" repo)))
(defn find-manifest-dir
"Get the path to the directory containing manifests for installed
packages."
[&opt opts]
(string (opt (or opts @{}) :modpath JANET_MODPATH) sep ".manifests"))
(defn find-manifest
"Get the full path of a manifest file given a package name."
[name &opt opts]
(string (find-manifest-dir opts) sep name ".txt"))
(defn find-cache
"Return the path to the global cache."
[&opt opts]
(def path (opt (or opts @{}) :modpath JANET_MODPATH))
(string path sep ".cache"))
(defn uninstall
"Uninstall bundle named name"
[name &opt opts]
(def manifest (find-manifest name opts))
(def f (file/open manifest :r))
(unless f (print manifest " does not exist") (break))
(loop [line :iterate (:read f :line)]
(def path ((string/split "\n" line) 0))
(print "removing " path)
(try (rm path) ([err]
(unless (= err "No such file or directory")
(error err)))))
(print "removing " manifest)
(rm manifest)
(:close f)
(print "Uninstalled."))
(defn clear-cache
"Clear the global git cache."
[&opt opts]
(rm (find-cache opts)))
(defn install-git
"Install a bundle from git. If the bundle is already installed, the bundle
is reinistalled (but not rebuilt if artifacts are cached)."
[repo &opt opts]
(def cache (find-cache opts))
(os/mkdir cache)
(def id (repo-id repo))
(def module-dir (string cache sep id))
(when (os/mkdir module-dir)
(os/execute ["git" "clone" repo module-dir] :p))
(def olddir (os/cwd))
(os/cd module-dir)
(try
(with-dyns [:rules @{}]
(import-rules "./project.janet")
(do-rule "install-deps")
(do-rule "build")
(do-rule "install"))
([err] nil))
(os/cd olddir))
(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))
(def path (string destdir sep name))
(array/push (dyn :installed-files) path)
(add-body "install"
(try (os/mkdir destdir) ([err] nil))
(copy src destdir)))
#
# Declaring Artifacts - used in project.janet, targets specifically
# tailored for janet.
#
(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."
@@ -396,41 +306,24 @@
(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))
(def libdir (opt opts :libdir LIBDIR))
(install-rule lname LIBDIR))
(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))
(def libdir (opt opts :libdir LIBDIR))
(each s sources
(install-rule s path)))
(defn declare-bin
"Declare a generic file to be installed as an executable."
[&keys opts]
(def main (opts :main))
(def binpath (opt opts :binpath JANET_BINPATH))
(install-rule main binpath))
(install-rule s libdir)))
(defn declare-binscript
"Declare a janet file to be installed as an executable script. Creates
a shim on windows."
"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)
# Create a dud batch file when on windows.
(when is-win
(def name (last (string/split sep main)))
(def bat (string "@echo off\r\njanet %~dp0\\" name "%*"))
(def newname (string binpath sep name ".bat"))
(add-body "install"
(spit newname bat))
(add-body "uninstall"
(os/rm newname))))
(def bindir (opt opts :bindir BINDIR))
(install-rule main bindir))
(defn declare-archive
"Build a janet archive. This is a file that bundles together many janet
@@ -442,8 +335,8 @@
(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))
(def libdir (opt opts :libdir LIBDIR))
(install-rule iname libdir))
(defn declare-project
"Define your project metadata. This should
@@ -451,37 +344,11 @@
Also sets up basic phony targets like clean, build, test, etc."
[&keys meta]
(setdyn :project meta)
(def installed-files @[])
(def manifests (find-manifest-dir))
(def manifest (find-manifest (meta :name)))
(setdyn :manifest manifest)
(setdyn :manifest-dir manifests)
(setdyn :installed-files installed-files)
(rule "./build" [] (os/mkdir "build"))
(phony "build" ["./build"])
(phony "manifest" []
(print "generating " manifest "...")
(os/mkdir manifests)
(spit manifest (string (string/join installed-files "\n") "\n")))
(phony "install" ["uninstall" "build" "manifest"]
(print "Installed as '" (meta :name) "'."))
(phony "install-deps" []
(if-let [deps (meta :dependencies)]
(each dep deps
(install-git dep))
(print "no dependencies found")))
(phony "uninstall" []
(uninstall (meta :name)))
(phony "clean" []
(rm "build")
(print "Deleted build directory."))
(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]

View File

@@ -104,7 +104,6 @@
# Generate parts and print them to stdout
(def parts (seq [[k entry]
:in (sort (pairs (table/getproto (fiber/getenv (fiber/current)))))
:when (symbol? k)
:when (and (get entry :doc) (not (get entry :private)))]
(emit-item k entry)))
(print

198
tools/highlight.janet Normal file
View File

@@ -0,0 +1,198 @@
# Copyright (C) Calvin Rose 2019
#
# Takes in a janet string and colorizes for multiple
# output formats.
# Constants for checking if symbols should be
# highlighted.
(def- core-env (table/getproto *env*))
(def- specials {'fn true
'var true
'do true
'while true
'def true
'splice true
'set true
'break true
'unquote true
'quasiquote true
'quote true
'if true})
(defn check-number [text] (and (scan-number text) text))
(defn- make-grammar
"Creates the grammar based on the paint function, which
colorizes fragments of text."
[paint]
(defn <-c
"Peg rule for capturing and coloring a rule."
[color what]
~(/ (<- ,what) ,(partial paint color)))
(defn color-symbol
"Color a symbol only if it is a core library binding or special."
[text]
(def sym (symbol text))
(def should-color (or (specials sym) (core-env sym)))
(paint (if should-color :coresym :symbol) text))
~{:ws (set " \t\r\f\n\v\0")
:readermac (set "';~,")
:symchars (+ (range "09" "AZ" "az" "\x80\xFF") (set "!$%&*+-./:<?=>@^_|"))
:token (some :symchars)
:hex (range "09" "af" "AF")
:escape (* "\\" (+ (set "ntrvzf0\"\\e")
(* "x" :hex :hex)
(error (constant "bad hex escape"))))
:comment ,(<-c :comment ~(* "#" (any (if-not (+ "\n" -1) 1))))
:symbol (/ ':token ,color-symbol)
:keyword ,(<-c :keyword ~(* ":" (any :symchars)))
:constant ,(<-c :constant ~(+ "true" "false" "nil"))
:bytes (* "\"" (any (+ :escape (if-not "\"" 1))) "\"")
:string ,(<-c :string :bytes)
:buffer ,(<-c :string ~(* "@" :bytes))
:long-bytes {:delim (some "`")
:open (capture :delim :n)
:close (cmt (* (not (> -1 "`")) (-> :n) ':delim) ,=)
:main (drop (* :open (any (if-not :close 1)) :close))}
:long-string ,(<-c :string :long-bytes)
:long-buffer ,(<-c :string ~(* "@" :long-bytes))
:number (/ (cmt ':token ,check-number) ,(partial paint :number))
:raw-value (+ :comment :constant :number :keyword
:string :buffer :long-string :long-buffer
:parray :barray :ptuple :btuple :struct :dict :symbol)
:value (* (? '(some (+ :ws :readermac))) :raw-value '(any :ws))
:root (any :value)
:root2 (any (* :value :value))
:ptuple (* '"(" :root (+ '")" (error "")))
:btuple (* '"[" :root (+ '"]" (error "")))
:struct (* '"{" :root2 (+ '"}" (error "")))
:parray (* '"@" :ptuple)
:barray (* '"@" :btuple)
:dict (* '"@" :struct)
:main (+ (% :root) (error ""))})
# Terminal syntax highlighting
(def- terminal-colors
{:number 32
:keyword 33
:string 35
:coresym 31
:constant 34
:comment 36})
(defn- terminal-paint
"Paint colors for ansi terminals"
[what str]
(def code (get terminal-colors what))
(if code (string "\e[" code "m" str "\e[0m") str))
# HTML syntax highlighting
(def- html-colors
{:number "j-number"
:keyword "j-keyword"
:string "j-string"
:coresym "j-coresym"
:constant "j-constant"
:comment "j-comment"
:line "j-line"})
(def- escapes
{38 "&amp;"
60 "&lt;"
62 "&gt;"
34 "&quot;"
39 "&#39;"
47 "&#47;"})
(def html-style
"Style tag to add to a page to highlight janet code"
```
<style type="text/css">
.j-main { color: white; background: #111; font-size: 1.4em; }
.j-number { color: #89dc76; }
.j-keyword { color: #ffd866; }
.j-string { color: #ab90f2; }
.j-coresym { color: #ff6188; }
.j-constant { color: #fc9867; }
.j-comment { color: darkgray; }
.j-line { color: gray; }
</style>
```)
(defn html-escape
"Escape special characters for HTML encoding."
[str]
(def buf @"")
(loop [byte :in str]
(if-let [rep (get escapes byte)]
(buffer/push-string buf rep)
(buffer/push-byte buf byte)))
buf)
(defn- html-paint
"Paint colors for HTML"
[what str]
(def color (get html-colors what))
(def escaped (html-escape str))
(if color
(string "<span class=\"" color "\">" escaped "</span>")
escaped))
# Create Pegs
(def- terminal-grammar (peg/compile (make-grammar terminal-paint)))
(def- html-grammar (peg/compile (make-grammar html-paint)))
# API
(defn ansi
"Highlight janet source code ANSI Termianl escape colors."
[source]
(0 (peg/match terminal-grammar source)))
(defn html
"Highlight janet source code and output HTML."
[source]
(string "<pre class=\"j-main\"><code>"
(0 (peg/match html-grammar source))
"</code></pre>"))
(defn html-file
"Highlight a janet file and print out a highlighted HTML version
of the file. Must provide a default title when creating the file."
[in-path out-path title &]
(default title in-path)
(def f (file/open in-path :r))
(def source (file/read f :all))
(file/close f)
(def markup (0 (peg/match html-grammar source)))
(def out (file/open out-path :w))
(file/write out
"<!doctype html><html><head><meta charset=\"UTF-8\">"
html-style
"<title>"
title
"</title></head>"
"<body class=\"j-main\"><pre>"
markup
"</pre></body></html>")
(file/close out))
(defn ansi-file
"Highlight a janet file and print the highlighted output to stdout."
[in-path]
(def f (file/open in-path :r))
(def source (file/read f :all))
(file/close f)
(def markup (0 (peg/match terminal-grammar source)))
(print markup))

39
tools/jpm Executable file
View File

@@ -0,0 +1,39 @@
#!/usr/bin/env janet
# CLI tool for building janet projects. Wraps cook.
(import cook :prefix "")
(import-rules "./project.janet")
(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:
--libdir : The directory to install modules to. Defaults to $JANET_PATH or module/*syspath*
--includedir : The directory containing janet headers. Defaults to $JANET_HEADERPATH or module/*headerpath*
--bindir : The directory to install binaries and scripts. Defaults to $JANET_BINDIR.
--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))
(each arg args
(if (string/has-prefix? "--" arg)
(let [[key value] (peg/match argpeg arg)]
(setdyn (keyword key) value))
(do-rule arg)))
(if (empty? args) (help))

View File

@@ -1,4 +1,4 @@
@echo off
@rem Wrapper around jpm
@rem Wrapper arounf jpm
janet %~dp0\jpm.janet %*

View File

@@ -2,25 +2,6 @@
# Used to help build the tmLanguage grammar. Emits
# the entire .tmLanguage file for janet.
# Use dynamic binding and make this the first
# expression in the file to not pollute (all-bindings)
(setdyn :allsyms
(array/concat
@["break"
"def"
"do"
"var"
"set"
"fn"
"while"
"if"
"quote"
"quasiquote"
"unquote"
"splice"]
(all-bindings)))
(def allsyms (dyn :allsyms))
(def grammar-template
`````
<?xml version="1.0" encoding="UTF-8"?>
@@ -362,6 +343,22 @@
# Now we generate the bindings in the language.
(def- specials
@["break"
"def"
"do"
"var"
"set"
"fn"
"while"
"if"
"quote"
"quasiquote"
"unquote"
"splice"])
(def allsyms (array/concat @[] specials (all-bindings)))
(def- escapes
{(get "|" 0) `\|`
(get "-" 0) `\-`