mirror of
https://github.com/ashinn/chibi-scheme.git
synced 2025-05-19 05:39:18 +02:00
Compare commits
No commits in common. "master" and "0.6.1" have entirely different histories.
721 changed files with 11332 additions and 93878 deletions
|
@ -1,30 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
if git rev-parse --verify HEAD >/dev/null 2>&1; then
|
||||
against=HEAD
|
||||
else
|
||||
# Initial commit: diff against an empty tree object
|
||||
against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
|
||||
fi
|
||||
|
||||
# fail if we add any new lines to C or Scheme source containing a tab
|
||||
if git diff --name-only "$against" | egrep -q '\.(cpp|h|scm|sld|stub)$' &&\
|
||||
git diff --name-only "$against" |\
|
||||
egrep '\.(cpp|h|scm|sld|stub)$' |\
|
||||
xargs -d'\n' git diff -U0 --no-color "$against" -- |\
|
||||
grep -q $'^+ *\t'; then
|
||||
echo "Error: Attempting to add a source file using tabs for indentation."
|
||||
echo
|
||||
echo -n " "
|
||||
git diff --name-only "$against" |\
|
||||
egrep '\.(cpp|h|scm|sld|stub)$' |\
|
||||
xargs -d'\n' git diff -U0 "$against" -- |\
|
||||
grep $'^+ *\t' | head -1
|
||||
echo
|
||||
cat <<EOF
|
||||
It's important for arguments to line up vertically to a precise column.
|
||||
Since there is no standard tab width, using tabs for indentation makes
|
||||
this impossible in general. Please use spaces.
|
||||
EOF
|
||||
exit 1
|
||||
fi
|
23
.github/workflows/CI.yaml
vendored
23
.github/workflows/CI.yaml
vendored
|
@ -1,23 +0,0 @@
|
|||
name: CI
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: ${{ matrix.os }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build
|
||||
run: make # assumes GNUMake
|
||||
- name: Test
|
||||
run: make test-all
|
||||
- name: Setup
|
||||
run: sudo make install
|
||||
- name: Run in PATH
|
||||
run: chibi-scheme r7rs-tests.scm
|
||||
working-directory: tests
|
86
.gitignore
vendored
86
.gitignore
vendored
|
@ -1,86 +0,0 @@
|
|||
# Object files
|
||||
*.o
|
||||
*.bc
|
||||
*.ko
|
||||
*.obj
|
||||
*.elf
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Libraries
|
||||
*.lib
|
||||
*.a
|
||||
*.la
|
||||
*.lo
|
||||
|
||||
# Shared objects (inc. Windows DLLs)
|
||||
*.dll
|
||||
*.dll.*
|
||||
*.so
|
||||
*.so.*
|
||||
*.dylib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
*.i*86
|
||||
*.x86_64
|
||||
*.hex
|
||||
|
||||
# Debug files
|
||||
*.dSYM/
|
||||
|
||||
# Snow Meta files
|
||||
lib/.*.meta
|
||||
|
||||
# Generated files
|
||||
chibi-scheme
|
||||
chibi-scheme-emscripten
|
||||
chibi-scheme.pc
|
||||
include/chibi/install.h
|
||||
lib/chibi/emscripten.c
|
||||
lib/chibi/filesystem.c
|
||||
lib/chibi/io/io.c
|
||||
lib/chibi/net.c
|
||||
lib/chibi/process.c
|
||||
lib/chibi/pty.c
|
||||
lib/chibi/snow/install.sld
|
||||
lib/chibi/stty.c
|
||||
lib/chibi/system.c
|
||||
lib/chibi/time.c
|
||||
lib/chibi/win32/process-win32.c
|
||||
lib/scheme/bytevector.c
|
||||
lib/srfi/144/math.c
|
||||
lib/srfi/160/uvprims.c
|
||||
*.tgz
|
||||
*.bz2
|
||||
*.xz
|
||||
*.html
|
||||
*.img
|
||||
*.err
|
||||
*.fasl
|
||||
*.txt
|
||||
!CMakeLists.txt
|
||||
*.test
|
||||
*.train
|
||||
*.h5
|
||||
!index.html
|
||||
|
||||
benchmarks/gabriel/times.tsv
|
||||
examples/snow-fort
|
||||
examples/synthcode
|
||||
tests/snow/repo-cache
|
||||
tests/snow/repo*/repo.scm
|
||||
tests/snow/tmp-root
|
||||
tmp
|
||||
/lib/chibi/crypto/crypto.c
|
||||
/chibi-scheme-ulimit
|
||||
/clibs.c
|
||||
|
||||
js/chibi.*
|
||||
|
||||
build-lib/chibi/char-set/derived.scm
|
||||
build-lib/chibi/char-set/width.scm
|
|
@ -4,8 +4,6 @@ syntax: glob
|
|||
*.s
|
||||
*.o
|
||||
*.so
|
||||
*.so.*
|
||||
*.pc
|
||||
*.sch
|
||||
*.sps
|
||||
*.txt
|
||||
|
@ -37,9 +35,6 @@ lib/chibi/process.c
|
|||
lib/chibi/system.c
|
||||
lib/chibi/time.c
|
||||
lib/chibi/stty.c
|
||||
lib/chibi/emscripten.c
|
||||
doc/*.html
|
||||
doc/lib/chibi/*.html
|
||||
misc/*
|
||||
tests/ffi/*.c
|
||||
tests/ffi/*.stub
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
language: c
|
||||
compiler:
|
||||
- clang
|
||||
- gcc
|
47
AUTHORS
47
AUTHORS
|
@ -1,11 +1,6 @@
|
|||
Alex Shinn wrote the initial version of chibi-scheme and all
|
||||
distributed modules.
|
||||
|
||||
The Emscripten build, syntax-case and SRFI 139 implementation, and
|
||||
various other patches were contributed by Marc Nieper-Wißkirchen.
|
||||
|
||||
The image handling code in gc_heap.c was written by Chris Walsh.
|
||||
|
||||
The `dynamic-wind' implementation is adapted from the implementation
|
||||
in the appendix to the Scheme48 reference manual, reportedly first
|
||||
written by Chris Hanson and John Lamping.
|
||||
|
@ -14,17 +9,6 @@ The (scheme time) module includes code for handling leap seconds
|
|||
from Alan Watson's Scheme clock library at
|
||||
http://code.google.com/p/scheme-clock/ under the same license.
|
||||
|
||||
The lgamma_r implementation for Windows builds is based on code by
|
||||
Haruhiko Okumura via Ruby.
|
||||
|
||||
The following distributed SRFIs use the reference implementations:
|
||||
|
||||
(srfi 101) is adapted from David van Horn's implementation
|
||||
(srfi 134) is Shiro Kawai's implementation
|
||||
(srfi 135) is Will Clinger's implementation
|
||||
(srfi 139), (srfi 146), (srfi 154), (srfi 165) are Marc Nieper-Wißkirchen's implementations
|
||||
(srfi 146 hash) is Arthur Gleckler's Hash Array Mapped Trie implementation
|
||||
|
||||
The benchmarks are based on the Racket versions of the classic
|
||||
Gabriel benchmarks from
|
||||
http://www.cs.utah.edu/~mflatt/benchmarks-20100126/log3/index.html.
|
||||
|
@ -32,58 +16,29 @@ They are not installed or needed but are included for convenience.
|
|||
|
||||
Thanks to the following people for patches and bug reports:
|
||||
|
||||
* Adam Feuer
|
||||
* Alan Watson
|
||||
* Alexei Lozovsky
|
||||
* Alexander Shendi
|
||||
* Andreas Rottman
|
||||
* Arthur Gleckler
|
||||
* Bakul Shah
|
||||
* Ben Davenport-Ray
|
||||
* Ben Mather
|
||||
* Ben Weaver
|
||||
* Bertrand Augereau
|
||||
* Bradley Lucier
|
||||
* Bruno Deferrari
|
||||
* Damien Diederen
|
||||
* Daphne Preston-Kendal
|
||||
* Doug Currie
|
||||
* Derrick Eddington
|
||||
* Dmitry Chestnykh
|
||||
* Eduardo Cavazos
|
||||
* Ekaitz Zarraga
|
||||
* Felix Winkelmann
|
||||
* Gregor Klinke
|
||||
* Jeremy Wolff
|
||||
* Jeronimo Pellegrini
|
||||
* John Cowan
|
||||
* John Samsa
|
||||
* Jonas Rinke
|
||||
* Kris Katterjohn
|
||||
* Lars J Aas
|
||||
* Lassi Kortela
|
||||
* Lorenzo Campedelli
|
||||
* Lukas Böger
|
||||
* Marc Nieper-Wißkirchen
|
||||
* McKay Marston
|
||||
* Meng Zhang
|
||||
* Michal Kowalski (sladegen)
|
||||
* Miroslav Urbanek
|
||||
* Naoki Koguro
|
||||
* Nguyễn Thái Ngọc Duy
|
||||
* Petteri Piiroinen
|
||||
* Rajesh Krishnan
|
||||
* Ricardo G. Herdt
|
||||
* Roger Crew
|
||||
* Seth Alves
|
||||
* Sören Tempel
|
||||
* Stephen Lewis
|
||||
* Taylor Venable
|
||||
* Travis Cross
|
||||
* Vasilij Schneidermann
|
||||
* Vitaliy Mysak
|
||||
* Yota Toyama
|
||||
* Yuki Okumura
|
||||
* Zhang Meng
|
||||
|
||||
If you would prefer not to be listed, or are one of the users listed
|
||||
without a full name, please contact me. If you've made a contribution
|
||||
|
|
603
CMakeLists.txt
603
CMakeLists.txt
|
@ -1,603 +0,0 @@
|
|||
|
||||
cmake_minimum_required(VERSION 3.12)
|
||||
|
||||
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/VERSION version)
|
||||
string(STRIP ${version} version)
|
||||
|
||||
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/RELEASE release)
|
||||
string(STRIP ${release} release)
|
||||
|
||||
project(chibi-scheme LANGUAGES C VERSION ${version}
|
||||
DESCRIPTION "Chibi-Scheme: minimal r7rs implementation, release: ${release}")
|
||||
|
||||
include(CheckIncludeFile)
|
||||
include(CheckSymbolExists)
|
||||
include(GNUInstallDirs)
|
||||
include(CMakePackageConfigHelpers)
|
||||
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
set(CMAKE_BUILD_TYPE "${CMAKE_BUILD_TYPE}" CACHE STRING
|
||||
"Build type: None, Debug, Release, RelWithDebInfo, MinSizeRel, or Sanitizer." FORCE)
|
||||
|
||||
if (NOT EXISTS ${CMAKE_BINARY_DIR}/CMakeCache.txt AND NOT CMAKE_BUILD_TYPE)
|
||||
# CMake doesn't have a default build type, so set one manually
|
||||
set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING "" FORCE)
|
||||
endif()
|
||||
|
||||
#
|
||||
# Features
|
||||
#
|
||||
|
||||
check_include_file(poll.h HAVE_POLL_H)
|
||||
check_symbol_exists(ntp_gettime sys/timex.h HAVE_NTP_GETTIME)
|
||||
check_symbol_exists(int_least8_t inttypes.h HAVE_STDINT_H)
|
||||
|
||||
if (WIN32 AND NOT CYGWIN)
|
||||
set(DEFAULT_SHARED_LIBS OFF)
|
||||
else()
|
||||
set(DEFAULT_SHARED_LIBS ON)
|
||||
endif()
|
||||
|
||||
option(BUILD_SHARED_LIBS "Build chibi-scheme as a shared library" ${DEFAULT_SHARED_LIBS})
|
||||
option(SEXP_USE_BOEHM "Use Boehm garbage collection library" OFF)
|
||||
|
||||
if(SEXP_USE_BOEHM)
|
||||
find_library(BOEHMGC gc REQUIRED)
|
||||
find_path(BOEHMGC_INCLUDE NAMES gc/gc.h)
|
||||
endif()
|
||||
|
||||
set(chibi-scheme-exclude-modules)
|
||||
if(WIN32)
|
||||
set(chibi-scheme-exclude-modules
|
||||
# Following modules are not compatible with Win32
|
||||
lib/chibi/net.sld
|
||||
lib/chibi/process.sld
|
||||
lib/chibi/stty.sld
|
||||
lib/chibi/system.sld
|
||||
lib/chibi/time.sld
|
||||
lib/chibi/pty.sld)
|
||||
endif()
|
||||
|
||||
#
|
||||
# Default settings for all targets. We use an interface library here to not
|
||||
# pollute/mutate global settings. Any configuration applied to this library
|
||||
# is propagated to its client targets.
|
||||
#
|
||||
|
||||
add_library(libchibi-common
|
||||
INTERFACE)
|
||||
|
||||
target_compile_definitions(libchibi-common
|
||||
INTERFACE
|
||||
SEXP_STATIC_LIBRARY=$<NOT:$<BOOL:${BUILD_SHARED_LIBS}>>
|
||||
SEXP_USE_DL=$<BOOL:${BUILD_SHARED_LIBS}>
|
||||
$<$<PLATFORM_ID:Windows>:BUILDING_DLL=$<BOOL:${BUILD_SHARED_LIBS}>>
|
||||
SEXP_USE_INTTYPES=$<BOOL:${HAVE_STDINT_H}>
|
||||
SEXP_USE_NTPGETTIME=$<BOOL:${HAVE_NTP_GETTIME}>
|
||||
$<$<NOT:$<BOOL:${HAVE_POLL_H}>>:SEXP_USE_GREEN_THREADS=0>
|
||||
$<$<PLATFORM_ID:Windows>:SEXP_USE_STRING_STREAMS=0>
|
||||
$<$<BOOL:${SEXP_USE_BOEHM}>:SEXP_USE_BOEHM=1>)
|
||||
|
||||
target_compile_options(libchibi-common
|
||||
INTERFACE
|
||||
$<$<C_COMPILER_ID:GNU>:-Wall>
|
||||
$<$<OR:$<C_COMPILER_ID:AppleClang>,$<C_COMPILER_ID:Clang>>:-Wall>
|
||||
$<$<CONFIG:SANITIZER>:-g
|
||||
-fsanitize=address,undefined,integer,float-divide-by-zero,float-cast-overflow,return
|
||||
-fno-omit-frame-pointer>)
|
||||
|
||||
target_include_directories(libchibi-common
|
||||
INTERFACE
|
||||
${BOEHMGC_INCLUDE}
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
|
||||
|
||||
target_link_libraries(libchibi-common INTERFACE
|
||||
${BOEHMGC}
|
||||
$<$<CONFIG:SANITIZER>:-fsanitize=address,undefined>
|
||||
$<$<PLATFORM_ID:Windows>:ws2_32>
|
||||
$<$<AND:$<PLATFORM_ID:Linux>,$<BOOL:${BUILD_SHARED_LIBS}>>:${CMAKE_DL_LIBS}>
|
||||
$<$<PLATFORM_ID:Linux>:m>)
|
||||
|
||||
#
|
||||
# Sources
|
||||
#
|
||||
|
||||
set(chibi-scheme-srcs
|
||||
# SEXP
|
||||
gc.c
|
||||
sexp.c
|
||||
bignum.c
|
||||
gc_heap.c
|
||||
|
||||
# Eval
|
||||
opcodes.c
|
||||
vm.c
|
||||
eval.c
|
||||
simplify.c)
|
||||
|
||||
#
|
||||
# Bootstrap
|
||||
#
|
||||
|
||||
add_executable(chibi-scheme-bootstrap
|
||||
EXCLUDE_FROM_ALL
|
||||
${chibi-scheme-srcs}
|
||||
main.c)
|
||||
|
||||
target_link_libraries(chibi-scheme-bootstrap PRIVATE libchibi-common)
|
||||
|
||||
|
||||
#
|
||||
# Core library
|
||||
#
|
||||
|
||||
add_library(libchibi-scheme
|
||||
${chibi-scheme-srcs})
|
||||
|
||||
target_link_libraries(libchibi-scheme
|
||||
PUBLIC libchibi-common)
|
||||
|
||||
set_target_properties(libchibi-scheme
|
||||
PROPERTIES
|
||||
PREFIX "" # It's liblibchibi-scheme otherwise
|
||||
SOVERSION ${CMAKE_PROJECT_VERSION_MAJOR}
|
||||
VERSION ${CMAKE_PROJECT_VERSION})
|
||||
|
||||
|
||||
#
|
||||
# Generate modules
|
||||
#
|
||||
|
||||
file(GLOB_RECURSE slds RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
CONFIGURE_DEPENDS lib/*.sld)
|
||||
if (chibi-scheme-exclude-modules)
|
||||
# CMake doesn't complain anymore about an empty 2nd argument, but 3.12 does. When we require a
|
||||
# more recent version, the if-guard should go.
|
||||
list(REMOVE_ITEM slds ${chibi-scheme-exclude-modules})
|
||||
endif()
|
||||
|
||||
set(chibi-ffi ${CMAKE_CURRENT_SOURCE_DIR}/tools/chibi-ffi)
|
||||
set(chibi-genstatic ${CMAKE_CURRENT_SOURCE_DIR}/tools/chibi-genstatic)
|
||||
|
||||
add_custom_target(chibi-compiled-libs)
|
||||
|
||||
function(add_compiled_library cfile)
|
||||
if (NOT BUILD_SHARED_LIBS)
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(link-libraries LINK_LIBRARIES)
|
||||
cmake_parse_arguments(compiledlib-options "" "" "${link-libraries}" ${ARGN})
|
||||
|
||||
get_filename_component(basename ${cfile} NAME_WE)
|
||||
get_filename_component(libdir ${cfile} DIRECTORY)
|
||||
|
||||
if(NOT IS_ABSOLUTE ${libdir})
|
||||
set(libdir ${CMAKE_CURRENT_BINARY_DIR}/${libdir})
|
||||
endif()
|
||||
|
||||
file(RELATIVE_PATH libname ${CMAKE_CURRENT_BINARY_DIR} ${libdir}/${basename})
|
||||
string(REPLACE "/" "-" libname ${libname})
|
||||
|
||||
add_library(${libname} ${cfile})
|
||||
target_link_libraries(${libname} PRIVATE libchibi-scheme ${compiledlib-options_LINK_LIBRARIES})
|
||||
add_dependencies(chibi-compiled-libs ${libname})
|
||||
|
||||
set_target_properties(${libname} PROPERTIES
|
||||
LIBRARY_OUTPUT_DIRECTORY ${libdir}
|
||||
LIBRARY_OUTPUT_NAME ${basename}
|
||||
PREFIX "")
|
||||
|
||||
file(RELATIVE_PATH installsubdir ${CMAKE_CURRENT_BINARY_DIR}/lib ${libdir})
|
||||
install(TARGETS ${libname}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/chibi/${installsubdir})
|
||||
endfunction()
|
||||
|
||||
if(BUILD_SHARED_LIBS)
|
||||
# This makes sure we only use the separate bootstrap executable for static
|
||||
# builds. With dynamic linking, the default executable is fine. The dispatch
|
||||
# is not a generator expression within the actual custom command to process
|
||||
# the stubs, as older CMake versions fail to properly construct the dependency
|
||||
# on the bootstrap executable from the generator expression.
|
||||
set(bootstrap chibi-scheme)
|
||||
else()
|
||||
set(bootstrap chibi-scheme-bootstrap)
|
||||
endif()
|
||||
|
||||
function(add_stubs_library stub)
|
||||
set(link-libraries LINK_LIBRARIES)
|
||||
cmake_parse_arguments(stubs-options "" "" "${link-libraries}" ${ARGN})
|
||||
|
||||
get_filename_component(stubdir ${stub} PATH)
|
||||
get_filename_component(basename ${stub} NAME_WE)
|
||||
set(stubfile ${CMAKE_CURRENT_SOURCE_DIR}/${stub})
|
||||
set(stubdir ${CMAKE_CURRENT_BINARY_DIR}/${stubdir})
|
||||
set(stubout ${stubdir}/${basename}.c)
|
||||
set(stubouts ${stubouts} ${stubout} PARENT_SCOPE)
|
||||
set(stublinkedlibs ${stublinkedlibs} ${stubs-options_LINK_LIBRARIES} PARENT_SCOPE)
|
||||
|
||||
file(MAKE_DIRECTORY ${stubdir})
|
||||
|
||||
add_custom_command(OUTPUT ${stubout}
|
||||
COMMAND ${bootstrap} ${chibi-ffi} ${stubfile} ${stubout}
|
||||
DEPENDS ${stubfile} ${chibi-ffi}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
add_compiled_library(${stubout} LINK_LIBRARIES ${stubs-options_LINK_LIBRARIES})
|
||||
endfunction()
|
||||
|
||||
add_stubs_library(lib/chibi/crypto/crypto.stub)
|
||||
add_stubs_library(lib/chibi/emscripten.stub)
|
||||
add_stubs_library(lib/chibi/filesystem.stub)
|
||||
add_stubs_library(lib/chibi/io/io.stub)
|
||||
add_stubs_library(lib/scheme/bytevector.stub)
|
||||
add_stubs_library(lib/srfi/144/math.stub)
|
||||
add_stubs_library(lib/srfi/160/uvprims.stub)
|
||||
|
||||
if(NOT WIN32)
|
||||
add_stubs_library(lib/chibi/net.stub)
|
||||
add_stubs_library(lib/chibi/process.stub)
|
||||
add_stubs_library(lib/chibi/pty.stub LINK_LIBRARIES util)
|
||||
add_stubs_library(lib/chibi/stty.stub)
|
||||
add_stubs_library(lib/chibi/system.stub)
|
||||
add_stubs_library(lib/chibi/time.stub)
|
||||
else()
|
||||
add_stubs_library(lib/chibi/win32/process-win32.stub)
|
||||
endif()
|
||||
|
||||
add_custom_target(chibi-scheme-stubs DEPENDS ${stubouts})
|
||||
|
||||
if (NOT BUILD_SHARED_LIBS)
|
||||
add_dependencies(libchibi-scheme chibi-scheme-stubs)
|
||||
endif()
|
||||
|
||||
add_compiled_library(lib/chibi/weak.c)
|
||||
add_compiled_library(lib/chibi/heap-stats.c)
|
||||
add_compiled_library(lib/chibi/disasm.c)
|
||||
add_compiled_library(lib/chibi/ast.c)
|
||||
add_compiled_library(lib/chibi/json.c)
|
||||
add_compiled_library(lib/srfi/18/threads.c)
|
||||
add_compiled_library(lib/chibi/optimize/rest.c)
|
||||
add_compiled_library(lib/chibi/optimize/profile.c)
|
||||
add_compiled_library(lib/srfi/27/rand.c)
|
||||
add_compiled_library(lib/srfi/151/bit.c)
|
||||
add_compiled_library(lib/srfi/39/param.c)
|
||||
add_compiled_library(lib/srfi/69/hash.c)
|
||||
add_compiled_library(lib/srfi/95/qsort.c)
|
||||
add_compiled_library(lib/srfi/98/env.c)
|
||||
add_compiled_library(lib/scheme/time.c)
|
||||
|
||||
#
|
||||
# Generate clib.c for SEXP_USE_STATIC_LIBS
|
||||
#
|
||||
|
||||
if (NOT BUILD_SHARED_LIBS)
|
||||
string(REPLACE ";" "\n" genstatic-input "${slds}")
|
||||
set(clibin ${CMAKE_CURRENT_BINARY_DIR}/clib-in.txt)
|
||||
set(clibout ${CMAKE_CURRENT_BINARY_DIR}/clib.c)
|
||||
set(genstatic-helper
|
||||
${CMAKE_CURRENT_LIST_DIR}/contrib/chibi-genstatic-helper.cmake)
|
||||
file(WRITE ${clibin} "${genstatic-input}")
|
||||
|
||||
add_custom_command(OUTPUT ${clibout}
|
||||
COMMAND
|
||||
${CMAKE_COMMAND}
|
||||
-DEXEC=$<TARGET_FILE:chibi-scheme-bootstrap>
|
||||
-DGENSTATIC=${chibi-genstatic}
|
||||
-DSTUBS=${clibin}
|
||||
-DOUT=${clibout}
|
||||
-P ${genstatic-helper}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
DEPENDS
|
||||
chibi-scheme-bootstrap
|
||||
${chibi-genstatic}
|
||||
${genstatic-helper}
|
||||
${slds})
|
||||
|
||||
# The generated file will #include both manually written files in
|
||||
# the source directory as well as files generated by chibi-ffi in
|
||||
# the build directory. The latter can be found without special flags,
|
||||
# as they are relative to the clib.c, but the preprocessor needs
|
||||
# help for the former. As only clib.c needs this flag, we set it
|
||||
# as locally as possible, i.e., not as a target property.
|
||||
set_source_files_properties(${clibout}
|
||||
PROPERTIES
|
||||
INCLUDE_DIRECTORIES
|
||||
${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
target_compile_definitions(libchibi-scheme
|
||||
PUBLIC
|
||||
SEXP_USE_STATIC_LIBS=1)
|
||||
|
||||
target_sources(libchibi-scheme
|
||||
PRIVATE
|
||||
${clibout})
|
||||
|
||||
target_link_libraries(libchibi-scheme
|
||||
PRIVATE
|
||||
${stublinkedlibs})
|
||||
endif()
|
||||
|
||||
#
|
||||
# Interpreter
|
||||
#
|
||||
|
||||
add_executable(chibi-scheme
|
||||
main.c)
|
||||
|
||||
target_link_libraries(chibi-scheme
|
||||
PRIVATE libchibi-scheme)
|
||||
|
||||
#
|
||||
# Generate "chibi/install.h"
|
||||
#
|
||||
|
||||
if(WIN32)
|
||||
set(platform "windows")
|
||||
elseif(CYGWIN)
|
||||
set(platform "cygwin")
|
||||
elseif(APPLE)
|
||||
set(platform "macosx")
|
||||
elseif(CMAKE_SYSTEM MATCHES "[Bb][Ss][Dd]")
|
||||
set(platform "bsd")
|
||||
elseif(CMAKE_SYSTEM MATCHES "[Aa]ndroid")
|
||||
set(platform "android")
|
||||
elseif(CMAKE_SYSTEM MATCHES "[Ss]un[Oo][Ss]")
|
||||
set(platform "solaris")
|
||||
elseif (CMAKE_SYSTEM MATCHES "[Ll]inux")
|
||||
set(platform "linux")
|
||||
else()
|
||||
set(platform "unix")
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
# Leave this empty for now, as the default GNU install directories won't
|
||||
# help on Windows.
|
||||
set(default_module_path "")
|
||||
else()
|
||||
string(JOIN ":" default_module_path
|
||||
${CMAKE_INSTALL_FULL_DATAROOTDIR}/chibi
|
||||
${CMAKE_INSTALL_FULL_LIBDIR}/chibi
|
||||
${CMAKE_INSTALL_FULL_DATAROOTDIR}/snow
|
||||
${CMAKE_INSTALL_FULL_LIBDIR}/snow)
|
||||
endif()
|
||||
|
||||
configure_file(include/chibi/install.h.in include/chibi/install.h)
|
||||
|
||||
#
|
||||
# Testing
|
||||
#
|
||||
|
||||
enable_testing()
|
||||
|
||||
set(chibi-scheme-tests
|
||||
r7rs-tests
|
||||
division-tests
|
||||
syntax-tests
|
||||
unicode-tests)
|
||||
|
||||
foreach(e ${chibi-scheme-tests})
|
||||
add_test(NAME "${e}"
|
||||
COMMAND chibi-scheme -I ${CMAKE_CURRENT_BINARY_DIR}/lib tests/${e}.scm
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
endforeach()
|
||||
|
||||
add_test(NAME r5rs-test
|
||||
COMMAND chibi-scheme -I ${CMAKE_CURRENT_BINARY_DIR}/lib -xchibi tests/r5rs-tests.scm
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
file(GLOB_RECURSE srfi_tests RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/lib
|
||||
CONFIGURE_DEPENDS lib/srfi/*/test.sld)
|
||||
|
||||
file(GLOB_RECURSE chibi_scheme_tests RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/lib
|
||||
CONFIGURE_DEPENDS lib/chibi/*-test.sld)
|
||||
|
||||
set(win32testexcludes
|
||||
# Excluded tests
|
||||
chibi/filesystem-test
|
||||
chibi/memoize-test
|
||||
chibi/term/ansi-test
|
||||
chibi/weak-test
|
||||
|
||||
# Not ported to Win32
|
||||
srfi/18/test # Threading
|
||||
chibi/doc-test # Depends (chibi time)
|
||||
chibi/log-test
|
||||
chibi/system-test
|
||||
chibi/tar-test # Depends (chibi system)
|
||||
chibi/process-test # Not applicable
|
||||
chibi/pty-test # Depends (chibi pty)
|
||||
chibi/shell-test # Depends Linux procfs
|
||||
)
|
||||
|
||||
foreach(e ${srfi_tests} ${chibi_scheme_tests})
|
||||
get_filename_component(pth ${e} PATH)
|
||||
get_filename_component(nam ${e} NAME_WE)
|
||||
list(APPEND testlibs ${pth}/${nam})
|
||||
endforeach()
|
||||
|
||||
if(WIN32)
|
||||
list(REMOVE_ITEM testlibs ${win32testexcludes})
|
||||
endif()
|
||||
|
||||
foreach(e ${testlibs})
|
||||
string(REGEX REPLACE "/" "_" testname ${e})
|
||||
string(REGEX REPLACE "/" " " form ${e})
|
||||
add_test(NAME "lib_${testname}"
|
||||
COMMAND chibi-scheme -I ${CMAKE_CURRENT_BINARY_DIR}/lib
|
||||
-e "(import (${form}))"
|
||||
-e "(run-tests)"
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
endforeach()
|
||||
|
||||
#
|
||||
# Testing (embedding)
|
||||
#
|
||||
|
||||
add_executable(test-foreign-apply-loop
|
||||
tests/foreign/apply-loop.c)
|
||||
|
||||
target_link_libraries(test-foreign-apply-loop
|
||||
PRIVATE libchibi-scheme)
|
||||
|
||||
add_test(NAME "foreign-apply-loop"
|
||||
COMMAND test-foreign-apply-loop
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
add_executable(test-foreign-typeid
|
||||
tests/foreign/typeid.c)
|
||||
|
||||
target_link_libraries(test-foreign-typeid
|
||||
PRIVATE libchibi-scheme)
|
||||
|
||||
add_test(NAME "foreign-typeid"
|
||||
COMMAND test-foreign-typeid
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
|
||||
#
|
||||
# Image, pkgconfig and meta file generation
|
||||
#
|
||||
|
||||
add_custom_command(OUTPUT chibi.img
|
||||
COMMAND chibi-scheme -I ${CMAKE_CURRENT_BINARY_DIR}/lib -mchibi.repl
|
||||
-d ${CMAKE_CURRENT_BINARY_DIR}/chibi.img
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
add_custom_command(OUTPUT red.img
|
||||
COMMAND chibi-scheme -I ${CMAKE_CURRENT_BINARY_DIR}/lib -xscheme.red -mchibi.repl
|
||||
-d ${CMAKE_CURRENT_BINARY_DIR}/red.img
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
add_custom_command(OUTPUT snow.img
|
||||
COMMAND chibi-scheme -I ${CMAKE_CURRENT_BINARY_DIR}/lib
|
||||
-mchibi.snow.commands -mchibi.snow.interface -mchibi.snow.package -mchibi.snow.utils
|
||||
-d ${CMAKE_CURRENT_BINARY_DIR}/snow.img
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
if(BUILD_SHARED_LIBS)
|
||||
# Currently, image dumps only work with shared library builds, which includes Windows
|
||||
add_custom_target(chibi-images ALL
|
||||
DEPENDS
|
||||
${CMAKE_CURRENT_BINARY_DIR}/chibi.img
|
||||
${CMAKE_CURRENT_BINARY_DIR}/red.img
|
||||
${CMAKE_CURRENT_BINARY_DIR}/snow.img
|
||||
# The dependency on libchibi-scheme is crucial here:
|
||||
chibi-compiled-libs)
|
||||
endif()
|
||||
|
||||
configure_file(contrib/chibi-scheme.pc.cmake.in chibi-scheme.pc @ONLY)
|
||||
|
||||
function(generate_package_list libdir output)
|
||||
add_custom_command(OUTPUT ${output}
|
||||
COMMAND
|
||||
${CMAKE_COMMAND}
|
||||
-DEXEC=$<TARGET_FILE:chibi-scheme>
|
||||
-DLIBDIR=${libdir}
|
||||
-DGENMETA=tools/generate-install-meta.scm
|
||||
-DVERSION=${CMAKE_PROJECT_VERSION}
|
||||
-DOUT=${CMAKE_CURRENT_BINARY_DIR}/${output}
|
||||
-P contrib/chibi-generate-install-meta-helper.cmake
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
DEPENDS
|
||||
chibi-scheme
|
||||
tools/generate-install-meta.scm
|
||||
contrib/chibi-generate-install-meta-helper.cmake)
|
||||
endfunction()
|
||||
|
||||
generate_package_list(lib/chibi .chibi.meta)
|
||||
generate_package_list(lib/scheme .scheme.meta)
|
||||
generate_package_list(lib/srfi .srfi.meta)
|
||||
|
||||
add_custom_target(chibi-meta-lists ALL
|
||||
DEPENDS
|
||||
${CMAKE_CURRENT_BINARY_DIR}/.chibi.meta
|
||||
${CMAKE_CURRENT_BINARY_DIR}/.scheme.meta
|
||||
${CMAKE_CURRENT_BINARY_DIR}/.srfi.meta)
|
||||
|
||||
|
||||
#
|
||||
# Installation
|
||||
#
|
||||
|
||||
install(DIRECTORY include/chibi
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
|
||||
PATTERN "sexp-*.[hc]" EXCLUDE
|
||||
PATTERN "*.h.in" EXCLUDE)
|
||||
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/include/chibi/install.h
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/chibi)
|
||||
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/chibi-scheme.pc
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
|
||||
|
||||
add_library(chibi::libchibi-scheme ALIAS libchibi-scheme)
|
||||
|
||||
install(TARGETS libchibi-scheme libchibi-common chibi-scheme
|
||||
EXPORT chibi-scheme-targets
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
|
||||
install(FILES
|
||||
tools/chibi-ffi
|
||||
tools/chibi-doc
|
||||
tools/snow-chibi
|
||||
tools/snow-chibi.scm
|
||||
DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
|
||||
install(FILES
|
||||
doc/chibi-scheme.1
|
||||
doc/chibi-ffi.1
|
||||
doc/chibi-doc.1
|
||||
DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
|
||||
|
||||
if(BUILD_SHARED_LIBS)
|
||||
install(FILES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/chibi.img
|
||||
${CMAKE_CURRENT_BINARY_DIR}/red.img
|
||||
${CMAKE_CURRENT_BINARY_DIR}/snow.img
|
||||
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/chibi)
|
||||
endif()
|
||||
|
||||
install(DIRECTORY
|
||||
lib/
|
||||
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/chibi
|
||||
PATTERN "*win32" EXCLUDE
|
||||
PATTERN "*test.sld" EXCLUDE
|
||||
PATTERN "*.c" EXCLUDE
|
||||
PATTERN "*.stub" EXCLUDE)
|
||||
|
||||
# This is to revert the above exclusion pattern
|
||||
install(FILES lib/chibi/test.sld
|
||||
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/chibi/chibi)
|
||||
|
||||
if(WIN32)
|
||||
install(DIRECTORY
|
||||
lib/
|
||||
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/chibi
|
||||
FILES_MATCHING
|
||||
PATTERN "*win32/*.scm"
|
||||
PATTERN "*win32/*.sld")
|
||||
endif()
|
||||
|
||||
install(FILES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/.chibi.meta
|
||||
${CMAKE_CURRENT_BINARY_DIR}/.scheme.meta
|
||||
${CMAKE_CURRENT_BINARY_DIR}/.srfi.meta
|
||||
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/chibi)
|
||||
|
||||
install(EXPORT chibi-scheme-targets
|
||||
FILE chibi-scheme-targets.cmake
|
||||
NAMESPACE chibi::
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/chibi)
|
||||
|
||||
write_basic_package_version_file(chibi-scheme-config-version.cmake
|
||||
VERSION ${CMAKE_PROJECT_VERSION}
|
||||
COMPATIBILITY ExactVersion)
|
||||
|
||||
install(FILES
|
||||
contrib/chibi-scheme-config.cmake
|
||||
${CMAKE_CURRENT_BINARY_DIR}/chibi-scheme-config-version.cmake
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/chibi)
|
|
@ -1,13 +0,0 @@
|
|||
# Contributing to Chibi-Scheme
|
||||
|
||||
Thanks for your interest!
|
||||
|
||||
Chibi-Scheme is fun and easy to hack. If you want to contribute your
|
||||
changes back upstream, there are just a few guidelines:
|
||||
|
||||
* Code must be released following the license in COPYING.
|
||||
* New modules likely belong on snow-fort.org, not the core distribution.
|
||||
* Chibi values small size over speed.
|
||||
* Features should be built up in layers, not added directly to the core.
|
||||
* Once you're ready to contribute, run `make init-dev` to install some
|
||||
local settings (currently only git submit hooks).
|
2
COPYING
2
COPYING
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 2009-2021 Alex Shinn
|
||||
Copyright (c) 2009-2012 Alex Shinn
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
|
561
Makefile
561
Makefile
|
@ -1,198 +1,125 @@
|
|||
# -*- makefile-gmake -*-
|
||||
|
||||
.PHONY: dist mips-dist cleaner distclean dist-clean test test-all test-dist checkdefs debian snowballs init-dev
|
||||
.PHONY: dist mips-dist cleaner test checkdefs
|
||||
.DEFAULT_GOAL := all
|
||||
|
||||
CHIBI_VERSION ?= $(shell cat VERSION)
|
||||
SOVERSION ?= $(CHIBI_VERSION)
|
||||
SOVERSION_MAJOR ?= $(shell echo "$(SOVERSION)" | sed "s/\..*//")
|
||||
|
||||
CHIBI_FFI ?= $(CHIBI) -q tools/chibi-ffi
|
||||
CHIBI_FFI ?= $(CHIBI) tools/chibi-ffi
|
||||
CHIBI_FFI_DEPENDENCIES ?= $(CHIBI_DEPENDENCIES) tools/chibi-ffi
|
||||
|
||||
CHIBI_DOC ?= $(CHIBI) tools/chibi-doc
|
||||
CHIBI_DOC_DEPENDENCIES ?= $(CHIBI_DEPENDENCIES) tools/chibi-doc $(COMPILED_LIBS)
|
||||
CHIBI_DOC_DEPENDENCIES ?= $(CHIBI_DEPENDENCIES) tools/chibi-doc
|
||||
|
||||
GENSTATIC ?= ./tools/chibi-genstatic
|
||||
|
||||
CHIBI ?= LD_LIBRARY_PATH=".:$(LD_LIBRARY_PATH)" DYLD_LIBRARY_PATH=".:$(DYLD_LIBRARY_PATH)" CHIBI_IGNORE_SYSTEM_PATH=1 CHIBI_MODULE_PATH=lib ./chibi-scheme$(EXE)
|
||||
CHIBI ?= LD_LIBRARY_PATH=".:$(LD_LIBRARY_PATH)" ./chibi-scheme$(EXE)
|
||||
CHIBI_DEPENDENCIES = ./chibi-scheme$(EXE)
|
||||
|
||||
SNOW_CHIBI ?= tools/snow-chibi
|
||||
|
||||
########################################################################
|
||||
|
||||
CHIBI_COMPILED_LIBS = lib/chibi/filesystem$(SO) lib/chibi/weak$(SO) \
|
||||
lib/chibi/heap-stats$(SO) lib/chibi/disasm$(SO) lib/chibi/ast$(SO) \
|
||||
lib/chibi/json$(SO) lib/chibi/emscripten$(SO)
|
||||
CHIBI_POSIX_COMPILED_LIBS = lib/chibi/process$(SO) lib/chibi/time$(SO) \
|
||||
lib/chibi/system$(SO) lib/chibi/stty$(SO) lib/chibi/pty$(SO) \
|
||||
lib/chibi/net$(SO) lib/srfi/18/threads$(SO)
|
||||
CHIBI_WIN32_COMPILED_LIBS = lib/chibi/win32/process-win32$(SO)
|
||||
CHIBI_CRYPTO_COMPILED_LIBS = lib/chibi/crypto/crypto$(SO)
|
||||
CHIBI_COMPILED_LIBS = lib/chibi/filesystem$(SO) lib/chibi/process$(SO) \
|
||||
lib/chibi/time$(SO) lib/chibi/system$(SO) lib/chibi/stty$(SO) \
|
||||
lib/chibi/weak$(SO) lib/chibi/heap-stats$(SO) lib/chibi/disasm$(SO) \
|
||||
lib/chibi/net$(SO)
|
||||
CHIBI_IO_COMPILED_LIBS = lib/chibi/io/io$(SO)
|
||||
CHIBI_OPT_COMPILED_LIBS = lib/chibi/optimize/rest$(SO) \
|
||||
lib/chibi/optimize/profile$(SO)
|
||||
EXTRA_COMPILED_LIBS ?=
|
||||
|
||||
COMPILED_LIBS = $(CHIBI_COMPILED_LIBS) $(CHIBI_IO_COMPILED_LIBS) \
|
||||
$(CHIBI_OPT_COMPILED_LIBS) $(CHIBI_CRYPTO_COMPILED_LIBS) \
|
||||
$(EXTRA_COMPILED_LIBS) \
|
||||
lib/srfi/27/rand$(SO) lib/srfi/151/bit$(SO) \
|
||||
lib/srfi/39/param$(SO) lib/srfi/69/hash$(SO) lib/srfi/95/qsort$(SO) \
|
||||
lib/srfi/98/env$(SO) lib/srfi/144/math$(SO) lib/srfi/160/uvprims$(SO) \
|
||||
lib/scheme/bytevector$(SO) lib/scheme/time$(SO)
|
||||
$(CHIBI_OPT_COMPILED_LIBS) lib/srfi/18/threads$(SO) \
|
||||
lib/srfi/27/rand$(SO) lib/srfi/33/bit$(SO) lib/srfi/39/param$(SO) \
|
||||
lib/srfi/69/hash$(SO) lib/srfi/95/qsort$(SO) lib/srfi/98/env$(SO) \
|
||||
lib/scheme/time$(SO)
|
||||
|
||||
BASE_INCLUDES = include/chibi/sexp.h include/chibi/features.h include/chibi/install.h include/chibi/bignum.h
|
||||
INCLUDES = $(BASE_INCLUDES) include/chibi/eval.h include/chibi/gc_heap.h
|
||||
INCLUDES = $(BASE_INCLUDES) include/chibi/eval.h
|
||||
|
||||
MODULE_DOCS := app assert ast base64 binary-record bytevector config \
|
||||
crypto/md5 crypto/rsa crypto/sha2 diff disasm doc edit-distance \
|
||||
equiv filesystem generic heap-stats io \
|
||||
iset/base iset/constructors iset/iterators json loop \
|
||||
match math/prime memoize mime modules net net/http-server net/servlet \
|
||||
optional parse pathname process repl scribble string stty sxml system \
|
||||
temp-file test time trace type-inference uri weak monad/environment \
|
||||
crypto/sha2 shell
|
||||
MODULE_DOCS := ast disasm equiv filesystem generic heap-stats io loop \
|
||||
match mime modules net pathname process repl scribble stty \
|
||||
system test time trace type-inference uri weak
|
||||
|
||||
IMAGE_FILES = lib/chibi.img lib/red.img lib/snow.img
|
||||
|
||||
HTML_LIBS = $(MODULE_DOCS:%=doc/lib/chibi/%.html) doc/lib/srfi/166/base.html
|
||||
|
||||
META_FILES = lib/.chibi.meta lib/.srfi.meta lib/.scheme.meta
|
||||
HTML_LIBS = $(MODULE_DOCS:%=doc/lib/chibi/%.html)
|
||||
|
||||
########################################################################
|
||||
# This includes the rules to build optional libraries.
|
||||
# It also pulls in Makefile.detect for platform detection.
|
||||
|
||||
include Makefile.libs
|
||||
|
||||
########################################################################
|
||||
# Library config.
|
||||
#
|
||||
# This is to allow "make SEXP_USE_BOEHM=1" and "make SEXP_USE_DL=0" to
|
||||
# automatically include the necessary compiler and linker flags in
|
||||
# addition to setting those features. If not using GNU make just
|
||||
# comment out the ifs and use the else branches for the defaults.
|
||||
|
||||
all: chibi-scheme$(EXE) all-libs chibi-scheme.pc $(META_FILES)
|
||||
ifeq ($(SEXP_USE_BOEHM),1)
|
||||
GCLDFLAGS := -lgc
|
||||
XCPPFLAGS := $(CPPFLAGS) -Iinclude $(D:%=-DSEXP_USE_%) -DSEXP_USE_BOEHM=1
|
||||
else
|
||||
GCLDFLAGS :=
|
||||
XCPPFLAGS := $(CPPFLAGS) -Iinclude $(D:%=-DSEXP_USE_%)
|
||||
endif
|
||||
|
||||
# Please run this if you want to contribute.
|
||||
init-dev:
|
||||
git config core.hooksPath .githooks
|
||||
ifeq ($(SEXP_USE_DL),0)
|
||||
XLDFLAGS := $(LDFLAGS) $(RLDFLAGS) $(GCLDFLAGS) -lm
|
||||
XCFLAGS := -Wall -DSEXP_USE_DL=0 -g -g3 -Os $(CFLAGS)
|
||||
else
|
||||
XLDFLAGS := $(LDFLAGS) $(RLDFLAGS) $(GCLDFLAGS) $(LIBDL) -lm
|
||||
XCFLAGS := -Wall -g -g3 -Os $(CFLAGS)
|
||||
endif
|
||||
|
||||
js: js/chibi.js
|
||||
########################################################################
|
||||
|
||||
js/chibi.js: chibi-scheme-emscripten chibi-scheme-static.bc js/pre.js js/post.js js/exported_functions.json
|
||||
emcc -O0 chibi-scheme-static.bc -o $@ -s ALLOW_MEMORY_GROWTH=1 -s MODULARIZE=1 -s EXPORT_NAME=\"Chibi\" -s EXPORTED_FUNCTIONS=@js/exported_functions.json `find lib -type f \( -name "*.scm" -or -name "*.sld" \) -printf " --preload-file %p"` -s 'EXTRA_EXPORTED_RUNTIME_METHODS=["ccall", "cwrap"]' --pre-js js/pre.js --post-js js/post.js
|
||||
all: chibi-scheme$(EXE) all-libs lib/chibi/ast$(SO)
|
||||
|
||||
chibi-scheme-static.bc:
|
||||
emmake $(MAKE) PLATFORM=emscripten CHIBI_DEPENDENCIES= CHIBI=./chibi-scheme-emscripten PREFIX= CFLAGS=-O2 SEXP_USE_DL=0 EXE=.bc SO=.bc STATICFLAGS=-shared CPPFLAGS="-DSEXP_USE_STRICT_TOPLEVEL_BINDINGS=1 -DSEXP_USE_ALIGNED_BYTECODE=1 -DSEXP_USE_STATIC_LIBS=1 -DSEXP_USE_STATIC_LIBS_NO_INCLUDE=0" clibs.c chibi-scheme-static.bc VERBOSE=1
|
||||
|
||||
chibi-scheme-emscripten: VERSION
|
||||
$(MAKE) distclean
|
||||
$(MAKE) chibi-scheme-static PLATFORM=emscripten SEXP_USE_DL=0
|
||||
(tempfile="`mktemp -t chibi.XXXXXX`" && \
|
||||
mv chibi-scheme-static$(EXE) "$$tempfile" && \
|
||||
$(MAKE) distclean; \
|
||||
mv "$$tempfile" chibi-scheme-emscripten)
|
||||
|
||||
include/chibi/install.h: Makefile.libs Makefile.detect
|
||||
include/chibi/install.h: Makefile
|
||||
echo '#define sexp_so_extension "'$(SO)'"' > $@
|
||||
echo '#define sexp_default_module_path "'$(MODDIR):$(BINMODDIR):$(SNOWMODDIR):$(SNOWBINMODDIR)'"' >> $@
|
||||
echo '#define sexp_default_module_path "'$(MODDIR):$(BINMODDIR)'"' >> $@
|
||||
echo '#define sexp_platform "'$(PLATFORM)'"' >> $@
|
||||
echo '#define sexp_architecture "'$(ARCH)'"' >> $@
|
||||
echo '#define sexp_version "'$(CHIBI_VERSION)'"' >> $@
|
||||
echo '#define sexp_version "'`cat VERSION`'"' >> $@
|
||||
echo '#define sexp_release_name "'`cat RELEASE`'"' >> $@
|
||||
|
||||
lib/chibi/snow/install.sld: Makefile.libs Makefile.detect
|
||||
echo '(define-library (chibi snow install)' > $@
|
||||
echo ' (import (scheme base))' >> $@
|
||||
echo ' (export snow-module-directory snow-binary-module-directory)' >> $@
|
||||
echo ' (begin' >> $@
|
||||
echo ' (define snow-module-directory "'$(SNOWMODDIR)'")' >> $@
|
||||
echo ' (define snow-binary-module-directory "'$(SNOWBINMODDIR)'")))' >> $@
|
||||
|
||||
%.o: %.c $(BASE_INCLUDES)
|
||||
$(CC) -c $(XCPPFLAGS) $(XCFLAGS) $(CLIBFLAGS) -o $@ $<
|
||||
|
||||
gc-ulimit.o: gc.c $(BASE_INCLUDES)
|
||||
$(CC) -c $(XCPPFLAGS) $(XCFLAGS) $(CLIBFLAGS) -DSEXP_USE_LIMITED_MALLOC -o $@ $<
|
||||
|
||||
sexp-ulimit.o: sexp.c $(BASE_INCLUDES)
|
||||
$(CC) -c $(XCPPFLAGS) $(XCFLAGS) $(CLIBFLAGS) -DSEXP_USE_LIMITED_MALLOC -o $@ $<
|
||||
|
||||
main.o: main.c $(INCLUDES)
|
||||
$(CC) -c $(XCPPFLAGS) $(XCFLAGS) -o $@ $<
|
||||
|
||||
SEXP_OBJS = gc.o sexp.o bignum.o gc_heap.o
|
||||
SEXP_ULIMIT_OBJS = gc-ulimit.o sexp-ulimit.o bignum.o gc_heap.o
|
||||
SEXP_OBJS = gc.o sexp.o bignum.o
|
||||
SEXP_ULIMIT_OBJS = gc.o sexp-ulimit.o bignum.o
|
||||
EVAL_OBJS = opcodes.o vm.o eval.o simplify.o
|
||||
|
||||
libchibi-sexp$(SO): $(SEXP_OBJS)
|
||||
$(CC) $(CLIBFLAGS) $(CLINKFLAGS) -o $@ $^ $(XLDFLAGS)
|
||||
$(CC) $(CLIBFLAGS) -o $@ $^ $(XLDFLAGS)
|
||||
|
||||
libchibi-scheme$(SO_VERSIONED_SUFFIX): $(SEXP_OBJS) $(EVAL_OBJS)
|
||||
$(CC) $(CLIBFLAGS) $(CLINKFLAGS) $(LIBCHIBI_FLAGS) -o $@ $^ $(XLDFLAGS)
|
||||
|
||||
libchibi-scheme$(SO_MAJOR_VERSIONED_SUFFIX): libchibi-scheme$(SO_VERSIONED_SUFFIX)
|
||||
$(LN) $< $@
|
||||
|
||||
libchibi-scheme$(SO): libchibi-scheme$(SO_MAJOR_VERSIONED_SUFFIX)
|
||||
$(LN) $< $@
|
||||
|
||||
libchibi-scheme.a: $(SEXP_OBJS) $(EVAL_OBJS)
|
||||
$(AR) rcs $@ $^
|
||||
libchibi-scheme$(SO): $(SEXP_OBJS) $(EVAL_OBJS)
|
||||
$(CC) $(CLIBFLAGS) -o $@ $^ $(XLDFLAGS)
|
||||
|
||||
chibi-scheme$(EXE): main.o libchibi-scheme$(SO)
|
||||
$(CC) $(XCPPFLAGS) $(XCFLAGS) $(LDFLAGS) -o $@ $< -L. $(RLDFLAGS) -lchibi-scheme
|
||||
$(CC) $(XCPPFLAGS) $(XCFLAGS) -o $@ $< -L. -lchibi-scheme
|
||||
|
||||
chibi-scheme-static$(EXE): main.o $(SEXP_OBJS) $(EVAL_OBJS)
|
||||
$(CC) $(XCFLAGS) $(STATICFLAGS) -o $@ $^ $(LDFLAGS) $(GCLDFLAGS) $(STATIC_LDFLAGS)
|
||||
$(CC) $(XCFLAGS) $(STATICFLAGS) -o $@ $^ $(LDFLAGS) $(GCLDFLAGS) -lm
|
||||
|
||||
chibi-scheme-ulimit$(EXE): main.o $(SEXP_ULIMIT_OBJS) $(EVAL_OBJS)
|
||||
$(CC) $(XCFLAGS) $(STATICFLAGS) -o $@ $^ $(LDFLAGS) $(GCLDFLAGS) $(STATIC_LDFLAGS)
|
||||
$(CC) $(XCFLAGS) $(STATICFLAGS) -o $@ $^ $(LDFLAGS) $(GCLDFLAGS) -lm
|
||||
|
||||
clibs.c: $(GENSTATIC) $(CHIBI_DEPENDENCIES) $(COMPILED_LIBS:%$(SO)=%.c)
|
||||
if [ -d .git ]; then \
|
||||
$(GIT) ls-files lib | $(GREP) .sld | $(CHIBI) -q $(GENSTATIC) > $@; \
|
||||
else \
|
||||
$(FIND) lib -name \*.sld | $(CHIBI) -q $(GENSTATIC) > $@; \
|
||||
fi
|
||||
|
||||
chibi-scheme.pc: chibi-scheme.pc.in
|
||||
echo "# pkg-config" > chibi-scheme.pc
|
||||
echo "prefix=$(PREFIX)" >> chibi-scheme.pc
|
||||
echo "exec_prefix=\$${prefix}" >> chibi-scheme.pc
|
||||
echo "libdir=$(LIBDIR)" >> chibi-scheme.pc
|
||||
echo "includedir=\$${prefix}/include" >> chibi-scheme.pc
|
||||
echo "version=$(CHIBI_VERSION)" >> chibi-scheme.pc
|
||||
echo "" >> chibi-scheme.pc
|
||||
cat chibi-scheme.pc.in >> chibi-scheme.pc
|
||||
clibs.c: $(GENSTATIC) chibi-scheme$(EXE)
|
||||
$(FIND) lib -name \*.sld | $(CHIBI) $(GENSTATIC) > $@
|
||||
|
||||
# A special case, this needs to be linked with the LDFLAGS in case
|
||||
# we're using Boehm.
|
||||
lib/chibi/ast$(SO): lib/chibi/ast.c $(INCLUDES) libchibi-scheme$(SO)
|
||||
-$(CC) $(CLIBFLAGS) $(CLINKFLAGS) $(XCPPFLAGS) $(XCFLAGS) $(LDFLAGS) -o $@ $< $(GCLDFLAGS) -L. $(RLDFLAGS) -lchibi-scheme
|
||||
lib/chibi/ast$(SO): lib/chibi/ast.c $(INCLUDES)
|
||||
-$(CC) $(CLIBFLAGS) $(XCPPFLAGS) $(XCFLAGS) -o $@ $< $(XLDFLAGS) -L. -lchibi-scheme
|
||||
|
||||
lib/chibi/crypto/crypto.c: lib/chibi/crypto/sha2.c
|
||||
lib/chibi/filesystem.c: lib/chibi/filesystem_win32_shim.c
|
||||
lib/chibi/io/io.c: lib/chibi/io/port.c
|
||||
lib/chibi/net.c: lib/chibi/accept.c
|
||||
lib/chibi/process.c: lib/chibi/signal.c
|
||||
lib/srfi/144/math.c: lib/srfi/144/lgamma_r.c
|
||||
|
||||
lib/chibi.img: $(CHIBI_DEPENDENCIES) all-libs
|
||||
$(CHIBI) -d $@
|
||||
|
||||
lib/snow.img: $(CHIBI_DEPENDENCIES) all-libs
|
||||
$(CHIBI) -mchibi.snow.commands -d $@
|
||||
|
||||
lib/red.img: $(CHIBI_DEPENDENCIES) all-libs
|
||||
$(CHIBI) -xscheme.red -mchibi.repl -d $@
|
||||
doc/lib/chibi/%.html: lib/chibi/%.sld $(CHIBI_DOC_DEPENDENCIES)
|
||||
$(CHIBI_DOC) chibi.$* > $@
|
||||
|
||||
doc: doc/chibi.html doc-libs
|
||||
|
||||
%.html: %.scrbl $(CHIBI_DOC_DEPENDENCIES)
|
||||
$(CHIBI_DOC) --html $< > $@
|
||||
|
||||
lib/.%.meta: lib/%/ tools/generate-install-meta.scm $(CHIBI_DEPENDENCIES)
|
||||
-$(FIND) $< -name \*.sld | \
|
||||
$(CHIBI) tools/generate-install-meta.scm $(CHIBI_VERSION) > $@
|
||||
$(CHIBI_DOC) $< > $@
|
||||
|
||||
########################################################################
|
||||
# Dist builds - rules to build generated files included in distribution
|
||||
|
@ -205,25 +132,14 @@ data/%.txt:
|
|||
build-lib/chibi/char-set/derived.scm: data/UnicodeData.txt data/DerivedCoreProperties.txt chibi-scheme$(EXE)
|
||||
$(CHIBI) tools/extract-unicode-props.scm --default > $@
|
||||
|
||||
build-lib/chibi/char-set/width.scm: data/UnicodeData.txt data/EastAsianWidth.txt chibi-scheme$(EXE)
|
||||
$(CHIBI) tools/extract-unicode-props.scm Zero-Width=Mn > $@
|
||||
$(CHIBI) tools/extract-unicode-props.scm -d data/EastAsianWidth.txt Full-Width=F@1,W@1 Ambiguous-Width=A@1 >> $@
|
||||
|
||||
lib/chibi/char-set/ascii.scm: build-lib/chibi/char-set/derived.scm chibi-scheme$(EXE)
|
||||
$(CHIBI) -Abuild-lib tools/optimize-char-sets.scm --ascii chibi.char-set.compute > $@
|
||||
|
||||
lib/chibi/char-set/full.scm: build-lib/chibi/char-set/derived.scm chibi-scheme$(EXE)
|
||||
$(CHIBI) -Abuild-lib tools/optimize-char-sets.scm chibi.char-set.compute > $@
|
||||
|
||||
lib/chibi/show/width.scm: build-lib/chibi/char-set/width.scm chibi-scheme$(EXE)
|
||||
$(CHIBI) -Abuild-lib tools/optimize-char-sets.scm --predicate chibi.char-set.width > $@
|
||||
|
||||
lib/scheme/char/case-offsets.scm: data/UnicodeData.txt data/CaseFolding.txt chibi-scheme$(EXE) all-libs
|
||||
$(CHIBI) tools/extract-case-offsets.scm data/UnicodeData.txt data/CaseFolding.txt > $@
|
||||
|
||||
# WARNING: this has a line for ß added by hand
|
||||
lib/scheme/char/special-casing.scm: data/CaseFolding.txt data/SpecialCasing.txt chibi-scheme$(EXE) all-libs
|
||||
$(CHIBI) tools/extract-special-casing.scm data/CaseFolding.txt data/SpecialCasing.txt > $@
|
||||
lib/scheme/char/case-offsets.scm: data/CaseFolding.txt chibi-scheme$(EXE) all-libs
|
||||
$(CHIBI) tools/extract-case-offsets.scm $< > $@
|
||||
|
||||
########################################################################
|
||||
# Tests
|
||||
|
@ -231,17 +147,17 @@ lib/scheme/char/special-casing.scm: data/CaseFolding.txt data/SpecialCasing.txt
|
|||
checkdefs:
|
||||
@for d in $(D); do \
|
||||
if ! $(GREP) -q " SEXP_USE_$${d%%=*} " include/chibi/features.h; then \
|
||||
echo "WARNING: unknown definition $$d"; \
|
||||
echo "WARNING: unknown definition $$d"; \
|
||||
fi; \
|
||||
done
|
||||
|
||||
test-basic: chibi-scheme$(EXE)
|
||||
@for f in tests/basic/*.scm; do \
|
||||
$(CHIBI) -xchibi $$f >$${f%.scm}.out 2>$${f%.scm}.err; \
|
||||
$(CHIBI) -xscheme $$f >$${f%.scm}.out 2>$${f%.scm}.err; \
|
||||
if $(DIFF) -q $(DIFFOPTS) $${f%.scm}.out $${f%.scm}.res; then \
|
||||
echo "[PASS] $${f%.scm}"; \
|
||||
echo "[PASS] $${f%.scm}"; \
|
||||
else \
|
||||
echo "[FAIL] $${f%.scm}"; \
|
||||
echo "[FAIL] $${f%.scm}"; \
|
||||
fi; \
|
||||
done
|
||||
|
||||
|
@ -251,43 +167,53 @@ test-memory: chibi-scheme-ulimit$(EXE)
|
|||
test-build:
|
||||
MAKE=$(MAKE) ./tests/build/build-tests.sh
|
||||
|
||||
test-run:
|
||||
./tests/run/command-line-tests.sh
|
||||
test-threads: chibi-scheme$(EXE) lib/srfi/18/threads$(SO) lib/srfi/39/param$(SO) lib/srfi/98/env$(SO) lib/chibi/ast$(SO) lib/chibi/time$(SO)
|
||||
$(CHIBI) -xscheme tests/thread-tests.scm
|
||||
|
||||
test-ffi: chibi-scheme$(EXE)
|
||||
$(CHIBI) tests/ffi/ffi-tests.scm
|
||||
test-numbers: chibi-scheme$(EXE)
|
||||
$(CHIBI) -xscheme tests/numeric-tests.scm
|
||||
|
||||
test-snow: chibi-scheme$(EXE) $(IMAGE_FILES)
|
||||
$(CHIBI) tests/snow/snow-tests.scm
|
||||
test-flonums: chibi-scheme$(EXE)
|
||||
$(CHIBI) -xscheme tests/flonum-tests.scm
|
||||
|
||||
test-hash: chibi-scheme$(EXE) lib/srfi/69/hash$(SO)
|
||||
$(CHIBI) -xscheme tests/hash-tests.scm
|
||||
|
||||
test-io: chibi-scheme$(EXE) lib/chibi/io/io$(SO)
|
||||
$(CHIBI) -xscheme tests/io-tests.scm
|
||||
|
||||
test-match: chibi-scheme$(EXE)
|
||||
$(CHIBI) -xscheme tests/match-tests.scm
|
||||
|
||||
test-loop: chibi-scheme$(EXE)
|
||||
$(CHIBI) -xscheme tests/loop-tests.scm
|
||||
|
||||
test-sort: chibi-scheme$(EXE) lib/srfi/33/bit$(SO)
|
||||
$(CHIBI) -xscheme tests/sort-tests.scm
|
||||
|
||||
test-srfi-1: chibi-scheme$(EXE)
|
||||
$(CHIBI) -xscheme tests/srfi-1-tests.scm
|
||||
|
||||
test-records: chibi-scheme$(EXE)
|
||||
$(CHIBI) -xscheme tests/record-tests.scm
|
||||
|
||||
test-weak: chibi-scheme$(EXE) lib/chibi/weak$(SO)
|
||||
$(CHIBI) -xscheme tests/weak-tests.scm
|
||||
|
||||
test-unicode: chibi-scheme$(EXE)
|
||||
$(CHIBI) -xchibi tests/unicode-tests.scm
|
||||
$(CHIBI) -xscheme tests/unicode-tests.scm
|
||||
|
||||
test-division: chibi-scheme$(EXE)
|
||||
$(CHIBI) tests/division-tests.scm
|
||||
test-process: chibi-scheme$(EXE) lib/chibi/process$(SO)
|
||||
$(CHIBI) -xscheme tests/process-tests.scm
|
||||
|
||||
test-system: chibi-scheme$(EXE) lib/chibi/system$(SO)
|
||||
$(CHIBI) -xscheme tests/system-tests.scm
|
||||
|
||||
test-libs: chibi-scheme$(EXE)
|
||||
@echo "\e[1mloading tests first, it may take a while to see output...\e[0m"
|
||||
$(CHIBI) tests/lib-tests.scm
|
||||
$(CHIBI) -xscheme tests/lib-tests.scm
|
||||
|
||||
test-r5rs: chibi-scheme$(EXE)
|
||||
$(CHIBI) -xchibi tests/r5rs-tests.scm
|
||||
|
||||
test-r7rs: chibi-scheme$(EXE)
|
||||
$(CHIBI) tests/r7rs-tests.scm
|
||||
|
||||
test-syntax: chibi-scheme$(EXE)
|
||||
$(CHIBI) tests/syntax-tests.scm
|
||||
|
||||
test: test-r7rs
|
||||
|
||||
test-safe-string-cursors: chibi-scheme$(EXE)
|
||||
$(CHIBI) -Dsafe-string-cursors tests/r7rs-tests.scm
|
||||
$(CHIBI) -Dsafe-string-cursors tests/lib-tests.scm
|
||||
|
||||
test-all: test test-syntax test-libs test-ffi test-division
|
||||
|
||||
test-dist: test-all test-memory test-build
|
||||
test: chibi-scheme$(EXE)
|
||||
$(CHIBI) -xscheme tests/r5rs-tests.scm
|
||||
|
||||
bench-gabriel: chibi-scheme$(EXE)
|
||||
./benchmarks/gabriel/run.sh
|
||||
|
@ -296,264 +222,119 @@ bench-gabriel: chibi-scheme$(EXE)
|
|||
# Packaging
|
||||
|
||||
clean: clean-libs
|
||||
-$(RM) *.o *.i *.s *.bc *.8 tests/basic/*.out tests/basic/*.err \
|
||||
tests/run/*.out tests/run/*.err
|
||||
-$(RM) *.o *.i *.s *.8 tests/basic/*.out tests/basic/*.err
|
||||
|
||||
cleaner: clean
|
||||
-$(RM) chibi-scheme$(EXE) chibi-scheme-static$(EXE) chibi-scheme-ulimit$(EXE) \
|
||||
$(IMAGE_FILES) libchibi-scheme*$(SO) *.a *.pc \
|
||||
libchibi-scheme$(SO_VERSIONED_SUFFIX) \
|
||||
libchibi-scheme$(SO_MAJOR_VERSIONED_SUFFIX) \
|
||||
include/chibi/install.h lib/.*.meta \
|
||||
chibi-scheme-emscripten \
|
||||
js/chibi.* \
|
||||
libchibi-scheme$(SO) *.a include/chibi/install.h \
|
||||
$(shell $(FIND) lib -name \*.o)
|
||||
|
||||
distclean: dist-clean-libs cleaner
|
||||
dist-clean: distclean
|
||||
dist-clean: dist-clean-libs cleaner
|
||||
|
||||
install-base: all
|
||||
install: all
|
||||
$(MKDIR) $(DESTDIR)$(BINDIR)
|
||||
$(INSTALL_EXE) -m0755 chibi-scheme$(EXE) $(DESTDIR)$(BINDIR)/
|
||||
$(INSTALL) -m0755 tools/chibi-ffi $(DESTDIR)$(BINDIR)/
|
||||
$(INSTALL) -m0755 tools/chibi-doc $(DESTDIR)$(BINDIR)/
|
||||
$(INSTALL) -m0755 tools/snow-chibi $(DESTDIR)$(BINDIR)/
|
||||
$(INSTALL) -m0755 tools/snow-chibi.scm $(DESTDIR)$(BINDIR)/
|
||||
$(MKDIR) $(DESTDIR)$(MODDIR)/chibi/char-set $(DESTDIR)$(MODDIR)/chibi/crypto $(DESTDIR)$(MODDIR)/chibi/io $(DESTDIR)$(MODDIR)/chibi/iset $(DESTDIR)$(MODDIR)/chibi/loop $(DESTDIR)$(MODDIR)/chibi/match $(DESTDIR)$(MODDIR)/chibi/math $(DESTDIR)$(MODDIR)/chibi/monad $(DESTDIR)$(MODDIR)/chibi/net $(DESTDIR)$(MODDIR)/chibi/optimize $(DESTDIR)$(MODDIR)/chibi/parse $(DESTDIR)$(MODDIR)/chibi/regexp $(DESTDIR)$(MODDIR)/chibi/show $(DESTDIR)$(MODDIR)/chibi/snow $(DESTDIR)$(MODDIR)/chibi/term $(DESTDIR)$(MODDIR)/chibi/text
|
||||
$(INSTALL) chibi-scheme$(EXE) $(DESTDIR)$(BINDIR)/
|
||||
$(INSTALL) tools/chibi-ffi $(DESTDIR)$(BINDIR)/
|
||||
$(INSTALL) tools/chibi-doc $(DESTDIR)$(BINDIR)/
|
||||
$(MKDIR) $(DESTDIR)$(MODDIR)/chibi/char-set $(DESTDIR)$(MODDIR)/chibi/io $(DESTDIR)$(MODDIR)/chibi/iset $(DESTDIR)$(MODDIR)/chibi/loop $(DESTDIR)$(MODDIR)/chibi/match $(DESTDIR)$(MODDIR)/chibi/net $(DESTDIR)$(MODDIR)/chibi/optimize $(DESTDIR)$(MODDIR)/chibi/term
|
||||
$(MKDIR) $(DESTDIR)$(MODDIR)/scheme/char
|
||||
$(MKDIR) $(DESTDIR)$(MODDIR)/scheme/time
|
||||
$(MKDIR) $(DESTDIR)$(MODDIR)/srfi/1 $(DESTDIR)$(MODDIR)/srfi/18 $(DESTDIR)$(MODDIR)/srfi/27 $(DESTDIR)$(MODDIR)/srfi/151 $(DESTDIR)$(MODDIR)/srfi/39 $(DESTDIR)$(MODDIR)/srfi/69 $(DESTDIR)$(MODDIR)/srfi/95 $(DESTDIR)$(MODDIR)/srfi/99 $(DESTDIR)$(MODDIR)/srfi/99/records $(DESTDIR)$(MODDIR)/srfi/113 $(DESTDIR)$(MODDIR)/srfi/117 $(DESTDIR)$(MODDIR)/srfi/121 $(DESTDIR)$(MODDIR)/srfi/125 $(DESTDIR)$(MODDIR)/srfi/128 $(DESTDIR)$(MODDIR)/srfi/129 $(DESTDIR)$(MODDIR)/srfi/132 $(DESTDIR)$(MODDIR)/srfi/133 $(DESTDIR)$(MODDIR)/srfi/135 $(DESTDIR)$(MODDIR)/srfi/143 $(DESTDIR)$(MODDIR)/srfi/144 $(DESTDIR)$(MODDIR)/srfi/159 $(DESTDIR)$(MODDIR)/srfi/160 $(DESTDIR)$(MODDIR)/srfi/166 $(DESTDIR)$(MODDIR)/srfi/146 $(DESTDIR)$(MODDIR)/srfi/179 $(DESTDIR)$(MODDIR)/srfi/211 $(DESTDIR)$(MODDIR)/srfi/231
|
||||
$(INSTALL) -m0644 $(META_FILES) $(DESTDIR)$(MODDIR)/
|
||||
$(INSTALL) -m0644 lib/*.scm $(DESTDIR)$(MODDIR)/
|
||||
$(INSTALL) -m0644 lib/chibi/*.sld lib/chibi/*.scm $(DESTDIR)$(MODDIR)/chibi/
|
||||
$(INSTALL) -m0644 lib/chibi/char-set/*.sld lib/chibi/char-set/*.scm $(DESTDIR)$(MODDIR)/chibi/char-set/
|
||||
$(INSTALL) -m0644 lib/chibi/crypto/*.sld lib/chibi/crypto/*.scm $(DESTDIR)$(MODDIR)/chibi/crypto/
|
||||
$(INSTALL) -m0644 lib/chibi/io/*.scm $(DESTDIR)$(MODDIR)/chibi/io/
|
||||
$(INSTALL) -m0644 lib/chibi/iset/*.sld lib/chibi/iset/*.scm $(DESTDIR)$(MODDIR)/chibi/iset/
|
||||
$(INSTALL) -m0644 lib/chibi/loop/*.scm $(DESTDIR)$(MODDIR)/chibi/loop/
|
||||
$(INSTALL) -m0644 lib/chibi/match/*.scm $(DESTDIR)$(MODDIR)/chibi/match/
|
||||
$(INSTALL) -m0644 lib/chibi/math/*.sld lib/chibi/math/*.scm $(DESTDIR)$(MODDIR)/chibi/math/
|
||||
$(INSTALL) -m0644 lib/chibi/monad/*.sld lib/chibi/monad/*.scm $(DESTDIR)$(MODDIR)/chibi/monad/
|
||||
$(INSTALL) -m0644 lib/chibi/net/*.sld lib/chibi/net/*.scm $(DESTDIR)$(MODDIR)/chibi/net/
|
||||
$(INSTALL) -m0644 lib/chibi/optimize/*.sld lib/chibi/optimize/*.scm $(DESTDIR)$(MODDIR)/chibi/optimize/
|
||||
$(INSTALL) -m0644 lib/chibi/parse/*.sld lib/chibi/parse/*.scm $(DESTDIR)$(MODDIR)/chibi/parse/
|
||||
$(INSTALL) -m0644 lib/chibi/regexp/*.sld lib/chibi/regexp/*.scm $(DESTDIR)$(MODDIR)/chibi/regexp/
|
||||
$(INSTALL) -m0644 lib/chibi/show/*.sld lib/chibi/show/*.scm $(DESTDIR)$(MODDIR)/chibi/show/
|
||||
$(INSTALL) -m0644 lib/chibi/snow/*.sld lib/chibi/snow/*.scm $(DESTDIR)$(MODDIR)/chibi/snow/
|
||||
$(INSTALL) -m0644 lib/chibi/term/*.sld lib/chibi/term/*.scm $(DESTDIR)$(MODDIR)/chibi/term/
|
||||
$(INSTALL) -m0644 lib/chibi/text/*.sld lib/chibi/text/*.scm $(DESTDIR)$(MODDIR)/chibi/text/
|
||||
$(INSTALL) -m0644 lib/scheme/*.sld lib/scheme/*.scm $(DESTDIR)$(MODDIR)/scheme/
|
||||
$(INSTALL) -m0644 lib/scheme/char/*.sld lib/scheme/char/*.scm $(DESTDIR)$(MODDIR)/scheme/char/
|
||||
$(INSTALL) -m0644 lib/scheme/time/*.sld $(DESTDIR)$(MODDIR)/scheme/time/
|
||||
$(INSTALL) -m0644 lib/srfi/*.sld lib/srfi/*.scm $(DESTDIR)$(MODDIR)/srfi/
|
||||
$(INSTALL) -m0644 lib/srfi/1/*.sld $(DESTDIR)$(MODDIR)/srfi/1/
|
||||
$(INSTALL) -m0644 lib/srfi/1/*.scm $(DESTDIR)$(MODDIR)/srfi/1/
|
||||
$(INSTALL) -m0644 lib/srfi/18/*.scm $(DESTDIR)$(MODDIR)/srfi/18/
|
||||
$(INSTALL) -m0644 lib/srfi/27/*.scm $(DESTDIR)$(MODDIR)/srfi/27/
|
||||
$(INSTALL) -m0644 lib/srfi/39/*.scm $(DESTDIR)$(MODDIR)/srfi/39/
|
||||
$(INSTALL) -m0644 lib/srfi/69/*.scm $(DESTDIR)$(MODDIR)/srfi/69/
|
||||
$(INSTALL) -m0644 lib/srfi/95/*.scm $(DESTDIR)$(MODDIR)/srfi/95/
|
||||
$(INSTALL) -m0644 lib/srfi/99/*.sld $(DESTDIR)$(MODDIR)/srfi/99/
|
||||
$(INSTALL) -m0644 lib/srfi/99/records/*.sld lib/srfi/99/records/*.scm $(DESTDIR)$(MODDIR)/srfi/99/records/
|
||||
$(INSTALL) -m0644 lib/srfi/113/*.scm $(DESTDIR)$(MODDIR)/srfi/113/
|
||||
$(INSTALL) -m0644 lib/srfi/117/*.scm $(DESTDIR)$(MODDIR)/srfi/117/
|
||||
$(INSTALL) -m0644 lib/srfi/121/*.scm $(DESTDIR)$(MODDIR)/srfi/121/
|
||||
$(INSTALL) -m0644 lib/srfi/125/*.scm $(DESTDIR)$(MODDIR)/srfi/125/
|
||||
$(INSTALL) -m0644 lib/srfi/128/*.scm $(DESTDIR)$(MODDIR)/srfi/128/
|
||||
$(INSTALL) -m0644 lib/srfi/129/*.scm $(DESTDIR)$(MODDIR)/srfi/129/
|
||||
$(INSTALL) -m0644 lib/srfi/132/*.scm $(DESTDIR)$(MODDIR)/srfi/132/
|
||||
$(INSTALL) -m0644 lib/srfi/133/*.scm $(DESTDIR)$(MODDIR)/srfi/133/
|
||||
$(INSTALL) -m0644 lib/srfi/135/*.sld lib/srfi/135/*.scm $(DESTDIR)$(MODDIR)/srfi/135/
|
||||
$(INSTALL) -m0644 lib/srfi/143/*.scm $(DESTDIR)$(MODDIR)/srfi/143/
|
||||
$(INSTALL) -m0644 lib/srfi/144/*.scm $(DESTDIR)$(MODDIR)/srfi/144/
|
||||
$(INSTALL) -m0644 lib/srfi/151/*.scm $(DESTDIR)$(MODDIR)/srfi/151/
|
||||
$(INSTALL) -m0644 lib/srfi/159/*.scm $(DESTDIR)$(MODDIR)/srfi/159/
|
||||
$(INSTALL) -m0644 lib/srfi/159/*.sld $(DESTDIR)$(MODDIR)/srfi/159/
|
||||
$(INSTALL) -m0644 lib/srfi/160/*.sld $(DESTDIR)$(MODDIR)/srfi/160/
|
||||
$(INSTALL) -m0644 lib/srfi/160/*.scm $(DESTDIR)$(MODDIR)/srfi/160/
|
||||
$(INSTALL) -m0644 lib/srfi/166/*.sld $(DESTDIR)$(MODDIR)/srfi/166/
|
||||
$(INSTALL) -m0644 lib/srfi/166/*.scm $(DESTDIR)$(MODDIR)/srfi/166/
|
||||
$(INSTALL) -m0644 lib/srfi/146/*.sld $(DESTDIR)$(MODDIR)/srfi/146/
|
||||
$(INSTALL) -m0644 lib/srfi/146/*.scm $(DESTDIR)$(MODDIR)/srfi/146/
|
||||
$(INSTALL) -m0644 lib/srfi/179/*.sld $(DESTDIR)$(MODDIR)/srfi/179/
|
||||
$(INSTALL) -m0644 lib/srfi/179/*.scm $(DESTDIR)$(MODDIR)/srfi/179/
|
||||
$(INSTALL) -m0644 lib/srfi/211/*.sld $(DESTDIR)$(MODDIR)/srfi/211/
|
||||
$(INSTALL) -m0644 lib/srfi/231/*.sld lib/srfi/231/*.scm $(DESTDIR)$(MODDIR)/srfi/231/
|
||||
$(MKDIR) $(DESTDIR)$(BINMODDIR)/chibi/crypto/
|
||||
$(MKDIR) $(DESTDIR)$(MODDIR)/srfi/1 $(DESTDIR)$(MODDIR)/srfi/18 $(DESTDIR)$(MODDIR)/srfi/27 $(DESTDIR)$(MODDIR)/srfi/33 $(DESTDIR)$(MODDIR)/srfi/39 $(DESTDIR)$(MODDIR)/srfi/69 $(DESTDIR)$(MODDIR)/srfi/95 $(DESTDIR)$(MODDIR)/srfi/99 $(DESTDIR)$(MODDIR)/srfi/99/records
|
||||
$(INSTALL) lib/*.scm $(DESTDIR)$(MODDIR)/
|
||||
$(INSTALL) lib/chibi/*.sld lib/chibi/*.scm $(DESTDIR)$(MODDIR)/chibi/
|
||||
$(INSTALL) lib/chibi/char-set/*.sld lib/chibi/char-set/*.scm $(DESTDIR)$(MODDIR)/chibi/char-set/
|
||||
$(INSTALL) lib/chibi/io/*.scm $(DESTDIR)$(MODDIR)/chibi/io/
|
||||
$(INSTALL) lib/chibi/iset/*.sld lib/chibi/iset/*.scm $(DESTDIR)$(MODDIR)/chibi/iset/
|
||||
$(INSTALL) lib/chibi/loop/*.scm $(DESTDIR)$(MODDIR)/chibi/loop/
|
||||
$(INSTALL) lib/chibi/match/*.scm $(DESTDIR)$(MODDIR)/chibi/match/
|
||||
$(INSTALL) lib/chibi/net/*.sld lib/chibi/net/*.scm $(DESTDIR)$(MODDIR)/chibi/net/
|
||||
$(INSTALL) lib/chibi/optimize/*.sld lib/chibi/optimize/*.scm $(DESTDIR)$(MODDIR)/chibi/optimize/
|
||||
$(INSTALL) lib/chibi/term/*.sld lib/chibi/term/*.scm $(DESTDIR)$(MODDIR)/chibi/term/
|
||||
$(INSTALL) lib/scheme/*.sld lib/scheme/*.scm $(DESTDIR)$(MODDIR)/scheme/
|
||||
$(INSTALL) lib/scheme/char/*.sld lib/scheme/char/*.scm $(DESTDIR)$(MODDIR)/scheme/char/
|
||||
$(INSTALL) lib/scheme/time/*.sld $(DESTDIR)$(MODDIR)/scheme/time/
|
||||
$(INSTALL) lib/srfi/*.sld lib/srfi/*.scm $(DESTDIR)$(MODDIR)/srfi/
|
||||
$(INSTALL) lib/srfi/1/*.scm $(DESTDIR)$(MODDIR)/srfi/1/
|
||||
$(INSTALL) lib/srfi/18/*.scm $(DESTDIR)$(MODDIR)/srfi/18/
|
||||
$(INSTALL) lib/srfi/27/*.scm $(DESTDIR)$(MODDIR)/srfi/27/
|
||||
$(INSTALL) lib/srfi/33/*.scm $(DESTDIR)$(MODDIR)/srfi/33/
|
||||
$(INSTALL) lib/srfi/39/*.scm $(DESTDIR)$(MODDIR)/srfi/39/
|
||||
$(INSTALL) lib/srfi/69/*.scm $(DESTDIR)$(MODDIR)/srfi/69/
|
||||
$(INSTALL) lib/srfi/95/*.scm $(DESTDIR)$(MODDIR)/srfi/95/
|
||||
$(INSTALL) lib/srfi/99/*.sld $(DESTDIR)$(MODDIR)/srfi/99/
|
||||
$(INSTALL) lib/srfi/99/records/*.sld lib/srfi/99/records/*.scm $(DESTDIR)$(MODDIR)/srfi/99/records/
|
||||
$(MKDIR) $(DESTDIR)$(BINMODDIR)/chibi/io/
|
||||
$(MKDIR) $(DESTDIR)$(BINMODDIR)/chibi/optimize/
|
||||
$(MKDIR) $(DESTDIR)$(BINMODDIR)/scheme/
|
||||
$(MKDIR) $(DESTDIR)$(BINMODDIR)/srfi/18 $(DESTDIR)$(BINMODDIR)/srfi/27 $(DESTDIR)$(BINMODDIR)/srfi/151 $(DESTDIR)$(BINMODDIR)/srfi/39 $(DESTDIR)$(BINMODDIR)/srfi/69 $(DESTDIR)$(BINMODDIR)/srfi/95 $(DESTDIR)$(BINMODDIR)/srfi/98 $(DESTDIR)$(BINMODDIR)/srfi/144 $(DESTDIR)$(BINMODDIR)/srfi/160
|
||||
$(INSTALL_EXE) -m0755 $(CHIBI_COMPILED_LIBS) $(DESTDIR)$(BINMODDIR)/chibi/
|
||||
$(INSTALL_EXE) -m0755 $(CHIBI_CRYPTO_COMPILED_LIBS) $(DESTDIR)$(BINMODDIR)/chibi/crypto/
|
||||
$(INSTALL_EXE) -m0755 $(CHIBI_IO_COMPILED_LIBS) $(DESTDIR)$(BINMODDIR)/chibi/io/
|
||||
$(INSTALL_EXE) -m0755 $(CHIBI_OPT_COMPILED_LIBS) $(DESTDIR)$(BINMODDIR)/chibi/optimize/
|
||||
$(INSTALL_EXE) -m0755 lib/scheme/time$(SO) $(DESTDIR)$(BINMODDIR)/scheme/
|
||||
$(INSTALL_EXE) -m0755 lib/scheme/bytevector$(SO) $(DESTDIR)$(BINMODDIR)/scheme/
|
||||
$(INSTALL_EXE) -m0755 lib/srfi/18/threads$(SO) $(DESTDIR)$(BINMODDIR)/srfi/18
|
||||
$(INSTALL_EXE) -m0755 lib/srfi/27/rand$(SO) $(DESTDIR)$(BINMODDIR)/srfi/27
|
||||
$(INSTALL_EXE) -m0755 lib/srfi/39/param$(SO) $(DESTDIR)$(BINMODDIR)/srfi/39
|
||||
$(INSTALL_EXE) -m0755 lib/srfi/69/hash$(SO) $(DESTDIR)$(BINMODDIR)/srfi/69
|
||||
$(INSTALL_EXE) -m0755 lib/srfi/95/qsort$(SO) $(DESTDIR)$(BINMODDIR)/srfi/95
|
||||
$(INSTALL_EXE) -m0755 lib/srfi/98/env$(SO) $(DESTDIR)$(BINMODDIR)/srfi/98
|
||||
$(INSTALL_EXE) -m0755 lib/srfi/144/math$(SO) $(DESTDIR)$(BINMODDIR)/srfi/144
|
||||
$(INSTALL_EXE) -m0755 lib/srfi/151/bit$(SO) $(DESTDIR)$(BINMODDIR)/srfi/151
|
||||
$(INSTALL_EXE) -m0755 lib/srfi/160/uvprims$(SO) $(DESTDIR)$(BINMODDIR)/srfi/160
|
||||
$(MKDIR) $(DESTDIR)$(BINMODDIR)/srfi/18 $(DESTDIR)$(BINMODDIR)/srfi/27 $(DESTDIR)$(BINMODDIR)/srfi/33 $(DESTDIR)$(BINMODDIR)/srfi/39 $(DESTDIR)$(BINMODDIR)/srfi/69 $(DESTDIR)$(BINMODDIR)/srfi/95 $(DESTDIR)$(BINMODDIR)/srfi/98
|
||||
$(INSTALL) $(CHIBI_COMPILED_LIBS) lib/chibi/ast$(SO) $(DESTDIR)$(BINMODDIR)/chibi/
|
||||
$(INSTALL) $(CHIBI_IO_COMPILED_LIBS) $(DESTDIR)$(BINMODDIR)/chibi/io/
|
||||
$(INSTALL) $(CHIBI_OPT_COMPILED_LIBS) $(DESTDIR)$(BINMODDIR)/chibi/optimize/
|
||||
$(INSTALL) lib/scheme/time$(SO) $(DESTDIR)$(BINMODDIR)/scheme/
|
||||
$(INSTALL) lib/srfi/18/threads$(SO) $(DESTDIR)$(BINMODDIR)/srfi/18
|
||||
$(INSTALL) lib/srfi/27/rand$(SO) $(DESTDIR)$(BINMODDIR)/srfi/27
|
||||
$(INSTALL) lib/srfi/33/bit$(SO) $(DESTDIR)$(BINMODDIR)/srfi/33
|
||||
$(INSTALL) lib/srfi/39/param$(SO) $(DESTDIR)$(BINMODDIR)/srfi/39
|
||||
$(INSTALL) lib/srfi/69/hash$(SO) $(DESTDIR)$(BINMODDIR)/srfi/69
|
||||
$(INSTALL) lib/srfi/95/qsort$(SO) $(DESTDIR)$(BINMODDIR)/srfi/95
|
||||
$(INSTALL) lib/srfi/98/env$(SO) $(DESTDIR)$(BINMODDIR)/srfi/98
|
||||
$(MKDIR) $(DESTDIR)$(INCDIR)
|
||||
$(INSTALL) -m0644 $(INCLUDES) $(DESTDIR)$(INCDIR)/
|
||||
$(INSTALL) $(INCLUDES) $(DESTDIR)$(INCDIR)/
|
||||
$(MKDIR) $(DESTDIR)$(LIBDIR)
|
||||
$(MKDIR) $(DESTDIR)$(SOLIBDIR)
|
||||
$(INSTALL_EXE) -m0755 libchibi-scheme$(SO_VERSIONED_SUFFIX) $(DESTDIR)$(SOLIBDIR)/
|
||||
$(LN) libchibi-scheme$(SO_VERSIONED_SUFFIX) $(DESTDIR)$(SOLIBDIR)/libchibi-scheme$(SO_MAJOR_VERSIONED_SUFFIX)
|
||||
$(LN) libchibi-scheme$(SO_VERSIONED_SUFFIX) $(DESTDIR)$(SOLIBDIR)/libchibi-scheme$(SO)
|
||||
-if test -f libchibi-scheme.a; then $(INSTALL) -m0644 libchibi-scheme.a $(DESTDIR)$(SOLIBDIR)/; fi
|
||||
$(MKDIR) $(DESTDIR)$(PKGCONFDIR)
|
||||
$(INSTALL) -m0644 chibi-scheme.pc $(DESTDIR)$(PKGCONFDIR)
|
||||
$(INSTALL) libchibi-scheme$(SO) $(DESTDIR)$(SOLIBDIR)/
|
||||
-$(INSTALL) libchibi-scheme.a $(DESTDIR)$(SOLIBDIR)/
|
||||
$(MKDIR) $(DESTDIR)$(MANDIR)
|
||||
$(INSTALL) -m0644 doc/chibi-scheme.1 $(DESTDIR)$(MANDIR)/
|
||||
$(INSTALL) -m0644 doc/chibi-ffi.1 $(DESTDIR)$(MANDIR)/
|
||||
$(INSTALL) -m0644 doc/chibi-doc.1 $(DESTDIR)$(MANDIR)/
|
||||
-if type $(LDCONFIG) >/dev/null 2>/dev/null; then $(LDCONFIG) >/dev/null 2>/dev/null; fi
|
||||
|
||||
install: install-base
|
||||
ifneq "$(IMAGE_FILES)" ""
|
||||
echo "Generating images"
|
||||
-[ -z "$(DESTDIR)" ] && LD_LIBRARY_PATH="$(SOLIBDIR):$(LD_LIBRARY_PATH)" DYLD_LIBRARY_PATH="$(SOLIBDIR):$(DYLD_LIBRARY_PATH)" CHIBI_MODULE_PATH="$(MODDIR):$(BINMODDIR)" $(BINDIR)/chibi-scheme$(EXE) -mchibi.repl -d $(MODDIR)/chibi.img
|
||||
-[ -z "$(DESTDIR)" ] && LD_LIBRARY_PATH="$(SOLIBDIR):$(LD_LIBRARY_PATH)" DYLD_LIBRARY_PATH="$(SOLIBDIR):$(DYLD_LIBRARY_PATH)" CHIBI_MODULE_PATH="$(MODDIR):$(BINMODDIR)" $(BINDIR)/chibi-scheme$(EXE) -xscheme.red -mchibi.repl -d $(MODDIR)/red.img
|
||||
-[ -z "$(DESTDIR)" ] && LD_LIBRARY_PATH="$(SOLIBDIR):$(LD_LIBRARY_PATH)" DYLD_LIBRARY_PATH="$(SOLIBDIR):$(DYLD_LIBRARY_PATH)" CHIBI_MODULE_PATH="$(MODDIR):$(BINMODDIR)" $(BINDIR)/chibi-scheme$(EXE) -mchibi.snow.commands -mchibi.snow.interface -mchibi.snow.package -mchibi.snow.utils -d $(DESTDIR)$(MODDIR)/snow.img
|
||||
endif
|
||||
$(INSTALL) doc/chibi-scheme.1 $(DESTDIR)$(MANDIR)/
|
||||
$(INSTALL) doc/chibi-ffi.1 $(DESTDIR)$(MANDIR)/
|
||||
$(INSTALL) doc/chibi-doc.1 $(DESTDIR)$(MANDIR)/
|
||||
-if type ldconfig >/dev/null 2>/dev/null; then ldconfig; fi
|
||||
|
||||
uninstall:
|
||||
-$(RM) $(DESTDIR)$(BINDIR)/chibi-scheme$(EXE)
|
||||
-$(RM) $(DESTDIR)$(BINDIR)/chibi-scheme-static$(EXE)
|
||||
-$(RM) $(DESTDIR)$(BINDIR)/chibi-ffi
|
||||
-$(RM) $(DESTDIR)$(BINDIR)/chibi-doc
|
||||
-$(RM) $(DESTDIR)$(BINDIR)/snow-chibi
|
||||
-$(RM) $(DESTDIR)$(BINDIR)/snow-chibi.scm
|
||||
-$(RM) $(DESTDIR)$(SOLIBDIR)/libchibi-scheme$(SO)
|
||||
-$(RM) $(DESTDIR)$(SOLIBDIR)/libchibi-scheme$(SO_VERSIONED_SUFFIX)
|
||||
-$(RM) $(DESTDIR)$(SOLIBDIR)/libchibi-scheme$(SO_MAJOR_VERSIONED_SUFFIX)
|
||||
-$(RM) $(DESTDIR)$(LIBDIR)/libchibi-scheme$(SO).a
|
||||
-$(RM) $(DESTDIR)$(PKGCONFDIR)/chibi-scheme.pc
|
||||
-$(CD) $(DESTDIR)$(PREFIX) && $(RM) $(INCLUDES)
|
||||
-$(RMDIR) $(DESTDIR)$(INCDIR)
|
||||
-$(RM) $(DESTDIR)$(MODDIR)/srfi/99/records/*.sld
|
||||
-$(RM) $(DESTDIR)$(MODDIR)/srfi/99/records/*.scm
|
||||
-$(RM) $(DESTDIR)$(MODDIR)/.*.meta
|
||||
-$(RM) $(DESTDIR)$(MODDIR)/*.img
|
||||
-$(RM) $(DESTDIR)$(MODDIR)/*.sld $(DESTDIR)$(MODDIR)/*/*.sld $(DESTDIR)$(MODDIR)/*/*/*.sld
|
||||
-$(RM) $(DESTDIR)$(MODDIR)/*.scm $(DESTDIR)$(MODDIR)/*/*.scm $(DESTDIR)$(MODDIR)/*/*/*.scm
|
||||
-$(CD) $(DESTDIR)$(MODDIR) && $(RM) $(COMPILED_LIBS:lib/%=%)
|
||||
-$(CD) $(DESTDIR)$(BINMODDIR) && $(RM) $(COMPILED_LIBS:lib/%=%)
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR)/chibi/char-set $(DESTDIR)$(BINMODDIR)/chibi/char-set
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR)/chibi/crypto $(DESTDIR)$(BINMODDIR)/chibi/crypto
|
||||
-$(CD) $(DESTDIR)$(INCDIR) && $(RM) $(INCLUDES)
|
||||
-$(RM) $(DESTDIR)$(MODDIR)/srfi/99/records/*.{sld,scm}
|
||||
-$(RM) $(DESTDIR)$(MODDIR)/*.{sld,scm} $(DESTDIR)$(MODDIR)/*/*.{sld,scm} $(DESTDIR)$(MODDIR)/*/*/*.{sld,scm}
|
||||
-$(CD) $(DESTDIR)$(MODDIR) && $(RM) $(COMPILED_LIBS:lib/%=%) chibi/ast$(SO)
|
||||
-$(CD) $(DESTDIR)$(BINMODDIR) && $(RM) $(COMPILED_LIBS:lib/%=%) chibi/ast$(SO)
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR)/chibi/io $(DESTDIR)$(BINMODDIR)/chibi/io
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR)/chibi/iset $(DESTDIR)$(BINMODDIR)/chibi/iset
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR)/chibi/loop $(DESTDIR)$(BINMODDIR)/chibi/loop
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR)/chibi/match $(DESTDIR)$(BINMODDIR)/chibi/match
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR)/chibi/math $(DESTDIR)$(BINMODDIR)/chibi/math
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR)/chibi/monad $(DESTDIR)$(BINMODDIR)/chibi/monad
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR)/chibi/net $(DESTDIR)$(BINMODDIR)/chibi/net
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR)/chibi/optimize $(DESTDIR)$(BINMODDIR)/chibi/optimize
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR)/chibi/parse $(DESTDIR)$(BINMODDIR)/chibi/parse
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR)/chibi/regexp $(DESTDIR)$(BINMODDIR)/chibi/regexp
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR)/chibi/show $(DESTDIR)$(BINMODDIR)/chibi/show
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR)/chibi/snow $(DESTDIR)$(BINMODDIR)/chibi/snow
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR)/chibi/term $(DESTDIR)$(BINMODDIR)/chibi/term
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR)/chibi/text $(DESTDIR)$(BINMODDIR)/chibi/text
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR)/chibi $(DESTDIR)$(BINMODDIR)/chibi
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR)/scheme/char $(DESTDIR)$(BINMODDIR)/scheme/char
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR)/scheme/time $(DESTDIR)$(BINMODDIR)/scheme/time
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR)/scheme $(DESTDIR)$(BINMODDIR)/scheme
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/1 $(DESTDIR)$(BINMODDIR)/srfi/1
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/18 $(DESTDIR)$(BINMODDIR)/srfi/18
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/27 $(DESTDIR)$(BINMODDIR)/srfi/27
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/33 $(DESTDIR)$(BINMODDIR)/srfi/33
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/39 $(DESTDIR)$(BINMODDIR)/srfi/39
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/69 $(DESTDIR)$(BINMODDIR)/srfi/69
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/95 $(DESTDIR)$(BINMODDIR)/srfi/95
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/98 $(DESTDIR)$(BINMODDIR)/srfi/98
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/99/records $(DESTDIR)$(BINMODDIR)/srfi/99/records
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/99 $(DESTDIR)$(BINMODDIR)/srfi/99
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/113 $(DESTDIR)$(BINMODDIR)/srfi/113
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/117 $(DESTDIR)$(BINMODDIR)/srfi/117
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/121 $(DESTDIR)$(BINMODDIR)/srfi/121
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/125 $(DESTDIR)$(BINMODDIR)/srfi/125
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/128 $(DESTDIR)$(BINMODDIR)/srfi/128
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/129 $(DESTDIR)$(BINMODDIR)/srfi/129
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/132 $(DESTDIR)$(BINMODDIR)/srfi/132
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/133 $(DESTDIR)$(BINMODDIR)/srfi/133
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/135 $(DESTDIR)$(BINMODDIR)/srfi/135
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/143 $(DESTDIR)$(BINMODDIR)/srfi/143
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/151 $(DESTDIR)$(BINMODDIR)/srfi/151
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/144 $(DESTDIR)$(BINMODDIR)/srfi/144
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/146 $(DESTDIR)$(BINMODDIR)/srfi/146
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/159 $(DESTDIR)$(BINMODDIR)/srfi/159
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/160 $(DESTDIR)$(BINMODDIR)/srfi/160
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/166 $(DESTDIR)$(BINMODDIR)/srfi/166
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/179 $(DESTDIR)$(BINMODDIR)/srfi/179
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/211 $(DESTDIR)$(BINMODDIR)/srfi/211
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/231 $(DESTDIR)$(BINMODDIR)/srfi/231
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi $(DESTDIR)$(BINMODDIR)/srfi
|
||||
-$(RMDIR) $(DESTDIR)$(MODDIR) $(DESTDIR)$(BINMODDIR)
|
||||
-$(RM) $(DESTDIR)$(MANDIR)/chibi-scheme.1 $(DESTDIR)$(MANDIR)/chibi-ffi.1 $(DESTDIR)$(MANDIR)/chibi-doc.1
|
||||
-$(RM) $(DESTDIR)$(PKGCONFDIR)/chibi-scheme.pc
|
||||
|
||||
dist: distclean
|
||||
$(RM) chibi-scheme-$(CHIBI_VERSION).tgz
|
||||
$(MKDIR) chibi-scheme-$(CHIBI_VERSION)
|
||||
@for f in `git ls-files | grep -v ^benchmarks/`; do $(MKDIR) chibi-scheme-$(CHIBI_VERSION)/`dirname $$f`; $(SYMLINK) `pwd`/$$f chibi-scheme-$(CHIBI_VERSION)/$$f; done
|
||||
$(TAR) cphzvf chibi-scheme-$(CHIBI_VERSION).tgz chibi-scheme-$(CHIBI_VERSION)
|
||||
$(RM) -r chibi-scheme-$(CHIBI_VERSION)
|
||||
dist: dist-clean
|
||||
$(RM) chibi-scheme-`cat VERSION`.tgz
|
||||
$(MKDIR) chibi-scheme-`cat VERSION`
|
||||
@for f in `hg manifest`; do $(MKDIR) chibi-scheme-`cat VERSION`/`dirname $$f`; $(SYMLINK) `pwd`/$$f chibi-scheme-`cat VERSION`/$$f; done
|
||||
$(TAR) cphzvf chibi-scheme-`cat VERSION`.tgz chibi-scheme-`cat VERSION`
|
||||
$(RM) -r chibi-scheme-`cat VERSION`
|
||||
|
||||
mips-dist: distclean
|
||||
$(RM) chibi-scheme-`date +%Y%m%d`-`git log HEAD^..HEAD | head -1 | cut -c8-`.tgz
|
||||
$(MKDIR) chibi-scheme-`date +%Y%m%d`-`git log HEAD^..HEAD | head -1 | cut -c8-`
|
||||
@for f in `git ls-files | grep -v ^benchmarks/`; do $(MKDIR) chibi-scheme-`date +%Y%m%d`-`git log HEAD^..HEAD | head -1 | cut -c8-`/`dirname $$f`; $(SYMLINK) `pwd`/$$f chibi-scheme-`date +%Y%m%d`-`git log HEAD^..HEAD | head -1 | cut -c8-`/$$f; done
|
||||
$(TAR) cphzvf chibi-scheme-`date +%Y%m%d`-`git log HEAD^..HEAD | head -1 | cut -c8-`.tgz chibi-scheme-`date +%Y%m%d`-`git log HEAD^..HEAD | head -1 | cut -c8-`
|
||||
$(RM) -r chibi-scheme-`date +%Y%m%d`-`git log HEAD^..HEAD | head -1 | cut -c8-`
|
||||
|
||||
debian:
|
||||
sudo checkinstall -D --pkgname chibi-scheme --pkgversion $(CHIBI_VERSION) --maintainer "http://groups.google.com/group/chibi-scheme" -y make PREFIX=/usr install
|
||||
|
||||
# Libraries in the standard distribution we want to make available to
|
||||
# other Scheme implementations. Note this is run with my own
|
||||
# ~/.snow/config.scm, which specifies my own settings regarding
|
||||
# author, license, extracting docs from scribble, etc.
|
||||
snowballs:
|
||||
$(SNOW_CHIBI) package --license public-domain lib/chibi/char-set/boundary.sld
|
||||
$(SNOW_CHIBI) package --license public-domain lib/chibi/match.sld
|
||||
$(SNOW_CHIBI) package -r lib/chibi/char-set.sld
|
||||
$(SNOW_CHIBI) package -r lib/chibi/iset.sld lib/chibi/iset/optimize.sld
|
||||
$(SNOW_CHIBI) package --doc https://srfi.schemers.org/srfi-115/srfi-115.html --test-library lib/srfi/115.sld
|
||||
$(SNOW_CHIBI) package -r --doc https://srfi.schemers.org/srfi-166/srfi-166.html --test-library lib/srfi/166/test.sld lib/srfi/166.sld lib/chibi/show/shared.sld
|
||||
$(SNOW_CHIBI) package -r --doc https://srfi.schemers.org/srfi-179/srfi-179.html --test-library lib/srfi/179/test.sld lib/srfi/179.sld
|
||||
$(SNOW_CHIBI) package lib/chibi/app.sld
|
||||
$(SNOW_CHIBI) package lib/chibi/assert.sld
|
||||
$(SNOW_CHIBI) package lib/chibi/base64.sld
|
||||
$(SNOW_CHIBI) package lib/chibi/binary-record.sld
|
||||
$(SNOW_CHIBI) package lib/chibi/bytevector.sld
|
||||
$(SNOW_CHIBI) package lib/chibi/config.sld
|
||||
$(SNOW_CHIBI) package lib/chibi/crypto/md5.sld
|
||||
$(SNOW_CHIBI) package lib/chibi/crypto/rsa.sld
|
||||
$(SNOW_CHIBI) package lib/chibi/crypto/sha2.sld
|
||||
$(SNOW_CHIBI) package lib/chibi/diff.sld
|
||||
$(SNOW_CHIBI) package lib/chibi/edit-distance.sld
|
||||
$(SNOW_CHIBI) package lib/chibi/filesystem.sld
|
||||
$(SNOW_CHIBI) package lib/chibi/math/prime.sld
|
||||
$(SNOW_CHIBI) package lib/chibi/mime.sld
|
||||
$(SNOW_CHIBI) package lib/chibi/monad/environment.sld
|
||||
$(SNOW_CHIBI) package lib/chibi/optional.sld
|
||||
$(SNOW_CHIBI) package lib/chibi/parse.sld lib/chibi/parse/common.sld
|
||||
$(SNOW_CHIBI) package lib/chibi/pathname.sld
|
||||
$(SNOW_CHIBI) package lib/chibi/quoted-printable.sld
|
||||
$(SNOW_CHIBI) package lib/chibi/regexp.sld lib/chibi/regexp/pcre.sld
|
||||
$(SNOW_CHIBI) package lib/chibi/scribble.sld
|
||||
$(SNOW_CHIBI) package lib/chibi/string.sld
|
||||
$(SNOW_CHIBI) package lib/chibi/sxml.sld
|
||||
$(SNOW_CHIBI) package lib/chibi/tar.sld
|
||||
$(SNOW_CHIBI) package lib/chibi/temp-file.sld
|
||||
$(SNOW_CHIBI) package lib/chibi/term/ansi.sld
|
||||
$(SNOW_CHIBI) package lib/chibi/term/edit-line.sld
|
||||
$(SNOW_CHIBI) package lib/chibi/test.sld
|
||||
$(SNOW_CHIBI) package lib/chibi/uri.sld
|
||||
$(SNOW_CHIBI) package lib/chibi/zlib.sld
|
||||
mips-dist: dist-clean
|
||||
$(RM) chibi-scheme-`date +%Y%m%d`-`hg tags|head -1|sed -n 's/.* \([0-9]*\):.*/\1/p'`.tgz
|
||||
$(MKDIR) chibi-scheme-`date +%Y%m%d`-`hg tags|head -1|sed -n 's/.* \([0-9]*\):.*/\1/p'`
|
||||
@for f in `hg manifest`; do $(MKDIR) chibi-scheme-`date +%Y%m%d`-`hg tags|head -1|sed -n 's/.* \([0-9]*\):.*/\1/p'`/`dirname $$f`; $(SYMLINK) `pwd`/$$f chibi-scheme-`date +%Y%m%d`-`hg tags|head -1|sed -n 's/.* \([0-9]*\):.*/\1/p'`/$$f; done
|
||||
$(TAR) cphzvf chibi-scheme-`date +%Y%m%d`-`hg tags|head -1|sed -n 's/.* \([0-9]*\):.*/\1/p'`.tgz chibi-scheme-`date +%Y%m%d`-`hg tags|head -1|sed -n 's/.* \([0-9]*\):.*/\1/p'`
|
||||
$(RM) -r chibi-scheme-`date +%Y%m%d`-`hg tags|head -1|sed -n 's/.* \([0-9]*\):.*/\1/p'`
|
||||
|
|
151
Makefile.detect
151
Makefile.detect
|
@ -9,7 +9,6 @@ PLATFORM=macosx
|
|||
else
|
||||
ifeq ($(shell uname),FreeBSD)
|
||||
PLATFORM=bsd
|
||||
LIBCHIBI_FLAGS = -Wl,-soname,libchibi-scheme$(SO).$(SOVERSION_MAJOR)
|
||||
else
|
||||
ifeq ($(shell uname),NetBSD)
|
||||
PLATFORM=bsd
|
||||
|
@ -21,7 +20,7 @@ ifeq ($(shell uname),DragonFly)
|
|||
PLATFORM=bsd
|
||||
else
|
||||
ifeq ($(shell uname -o),Msys)
|
||||
PLATFORM=windows
|
||||
PLATFORM=mingw
|
||||
SOLIBDIR = $(BINDIR)
|
||||
DIFFOPTS = -b
|
||||
else
|
||||
|
@ -30,15 +29,9 @@ PLATFORM=cygwin
|
|||
SOLIBDIR = $(BINDIR)
|
||||
DIFFOPTS = -b
|
||||
else
|
||||
ifeq ($(shell uname -o),Android)
|
||||
PLATFORM=android
|
||||
else
|
||||
ifeq ($(shell uname -o),GNU/Linux)
|
||||
PLATFORM=linux
|
||||
else
|
||||
ifeq ($(shell uname),SunOS)
|
||||
PLATFORM=solaris
|
||||
else
|
||||
PLATFORM=unix
|
||||
endif
|
||||
endif
|
||||
|
@ -48,86 +41,49 @@ endif
|
|||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifndef ARCH
|
||||
ARCH = $(shell uname -m)
|
||||
endif
|
||||
|
||||
########################################################################
|
||||
# Set default variables for the platform.
|
||||
|
||||
LIBDL = -ldl
|
||||
SO_VERSIONED_SUFFIX = $(SO).$(SOVERSION)
|
||||
SO_MAJOR_VERSIONED_SUFFIX = $(SO).$(SOVERSION_MAJOR)
|
||||
STATIC_LDFLAGS = -lm -ldl -lutil
|
||||
|
||||
ifeq ($(PLATFORM),macosx)
|
||||
SO = .dylib
|
||||
SO_VERSIONED_SUFFIX = .$(SOVERSION)$(SO)
|
||||
SO_MAJOR_VERSIONED_SUFFIX = .$(SOVERSION_MAJOR)$(SO)
|
||||
EXE =
|
||||
CLIBFLAGS =
|
||||
CLINKFLAGS = -dynamiclib
|
||||
STATICFLAGS = -DSEXP_USE_DL=0 # -static-libgcc
|
||||
LIBCHIBI_FLAGS = -install_name $(DESTDIR)$(SOLIBDIR)/libchibi-scheme.$(SOVERSION).dylib
|
||||
CLIBFLAGS = -dynamiclib
|
||||
STATICFLAGS = -static-libgcc -DSEXP_USE_DL=0
|
||||
else
|
||||
ifeq ($(PLATFORM),bsd)
|
||||
SO = .so
|
||||
EXE =
|
||||
CLIBFLAGS = -fPIC
|
||||
CLINKFLAGS = -shared
|
||||
CLIBFLAGS = -fPIC -shared
|
||||
LIBDL =
|
||||
RLDFLAGS=-Wl,-R$(LIBDIR)
|
||||
else
|
||||
ifeq ($(PLATFORM),solaris)
|
||||
SO = .so
|
||||
EXE =
|
||||
CLIBFLAGS = -fPIC
|
||||
CLINKFLAGS = -shared
|
||||
LIBDL = -ldl
|
||||
RLDFLAGS=-Wl,-R$(LIBDIR)
|
||||
else
|
||||
ifeq ($(PLATFORM),windows)
|
||||
SO = .dll
|
||||
EXE = .exe
|
||||
CC ?= gcc
|
||||
CLIBFLAGS =
|
||||
CLINKFLAGS = -shared
|
||||
CPPFLAGS += -DSEXP_USE_STRING_STREAMS=0 -DSEXP_USE_GREEN_THREADS=0 -DSEXP_USE_GC_FILE_DESCRIPTORS=0 -DBUILDING_DLL
|
||||
LIBCHIBI_FLAGS = -Wl,--out-implib,libchibi-scheme$(SO).a
|
||||
STATICFLAGS =
|
||||
STATIC_LDFLAGS = -lm -ldl
|
||||
LIBDL = -lws2_32
|
||||
else
|
||||
ifeq ($(PLATFORM),msys)
|
||||
ifeq ($(PLATFORM),mingw)
|
||||
SO = .dll
|
||||
EXE = .exe
|
||||
CC = gcc
|
||||
CLIBFLAGS =
|
||||
CLINKFLAGS = -shared
|
||||
CPPFLAGS += -DSEXP_USE_STRING_STREAMS=0
|
||||
LIBCHIBI_FLAGS = -Wl,--out-implib,libchibi-scheme$(SO).a
|
||||
STATIC_LDFLAGS = -lm -ldl
|
||||
CLIBFLAGS = -shared
|
||||
CPPFLAGS += -DSEXP_USE_STRING_STREAMS=0 -DBUILDING_DLL
|
||||
LDFLAGS += -Wl,--out-implib,libchibi-scheme$(SO).a
|
||||
STATICFLAGS = -DSEXP_USE_DL=0
|
||||
LIBDL =
|
||||
else
|
||||
ifeq ($(PLATFORM),cygwin)
|
||||
SO = .dll
|
||||
EXE = .exe
|
||||
CC = gcc
|
||||
CLIBFLAGS =
|
||||
CLINKFLAGS = -shared
|
||||
CLIBFLAGS = -shared
|
||||
CPPFLAGS += -DSEXP_USE_STRING_STREAMS=0
|
||||
LIBCHIBI_FLAGS = -Wl,--out-implib,libchibi-scheme$(SO).a
|
||||
STATIC_LDFLAGS = -lm -ldl
|
||||
LDFLAGS += -Wl,--out-implib,libchibi-scheme$(SO).a
|
||||
else
|
||||
SO = .so
|
||||
EXE =
|
||||
CLIBFLAGS = -fPIC
|
||||
CLINKFLAGS = -shared
|
||||
CLIBFLAGS = -fPIC -shared
|
||||
STATICFLAGS = -static -DSEXP_USE_DL=0
|
||||
LIBCHIBI_FLAGS = -Wl,-soname,libchibi-scheme$(SO).$(SOVERSION_MAJOR)
|
||||
ifeq ($(PLATFORM),BSD)
|
||||
LIBDL=
|
||||
RLDFLAGS=-Wl,-R$(DESTDIR)$(LIBDIR)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
@ -135,83 +91,18 @@ endif
|
|||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(PLATFORM),emscripten)
|
||||
STATIC_LDFLAGS = -lm -ldl
|
||||
endif
|
||||
|
||||
ifeq ($(PLATFORM),unix)
|
||||
#RLDFLAGS=-rpath $(LIBDIR)
|
||||
RLDFLAGS=-Wl,-R$(LIBDIR)
|
||||
RLDFLAGS=-Wl,-R$(DESTDIR)$(LIBDIR)
|
||||
endif
|
||||
|
||||
########################################################################
|
||||
# Library config.
|
||||
#
|
||||
# This is to allow "make SEXP_USE_BOEHM=1" and "make SEXP_USE_DL=0" to
|
||||
# automatically include the necessary compiler and linker flags in
|
||||
# addition to setting those features. If not using GNU make just
|
||||
# comment out the ifs and use the else branches for the defaults.
|
||||
# Check for NTP (who needs autoconf?)
|
||||
|
||||
ifeq ($(SEXP_USE_BOEHM),1)
|
||||
GCLDFLAGS := -lgc
|
||||
XCPPFLAGS := $(CPPFLAGS) -Iinclude $(D:%=-DSEXP_USE_%) -DSEXP_USE_BOEHM=1
|
||||
else
|
||||
GCLDFLAGS :=
|
||||
XCPPFLAGS := $(CPPFLAGS) -Iinclude $(D:%=-DSEXP_USE_%)
|
||||
endif
|
||||
|
||||
ifeq ($(SEXP_USE_DL),0)
|
||||
XLDFLAGS := $(LDFLAGS) $(RLDFLAGS) $(GCLDFLAGS) -lm
|
||||
XCFLAGS := -Wall -DSEXP_USE_DL=0 -g -g3 -O3 $(CFLAGS)
|
||||
else
|
||||
XLDFLAGS := $(LDFLAGS) $(RLDFLAGS) $(GCLDFLAGS) $(LIBDL) -lm
|
||||
XCFLAGS := -Wall -g -g3 -O3 $(CFLAGS)
|
||||
endif
|
||||
|
||||
ifeq ($(PLATFORM),solaris)
|
||||
XLDFLAGS += -lsocket
|
||||
XCPPFLAGS += -D_POSIX_PTHREAD_SEMANTICS
|
||||
endif
|
||||
|
||||
# Choose compiled library on MSYS
|
||||
ifeq ($(OS), Windows_NT)
|
||||
ifeq ($(PLATFORM),msys)
|
||||
EXCLUDE_WIN32_LIBS=1
|
||||
else
|
||||
ifeq ($(shell uname -o),Cygwin)
|
||||
EXCLUDE_WIN32_LIBS=1
|
||||
else
|
||||
EXCLUDE_POSIX_LIBS=1
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
CHIBI_POSIX_COMPILED_LIBS = lib/chibi/process$(SO) lib/chibi/time$(SO) \
|
||||
lib/chibi/system$(SO) lib/chibi/stty$(SO) lib/chibi/pty$(SO) \
|
||||
lib/chibi/net$(SO) lib/srfi/18/threads$(SO)
|
||||
CHIBI_WIN32_COMPILED_LIBS = lib/chibi/win32/process-win32$(SO)
|
||||
|
||||
ifndef EXCLUDE_POSIX_LIBS
|
||||
CHIBI_COMPILED_LIBS += $(CHIBI_POSIX_COMPILED_LIBS)
|
||||
else
|
||||
CHIBI_COMPILED_LIBS += $(CHIBI_WIN32_COMPILED_LIBS)
|
||||
endif
|
||||
|
||||
########################################################################
|
||||
# Check for headers (who needs autoconf?)
|
||||
|
||||
ifndef SEXP_USE_NTP_GETTIME
|
||||
SEXP_USE_NTP_GETTIME := $(shell echo "int main(){struct ntptimeval n; ntp_gettime(&n);}" | $(CC) -fsyntax-only -include sys/timex.h -xc - >/dev/null 2>/dev/null && echo 1 || echo 0)
|
||||
ifndef $(SEXP_USE_NTP_GETTIME)
|
||||
SEXP_USE_NTP_GETTIME := $(shell echo "main(){struct ntptimeval n; ntp_gettime(&n);}" | gcc -fsyntax-only -include sys/timex.h -xc - >/dev/null 2>/dev/null && echo 1 || echo 0)
|
||||
endif
|
||||
|
||||
ifeq ($(SEXP_USE_NTP_GETTIME),1)
|
||||
XCPPFLAGS += -DSEXP_USE_NTPGETTIME
|
||||
endif
|
||||
|
||||
ifndef SEXP_USE_INTTYPES
|
||||
SEXP_USE_INTTYPES := $(shell echo "int main(){int_least8_t x;}" | $(CC) -fsyntax-only -include inttypes.h -xc - >/dev/null 2>/dev/null && echo 1 || echo 0)
|
||||
endif
|
||||
|
||||
ifeq ($(SEXP_USE_INTTYPES),1)
|
||||
XCPPFLAGS += -DSEXP_USE_INTTYPES
|
||||
CPPFLAGS += -DSEXP_USE_NTPGETTIME
|
||||
endif
|
||||
|
|
|
@ -9,55 +9,32 @@
|
|||
# install configuration
|
||||
|
||||
CC ?= cc
|
||||
AR ?= ar
|
||||
CD ?= cd
|
||||
RM ?= rm -f
|
||||
LS ?= ls
|
||||
CP ?= cp
|
||||
LN ?= ln -sf
|
||||
INSTALL ?= install
|
||||
INSTALL_EXE ?= $(INSTALL)
|
||||
MKDIR ?= $(INSTALL) -d
|
||||
RMDIR ?= rmdir
|
||||
TAR ?= tar
|
||||
DIFF ?= diff
|
||||
GIT ?= git
|
||||
GREP ?= grep
|
||||
FIND ?= find
|
||||
SYMLINK ?= ln -s
|
||||
LDCONFIG ?= ldconfig
|
||||
|
||||
# gnu coding standards
|
||||
prefix ?= /usr/local
|
||||
PREFIX ?= $(prefix)
|
||||
exec_prefix ?= $(PREFIX)
|
||||
bindir ?= $(exec_prefix)/bin
|
||||
libdir ?= $(exec_prefix)/lib
|
||||
includedir ?= $(PREFIX)/include
|
||||
datarootdir ?= $(PREFIX)/share
|
||||
datadir ?= $(datarootdir)
|
||||
mandir ?= $(datarootdir)/man
|
||||
man1dir ?= $(mandir)/man1
|
||||
PREFIX ?= /usr/local
|
||||
BINDIR ?= $(PREFIX)/bin
|
||||
LIBDIR ?= $(PREFIX)/lib
|
||||
SOLIBDIR ?= $(PREFIX)/lib
|
||||
INCDIR ?= $(PREFIX)/include/chibi
|
||||
MODDIR ?= $(PREFIX)/share/chibi
|
||||
BINMODDIR ?= $(PREFIX)/lib/chibi
|
||||
MANDIR ?= $(PREFIX)/share/man/man1
|
||||
|
||||
# hysterical raisins
|
||||
BINDIR ?= $(bindir)
|
||||
LIBDIR ?= $(libdir)
|
||||
SOLIBDIR ?= $(libdir)
|
||||
INCDIR ?= $(includedir)/chibi
|
||||
MODDIR ?= $(datadir)/chibi
|
||||
BINMODDIR ?= $(SOLIBDIR)/chibi
|
||||
PKGCONFDIR ?= $(SOLIBDIR)/pkgconfig
|
||||
MANDIR ?= $(man1dir)
|
||||
DESTDIR ?=
|
||||
|
||||
# allow snow to be configured separately
|
||||
SNOWPREFIX ?= /usr/local
|
||||
SNOWLIBDIR ?= $(SNOWPREFIX)/lib
|
||||
SNOWSOLIBDIR ?= $(SNOWLIBDIR)
|
||||
SNOWMODDIR ?= $(SNOWPREFIX)/share/snow
|
||||
SNOWBINMODDIR ?= $(SNOWSOLIBDIR)/snow
|
||||
|
||||
# for packaging tools
|
||||
DESTDIR ?=
|
||||
CHIBI ?= chibi-scheme$(EXE)
|
||||
CHIBI_FFI ?= chibi-ffi
|
||||
CHIBI_DOC ?= chibi-doc
|
||||
|
||||
########################################################################
|
||||
# System configuration - if not using GNU make, set PLATFORM and the
|
||||
|
@ -67,22 +44,19 @@ include Makefile.detect
|
|||
|
||||
########################################################################
|
||||
|
||||
all-libs: $(COMPILED_LIBS) lib/chibi/snow/install.sld
|
||||
all-libs: $(COMPILED_LIBS)
|
||||
|
||||
lib/%.c: lib/%.stub $(CHIBI_FFI_DEPENDENCIES)
|
||||
$(CHIBI_FFI) $<
|
||||
|
||||
lib/chibi/pty$(SO): lib/chibi/pty.c $(INCLUDES) libchibi-scheme$(SO)
|
||||
$(CC) $(CLIBFLAGS) $(CLINKFLAGS) $(XCPPFLAGS) $(XCFLAGS) $(LDFLAGS) -o $@ $< -L. $(RLDFLAGS) $(XLIBS) -lchibi-scheme -lutil
|
||||
|
||||
lib/%$(SO): lib/%.c $(INCLUDES) libchibi-scheme$(SO)
|
||||
$(CC) $(CLIBFLAGS) $(CLINKFLAGS) $(XCPPFLAGS) $(XCFLAGS) $(LDFLAGS) -o $@ $< -L. $(RLDFLAGS) $(XLIBS) -lchibi-scheme
|
||||
lib/%$(SO): lib/%.c $(INCLUDES)
|
||||
$(CC) $(CLIBFLAGS) $(XCPPFLAGS) $(XCFLAGS) -o $@ $< -L. $(XLIBS) -lchibi-scheme
|
||||
|
||||
doc-libs: $(HTML_LIBS)
|
||||
|
||||
doc/lib/%.html: lib/%.sld $(CHIBI_DOC_DEPENDENCIES)
|
||||
doc/lib/%.html: lib/%.sld
|
||||
$(MKDIR) $(dir $@)
|
||||
$(CHIBI_DOC) --html $(subst /,.,$*) > $@
|
||||
$(CHIBI_DOC) $(subst /,.,$*) > $@
|
||||
|
||||
clean-libs:
|
||||
$(RM) $(COMPILED_LIBS)
|
||||
|
|
39
README
Normal file
39
README
Normal file
|
@ -0,0 +1,39 @@
|
|||
|
||||
Chibi-Scheme
|
||||
--------------
|
||||
|
||||
Minimal Scheme Implementation for use as an Extension Language
|
||||
|
||||
http://synthcode.com/wiki/chibi-scheme/
|
||||
|
||||
Chibi-Scheme is a very small library intended for use as an extension
|
||||
and scripting language in C programs. In addition to support for
|
||||
lightweight VM-based threads, each VM itself runs in an isolated heap
|
||||
allowing multiple VMs to run simultaneously in different OS threads.
|
||||
|
||||
The default language is based on an extended subset of the current
|
||||
draft R7RS Scheme, with support for all libraries. To get a pure R7RS
|
||||
repl you can run
|
||||
|
||||
chibi-scheme -xscheme.base
|
||||
|
||||
or see the (chibi repl) library for more options.
|
||||
|
||||
Support for additional languages such as JavaScript, Go, Lua and Bash
|
||||
are planned for future releases. Scheme is chosen as a substrate
|
||||
because its first class continuations and guaranteed tail-call
|
||||
optimization makes implementing other languages easy.
|
||||
|
||||
To build on most platforms just run "make && make test". This will
|
||||
provide a shared library "libchibi-scheme", as well as a sample
|
||||
"chibi-scheme" command-line repl. You can then run
|
||||
|
||||
sudo make PREFIX=/usr/local install
|
||||
|
||||
to install the binaries, leaving out the PREFIX for the default
|
||||
/usr/local or specifying an alternate install location. If you want
|
||||
to try out chibi-scheme without installing, be sure to set
|
||||
LD_LIBRARY_PATH so it can find the shared libraries.
|
||||
|
||||
For more detailed documentation, run "make doc" and see the generated
|
||||
"doc/chibi.html".
|
|
@ -1,81 +0,0 @@
|
|||
Chibi-scheme for Windows
|
||||
========================
|
||||
|
||||
Chibi-scheme provides limited support for native desktop Windows. To use
|
||||
fully-featured Chibi-scheme on Windows, consider using POSIX layer such as
|
||||
Windows Subsytem for Linux(WSL), Cygwin or MSYS.
|
||||
|
||||
Currently, only R7RS Small libraries are available for the platform.
|
||||
|
||||
Supported Environments
|
||||
----------------------
|
||||
|
||||
Chibi-scheme can be compiled with following platforms:
|
||||
|
||||
* Microsoft Visual Studio 2017
|
||||
* MinGW32
|
||||
* MinGW64
|
||||
* MSYS
|
||||
|
||||
|
||||
Known Issues
|
||||
------------
|
||||
|
||||
Following libraries are not ported yet:
|
||||
|
||||
* `(chibi net)`
|
||||
* `(chibi process)` : `exit` is available through `(scheme process-context)`
|
||||
* `(chibi stty)`
|
||||
* `(chibi system)`
|
||||
* `(chibi time)`
|
||||
|
||||
Following library is not completely ported:
|
||||
|
||||
* `(chibi filesystem)`
|
||||
|
||||
Other issues:
|
||||
|
||||
* SRFI-27: Due to C Runtime limitation, the library is not thread-safe
|
||||
* `make install` is not supported on Windows platforms
|
||||
* On MSVC, flonum precision is degraded when compared with other compilers
|
||||
* Cross compilation is not supported
|
||||
|
||||
|
||||
Build with MinGW(Makefile)
|
||||
--------------------------
|
||||
|
||||
The top-level `Makefile` can be used with MinGW.
|
||||
|
||||
1. Open MinGW64 or MinGW32 command prompt
|
||||
2. `make`
|
||||
3. `make test`
|
||||
|
||||
Currently, `make doc` is not supported on these platforms.
|
||||
|
||||
|
||||
Build with MSYS(Makefile)
|
||||
-------------------------
|
||||
|
||||
By default, the Makefile will compile against native Windows API. To use
|
||||
MSYS's own POSIX emulation layer, specify `PLATFORM=msys`.
|
||||
|
||||
1. Open MSYS command prompt
|
||||
2. `make PLATFORM=msys`
|
||||
3. `make PLATFORM=msys test`
|
||||
|
||||
|
||||
Build with Visual Studio(CMake)
|
||||
-------------------------------
|
||||
|
||||
Minimal `CMakeLists.txt` is provided as an example to build Chibi-scheme on
|
||||
Windows platforms. This is only intended to be used with Windows platforms;
|
||||
currently it does not provide features provided with standard `Makefile` nor
|
||||
it does not support UNIX/APPLE platforms either.
|
||||
|
||||
1. (Make sure CMake was selected with Visual Studio installer)
|
||||
2. Open this directory with "Open with Visual Studio"
|
||||
3. Choose "x86-" or "x64-" configuration
|
||||
4. "CMake" => "Build all"
|
||||
5. "CMake" => "Tests" => "Run chibi-scheme Tests"
|
||||
|
||||
|
60
README.md
60
README.md
|
@ -1,60 +0,0 @@
|
|||
# 
|
||||
|
||||
**Minimal Scheme Implementation for use as an Extension Language**
|
||||
|
||||
https://github.com/ashinn/chibi-scheme
|
||||
|
||||
Chibi-Scheme is a very small library intended for use as an extension
|
||||
and scripting language in C programs. In addition to support for
|
||||
lightweight VM-based threads, each VM itself runs in an isolated heap
|
||||
allowing multiple VMs to run simultaneously in different OS threads.
|
||||
|
||||
There are no external dependencies so is relatively easy to drop into
|
||||
any project.
|
||||
|
||||
Despite the small size, Chibi-Scheme attempts to do The Right Thing.
|
||||
The default settings include:
|
||||
|
||||
* a full numeric tower, with rational and complex numbers
|
||||
* full and seamless Unicode support
|
||||
* low-level and high-level hygienic macros
|
||||
* an extensible module system
|
||||
|
||||
Specifically, the default repl language contains all bindings from
|
||||
[R7RS small](https://small.r7rs.org/), available explicitly as the
|
||||
`(scheme small)` library. The language is built in layers, however -
|
||||
see the manual for instructions on compiling with fewer features or
|
||||
requesting a smaller language on startup.
|
||||
|
||||
Chibi-Scheme is known to work on **32** and **64-bit** Linux, FreeBSD,
|
||||
NetBSD, OpenBSD, DragonFlyBSD, OS X, Plan 9, Windows, iOS, Android,
|
||||
ARM and [Emscripten](https://kripken.github.io/emscripten-site). Basic
|
||||
support for native Windows desktop also exists. See README-win32.md
|
||||
for details and build instructions.
|
||||
|
||||
To build on most platforms just run `make && make test`. This has a
|
||||
few conditionals assuming GNU make. If using another make, there are
|
||||
a few parameters in Makefile.detect you need to set by hand.
|
||||
|
||||
This will provide a shared library *libchibi-scheme*, as well as a
|
||||
sample *chibi-scheme* command-line repl. You can then run
|
||||
|
||||
sudo make install
|
||||
|
||||
to install the binaries and libraries. You can optionally specify a
|
||||
**PREFIX** for the installation directory:
|
||||
|
||||
make PREFIX=/path/to/install/
|
||||
sudo make PREFIX=/path/to/install/ install
|
||||
|
||||
By default files are installed in **/usr/local**.
|
||||
|
||||
If you want to try out chibi-scheme without installing, be sure to set
|
||||
`LD_LIBRARY_PATH` (`DYLD_LIBRARY_PATH` on macOS) so it can find the
|
||||
shared libraries.
|
||||
|
||||
To make the emscripten build run `make js` (_not_ `emmake make js`).
|
||||
|
||||
For more detailed documentation, run `make doc` and see the generated
|
||||
*doc/chibi.html* or read the [manual](http://synthcode.com/scheme/chibi/)
|
||||
online.
|
2
RELEASE
2
RELEASE
|
@ -1 +1 @@
|
|||
sodium
|
||||
carbon
|
||||
|
|
32
TODO
32
TODO
|
@ -10,8 +10,7 @@
|
|||
** TODO native x86 backend
|
||||
API redesign in preparation complete, initial
|
||||
tests on native factorial and closures working.
|
||||
** DONE fasl/image files
|
||||
- State "DONE" from "TODO" [2017-08-30 Wed 23:13]
|
||||
** TODO fasl/image files
|
||||
sexp_copy_context() can form the basis for images,
|
||||
FASL for arbitrary modules will need additional
|
||||
help with resolving external references.
|
||||
|
@ -19,8 +18,7 @@
|
|||
- State "DONE" from "TODO" [2011-11-10 Thu 20:44]
|
||||
*** TODO static image compiled into library
|
||||
With this you'll be able to run Chibi without any filesystem.
|
||||
*** DONE external tool to compact and optimize images
|
||||
- State "DONE" from "TODO" [2017-08-30 Wed 23:13]
|
||||
*** TODO external tool to compact and optimize images
|
||||
The current GC is mark&sweep, which can cause fragmentation,
|
||||
but we can at at least compact the initial fixed image.
|
||||
*** TODO fasl versions of modules
|
||||
|
@ -91,6 +89,8 @@
|
|||
- State "DONE" from "TODO" [2010-07-11 Sun 15:31]
|
||||
VM now supports an optional hook for green threads,
|
||||
and a SRFI-18 interface is provided as a separate module.
|
||||
I/O operations will currently block all threads though,
|
||||
this needs to be addressed.
|
||||
*** DONE thread-local parameters
|
||||
CLOSED: [2010-12-06 Mon 21:52]
|
||||
*** TODO efficient priority queues
|
||||
|
@ -125,8 +125,7 @@
|
|||
- State "DONE" [2009-12-08 Tue 14:39]
|
||||
** DONE only/except/rename/prefix modifiers
|
||||
- State "DONE" [2009-12-16 Wed 18:57]
|
||||
** DONE scheme-complete.el support
|
||||
- State "DONE" from "TODO" [2017-08-30 Wed 23:14]
|
||||
** TODO scheme-complete.el support
|
||||
** DONE access individual modules from repl
|
||||
- State "DONE" [2009-12-26 Sat 01:49]
|
||||
|
||||
|
@ -158,15 +157,11 @@
|
|||
- State "DONE" [2009-12-16 Wed 18:58]
|
||||
** DONE uri library
|
||||
- State "DONE" [2009-12-16 Wed 18:58]
|
||||
** DONE http library
|
||||
- State "DONE" from "TODO" [2015-04-09 Thu 01:22]
|
||||
** DONE show (formatting) library
|
||||
- State "DONE" from "TODO" [2015-04-09 Thu 01:22]
|
||||
** TODO http library
|
||||
** TODO show (formatting) library
|
||||
** TODO zip library
|
||||
** DONE tar library
|
||||
- State "DONE" from "TODO" [2015-04-09 Thu 01:22]
|
||||
** DONE md5sum library
|
||||
- State "DONE" from "TODO" [2015-04-09 Thu 01:22]
|
||||
** TODO tar library
|
||||
** TODO md5sum library
|
||||
|
||||
* ports
|
||||
** DONE basic mingw support
|
||||
|
@ -182,14 +177,11 @@
|
|||
* miscellaneous
|
||||
** DONE user documentation
|
||||
- State "DONE" from "TODO" [2011-11-10 Thu 20:45]
|
||||
** DONE full test suite for libraries
|
||||
- State "DONE" from "TODO" [2017-08-30 Wed 23:14]
|
||||
** TODO full test suite for libraries
|
||||
** TODO thorough source documentation
|
||||
|
||||
* distribution
|
||||
** DONE packaging format (Snow2)
|
||||
- State "DONE" from "TODO" [2015-04-09 Thu 01:22]
|
||||
** DONE code repository with fetch+install tool
|
||||
- State "DONE" from "TODO" [2015-04-09 Thu 01:22]
|
||||
** TODO packaging format (Snow2)
|
||||
** TODO code repository with fetch+install tool
|
||||
** TODO translator to/from other implementations
|
||||
|
||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
0.11.0
|
||||
0.6.1
|
||||
|
|
53
appveyor.yml
53
appveyor.yml
|
@ -1,53 +0,0 @@
|
|||
image: Visual Studio 2017
|
||||
|
||||
environment:
|
||||
matrix:
|
||||
- ARCH: x64
|
||||
TOOLCHAIN: MinGW
|
||||
BUILDSYSTEM: MSYS2
|
||||
- ARCH: x64
|
||||
TOOLCHAIN: MSYS
|
||||
BUILDSYSTEM: MSYS2
|
||||
- ARCH: x86
|
||||
TOOLCHAIN: MinGW
|
||||
BUILDSYSTEM: MSYS2
|
||||
- ARCH: x86
|
||||
TOOLCHAIN: MinGW
|
||||
BUILDSYSTEM: CMAKE
|
||||
- ARCH: x64
|
||||
TOOLCHAIN: MinGW
|
||||
BUILDSYSTEM: CMAKE
|
||||
- ARCH: x86
|
||||
TOOLCHAIN: MSVC
|
||||
BUILDSYSTEM: CMAKE
|
||||
- ARCH: x64
|
||||
TOOLCHAIN: MSVC
|
||||
BUILDSYSTEM: CMAKE
|
||||
|
||||
install:
|
||||
- if %BUILDSYSTEM%.==CMAKE. cinst ninja
|
||||
- if %BUILDSYSTEM%.==CMAKE. set PATH=c:/tools/ninja;%PATH%
|
||||
- if %TOOLCHAIN%%ARCH%.==MSVCx86. call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars32.bat"
|
||||
- if %TOOLCHAIN%%ARCH%.==MSVCx64. call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat"
|
||||
|
||||
before_build:
|
||||
- set BUILDTYPE= %ARCH%%TOOLCHAIN%
|
||||
- if %BUILDTYPE%.==x64MinGW. set PATH=c:\msys64\usr\bin;c:\msys64\mingw64\bin;%PATH%
|
||||
- if %BUILDTYPE%.==x86MinGW. set PATH=c:\msys64\usr\bin;c:\msys64\mingw32\bin;%PATH%
|
||||
- if %BUILDTYPE%.==x64MSYS. set PATH=c:\msys64\usr\bin;%PATH%
|
||||
- if %BUILDTYPE%.==x64MinGW. set CC=c:/msys64/mingw64/bin/gcc
|
||||
- if %BUILDTYPE%.==x86MinGW. set CC=c:/msys64/mingw32/bin/gcc
|
||||
- if %BUILDTYPE%.==x64MSYS. set CC=gcc
|
||||
- if %TOOLCHAIN%.==MSVC. set CC=cl.exe
|
||||
- if %TOOLCHAIN%%BUILDSYSTEM%.==MinGWMSYS2. set EXARG=
|
||||
- if %TOOLCHAIN%%BUILDSYSTEM%.==MSYSMSYS2. set EXARG=PLATFORM=msys
|
||||
- if %BUILDSYSTEM%.==CMAKE. cmake -G Ninja .
|
||||
|
||||
build_script:
|
||||
- if %BUILDSYSTEM%.==MSYS2. make CC=%CC% %EXARG%
|
||||
- if %BUILDSYSTEM%.==CMAKE. ninja
|
||||
|
||||
test_script:
|
||||
- if %BUILDSYSTEM%.==MSYS2. make CC=%CC% %EXARG% test
|
||||
- if %BUILDSYSTEM%.==CMAKE. ctest --verbose .
|
||||
|
|
@ -1,47 +1,25 @@
|
|||
|
||||
(import (chibi ast) (chibi time) (scheme cxr) (srfi 33) (srfi 39))
|
||||
(import (chibi time) (scheme cxr) (srfi 33) (srfi 39))
|
||||
|
||||
(define (timeval->milliseconds tv)
|
||||
(quotient (+ (* 1000000 (timeval-seconds tv)) (timeval-microseconds tv))
|
||||
1000))
|
||||
|
||||
(define (timeval-diff start end)
|
||||
(- (timeval->milliseconds end)
|
||||
(timeval->milliseconds start)))
|
||||
|
||||
(define (time* thunk)
|
||||
(call-with-output-string
|
||||
(lambda (out)
|
||||
(gc)
|
||||
(let* ((start (car (get-time-of-day)))
|
||||
(start-rusage (get-resource-usage))
|
||||
(gc-start (gc-usecs))
|
||||
(gc-start-count (gc-count))
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
(result (parameterize ((current-output-port out)) (thunk)))
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
(end (car (get-time-of-day)))
|
||||
(end-rusage (get-resource-usage))
|
||||
(gc-end (gc-usecs))
|
||||
(gc-msecs (quotient (- gc-end gc-start) 1000))
|
||||
(real-msecs (timeval-diff start end))
|
||||
(user-msecs
|
||||
(timeval-diff (resource-usage-time start-rusage)
|
||||
(resource-usage-time end-rusage)))
|
||||
(system-msecs
|
||||
(timeval-diff (resource-usage-system-time start-rusage)
|
||||
(resource-usage-system-time end-rusage))))
|
||||
(msecs (- (timeval->milliseconds end)
|
||||
(timeval->milliseconds start))))
|
||||
(display "user: ")
|
||||
(display user-msecs)
|
||||
(display " system: ")
|
||||
(display system-msecs)
|
||||
(display msecs)
|
||||
(display " system: 0")
|
||||
(display " real: ")
|
||||
(display real-msecs)
|
||||
(display " gc: ")
|
||||
(display gc-msecs)
|
||||
(display " (")
|
||||
(display (- (gc-count) gc-start-count))
|
||||
(display " times)\n")
|
||||
(display msecs)
|
||||
(display " gc: 0")
|
||||
(newline)
|
||||
(display "result: ")
|
||||
(write result)
|
||||
(newline)
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# set -ex
|
||||
|
||||
BENCHDIR=$(dirname $0)
|
||||
if [ "${BENCHDIR%%/*}" = "." ]; then
|
||||
BENCHDIR="$(pwd)${BENCHDIR#.}"
|
||||
fi
|
||||
|
||||
TS1="${1:--2}"
|
||||
TS2="${2:--1}"
|
||||
DB="${3:-${BENCHDIR}/times.tsv}"
|
||||
|
||||
if [ "$TS1" -lt 1000000000 ]; then
|
||||
SORT_OPTS='-nu'
|
||||
if [ "$TS1" -lt 0 ]; then
|
||||
SORT_OPTS='-nru'
|
||||
TS1=$((0 - TS1))
|
||||
fi
|
||||
TS1=$(cut -f 7 "$DB" | sort "$SORT_OPTS" | tail -n +$TS1 | head -1)
|
||||
fi
|
||||
if [ "$TS2" -lt 1000000000 ]; then
|
||||
SORT_OPTS='-nu'
|
||||
if [ "$TS2" -lt 0 ]; then
|
||||
SORT_OPTS='-nru'
|
||||
TS2=$((0 - TS2))
|
||||
fi
|
||||
TS2=$(cut -f 7 "$DB" | sort "$SORT_OPTS" | tail -n +$TS2 | head -1)
|
||||
fi
|
||||
|
||||
join -t $'\t' \
|
||||
<(grep $'\t'"$TS1"$'\t' "$DB" | cut -f 1-2,5) \
|
||||
<(grep $'\t'"$TS2"$'\t' "$DB" | cut -f 1-2,5) \
|
||||
| perl -F'\t' -ane 'sub gain{($_[0]<=0)?0:100*($_[1]-$_[0])/$_[0]} $u=gain($F[1], $F[3]); $g=gain($F[2], $F[4]); printf STDOUT "%s\t%d\t%d\t%.2f%%\t%d\t%d\t%.2f%%\n", $F[0], $F[1], $F[3], $u, $F[2], $F[4], $g'
|
|
@ -1 +0,0 @@
|
|||
1
|
|
@ -1,201 +0,0 @@
|
|||
;;; RAY -- Ray-trace a simple scene with spheres, generating a ".pgm" file.
|
||||
;;; Translated to Scheme from Paul Graham's book ANSI Common Lisp, Example 9.8
|
||||
|
||||
(import (scheme base)
|
||||
(scheme inexact)
|
||||
(scheme file)
|
||||
(scheme read)
|
||||
(scheme write)
|
||||
(scheme time))
|
||||
|
||||
(define (make-point x y z)
|
||||
(vector x y z))
|
||||
|
||||
(define (point-x p) (vector-ref p 0))
|
||||
(define (point-y p) (vector-ref p 1))
|
||||
(define (point-z p) (vector-ref p 2))
|
||||
|
||||
(define (sq x) (* x x))
|
||||
|
||||
(define (mag x y z)
|
||||
(sqrt (+ (sq x) (sq y) (sq z))))
|
||||
|
||||
(define (unit-vector x y z)
|
||||
(let ((d (mag x y z)))
|
||||
(make-point (/ x d) (/ y d) (/ z d))))
|
||||
|
||||
(define (distance p1 p2)
|
||||
(mag (- (point-x p1) (point-x p2))
|
||||
(- (point-y p1) (point-y p2))
|
||||
(- (point-z p1) (point-z p2))))
|
||||
|
||||
(define (minroot a b c)
|
||||
(if (zero? a)
|
||||
(/ (- c) b)
|
||||
(let ((disc (- (sq b) (* 4.0 a c))))
|
||||
(if (negative? disc)
|
||||
#f
|
||||
(let ((discrt (sqrt disc))
|
||||
(minus-b (- b))
|
||||
(two-a (* 2.0 a)))
|
||||
(min (/ (+ minus-b discrt) two-a)
|
||||
(/ (- minus-b discrt) two-a)))))))
|
||||
|
||||
(define *world* '())
|
||||
|
||||
(define eye (make-point 0.0 0.0 200.0))
|
||||
|
||||
(define (tracer pathname res)
|
||||
(if (file-exists? pathname)
|
||||
(delete-file pathname))
|
||||
(call-with-output-file
|
||||
pathname
|
||||
(lambda (p)
|
||||
(let ((extent (* res 100)))
|
||||
(display "P2 " p)
|
||||
(write extent p)
|
||||
(display " " p)
|
||||
(write extent p)
|
||||
(display " 255" p)
|
||||
(newline p)
|
||||
(do ((y 0 (+ y 1)))
|
||||
((= y extent))
|
||||
(do ((x 0 (+ x 1)))
|
||||
((= x extent))
|
||||
(write (color-at
|
||||
(+ -50.0
|
||||
(/ (inexact x) (inexact res)))
|
||||
(+ -50.0
|
||||
(/ (inexact y) (inexact res))))
|
||||
p)
|
||||
(newline p)))))))
|
||||
|
||||
(define (color-at x y)
|
||||
(let ((ray (unit-vector (- x (point-x eye))
|
||||
(- y (point-y eye))
|
||||
(- (point-z eye)))))
|
||||
(exact (round (* (sendray eye ray) 255.0)))))
|
||||
|
||||
|
||||
|
||||
(define (sendray pt ray)
|
||||
(let* ((x (first-hit pt ray))
|
||||
(s (vector-ref x 0))
|
||||
(int (vector-ref x 1)))
|
||||
(if s
|
||||
(* (lambert s int ray)
|
||||
(surface-color s))
|
||||
0.0)))
|
||||
|
||||
(define (first-hit pt ray)
|
||||
(let loop ((lst *world*) (surface #f) (hit #f) (dist 1e308))
|
||||
(if (null? lst)
|
||||
(vector surface hit)
|
||||
(let ((s (car lst)))
|
||||
(let ((h (intersect s pt ray)))
|
||||
(if h
|
||||
(let ((d (distance h pt)))
|
||||
(if (< d dist)
|
||||
(loop (cdr lst) s h d)
|
||||
(loop (cdr lst) surface hit dist)))
|
||||
(loop (cdr lst) surface hit dist)))))))
|
||||
|
||||
(define (lambert s int ray)
|
||||
(let ((n (normal s int)))
|
||||
(max 0.0
|
||||
(+ (* (point-x ray) (point-x n))
|
||||
(* (point-y ray) (point-y n))
|
||||
(* (point-z ray) (point-z n))))))
|
||||
|
||||
(define (make-sphere color radius center)
|
||||
(vector color radius center))
|
||||
|
||||
(define (sphere-color s) (vector-ref s 0))
|
||||
(define (sphere-radius s) (vector-ref s 1))
|
||||
(define (sphere-center s) (vector-ref s 2))
|
||||
|
||||
(define (defsphere x y z r c)
|
||||
(let ((s (make-sphere c r (make-point x y z))))
|
||||
(set! *world* (cons s *world*))
|
||||
s))
|
||||
|
||||
(define (surface-color s)
|
||||
(sphere-color s))
|
||||
|
||||
(define (intersect s pt ray)
|
||||
(sphere-intersect s pt ray))
|
||||
|
||||
(define (sphere-intersect s pt ray)
|
||||
(let* ((xr (point-x ray))
|
||||
(yr (point-y ray))
|
||||
(zr (point-z ray))
|
||||
(c (sphere-center s))
|
||||
(n (minroot
|
||||
(+ (sq xr) (sq yr) (sq zr))
|
||||
(* 2.0
|
||||
(+ (* (- (point-x pt) (point-x c)) xr)
|
||||
(* (- (point-y pt) (point-y c)) yr)
|
||||
(* (- (point-z pt) (point-z c)) zr)))
|
||||
(+ (sq (- (point-x pt) (point-x c)))
|
||||
(sq (- (point-y pt) (point-y c)))
|
||||
(sq (- (point-z pt) (point-z c)))
|
||||
(- (sq (sphere-radius s)))))))
|
||||
(if n
|
||||
(make-point (+ (point-x pt) (* n xr))
|
||||
(+ (point-y pt) (* n yr))
|
||||
(+ (point-z pt) (* n zr)))
|
||||
#f)))
|
||||
|
||||
(define (normal s pt)
|
||||
(sphere-normal s pt))
|
||||
|
||||
(define (sphere-normal s pt)
|
||||
(let ((c (sphere-center s)))
|
||||
(unit-vector (- (point-x c) (point-x pt))
|
||||
(- (point-y c) (point-y pt))
|
||||
(- (point-z c) (point-z pt)))))
|
||||
|
||||
(define (ray-test res output-file)
|
||||
(set! *world* '())
|
||||
(defsphere 0.0 -300.0 -1200.0 200.0 0.8)
|
||||
(defsphere -80.0 -150.0 -1200.0 200.0 0.7)
|
||||
(defsphere 70.0 -100.0 -1200.0 200.0 0.9)
|
||||
(do ((x -2 (+ x 1)))
|
||||
((> x 2))
|
||||
(do ((z 2 (+ z 1)))
|
||||
((> z 7))
|
||||
(defsphere
|
||||
(* (inexact x) 200.0)
|
||||
300.0
|
||||
(* (inexact z) -400.0)
|
||||
40.0
|
||||
0.75)))
|
||||
(tracer output-file res))
|
||||
|
||||
(define (run input output)
|
||||
(ray-test input output)
|
||||
'ok)
|
||||
|
||||
(define (hide count input)
|
||||
input)
|
||||
|
||||
(define (run-r7rs-benchmark name count thunk verify?)
|
||||
(do ((i 0 (+ i 1))
|
||||
(res #f (thunk)))
|
||||
((= i count)
|
||||
(if (not (verify? res))
|
||||
(error "bad output" res)))))
|
||||
|
||||
(define (main)
|
||||
(let* ((count (read))
|
||||
(input1 (read))
|
||||
(input2 (read))
|
||||
(output (read))
|
||||
(s2 (number->string count))
|
||||
(s1 (number->string input1))
|
||||
(name "ray"))
|
||||
(run-r7rs-benchmark
|
||||
(string-append name ":" s2)
|
||||
count
|
||||
(lambda () (run (hide count input1) (hide count input2)))
|
||||
(lambda (result) (equal? result output)))))
|
|
@ -1,32 +1,16 @@
|
|||
#!/bin/sh
|
||||
|
||||
# set -ex
|
||||
|
||||
BENCHDIR=$(dirname $0)
|
||||
if [ "${BENCHDIR%%/*}" = "." ]; then
|
||||
BENCHDIR="$(pwd)${BENCHDIR#.}"
|
||||
if [ "${BENCHDIR%%/*}" == "." ]; then
|
||||
BENCHDIR=$(pwd)${BENCHDIR#.}
|
||||
fi
|
||||
OUTPUT="$BENCHDIR/out.txt"
|
||||
DB="$BENCHDIR/times.tsv"
|
||||
CHIBIHOME="${BENCHDIR%%/benchmarks/gabriel}"
|
||||
CHIBIHOME=${BENCHDIR%%/benchmarks/gabriel}
|
||||
CHIBI="${CHIBI:-${CHIBIHOME}/chibi-scheme} -I$CHIBIHOME"
|
||||
HEAP="2M"
|
||||
|
||||
cd "$BENCHDIR"
|
||||
cd $BENCHDIR
|
||||
for t in *.sch; do
|
||||
echo "program: ${t%%.sch}"
|
||||
echo "${t%%.sch}"
|
||||
LD_LIBRARY_PATH="$CHIBIHOME" DYLD_LIBRARY_PATH="$CHIBIHOME" \
|
||||
$CHIBI -I"$CHIBIHOME/lib" -h"$HEAP" -q -lchibi-prelude.scm "$t"
|
||||
done | tee "$OUTPUT"
|
||||
$CHIBI -I"$CHIBIHOME/lib" -lchibi-prelude.scm $t
|
||||
done
|
||||
cd -
|
||||
|
||||
if [ ! -f "$DB" ]; then
|
||||
echo $'program\tuser_ms\tsystem_ms\treal_ms\tgc_ms\tgc_count\ttimestamp\tcommit\tfeatures\tinit_heap\tcpu' > "$DB"
|
||||
fi
|
||||
|
||||
#DATE=$(date -Iseconds)
|
||||
DATE=$(date +%s)
|
||||
COMMIT=$(git -C "$CHIBIHOME" rev-parse HEAD)
|
||||
FEATURES=$(LD_LIBRARY_PATH="$CHIBIHOME" DYLD_LIBRARY_PATH="$CHIBIHOME" $CHIBI -q -p'(cddr *features*)' | tr ' ' , | tr -d '()')
|
||||
CPU=$(lscpu | perl -ne 'if (s/^Model name:\s*//){s/\b(Intel|Core|Atom|AMD|CPU)(\s*\(\w+\))?\s*//gi;s/\s*@\s*[.\d]+[KMGT]Hz\b\s*//gi;print}')
|
||||
perl -ane 'if (/^program:\s*(\w+)/) {$p=$1} elsif (/^user:\s*(\d+)\s*system:\s*(\d+)\s*real:\s*(\d+)(?:\s*gc:\s*(\d+)\s*(?:\((\d+)\s*times\))?)?/) {print"$p\t$1\t$2\t$3\t$4\t$5\t'"$DATE"'\t'"$COMMIT"'\t'"$FEATURES"'\t'"$HEAP"'\t'"$CPU"'\n"}' "$OUTPUT" >> "$DB"
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
;; This code is written by Alex Shinn and placed in the
|
||||
;; Public Domain. All warranties are disclaimed.
|
||||
|
||||
(define char-set:letter+digit
|
||||
(immutable-char-set (char-set-union char-set:letter char-set:digit)))
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
|
||||
;; Don't import this - it's temporarily used to compute optimized
|
||||
;; char-set representations.
|
||||
|
||||
(define-library (chibi char-set width)
|
||||
(import (chibi) (chibi iset) (chibi char-set))
|
||||
(include "width.scm")
|
||||
(export
|
||||
char-set:zero-width
|
||||
char-set:full-width
|
||||
char-set:ambiguous-width
|
||||
))
|
|
@ -1,7 +0,0 @@
|
|||
Name: chibi-scheme
|
||||
URL: http://synthcode.com/scheme/chibi/
|
||||
Description: Minimal Scheme Implementation for use as an Extension Language
|
||||
Version: ${version}
|
||||
Libs: -L${libdir} -lchibi-scheme
|
||||
Libs.private: -dl -lm
|
||||
Cflags: -I${includedir}
|
206
chibi-scheme.vcproj
Normal file
206
chibi-scheme.vcproj
Normal file
|
@ -0,0 +1,206 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9.00"
|
||||
Name="chibi-scheme"
|
||||
ProjectGUID="{38DC39DA-5328-4FFE-84E2-E16FF1864945}"
|
||||
RootNamespace="chibi-scheme"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="0"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="Debug"
|
||||
IntermediateDirectory="Debug"
|
||||
ConfigurationType="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="include"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;CHIBISCHEME_EXPORTS"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="Release"
|
||||
IntermediateDirectory="Release"
|
||||
ConfigurationType="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;CHIBISCHEME_EXPORTS;"
|
||||
RuntimeLibrary="2"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="2"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\eval.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\main.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\sexp.c"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions="-DPLATFORM=mingw;-DSEXP_USE_STRING_STREAMS=0;-DSEXP_USE_DEBUG=0;-DSEXP_USE_DL=0;-DBUILDING_DLL"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
5
configure
vendored
5
configure
vendored
|
@ -1,5 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
echo "Autoconf is an evil piece bloatware encouraging cargo-cult programming."
|
||||
echo "Make, on the other hand, is a beautiful little prolog for the filesystem."
|
||||
echo "Just run 'make'."
|
|
@ -26,9 +26,6 @@ _chibi-scheme() {
|
|||
-x*)
|
||||
COMPREPLY=( $( compgen -W "$(_chibi-modules | sed 's!^!-x!')" -- "$cur") )
|
||||
return 0;;
|
||||
-R*)
|
||||
COMPREPLY=( $( compgen -W "$(_chibi-modules | sed 's!^!-R!')" -- "$cur") )
|
||||
return 0;;
|
||||
-l*)
|
||||
compopt -o nospace
|
||||
_filedir
|
||||
|
@ -45,7 +42,7 @@ _chibi-scheme() {
|
|||
COMPREPLY=( $( compgen -W "$(echo $sizes | tr ' ' '\n' | sed 's!^!-h!')" -- "${cur}" ) )
|
||||
return 0;;
|
||||
-)
|
||||
COMPREPLY=( $( compgen -W '-d -e -f -h -i -l -m -p -q -x -A -I -R -V' \
|
||||
COMPREPLY=( $( compgen -W '-d -e -f -h -i -l -m -p -q -x -A -I -V' \
|
||||
-- "$cur") )
|
||||
return 0;;
|
||||
-*)
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
|
||||
execute_process(
|
||||
COMMAND find ${LIBDIR} -name "*.sld"
|
||||
COMMAND ${EXEC} ${GENMETA} ${VERSION}
|
||||
OUTPUT_FILE ${OUT}
|
||||
RESULT_VARIABLE error)
|
||||
|
||||
if(error)
|
||||
message(FATAL_ERROR "${error}")
|
||||
endif()
|
|
@ -1,27 +0,0 @@
|
|||
#
|
||||
# chibi-genstatic-helper.cmake
|
||||
#
|
||||
# INPUT:
|
||||
# ROOT=<DIR>
|
||||
# EXEC=<EXECUTABLE>
|
||||
# GENSTATIC=<FILE>
|
||||
# STUBS=<FILE>
|
||||
# OUT=<FILE>
|
||||
if(NOT EXEC)
|
||||
message(FATAL_ERROR "huh?")
|
||||
endif()
|
||||
|
||||
if(NOT OUT)
|
||||
message(FATAL_ERROR "huh?")
|
||||
endif()
|
||||
|
||||
execute_process(
|
||||
COMMAND ${EXEC} ${GENSTATIC} --no-inline
|
||||
INPUT_FILE ${STUBS}
|
||||
OUTPUT_FILE ${OUT}
|
||||
RESULT_VARIABLE rr
|
||||
)
|
||||
|
||||
if(rr)
|
||||
message(FATAL_ERROR "Error: ${rr}")
|
||||
endif()
|
|
@ -1,2 +0,0 @@
|
|||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/chibi-scheme-targets.cmake)
|
|
@ -1,14 +0,0 @@
|
|||
# pkg-config
|
||||
prefix=@CMAKE_INSTALL_PREFIX@
|
||||
exec_prefix=@CMAKE_INSTALL_FULL_BINDIR@
|
||||
libdir=@CMAKE_INSTALL_FULL_LIBDIR@
|
||||
includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
|
||||
version=@CMAKE_PROJECT_VERSION@
|
||||
|
||||
Name: chibi-scheme
|
||||
URL: http://synthcode.com/scheme/chibi/
|
||||
Description: Minimal Scheme Implementation for use as an Extension Language
|
||||
Version: ${version}
|
||||
Libs: -L${libdir} -lchibi-scheme
|
||||
Libs.private: -dl -lm
|
||||
Cflags: -I${includedir}
|
|
@ -1,439 +0,0 @@
|
|||
;; scheme-keywords.el
|
||||
;; Scheme R7RS-small syntax highlighting and keyword completion for GNU Emacs
|
||||
;; Copyright (c) 2015 Frère Jérôme. Contributed to the `Chibi-Scheme' project
|
||||
;; under the same BSD-style license: http://synthcode.com/license.txt
|
||||
|
||||
;; The *optional* keyword completion is provided by the `company' framework
|
||||
;; See: https://company-mode.github.io
|
||||
|
||||
;; Installation:
|
||||
|
||||
;; If necessary, add the location of this file to your Emacs `load-path':
|
||||
;; (add-to-list 'load-path "FILE LOCATION")
|
||||
|
||||
;; Add the following lines to your `.emacs' configuration file:
|
||||
;; (when (require 'scheme-keywords nil t)
|
||||
;; (add-to-list 'auto-mode-alist '("\\.sld\\'" . scheme-mode))
|
||||
;; ;; CUSTOMIZATION HERE
|
||||
;; )
|
||||
|
||||
;; Customization:
|
||||
|
||||
;; (scheme-add-keywords 'LIST 'FACE) ;; define additional highlights
|
||||
;; (setq scheme-keywords-completions 'LIST) ;; define additional completions
|
||||
|
||||
(require 'company nil t)
|
||||
(require 'cl)
|
||||
|
||||
(defconst scheme-procedures-list
|
||||
'("and"
|
||||
"begin"
|
||||
"call\/cc"
|
||||
"call-with-current-continuation"
|
||||
"call-with-input-file"
|
||||
"call-with-output-file"
|
||||
"call-with-port"
|
||||
"call-with-values"
|
||||
"case"
|
||||
"case-lambda"
|
||||
"cond"
|
||||
"cond-expand"
|
||||
"cons"
|
||||
"define"
|
||||
"define-library"
|
||||
"define-record-type"
|
||||
"define-syntax"
|
||||
"define-values"
|
||||
"delay"
|
||||
"delay-force"
|
||||
"do"
|
||||
"dynamic-wind"
|
||||
"else"
|
||||
"eof-object"
|
||||
"export"
|
||||
"features"
|
||||
"force"
|
||||
"for-each"
|
||||
"if"
|
||||
"import"
|
||||
"include"
|
||||
"include-ci"
|
||||
"lambda"
|
||||
"let"
|
||||
"let\*"
|
||||
"letrec"
|
||||
"letrec\*"
|
||||
"letrec-syntax"
|
||||
"let-syntax"
|
||||
"let-values"
|
||||
"let\*-values"
|
||||
"library"
|
||||
"list"
|
||||
"load"
|
||||
"not"
|
||||
"or"
|
||||
"quasiquote"
|
||||
"quote"
|
||||
"scheme-report-environment"
|
||||
"syntax-error"
|
||||
"syntax-rules"
|
||||
"unless"
|
||||
"unquote"
|
||||
"unquote-splicing"
|
||||
"values"
|
||||
"when"))
|
||||
|
||||
(defconst scheme-operators-list
|
||||
'("\<"
|
||||
"\<\="
|
||||
"\="
|
||||
"\=\>"
|
||||
"\>"
|
||||
"\>\="
|
||||
"\_"
|
||||
"\-"
|
||||
"\/"
|
||||
"\.\.\."
|
||||
"\*"
|
||||
"\+"
|
||||
"caaaar"
|
||||
"caaadr"
|
||||
"caaar"
|
||||
"caadar"
|
||||
"caaddr"
|
||||
"caadr"
|
||||
"caar"
|
||||
"cadaar"
|
||||
"cadadr"
|
||||
"cadar"
|
||||
"caddar"
|
||||
"cadddr"
|
||||
"caddr"
|
||||
"cadr"
|
||||
"car"
|
||||
"cdaaar"
|
||||
"cdaadr"
|
||||
"cdaar"
|
||||
"cdadar"
|
||||
"cdaddr"
|
||||
"cdadr"
|
||||
"cdar"
|
||||
"cddaar"
|
||||
"cddadr"
|
||||
"cddar"
|
||||
"cdddar"
|
||||
"cddddr"
|
||||
"cdddr"
|
||||
"cddr"
|
||||
"cdr"
|
||||
"\#f"
|
||||
"\#false"
|
||||
"\#t"
|
||||
"\#true"))
|
||||
|
||||
(defconst scheme-predicates-list
|
||||
'("binary-port\?"
|
||||
"boolean\=\?"
|
||||
"boolean\?"
|
||||
"bytevector"
|
||||
"bytevector\?"
|
||||
"char\<\=\?"
|
||||
"char\<\?"
|
||||
"char\=\?"
|
||||
"char\>\=\?"
|
||||
"char\>\?"
|
||||
"char\?"
|
||||
"char-alphabetic\?"
|
||||
"char-ci\<\=\?"
|
||||
"char-ci\<\?"
|
||||
"char-ci\=\?"
|
||||
"char-ci\>\=\?"
|
||||
"char-ci\>\?"
|
||||
"char-numeric\?"
|
||||
"char-ready\?"
|
||||
"char-lower-case\?"
|
||||
"char-upper-case\?"
|
||||
"char-whitespace\?"
|
||||
"complex\?"
|
||||
"eof-object\?"
|
||||
"eq\?"
|
||||
"equal\?"
|
||||
"eqv\?"
|
||||
"error-object\?"
|
||||
"even\?"
|
||||
"exact\?"
|
||||
"exact-integer\?"
|
||||
"file-error\?"
|
||||
"file-exists\?"
|
||||
"finite\?"
|
||||
"inexact\?"
|
||||
"infinite\?"
|
||||
"input-port\?"
|
||||
"input-port-open\?"
|
||||
"integer\?"
|
||||
"list\?"
|
||||
"nan\?"
|
||||
"negative\?"
|
||||
"null\?"
|
||||
"number\?"
|
||||
"odd\?"
|
||||
"output-port\?"
|
||||
"output-port-open\?"
|
||||
"pair\?"
|
||||
"port\?"
|
||||
"positive\?"
|
||||
"procedure\?"
|
||||
"promise\?"
|
||||
"rational\?"
|
||||
"read-error\?"
|
||||
"real\?"
|
||||
"string\<\=\?"
|
||||
"string\<\?"
|
||||
"string\=\?"
|
||||
"string\>\=\?"
|
||||
"string\>\?"
|
||||
"string\?"
|
||||
"string-ci\<\=\?"
|
||||
"string-ci\<\?"
|
||||
"string-ci\=\?"
|
||||
"string-ci\>\=\?"
|
||||
"string-ci\>\?"
|
||||
"symbol\=\?"
|
||||
"symbol\?"
|
||||
"textual-port\?"
|
||||
"u8-ready\?"
|
||||
"vector\?"
|
||||
"zero\?"))
|
||||
|
||||
(defconst scheme-mutations-list
|
||||
'("bytevector-copy\!"
|
||||
"bytevector-u8-set\!"
|
||||
"list-set\!"
|
||||
"read-bytevector\!"
|
||||
"set\!"
|
||||
"set-car\!"
|
||||
"set-cdr\!"
|
||||
"string-copy\!"
|
||||
"string-fill\!"
|
||||
"string-set\!"
|
||||
"vector-copy\!"
|
||||
"vector-fill\!"
|
||||
"vector-set\!"))
|
||||
|
||||
(defconst scheme-exceptions-list
|
||||
'("emergency-exit"
|
||||
"error"
|
||||
"error-object-message"
|
||||
"error-object-irritants"
|
||||
"exit"
|
||||
"guard"
|
||||
"raise"
|
||||
"raise-continuable"
|
||||
"with-exception-handler"))
|
||||
|
||||
(defconst scheme-functions-list
|
||||
'("abs"
|
||||
"acos"
|
||||
"angle"
|
||||
"append"
|
||||
"apply"
|
||||
"asin"
|
||||
"assoc"
|
||||
"assq"
|
||||
"assv"
|
||||
"atan"
|
||||
"bytevector"
|
||||
"bytevector-append"
|
||||
"bytevector-copy"
|
||||
"bytevector-length"
|
||||
"bytevector-u8-ref"
|
||||
"ceiling"
|
||||
"ceiling\/"
|
||||
"ceiling-quotient"
|
||||
"ceiling-remainder"
|
||||
"centered\/"
|
||||
"centered-quotient"
|
||||
"centered-remainder"
|
||||
"char-downcase"
|
||||
"char-foldcase"
|
||||
"char-\>integer"
|
||||
"char-upcase"
|
||||
"close-input-port"
|
||||
"close-output-port"
|
||||
"close-port"
|
||||
"command-line"
|
||||
"cos"
|
||||
"current-error-port"
|
||||
"current-input-port"
|
||||
"current-jiffy"
|
||||
"current-output-port"
|
||||
"current-second"
|
||||
"delete-file"
|
||||
"denominator"
|
||||
"digit-value"
|
||||
"display"
|
||||
"environment"
|
||||
"euclidean\/"
|
||||
"euclidean-quotient"
|
||||
"euclidean-remainder"
|
||||
"exact"
|
||||
"exact-\>inexact"
|
||||
"exact-integer-sqrt"
|
||||
"exp"
|
||||
"expt"
|
||||
"floor"
|
||||
"floor\/"
|
||||
"floor-quotient"
|
||||
"floor-remainder"
|
||||
"flush-output-port"
|
||||
"gcd"
|
||||
"get-environment-variable"
|
||||
"get-environment-variables"
|
||||
"get-output-bytevector"
|
||||
"get-output-string"
|
||||
"imag-part"
|
||||
"inexact"
|
||||
"inexact-\>exact"
|
||||
"integer-\>char"
|
||||
"interaction-environment"
|
||||
"jiffies-per-second"
|
||||
"lcm"
|
||||
"length"
|
||||
"list-copy"
|
||||
"list-ref"
|
||||
"list-\>string"
|
||||
"list-tail"
|
||||
"list-\>vector"
|
||||
"log"
|
||||
"magnitude"
|
||||
"make-bytevector"
|
||||
"make-list"
|
||||
"make-parameter"
|
||||
"make-polar"
|
||||
"make-promise"
|
||||
"make-rectangular"
|
||||
"make-string"
|
||||
"make-vector"
|
||||
"map"
|
||||
"max"
|
||||
"member"
|
||||
"memq"
|
||||
"memv"
|
||||
"min"
|
||||
"modulo"
|
||||
"newline"
|
||||
"null-environment"
|
||||
"number-\>string"
|
||||
"numerator"
|
||||
"open-binary-input-file"
|
||||
"open-binary-output-file"
|
||||
"open-input-bytevector"
|
||||
"open-input-file"
|
||||
"open-input-string"
|
||||
"open-output-bytevector"
|
||||
"open-output-file"
|
||||
"open-output-string"
|
||||
"parameterize"
|
||||
"peek-char"
|
||||
"peek-u8"
|
||||
"quotient"
|
||||
"rationalize"
|
||||
"read"
|
||||
"read-bytevector"
|
||||
"read-char"
|
||||
"read-line"
|
||||
"read-string"
|
||||
"read-u8"
|
||||
"real-part"
|
||||
"remainder"
|
||||
"reverse"
|
||||
"round"
|
||||
"round\/"
|
||||
"round-quotient"
|
||||
"round-remainder"
|
||||
"sin"
|
||||
"sqrt"
|
||||
"square"
|
||||
"string"
|
||||
"string-append"
|
||||
"string-copy"
|
||||
"string-downcase"
|
||||
"string-foldcase"
|
||||
"string-for-each"
|
||||
"string-length"
|
||||
"string-\>list"
|
||||
"string-map"
|
||||
"string-\>number"
|
||||
"string-ref"
|
||||
"string-\>symbol"
|
||||
"string-upcase"
|
||||
"string-\>utf8"
|
||||
"string-\>vector"
|
||||
"substring"
|
||||
"symbol-\>string"
|
||||
"tan"
|
||||
"truncate"
|
||||
"truncate\/"
|
||||
"truncate-quotient"
|
||||
"truncate-remainder"
|
||||
"utf8-\>string"
|
||||
"vector"
|
||||
"vector-append"
|
||||
"vector-copy"
|
||||
"vector-for-each"
|
||||
"vector-length"
|
||||
"vector-\>list"
|
||||
"vector-map"
|
||||
"vector-ref"
|
||||
"vector-\>string"
|
||||
"with-input-from-file"
|
||||
"with-output-to-file"
|
||||
"write"
|
||||
"write-bytevector"
|
||||
"write-char"
|
||||
"write-shared"
|
||||
"write-simple"
|
||||
"write-string"
|
||||
"write-u8"))
|
||||
|
||||
(defvar scheme-keywords-completions '())
|
||||
|
||||
(defun scheme-add-keywords (keywords face)
|
||||
"Add keywords to Scheme mode."
|
||||
(interactive (list 'interactive))
|
||||
(let ((keyword-list (concat "\\<\\(" (regexp-opt keywords) "\\)\\>")))
|
||||
(font-lock-add-keywords 'scheme-mode
|
||||
`((,keyword-list 1 ',face)))))
|
||||
|
||||
(scheme-add-keywords scheme-procedures-list
|
||||
'font-lock-keyword-face)
|
||||
(scheme-add-keywords scheme-operators-list
|
||||
'font-lock-builtin-face)
|
||||
(scheme-add-keywords scheme-predicates-list
|
||||
'font-lock-type-face)
|
||||
(scheme-add-keywords scheme-mutations-list
|
||||
'font-lock-type-face)
|
||||
(scheme-add-keywords scheme-exceptions-list
|
||||
'font-lock-warning-face)
|
||||
(scheme-add-keywords scheme-functions-list
|
||||
'font-lock-function-name-face)
|
||||
|
||||
(defun scheme-keywords-hook ()
|
||||
(when (featurep 'company)
|
||||
(defun company-scheme-keywords
|
||||
(command &optional argument &rest ignored)
|
||||
(interactive (list 'interactive))
|
||||
(case command
|
||||
(interactive (company-begin-backend 'company-scheme-keywords))
|
||||
(prefix (and (eq major-mode 'scheme-mode) (company-grab-symbol)))
|
||||
(candidates (remove-if-not
|
||||
(lambda (candidate)
|
||||
(string-prefix-p argument candidate))
|
||||
(append scheme-procedures-list scheme-operators-list
|
||||
scheme-predicates-list scheme-mutations-list
|
||||
scheme-exceptions-list scheme-functions-list
|
||||
scheme-keywords-completions)))))
|
||||
(add-to-list 'company-backends 'company-scheme-keywords)))
|
||||
(add-hook 'scheme-mode-hook 'scheme-keywords-hook)
|
||||
|
||||
(provide 'scheme-keywords)
|
2
data/.gitignore
vendored
2
data/.gitignore
vendored
|
@ -1,2 +0,0 @@
|
|||
# downloaded unicode standard files
|
||||
*.txt
|
|
@ -6,7 +6,6 @@ chibi-doc \- generate docs from Scheme scribble syntax
|
|||
|
||||
.SH SYNOPSIS
|
||||
.B chibi-doc
|
||||
[-hst]
|
||||
[
|
||||
.I file
|
||||
]
|
||||
|
@ -14,9 +13,6 @@ chibi-doc \- generate docs from Scheme scribble syntax
|
|||
|
||||
.B chibi-doc
|
||||
.I dotted-name.of.module
|
||||
[
|
||||
.I identifier
|
||||
]
|
||||
.BR
|
||||
.SP 0.4
|
||||
|
||||
|
@ -33,17 +29,6 @@ comments are any line beginning with the characters
|
|||
|
||||
The scribble syntax is described in the manual.
|
||||
|
||||
.SH OPTIONS
|
||||
.TP 5
|
||||
.BI -h
|
||||
Outputs in HTML format (the default).
|
||||
.TP
|
||||
.BI -s
|
||||
Outputs in SXML format.
|
||||
.TP
|
||||
.BI -t
|
||||
Outputs in text format (the default for describing a single variable).
|
||||
|
||||
.SH AUTHORS
|
||||
.PP
|
||||
Alex Shinn (alexshinn @ gmail . com)
|
||||
|
@ -52,4 +37,4 @@ Alex Shinn (alexshinn @ gmail . com)
|
|||
.PP
|
||||
The chibi-scheme home-page:
|
||||
.BR
|
||||
https://github.com/ashinn/chibi-scheme/
|
||||
http://code.google.com/p/chibi-scheme/
|
||||
|
|
|
@ -42,4 +42,4 @@ Alex Shinn (alexshinn @ gmail . com)
|
|||
.PP
|
||||
The chibi-scheme home-page:
|
||||
.BR
|
||||
https://github.com/ashinn/chibi-scheme/
|
||||
http://code.google.com/p/chibi-scheme/
|
||||
|
|
|
@ -6,16 +6,13 @@ chibi-scheme \- a tiny Scheme interpreter
|
|||
|
||||
.SH SYNOPSIS
|
||||
.B chibi-scheme
|
||||
[-qQrRfTV]
|
||||
[-qrfV]
|
||||
[-I
|
||||
.I path
|
||||
]
|
||||
[-A
|
||||
.I path
|
||||
]
|
||||
[-D
|
||||
.I feature
|
||||
]
|
||||
[-m
|
||||
.I module
|
||||
]
|
||||
|
@ -31,9 +28,6 @@ chibi-scheme \- a tiny Scheme interpreter
|
|||
[-p
|
||||
.I expr
|
||||
]
|
||||
[-t
|
||||
.I module.id
|
||||
]
|
||||
[-d
|
||||
.I image-file
|
||||
]
|
||||
|
@ -75,85 +69,29 @@ program. Signals aren't caught either - to enable handling keyboard
|
|||
interrupts you can use the (chibi process) module. For a more
|
||||
sophisticated REPL with readline support, signal handling, module
|
||||
management and smarter read/write you may want to use the (chibi repl)
|
||||
module. This can be launched automatically with:
|
||||
.I chibi-scheme -R
|
||||
\[char46]
|
||||
module. For example,
|
||||
.I chibi-scheme -mchibi.repl -e'(repl)'
|
||||
|
||||
For convenience the default language is the
|
||||
(scheme small) module, which includes every library in the R7RS
|
||||
small standard, and transitively some other dependencies. All of this
|
||||
together is actually quite large, so for a more minimal startup
|
||||
language you'll want to use the
|
||||
.I -x module
|
||||
option described below.
|
||||
To get a mostly R5RS-compatible language, use
|
||||
.I chibi-scheme -xscheme.r5rs
|
||||
or to get just the core language used for bootstrapping, use
|
||||
.I chibi-scheme -xchibi
|
||||
or its shortcut
|
||||
.I chibi-scheme -q
|
||||
\[char46]
|
||||
The default language is an extended subset of the draft R7RS
|
||||
(scheme base) module. To get exactly the base module, use
|
||||
.I chibi-scheme -xscheme.base
|
||||
|
||||
.SH OPTIONS
|
||||
|
||||
Space is optional between options and their arguments. Options
|
||||
without arguments may not be chained together.
|
||||
|
||||
To reduce the need for shell escapes, options with module arguments
|
||||
(
|
||||
.I -m
|
||||
,
|
||||
.I -x
|
||||
and
|
||||
.I -R
|
||||
) are written in a dot notation, so that the module
|
||||
.I (foo bar)
|
||||
is written as
|
||||
.I foo.bar
|
||||
\[char46]
|
||||
|
||||
.TP 5
|
||||
.BI -V
|
||||
Prints the version information and exits.
|
||||
.TP
|
||||
.BI -q
|
||||
"Quick" load, shortcut for
|
||||
.I chibi-scheme -xchibi
|
||||
This is a slightly different language from (scheme base),
|
||||
which may load faster, and is guaranteed not to load any
|
||||
additional shared libraries.
|
||||
Don't load the initialization file. The resulting
|
||||
environment will only contain the core syntactic forms
|
||||
and primitives coded in C.
|
||||
.TP
|
||||
.BI -Q
|
||||
Extra "quick" load, shortcut for
|
||||
.I chibi-scheme -xchibi.primitive
|
||||
The resulting environment will only contain the core syntactic
|
||||
forms and primitives coded in C. This is very fast and guaranteed
|
||||
not to load any external files, but is also very limited.
|
||||
.TP
|
||||
.BI -r [main]
|
||||
.BI -r
|
||||
Run the "main" procedure when the script finishes loading as in SRFI-22.
|
||||
.TP
|
||||
.BI -R [module]
|
||||
Loads the given module and runs the "main" procedure it defines (which
|
||||
need not be exported) with a single argument of the list of command-line
|
||||
arguments as in SRFI-22. The name "main" can be overridden with the -r
|
||||
option.
|
||||
.I [module]
|
||||
may be omitted, in which case it defaults to chibi.repl. Thus
|
||||
.I chibi-scheme -R
|
||||
is the recommended means to obtain the advanced REPL.
|
||||
.TP
|
||||
.BI -s
|
||||
Strict mode, escalating warnings to fatal errors.
|
||||
.TP
|
||||
.BI -f
|
||||
Change the reader to case-fold symbols as in R5RS.
|
||||
.TP
|
||||
.BI -T
|
||||
Disables tail-call optimization. This can be useful for
|
||||
debugging in some cases, but also makes it very likely to
|
||||
overflow the stack.
|
||||
.TP
|
||||
.BI -h size[/max_size]
|
||||
Specifies the initial size of the heap, in bytes,
|
||||
optionally followed by the maximum size the heap can
|
||||
|
@ -175,12 +113,6 @@ Appends
|
|||
.I path
|
||||
to the load path list.
|
||||
.TP
|
||||
.BI -D feature
|
||||
Adds
|
||||
.I feature
|
||||
to the feature list, useful for cond-expanding different
|
||||
library code.
|
||||
.TP
|
||||
.BI -m module
|
||||
.TP
|
||||
.BI -x module
|
||||
|
@ -188,7 +120,11 @@ Imports
|
|||
.I module
|
||||
as though "(import
|
||||
.I module
|
||||
)" were evaluated.
|
||||
)" were evaluated. However, to reduce the need for shell
|
||||
escapes, modules are written in a dot notation, so that the module
|
||||
.I (foo bar)
|
||||
is written as
|
||||
.I foo.bar
|
||||
If the
|
||||
.BI -x
|
||||
version is used, then
|
||||
|
@ -209,12 +145,6 @@ Evaluates the Scheme expression
|
|||
.I expr
|
||||
then prints the result to stdout.
|
||||
.TP
|
||||
.BI -t module.id
|
||||
Enables tracing for the given identifier
|
||||
.I id
|
||||
in the module
|
||||
.I module.
|
||||
.TP
|
||||
.BI -d image-file
|
||||
Dumps the current Scheme heap to
|
||||
.I image-file
|
||||
|
@ -225,35 +155,13 @@ Loads the Scheme heap from
|
|||
.I image-file
|
||||
instead of compiling the init file on the fly.
|
||||
This feature is still experimental.
|
||||
.TP
|
||||
.BI -b
|
||||
Makes stdio nonblocking (blocking by default). Only available when
|
||||
lightweight threads are enabled.
|
||||
|
||||
.SH ENVIRONMENT
|
||||
.TP
|
||||
.B CHIBI_MODULE_PATH
|
||||
.TQ
|
||||
A colon separated list of directories to search for module
|
||||
files, inserted before the system default load paths. chibi-scheme
|
||||
searches for modules in directories in the following order:
|
||||
|
||||
.TP
|
||||
directories included with the -I path option
|
||||
.TP
|
||||
directories included from CHIBI_MODULE_PATH
|
||||
.TP
|
||||
system directories
|
||||
.TP
|
||||
directories included with -A path option
|
||||
|
||||
If CHIBI_MODULE_PATH is unset, the directories "./lib", and "." are
|
||||
searched in order. Set to empty to only consider -I, system
|
||||
directories and -A.
|
||||
|
||||
.TP
|
||||
.B CHIBI_IGNORE_SYSTEM_PATH
|
||||
If set to anything but "0", system directories (as listed above) are
|
||||
not included in the search paths.
|
||||
files, inserted before the system default load paths.
|
||||
|
||||
.SH AUTHORS
|
||||
.PP
|
||||
|
@ -261,9 +169,9 @@ Alex Shinn (alexshinn @ gmail . com)
|
|||
|
||||
.SH SEE ALSO
|
||||
.PP
|
||||
More detailed information can be found in the manual included in
|
||||
doc/chibi.scrbl included in the distribution.
|
||||
More detailed information can be found in the README file
|
||||
included in the distribution.
|
||||
|
||||
The chibi-scheme home-page:
|
||||
.br
|
||||
https://github.com/ashinn/chibi-scheme/
|
||||
http://code.google.com/p/chibi-scheme/
|
||||
|
|
1579
doc/chibi.scrbl
1579
doc/chibi.scrbl
File diff suppressed because it is too large
Load diff
|
@ -1,29 +0,0 @@
|
|||
#!/usr/bin/env chibi-scheme
|
||||
|
||||
(import (scheme base) (scheme write) (chibi net) (chibi net server))
|
||||
|
||||
;; Copy each input line to output.
|
||||
(define (echo-handler in out sock addr)
|
||||
(let ((line (read-line in)))
|
||||
(cond
|
||||
((not (or (eof-object? line) (equal? line "")))
|
||||
;; log the request to stdout
|
||||
(display "read: ") (write line)
|
||||
(display " from ")
|
||||
(display (sockaddr-name (address-info-address addr)))
|
||||
(display " port ") (write (sockaddr-port (address-info-address addr)))
|
||||
(newline)
|
||||
;; write and flush the response
|
||||
(display line out)
|
||||
(newline out)
|
||||
(flush-output-port out)
|
||||
(echo-handler in out sock addr)))))
|
||||
|
||||
(define (get-inet6-address-info host service)
|
||||
(let ((hints (make-address-info address-family/inet6
|
||||
socket-type/stream
|
||||
ip-proto/tcp)))
|
||||
(get-address-info host service hints)))
|
||||
|
||||
;; Start the server on local ipv6 addresses on port 5556.
|
||||
(run-net-server (get-inet6-address-info #f 5556) echo-handler)
|
|
@ -1,22 +0,0 @@
|
|||
#!/usr/bin/env chibi-scheme
|
||||
|
||||
(import (scheme base) (chibi net))
|
||||
|
||||
(define (get-udp-address-info host service)
|
||||
(let ((hints (make-address-info address-family/inet
|
||||
socket-type/datagram
|
||||
ip-proto/udp)))
|
||||
(get-address-info host service hints)))
|
||||
|
||||
;; create and bind a udp socket
|
||||
(let* ((addr (get-udp-address-info #f 5556))
|
||||
(sock (socket (address-info-family addr)
|
||||
(address-info-socket-type addr)
|
||||
(address-info-protocol addr))))
|
||||
(bind sock (address-info-address addr) (address-info-address-length addr))
|
||||
;; for every packet we receive, just send it back
|
||||
(let lp ()
|
||||
(cond
|
||||
((receive sock 512 0 addr)
|
||||
=> (lambda (bv) (send sock bv 0 addr))))
|
||||
(lp)))
|
18
examples/echo-server.scm
Executable file → Normal file
18
examples/echo-server.scm
Executable file → Normal file
|
@ -1,26 +1,20 @@
|
|||
#!/usr/bin/env chibi-scheme
|
||||
|
||||
;; Simple R7RS echo server, using the run-net-server utility from
|
||||
;; (chibi net server).
|
||||
;; Simple R7RS echo server, using (srfi 18) threads and the
|
||||
;; run-net-server utility from (chibi net server).
|
||||
|
||||
(import (scheme base) (scheme write) (chibi net) (chibi net server))
|
||||
(import (scheme base) (scheme write) (srfi 18) (chibi net server))
|
||||
|
||||
;; Copy each input line to output.
|
||||
(define (echo-handler in out sock addr)
|
||||
(let ((line (read-line in)))
|
||||
(cond
|
||||
((not (or (eof-object? line) (equal? line "")))
|
||||
;; log the request to stdout
|
||||
(display "read: ") (write line)
|
||||
(display " from ")
|
||||
(display (sockaddr-name (address-info-address addr)))
|
||||
(display ":") (write (sockaddr-port (address-info-address addr)))
|
||||
(newline)
|
||||
;; write and flush the response
|
||||
(display "read: ") (write line) (newline)
|
||||
(display line out)
|
||||
(newline out)
|
||||
(flush-output-port out)
|
||||
(thread-yield!)
|
||||
(echo-handler in out sock addr)))))
|
||||
|
||||
;; Start the server on *:5556 dispatching clients to echo-handler.
|
||||
;; Start the server on localhost:5556 dispatching clients to echo-handler.
|
||||
(run-net-server 5556 echo-handler)
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
(import (scheme base))
|
||||
|
||||
(write-string "Hello world!\n")
|
|
@ -1,26 +0,0 @@
|
|||
#!/usr/bin/env chibi-scheme
|
||||
|
||||
(import (scheme base) (scheme read) (scheme write) (scheme eval)
|
||||
(chibi net) (chibi net server))
|
||||
|
||||
(define (repl-handler in out sock addr)
|
||||
(let ((env (environment '(scheme base)
|
||||
'(only (chibi) import))))
|
||||
(let lp ()
|
||||
(let ((expr (read in)))
|
||||
(cond
|
||||
((not (eof-object? expr))
|
||||
(let ((result (guard (exn (else
|
||||
(display "ERROR: " out)
|
||||
(write exn out)
|
||||
(newline out)
|
||||
(if #f #f)))
|
||||
(eval expr env))))
|
||||
(cond
|
||||
((not (eq? result (if #f #f)))
|
||||
(write result out)
|
||||
(newline out)))
|
||||
(flush-output-port out)
|
||||
(lp))))))))
|
||||
|
||||
(run-net-server 5556 repl-handler)
|
|
@ -1,36 +0,0 @@
|
|||
#! /usr/bin/env chibi-scheme
|
||||
|
||||
; Simple HTTP client
|
||||
; Retrieves the contents of the URL argument:
|
||||
|
||||
; Usage:
|
||||
; simple-http-client.scm [URL]
|
||||
;
|
||||
; Example:
|
||||
; simple-http-client.scm http://localhost:8000
|
||||
|
||||
(import (chibi) (chibi net) (chibi net http) (chibi io))
|
||||
|
||||
(if (> (length (command-line)) 1)
|
||||
(let ((url (car (cdr (command-line)))))
|
||||
(if (> (string-length url) 0)
|
||||
(begin
|
||||
(display (read-string 65536 (http-get url)))
|
||||
(newline))))
|
||||
(let ((progname (car (command-line))))
|
||||
(display "Retrieve the contents of a URL.")
|
||||
(newline)
|
||||
(display "Usage:")
|
||||
(newline)
|
||||
(newline)
|
||||
(display progname)
|
||||
(display " [URL]")
|
||||
(newline)))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
#! /usr/bin/env chibi-scheme
|
||||
|
||||
; Simple HTTP server
|
||||
; Returns a minimal HTML page with a single number incremented
|
||||
; every request. Binds to localhost port 8000.
|
||||
|
||||
(import (chibi) (chibi net http-server) (chibi net servlet) (chibi sxml))
|
||||
|
||||
(let ((count 0))
|
||||
(run-http-server
|
||||
8000
|
||||
(lambda (cfg request next restart)
|
||||
(set! count (+ 1 count))
|
||||
(servlet-write request (sxml->xml `(html (body
|
||||
(p "Count: \n")
|
||||
(p ,count))))))))
|
455
gc.c
455
gc.c
|
@ -1,19 +1,21 @@
|
|||
/* gc.c -- simple mark&sweep garbage collector */
|
||||
/* Copyright (c) 2009-2015 Alex Shinn. All rights reserved. */
|
||||
/* Copyright (c) 2009-2012 Alex Shinn. All rights reserved. */
|
||||
/* BSD-style license: http://synthcode.com/license.txt */
|
||||
|
||||
#if ! SEXP_USE_BOEHM && ! SEXP_USE_MALLOC
|
||||
|
||||
#include "chibi/sexp.h"
|
||||
|
||||
#if SEXP_USE_TIME_GC
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
#if SEXP_USE_MMAP_GC
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
#define SEXP_RTLD_DEFAULT RTLD_SELF
|
||||
#else
|
||||
#define SEXP_RTLD_DEFAULT RTLD_DEFAULT
|
||||
#endif
|
||||
|
||||
#define SEXP_BANNER(x) ("**************** GC "x"\n")
|
||||
|
||||
#define SEXP_MINIMUM_OBJECT_SIZE (sexp_heap_align(1))
|
||||
|
@ -37,52 +39,14 @@ static sexp_heap sexp_heap_last (sexp_heap h) {
|
|||
return h;
|
||||
}
|
||||
|
||||
#if !SEXP_USE_FIXED_CHUNK_SIZE_HEAPS && !SEXP_USE_MALLOC
|
||||
static size_t sexp_heap_total_size (sexp_heap h) {
|
||||
size_t total_size = 0;
|
||||
for (; h; h=h->next)
|
||||
total_size += h->size;
|
||||
return total_size;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ! SEXP_USE_GLOBAL_HEAP
|
||||
#if SEXP_USE_DEBUG_GC
|
||||
void sexp_debug_heap_stats (sexp_heap heap) {
|
||||
sexp_free_list ls;
|
||||
size_t available = 0;
|
||||
for (ls=heap->free_list; ls; ls=ls->next)
|
||||
available += ls->size;
|
||||
#if SEXP_USE_FIXED_CHUNK_SIZE_HEAPS
|
||||
sexp_debug_printf("free heap: %p (chunk size: %lu): %ld / %ld used (%.2f%%)", heap, heap->chunk_size, heap->size - available, heap->size, 100*(heap->size - available) / (float)heap->size);
|
||||
#else
|
||||
sexp_debug_printf("free heap: %p: %ld / %ld used (%.2f%%)", heap, heap->size - available, heap->size, 100*(heap->size - available) / (float)heap->size);
|
||||
#endif
|
||||
if (heap->next)
|
||||
sexp_debug_heap_stats(heap->next);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SEXP_USE_TRACK_ALLOC_TIMES
|
||||
void sexp_debug_alloc_times(sexp ctx) {
|
||||
double mean = (double) sexp_context_alloc_usecs(ctx) / sexp_context_alloc_count(ctx);
|
||||
double var = (double) sexp_context_alloc_usecs_sq(ctx) / sexp_context_alloc_count(ctx) - mean*mean;
|
||||
fprintf(stderr, SEXP_BANNER("alloc: mean: %0.3lfμs var: %0.3lfμs (%ld times)"), mean, var, sexp_context_alloc_count(ctx));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SEXP_USE_TRACK_ALLOC_SIZES
|
||||
void sexp_debug_alloc_sizes(sexp ctx) {
|
||||
int i;
|
||||
fprintf(stderr, "alloc size histogram: {");
|
||||
for (i=0; i<SEXP_ALLOC_HISTOGRAM_BUCKETS; ++i) {
|
||||
if ((i+1)*sexp_heap_align(1)<100 || sexp_context_alloc_histogram(ctx)[i]>0)
|
||||
fprintf(stderr, " %ld:%ld", (i+1)*sexp_heap_align(1), sexp_context_alloc_histogram(ctx)[i]);
|
||||
}
|
||||
fprintf(stderr, "}\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
void sexp_free_heap (sexp_heap heap) {
|
||||
#if SEXP_USE_MMAP_GC
|
||||
munmap(heap, sexp_heap_pad_size(heap->size));
|
||||
|
@ -128,16 +92,16 @@ void sexp_release_object(sexp ctx, sexp x) {
|
|||
}
|
||||
}
|
||||
|
||||
SEXP_API sexp_uint_t sexp_allocated_bytes (sexp ctx, sexp x) {
|
||||
sexp_uint_t sexp_allocated_bytes (sexp ctx, sexp x) {
|
||||
sexp_uint_t res;
|
||||
sexp t;
|
||||
if (!sexp_pointerp(x) || (sexp_pointer_tag(x) >= sexp_context_num_types(ctx)))
|
||||
return sexp_heap_align(1);
|
||||
t = sexp_object_type(ctx, x);
|
||||
res = sexp_type_size_of_object(t, x) + SEXP_GC_PAD;
|
||||
res = sexp_type_size_of_object(t, x);
|
||||
#if SEXP_USE_DEBUG_GC
|
||||
if (res == 0) {
|
||||
fprintf(stderr, SEXP_BANNER("%p zero-size object: %p (type tag: %d)"), ctx, x, sexp_pointer_tag(x));
|
||||
fprintf(stderr, SEXP_BANNER("%p zero-size object: %p"), ctx, x);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
@ -220,40 +184,9 @@ int sexp_valid_object_p (sexp ctx, sexp x) {
|
|||
return sexp_in_heap_p(ctx, x) && sexp_valid_object_type_p(ctx, x)
|
||||
&& sexp_valid_header_magic_p(ctx, x);
|
||||
}
|
||||
#define sexp_gc_pass_ctx(x) x,
|
||||
#else
|
||||
#define sexp_gc_pass_ctx(x)
|
||||
#endif
|
||||
|
||||
static void sexp_mark_stack_push (sexp ctx, sexp *start, sexp *end) {
|
||||
struct sexp_mark_stack_ptr_t *stack = sexp_context_mark_stack(ctx);
|
||||
struct sexp_mark_stack_ptr_t **ptr = &sexp_context_mark_stack_ptr(ctx);
|
||||
struct sexp_mark_stack_ptr_t *old = *ptr;
|
||||
|
||||
if (old == NULL) {
|
||||
*ptr = stack;
|
||||
} else if (old >= stack && old + 1 < stack + SEXP_MARK_STACK_COUNT) {
|
||||
(*ptr)++;
|
||||
} else {
|
||||
*ptr = malloc(sizeof(**ptr));
|
||||
}
|
||||
|
||||
(*ptr)->start = start;
|
||||
(*ptr)->end = end;
|
||||
(*ptr)->prev = old;
|
||||
}
|
||||
|
||||
static void sexp_mark_stack_pop (sexp ctx) {
|
||||
struct sexp_mark_stack_ptr_t *stack = sexp_context_mark_stack(ctx);
|
||||
struct sexp_mark_stack_ptr_t *old = sexp_context_mark_stack_ptr(ctx);
|
||||
|
||||
sexp_context_mark_stack_ptr(ctx) = old->prev;
|
||||
if (!(old >= stack && old < stack + SEXP_MARK_STACK_COUNT)) {
|
||||
free(old);
|
||||
}
|
||||
}
|
||||
|
||||
static void sexp_mark_one (sexp ctx, sexp* types, sexp x) {
|
||||
void sexp_mark (sexp ctx, sexp x) {
|
||||
sexp_sint_t len;
|
||||
sexp t, *p, *q;
|
||||
struct sexp_gc_var_t *saves;
|
||||
|
@ -261,46 +194,25 @@ static void sexp_mark_one (sexp ctx, sexp* types, sexp x) {
|
|||
if (!x || !sexp_pointerp(x) || !sexp_valid_object_p(ctx, x) || sexp_markedp(x))
|
||||
return;
|
||||
sexp_markedp(x) = 1;
|
||||
if (sexp_contextp(x)) {
|
||||
if (sexp_contextp(x))
|
||||
for (saves=sexp_context_saves(x); saves; saves=saves->next)
|
||||
if (saves->var) sexp_mark_one(ctx, types, *(saves->var));
|
||||
}
|
||||
t = types[sexp_pointer_tag(x)];
|
||||
if (saves->var) sexp_mark(ctx, *(saves->var));
|
||||
t = sexp_object_type(ctx, x);
|
||||
len = sexp_type_num_slots_of_object(t, x) - 1;
|
||||
if (len >= 0) {
|
||||
p = (sexp*) (((char*)x) + sexp_type_field_base(t));
|
||||
q = p + len;
|
||||
while (p < q && (*q && sexp_pointerp(*q) ? sexp_markedp(*q) : 1))
|
||||
while (p < q && ! (*q && sexp_pointerp(*q)))
|
||||
q--; /* skip trailing immediates */
|
||||
while (p < q && *q == q[-1])
|
||||
q--; /* skip trailing duplicates */
|
||||
if (p < q) {
|
||||
sexp_mark_stack_push(ctx, p, q);
|
||||
}
|
||||
x = *q;
|
||||
while (p < q)
|
||||
sexp_mark(ctx, *p++);
|
||||
x = *p;
|
||||
goto loop;
|
||||
}
|
||||
}
|
||||
|
||||
static void sexp_mark_one_start (sexp ctx, sexp* types, sexp x) {
|
||||
struct sexp_mark_stack_ptr_t **ptr = &sexp_context_mark_stack_ptr(ctx);
|
||||
sexp *p, *q;
|
||||
sexp_mark_one(ctx, types, x);
|
||||
|
||||
while (*ptr) {
|
||||
p = (*ptr)->start;
|
||||
q = (*ptr)->end;
|
||||
sexp_mark_stack_pop(ctx);
|
||||
while (p < q) {
|
||||
sexp_mark_one(ctx, types, *p++);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sexp_mark (sexp ctx, sexp x) {
|
||||
sexp_mark_one_start(ctx, sexp_vector_data(sexp_global(ctx, SEXP_G_TYPES)), x);
|
||||
}
|
||||
|
||||
#if SEXP_USE_CONSERVATIVE_GC
|
||||
|
||||
int stack_references_pointer_p (sexp ctx, sexp x) {
|
||||
|
@ -311,18 +223,6 @@ int stack_references_pointer_p (sexp ctx, sexp x) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
#if SEXP_USE_TRACK_ALLOC_BACKTRACE
|
||||
void sexp_print_gc_trace(sexp ctx, sexp p) {
|
||||
int i;
|
||||
char **debug_text = backtrace_symbols(p->backtrace, SEXP_BACKTRACE_SIZE);
|
||||
for (i=0; i < SEXP_BACKTRACE_SIZE; i++)
|
||||
fprintf(stderr, SEXP_BANNER(" : %s"), debug_text[i]);
|
||||
free(debug_text);
|
||||
}
|
||||
#else
|
||||
#define sexp_print_gc_trace(ctx, p)
|
||||
#endif
|
||||
|
||||
void sexp_conservative_mark (sexp ctx) {
|
||||
sexp_heap h = sexp_context_heap(ctx);
|
||||
sexp p, end;
|
||||
|
@ -347,7 +247,6 @@ void sexp_conservative_mark (sexp ctx) {
|
|||
if (p && sexp_pointerp(p)) {
|
||||
fprintf(stderr, SEXP_BANNER("MISS: %p [%d]: %s"), p,
|
||||
sexp_pointer_tag(p), sexp_pointer_source(p));
|
||||
sexp_print_gc_trace(ctx, p);
|
||||
fflush(stderr);
|
||||
}
|
||||
#endif
|
||||
|
@ -364,16 +263,12 @@ void sexp_conservative_mark (sexp ctx) {
|
|||
#endif
|
||||
|
||||
#if SEXP_USE_WEAK_REFERENCES
|
||||
int sexp_reset_weak_references(sexp ctx) {
|
||||
int i, len, broke, all_reset_p;
|
||||
sexp_heap h;
|
||||
void sexp_reset_weak_references(sexp ctx) {
|
||||
int i, len, all_reset_p;
|
||||
sexp_heap h = sexp_context_heap(ctx);
|
||||
sexp p, t, end, *v;
|
||||
sexp_free_list q, r;
|
||||
if (sexp_not(sexp_global(ctx, SEXP_G_WEAK_OBJECTS_PRESENT)))
|
||||
return 0;
|
||||
broke = 0;
|
||||
/* just scan the whole heap */
|
||||
for (h = sexp_context_heap(ctx) ; h; h=h->next) {
|
||||
for ( ; h; h=h->next) { /* just scan the whole heap */
|
||||
p = sexp_heap_first_block(h);
|
||||
q = h->free_list;
|
||||
end = sexp_heap_end(h);
|
||||
|
@ -400,7 +295,6 @@ int sexp_reset_weak_references(sexp ctx) {
|
|||
}
|
||||
}
|
||||
if (all_reset_p) { /* ephemerons */
|
||||
broke++;
|
||||
len += sexp_type_weak_len_extra(t);
|
||||
for ( ; i<len; i++) v[i] = SEXP_FALSE;
|
||||
}
|
||||
|
@ -409,14 +303,11 @@ int sexp_reset_weak_references(sexp ctx) {
|
|||
p = (sexp) (((char*)p)+sexp_heap_align(sexp_allocated_bytes(ctx, p)));
|
||||
}
|
||||
}
|
||||
sexp_debug_printf("%p (broke %d weak references)", ctx, broke);
|
||||
return broke;
|
||||
}
|
||||
#else
|
||||
#define sexp_reset_weak_references(ctx) 0
|
||||
#define sexp_reset_weak_references(ctx)
|
||||
#endif
|
||||
|
||||
#if SEXP_USE_FINALIZERS
|
||||
sexp sexp_finalize (sexp ctx) {
|
||||
size_t size;
|
||||
sexp p, t, end;
|
||||
|
@ -442,9 +333,6 @@ sexp sexp_finalize (sexp ctx) {
|
|||
continue;
|
||||
}
|
||||
size = sexp_heap_align(sexp_allocated_bytes(ctx, p));
|
||||
if (size == 0) {
|
||||
return SEXP_FALSE;
|
||||
}
|
||||
if (!sexp_markedp(p)) {
|
||||
t = sexp_object_type(ctx, p);
|
||||
finalizer = sexp_type_finalize(t);
|
||||
|
@ -466,7 +354,6 @@ sexp sexp_finalize (sexp ctx) {
|
|||
#endif
|
||||
return sexp_make_fixnum(finalize_count);
|
||||
}
|
||||
#endif
|
||||
|
||||
sexp sexp_sweep (sexp ctx, size_t *sum_freed_ptr) {
|
||||
size_t freed, max_freed=0, sum_freed=0, size;
|
||||
|
@ -487,7 +374,7 @@ sexp sexp_sweep (sexp ctx, size_t *sum_freed_ptr) {
|
|||
continue;
|
||||
}
|
||||
size = sexp_heap_align(sexp_allocated_bytes(ctx, p));
|
||||
#if SEXP_USE_DEBUG_GC > 1
|
||||
#if SEXP_USE_DEBUG_GC
|
||||
if (!sexp_valid_object_p(ctx, p))
|
||||
fprintf(stderr, SEXP_BANNER("%p sweep: invalid object at %p"), ctx, p);
|
||||
if ((char*)q + q->size > (char*)p)
|
||||
|
@ -552,46 +439,32 @@ void sexp_mark_global_symbols(sexp ctx) {
|
|||
|
||||
sexp sexp_gc (sexp ctx, size_t *sum_freed) {
|
||||
sexp res, finalized SEXP_NO_WARN_UNUSED;
|
||||
#if SEXP_USE_TIME_GC
|
||||
sexp_uint_t gc_usecs;
|
||||
struct rusage start, end;
|
||||
getrusage(RUSAGE_SELF, &start);
|
||||
sexp_debug_printf("%p (heap: %p size: %lu)", ctx, sexp_context_heap(ctx),
|
||||
sexp_heap_total_size(sexp_context_heap(ctx)));
|
||||
#endif
|
||||
sexp_mark_global_symbols(ctx);
|
||||
sexp_mark(ctx, ctx);
|
||||
sexp_conservative_mark(ctx);
|
||||
sexp_reset_weak_references(ctx);
|
||||
finalized = sexp_finalize(ctx);
|
||||
res = sexp_sweep(ctx, sum_freed);
|
||||
++sexp_context_gc_count(ctx);
|
||||
#if SEXP_USE_TIME_GC
|
||||
getrusage(RUSAGE_SELF, &end);
|
||||
gc_usecs = (end.ru_utime.tv_sec - start.ru_utime.tv_sec) * 1000000 +
|
||||
end.ru_utime.tv_usec - start.ru_utime.tv_usec;
|
||||
sexp_context_gc_usecs(ctx) += gc_usecs;
|
||||
sexp_debug_printf("%p (freed: %lu max_freed: %lu finalized: %lu time: %luus)",
|
||||
ctx, (sum_freed ? *sum_freed : 0), sexp_unbox_fixnum(res),
|
||||
sexp_unbox_fixnum(finalized), gc_usecs);
|
||||
#endif
|
||||
sexp_debug_printf("%p (freed: %lu max_freed: %lu finalized: %lu)", ctx,
|
||||
(sum_freed ? *sum_freed : 0), sexp_unbox_fixnum(res),
|
||||
sexp_unbox_fixnum(finalized));
|
||||
return res;
|
||||
}
|
||||
|
||||
sexp_heap sexp_make_heap (size_t size, size_t max_size, size_t chunk_size) {
|
||||
sexp_heap sexp_make_heap (size_t size, size_t max_size) {
|
||||
sexp_free_list free, next;
|
||||
sexp_heap h;
|
||||
#if SEXP_USE_MMAP_GC
|
||||
h = mmap(NULL, sexp_heap_pad_size(size), PROT_READ|PROT_WRITE,
|
||||
MAP_ANON|MAP_PRIVATE, -1, 0);
|
||||
if (h == MAP_FAILED) return NULL;
|
||||
h = mmap(NULL, sexp_heap_pad_size(size), PROT_READ|PROT_WRITE|PROT_EXEC,
|
||||
MAP_ANON|MAP_PRIVATE, 0, 0);
|
||||
#else
|
||||
h = sexp_malloc(sexp_heap_pad_size(size));
|
||||
if (! h) return NULL;
|
||||
#endif
|
||||
if (! h) return NULL;
|
||||
h->size = size;
|
||||
h->max_size = max_size;
|
||||
h->chunk_size = chunk_size;
|
||||
h->data = (char*) sexp_heap_align(sizeof(h->data)+(sexp_uint_t)&(h->data));
|
||||
free = h->free_list = (sexp_free_list) h->data;
|
||||
h->next = NULL;
|
||||
|
@ -611,48 +484,22 @@ sexp_heap sexp_make_heap (size_t size, size_t max_size, size_t chunk_size) {
|
|||
return h;
|
||||
}
|
||||
|
||||
int sexp_grow_heap (sexp ctx, size_t size, size_t chunk_size) {
|
||||
int sexp_grow_heap (sexp ctx, size_t size) {
|
||||
size_t cur_size, new_size;
|
||||
sexp_heap tmp, h = sexp_heap_last(sexp_context_heap(ctx));
|
||||
#if SEXP_USE_FIXED_CHUNK_SIZE_HEAPS
|
||||
for (tmp=sexp_context_heap(ctx); tmp; tmp=tmp->next)
|
||||
if (tmp->chunk_size == size) {
|
||||
while (tmp->next && tmp->next->chunk_size == size)
|
||||
tmp = tmp->next;
|
||||
h = tmp;
|
||||
chunk_size = size;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
sexp_heap h = sexp_heap_last(sexp_context_heap(ctx));
|
||||
cur_size = h->size;
|
||||
new_size = (size_t) ceil(SEXP_GROW_HEAP_FACTOR * (double) (sexp_heap_align(((cur_size > size) ? cur_size : size))));
|
||||
tmp = sexp_make_heap(new_size, h->max_size, chunk_size);
|
||||
if (tmp) {
|
||||
tmp->next = h->next;
|
||||
h->next = tmp;
|
||||
}
|
||||
new_size = sexp_heap_align(((cur_size > size) ? cur_size : size) * 2);
|
||||
h->next = sexp_make_heap(new_size, h->max_size);
|
||||
return (h->next != NULL);
|
||||
}
|
||||
|
||||
void* sexp_try_alloc (sexp ctx, size_t size) {
|
||||
sexp_free_list ls1, ls2, ls3;
|
||||
sexp_heap h;
|
||||
#if SEXP_USE_FIXED_CHUNK_SIZE_HEAPS
|
||||
int found_fixed = 0;
|
||||
#endif
|
||||
for (h=sexp_context_heap(ctx); h; h=h->next) {
|
||||
#if SEXP_USE_FIXED_CHUNK_SIZE_HEAPS
|
||||
if (h->chunk_size) {
|
||||
if (h->chunk_size != size)
|
||||
continue;
|
||||
found_fixed = 1;
|
||||
} else if (found_fixed) { /* don't use a non-fixed heap */
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
for (ls1=h->free_list, ls2=ls1->next; ls2; ls1=ls2, ls2=ls2->next) {
|
||||
for (h=sexp_context_heap(ctx); h; h=h->next)
|
||||
for (ls1=h->free_list, ls2=ls1->next; ls2; ls1=ls2, ls2=ls2->next)
|
||||
if (ls2->size >= size) {
|
||||
#if SEXP_USE_DEBUG_GC > 1
|
||||
#if SEXP_USE_DEBUG_GC
|
||||
ls3 = (sexp_free_list) sexp_heap_end(h);
|
||||
if (ls2 >= ls3)
|
||||
fprintf(stderr, "alloced %lu bytes past end of heap: %p (%lu) >= %p"
|
||||
|
@ -670,87 +517,207 @@ void* sexp_try_alloc (sexp ctx, size_t size) {
|
|||
memset((void*)ls2, 0, size);
|
||||
return ls2;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if SEXP_USE_FIXED_CHUNK_SIZE_HEAPS
|
||||
int sexp_find_fixed_chunk_heap_usage(sexp ctx, size_t size, size_t* sum_freed, size_t* total_size) {
|
||||
sexp_heap h;
|
||||
sexp_free_list ls;
|
||||
size_t avail=0, total=0;
|
||||
for (h=sexp_context_heap(ctx); h; h=h->next) {
|
||||
if (h->chunk_size == size || !h->chunk_size) {
|
||||
for (; h && (h->chunk_size == size || !h->chunk_size); h=h->next) {
|
||||
total += h->size;
|
||||
for (ls=h->free_list; ls; ls=ls->next)
|
||||
avail += ls->size;
|
||||
}
|
||||
*sum_freed = avail;
|
||||
*total_size = total;
|
||||
return h && h->chunk_size > 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ! SEXP_USE_MALLOC
|
||||
void* sexp_alloc (sexp ctx, size_t size) {
|
||||
void *res;
|
||||
size_t max_freed, sum_freed, total_size=0;
|
||||
size_t max_freed, sum_freed, total_size;
|
||||
sexp_heap h = sexp_context_heap(ctx);
|
||||
#if SEXP_USE_TRACK_ALLOC_SIZES
|
||||
size_t size_bucket;
|
||||
#endif
|
||||
#if SEXP_USE_TRACK_ALLOC_TIMES
|
||||
sexp_uint_t alloc_time;
|
||||
struct timeval start, end;
|
||||
gettimeofday(&start, NULL);
|
||||
#endif
|
||||
size = sexp_heap_align(size) + SEXP_GC_PAD;
|
||||
#if SEXP_USE_TRACK_ALLOC_SIZES
|
||||
size_bucket = (size - SEXP_GC_PAD) / sexp_heap_align(1) - 1;
|
||||
++sexp_context_alloc_histogram(ctx)[size_bucket >= SEXP_ALLOC_HISTOGRAM_BUCKETS ? SEXP_ALLOC_HISTOGRAM_BUCKETS-1 : size_bucket];
|
||||
#endif
|
||||
size = sexp_heap_align(size);
|
||||
res = sexp_try_alloc(ctx, size);
|
||||
if (! res) {
|
||||
max_freed = sexp_unbox_fixnum(sexp_gc(ctx, &sum_freed));
|
||||
#if SEXP_USE_FIXED_CHUNK_SIZE_HEAPS
|
||||
sexp_find_fixed_chunk_heap_usage(ctx, size, &sum_freed, &total_size);
|
||||
#else
|
||||
total_size = sexp_heap_total_size(sexp_context_heap(ctx));
|
||||
#endif
|
||||
if (((max_freed < size)
|
||||
|| ((total_size > sum_freed)
|
||||
&& (total_size - sum_freed) > (total_size*SEXP_GROW_HEAP_RATIO)))
|
||||
&& ((!h->max_size) || (total_size < h->max_size)))
|
||||
sexp_grow_heap(ctx, size, 0);
|
||||
sexp_grow_heap(ctx, size);
|
||||
res = sexp_try_alloc(ctx, size);
|
||||
if (! res) {
|
||||
res = sexp_global(ctx, SEXP_G_OOM_ERROR);
|
||||
sexp_debug_printf("ran out of memory allocating %lu bytes => %p", size, res);
|
||||
}
|
||||
}
|
||||
#if SEXP_USE_TRACK_ALLOC_TIMES
|
||||
gettimeofday(&end, NULL);
|
||||
alloc_time = 1000000*(end.tv_sec - start.tv_sec) + (end.tv_usec - start.tv_usec);
|
||||
sexp_context_alloc_count(ctx) += 1;
|
||||
sexp_context_alloc_usecs(ctx) += alloc_time;
|
||||
sexp_context_alloc_usecs_sq(ctx) += alloc_time*alloc_time;
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ! SEXP_USE_GLOBAL_HEAP
|
||||
|
||||
void sexp_offset_heap_pointers (sexp_heap heap, sexp_heap from_heap, sexp* types, sexp flags) {
|
||||
sexp_sint_t i, off, len, freep, loadp;
|
||||
sexp_free_list q;
|
||||
sexp p, t, end, *v;
|
||||
#if SEXP_USE_DL
|
||||
sexp name;
|
||||
#endif
|
||||
freep = sexp_unbox_fixnum(flags) & sexp_unbox_fixnum(SEXP_COPY_FREEP);
|
||||
loadp = sexp_unbox_fixnum(flags) & sexp_unbox_fixnum(SEXP_COPY_LOADP);
|
||||
|
||||
off = (sexp_sint_t)((sexp_sint_t)heap - (sexp_sint_t)from_heap);
|
||||
heap->data += off;
|
||||
end = (sexp) (heap->data + heap->size);
|
||||
|
||||
/* adjust the free list */
|
||||
heap->free_list = (sexp_free_list) ((char*)heap->free_list + off);
|
||||
for (q=heap->free_list; q->next; q=q->next)
|
||||
q->next = (sexp_free_list) ((char*)q->next + off);
|
||||
|
||||
/* adjust data by traversing over the new heap */
|
||||
p = (sexp) (heap->data + sexp_heap_align(sexp_free_chunk_size));
|
||||
q = heap->free_list;
|
||||
while (p < end) {
|
||||
/* find the next free list pointer */
|
||||
for ( ; q && ((char*)q < (char*)p); q=q->next)
|
||||
;
|
||||
if ((char*)q == (char*)p) { /* this is a free block, skip it */
|
||||
p = (sexp) (((char*)p) + q->size);
|
||||
} else {
|
||||
t = (sexp)((char*)(types[sexp_pointer_tag(p)])
|
||||
+ ((char*)types > (char*)p ? off : 0));
|
||||
len = sexp_type_num_slots_of_object(t, p);
|
||||
v = (sexp*) ((char*)p + sexp_type_field_base(t));
|
||||
/* offset any pointers in the _destination_ heap */
|
||||
for (i=0; i<len; i++)
|
||||
if (v[i] && sexp_pointerp(v[i]))
|
||||
v[i] = (sexp) ((char*)v[i] + off);
|
||||
/* don't free unless specified - only the original cleans up */
|
||||
if (! freep)
|
||||
sexp_freep(p) = 0;
|
||||
/* adjust context heaps, don't copy saved sexp_gc_vars */
|
||||
if (sexp_contextp(p)) {
|
||||
#if SEXP_USE_GREEN_THREADS
|
||||
sexp_context_ip(p) += off;
|
||||
#endif
|
||||
sexp_context_last_fp(p) += off;
|
||||
sexp_stack_top(sexp_context_stack(p)) = 0;
|
||||
sexp_context_saves(p) = NULL;
|
||||
sexp_context_heap(p) = heap;
|
||||
} else if (sexp_bytecodep(p) && off != 0) {
|
||||
for (i=0; i<sexp_bytecode_length(p); ) {
|
||||
switch (sexp_bytecode_data(p)[i++]) {
|
||||
case SEXP_OP_FCALL0: case SEXP_OP_FCALL1:
|
||||
case SEXP_OP_FCALL2: case SEXP_OP_FCALL3:
|
||||
case SEXP_OP_FCALL4: case SEXP_OP_CALL:
|
||||
case SEXP_OP_TAIL_CALL: case SEXP_OP_PUSH:
|
||||
case SEXP_OP_GLOBAL_REF: case SEXP_OP_GLOBAL_KNOWN_REF:
|
||||
#if SEXP_USE_GREEN_THREADS
|
||||
case SEXP_OP_PARAMETER_REF:
|
||||
#endif
|
||||
#if SEXP_USE_EXTENDED_FCALL
|
||||
case SEXP_OP_FCALLN:
|
||||
#endif
|
||||
v = (sexp*)(&(sexp_bytecode_data(p)[i]));
|
||||
if (v[0] && sexp_pointerp(v[0])) v[0] = (sexp) (((char*)v[0]) + off);
|
||||
/* ... FALLTHROUGH ... */
|
||||
case SEXP_OP_JUMP: case SEXP_OP_JUMP_UNLESS:
|
||||
case SEXP_OP_STACK_REF: case SEXP_OP_CLOSURE_REF:
|
||||
case SEXP_OP_LOCAL_REF: case SEXP_OP_LOCAL_SET:
|
||||
case SEXP_OP_TYPEP:
|
||||
#if SEXP_USE_RESERVE_OPCODE
|
||||
case SEXP_OP_RESERVE:
|
||||
#endif
|
||||
i += sizeof(sexp); break;
|
||||
case SEXP_OP_MAKE: case SEXP_OP_SLOT_REF: case SEXP_OP_SLOT_SET:
|
||||
i += 2*sizeof(sexp); break;
|
||||
case SEXP_OP_MAKE_PROCEDURE:
|
||||
v = (sexp*)(&(sexp_bytecode_data(p)[i]));
|
||||
if (v[2] && sexp_pointerp(v[2])) v[2] = (sexp) (((char*)v[2]) + off);
|
||||
i += 3*sizeof(sexp); break;
|
||||
}
|
||||
}
|
||||
} else if (sexp_portp(p) && sexp_port_stream(p)) {
|
||||
sexp_port_stream(p) = 0;
|
||||
sexp_port_openp(p) = 0;
|
||||
sexp_freep(p) = 0;
|
||||
#if SEXP_USE_DL
|
||||
} else if (loadp && sexp_dlp(p)) {
|
||||
sexp_dl_handle(p) = NULL;
|
||||
#endif
|
||||
}
|
||||
p = (sexp) (((char*)p)+sexp_heap_align(sexp_type_size_of_object(t, p)));
|
||||
}
|
||||
}
|
||||
|
||||
/* make a second pass to fix code references */
|
||||
if (loadp) {
|
||||
p = (sexp) (heap->data + sexp_heap_align(sexp_free_chunk_size));
|
||||
q = heap->free_list;
|
||||
while (p < end) {
|
||||
/* find the next free list pointer */
|
||||
for ( ; q && ((char*)q < (char*)p); q=q->next)
|
||||
;
|
||||
if ((char*)q == (char*)p) { /* this is a free block, skip it */
|
||||
p = (sexp) (((char*)p) + q->size);
|
||||
} else {
|
||||
#if SEXP_USE_DL
|
||||
if (sexp_opcodep(p) && sexp_opcode_func(p)) {
|
||||
name = (sexp_opcode_data2(p) && sexp_stringp(sexp_opcode_data2(p))) ? sexp_opcode_data2(p) : sexp_opcode_name(p);
|
||||
if (sexp_dlp(sexp_opcode_dl(p))) {
|
||||
if (!sexp_dl_handle(sexp_opcode_dl(p)))
|
||||
sexp_dl_handle(sexp_opcode_dl(p)) = dlopen(sexp_string_data(sexp_dl_file(sexp_opcode_dl(p))), RTLD_LAZY);
|
||||
sexp_opcode_func(p) = dlsym(sexp_dl_handle(sexp_opcode_dl(p)), sexp_string_data(name));
|
||||
} else {
|
||||
sexp_opcode_func(p) = dlsym(SEXP_RTLD_DEFAULT, sexp_string_data(name));
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
if (sexp_typep(p)) {
|
||||
if (sexp_type_finalize(p)) {
|
||||
/* TODO: handle arbitrary finalizers in images */
|
||||
#if SEXP_USE_DL
|
||||
if (sexp_type_tag(p) == SEXP_DL)
|
||||
sexp_type_finalize(p) = SEXP_FINALIZE_DL;
|
||||
else
|
||||
#endif
|
||||
sexp_type_finalize(p) = SEXP_FINALIZE_PORT;
|
||||
}
|
||||
}
|
||||
t = types[sexp_pointer_tag(p)];
|
||||
p = (sexp) (((char*)p)+sexp_heap_align(sexp_type_size_of_object(t, p)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sexp sexp_copy_context (sexp ctx, sexp dst, sexp flags) {
|
||||
sexp_sint_t off;
|
||||
sexp_heap to, from = sexp_context_heap(ctx);
|
||||
|
||||
/* validate input, creating a new heap if needed */
|
||||
if (from->next) {
|
||||
return sexp_user_exception(ctx, NULL, "can't copy a non-contiguous heap", ctx);
|
||||
} else if (! dst || sexp_not(dst)) {
|
||||
to = sexp_make_heap(from->size, from->max_size);
|
||||
if (!to) return sexp_global(ctx, SEXP_G_OOM_ERROR);
|
||||
dst = (sexp) ((char*)ctx + ((char*)to - (char*)from));
|
||||
} else if (! sexp_contextp(dst)) {
|
||||
return sexp_type_exception(ctx, NULL, SEXP_CONTEXT, dst);
|
||||
} else if (sexp_context_heap(dst)->size < from->size) {
|
||||
return sexp_user_exception(ctx, NULL, "destination context too small", dst);
|
||||
} else {
|
||||
to = sexp_context_heap(dst);
|
||||
}
|
||||
|
||||
/* copy the raw data */
|
||||
off = (char*)to - (char*)from;
|
||||
memcpy(to, from, sexp_heap_pad_size(from->size));
|
||||
|
||||
/* adjust the pointers */
|
||||
sexp_offset_heap_pointers(to, from, sexp_context_types(ctx) + off, flags);
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void sexp_gc_init (void) {
|
||||
#if SEXP_USE_GLOBAL_HEAP || SEXP_USE_CONSERVATIVE_GC
|
||||
sexp_uint_t size = sexp_heap_align(SEXP_INITIAL_HEAP_SIZE);
|
||||
#endif
|
||||
#if SEXP_USE_GLOBAL_HEAP
|
||||
sexp_global_heap = sexp_make_heap(size, SEXP_MAXIMUM_HEAP_SIZE, 0);
|
||||
sexp_global_heap = sexp_make_heap(size, SEXP_MAXIMUM_HEAP_SIZE);
|
||||
#endif
|
||||
#if SEXP_USE_CONSERVATIVE_GC
|
||||
/* the +32 is a hack, but this is just for debugging anyway */
|
||||
|
@ -758,4 +725,4 @@ void sexp_gc_init (void) {
|
|||
#endif
|
||||
}
|
||||
|
||||
#endif /* ! SEXP_USE_BOEHM && ! SEXP_USE_MALLOC */
|
||||
#endif
|
||||
|
|
789
gc_heap.c
789
gc_heap.c
|
@ -1,789 +0,0 @@
|
|||
/* gc_heap.h -- heap packing, run-time image generation */
|
||||
/* Copyright (c) 2016 Chris Walsh. All rights reserved. */
|
||||
/* BSD-style license: http://synthcode.com/license.txt */
|
||||
|
||||
#include "chibi/gc_heap.h"
|
||||
|
||||
#if SEXP_USE_IMAGE_LOADING
|
||||
|
||||
#define ERR_STR_SIZE 256
|
||||
static char gc_heap_err_str[ERR_STR_SIZE];
|
||||
|
||||
|
||||
static sexp_uint_t sexp_gc_allocated_bytes (sexp ctx, sexp *types, size_t types_cnt, sexp x) {
|
||||
sexp_uint_t res = 0;
|
||||
if (!sexp_pointerp(x) || (sexp_pointer_tag(x) >= types_cnt)) {
|
||||
res = 1;
|
||||
} else {
|
||||
res = sexp_type_size_of_object(types[sexp_pointer_tag(x)], x) + SEXP_GC_PAD;
|
||||
}
|
||||
return sexp_heap_align(res);
|
||||
}
|
||||
|
||||
|
||||
sexp sexp_gc_heap_walk(sexp ctx,
|
||||
sexp_heap h, /* normally set to sexp_context_heap(ctx) */
|
||||
sexp *t, /* normally set to sexp_context_types(ctx) */
|
||||
size_t t_cnt, /* normally set to sexp_context_num_types(ctx) */
|
||||
void *user,
|
||||
sexp (*heap_callback)(sexp ctx, sexp_heap h, void *user),
|
||||
sexp (*free_callback)(sexp ctx, sexp_free_list f, void *user),
|
||||
sexp (*sexp_callback)(sexp ctx, sexp s, void *user))
|
||||
{
|
||||
sexp res = SEXP_FALSE;
|
||||
|
||||
size_t size = 0;
|
||||
while (h) {
|
||||
sexp p = sexp_heap_first_block(h);
|
||||
sexp_free_list q = h->free_list;
|
||||
sexp end = sexp_heap_end(h);
|
||||
|
||||
while (p < end) {
|
||||
/* find the preceding and succeeding free list pointers */
|
||||
sexp_free_list r = q->next;
|
||||
while (r && ((unsigned char*)r < (unsigned char*)p)) {
|
||||
q = r;
|
||||
r = r->next;
|
||||
}
|
||||
|
||||
if ( (unsigned char*)r == (unsigned char*)p ) {
|
||||
if (free_callback && (res = free_callback(ctx, r, user)) != SEXP_TRUE) {
|
||||
return res; }
|
||||
size = r ? r->size : 0;
|
||||
} else {
|
||||
if (sexp_callback && (res = sexp_callback(ctx, p, user)) != SEXP_TRUE) {
|
||||
return res; }
|
||||
size = sexp_gc_allocated_bytes(ctx, t, t_cnt, p);
|
||||
if (size == 0) {
|
||||
snprintf(gc_heap_err_str, ERR_STR_SIZE, "Heap element with a zero size detected");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
p = (sexp)(((unsigned char*)p) + size);
|
||||
}
|
||||
|
||||
if (heap_callback && (res = heap_callback(ctx, h, user)) != SEXP_TRUE) {
|
||||
return res; }
|
||||
h = h->next;
|
||||
}
|
||||
res = SEXP_TRUE;
|
||||
done:
|
||||
if (res != SEXP_TRUE) res = sexp_user_exception(ctx, NULL, gc_heap_err_str, SEXP_NULL);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
struct sexp_remap {
|
||||
sexp srcp;
|
||||
sexp dstp;
|
||||
};
|
||||
|
||||
struct sexp_remap_state {
|
||||
size_t index, heaps_count, sexps_count, sexps_size;
|
||||
sexp p, end, ctx_src, ctx_dst;
|
||||
sexp_heap heap;
|
||||
int mode;
|
||||
struct sexp_remap *remap;
|
||||
};
|
||||
|
||||
|
||||
static sexp heap_callback_count(sexp ctx, sexp_heap h, void *user) {
|
||||
struct sexp_remap_state* state = user;
|
||||
state->heaps_count += 1;
|
||||
return SEXP_TRUE;
|
||||
}
|
||||
|
||||
static sexp sexp_callback_count(sexp ctx, sexp s, void *user) {
|
||||
struct sexp_remap_state* state = user;
|
||||
size_t size = sexp_gc_allocated_bytes(ctx, sexp_context_types(ctx),
|
||||
sexp_context_num_types(ctx), s);
|
||||
state->sexps_count += 1;
|
||||
state->sexps_size += size;
|
||||
return SEXP_TRUE;
|
||||
}
|
||||
|
||||
static sexp heap_callback_remap(sexp ctx, sexp_heap h, void *user) {
|
||||
return SEXP_NULL;
|
||||
}
|
||||
|
||||
static sexp sexp_callback_remap(sexp ctx, sexp s, void *user) {
|
||||
struct sexp_remap_state* state = user;
|
||||
size_t size = sexp_gc_allocated_bytes(ctx, sexp_context_types(ctx),
|
||||
sexp_context_num_types(ctx), s);
|
||||
if (state->p >= state->end) {
|
||||
snprintf(gc_heap_err_str, ERR_STR_SIZE, "callback_remap i=%zu p>end internal error", state->index);
|
||||
return SEXP_FALSE; }
|
||||
memcpy(state->p, s, size);
|
||||
|
||||
state->remap[state->index].srcp = s;
|
||||
state->remap[state->index].dstp = state->p;
|
||||
if (ctx == s) state->ctx_dst = state->p;
|
||||
|
||||
state->p = (sexp)(((unsigned char*)state->p) + size);
|
||||
state->index += 1;
|
||||
|
||||
return SEXP_TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Return a destination (remapped) pointer for a given source pointer */
|
||||
static sexp sexp_gc_heap_pack_src_to_dst(void* adata, sexp srcp) {
|
||||
|
||||
struct sexp_remap_state* state = adata;
|
||||
sexp_sint_t imin = 0;
|
||||
sexp_sint_t imax = state->sexps_count - 1;
|
||||
|
||||
while (imin <= imax) {
|
||||
sexp_sint_t imid = ((imax - imin) / 2) + imin;
|
||||
sexp midp = state->remap[imid].srcp;
|
||||
if (midp == srcp) {
|
||||
return state->remap[imid].dstp;
|
||||
} else if (midp < srcp) {
|
||||
imin = imid + 1;
|
||||
} else {
|
||||
imax = imid - 1;
|
||||
}
|
||||
}
|
||||
snprintf(gc_heap_err_str, ERR_STR_SIZE, "Source SEXP not found in src->dst mapping");
|
||||
return SEXP_FALSE;
|
||||
}
|
||||
|
||||
|
||||
static sexp sexp_adjust_fields(sexp dstp, sexp* types, sexp (* adjust_fn)(void *, sexp), void *adata) {
|
||||
sexp_tag_t tag = sexp_pointer_tag(dstp);
|
||||
sexp type_spec = types[tag];
|
||||
size_t type_sexp_cnt = sexp_type_num_slots_of_object(type_spec, dstp);
|
||||
sexp* vec = (sexp*)((unsigned char*)dstp + sexp_type_field_base(type_spec));
|
||||
int i;
|
||||
|
||||
for (i = 0; i < type_sexp_cnt; i++) {
|
||||
sexp src = vec[i];
|
||||
sexp dst = src;
|
||||
if (src && sexp_pointerp(src)) {
|
||||
dst = adjust_fn(adata, src);
|
||||
if (!sexp_pointerp(dst)) {
|
||||
size_t sz = strlen(gc_heap_err_str);
|
||||
snprintf(gc_heap_err_str + sz, ERR_STR_SIZE - sz, " from adjust fields, tag=%u i=%d", tag, i);
|
||||
return SEXP_FALSE; }
|
||||
}
|
||||
vec[i] = dst;
|
||||
}
|
||||
return SEXP_TRUE;
|
||||
}
|
||||
|
||||
|
||||
static sexp sexp_adjust_bytecode(sexp dstp, sexp (*adjust_fn)(void *, sexp), void *adata) {
|
||||
sexp res = SEXP_FALSE;
|
||||
sexp src, dst;
|
||||
sexp* vec;
|
||||
int i;
|
||||
|
||||
for (i=0; i < sexp_bytecode_length(dstp); ) {
|
||||
switch (sexp_bytecode_data(dstp)[i++]) {
|
||||
case SEXP_OP_FCALL0: case SEXP_OP_FCALL1:
|
||||
case SEXP_OP_FCALL2: case SEXP_OP_FCALL3:
|
||||
case SEXP_OP_FCALL4: case SEXP_OP_CALL:
|
||||
case SEXP_OP_TAIL_CALL: case SEXP_OP_PUSH:
|
||||
case SEXP_OP_GLOBAL_REF: case SEXP_OP_GLOBAL_KNOWN_REF:
|
||||
#if SEXP_USE_GREEN_THREADS
|
||||
case SEXP_OP_PARAMETER_REF:
|
||||
#endif
|
||||
#if SEXP_USE_EXTENDED_FCALL
|
||||
case SEXP_OP_FCALLN:
|
||||
#endif
|
||||
vec = (sexp*)(&(sexp_bytecode_data(dstp)[i]));
|
||||
src = vec[0];
|
||||
if (src && sexp_pointerp(src)) {
|
||||
dst = adjust_fn(adata, src);
|
||||
if (!sexp_pointerp(dst)) {
|
||||
size_t sz = strlen(gc_heap_err_str);
|
||||
snprintf(gc_heap_err_str + sz, ERR_STR_SIZE - sz, " from adjust bytecode, FCALLN");
|
||||
goto done; }
|
||||
vec[0] = dst;
|
||||
}
|
||||
/* ... FALLTHROUGH ... */
|
||||
case SEXP_OP_JUMP: case SEXP_OP_JUMP_UNLESS:
|
||||
case SEXP_OP_STACK_REF: case SEXP_OP_CLOSURE_REF:
|
||||
case SEXP_OP_LOCAL_REF: case SEXP_OP_LOCAL_SET:
|
||||
case SEXP_OP_TYPEP:
|
||||
#if SEXP_USE_RESERVE_OPCODE
|
||||
case SEXP_OP_RESERVE:
|
||||
#endif
|
||||
i += sizeof(sexp); break;
|
||||
case SEXP_OP_MAKE: case SEXP_OP_SLOT_REF: case SEXP_OP_SLOT_SET:
|
||||
i += 2*sizeof(sexp); break;
|
||||
case SEXP_OP_MAKE_PROCEDURE:
|
||||
vec = (sexp*)(&(sexp_bytecode_data(dstp)[i]));
|
||||
src = vec[2];
|
||||
if (src && sexp_pointerp(src)) {
|
||||
dst = adjust_fn(adata, src);
|
||||
if (!sexp_pointerp(dst)) {
|
||||
size_t sz = strlen(gc_heap_err_str);
|
||||
snprintf(gc_heap_err_str + sz, ERR_STR_SIZE - sz, " from adjust bytecode, PROCEDURE");
|
||||
goto done; }
|
||||
vec[2] = dst;
|
||||
}
|
||||
i += 3*sizeof(sexp); break;
|
||||
}
|
||||
}
|
||||
res = SEXP_TRUE;
|
||||
done:
|
||||
return res;
|
||||
}
|
||||
|
||||
static sexp sexp_gc_heap_pack_adjust(sexp dstp, sexp* types, struct sexp_remap_state* state) {
|
||||
sexp res = SEXP_FALSE;
|
||||
/* Adjust internal types which contain fields of sexp pointer(s)
|
||||
within in the heap */
|
||||
if ((res = sexp_adjust_fields(dstp, types, sexp_gc_heap_pack_src_to_dst, state)) != SEXP_TRUE) {
|
||||
goto done; }
|
||||
|
||||
/* Other adjustments - context heap pointer, bytecode pointers */
|
||||
if (sexp_contextp(dstp)) {
|
||||
sexp_context_heap(dstp) = state->heap;
|
||||
} else if (sexp_bytecodep(dstp)) {
|
||||
if ((res = sexp_adjust_bytecode(dstp, sexp_gc_heap_pack_src_to_dst, state)) != SEXP_TRUE) {
|
||||
goto done; }
|
||||
}
|
||||
res = SEXP_TRUE;
|
||||
done:
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static sexp_heap sexp_gc_packed_heap_make(size_t packed_size, size_t free_size) {
|
||||
if (free_size > 0 && free_size < 2*sexp_free_chunk_size) {
|
||||
free_size = 2*sexp_free_chunk_size;
|
||||
}
|
||||
free_size = sexp_heap_align(free_size);
|
||||
size_t req_size = packed_size + free_size + sexp_free_chunk_size + 128;
|
||||
sexp_heap heap = sexp_make_heap(sexp_heap_align(req_size), 0, 0);
|
||||
if (!heap) {
|
||||
snprintf(gc_heap_err_str, ERR_STR_SIZE, "Could not allocate memory for heap");
|
||||
return NULL;
|
||||
}
|
||||
sexp base = sexp_heap_first_block(heap);
|
||||
size_t pad = (unsigned char *)base - (unsigned char *)heap->data;
|
||||
heap->size = packed_size + free_size + pad;
|
||||
heap->free_list->size = 0;
|
||||
if (free_size == 0) {
|
||||
heap->free_list->next = NULL;
|
||||
} else {
|
||||
heap->free_list->next = (sexp_free_list)((unsigned char *)base + packed_size);
|
||||
heap->free_list->next->next = NULL;
|
||||
heap->free_list->next->size = free_size;
|
||||
}
|
||||
return heap;
|
||||
}
|
||||
|
||||
static int heaps_compar(const void* v1, const void* v2) {
|
||||
sexp_heap h1 = *((sexp_heap*)v1);
|
||||
sexp_heap h2 = *((sexp_heap*)v2);
|
||||
return
|
||||
(h1 < h2) ? -1 :
|
||||
(h1 > h2) ? 1 : 0;
|
||||
}
|
||||
|
||||
/* Pack the heap. Return a new context with a unified, packed heap. No change to original context. */
|
||||
sexp sexp_gc_heap_pack(sexp ctx_src, sexp_uint_t heap_free_size) {
|
||||
|
||||
sexp res = NULL;
|
||||
sexp_gc(ctx_src, NULL);
|
||||
sexp_heap* heaps = NULL;
|
||||
int i = 0;
|
||||
|
||||
/* 1. Collect statistics - sexp count, size, heap count */
|
||||
|
||||
struct sexp_remap_state state;
|
||||
memset(&state, 0, sizeof(struct sexp_remap_state));
|
||||
state.ctx_src = ctx_src;
|
||||
if ((res = sexp_gc_heap_walk(ctx_src, sexp_context_heap(ctx_src),
|
||||
sexp_context_types(ctx_src), sexp_context_num_types(ctx_src),
|
||||
&state, heap_callback_count, NULL, sexp_callback_count)) != SEXP_TRUE) {
|
||||
goto done; }
|
||||
|
||||
/* 2. Make a new heap of the correct size to hold the sexps from the old heap. */
|
||||
|
||||
state.heap = sexp_gc_packed_heap_make(state.sexps_size, heap_free_size);
|
||||
if (!state.heap) {
|
||||
res = sexp_global(ctx_src, SEXP_G_OOM_ERROR);
|
||||
goto done; }
|
||||
|
||||
/* 3. Create a list of heaps sorted by increasing memory address, for srcp search lookup */
|
||||
|
||||
heaps = malloc(sizeof(sexp_heap) * state.heaps_count);
|
||||
if (!heaps) {
|
||||
res = sexp_global(ctx_src, SEXP_G_OOM_ERROR);
|
||||
goto done; }
|
||||
sexp_heap h = sexp_context_heap(ctx_src);
|
||||
for (i = 0; h; i++, h=h->next) { heaps[i] = h; }
|
||||
qsort(heaps, state.heaps_count, sizeof(sexp_heap), heaps_compar);
|
||||
|
||||
/* 4. Pack the sexps into the new heap */
|
||||
|
||||
state.p = sexp_heap_first_block(state.heap);
|
||||
state.end = sexp_heap_end(state.heap);
|
||||
state.index = 0;
|
||||
state.remap = malloc(sizeof(struct sexp_remap) * state.sexps_count);
|
||||
if (!state.remap) {
|
||||
res = sexp_global(ctx_src, SEXP_G_OOM_ERROR);
|
||||
goto done; }
|
||||
|
||||
for (i = 0; i < state.heaps_count; i++) {
|
||||
res = sexp_gc_heap_walk(ctx_src, heaps[i],
|
||||
sexp_context_types(ctx_src), sexp_context_num_types(ctx_src),
|
||||
&state, heap_callback_remap, NULL, sexp_callback_remap);
|
||||
if (!(res == SEXP_TRUE || res == SEXP_NULL)) {
|
||||
size_t sz = strlen(gc_heap_err_str);
|
||||
snprintf(gc_heap_err_str + sz, ERR_STR_SIZE - sz, "; remap heap %d %p walk heap_pack", i, heaps[i]);
|
||||
goto done; }
|
||||
}
|
||||
|
||||
/* 5. Adjust sexp pointers to new locations inside the new heap */
|
||||
|
||||
sexp* types = sexp_context_types(state.ctx_src);
|
||||
int idx;
|
||||
for (idx = 0; idx < state.sexps_count; idx++) {
|
||||
sexp dstp = state.remap[idx].dstp;
|
||||
res = sexp_gc_heap_pack_adjust(dstp, types, &state);
|
||||
if (res != SEXP_TRUE) {
|
||||
size_t sz = strlen(gc_heap_err_str);
|
||||
snprintf(gc_heap_err_str + sz, ERR_STR_SIZE - sz, "; src->dst idx=%d heap_pack", idx);
|
||||
goto done; }
|
||||
}
|
||||
|
||||
res = SEXP_TRUE;
|
||||
|
||||
done:
|
||||
/* 6. Clean up. */
|
||||
|
||||
if (state.heap && res != SEXP_TRUE) { sexp_free_heap(state.heap); }
|
||||
if (state.remap) { free(state.remap); }
|
||||
if (heaps) { free(heaps); }
|
||||
|
||||
return (res == SEXP_TRUE) ? state.ctx_dst : res;
|
||||
}
|
||||
|
||||
|
||||
#define SEXP_IMAGE_MAGIC "\a\achibi\n\0"
|
||||
#define SEXP_IMAGE_MAJOR_VERSION 1
|
||||
#define SEXP_IMAGE_MINOR_VERSION 1
|
||||
|
||||
struct sexp_image_header_t {
|
||||
char magic[8];
|
||||
short major, minor;
|
||||
sexp_abi_identifier_t abi;
|
||||
sexp_uint_t size;
|
||||
sexp base;
|
||||
sexp context;
|
||||
};
|
||||
|
||||
|
||||
sexp sexp_save_image (sexp ctx_in, const char* filename) {
|
||||
sexp_heap heap = NULL;
|
||||
sexp res = NULL;
|
||||
FILE *fp = fopen(filename, "wb");
|
||||
if (!fp) {
|
||||
snprintf(gc_heap_err_str, ERR_STR_SIZE, "Could not open image file for writing: %s", filename);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Save ONLY packed, active SEXPs. No free list structures or padding. */
|
||||
sexp ctx_out = sexp_gc_heap_pack(ctx_in, 0);
|
||||
if (!ctx_out || !sexp_contextp(ctx_out)) {
|
||||
goto done;
|
||||
}
|
||||
heap = sexp_context_heap(ctx_out);
|
||||
sexp base = sexp_heap_first_block(heap);
|
||||
size_t pad = (size_t)((unsigned char *)base - (unsigned char *)heap->data);
|
||||
size_t size = heap->size - pad;
|
||||
|
||||
struct sexp_image_header_t header;
|
||||
memcpy(&header.magic, SEXP_IMAGE_MAGIC, sizeof(header.magic));
|
||||
memcpy(&header.abi, SEXP_ABI_IDENTIFIER, sizeof(header.abi));
|
||||
header.major = SEXP_IMAGE_MAJOR_VERSION;
|
||||
header.minor = SEXP_IMAGE_MINOR_VERSION;
|
||||
header.size = size;
|
||||
header.base = base;
|
||||
header.context = ctx_out;
|
||||
|
||||
if (! (fwrite(&header, sizeof(header), 1, fp) == 1 &&
|
||||
fwrite(base, size, 1, fp) == 1)) {
|
||||
snprintf(gc_heap_err_str, ERR_STR_SIZE, "Error writing image file: %s", filename);
|
||||
goto done;
|
||||
}
|
||||
|
||||
res = SEXP_TRUE;
|
||||
done:
|
||||
if (fp) fclose(fp);
|
||||
if (heap) sexp_free_heap(heap);
|
||||
if (res != SEXP_TRUE) res = sexp_user_exception(ctx_in, NULL, gc_heap_err_str, SEXP_NULL);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if SEXP_USE_DL
|
||||
|
||||
#ifdef __APPLE__
|
||||
#define SEXP_RTLD_DEFAULT RTLD_SELF
|
||||
#else
|
||||
#define SEXP_RTLD_DEFAULT RTLD_DEFAULT
|
||||
#endif
|
||||
|
||||
struct load_image_state {
|
||||
sexp_sint_t offset;
|
||||
sexp_heap heap;
|
||||
sexp *types;
|
||||
size_t types_cnt;
|
||||
};
|
||||
|
||||
/* Return a destination (remapped) pointer for a given source pointer */
|
||||
static sexp load_image_src_to_dst(void* adata, sexp srcp) {
|
||||
struct load_image_state* state = adata;
|
||||
return (sexp)((unsigned char *)srcp + state->offset);
|
||||
}
|
||||
|
||||
|
||||
static sexp load_image_callback_p1 (sexp ctx, sexp p, void *user) {
|
||||
sexp res = NULL;
|
||||
struct load_image_state* state = user;
|
||||
|
||||
if ((res = sexp_adjust_fields(p, state->types, load_image_src_to_dst, state)) != SEXP_TRUE) {
|
||||
goto done; }
|
||||
|
||||
if (sexp_contextp(p)) {
|
||||
#if SEXP_USE_GREEN_THREADS
|
||||
sexp_context_ip(p) += state->offset;
|
||||
#endif
|
||||
sexp_context_last_fp(p) += state->offset;
|
||||
sexp_stack_top(sexp_context_stack(p)) = 0;
|
||||
sexp_context_saves(p) = NULL;
|
||||
sexp_context_heap(p) = state->heap;
|
||||
|
||||
} else if (sexp_bytecodep(p)) {
|
||||
if ((res = sexp_adjust_bytecode(p, load_image_src_to_dst, state)) != SEXP_TRUE) {
|
||||
goto done; }
|
||||
|
||||
} else if (sexp_portp(p) && sexp_port_stream(p)) {
|
||||
sexp_port_stream(p) = 0;
|
||||
sexp_port_openp(p) = 0;
|
||||
sexp_freep(p) = 0;
|
||||
|
||||
} else if (sexp_dlp(p)) {
|
||||
sexp_dl_handle(p) = NULL;
|
||||
|
||||
}
|
||||
res = SEXP_TRUE;
|
||||
done:
|
||||
return res;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
static void* load_image_fn(sexp ctx, sexp dl, sexp name) {
|
||||
snprintf(gc_heap_err_str, ERR_STR_SIZE,
|
||||
"load_image_fn: Needed to be ported to Win32");
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
static void* load_image_fn(sexp ctx, sexp dl, sexp name) {
|
||||
sexp ls;
|
||||
void *fn = NULL;
|
||||
char *file_name, *rel_name=NULL, *new_file_name;
|
||||
char *handle_name = "<static>";
|
||||
char *symbol_name = sexp_string_data(name);
|
||||
if (dl && sexp_dlp(dl)) {
|
||||
if (!sexp_dl_handle(dl)) {
|
||||
/* try exact file, then the search path */
|
||||
file_name = sexp_string_data(sexp_dl_file(dl));
|
||||
sexp_dl_handle(dl) = dlopen(file_name, RTLD_LAZY);
|
||||
if (!sexp_dl_handle(dl)) {
|
||||
for (ls = sexp_global(ctx, SEXP_G_MODULE_PATH); sexp_pairp(ls); ls=sexp_cdr(ls)) {
|
||||
if (strstr(file_name, sexp_string_data(sexp_car(ls))) == file_name) {
|
||||
rel_name = file_name + sexp_string_size(sexp_car(ls));
|
||||
while (*rel_name == '/')
|
||||
++rel_name;
|
||||
new_file_name = sexp_find_module_file_raw(ctx, rel_name);
|
||||
if (new_file_name) {
|
||||
sexp_dl_handle(dl) = dlopen(new_file_name, RTLD_LAZY);
|
||||
free(new_file_name);
|
||||
if (sexp_dl_handle(dl))
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!sexp_dl_handle(dl)) {
|
||||
handle_name = sexp_string_data(sexp_dl_file(dl));
|
||||
snprintf(gc_heap_err_str, ERR_STR_SIZE, "dlopen failure: %s",
|
||||
handle_name);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
fn = dlsym(sexp_dl_handle(dl), symbol_name);
|
||||
} else {
|
||||
fn = dlsym(SEXP_RTLD_DEFAULT, symbol_name);
|
||||
}
|
||||
if (!fn) {
|
||||
snprintf(gc_heap_err_str, ERR_STR_SIZE,
|
||||
"dynamic function lookup failure: %s %s",
|
||||
handle_name, symbol_name);
|
||||
}
|
||||
return fn;
|
||||
}
|
||||
#endif
|
||||
|
||||
static sexp load_image_callback_p2 (sexp ctx, sexp dstp, void *user) {
|
||||
sexp res = NULL;
|
||||
sexp name = NULL;
|
||||
void *fn = NULL;
|
||||
|
||||
if (sexp_opcodep(dstp) && sexp_opcode_func(dstp)) {
|
||||
if (sexp_opcode_data2(dstp) && sexp_stringp(sexp_opcode_data2(dstp))) {
|
||||
name = sexp_opcode_data2(dstp);
|
||||
} else {
|
||||
name = sexp_opcode_name(dstp);
|
||||
}
|
||||
if (!name) {
|
||||
snprintf(gc_heap_err_str, ERR_STR_SIZE, "opcode func field missing function name");
|
||||
return SEXP_FALSE;
|
||||
}
|
||||
|
||||
fn = load_image_fn(ctx, sexp_opcode_dl(dstp), name);
|
||||
if (!fn) {
|
||||
return SEXP_FALSE;
|
||||
}
|
||||
sexp_opcode_func(dstp) = fn;
|
||||
|
||||
} else if (sexp_typep(dstp) && sexp_type_finalize(dstp)) {
|
||||
name = sexp_type_finalize_name(dstp);
|
||||
if (!name) {
|
||||
snprintf(gc_heap_err_str, ERR_STR_SIZE, "type finalize field missing function name");
|
||||
return SEXP_FALSE;
|
||||
}
|
||||
fn = load_image_fn(ctx, sexp_type_dl(dstp), name);
|
||||
if (!fn) {
|
||||
return SEXP_FALSE;
|
||||
}
|
||||
sexp_type_finalize(dstp) = fn;
|
||||
}
|
||||
res = SEXP_TRUE;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static int load_image_header(FILE *fp, struct sexp_image_header_t* header) {
|
||||
if (!fp || !header) { return 0; }
|
||||
|
||||
if (fread(header, sizeof(struct sexp_image_header_t), 1, fp) != 1) {
|
||||
snprintf(gc_heap_err_str, ERR_STR_SIZE, "couldn't read image header");
|
||||
return 0;
|
||||
}
|
||||
if (memcmp(header->magic, SEXP_IMAGE_MAGIC, sizeof(header->magic)) != 0) {
|
||||
snprintf(gc_heap_err_str, ERR_STR_SIZE, "invalid image file magic %s\n", header->magic);
|
||||
return 0;
|
||||
} else if (header->major != SEXP_IMAGE_MAJOR_VERSION
|
||||
|| header->major < SEXP_IMAGE_MINOR_VERSION) {
|
||||
snprintf(gc_heap_err_str, ERR_STR_SIZE, "unsupported image version: %d.%d\n",
|
||||
header->major, header->minor);
|
||||
return 0;
|
||||
} else if (!sexp_abi_compatible(NULL, header->abi, SEXP_ABI_IDENTIFIER)) {
|
||||
snprintf(gc_heap_err_str, ERR_STR_SIZE, "unsupported ABI: %s (expected %s)\n",
|
||||
header->abi, SEXP_ABI_IDENTIFIER);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
char* sexp_load_image_err() {
|
||||
gc_heap_err_str[ERR_STR_SIZE-1] = 0;
|
||||
return gc_heap_err_str;
|
||||
}
|
||||
|
||||
static const char* all_paths[] = {sexp_default_module_path, sexp_default_user_module_path};
|
||||
|
||||
sexp sexp_load_image (const char* filename, off_t offset, sexp_uint_t heap_free_size, sexp_uint_t heap_max_size) {
|
||||
struct load_image_state state;
|
||||
struct sexp_image_header_t header;
|
||||
const char *mod_path, *colon, *end;
|
||||
char path[512];
|
||||
FILE *fp;
|
||||
int i, len;
|
||||
sexp res = NULL, ctx = NULL, base, *ctx_globals, *ctx_types;
|
||||
|
||||
gc_heap_err_str[0] = 0;
|
||||
|
||||
memset(&state, 0, sizeof(struct load_image_state));
|
||||
|
||||
fp = fopen(filename, "rb");
|
||||
/* fallback to the default search path (can't use sexp_find_module_file */
|
||||
/* since there's no context yet) */
|
||||
for (i=0; !fp && i<sizeof(all_paths)/sizeof(all_paths[0]); ++i) {
|
||||
for (mod_path=all_paths[i]; *mod_path; mod_path=colon+1) {
|
||||
colon = strchr(mod_path, ':');
|
||||
end = colon ? colon : mod_path + strlen(mod_path);
|
||||
snprintf(path, sizeof(path), "%s", mod_path);
|
||||
if (end[-1] != '/') path[end-mod_path] = '/';
|
||||
len = (end-mod_path) + (end[-1] == '/' ? 0 : 1);
|
||||
snprintf(path + len, sizeof(path) - len, "%s", filename);
|
||||
fp = fopen(path, "rb");
|
||||
if (fp || !colon) break;
|
||||
}
|
||||
}
|
||||
if (!fp) {
|
||||
snprintf(gc_heap_err_str, ERR_STR_SIZE, "couldn't open image file for reading: %s\n", filename);
|
||||
goto done;
|
||||
}
|
||||
if (offset > 0 && fseek(fp, offset, SEEK_SET) < 0) {
|
||||
snprintf(gc_heap_err_str, ERR_STR_SIZE, "couldn't seek to image offset: %s -> %"SEXP_PRIdOFF": %s\n", filename, offset, strerror(errno));
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!load_image_header(fp, &header)) { goto done; }
|
||||
|
||||
state.heap = sexp_gc_packed_heap_make(header.size, heap_free_size);
|
||||
if (!state.heap) {
|
||||
snprintf(gc_heap_err_str, ERR_STR_SIZE, "couldn't malloc heap\n");
|
||||
goto done;
|
||||
}
|
||||
base = sexp_heap_first_block(state.heap);
|
||||
|
||||
if (fread(base, 1, header.size, fp) != header.size) {
|
||||
snprintf(gc_heap_err_str, ERR_STR_SIZE, "error reading image\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Adjust pointers in loaded packed heap. */
|
||||
|
||||
state.offset = (sexp_sint_t)((sexp_sint_t)base - (sexp_sint_t)header.base);
|
||||
ctx = (sexp)((unsigned char *)header.context + state.offset);
|
||||
sexp_context_heap(ctx) = state.heap;
|
||||
|
||||
/* Type information (specifically, how big types are) is stored as sexps in the
|
||||
heap. This information is needed to sucessfully walk an arbitrary heap. A
|
||||
copy of the type array pointers with correct offsets is applied is created outside
|
||||
of the new heap to be used with the pointer adjustment process.
|
||||
*/
|
||||
ctx_globals = sexp_vector_data((sexp)((unsigned char*)sexp_context_globals(ctx) + state.offset));
|
||||
ctx_types = sexp_vector_data((sexp)((unsigned char*)(ctx_globals[SEXP_G_TYPES]) + state.offset));
|
||||
state.types_cnt = sexp_unbox_fixnum(ctx_globals[SEXP_G_NUM_TYPES]);
|
||||
state.types = malloc(sizeof(sexp) * state.types_cnt);
|
||||
if (!state.types) goto done;
|
||||
for (i = 0; i < state.types_cnt; i++) {
|
||||
state.types[i] = (sexp)((unsigned char *)ctx_types[i] + state.offset);
|
||||
}
|
||||
|
||||
if (sexp_gc_heap_walk(ctx, sexp_context_heap(ctx), state.types, state.types_cnt,
|
||||
&state, NULL, NULL, load_image_callback_p1) != SEXP_TRUE)
|
||||
goto done;
|
||||
|
||||
/* Second pass to fix code references */
|
||||
if (sexp_gc_heap_walk(ctx, sexp_context_heap(ctx), state.types, state.types_cnt,
|
||||
&state, NULL, NULL, load_image_callback_p2) != SEXP_TRUE)
|
||||
goto done;
|
||||
|
||||
if (heap_max_size > SEXP_INITIAL_HEAP_SIZE) {
|
||||
sexp_context_heap(ctx)->max_size = heap_max_size;
|
||||
}
|
||||
|
||||
res = ctx;
|
||||
done:
|
||||
if (fp) fclose(fp);
|
||||
if (state.heap && !ctx) free(state.heap);
|
||||
if (state.types) free(state.types);
|
||||
return res;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
sexp sexp_load_image (const char* filename, sexp_uint_t heap_free_size, sexp_uint_t heap_max_size) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
/****************** Debugging ************************/
|
||||
|
||||
/* you can use (chibi heap-stats) without debug enabled */
|
||||
#if SEXP_USE_DEBUG_GC
|
||||
|
||||
#define SEXP_CORE_TYPES_MAX 255
|
||||
|
||||
struct sexp_stats_entry {
|
||||
size_t count;
|
||||
size_t size_all;
|
||||
size_t size_min;
|
||||
size_t size_max;
|
||||
};
|
||||
|
||||
struct sexp_stats {
|
||||
struct sexp_stats_entry sexps[SEXP_CORE_TYPES_MAX+1];
|
||||
struct sexp_stats_entry heaps;
|
||||
struct sexp_stats_entry frees;
|
||||
size_t sexp_count;
|
||||
};
|
||||
|
||||
static void sexp_stats_entry_set(struct sexp_stats_entry *entry, size_t value) {
|
||||
entry->count += 1;
|
||||
entry->size_all += value;
|
||||
if (entry->size_min == 0 || value < entry->size_min) entry->size_min = value;
|
||||
if (value > entry->size_max) entry->size_max = value;
|
||||
}
|
||||
|
||||
static sexp heap_stats_callback(sexp ctx, sexp_heap h, void *user) {
|
||||
struct sexp_stats *stats = user;
|
||||
sexp_stats_entry_set(&(stats->heaps), h->size);
|
||||
return SEXP_TRUE;
|
||||
}
|
||||
|
||||
static sexp free_stats_callback(sexp ctx, sexp_free_list f, void *user) {
|
||||
struct sexp_stats *stats = user;
|
||||
sexp_stats_entry_set(&(stats->frees), f->size);
|
||||
return SEXP_TRUE;
|
||||
}
|
||||
|
||||
static sexp sexp_stats_callback(sexp ctx, sexp s, void *user) {
|
||||
struct sexp_stats *stats = user;
|
||||
int tag = sexp_pointer_tag(s);
|
||||
size_t size = sexp_gc_allocated_bytes(ctx, sexp_context_types(ctx),
|
||||
sexp_context_num_types(ctx), s);
|
||||
if (tag > SEXP_CORE_TYPES_MAX) tag = SEXP_CORE_TYPES_MAX;
|
||||
sexp_stats_entry_set(&(stats->sexps[tag]), size);
|
||||
stats->sexp_count += 1;
|
||||
return SEXP_TRUE;
|
||||
}
|
||||
|
||||
void sexp_gc_heap_stats_print(sexp ctx)
|
||||
{
|
||||
if (!ctx || !sexp_contextp(ctx)) return;
|
||||
|
||||
struct sexp_stats stats;
|
||||
memset(&stats, 0, sizeof(struct sexp_stats));
|
||||
sexp_gc_heap_walk(ctx, sexp_context_heap(ctx), sexp_context_types(ctx), sexp_context_num_types(ctx),
|
||||
&stats, heap_stats_callback, free_stats_callback, sexp_stats_callback);
|
||||
|
||||
printf("Heap Stats\n %6zu %7zu\n",
|
||||
stats.heaps.count, stats.heaps.size_all);
|
||||
printf("Free Stats\n %6zu %7zu %5zu %5zu\n",
|
||||
stats.frees.count, stats.frees.size_all, stats.frees.size_min, stats.frees.size_max);
|
||||
printf("Sexp Stats\n");
|
||||
size_t total_count = 0;
|
||||
size_t total_size = 0;
|
||||
int i;
|
||||
for (i = 0; i <= SEXP_CORE_TYPES_MAX; i++) {
|
||||
if (stats.sexps[i].count == 0) continue;
|
||||
printf("%3d %6zu %7zu %5zu %5zu\n", i,
|
||||
stats.sexps[i].count, stats.sexps[i].size_all, stats.sexps[i].size_min, stats.sexps[i].size_max);
|
||||
total_count += stats.sexps[i].count;
|
||||
total_size += stats.sexps[i].size_all;
|
||||
}
|
||||
printf(" ========================================\n");
|
||||
printf(" %6zu %7zu\n", total_count, total_size);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SEXP_USE_IMAGE_LOADING */
|
|
@ -1,5 +1,5 @@
|
|||
/* bignum.h -- header for bignum utilities */
|
||||
/* Copyright (c) 2009-2020 Alex Shinn. All rights reserved. */
|
||||
/* Copyright (c) 2009-2012 Alex Shinn. All rights reserved. */
|
||||
/* BSD-style license: http://synthcode.com/license.txt */
|
||||
|
||||
#ifndef SEXP_BIGNUM_H
|
||||
|
@ -7,23 +7,7 @@
|
|||
|
||||
#include "chibi/eval.h"
|
||||
|
||||
#if SEXP_USE_CUSTOM_LONG_LONGS
|
||||
#ifdef PLAN9
|
||||
#include <ape/stdint.h>
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
typedef struct
|
||||
{
|
||||
uint64_t hi;
|
||||
uint64_t lo;
|
||||
} sexp_luint_t;
|
||||
typedef struct
|
||||
{
|
||||
int64_t hi;
|
||||
uint64_t lo;
|
||||
} sexp_lsint_t;
|
||||
#elif SEXP_64_BIT
|
||||
#if (SEXP_64_BIT) && defined(__GNUC__)
|
||||
typedef unsigned int uint128_t __attribute__((mode(TI)));
|
||||
typedef int sint128_t __attribute__((mode(TI)));
|
||||
typedef uint128_t sexp_luint_t;
|
||||
|
@ -33,364 +17,6 @@ typedef unsigned long long sexp_luint_t;
|
|||
typedef long long sexp_lsint_t;
|
||||
#endif
|
||||
|
||||
#if !SEXP_USE_CUSTOM_LONG_LONGS
|
||||
|
||||
#define sexp_lsint_fits_sint(x) ((sexp_sint_t)x == x)
|
||||
#define sexp_luint_fits_uint(x) ((sexp_uint_t)x == x)
|
||||
#define lsint_from_sint(v) ((sexp_lsint_t)v)
|
||||
#define luint_from_uint(v) ((sexp_luint_t)v)
|
||||
#define lsint_to_sint(v) ((sexp_sint_t)v)
|
||||
#define luint_to_uint(v) ((sexp_uint_t)v)
|
||||
#define lsint_to_sint_hi(v) ((sexp_sint_t) ((v) >> (8*sizeof(sexp_sint_t))))
|
||||
#define luint_to_uint_hi(v) ((sexp_uint_t) ((v) >> (8*sizeof(sexp_uint_t))))
|
||||
#define lsint_negate(v) (-((sexp_lsint_t)v))
|
||||
#define luint_eq(a, b) (((sexp_luint_t)a)==((sexp_luint_t)b))
|
||||
#define luint_lt(a, b) (((sexp_luint_t)a)<((sexp_luint_t)b))
|
||||
#define lsint_lt_0(a) (((sexp_lsint_t)a)<0)
|
||||
#define luint_shl(a, shift) (((sexp_luint_t)a)<<(shift))
|
||||
#define luint_shr(a, shift) (((sexp_luint_t)a)>>(shift))
|
||||
#define luint_add(a, b) (((sexp_luint_t)a)+((sexp_luint_t)b))
|
||||
#define luint_add_uint(a, b) (((sexp_luint_t)a)+((sexp_uint_t)b))
|
||||
#define luint_sub(a, b) (((sexp_luint_t)a)-((sexp_luint_t)b))
|
||||
#define luint_mul_uint(a, b) (((sexp_luint_t)a)*((sexp_uint_t)b))
|
||||
#define lsint_mul_sint(a, b) (((sexp_lsint_t)a)*((sexp_sint_t)b))
|
||||
#define luint_div(a, b) (((sexp_luint_t)a)/((sexp_luint_t)b))
|
||||
#define luint_div_uint(a, b) (((sexp_luint_t)a)/((sexp_luint_t)b))
|
||||
#define luint_and(a, b) (((sexp_luint_t)a)&((sexp_luint_t)b))
|
||||
#define luint_is_fixnum(x) (((sexp_luint_t)x)<=SEXP_MAX_FIXNUM)
|
||||
#define lsint_is_fixnum(x) ((SEXP_MIN_FIXNUM <= ((sexp_lsint_t)x)) && (((sexp_lsint_t)x) <= SEXP_MAX_FIXNUM))
|
||||
|
||||
#else
|
||||
|
||||
static inline int lsint_lt_0(sexp_lsint_t a) {
|
||||
return a.hi < 0;
|
||||
}
|
||||
|
||||
static inline int sexp_lsint_fits_sint(sexp_lsint_t x) {
|
||||
return x.hi == (((int64_t)x.lo)>>63) && ((sexp_sint_t)x.lo == x.lo);
|
||||
}
|
||||
static inline int sexp_luint_fits_uint(sexp_luint_t x) {
|
||||
return x.hi == 0 && ((sexp_uint_t)x.lo == x.lo);
|
||||
}
|
||||
|
||||
static inline sexp_luint_t luint_from_lsint(sexp_lsint_t v) {
|
||||
sexp_luint_t result;
|
||||
result.hi = v.hi;
|
||||
result.lo = v.lo;
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline sexp_lsint_t lsint_from_luint(sexp_luint_t v) {
|
||||
sexp_lsint_t result;
|
||||
result.hi = v.hi;
|
||||
result.lo = v.lo;
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline sexp_lsint_t lsint_from_sint(sexp_sint_t v) {
|
||||
sexp_lsint_t result;
|
||||
result.hi = v >> 63;
|
||||
result.lo = v;
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline sexp_luint_t luint_from_uint(sexp_uint_t v) {
|
||||
sexp_luint_t result;
|
||||
result.hi = 0;
|
||||
result.lo = v;
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline sexp_sint_t lsint_to_sint(sexp_lsint_t v) {
|
||||
return v.lo;
|
||||
}
|
||||
|
||||
static inline sexp_uint_t luint_to_uint(sexp_luint_t v) {
|
||||
return v.lo;
|
||||
}
|
||||
|
||||
static inline sexp_sint_t lsint_to_sint_hi(sexp_lsint_t v) {
|
||||
#if SEXP_64_BIT
|
||||
return v.hi;
|
||||
#else
|
||||
return v.lo >> 32;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline sexp_uint_t luint_to_uint_hi(sexp_luint_t v) {
|
||||
#if SEXP_64_BIT
|
||||
return v.hi;
|
||||
#else
|
||||
return v.lo >> 32;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline sexp_lsint_t lsint_negate(sexp_lsint_t v) {
|
||||
sexp_luint_t a;
|
||||
a.hi = ~v.hi;
|
||||
a.lo = ~v.lo;
|
||||
|
||||
uint64_t aLoLo = a.lo & 0xFFFFFFFF;
|
||||
uint64_t aLoHi = a.lo >> 32;
|
||||
uint64_t aHiLo = a.hi & 0xFFFFFFFF;
|
||||
uint64_t aHiHi = a.hi >> 32;
|
||||
|
||||
uint64_t carry;
|
||||
uint64_t sumLoLo = aLoLo + 1;
|
||||
carry = sumLoLo >> 32;
|
||||
uint64_t resultLoLo = sumLoLo & 0xFFFFFFFF;
|
||||
|
||||
uint64_t sumLoHi = aLoHi + carry;
|
||||
uint64_t resultLoHi = sumLoHi & 0xFFFFFFFF;
|
||||
carry = sumLoHi >> 32;
|
||||
|
||||
uint64_t sumHiLo = aHiLo + carry;
|
||||
uint64_t resultHiLo = sumHiLo & 0xFFFFFFFF;
|
||||
carry = sumHiLo >> 32;
|
||||
|
||||
uint64_t sumHiHi = aHiHi + carry;
|
||||
uint64_t resultHiHi = sumHiHi & 0xFFFFFFFF;
|
||||
/* carry = sumHiHi >> 32; */
|
||||
|
||||
sexp_lsint_t result;
|
||||
result.hi = (resultHiHi << 32) | resultHiLo;
|
||||
result.lo = (resultLoHi << 32) | resultLoLo;
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline int luint_eq(sexp_luint_t a, sexp_luint_t b) {
|
||||
return (a.hi == b.hi) && (a.lo == b.lo);
|
||||
}
|
||||
|
||||
static inline int luint_lt(sexp_luint_t a, sexp_luint_t b) {
|
||||
if (a.hi < b.hi)
|
||||
return 1;
|
||||
else if (a.hi > b.hi)
|
||||
return 0;
|
||||
else
|
||||
return a.lo < b.lo;
|
||||
}
|
||||
|
||||
static inline sexp_luint_t luint_shl(sexp_luint_t v, size_t shift) {
|
||||
if (shift == 0)
|
||||
return v;
|
||||
sexp_luint_t result;
|
||||
if (shift >= 64) {
|
||||
result.hi = v.lo << (shift - 64);
|
||||
result.lo = 0;
|
||||
} else {
|
||||
result.hi = (v.hi << shift) | (v.lo >> (64-shift));
|
||||
result.lo = v.lo << shift;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline sexp_luint_t luint_shr(sexp_luint_t v, size_t shift) {
|
||||
if (shift == 0)
|
||||
return v;
|
||||
sexp_luint_t result;
|
||||
if (shift >= 64) {
|
||||
result.hi = 0;
|
||||
result.lo = v.hi >> (shift - 64);
|
||||
} else {
|
||||
result.hi = v.hi >> shift;
|
||||
result.lo = (v.lo >> shift) | (v.hi << (64-shift));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline sexp_luint_t luint_add(sexp_luint_t a, sexp_luint_t b) {
|
||||
uint64_t aLoLo = a.lo & 0xFFFFFFFF;
|
||||
uint64_t aLoHi = a.lo >> 32;
|
||||
uint64_t aHiLo = a.hi & 0xFFFFFFFF;
|
||||
uint64_t aHiHi = a.hi >> 32;
|
||||
uint64_t bLoLo = b.lo & 0xFFFFFFFF;
|
||||
uint64_t bLoHi = b.lo >> 32;
|
||||
uint64_t bHiLo = b.hi & 0xFFFFFFFF;
|
||||
uint64_t bHiHi = b.hi >> 32;
|
||||
|
||||
uint64_t carry;
|
||||
uint64_t sumLoLo = (aLoLo + bLoLo);
|
||||
carry = sumLoLo >> 32;
|
||||
uint64_t resultLoLo = sumLoLo & 0xFFFFFFFF;
|
||||
|
||||
uint64_t sumLoHi = (aLoHi + bLoHi) + carry;
|
||||
uint64_t resultLoHi = sumLoHi & 0xFFFFFFFF;
|
||||
carry = sumLoHi >> 32;
|
||||
|
||||
uint64_t sumHiLo = (aHiLo + bHiLo) + carry;
|
||||
uint64_t resultHiLo = sumHiLo & 0xFFFFFFFF;
|
||||
carry = sumHiLo >> 32;
|
||||
|
||||
uint64_t sumHiHi = (aHiHi + bHiHi) + carry;
|
||||
uint64_t resultHiHi = sumHiHi & 0xFFFFFFFF;
|
||||
/* carry = sumHiHi >> 32; */
|
||||
|
||||
sexp_luint_t result;
|
||||
result.hi = (resultHiHi << 32) | resultHiLo;
|
||||
result.lo = (resultLoHi << 32) | resultLoLo;
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline sexp_luint_t luint_add_uint(sexp_luint_t a, sexp_uint_t b) {
|
||||
uint64_t aLoLo = a.lo & 0xFFFFFFFF;
|
||||
uint64_t aLoHi = a.lo >> 32;
|
||||
uint64_t aHiLo = a.hi & 0xFFFFFFFF;
|
||||
uint64_t aHiHi = a.hi >> 32;
|
||||
uint64_t bLoLo = b & 0xFFFFFFFF;
|
||||
uint64_t bLoHi = b >> 32;
|
||||
|
||||
uint64_t carry;
|
||||
uint64_t sumLoLo = (aLoLo + bLoLo);
|
||||
carry = sumLoLo >> 32;
|
||||
uint64_t resultLoLo = sumLoLo & 0xFFFFFFFF;
|
||||
|
||||
uint64_t sumLoHi = (aLoHi + bLoHi) + carry;
|
||||
uint64_t resultLoHi = sumLoHi & 0xFFFFFFFF;
|
||||
carry = sumLoHi >> 32;
|
||||
|
||||
uint64_t sumHiLo = aHiLo + carry;
|
||||
uint64_t resultHiLo = sumHiLo & 0xFFFFFFFF;
|
||||
carry = sumHiLo >> 32;
|
||||
|
||||
uint64_t sumHiHi = aHiHi + carry;
|
||||
uint64_t resultHiHi = sumHiHi & 0xFFFFFFFF;
|
||||
/* carry = sumHiHi >> 32; */
|
||||
|
||||
sexp_luint_t result;
|
||||
result.hi = (resultHiHi << 32) | resultHiLo;
|
||||
result.lo = (resultLoHi << 32) | resultLoLo;
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline sexp_luint_t luint_sub(sexp_luint_t a, sexp_luint_t b) {
|
||||
sexp_luint_t negB;
|
||||
negB.hi = ~b.hi;
|
||||
negB.lo = ~b.lo;
|
||||
return luint_add(a, luint_add_uint(negB, 1));
|
||||
}
|
||||
|
||||
static inline sexp_luint_t luint_mul_uint(sexp_luint_t a, sexp_uint_t b) {
|
||||
uint64_t aLoLo = a.lo & 0xFFFFFFFF;
|
||||
uint64_t aLoHi = a.lo >> 32;
|
||||
uint64_t aHiLo = a.hi & 0xFFFFFFFF;
|
||||
uint64_t aHiHi = a.hi >> 32;
|
||||
|
||||
uint64_t bLo = b & 0xFFFFFFFF;
|
||||
uint64_t bHi = b >> 32;
|
||||
|
||||
sexp_luint_t resultBLo, resultBHi;
|
||||
{
|
||||
sexp_luint_t prodLoLo;
|
||||
prodLoLo.hi = 0;
|
||||
prodLoLo.lo = aLoLo * bLo;
|
||||
|
||||
sexp_luint_t prodLoHi;
|
||||
prodLoHi.hi = (aLoHi * bLo) >> 32;
|
||||
prodLoHi.lo = (aLoHi * bLo) << 32;
|
||||
|
||||
sexp_luint_t prodHiLo;
|
||||
prodHiLo.hi = aHiLo * bLo;
|
||||
prodHiLo.lo = 0;
|
||||
|
||||
sexp_luint_t prodHiHi;
|
||||
prodHiHi.hi = (aHiHi * bLo) << 32;
|
||||
prodHiHi.lo = 0;
|
||||
|
||||
resultBLo = luint_add(luint_add(luint_add(prodLoLo, prodLoHi), prodHiLo), prodHiHi);
|
||||
}
|
||||
{
|
||||
sexp_luint_t prodLoLo;
|
||||
prodLoLo.hi = 0;
|
||||
prodLoLo.lo = aLoLo * bHi;
|
||||
|
||||
sexp_luint_t prodLoHi;
|
||||
prodLoHi.hi = (aLoHi * bHi) >> 32;
|
||||
prodLoHi.lo = (aLoHi * bHi) << 32;
|
||||
|
||||
sexp_luint_t prodHiLo;
|
||||
prodHiLo.hi = aHiLo * bHi;
|
||||
prodHiLo.lo = 0;
|
||||
|
||||
sexp_luint_t prodHiHi;
|
||||
prodHiHi.hi = (aHiHi * bHi) << 32;
|
||||
prodHiHi.lo = 0;
|
||||
|
||||
resultBHi = luint_add(luint_add(luint_add(prodLoLo, prodLoHi), prodHiLo), prodHiHi);
|
||||
}
|
||||
|
||||
sexp_luint_t result = luint_add(resultBLo, luint_shl(resultBHi, 32));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline sexp_lsint_t lsint_mul_sint(sexp_lsint_t a, sexp_sint_t b) {
|
||||
if (lsint_lt_0(a)) {
|
||||
sexp_luint_t minusA = luint_from_lsint(lsint_negate(a));
|
||||
if (b < 0)
|
||||
return lsint_from_luint(luint_mul_uint(minusA, (sexp_uint_t)-b));
|
||||
else
|
||||
return lsint_negate(lsint_from_luint(luint_mul_uint(minusA, (sexp_uint_t)b)));
|
||||
} else {
|
||||
if (b < 0)
|
||||
return lsint_negate(lsint_from_luint(luint_mul_uint(luint_from_lsint(a), (sexp_uint_t)-b)));
|
||||
else
|
||||
return lsint_from_luint(luint_mul_uint(luint_from_lsint(a), (sexp_uint_t)b));
|
||||
}
|
||||
}
|
||||
|
||||
static inline sexp_luint_t luint_div(sexp_luint_t a, sexp_luint_t b) {
|
||||
if (luint_lt(a, b))
|
||||
return luint_from_uint(0);
|
||||
else if (luint_eq(a, b))
|
||||
return luint_from_uint(1);
|
||||
|
||||
sexp_luint_t quotient = luint_from_uint(0);
|
||||
sexp_luint_t remainder = luint_from_uint(0);
|
||||
|
||||
for (int i = 0; i < 128; i++) {
|
||||
quotient = luint_shl(quotient, 1);
|
||||
|
||||
remainder = luint_shl(remainder, 1);
|
||||
remainder.lo |= (a.hi >> 63) & 1;
|
||||
a = luint_shl(a, 1);
|
||||
|
||||
if (!(luint_lt(remainder, b))) {
|
||||
remainder = luint_sub(remainder, b);
|
||||
quotient.lo |= 1;
|
||||
}
|
||||
}
|
||||
|
||||
return quotient;
|
||||
}
|
||||
|
||||
static inline sexp_luint_t luint_div_uint(sexp_luint_t a, sexp_uint_t b) {
|
||||
return luint_div(a, luint_from_uint(b));
|
||||
}
|
||||
|
||||
static inline sexp_luint_t luint_and(sexp_luint_t a, sexp_luint_t b) {
|
||||
sexp_luint_t result;
|
||||
result.hi = a.hi & b.hi;
|
||||
result.lo = a.lo & b.lo;
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline int luint_is_fixnum(sexp_luint_t x) {
|
||||
return (x.hi == 0) && (x.lo <= SEXP_MAX_FIXNUM);
|
||||
}
|
||||
|
||||
static inline int lsint_is_fixnum(sexp_lsint_t x) {
|
||||
if (x.hi > 0)
|
||||
return 0;
|
||||
else if (x.hi == 0)
|
||||
return x.lo <= SEXP_MAX_FIXNUM;
|
||||
else if (x.hi == -1)
|
||||
return SEXP_MIN_FIXNUM <= x.lo;
|
||||
else return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
SEXP_API sexp_sint_t sexp_bignum_compare (sexp a, sexp b);
|
||||
SEXP_API sexp sexp_compare (sexp ctx, sexp a, sexp b);
|
||||
SEXP_API sexp sexp_make_bignum (sexp ctx, sexp_uint_t len);
|
||||
|
@ -400,9 +26,7 @@ SEXP_API sexp_uint_t sexp_bignum_hi (sexp a);
|
|||
SEXP_API sexp sexp_fixnum_to_bignum (sexp ctx, sexp a);
|
||||
SEXP_API double sexp_bignum_to_double (sexp a);
|
||||
SEXP_API sexp sexp_double_to_bignum (sexp ctx, double f);
|
||||
SEXP_API double sexp_to_double (sexp ctx, sexp x);
|
||||
SEXP_API sexp sexp_bignum_fxadd (sexp ctx, sexp a, sexp_uint_t b);
|
||||
SEXP_API sexp sexp_bignum_fxsub (sexp ctx, sexp a, sexp_uint_t b);
|
||||
SEXP_API sexp sexp_bignum_fxmul (sexp ctx, sexp d, sexp a, sexp_uint_t b, int offset);
|
||||
SEXP_API sexp_uint_t sexp_bignum_fxdiv (sexp ctx, sexp a, sexp_uint_t b, int offset);
|
||||
SEXP_API sexp sexp_bignum_add (sexp ctx, sexp dst, sexp a, sexp b);
|
||||
|
@ -410,7 +34,6 @@ SEXP_API sexp sexp_bignum_sub (sexp ctx, sexp dst, sexp a, sexp b);
|
|||
SEXP_API sexp sexp_bignum_mul (sexp ctx, sexp dst, sexp a, sexp b);
|
||||
SEXP_API sexp sexp_bignum_div (sexp ctx, sexp dst, sexp a, sexp b);
|
||||
SEXP_API sexp sexp_bignum_expt (sexp ctx, sexp n, sexp e);
|
||||
SEXP_API sexp sexp_bignum_sqrt (sexp ctx, sexp a, sexp* rem);
|
||||
SEXP_API sexp sexp_add (sexp ctx, sexp a, sexp b);
|
||||
SEXP_API sexp sexp_sub (sexp ctx, sexp a, sexp b);
|
||||
SEXP_API sexp sexp_mul (sexp ctx, sexp a, sexp b);
|
||||
|
@ -419,15 +42,13 @@ SEXP_API sexp sexp_quotient (sexp ctx, sexp a, sexp b);
|
|||
SEXP_API sexp sexp_remainder (sexp ctx, sexp a, sexp b);
|
||||
#if SEXP_USE_RATIOS
|
||||
SEXP_API sexp sexp_double_to_ratio (sexp ctx, double f);
|
||||
SEXP_API sexp sexp_double_to_ratio_2 (sexp ctx, double f);
|
||||
SEXP_API double sexp_ratio_to_double (sexp ctx, sexp rat);
|
||||
SEXP_API double sexp_ratio_to_double (sexp rat);
|
||||
SEXP_API sexp sexp_make_ratio (sexp ctx, sexp num, sexp den);
|
||||
SEXP_API sexp sexp_ratio_normalize (sexp ctx, sexp rat, sexp in);
|
||||
SEXP_API sexp sexp_ratio_round (sexp ctx, sexp a);
|
||||
SEXP_API sexp sexp_ratio_trunc (sexp ctx, sexp a);
|
||||
SEXP_API sexp sexp_ratio_floor (sexp ctx, sexp a);
|
||||
SEXP_API sexp sexp_ratio_ceiling (sexp ctx, sexp a);
|
||||
SEXP_API sexp sexp_ratio_compare (sexp ctx, sexp a, sexp b);
|
||||
#endif
|
||||
#if SEXP_USE_COMPLEX
|
||||
SEXP_API sexp sexp_make_complex (sexp ctx, sexp real, sexp image);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* eval.h -- headers for eval library */
|
||||
/* Copyright (c) 2009-2015 Alex Shinn. All rights reserved. */
|
||||
/* Copyright (c) 2009-2011 Alex Shinn. All rights reserved. */
|
||||
/* BSD-style license: http://synthcode.com/license.txt */
|
||||
|
||||
#ifndef SEXP_EVAL_H
|
||||
|
@ -15,7 +15,7 @@ extern "C" {
|
|||
|
||||
#define sexp_init_file "init-"
|
||||
#define sexp_init_file_suffix ".scm"
|
||||
#define sexp_meta_file "meta-7.scm"
|
||||
#define sexp_meta_file "meta.scm"
|
||||
#define sexp_leap_seconds_file "leap.txt"
|
||||
|
||||
enum sexp_core_form_names {
|
||||
|
@ -46,18 +46,19 @@ enum sexp_opcode_classes {
|
|||
SEXP_OPC_NUM_OP_CLASSES
|
||||
};
|
||||
|
||||
SEXP_API struct sexp_opcode_struct* sexp_primitive_opcodes;
|
||||
|
||||
#if SEXP_USE_DEBUG_VM || SEXP_USE_PROFILE_VM || SEXP_USE_STATIC_LIBS
|
||||
SEXP_API const char** sexp_opcode_names;
|
||||
#endif
|
||||
|
||||
/**************************** prototypes ******************************/
|
||||
|
||||
SEXP_API void sexp_warn (sexp ctx, const char *msg, sexp x);
|
||||
SEXP_API void sexp_warn (sexp ctx, char *msg, sexp x);
|
||||
SEXP_API void sexp_scheme_init (void);
|
||||
SEXP_API sexp sexp_make_eval_context (sexp context, sexp stack, sexp env, sexp_uint_t size, sexp_uint_t max_size);
|
||||
SEXP_API sexp sexp_make_child_context (sexp context, sexp lambda);
|
||||
SEXP_API sexp sexp_compile_error (sexp ctx, const char *message, sexp obj);
|
||||
SEXP_API sexp sexp_maybe_wrap_error (sexp ctx, sexp obj);
|
||||
SEXP_API sexp sexp_analyze (sexp context, sexp x);
|
||||
SEXP_API sexp sexp_simplify (sexp ctx, sexp self, sexp_sint_t n, sexp ast);
|
||||
SEXP_API sexp sexp_make_lambda (sexp ctx, sexp params);
|
||||
|
@ -74,33 +75,28 @@ SEXP_API void sexp_bless_bytecode (sexp ctx, sexp bc);
|
|||
#endif
|
||||
SEXP_API sexp sexp_complete_bytecode (sexp ctx);
|
||||
SEXP_API void sexp_shrink_bcode (sexp ctx, sexp_uint_t i);
|
||||
SEXP_API void sexp_expand_bcode (sexp ctx, sexp_sint_t size);
|
||||
SEXP_API void sexp_expand_bcode (sexp ctx, sexp_uint_t size);
|
||||
SEXP_API void sexp_stack_trace (sexp ctx, sexp out);
|
||||
SEXP_API sexp sexp_free_vars (sexp context, sexp x, sexp fv);
|
||||
SEXP_API int sexp_param_index (sexp ctx, sexp lambda, sexp name);
|
||||
SEXP_API int sexp_param_index (sexp lambda, sexp name);
|
||||
SEXP_API sexp sexp_compile_op (sexp context, sexp self, sexp_sint_t n, sexp obj, sexp env);
|
||||
SEXP_API sexp sexp_generate_op (sexp context, sexp self, sexp_sint_t n, sexp obj, sexp env);
|
||||
SEXP_API sexp sexp_eval_op (sexp context, sexp self, sexp_sint_t n, sexp obj, sexp env);
|
||||
SEXP_API sexp sexp_eval_string (sexp context, const char *str, sexp_sint_t len, sexp env);
|
||||
SEXP_API sexp sexp_load_op (sexp context, sexp self, sexp_sint_t n, sexp expr, sexp env);
|
||||
SEXP_API sexp sexp_exception_type_op (sexp ctx, sexp self, sexp_sint_t n, sexp exn);
|
||||
SEXP_API sexp sexp_make_env_op (sexp context, sexp self, sexp_sint_t n);
|
||||
SEXP_API sexp sexp_make_null_env_op (sexp context, sexp self, sexp_sint_t n, sexp version);
|
||||
SEXP_API sexp sexp_env_cell_define (sexp ctx, sexp env, sexp name, sexp value, sexp* varenv);
|
||||
SEXP_API sexp sexp_make_primitive_env_op (sexp context, sexp self, sexp_sint_t n, sexp version);
|
||||
SEXP_API sexp sexp_make_primitive_env (sexp context, sexp version);
|
||||
SEXP_API sexp sexp_make_standard_env_op (sexp context, sexp self, sexp_sint_t n, sexp version);
|
||||
SEXP_API void sexp_set_parameter (sexp ctx, sexp env, sexp name, sexp value);
|
||||
SEXP_API sexp sexp_load_standard_ports (sexp context, sexp env, FILE* in, FILE* out, FILE* err, int no_close);
|
||||
SEXP_API sexp sexp_load_standard_env (sexp context, sexp env, sexp version);
|
||||
SEXP_API char* sexp_find_module_file_raw (sexp ctx, const char *file);
|
||||
SEXP_API sexp sexp_find_module_file (sexp ctx, const char *file);
|
||||
SEXP_API sexp sexp_load_module_file (sexp ctx, const char *file, sexp env);
|
||||
SEXP_API sexp sexp_current_module_path_op (sexp ctx, sexp self, sexp_sint_t n, sexp x);
|
||||
SEXP_API sexp sexp_find_module_file_op (sexp ctx, sexp self, sexp_sint_t n, sexp file);
|
||||
SEXP_API sexp sexp_load_module_file_op (sexp ctx, sexp self, sexp_sint_t n, sexp file, sexp env);
|
||||
SEXP_API sexp sexp_add_module_directory_op (sexp ctx, sexp self, sexp_sint_t n, sexp dir, sexp appendp);
|
||||
SEXP_API sexp sexp_current_environment (sexp ctx, sexp self, sexp_sint_t n);
|
||||
SEXP_API sexp sexp_set_current_environment (sexp ctx, sexp self, sexp_sint_t n, sexp env);
|
||||
SEXP_API sexp sexp_meta_environment (sexp ctx, sexp self, sexp_sint_t n);
|
||||
SEXP_API sexp sexp_extend_env (sexp ctx, sexp env, sexp vars, sexp value);
|
||||
SEXP_API sexp sexp_env_import_op (sexp ctx, sexp self, sexp_sint_t n, sexp to, sexp from, sexp ls, sexp immutp);
|
||||
|
@ -115,37 +111,27 @@ SEXP_API sexp sexp_open_output_file_op(sexp ctx, sexp self, sexp_sint_t n, sexp
|
|||
SEXP_API sexp sexp_open_binary_input_file(sexp ctx, sexp self, sexp_sint_t n, sexp x);
|
||||
SEXP_API sexp sexp_open_binary_output_file(sexp ctx, sexp self, sexp_sint_t n, sexp x);
|
||||
SEXP_API sexp sexp_close_port_op(sexp ctx, sexp self, sexp_sint_t n, sexp x);
|
||||
SEXP_API sexp sexp_set_port_line_op (sexp ctx, sexp self, sexp_sint_t n, sexp port, sexp line);
|
||||
SEXP_API sexp sexp_env_define (sexp ctx, sexp env, sexp sym, sexp val);
|
||||
SEXP_API sexp sexp_env_cell (sexp ctx, sexp env, sexp sym, int localp);
|
||||
SEXP_API sexp sexp_env_ref (sexp ctx, sexp env, sexp sym, sexp dflt);
|
||||
SEXP_API sexp sexp_env_parent_op (sexp ctx, sexp self, sexp_sint_t n, sexp env);
|
||||
SEXP_API sexp sexp_env_cell (sexp env, sexp sym, int localp);
|
||||
SEXP_API sexp sexp_env_ref (sexp env, sexp sym, sexp dflt);
|
||||
SEXP_API sexp sexp_parameter_ref (sexp ctx, sexp param);
|
||||
#if SEXP_USE_RENAME_BINDINGS
|
||||
SEXP_API sexp sexp_env_rename (sexp ctx, sexp env, sexp key, sexp value);
|
||||
#endif
|
||||
SEXP_API sexp sexp_warn_undefs_op (sexp ctx, sexp self, sexp_sint_t n, sexp from, sexp to, sexp res);
|
||||
SEXP_API sexp sexp_make_lit (sexp ctx, sexp value);
|
||||
SEXP_API sexp sexp_make_opcode (sexp, sexp, sexp, sexp, sexp, sexp, sexp, sexp, sexp, sexp, sexp, sexp, sexp_proc1);
|
||||
SEXP_API sexp sexp_make_procedure_op (sexp ctx, sexp self, sexp_sint_t n, sexp flags, sexp num_args, sexp bc, sexp vars);
|
||||
SEXP_API sexp sexp_define_foreign_aux (sexp ctx, sexp env, const char *name, int num_args, int flags, const char *fname, sexp_proc1 f, sexp data);
|
||||
SEXP_API sexp sexp_define_foreign_proc_aux (sexp ctx, sexp env, const char *name, int num_args, int flags, const char *fname, sexp_proc1 f, sexp data);
|
||||
SEXP_API sexp sexp_define_foreign_aux (sexp ctx, sexp env, const char *name, int num_args, int flags, sexp_proc1 f, sexp data);
|
||||
SEXP_API sexp sexp_register_optimization(sexp ctx, sexp self, sexp_sint_t n, sexp f, sexp i);
|
||||
#if SEXP_USE_AUTO_FORCE
|
||||
SEXP_API sexp sexp_make_promise (sexp ctx, sexp self, sexp_sint_t n, sexp done, sexp val);
|
||||
#endif
|
||||
#if SEXP_USE_UTF8_STRINGS
|
||||
SEXP_API sexp sexp_read_utf8_char (sexp ctx, sexp port, int i);
|
||||
SEXP_API void sexp_push_utf8_char (sexp ctx, int i, sexp port);
|
||||
SEXP_API void sexp_string_utf8_set (sexp ctx, sexp str, sexp index, sexp ch);
|
||||
SEXP_API sexp sexp_string_utf8_index_ref (sexp ctx, sexp self, sexp_sint_t n, sexp str, sexp i);
|
||||
SEXP_API sexp sexp_string_utf8_index_set (sexp ctx, sexp self, sexp_sint_t n, sexp str, sexp i, sexp ch);
|
||||
#endif
|
||||
#if SEXP_USE_GREEN_THREADS
|
||||
SEXP_API sexp sexp_dk (sexp ctx, sexp self, sexp_sint_t n, sexp val);
|
||||
#endif
|
||||
SEXP_API sexp sexp_thread_parameters (sexp ctx, sexp self, sexp_sint_t n);
|
||||
SEXP_API sexp sexp_thread_parameters_set (sexp ctx, sexp self, sexp_sint_t n, sexp val);
|
||||
#endif
|
||||
SEXP_API sexp sexp_string_cmp_op (sexp ctx, sexp self, sexp_sint_t n, sexp a, sexp b, sexp ci);
|
||||
#if SEXP_USE_RATIOS
|
||||
SEXP_API sexp sexp_ratio_numerator_op (sexp ctx, sexp self, sexp_sint_t n, sexp rat);
|
||||
|
@ -170,33 +156,28 @@ SEXP_API sexp sexp_asin(sexp ctx, sexp self, sexp_sint_t n, sexp z);
|
|||
SEXP_API sexp sexp_acos(sexp ctx, sexp self, sexp_sint_t n, sexp z);
|
||||
SEXP_API sexp sexp_atan(sexp ctx, sexp self, sexp_sint_t n, sexp z);
|
||||
SEXP_API sexp sexp_sqrt(sexp ctx, sexp self, sexp_sint_t n, sexp z);
|
||||
SEXP_API sexp sexp_exact_sqrt(sexp ctx, sexp self, sexp_sint_t n, sexp z);
|
||||
SEXP_API sexp sexp_inexact_sqrt(sexp ctx, sexp self, sexp_sint_t n, sexp z);
|
||||
SEXP_API sexp sexp_round(sexp ctx, sexp self, sexp_sint_t n, sexp x);
|
||||
SEXP_API sexp sexp_trunc(sexp ctx, sexp self, sexp_sint_t n, sexp x);
|
||||
SEXP_API sexp sexp_floor(sexp ctx, sexp self, sexp_sint_t n, sexp x);
|
||||
SEXP_API sexp sexp_ceiling(sexp ctx, sexp self, sexp_sint_t n, sexp x);
|
||||
#endif
|
||||
SEXP_API sexp sexp_expt_op(sexp ctx, sexp self, sexp_sint_t n, sexp z1, sexp z2);
|
||||
SEXP_API sexp sexp_exact_to_inexact(sexp ctx, sexp self, sexp_sint_t n, sexp i);
|
||||
SEXP_API sexp sexp_inexact_to_exact(sexp ctx, sexp self, sexp_sint_t n, sexp x);
|
||||
|
||||
#if SEXP_USE_NATIVE_X86
|
||||
SEXP_API sexp sexp_write_char_op(sexp ctx, sexp self, sexp_sint_t n, sexp ch, sexp out);
|
||||
SEXP_API sexp sexp_newline_op(sexp ctx, sexp self, sexp_sint_t n, sexp out);
|
||||
SEXP_API sexp sexp_read_char_op(sexp ctx, sexp self, sexp_sint_t n, sexp in);
|
||||
SEXP_API sexp sexp_peek_char_op(sexp ctx, sexp self, sexp_sint_t n, sexp in);
|
||||
SEXP_API sexp sexp_exact_to_inexact(sexp ctx, sexp self, sexp_sint_t n, sexp i);
|
||||
SEXP_API sexp sexp_inexact_to_exact(sexp ctx, sexp self, sexp_sint_t n, sexp x);
|
||||
SEXP_API sexp sexp_char_upcase(sexp ctx, sexp self, sexp_sint_t n, sexp ch);
|
||||
SEXP_API sexp sexp_char_downcase(sexp ctx, sexp self, sexp_sint_t n, sexp ch);
|
||||
#endif
|
||||
|
||||
SEXP_API sexp sexp_define_foreign_param_aux(sexp ctx, sexp env, const char *name, int num_args, const char *fname, sexp_proc1 f, const char *param);
|
||||
#define sexp_define_foreign(c,e,s,n,f) sexp_define_foreign_aux(c,e,s,n,0,(sexp_proc1)f,NULL)
|
||||
#define sexp_define_foreign_opt(c,e,s,n,f,d) sexp_define_foreign_aux(c,e,s,n,1,(sexp_proc1)f,d)
|
||||
|
||||
#define sexp_define_foreign(c,e,s,n,f) sexp_define_foreign_aux(c,e,s,n,0,(const char*)#f,(sexp_proc1)f,NULL)
|
||||
#define sexp_define_foreign_param(c,e,s,n,f,p) sexp_define_foreign_param_aux(c,e,s,n,(const char*)#f,(sexp_proc1)f,p)
|
||||
#define sexp_define_foreign_opt(c,e,s,n,f,p) sexp_define_foreign_aux(c,e,s,n,1,(const char*)#f,(sexp_proc1)f,p)
|
||||
#define sexp_define_foreign_proc(c,e,s,n,f) sexp_define_foreign_proc_aux(c,e,s,n,SEXP_PROC_NONE,(const char*)#f,(sexp_proc1)f,NULL)
|
||||
#define sexp_define_foreign_proc_rest(c,e,s,n,f) sexp_define_foreign_proc_aux(c,e,s,n,SEXP_PROC_VARIADIC,(const char*)#f,(sexp_proc1)f,NULL)
|
||||
SEXP_API sexp sexp_define_foreign_param (sexp ctx, sexp env, const char *name, int num_args, sexp_proc1 f, const char *param);
|
||||
|
||||
#define sexp_env_key(x) sexp_car(x)
|
||||
#define sexp_env_value(x) sexp_cdr(x)
|
||||
|
@ -238,9 +219,6 @@ SEXP_API sexp sexp_9p_req_fid (sexp ctx, sexp self, sexp_sint_t n, sexp req);
|
|||
SEXP_API sexp sexp_9p_req_newfid (sexp ctx, sexp self, sexp_sint_t n, sexp req);
|
||||
SEXP_API sexp sexp_9p_respond (sexp ctx, sexp self, sexp_sint_t n, sexp req, sexp err);
|
||||
SEXP_API sexp sexp_9p_responderror (sexp ctx, sexp self, sexp_sint_t n, sexp req);
|
||||
#else
|
||||
SEXP_API sexp sexp_get_port_fileno (sexp ctx, sexp self, sexp_sint_t n, sexp port);
|
||||
SEXP_API sexp sexp_stream_portp_op (sexp ctx, sexp self, sexp_sint_t n, sexp port);
|
||||
#endif
|
||||
|
||||
#if SEXP_USE_SIMPLIFY
|
||||
|
@ -254,8 +232,7 @@ SEXP_API int sexp_rest_unused_p (sexp lambda);
|
|||
#define sexp_make_procedure(ctx, f, n, b, v) sexp_make_procedure_op(ctx, NULL, 4, f, n, b, v)
|
||||
#define sexp_make_env(ctx) sexp_make_env_op(ctx, NULL, 0)
|
||||
#define sexp_make_null_env(ctx, v) sexp_make_null_env_op(ctx, NULL, 0, v)
|
||||
#define sexp_make_primitive_env(ctx, v) sexp_make_primitive_env_op(ctx, NULL, 1, v)
|
||||
#define sexp_make_standard_env(ctx, v) sexp_make_standard_env_op(ctx, NULL, 1, v)
|
||||
#define sexp_make_standard_env(ctx) sexp_make_standard_env_op(ctx, NULL, 0)
|
||||
#define sexp_add_module_directory(ctx, d, a) sexp_add_module_directory_op(ctx, NULL, 1, d, a)
|
||||
#define sexp_eval(ctx, x, e) sexp_eval_op(ctx, NULL, 2, x, e)
|
||||
#define sexp_load(ctx, f, e) sexp_load_op(ctx, NULL, 2, f, e)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* features.h -- general feature configuration */
|
||||
/* Copyright (c) 2009-2021 Alex Shinn. All rights reserved. */
|
||||
/* Copyright (c) 2009-2012 Alex Shinn. All rights reserved. */
|
||||
/* BSD-style license: http://synthcode.com/license.txt */
|
||||
|
||||
/* uncomment this to disable most features */
|
||||
|
@ -23,27 +23,16 @@
|
|||
/* sexp_init_library(ctx, env) function provided. */
|
||||
/* #define SEXP_USE_DL 0 */
|
||||
|
||||
/* uncomment this to support statically compiled C libs */
|
||||
/* Unless SEXP_USE_STATIC_LIBS_EMPTY is set (see below), this */
|
||||
/* will statically include the clibs.c file into the standard */
|
||||
/* environment, so that you can have access to a predefined set */
|
||||
/* of C libraries without needing dynamic loading. The clibs.c */
|
||||
/* file is generated automatically by searching the lib directory */
|
||||
/* for modules with include-shared, but can be hand-tailored to */
|
||||
/* your needs. You can also register your own C libraries using */
|
||||
/* sexp_add_static_libraries (see below). */
|
||||
/* uncomment this to statically compile all C libs */
|
||||
/* If set, this will statically include the clibs.c file */
|
||||
/* into the standard environment, so that you can have */
|
||||
/* access to a predefined set of C libraries without */
|
||||
/* needing dynamic loading. The clibs.c file is generated */
|
||||
/* automatically by searching the lib directory for */
|
||||
/* modules with include-shared, but can be hand-tailored */
|
||||
/* to your needs. */
|
||||
/* #define SEXP_USE_STATIC_LIBS 1 */
|
||||
|
||||
/* uncomment this to enable user exported C libs */
|
||||
/* You can register your own C libraries using */
|
||||
/* sexp_add_static_libraries. Each entry in the supplied table, */
|
||||
/* is a name/entry point pair. These work as if they were */
|
||||
/* dynamically loaded libraries, so naming follows the same */
|
||||
/* conventions. An entry {"foo", init_foo} will register a */
|
||||
/* library that can be loaded with (load "foo"), or */
|
||||
/* (include-shared "foo"), both of which will call init_foo. */
|
||||
/* #define SEXP_USE_STATIC_LIBS_EMPTY 1 */
|
||||
|
||||
/* uncomment this to disable detailed source info for debugging */
|
||||
/* By default Chibi will associate source info with every */
|
||||
/* bytecode offset. By disabling this only lambda-level source */
|
||||
|
@ -75,21 +64,9 @@
|
|||
/* if you suspect a bug in the native GC. */
|
||||
/* #define SEXP_USE_BOEHM 1 */
|
||||
|
||||
/* uncomment this to enable automatic file descriptor unification */
|
||||
/* File descriptors as returned by C functions are raw integers, */
|
||||
/* which are convereted to GC'ed first-class objects on the Scheme */
|
||||
/* side. By default we assume that each fd is new, however if this */
|
||||
/* option is enabled and an fd is returned which matches an existing */
|
||||
/* open fd, they are assumed to refer to the same descriptor and */
|
||||
/* unified. */
|
||||
/* #define SEXP_USE_UNIFY_FILENOS_BY_NUMBER 1 */
|
||||
|
||||
/* uncomment this to disable weak references */
|
||||
/* #define SEXP_USE_WEAK_REFERENCES 0 */
|
||||
|
||||
/* uncomment this to enable heap regions for fixed-size chunks */
|
||||
/* #define SEXP_USE_FIXED_CHUNK_SIZE_HEAPS 1 */
|
||||
|
||||
/* uncomment this to just malloc manually instead of any GC */
|
||||
/* Mostly for debugging purposes, this is the no GC option. */
|
||||
/* You can use just the read/write API and */
|
||||
|
@ -104,30 +81,18 @@
|
|||
/* go away and you're not working on your own C extension. */
|
||||
/* #define SEXP_USE_CONSERVATIVE_GC 1 */
|
||||
|
||||
/* uncomment this to disable automatic running of finalizers */
|
||||
/* You will need to close ports and file descriptors manually */
|
||||
/* (as you should anyway) and some C extensions may break. */
|
||||
/* #define SEXP_USE_FINALIZERS 0 */
|
||||
|
||||
/* uncomment this to add additional native checks to only mark objects in the heap */
|
||||
/* #define SEXP_USE_SAFE_GC_MARK 1 */
|
||||
|
||||
/* uncomment this to track what C source line each object is allocated from */
|
||||
/* #define SEXP_USE_TRACK_ALLOC_SOURCE 1 */
|
||||
|
||||
/* uncomment this to take a short backtrace of where each object is */
|
||||
/* allocated from */
|
||||
/* #define SEXP_USE_TRACK_ALLOC_BACKTRACE 1 */
|
||||
|
||||
/* uncomment this to add additional native gc checks to verify a magic header */
|
||||
/* #define SEXP_USE_HEADER_MAGIC 1 */
|
||||
|
||||
/* uncomment this to add very verbose debugging stats to the native GC */
|
||||
/* #define SEXP_USE_DEBUG_GC 1 */
|
||||
|
||||
/* uncomment this to add instrumentation to the native GC */
|
||||
/* #define SEXP_USE_TIME_GC 1 */
|
||||
|
||||
/* uncomment this to enable "safe" field accessors for primitive types */
|
||||
/* The sexp union type fields are abstracted away with macros of the */
|
||||
/* form sexp_<type>_<field>(<obj>), however these are just convenience */
|
||||
|
@ -143,10 +108,6 @@
|
|||
/* may be very slow and using CFLAGS=-O0 is recommended. */
|
||||
/* #define SEXP_USE_SAFE_ACCESSORS 1 */
|
||||
|
||||
/* uncomment to install a default signal handler in main() for segfaults */
|
||||
/* This will print a helpful backtrace. */
|
||||
/* #define SEXP_USE_PRINT_BACKTRACE_ON_SEGFAULT 1 */
|
||||
|
||||
/* uncomment this to make the heap common to all contexts */
|
||||
/* By default separate contexts can have separate heaps, */
|
||||
/* and are thus thread-safe and independant. */
|
||||
|
@ -188,27 +149,11 @@
|
|||
/* uncomment this if you don't want 1## style approximate digits */
|
||||
/* #define SEXP_USE_PLACEHOLDER_DIGITS 0 */
|
||||
|
||||
/* uncomment this to disable a workaround for numeric formatting, */
|
||||
/* to fix numbers in locales which don't use the '.' decimal sep */
|
||||
/* #define SEXP_USE_PATCH_NON_DECIMAL_NUMERIC_FORMATS 0 */
|
||||
|
||||
/* uncomment this if you don't need extended math operations */
|
||||
/* This includes the trigonometric and expt functions. */
|
||||
/* Automatically disabled if you've disabled flonums. */
|
||||
/* #define SEXP_USE_MATH 0 */
|
||||
|
||||
/* uncomment this to enable lenient matching of top-level bindings */
|
||||
/* Historically, to match behavior with some other Schemes and in */
|
||||
/* hopes of making it easier to use macros and modules, Chibi allowed */
|
||||
/* top-level bindings with the same underlying symbol name to match */
|
||||
/* with identifier=?. In particular, there still isn't a good way */
|
||||
/* to handle the case where auxiliary syntax conflicts with some other */
|
||||
/* binding without renaming one or the other (though SRFI 206 helps). */
|
||||
/* However, if people make use of this you can write Chibi programs */
|
||||
/* which don't work portably in other implementations, which has been */
|
||||
/* a source of confusion, so the default has reverted to strict R7RS. */
|
||||
/* #define SEXP_USE_STRICT_TOPLEVEL_BINDINGS 0 */
|
||||
|
||||
/* uncomment this to disable warning about references to undefined variables */
|
||||
/* This is something of a hack, but can be quite useful. */
|
||||
/* It's very fast and doesn't involve any separate analysis */
|
||||
|
@ -231,11 +176,6 @@
|
|||
/* uncomment this to disable extended char names as defined in R7RS */
|
||||
/* #define SEXP_USE_EXTENDED_CHAR_NAMES 0 */
|
||||
|
||||
/* uncomment this to disable R7RS #<n>= and #<n># reader labels in source */
|
||||
/* The (scheme read) and (scheme write) libraries always support */
|
||||
/* this regardless. */
|
||||
/* #define SEXP_USE_READER_LABELS 0 */
|
||||
|
||||
/* uncomment this to disable UTF-8 string support */
|
||||
/* The default settings store strings in memory as UTF-8, */
|
||||
/* and assumes strings passed to/from the C FFI are UTF-8. */
|
||||
|
@ -246,32 +186,10 @@
|
|||
/* Making them immutable allows for packed UTF-8 strings. */
|
||||
/* #define SEXP_USE_MUTABLE_STRINGS 0 */
|
||||
|
||||
/* uncomment this to enable precomputed index->cursor tables for strings */
|
||||
/* This makes string-ref faster at the expensive of making string */
|
||||
/* construction (including string-append and I/O) slower. */
|
||||
/* You can configure with SEXP_STRING_INDEX_TABLE_CHUNK_SIZE below, */
|
||||
/* the default is caching every 64th index (<=12.5% string overhead). */
|
||||
/* With a minimum of 1 you'd have up to 8x string overhead, and */
|
||||
/* string-ref would still be slightly slower than string-cursors, */
|
||||
/* and string-append would be marginally slower as well. */
|
||||
/* */
|
||||
/* In practice, the overhead of iterating over a string with */
|
||||
/* string-ref isn't noticeable until about 10k chars. Times */
|
||||
/* for iteration using the different approaches: */
|
||||
/* */
|
||||
/* impl\len 1000 10000 100000 1000000 */
|
||||
/* string-ref (utf8) 1 97 9622 x */
|
||||
/* string-ref (fast) 0 2 19 216 */
|
||||
/* cursor-ref (srfi 130) 0 4 18 150 */
|
||||
/* text-ref (srfi 135) 2 27 211 2006 */
|
||||
/* */
|
||||
/* #define SEXP_USE_STRING_INDEX_TABLE 1 */
|
||||
|
||||
/* uncomment this to cache a string cursor for string-ref calls */
|
||||
/* The default is not to use a cache. The goal of caching is to */
|
||||
/* soften the performance impact of repeated O(n) string-ref */
|
||||
/* operations on the same string. */
|
||||
/* #define SEXP_USE_STRING_REF_CACHE 1 */
|
||||
/* uncomment this to base string ports on C streams */
|
||||
/* This historic option enables string and custom ports backed */
|
||||
/* by FILE* objects using memstreams and funopen/fopencookie. */
|
||||
/* #define SEXP_USE_STRING_STREAMS 1 */
|
||||
|
||||
/* uncomment this to disable automatic closing of ports */
|
||||
/* If enabled, the underlying FILE* for file ports will be */
|
||||
|
@ -279,10 +197,11 @@
|
|||
/* apply to stdin/stdout/stderr. */
|
||||
/* #define SEXP_USE_AUTOCLOSE_PORTS 0 */
|
||||
|
||||
/* uncomment this to use a 2010/01/01 epoch */
|
||||
/* By default chibi uses the normal 1970 unix epoch in accordance */
|
||||
/* with R7RS, but this can represent more times as fixnums. */
|
||||
/* #define SEXP_USE_2010_EPOCH 1 */
|
||||
/* uncomment this to use the normal 1970 unix epoch */
|
||||
/* By default chibi uses an datetime epoch starting at */
|
||||
/* 2010/01/01 00:00:00 in order to be able to represent */
|
||||
/* more common times as fixnums. */
|
||||
/* #define SEXP_USE_2010_EPOCH 0 */
|
||||
|
||||
/* uncomment this to disable stack overflow checks */
|
||||
/* By default stacks are fairly small, so it's good to leave */
|
||||
|
@ -301,7 +220,7 @@
|
|||
|
||||
/* uncomment this to make the VM adhere to alignment rules */
|
||||
/* This is required on some platforms, e.g. ARM */
|
||||
/* #define SEXP_USE_ALIGNED_BYTECODE 1 */
|
||||
/* #define SEXP_USE_ALIGNED_BYTECODE */
|
||||
|
||||
/************************************************************************/
|
||||
/* These settings are configurable but only recommended for */
|
||||
|
@ -327,39 +246,17 @@
|
|||
#define SEXP_GROW_HEAP_RATIO 0.75
|
||||
#endif
|
||||
|
||||
/* how much to expand the heap size by */
|
||||
#ifndef SEXP_GROW_HEAP_FACTOR
|
||||
#define SEXP_GROW_HEAP_FACTOR 2 /* 1.6180339887498948482 */
|
||||
#endif
|
||||
|
||||
/* size of per-context stack that is used during gc cycles
|
||||
* increase if you can affort extra unused memory */
|
||||
#define SEXP_MARK_STACK_COUNT 1024
|
||||
|
||||
/* the default number of opcodes to run each thread for */
|
||||
#ifndef SEXP_DEFAULT_QUANTUM
|
||||
#define SEXP_DEFAULT_QUANTUM 500
|
||||
#endif
|
||||
|
||||
#ifndef SEXP_MAX_ANALYZE_DEPTH
|
||||
#define SEXP_MAX_ANALYZE_DEPTH 8192
|
||||
#endif
|
||||
|
||||
/* The size of flexible arrays (empty arrays at the end of a struct */
|
||||
/* representing the trailing data), when compiled with C++. Technically */
|
||||
/* 0 is an illegal value here, and the C++ idiom is to use 1, but this */
|
||||
/* breaks compatibility with C when computing the size of structs, and */
|
||||
/* in practice all of the major C++ compilers support 0. */
|
||||
#ifndef SEXP_FLEXIBLE_ARRAY_SIZE
|
||||
#define SEXP_FLEXIBLE_ARRAY_SIZE 0
|
||||
#endif
|
||||
|
||||
/************************************************************************/
|
||||
/* DEFAULTS - DO NOT MODIFY ANYTHING BELOW THIS LINE */
|
||||
/************************************************************************/
|
||||
|
||||
#ifndef SEXP_64_BIT
|
||||
#if defined(__amd64) || defined(__x86_64) || defined(_WIN64) || defined(_Wp64) || defined(__LP64__) || defined(__PPC64__) || defined(__mips64__) || defined(__sparc64__) || defined(__arm64)
|
||||
#if defined(__amd64) || defined(__x86_64) || defined(_WIN64) || defined(_Wp64)
|
||||
#define SEXP_64_BIT 1
|
||||
#else
|
||||
#define SEXP_64_BIT 0
|
||||
|
@ -375,51 +272,6 @@
|
|||
#endif
|
||||
#endif
|
||||
|
||||
/* Detect specific BSD */
|
||||
#if SEXP_BSD
|
||||
#if defined(__APPLE__)
|
||||
#define SEXP_DARWIN 1
|
||||
#define SEXP_FREEBSD 0
|
||||
#define SEXP_NETBSD 0
|
||||
#define SEXP_DRAGONFLY 0
|
||||
#define SEXP_OPENBSD 0
|
||||
#elif defined(__FreeBSD__)
|
||||
#define SEXP_DARWIN 0
|
||||
#define SEXP_FREEBSD 1
|
||||
#define SEXP_NETBSD 0
|
||||
#define SEXP_DRAGONFLY 0
|
||||
#define SEXP_OPENBSD 0
|
||||
#elif defined(__NetBSD__)
|
||||
#define SEXP_DARWIN 0
|
||||
#define SEXP_FREEBSD 0
|
||||
#define SEXP_NETBSD 1
|
||||
#define SEXP_DRAGONFLY 0
|
||||
#define SEXP_OPENBSD 0
|
||||
#elif defined(__DragonFly__)
|
||||
#define SEXP_DARWIN 0
|
||||
#define SEXP_FREEBSD 0
|
||||
#define SEXP_NETBSD 0
|
||||
#define SEXP_DRAGONFLY 1
|
||||
#define SEXP_OPENBSD 0
|
||||
#elif defined(__OpenBSD__)
|
||||
#define SEXP_DARWIN 0
|
||||
#define SEXP_FREEBSD 0
|
||||
#define SEXP_NETBSD 0
|
||||
#define SEXP_DRAGONFLY 0
|
||||
#define SEXP_OPENBSD 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* for bignum support, need a double long to store long*long */
|
||||
/* gcc supports uint128_t, otherwise we need a custom struct */
|
||||
#ifndef SEXP_USE_CUSTOM_LONG_LONGS
|
||||
#if SEXP_64_BIT && !defined(__GNUC__)
|
||||
#define SEXP_USE_CUSTOM_LONG_LONGS 1
|
||||
#else
|
||||
#define SEXP_USE_CUSTOM_LONG_LONGS 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef SEXP_USE_NO_FEATURES
|
||||
#define SEXP_USE_NO_FEATURES 0
|
||||
#endif
|
||||
|
@ -428,19 +280,9 @@
|
|||
#define SEXP_USE_PEDANTIC 0
|
||||
#endif
|
||||
|
||||
/* this ensures public structs and enums are unchanged by feature toggles. */
|
||||
/* should generally be left at 1. */
|
||||
#ifndef SEXP_USE_STABLE_ABI
|
||||
#define SEXP_USE_STABLE_ABI 1
|
||||
#endif
|
||||
|
||||
#ifndef SEXP_USE_GREEN_THREADS
|
||||
#if defined(_WIN32)
|
||||
#define SEXP_USE_GREEN_THREADS 0
|
||||
#else
|
||||
#define SEXP_USE_GREEN_THREADS ! SEXP_USE_NO_FEATURES
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef SEXP_USE_DEBUG_THREADS
|
||||
#define SEXP_USE_DEBUG_THREADS 0
|
||||
|
@ -458,10 +300,6 @@
|
|||
#define SEXP_USE_MODULES ! SEXP_USE_NO_FEATURES
|
||||
#endif
|
||||
|
||||
#ifndef sexp_default_user_module_path
|
||||
#define sexp_default_user_module_path "./lib:."
|
||||
#endif
|
||||
|
||||
#ifndef SEXP_USE_TYPE_DEFS
|
||||
#define SEXP_USE_TYPE_DEFS ! SEXP_USE_NO_FEATURES
|
||||
#endif
|
||||
|
@ -471,28 +309,15 @@
|
|||
#endif
|
||||
|
||||
#ifndef SEXP_USE_DL
|
||||
#if defined(PLAN9)
|
||||
#if defined(PLAN9) || defined(_WIN32)
|
||||
#define SEXP_USE_DL 0
|
||||
#else
|
||||
#define SEXP_USE_DL ! SEXP_USE_NO_FEATURES
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef SEXP_USE_STATIC_LIBS_EMPTY
|
||||
#define SEXP_USE_STATIC_LIBS_EMPTY 0
|
||||
#endif
|
||||
|
||||
#ifndef SEXP_USE_STATIC_LIBS
|
||||
#define SEXP_USE_STATIC_LIBS SEXP_USE_STATIC_LIBS_EMPTY
|
||||
#endif
|
||||
|
||||
/* don't include clibs.c - include separately or link */
|
||||
#ifndef SEXP_USE_STATIC_LIBS_NO_INCLUDE
|
||||
#if defined(PLAN9) || SEXP_USE_STATIC_LIBS_EMPTY
|
||||
#define SEXP_USE_STATIC_LIBS_NO_INCLUDE 0
|
||||
#else
|
||||
#define SEXP_USE_STATIC_LIBS_NO_INCLUDE 1
|
||||
#endif
|
||||
#define SEXP_USE_STATIC_LIBS 0
|
||||
#endif
|
||||
|
||||
#ifndef SEXP_USE_FULL_SOURCE_INFO
|
||||
|
@ -507,21 +332,9 @@
|
|||
#define SEXP_USE_BOEHM 0
|
||||
#endif
|
||||
|
||||
#ifdef SEXP_USE_UNIFY_FILENOS_BY_NUMBER
|
||||
#define SEXP_USE_UNIFY_FILENOS_BY_NUMBER 0
|
||||
#endif
|
||||
|
||||
#ifndef SEXP_USE_WEAK_REFERENCES
|
||||
#if SEXP_USE_UNIFY_FILENOS_BY_NUMBER
|
||||
#define SEXP_USE_WEAK_REFERENCES 1
|
||||
#else
|
||||
#define SEXP_USE_WEAK_REFERENCES ! SEXP_USE_NO_FEATURES
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef SEXP_USE_FIXED_CHUNK_SIZE_HEAPS
|
||||
#define SEXP_USE_FIXED_CHUNK_SIZE_HEAPS 0
|
||||
#endif
|
||||
|
||||
#ifndef SEXP_USE_MALLOC
|
||||
#define SEXP_USE_MALLOC 0
|
||||
|
@ -539,14 +352,6 @@
|
|||
#define SEXP_USE_DEBUG_GC 0
|
||||
#endif
|
||||
|
||||
#ifndef SEXP_USE_TIME_GC
|
||||
#if SEXP_USE_DEBUG_GC > 0 || defined(__linux) || SEXP_BSD
|
||||
#define SEXP_USE_TIME_GC 1
|
||||
#else
|
||||
#define SEXP_USE_TIME_GC 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef SEXP_USE_SAFE_GC_MARK
|
||||
#define SEXP_USE_SAFE_GC_MARK SEXP_USE_DEBUG_GC > 1
|
||||
#endif
|
||||
|
@ -555,42 +360,14 @@
|
|||
#define SEXP_USE_CONSERVATIVE_GC 0
|
||||
#endif
|
||||
|
||||
#ifndef SEXP_USE_FINALIZERS
|
||||
#define SEXP_USE_FINALIZERS 1
|
||||
#endif
|
||||
|
||||
#ifndef SEXP_USE_TRACK_ALLOC_SOURCE
|
||||
#define SEXP_USE_TRACK_ALLOC_SOURCE SEXP_USE_DEBUG_GC > 2
|
||||
#endif
|
||||
|
||||
#ifndef SEXP_USE_TRACK_ALLOC_BACKTRACE
|
||||
#define SEXP_USE_TRACK_ALLOC_BACKTRACE SEXP_USE_TRACK_ALLOC_SOURCE
|
||||
#endif
|
||||
|
||||
#ifndef SEXP_USE_TRACK_ALLOC_TIMES
|
||||
#define SEXP_USE_TRACK_ALLOC_TIMES 0
|
||||
#endif
|
||||
|
||||
#ifndef SEXP_USE_TRACK_ALLOC_SIZES
|
||||
#define SEXP_USE_TRACK_ALLOC_SIZES 0
|
||||
#endif
|
||||
|
||||
#ifndef SEXP_ALLOC_HISTOGRAM_BUCKETS
|
||||
#define SEXP_ALLOC_HISTOGRAM_BUCKETS 32
|
||||
#endif
|
||||
|
||||
#ifndef SEXP_BACKTRACE_SIZE
|
||||
#define SEXP_BACKTRACE_SIZE 3
|
||||
#endif
|
||||
|
||||
#ifndef SEXP_USE_HEADER_MAGIC
|
||||
#define SEXP_USE_HEADER_MAGIC 0
|
||||
#endif
|
||||
|
||||
#ifndef SEXP_GC_PAD
|
||||
#define SEXP_GC_PAD 0
|
||||
#endif
|
||||
|
||||
#ifndef SEXP_USE_SAFE_ACCESSORS
|
||||
#define SEXP_USE_SAFE_ACCESSORS 0
|
||||
#endif
|
||||
|
@ -616,26 +393,18 @@
|
|||
#endif
|
||||
|
||||
#ifndef SEXP_USE_STRICT_TOPLEVEL_BINDINGS
|
||||
#define SEXP_USE_STRICT_TOPLEVEL_BINDINGS 1
|
||||
#define SEXP_USE_STRICT_TOPLEVEL_BINDINGS 0
|
||||
#endif
|
||||
|
||||
#if SEXP_USE_STRICT_TOPLEVEL_BINDINGS
|
||||
#define SEXP_USE_RENAME_BINDINGS 1
|
||||
#else
|
||||
#ifndef SEXP_USE_RENAME_BINDINGS
|
||||
#define SEXP_USE_RENAME_BINDINGS 1
|
||||
#define SEXP_USE_RENAME_BINDINGS 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef SEXP_USE_SPLICING_LET_SYNTAX
|
||||
#define SEXP_USE_SPLICING_LET_SYNTAX 0
|
||||
#endif
|
||||
|
||||
#ifndef SEXP_USE_FLAT_SYNTACTIC_CLOSURES
|
||||
#define SEXP_USE_FLAT_SYNTACTIC_CLOSURES 0
|
||||
#endif
|
||||
|
||||
#ifndef SEXP_USE_UNWRAPPED_TOPLEVEL_BINDINGS
|
||||
#if SEXP_USE_UNWRAPPED_TOPLEVEL_BINDINGS
|
||||
#define SEXP_USE_UNWRAPPED_TOPLEVEL_BINDINGS 0
|
||||
#endif
|
||||
|
||||
|
@ -690,10 +459,6 @@
|
|||
#define SEXP_PLACEHOLDER_DIGIT '#'
|
||||
#endif
|
||||
|
||||
#ifndef SEXP_USE_PATCH_NON_DECIMAL_NUMERIC_FORMATS
|
||||
#define SEXP_USE_PATCH_NON_DECIMAL_NUMERIC_FORMATS 1
|
||||
#endif
|
||||
|
||||
#ifndef SEXP_USE_MATH
|
||||
#define SEXP_USE_MATH SEXP_USE_FLONUMS && ! SEXP_USE_NO_FEATURES
|
||||
#endif
|
||||
|
@ -710,27 +475,15 @@
|
|||
#define SEXP_USE_OBJECT_BRACE_LITERALS (SEXP_USE_TYPE_DEFS && !SEXP_USE_NO_FEATURES)
|
||||
#endif
|
||||
|
||||
/* Dangerous without shared object detection. */
|
||||
#ifndef SEXP_USE_TYPE_PRINTERS
|
||||
#define SEXP_USE_TYPE_PRINTERS SEXP_USE_OBJECT_BRACE_LITERALS
|
||||
#endif
|
||||
|
||||
#ifndef SEXP_USE_UNIFORM_VECTOR_LITERALS
|
||||
#define SEXP_USE_UNIFORM_VECTOR_LITERALS ! SEXP_USE_NO_FEATURES
|
||||
#endif
|
||||
|
||||
#ifndef SEXP_USE_MINI_FLOAT_UNIFORM_VECTORS
|
||||
#define SEXP_USE_MINI_FLOAT_UNIFORM_VECTORS ! SEXP_USE_NO_FEATURES
|
||||
#define SEXP_USE_TYPE_PRINTERS 0
|
||||
#endif
|
||||
|
||||
#ifndef SEXP_USE_BYTEVECTOR_LITERALS
|
||||
#define SEXP_USE_BYTEVECTOR_LITERALS SEXP_USE_UNIFORM_VECTOR_LITERALS
|
||||
#define SEXP_USE_BYTEVECTOR_LITERALS ! SEXP_USE_NO_FEATURES
|
||||
#endif
|
||||
|
||||
#ifndef SEXP_BYTEVECTOR_HEX_LITERALS
|
||||
#define SEXP_BYTEVECTOR_HEX_LITERALS SEXP_USE_BYTEVECTOR_LITERALS
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef SEXP_USE_SELF_PARAMETER
|
||||
#define SEXP_USE_SELF_PARAMETER 1
|
||||
#endif
|
||||
|
@ -783,10 +536,6 @@
|
|||
#define SEXP_USE_EXTENDED_CHAR_NAMES ! SEXP_USE_NO_FEATURES
|
||||
#endif
|
||||
|
||||
#ifndef SEXP_USE_READER_LABELS
|
||||
#define SEXP_USE_READER_LABELS ! SEXP_USE_NO_FEATURES
|
||||
#endif
|
||||
|
||||
#ifndef SEXP_USE_UTF8_STRINGS
|
||||
#define SEXP_USE_UTF8_STRINGS ! SEXP_USE_NO_FEATURES
|
||||
#endif
|
||||
|
@ -802,20 +551,8 @@
|
|||
#define SEXP_USE_PACKED_STRINGS 1
|
||||
#endif
|
||||
|
||||
#if SEXP_USE_PACKED_STRINGS
|
||||
#define SEXP_USE_STRING_INDEX_TABLE 0
|
||||
#endif
|
||||
#ifndef SEXP_USE_STRING_INDEX_TABLE
|
||||
#define SEXP_USE_STRING_INDEX_TABLE 0
|
||||
#endif
|
||||
|
||||
/* for every chunk_size indexes store the precomputed offset */
|
||||
#ifndef SEXP_STRING_INDEX_TABLE_CHUNK_SIZE
|
||||
#define SEXP_STRING_INDEX_TABLE_CHUNK_SIZE 64
|
||||
#endif
|
||||
|
||||
#ifndef SEXP_USE_DISJOINT_STRING_CURSORS
|
||||
#define SEXP_USE_DISJOINT_STRING_CURSORS SEXP_USE_UTF8_STRINGS
|
||||
#ifndef SEXP_USE_STRING_STREAMS
|
||||
#define SEXP_USE_STRING_STREAMS 0
|
||||
#endif
|
||||
|
||||
#ifndef SEXP_USE_AUTOCLOSE_PORTS
|
||||
|
@ -823,11 +560,7 @@
|
|||
#endif
|
||||
|
||||
#ifndef SEXP_USE_GC_FILE_DESCRIPTORS
|
||||
#ifdef PLAN9
|
||||
#define SEXP_USE_GC_FILE_DESCRIPTORS 0
|
||||
#else
|
||||
#define SEXP_USE_GC_FILE_DESCRIPTORS (SEXP_USE_AUTOCLOSE_PORTS &&!SEXP_USE_BOEHM)
|
||||
#endif
|
||||
#define SEXP_USE_GC_FILE_DESCRIPTORS (SEXP_USE_AUTOCLOSE_PORTS &&!SEXP_USE_BOEHM && !defined(PLAN9))
|
||||
#endif
|
||||
|
||||
#ifndef SEXP_USE_BIDIRECTIONAL_PORTS
|
||||
|
@ -843,7 +576,7 @@
|
|||
#endif
|
||||
|
||||
#ifndef SEXP_USE_2010_EPOCH
|
||||
#define SEXP_USE_2010_EPOCH 0
|
||||
#define SEXP_USE_2010_EPOCH ! SEXP_USE_NO_FEATURES
|
||||
#endif
|
||||
|
||||
#ifndef SEXP_EPOCH_OFFSET
|
||||
|
@ -880,33 +613,12 @@
|
|||
#define SEXP_MAX_STACK_SIZE SEXP_INIT_STACK_SIZE*1000
|
||||
#endif
|
||||
|
||||
#ifndef SEXP_MAX_VECTOR_LENGTH
|
||||
#define SEXP_MAX_VECTOR_LENGTH (SEXP_MAX_FIXNUM >> 1)
|
||||
#endif
|
||||
|
||||
#ifndef SEXP_DEFAULT_EQUAL_DEPTH
|
||||
#define SEXP_DEFAULT_EQUAL_DEPTH 10000
|
||||
#endif
|
||||
|
||||
#ifndef SEXP_DEFAULT_EQUAL_BOUND
|
||||
#define SEXP_DEFAULT_EQUAL_BOUND 100000000
|
||||
#endif
|
||||
|
||||
#ifndef SEXP_DEFAULT_WRITE_BOUND
|
||||
#define SEXP_DEFAULT_WRITE_BOUND 10000
|
||||
#endif
|
||||
|
||||
#ifndef SEXP_STRIP_SYNCLOS_BOUND
|
||||
#define SEXP_STRIP_SYNCLOS_BOUND 10000
|
||||
#endif
|
||||
|
||||
#ifndef SEXP_POLL_SLEEP_TIME
|
||||
#define SEXP_POLL_SLEEP_TIME 5000
|
||||
#define SEXP_POLL_SLEEP_TIME_MS 5
|
||||
#define SEXP_DEFAULT_EQUAL_BOUND 100000
|
||||
#endif
|
||||
|
||||
#ifndef SEXP_USE_IMAGE_LOADING
|
||||
#define SEXP_USE_IMAGE_LOADING SEXP_USE_DL && SEXP_64_BIT && !SEXP_USE_GLOBAL_HEAP && !SEXP_USE_BOEHM && !SEXP_USE_NO_FEATURES
|
||||
#define SEXP_USE_IMAGE_LOADING SEXP_USE_DL && !SEXP_USE_GLOBAL_HEAP && !SEXP_USE_BOEHM && !SEXP_USE_NO_FEATURES
|
||||
#endif
|
||||
|
||||
#ifndef SEXP_USE_UNSAFE_PUSH
|
||||
|
@ -917,15 +629,6 @@
|
|||
#define SEXP_USE_MAIN_HELP ! SEXP_USE_NO_FEATURES
|
||||
#endif
|
||||
|
||||
#ifndef SEXP_USE_MAIN_ERROR_ADVISE
|
||||
#define SEXP_USE_MAIN_ERROR_ADVISE ! SEXP_USE_NO_FEATURES
|
||||
#endif
|
||||
|
||||
#ifndef SEXP_USE_SEND_FILE
|
||||
#define SEXP_USE_SEND_FILE 0
|
||||
/* #define SEXP_USE_SEND_FILE (__linux || SEXP_BSD) */
|
||||
#endif
|
||||
|
||||
#if SEXP_USE_NATIVE_X86
|
||||
#undef SEXP_USE_BOEHM
|
||||
#define SEXP_USE_BOEHM 1
|
||||
|
@ -944,17 +647,13 @@
|
|||
#endif
|
||||
|
||||
#ifndef SEXP_USE_ALIGNED_BYTECODE
|
||||
#if defined(__arm__) || defined(__sparc__) || defined(__sparc64__) || defined(__mips__) || defined(__mips64__)
|
||||
#if defined(__arm__)
|
||||
#define SEXP_USE_ALIGNED_BYTECODE 1
|
||||
#else
|
||||
#define SEXP_USE_ALIGNED_BYTECODE 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef SEXP_USE_SIGNED_SHIFTS
|
||||
#define SEXP_USE_SIGNED_SHIFTS 0
|
||||
#endif
|
||||
|
||||
#ifdef PLAN9
|
||||
#define strcasecmp cistrcmp
|
||||
#define strncasecmp cistrncmp
|
||||
|
@ -964,17 +663,6 @@
|
|||
#define isinf(x) (isInf(x,1) || isInf(x,-1))
|
||||
#define isnan(x) isNaN(x)
|
||||
#elif defined(_WIN32)
|
||||
#define SHUT_RD 0 /* SD_RECEIVE */
|
||||
#define SHUT_WR 1 /* SD_SEND */
|
||||
#define SHUT_RDWR 2 /* SD_BOTH */
|
||||
#ifdef _MSC_VER
|
||||
#define _CRT_SECURE_NO_WARNINGS 1
|
||||
#define _CRT_NONSTDC_NO_DEPRECATE 1
|
||||
#define _USE_MATH_DEFINES /* For M_LN10 */
|
||||
#define strcasecmp _stricmp
|
||||
#define strncasecmp _strnicmp
|
||||
#pragma warning(disable:4146) /* unary minus operator to unsigned type */
|
||||
#if _MSC_VER < 1900
|
||||
#define snprintf(buf, len, fmt, val) sprintf(buf, fmt, val)
|
||||
#define strcasecmp lstrcmpi
|
||||
#define strncasecmp(s1, s2, n) lstrcmpi(s1, s2)
|
||||
|
@ -983,10 +671,6 @@
|
|||
#define isnan(x) (x!=x)
|
||||
#define isinf(x) (x > DBL_MAX || x < -DBL_MAX)
|
||||
#endif
|
||||
#elif !defined(__MINGW32__)
|
||||
#error Unknown Win32 compiler!
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#define sexp_pos_infinity (DBL_MAX*DBL_MAX)
|
||||
|
@ -1002,18 +686,14 @@
|
|||
#define sexp_nan (0.0/0.0)
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef SEXP_STATIC_LIBRARY
|
||||
#define SEXP_API extern
|
||||
#else
|
||||
#ifdef __MINGW32__
|
||||
#ifdef BUILDING_DLL
|
||||
#define SEXP_API __declspec(dllexport)
|
||||
#else
|
||||
#define SEXP_API __declspec(dllimport)
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
#define SEXP_API extern
|
||||
#define SEXP_API
|
||||
#endif
|
||||
|
||||
/************************************************************************/
|
||||
|
|
|
@ -1,105 +0,0 @@
|
|||
/* gc_heap.h -- heap packing, run-time image generation */
|
||||
/* Copyright (c) 2016 Chris Walsh. All rights reserved. */
|
||||
/* BSD-style license: http://synthcode.com/license.txt */
|
||||
|
||||
#ifndef SEXP_GC_HEAP_H
|
||||
#define SEXP_GC_HEAP_H
|
||||
|
||||
#include "chibi/sexp.h"
|
||||
|
||||
#if SEXP_USE_IMAGE_LOADING
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Iterate the heap associated with the context argument 'ctx',
|
||||
calling user provided callbacks for the individual heap elements.
|
||||
|
||||
For each heap found, heap_callback is called.
|
||||
For each free segment found, free_callback is called.
|
||||
For each valid sexp found, sexp_callback is called.
|
||||
|
||||
Callbacks are skipped if the associated function
|
||||
pointer argument is NULL.
|
||||
|
||||
A callback return value of SEXP_TRUE allows the heap walk to
|
||||
continue normally. Any other value terminates the heap walk
|
||||
with the callback result being returned.
|
||||
|
||||
The sexp_gc_heap_walk return value of SEXP_TRUE indicates all
|
||||
elements of the heap were walked normally. Any other return
|
||||
value indicates an abnormal return condition.
|
||||
*/
|
||||
SEXP_API sexp sexp_gc_heap_walk(
|
||||
sexp ctx, /* a possibly incomplete context */
|
||||
sexp_heap h, /* normally set to sexp_context_heap(ctx) */
|
||||
sexp *types, /* normally set to sexp_context_types(ctx) */
|
||||
size_t types_cnt, /* normally set to sexp_context_num_types(ctx) */
|
||||
void *user, /* arbitrary data passed to callbacks */
|
||||
sexp (*heap_callback)(sexp ctx, sexp_heap h, void *user),
|
||||
sexp (*free_callback)(sexp ctx, sexp_free_list f, void *user),
|
||||
sexp (*sexp_callback)(sexp ctx, sexp s, void *user));
|
||||
|
||||
|
||||
/* Returns a new context which contains a single, packed heap.
|
||||
|
||||
The original ctx or heap are not altered, leaving two copies
|
||||
of all sexps. For runtime use where you are packing the heap
|
||||
to make accesses more efficient, the old heap and context should
|
||||
be discarded after a sucessful call to heap pack; finalizers do
|
||||
not need to be called since all active objects are in the new heap.
|
||||
|
||||
The input heap_size specifies the amount of free space to allocate
|
||||
at the end of the packed heap. A heap_size of zero will produce a
|
||||
single packed heap just large enough to hold all sexps from the
|
||||
original heap.
|
||||
*/
|
||||
SEXP_API sexp sexp_gc_heap_pack(sexp ctx, sexp_uint_t heap_free_size);
|
||||
|
||||
|
||||
/* Creates a new packed heap from the provided context, and saves
|
||||
the contents of the packed heap to the file named filename.
|
||||
|
||||
If sucessful, SEXP_TRUE is returned. If a problem was encountered
|
||||
in either creating the packed heap or saving to a file, then either
|
||||
SEXP_FALSE or an exception is returned. Because of shared code with
|
||||
sexp_load_image, sexp_load_image_err() can also be used to return the
|
||||
error condition.
|
||||
|
||||
In all cases, upon completion the temporary packed context is deleted
|
||||
and the context provided as an argument is not changed.
|
||||
*/
|
||||
SEXP_API sexp sexp_save_image (sexp ctx, const char* filename);
|
||||
|
||||
|
||||
/* Loads a previously saved image, and returns the context associated with
|
||||
that image. If the context could not be loaded, either NULL or an exception
|
||||
are returned instead.
|
||||
|
||||
A new context is created with the contents of filename loaded into the
|
||||
heap. The heap_free_size parameter specifies the size of the heap to be
|
||||
created in addition to the heap image on disk. A size of zero will
|
||||
result in an initial heap exactly the size of the disk image which will
|
||||
be expanded with an additional heap when the system requests storage space.
|
||||
|
||||
The return value is either the context of the loaded image, or NULL. In
|
||||
the case of a NULL context, the function sexp_load_image_err() can be called
|
||||
to provide a description of the error encountered. An sexp exception cannot be
|
||||
returned because there is not a valid context in which to put the exception.
|
||||
*/
|
||||
SEXP_API sexp sexp_load_image (const char* filename, off_t offset, sexp_uint_t heap_free_size, sexp_uint_t heap_max_size);
|
||||
|
||||
|
||||
/* In the case that sexp_load_image() returns NULL, this function will return
|
||||
a string containing a description of the error condition.
|
||||
*/
|
||||
SEXP_API char* sexp_load_image_err();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SEXP_USE_IMAGE_LOADING */
|
||||
|
||||
#endif /* ! SEXP_GC_HEAP_H */
|
|
@ -1,6 +0,0 @@
|
|||
#define sexp_so_extension "@CMAKE_SHARED_LIBRARY_SUFFIX@"
|
||||
#define sexp_default_module_path "@default_module_path@"
|
||||
#define sexp_platform "@platform@"
|
||||
#define sexp_architecture "@CMAKE_SYSTEM_PROCESSOR@"
|
||||
#define sexp_version "@CMAKE_PROJECT_VERSION@"
|
||||
#define sexp_release_name "@release@"
|
|
@ -1,92 +0,0 @@
|
|||
/* auto-generated by ./symhuff.scm on Sun Feb 25 23:12:52 2007 */
|
||||
|
||||
char _huff_tab21[] = {
|
||||
'\x01', '\x00', '\x03', '\x00', '\x02', '\x00', '\x04', '\x00',
|
||||
};
|
||||
|
||||
char _huff_tab19[] = {
|
||||
'\x01', 'j', '\x01', '\x00',
|
||||
};
|
||||
|
||||
char _huff_tab20[] = {
|
||||
'\x05', '\x09', '\x07', '\x0b', '\x06', '\x0a', '\x08', '\x0c',
|
||||
};
|
||||
|
||||
char _huff_tab18[] = {
|
||||
'2', ':', '6', 'B', '4', '@', '8', 'D',
|
||||
'3', ';', '7', 'C', '5', 'A', '9', 'E',
|
||||
};
|
||||
|
||||
char _huff_tab17[] = {
|
||||
'\x0d', '\x1d', '\x15', '&', '\x11', '"', '\x19', ',',
|
||||
'\x0f', '\x1f', '\x17', '(', '\x13', '$', '\x1b', '0',
|
||||
'\x0e', '\x1e', '\x16', '\'', '\x12', '#', '\x1a', '.',
|
||||
'\x10', '\x20', '\x18', ')', '\x14', '%', '\x1c', '1',
|
||||
};
|
||||
|
||||
char _huff_tab16[] = {
|
||||
'V', '^', 'Z', '|', 'X', '`', '\\', '~',
|
||||
'W', '_', '[', '}', 'Y', '{', ']', '\x7f',
|
||||
};
|
||||
|
||||
char _huff_tab15[] = {
|
||||
'F', 'N', 'J', 'R', 'H', 'P', 'L', 'T',
|
||||
'G', 'O', 'K', 'S', 'I', 'Q', 'M', 'U',
|
||||
};
|
||||
|
||||
char _huff_tab13[] = {
|
||||
'\x00', '\x00', '\x00', '+', '\x00', '\x00', '\x00', '/',
|
||||
};
|
||||
|
||||
char _huff_tab14[] = {
|
||||
'*', 'z',
|
||||
};
|
||||
|
||||
char _huff_tab11[] = {
|
||||
'\x00', 'b', '\x00', 'x',
|
||||
};
|
||||
|
||||
char _huff_tab12[] = {
|
||||
'!', 'k',
|
||||
};
|
||||
|
||||
char _huff_tab9[] = {
|
||||
'\x00', 's', '\x00', 'l',
|
||||
};
|
||||
|
||||
char _huff_tab10[] = {
|
||||
'y', 'w', '<', 'q',
|
||||
};
|
||||
|
||||
char _huff_tab8[] = {
|
||||
'p', '?', 'g', 'u',
|
||||
};
|
||||
|
||||
char _huff_tab7[] = {
|
||||
'f', '>', '=', 'v',
|
||||
};
|
||||
|
||||
char _huff_tab5[] = {
|
||||
'\x00', 'o', '\x00', 'd',
|
||||
};
|
||||
|
||||
char _huff_tab6[] = {
|
||||
'h', 'm',
|
||||
};
|
||||
|
||||
char _huff_tab4[] = {
|
||||
'c', 'i',
|
||||
};
|
||||
|
||||
char _huff_tab3[] = {
|
||||
'n', '-',
|
||||
};
|
||||
|
||||
char _huff_tab1[] = {
|
||||
'\x00', '\x00', '\x00', 'r', '\x00', '\x00', '\x00', 'a',
|
||||
};
|
||||
|
||||
char _huff_tab2[] = {
|
||||
'e', 't',
|
||||
};
|
||||
|
943
include/chibi/sexp.h
Normal file → Executable file
943
include/chibi/sexp.h
Normal file → Executable file
File diff suppressed because it is too large
Load diff
|
@ -1,4 +0,0 @@
|
|||
[
|
||||
"_main",
|
||||
"_sexp_resume"
|
||||
]
|
116
js/index.html
116
js/index.html
|
@ -1,116 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Chibi-Scheme</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
height: 100vh;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
main {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
#program {
|
||||
flex: 1 1 0;
|
||||
padding: 0.5em;
|
||||
}
|
||||
#start {
|
||||
font-size: inherit;
|
||||
padding: 0.5em;
|
||||
}
|
||||
#output {
|
||||
font-family: monospace;
|
||||
padding: 0.5em;
|
||||
white-space: pre;
|
||||
background-color: #000;
|
||||
color: #fff;
|
||||
overflow: auto;
|
||||
flex: 1 1 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<textarea id="program" spellcheck="false">;
|
||||
; This is Chibi-Scheme compiled with Emscripten to run in the browser.
|
||||
;
|
||||
|
||||
(import (scheme base))
|
||||
(write-string "Hello, world!\n")
|
||||
|
||||
;
|
||||
; You can also run arbitrary JavaScript code from scheme and yield control back and forth between Scheme and the browser
|
||||
;
|
||||
|
||||
(import (chibi emscripten)) ; exports: eval-script!, integer-eval-script, string-eval-script, wait-on-event!
|
||||
|
||||
(write-string (number->string (integer-eval-script "6 * 7")))
|
||||
(newline)
|
||||
|
||||
(eval-script! "window.addEventListener('click', function () {
|
||||
Module['resume'](); // give control back to the Scheme process
|
||||
})")
|
||||
|
||||
(let loop ()
|
||||
(wait-on-event!) ; yields control back to the browser
|
||||
(write-string "You have clicked me!\n")
|
||||
(loop))
|
||||
|
||||
(write-string "Control never reaches this point\n")
|
||||
</textarea>
|
||||
<button type="button" id="start" disabled>Start Program</button>
|
||||
<div id="output"></div>
|
||||
</main>
|
||||
<script src="chibi.js"></script>
|
||||
<script>
|
||||
function start(program, args, onOutput, onError) {
|
||||
var firstError = true;
|
||||
Chibi({
|
||||
print: onOutput,
|
||||
printErr: function (text) {
|
||||
if (firstError) {
|
||||
firstError = false;
|
||||
return;
|
||||
}
|
||||
if (onError !== undefined) {
|
||||
onError(text);
|
||||
} else {
|
||||
onOutput(text);
|
||||
}
|
||||
},
|
||||
program: program,
|
||||
arguments: args
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
(function () {
|
||||
var programField = document.querySelector('#program');
|
||||
var startButton = document.querySelector('#start');
|
||||
var program = sessionStorage.getItem('program');
|
||||
if (program) {
|
||||
programField.value = program;
|
||||
}
|
||||
programField.addEventListener('input', function() {
|
||||
sessionStorage.setItem('program', programField.value);
|
||||
});
|
||||
startButton.addEventListener('click', function() {
|
||||
var program = programField.value;
|
||||
startButton.disabled = true;
|
||||
start(program, [],
|
||||
function(text) {
|
||||
output.textContent = output.textContent + text + '\n'
|
||||
});
|
||||
});
|
||||
startButton.disabled = false;
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,2 +0,0 @@
|
|||
Module['resume'] = Module.cwrap('sexp_resume', 'void', []);
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
Module['preRun'].push(function () {
|
||||
FS.writeFile('program.scm', Module['program']);
|
||||
});
|
||||
Module['arguments'] = Module['arguments'] || [];
|
||||
Module['arguments'].unshift('program.scm');
|
||||
|
|
@ -13,8 +13,8 @@ sexp sexp_accept (sexp ctx, sexp self, int sock, struct sockaddr* addr, socklen_
|
|||
#if SEXP_USE_GREEN_THREADS
|
||||
if (res < 0 && errno == EWOULDBLOCK) {
|
||||
f = sexp_global(ctx, SEXP_G_THREADS_BLOCKER);
|
||||
if (sexp_applicablep(f)) {
|
||||
sexp_apply2(ctx, f, sexp_make_fixnum(sock), SEXP_FALSE);
|
||||
if (sexp_opcodep(f)) {
|
||||
((sexp_proc2)sexp_opcode_func(f))(ctx, f, 1, sexp_make_fixnum(sock));
|
||||
return sexp_global(ctx, SEXP_G_IO_BLOCK_ERROR);
|
||||
}
|
||||
}
|
||||
|
@ -24,57 +24,8 @@ sexp sexp_accept (sexp ctx, sexp self, int sock, struct sockaddr* addr, socklen_
|
|||
return sexp_make_fileno(ctx, sexp_make_fixnum(res), SEXP_FALSE);
|
||||
}
|
||||
|
||||
/* likewise sendto and recvfrom should suspend the thread gracefully */
|
||||
|
||||
#define sexp_zerop(x) ((x) == SEXP_ZERO || (sexp_flonump(x) && sexp_flonum_value(x) == 0.0))
|
||||
|
||||
sexp sexp_sendto (sexp ctx, sexp self, int sock, const void* buffer, size_t len, int flags, struct sockaddr* addr, socklen_t addr_len, sexp timeout) {
|
||||
#if SEXP_USE_GREEN_THREADS
|
||||
sexp f;
|
||||
#endif
|
||||
ssize_t res;
|
||||
res = sendto(sock, buffer, len, flags, addr, addr_len);
|
||||
#if SEXP_USE_GREEN_THREADS
|
||||
if (res < 0 && errno == EWOULDBLOCK && !sexp_zerop(timeout)) {
|
||||
f = sexp_global(ctx, SEXP_G_THREADS_BLOCKER);
|
||||
if (sexp_applicablep(f)) {
|
||||
sexp_apply2(ctx, f, sexp_make_fixnum(sock), timeout);
|
||||
return sexp_global(ctx, SEXP_G_IO_BLOCK_ONCE_ERROR);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return sexp_make_fixnum(res);
|
||||
}
|
||||
|
||||
sexp sexp_recvfrom (sexp ctx, sexp self, int sock, void* buffer, size_t len, int flags, struct sockaddr* addr, socklen_t addr_len, sexp timeout) {
|
||||
#if SEXP_USE_GREEN_THREADS
|
||||
sexp f;
|
||||
#endif
|
||||
ssize_t res;
|
||||
res = recvfrom(sock, buffer, len, flags, addr, &addr_len);
|
||||
#if SEXP_USE_GREEN_THREADS
|
||||
if (res < 0 && errno == EWOULDBLOCK && !sexp_zerop(timeout)) {
|
||||
f = sexp_global(ctx, SEXP_G_THREADS_BLOCKER);
|
||||
if (sexp_applicablep(f)) {
|
||||
sexp_apply2(ctx, f, sexp_make_fixnum(sock), timeout);
|
||||
return sexp_global(ctx, SEXP_G_IO_BLOCK_ONCE_ERROR);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return sexp_make_fixnum(res);
|
||||
}
|
||||
|
||||
/* If we're binding or listening on a socket from Scheme, we most */
|
||||
/* likely want it to be non-blocking. */
|
||||
|
||||
sexp sexp_bind (sexp ctx, sexp self, int fd, struct sockaddr* addr, socklen_t addr_len) {
|
||||
int res = bind(fd, addr, addr_len);
|
||||
#if SEXP_USE_GREEN_THREADS
|
||||
if (res >= 0)
|
||||
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
|
||||
#endif
|
||||
return (res == 0) ? SEXP_TRUE : SEXP_FALSE;
|
||||
}
|
||||
/* If we're listening on a socket from Scheme, we most likely want it */
|
||||
/* to be non-blocking. */
|
||||
|
||||
sexp sexp_listen (sexp ctx, sexp self, sexp fileno, sexp backlog) {
|
||||
int fd, res;
|
||||
|
@ -88,23 +39,3 @@ sexp sexp_listen (sexp ctx, sexp self, sexp fileno, sexp backlog) {
|
|||
#endif
|
||||
return (res == 0) ? SEXP_TRUE : SEXP_FALSE;
|
||||
}
|
||||
|
||||
/* Additional utilities. */
|
||||
|
||||
sexp sexp_sockaddr_name (sexp ctx, sexp self, struct sockaddr* addr) {
|
||||
char buf[INET6_ADDRSTRLEN];
|
||||
/* struct sockaddr_in *sa = (struct sockaddr_in *)addr; */
|
||||
/* unsigned char *ptr = (unsigned char *)&(sa->sin_addr); */
|
||||
/* snprintf(buf, sizeof(buf), "%d.%d.%d.%d", ptr[0], ptr[1], ptr[2], ptr[3]); */
|
||||
inet_ntop(addr->sa_family,
|
||||
(addr->sa_family == AF_INET6 ?
|
||||
(void*)(&(((struct sockaddr_in6 *)addr)->sin6_addr)) :
|
||||
(void*)(&(((struct sockaddr_in *)addr)->sin_addr))),
|
||||
buf, INET6_ADDRSTRLEN);
|
||||
return sexp_c_string(ctx, buf, -1);
|
||||
}
|
||||
|
||||
int sexp_sockaddr_port (sexp ctx, sexp self, struct sockaddr* addr) {
|
||||
struct sockaddr_in *sa = (struct sockaddr_in *)addr;
|
||||
return ntohs(sa->sin_port);
|
||||
}
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
(define-library (chibi app-test)
|
||||
(import (scheme base) (chibi app) (chibi config) (chibi test))
|
||||
(export run-tests)
|
||||
(begin
|
||||
(define (feed cfg spec . args)
|
||||
(let ((animals (conf-get-list cfg 'animals '())))
|
||||
(cons (if (conf-get cfg 'lions) (cons 'lions animals) animals) args)))
|
||||
(define (wash cfg spec . args)
|
||||
(let ((animals (conf-get-list cfg 'animals '())))
|
||||
(cons (cons 'soap (conf-get cfg '(command wash soap))) animals)))
|
||||
(define zoo-app-spec
|
||||
`(zoo
|
||||
"Zookeeper Application"
|
||||
(@
|
||||
(animals (list symbol) "list of animals to act on (default all)")
|
||||
(lions boolean (#\l) "also apply the action to lions"))
|
||||
(or
|
||||
(feed "feed the animals" (,feed animals ...))
|
||||
(wash "wash the animals" (@ (soap boolean)) (,wash animals ...))
|
||||
(help "print help" (,app-help-command)))
|
||||
))
|
||||
(define (run-tests)
|
||||
(test-begin "app")
|
||||
(test '((camel elephant) "today")
|
||||
(run-application
|
||||
zoo-app-spec
|
||||
'("zoo" "--animals" "camel,elephant" "feed" "today")))
|
||||
(test '((lions camel elephant) "tomorrow")
|
||||
(run-application
|
||||
zoo-app-spec
|
||||
'("zoo" "--animals" "camel,elephant" "--lions" "feed" "tomorrow")))
|
||||
(test '((soap . #f) rhino)
|
||||
(run-application zoo-app-spec '("zoo" "--animals" "rhino" "wash")))
|
||||
(test '((soap . #t) rhino)
|
||||
(run-application zoo-app-spec
|
||||
'("zoo" "--animals" "rhino" "wash" "--soap")))
|
||||
(test '((soap . #t) rhino)
|
||||
(run-application zoo-app-spec
|
||||
'("zoo" "wash" "--soap" "--animals" "rhino")))
|
||||
(test 'error
|
||||
(guard (exn (else 'error))
|
||||
(run-application zoo-app-spec
|
||||
'("zoo" "--soap" "wash" "--animals" "rhino"))))
|
||||
(let ((out (open-output-string)))
|
||||
(parameterize ((current-output-port out))
|
||||
(run-application zoo-app-spec '("zoo" "help"))
|
||||
(test "Usage: zoo [options] <command>\nCommands:\n feed animals ... - feed the animals\n wash animals ... - wash the animals\n help - print help\nOptions:\n --animals - list of animals to act on (default all)\n -l, --lions - also apply the action to lions\n"
|
||||
(get-output-string out))))
|
||||
(test-end))))
|
|
@ -1,557 +0,0 @@
|
|||
;; app.scm -- unified option parsing and config
|
||||
;; Copyright (c) 2012-2024 Alex Shinn. All rights reserved.
|
||||
;; BSD-style license: http://synthcode.com/license.txt
|
||||
|
||||
;;> The high-level interface. Parses a command-line with optional
|
||||
;;> and/or positional arguments, with arbitrarily nested subcommands
|
||||
;;> (optionally having their own arguments), and calls the
|
||||
;;> corresponding main procedure on the parsed config.
|
||||
;;>
|
||||
;;> Given an application spec \var{spec}, parses the given
|
||||
;;> command-line arguments \var{args} into a config object (from
|
||||
;;> \scheme{(chibi config)}), prepended to the existing object
|
||||
;;> \var{config} if given. Then runs the corresponding command (or
|
||||
;;> sub-command) procedure from \var{spec} on the following arguments:
|
||||
;;>
|
||||
;;> \scheme{(<proc> <config> <spec> <positional args> ...)}
|
||||
;;>
|
||||
;;> The app spec should be a list of the form:
|
||||
;;>
|
||||
;;> \scheme{(<command> [<doc-string>] <clauses> ...)}
|
||||
;;>
|
||||
;;> where clauses can be any of:
|
||||
;;>
|
||||
;;> \itemlist[
|
||||
;;> \item{\scheme{(@ <opt-spec>)} - option spec, described below}
|
||||
;;> \item{\scheme{(begin: <begin-proc>)} - procedure to run before main}
|
||||
;;> \item{\scheme{(end: <end-proc>)} - procedure to run after main}
|
||||
;;> \item{\scheme{(types: (<type-name> <parser>) ...)} - additional types that can be used in argument parsing}
|
||||
;;> \item{\scheme{(<proc> args ...)} - main procedure (args only for documentation)}
|
||||
;;> \item{\scheme{<app-spec>} - a subcommand described by the nested spec}
|
||||
;;> \item{\scheme{(or <app-spec> ...)} - an alternate list of subcommands}
|
||||
;;> ]
|
||||
;;>
|
||||
;;> For subcommands the symbolic command name must match, though it is
|
||||
;;> ignored for the initial spec (i.e. the application name is not
|
||||
;;> checked). The \scheme{begin} and \scheme{end} procedures can be
|
||||
;;> useful for loading and saving state common to all subcommands.
|
||||
;;>
|
||||
;;> The \scheme{opt-spec} describes command-line options, and is a
|
||||
;;> simple list with each opt of the form:
|
||||
;;>
|
||||
;;> \scheme{(<name> <type> [(<aliases> ...)] [<doc-string>])}
|
||||
;;>
|
||||
;;> where \scheme{<name>} is a symbol name, \scheme{<aliases>} is an
|
||||
;;> optional list of strings (for long options) or characters (for
|
||||
;;> short options) to serve as aliases in addition to the exact name.
|
||||
;;> \scheme{type} can be any of:
|
||||
;;>
|
||||
;;> \itemlist[
|
||||
;;> \item{\scheme{boolean} - boolean, associated value optional, allowing \scheme{--noname} to indicate \scheme{#false}}
|
||||
;;> \item{\scheme{char} - a single character}
|
||||
;;> \item{\scheme{integer} - an exact integer}
|
||||
;;> \item{\scheme{real} - any real number}
|
||||
;;> \item{\scheme{number} - any real or complex number}
|
||||
;;> \item{\scheme{symbol} - a symbol}
|
||||
;;> \item{\scheme{string} - a string}
|
||||
;;> \item{\scheme{sexp} - a sexp parsed with \scheme{read}}
|
||||
;;> \item{\scheme{(list <type>)} - a comma-delimited list of types}
|
||||
;;> ]
|
||||
;;>
|
||||
;;> Note that the options specs are composed entirely of objects that
|
||||
;;> can be read and written, thus for example optionally loaded from
|
||||
;;> files, whereas the app specs include embedded procedure objects so
|
||||
;;> are typically written with \scheme{quasiquote}.
|
||||
;;>
|
||||
;;> Complete Example - stripped down ls(1):
|
||||
;;>
|
||||
;;> \schemeblock{
|
||||
;;> (import (scheme base)
|
||||
;;> (scheme process-context)
|
||||
;;> (scheme write)
|
||||
;;> (srfi 130)
|
||||
;;> (chibi app)
|
||||
;;> (chibi config)
|
||||
;;> (chibi filesystem))
|
||||
;;>
|
||||
;;> (define (ls cfg spec . files)
|
||||
;;> (for-each
|
||||
;;> (lambda (x)
|
||||
;;> (for-each
|
||||
;;> (lambda (file)
|
||||
;;> (unless (and (string-prefix? "." file)
|
||||
;;> (not (conf-get cfg 'all)))
|
||||
;;> (write-string file)
|
||||
;;> (when (conf-get cfg 'long)
|
||||
;;> (write-string " ")
|
||||
;;> (write (file-modification-time file)))
|
||||
;;> (newline)))
|
||||
;;> (if (file-directory? x) (directory-files x) (list x))))
|
||||
;;> files))
|
||||
;;>
|
||||
;;> (run-application
|
||||
;;> `(ls
|
||||
;;> "list directory contents"
|
||||
;;> (@
|
||||
;;> (long boolean (#\\l) "use a long listing format")
|
||||
;;> (all boolean (#\\a) "do not ignore entries starting with ."))
|
||||
;;> (,ls files ...))
|
||||
;;> (command-line))
|
||||
;;> }
|
||||
;;>
|
||||
;;> Subcommand Skeleton Example:
|
||||
;;>
|
||||
;;> \schemeblock{
|
||||
;;> (run-application
|
||||
;;> `(zoo
|
||||
;;> "Zookeeper Application"
|
||||
;;> (@
|
||||
;;> (animals (list symbol) "list of animals to act on (default all)")
|
||||
;;> (lions boolean (#\\l) "also apply the action to lions"))
|
||||
;;> (or
|
||||
;;> (feed "feed the animals" () (,feed animals ...))
|
||||
;;> (wash "wash the animals" (@ (soap boolean)) (,wash animals ...))
|
||||
;;> (help "print help" (,app-help-command))))
|
||||
;;> (command-line)
|
||||
;;> (conf-load (string-append (get-environment-variable "HOME") "/.zoo")))
|
||||
;;> }
|
||||
;;>
|
||||
;;> The second and third arguments here are optional, provided to show
|
||||
;;> the common pattern of allowing the same options to be specified
|
||||
;;> either in a file and/or on the command-line. The above app can be
|
||||
;;> run as:
|
||||
;;>
|
||||
;;> Feed all animals, including lions:
|
||||
;;> \command{zoo -l feed}
|
||||
;;>
|
||||
;;> Wash the elephants with soap:
|
||||
;;> \command{zoo --animals=elephant wash --soap}
|
||||
;;>
|
||||
;;> Print help:
|
||||
;;> \command{zoo help}
|
||||
;;>
|
||||
;;> The application procedures themselves are of the form:
|
||||
;;>
|
||||
;;> \scheme{(proc cfg spec args ...)}
|
||||
;;>
|
||||
;;> where \var{cfg} is a config object from \scheme{(chibi config)}
|
||||
;;> holding the parsed option info, \var{spec} is the original app
|
||||
;;> spec, and \var{args} are the remaining non-option command-line
|
||||
;;> arguments.
|
||||
;;>
|
||||
;;> To retrieve the options for the above example you can use:
|
||||
;;>
|
||||
;;> \itemlist[
|
||||
;;> \item{\scheme{(conf-get cfg 'animals)}}
|
||||
;;> \item{\scheme{(conf-get cfg 'lions)}}
|
||||
;;> \item{\scheme{(conf-get cfg '(command wash soap))}}
|
||||
;;> ]
|
||||
;;>
|
||||
;;> Notice that options for subcommands are nested under the
|
||||
;;> \scheme{(command <name>)} prefix, so that you can use the same
|
||||
;;> name for different subcommands without conflict. This also means
|
||||
;;> the subcommand options are distinct from the top-level options, so
|
||||
;;> when using subcommands users must always write the command line
|
||||
;;> as:
|
||||
;;>
|
||||
;;> \command{app [<general options>] <subcommand> [<sub options>]}
|
||||
;;>
|
||||
;;> The ~/.zoo file could then hold an sexp of the form:
|
||||
;;>
|
||||
;;> \schemeblock{
|
||||
;;> ((animals (camel elephant rhinocerous))
|
||||
;;> (command
|
||||
;;> (wash
|
||||
;;> (soap #t))))
|
||||
;;> }
|
||||
|
||||
(define (run-application spec . o)
|
||||
(let ((args (or (and (pair? o) (car o)) (command-line)))
|
||||
(config (and (pair? o) (pair? (cdr o)) (cadr o))))
|
||||
(cond
|
||||
((parse-app '() (cdr spec) '() (cdr args) config #f #f '())
|
||||
=> (lambda (v)
|
||||
(let ((proc (vector-ref v 0))
|
||||
(cfg (vector-ref v 1))
|
||||
(args (vector-ref v 2))
|
||||
(init (vector-ref v 3))
|
||||
(end (vector-ref v 4)))
|
||||
(if init (init cfg))
|
||||
(let ((res (apply proc cfg spec args)))
|
||||
(if end (end cfg))
|
||||
res))))
|
||||
((null? (cdr args))
|
||||
(app-help spec args)
|
||||
(error "Expected a command"))
|
||||
(else
|
||||
(error "Unknown command" args)))))
|
||||
|
||||
;;> Parse a single command-line argument from \var{args} according to
|
||||
;;> \var{conf-spec}, and returns a list of two values: the
|
||||
;;> \scheme{(name value)} for the option, and a list of remaining
|
||||
;;> unparsed args. \scheme{name} will have the current \var{prefix}
|
||||
;;> prepended. If a parse error or unknown option is found, calls
|
||||
;;> \var{fail} with a single string argument describing the error,
|
||||
;;> returning that result.
|
||||
|
||||
(define (parse-option prefix conf-spec args types fail)
|
||||
(define (parse-value type str)
|
||||
(cond
|
||||
((not (string? str))
|
||||
(list str #f))
|
||||
((and (pair? type) (eq? 'list (car type)))
|
||||
(let ((res (map (lambda (x) (parse-value (cadr type) x))
|
||||
(string-split str #\,))))
|
||||
(list (map car res) (any string? (map cdr res)))))
|
||||
(else
|
||||
(case type
|
||||
((boolean)
|
||||
(list (not (member str '("#f" "#false" "#F" "#FALSE" "false" "FALSE")))
|
||||
#f))
|
||||
((number integer real)
|
||||
(let ((n (string->number str)))
|
||||
(cond
|
||||
((and (eq? type 'integer) (not (integer? n)))
|
||||
(list n "expected an integer"))
|
||||
((and (eq? type 'real) (not (real? n)))
|
||||
(list n "expected a real number"))
|
||||
(else
|
||||
(list n #f)))))
|
||||
((symbol)
|
||||
(list (string->symbol str) #f))
|
||||
((char)
|
||||
(if (not (= 1 (string-length str)))
|
||||
(list #f "expected a single character")
|
||||
(list (string-ref str 0) #f)))
|
||||
((sexp)
|
||||
(list (guard (exn (else str))
|
||||
(let* ((in (open-input-string str))
|
||||
(res (read in)))
|
||||
(close-input-port in)
|
||||
res))
|
||||
#f))
|
||||
(else
|
||||
(cond
|
||||
((assq type types)
|
||||
=> (lambda (cell) (list ((cadr cell) str) #f)))
|
||||
(else (list str #f))))))))
|
||||
(define (lookup-conf-spec conf-spec syms strs)
|
||||
(let ((sym (car syms))
|
||||
(str (car strs)))
|
||||
(cond
|
||||
((= 1 (length syms))
|
||||
(let lp ((ls conf-spec))
|
||||
(and (pair? ls)
|
||||
(let ((x (car ls)))
|
||||
(cond
|
||||
((eq? sym (car x)) x)
|
||||
((and (pair? (cddr x)) (pair? (third x))
|
||||
(member str (third x)))
|
||||
x)
|
||||
((and (pair? (cddr x)) (pair? (third x))
|
||||
(member `(not ,str) (third x)))
|
||||
`(not ,x))
|
||||
(else (lp (cdr ls))))))))
|
||||
(else
|
||||
(let lp ((ls conf-spec))
|
||||
(and (pair? ls)
|
||||
(let ((x (car ls)))
|
||||
(cond
|
||||
((or (eq? sym (car x))
|
||||
(and (pair? (cddr x)) (pair? (third x))
|
||||
(member str (third x))))
|
||||
(let ((type (cadr x)))
|
||||
(if (not (and (pair? type) (eq? 'conf (car type))))
|
||||
(error "option prefix not a subconf" sym)
|
||||
(lookup-conf-spec (cdr type) (cdr syms) (cdr strs)))))
|
||||
(else (lp (cdr ls)))))))))))
|
||||
(define (lookup-short-option ch spec)
|
||||
(let lp ((ls spec))
|
||||
(and (pair? ls)
|
||||
(let ((x (car ls)))
|
||||
(cond
|
||||
((and (pair? (cddr x)) (pair? (third x)) (memv ch (third x)))
|
||||
x)
|
||||
((and (pair? (cddr x)) (pair? (third x))
|
||||
(member `(not ,ch) (third x)))
|
||||
`(not ,x))
|
||||
(else (lp (cdr ls))))))))
|
||||
(define (parse-long-option str args fail)
|
||||
(let* ((fail-args (cons (string-append "--" str) args))
|
||||
(str+val (string-split str #\= 2))
|
||||
(str (car str+val))
|
||||
(args (if (pair? (cdr str+val)) (cons (cadr str+val) args) args))
|
||||
(strs (string-split str #\.))
|
||||
(syms (map string->symbol strs))
|
||||
(spec (lookup-conf-spec conf-spec syms strs)))
|
||||
(cond
|
||||
((not spec)
|
||||
;; check for 'no' prefix on boolean
|
||||
(if (not (string-prefix? "no" str))
|
||||
(fail prefix conf-spec (car fail-args) fail-args "unknown option")
|
||||
(let ((res (parse-long-option (substring str 2) args (lambda args #f))))
|
||||
(cond
|
||||
((not res)
|
||||
(fail prefix conf-spec (car fail-args) fail-args
|
||||
"unknown option"))
|
||||
((not (boolean? (cdar res)))
|
||||
(error "'no' prefix only valid on boolean options"))
|
||||
(else
|
||||
`((,(caar res) . #f) ,@(cdr res)))))))
|
||||
((and (pair? spec) (eq? 'not (car spec)))
|
||||
(cons (cons (append prefix (list (car spec))) #f) args))
|
||||
((and (eq? 'boolean (cadr spec)) (null? (cdr str+val)))
|
||||
(cons (cons (append prefix (list (car spec))) #t) args))
|
||||
((null? args)
|
||||
(fail prefix conf-spec (car fail-args) fail-args
|
||||
"missing argument to option"))
|
||||
(else
|
||||
(let ((val+err (parse-value (cadr spec) (car args))))
|
||||
(if (cadr val+err)
|
||||
(fail prefix conf-spec (car fail-args) fail-args (cadr val+err))
|
||||
(cons (cons (append prefix (drop-right syms 1) (list (car spec)))
|
||||
(car val+err))
|
||||
(cdr args))))))))
|
||||
(define (parse-short-option str args fail)
|
||||
(let* ((ch (string-ref str 0))
|
||||
(x (lookup-short-option ch conf-spec))
|
||||
(fail-args (cons (string-append "-" str) args)))
|
||||
(cond
|
||||
((not x)
|
||||
(fail prefix conf-spec (car fail-args) fail-args "unknown option"))
|
||||
((and (pair? x) (eq? 'not (car x)))
|
||||
(cons (cons (append prefix (list (car (cadr x)))) #f)
|
||||
(if (= 1 (string-length str))
|
||||
args
|
||||
(cons (string-append "-" (substring str 1)) args))))
|
||||
((eq? 'boolean (cadr x))
|
||||
(cons (cons (append prefix (list (car x))) #t)
|
||||
(if (= 1 (string-length str))
|
||||
args
|
||||
(cons (string-append "-" (substring str 1)) args))))
|
||||
((> (string-length str) 1)
|
||||
(let ((val+err (parse-value (cadr x) (substring str 1))))
|
||||
(if (cadr val+err)
|
||||
(fail prefix conf-spec (car args) args (cadr val+err))
|
||||
(cons (cons (append prefix (list (car x))) (car val+err))
|
||||
args))))
|
||||
((null? args)
|
||||
(fail prefix conf-spec (car fail-args) fail-args
|
||||
"missing argument to option"))
|
||||
(else
|
||||
(cons (cons (append prefix (list (car x))) (car args)) (cdr args))))))
|
||||
(if (eqv? #\- (string-ref (car args) 1))
|
||||
(parse-long-option (substring (car args) 2) (cdr args) fail)
|
||||
(parse-short-option (substring (car args) 1) (cdr args) fail)))
|
||||
|
||||
;;> Parse a list of command-line arguments into a config object.
|
||||
;;> Returns a list whose head is the resulting config object, and tail
|
||||
;;> is the list of remaining non-option arguments. Calls fail on
|
||||
;;> error and tries to continue processing from the result.
|
||||
|
||||
(define (parse-options prefix conf-spec orig-args types fail)
|
||||
(let lp ((args orig-args)
|
||||
(opts (make-conf '() #f (cons 'options orig-args) #f)))
|
||||
(cond
|
||||
((null? args)
|
||||
(cons opts args))
|
||||
((or (member (car args) '("" "-" "--"))
|
||||
(not (eqv? #\- (string-ref (car args) 0))))
|
||||
(cons opts (if (equal? (car args) "--") (cdr args) args)))
|
||||
(else
|
||||
(let ((val+args (parse-option prefix conf-spec args types fail)))
|
||||
(lp (cdr val+args)
|
||||
(conf-set opts (caar val+args) (cdar val+args))))))))
|
||||
|
||||
;;> Parses a list of command-line arguments \var{args} according to
|
||||
;;> the application spec \var{opt-spec}. Returns a vector of five
|
||||
;;> elements:
|
||||
;;>
|
||||
;;> \itemlist[
|
||||
;;> \item{\scheme{proc} - procedure to run the application}
|
||||
;;> \item{\scheme{config} - a config object containing all parsed options}
|
||||
;;> \item{\scheme{args} - a list of remaining unparsed command-line arguments}
|
||||
;;> \item{\scheme{init} - an optional procedure to call before \scheme{proc}}
|
||||
;;> \item{\scheme{end} - an optional procedure to call after \scheme{proc}}
|
||||
;;> ]
|
||||
;;>
|
||||
;;> The config object is prepended to \var{config}, with option names
|
||||
;;> all prefixed by \var{prefix}. The original \var{spec} is used for
|
||||
;;> \scheme{app-help}.
|
||||
|
||||
(define (parse-app prefix spec opt-spec args config init end types . o)
|
||||
(define (next-prefix prefix name)
|
||||
(append (if (null? prefix) '(command) prefix) (list name)))
|
||||
(define (prev-prefix prefix)
|
||||
(cond ((and (= 2 (length prefix))) '())
|
||||
((null? prefix) '())
|
||||
(else (reverse (cdr (reverse prefix))))))
|
||||
(define (all-opt-names opt-spec)
|
||||
;; TODO: nested options
|
||||
(let lp ((ls opt-spec) (res '()))
|
||||
(if (null? ls)
|
||||
(map (lambda (x) (if (symbol? x) (symbol->string x) x))
|
||||
(remove char? (reverse res)))
|
||||
(let ((o (car ls)))
|
||||
(lp (cdr ls)
|
||||
(append (if (and (pair? (cddr o)) (pair? (third o)))
|
||||
(third o)
|
||||
'())
|
||||
(cons (car o) res)))))))
|
||||
(let ((fail (if (pair? o)
|
||||
(car o)
|
||||
(lambda (prefix spec opt args reason)
|
||||
(cond
|
||||
((and (string=? reason "unknown option")
|
||||
(find-nearest-edits opt (all-opt-names spec)))
|
||||
=> (lambda (similar)
|
||||
(if (pair? similar)
|
||||
(error reason opt "Did you mean: " similar)
|
||||
(error reason opt))))
|
||||
(else
|
||||
(error reason opt)))))))
|
||||
(cond
|
||||
((null? spec)
|
||||
(error "no procedure in application spec"))
|
||||
((or (null? (car spec)) (equal? '(@) (car spec)))
|
||||
(parse-app prefix (cdr spec) opt-spec args config init end types fail))
|
||||
((pair? (car spec))
|
||||
(case (caar spec)
|
||||
((@)
|
||||
(let* ((tail (cdar spec))
|
||||
(new-opt-spec
|
||||
(cond
|
||||
((not (pair? tail))
|
||||
'())
|
||||
((or (pair? (cdr tail))
|
||||
(and (pair? (car tail)) (symbol? (caar tail))))
|
||||
tail)
|
||||
(else
|
||||
(car tail))))
|
||||
(new-fail
|
||||
(lambda (new-prefix new-spec new-opt new-args reason)
|
||||
(parse-option (prev-prefix prefix) opt-spec new-args types fail)))
|
||||
(cfg+args (parse-options prefix new-opt-spec args types new-fail))
|
||||
(config (conf-append (car cfg+args) config))
|
||||
(args (cdr cfg+args)))
|
||||
(parse-app prefix (cdr spec) new-opt-spec args config
|
||||
init end types new-fail)))
|
||||
((or)
|
||||
(any (lambda (x) (parse-app prefix x opt-spec args config init end types))
|
||||
(cdar spec)))
|
||||
((begin:)
|
||||
(parse-app prefix (cdr spec) opt-spec args config
|
||||
(cadr (car spec)) end types fail))
|
||||
((end:)
|
||||
(parse-app prefix (cdr spec) opt-spec args config
|
||||
init (cadr (car spec)) types fail))
|
||||
((types:)
|
||||
(parse-app prefix (cdr spec) opt-spec args config
|
||||
init end (cdr (car spec)) fail))
|
||||
(else
|
||||
(if (procedure? (caar spec))
|
||||
(vector (caar spec) config args init end) ; TODO: verify
|
||||
(parse-app prefix (car spec) opt-spec args config
|
||||
init end types fail)))))
|
||||
((symbol? (car spec))
|
||||
(and (pair? args)
|
||||
(eq? (car spec) (string->symbol (car args)))
|
||||
(let ((prefix (next-prefix prefix (car spec))))
|
||||
(parse-app prefix (cdr spec) opt-spec (cdr args) config
|
||||
init end types fail))))
|
||||
((procedure? (car spec))
|
||||
(vector (car spec) config args init end))
|
||||
(else
|
||||
(if (not (string? (car spec)))
|
||||
(error "unknown application spec" (car spec)))
|
||||
(parse-app prefix (cdr spec) opt-spec args config init end types fail)))))
|
||||
|
||||
(define (print-command-help command out)
|
||||
(cond
|
||||
((and (pair? command) (symbol? (car command)))
|
||||
(display " " out)
|
||||
(display (car command) out)
|
||||
(cond
|
||||
((find (lambda (x) (and (pair? x) (procedure? (car x)))) command)
|
||||
=> (lambda (x)
|
||||
(let lp ((args (cdr x)) (opt-depth 0))
|
||||
(cond
|
||||
((null? args)
|
||||
(display (make-string opt-depth #\]) out))
|
||||
((pair? (car args))
|
||||
(display " [" out)
|
||||
(display (caar args) out)
|
||||
(lp (cdr args) (+ opt-depth 1)))
|
||||
(else
|
||||
(display " " out)
|
||||
(display (car args) out)
|
||||
(lp (cdr args) opt-depth)))))))
|
||||
(cond
|
||||
((find string? command)
|
||||
=> (lambda (doc-string) (display " - " out) (display doc-string out))))
|
||||
(newline out))))
|
||||
|
||||
(define (print-option-help option out)
|
||||
(let* ((str (symbol->string (car option)))
|
||||
(names (if (and (pair? (cdr option)) (pair? (cddr option)))
|
||||
(car (cddr option))
|
||||
'()))
|
||||
(pref-str (cond ((find string? names) => values) (else str)))
|
||||
(pref-ch (find char? names))
|
||||
(doc (find string? (cdr option))))
|
||||
;; TODO: consider aligning these
|
||||
(cond
|
||||
(pref-ch (display " -" out) (write-char pref-ch out))
|
||||
(else (display " " out)))
|
||||
(cond
|
||||
(pref-str
|
||||
(display (if pref-ch ", " " ") out)
|
||||
(display "--" out) (display pref-str out)))
|
||||
(cond (doc (display " - " out) (display doc out)))
|
||||
(newline out)))
|
||||
|
||||
(define (print-help name docs commands options . o)
|
||||
(let ((out (if (pair? o) (car o) (current-output-port))))
|
||||
(display "Usage: " out) (display name out)
|
||||
(if (pair? options) (display " [options]" out))
|
||||
(case (length commands)
|
||||
((0) (newline out))
|
||||
(else
|
||||
(display " <command>\nCommands:\n" out)
|
||||
(for-each (lambda (c) (print-command-help c out)) commands))
|
||||
((1) (print-command-help (car commands) out)))
|
||||
(if (pair? options) (display "Options:\n" out))
|
||||
(for-each (lambda (o) (print-option-help o out)) options)))
|
||||
|
||||
;;> Print a help summary for the given application spec \var{spec}.
|
||||
|
||||
(define (app-help spec args . o)
|
||||
(let ((out (if (pair? o) (car o) (current-output-port))))
|
||||
(let lp ((ls (cdr spec))
|
||||
(docs #f)
|
||||
(commands '())
|
||||
(options '()))
|
||||
(cond
|
||||
((null? ls)
|
||||
(print-help (car spec) docs commands options out))
|
||||
((or (string? (car ls))
|
||||
(and (pair? (car ls)) (memq (caar ls) '(begin: end:) )))
|
||||
(lp (cdr ls) (car ls) commands options))
|
||||
((and (pair? (car ls)) (eq? '@ (caar ls)))
|
||||
(lp (cdr ls) docs commands (append options (cdar ls))))
|
||||
((and (pair? (car ls)) (symbol? (caar ls)))
|
||||
;; don't print nested commands
|
||||
(if (pair? commands)
|
||||
(print-help (car spec) docs commands options out)
|
||||
(if (eq? 'or (caar ls))
|
||||
(lp (cdr ls) docs (cdar ls) options)
|
||||
(lp (cdr ls) docs (list (car ls)) options))))
|
||||
(else
|
||||
(lp (cdr ls) docs commands options))))))
|
||||
|
||||
;;> The subcommand form of \scheme{app-help}. You can use this as a
|
||||
;;> subcommand in an application spec, for example as:
|
||||
;;> \schemeblock{(help "print help" (,app-help-command args ...))}
|
||||
|
||||
(define (app-help-command config spec . args)
|
||||
(app-help spec args (current-output-port)))
|
|
@ -1,14 +0,0 @@
|
|||
;;> Unified command-line option parsing and config management.
|
||||
|
||||
(define-library (chibi app)
|
||||
(export parse-option parse-options parse-app run-application
|
||||
app-help app-help-command)
|
||||
(import (scheme base)
|
||||
(scheme read)
|
||||
(scheme write)
|
||||
(scheme process-context)
|
||||
(srfi 1)
|
||||
(chibi config)
|
||||
(chibi edit-distance)
|
||||
(chibi string))
|
||||
(include "app.scm"))
|
|
@ -1,33 +0,0 @@
|
|||
(define (list-bindings env)
|
||||
(let parents ((env env) (binds '()))
|
||||
(if (not env) binds
|
||||
(let symbols ((syms (env-exports env)) (binds binds))
|
||||
(if (null? syms) (parents (env-parent env) binds)
|
||||
(symbols (cdr syms) (if (assv (car syms) binds) binds
|
||||
(cons (cons (car syms) env)
|
||||
binds))))))))
|
||||
|
||||
(define (apropos-list-bindings query)
|
||||
(cond ((symbol? query) (set! query (symbol->string query)))
|
||||
((not (string? query))
|
||||
(error "Apropos query must be a symbol or a string")))
|
||||
(sort (filter (lambda (binding)
|
||||
(string-contains (symbol->string (car binding)) query))
|
||||
(list-bindings (interaction-environment)))
|
||||
(lambda (a b) (string<? (symbol->string (car a))
|
||||
(symbol->string (car b))))))
|
||||
|
||||
(define (apropos-list query) (map car (apropos-list-bindings query)))
|
||||
|
||||
(define (apropos-prefix sym env)
|
||||
(let ((p "procedure ")
|
||||
(s "syntax ")
|
||||
(v "variable "))
|
||||
(guard (_ (else s)) (if (procedure? (eval sym env)) p v))))
|
||||
|
||||
(define (apropos query)
|
||||
(for-each (lambda (bind)
|
||||
(display (apropos-prefix (car bind) (cdr bind)))
|
||||
(write (car bind))
|
||||
(newline))
|
||||
(apropos-list-bindings query)))
|
|
@ -1,4 +0,0 @@
|
|||
(define-library (chibi apropos)
|
||||
(export apropos apropos-list)
|
||||
(import (scheme base) (chibi) (chibi string) (srfi 1) (srfi 95))
|
||||
(include "apropos.scm"))
|
|
@ -1,30 +0,0 @@
|
|||
|
||||
(define-library (chibi assert-test)
|
||||
(import (chibi) (chibi assert) (chibi test))
|
||||
(export run-tests)
|
||||
(begin
|
||||
(define-syntax test-assert
|
||||
(syntax-rules ()
|
||||
((test-assert irritants expr)
|
||||
(protect (exn
|
||||
(else
|
||||
(test irritants (exception-irritants exn))))
|
||||
expr
|
||||
(error "assertion not triggered")))))
|
||||
(define (run-tests)
|
||||
(test-begin "assert")
|
||||
(test-assert '((= x (+ x 1))
|
||||
(x 3))
|
||||
(let ((x 3)) (assert (= x (+ x 1)))))
|
||||
(test-assert '((= x (+ y 1))
|
||||
(x 3)
|
||||
(y 42))
|
||||
(let ((x 3) (y 42)) (assert (= x (+ y 1)))))
|
||||
(test-assert '((eq? x 'three)
|
||||
(x 3))
|
||||
(let ((x 3)) (assert (eq? x 'three))))
|
||||
(test-assert '((eq? x 'three)
|
||||
"expected three: "
|
||||
3)
|
||||
(let ((x 3)) (assert (eq? x 'three) "expected three: " x)))
|
||||
(test-end))))
|
|
@ -1,115 +0,0 @@
|
|||
|
||||
;;> A nice assert macro.
|
||||
;;>
|
||||
;;> Assert macros are common in Scheme, in particular being helpful
|
||||
;;> for domain checks at the beginning of a procedure to catch errors
|
||||
;;> as early as possible. Compared to statically typed languages this
|
||||
;;> has the advantages that the assertions are optional, and that they
|
||||
;;> are not limited by the type system. SRFI 145 provides the related
|
||||
;;> notion of assumptions, but the motivation there is to provide
|
||||
;;> hints to optimizing compilers, and these are not required to
|
||||
;;> actually signal an error.
|
||||
;;>
|
||||
;;> \macro{(assert expr [msg ...])}
|
||||
;;>
|
||||
;;> Equivalent to SRFI 145 \code{assume} except that an error is
|
||||
;;> guaranteed to be raised if \var{expr} is false. Conceptually
|
||||
;;> shorthand for
|
||||
;;>
|
||||
;;> \code{(or \var{expr}
|
||||
;;> (error "assertion failed" \var{msg} ...))}
|
||||
;;>
|
||||
;;> that is, evaluates \var{expr} and returns it if true, but raises
|
||||
;;> an exception otherwise. The error is augmented to include the
|
||||
;;> text of the failed \var{expr}. If no additional \var{msg}
|
||||
;;> arguments are provided then \var{expr} is scanned for free
|
||||
;;> variables in non-operator positions to report values from, e.g. in
|
||||
;;>
|
||||
;;> \code{(let ((x 3))
|
||||
;;> (assert (= x (+ x 1))))}
|
||||
;;>
|
||||
;;> the error would also report the bound value of \code{x}. This
|
||||
;;> uses the technique from Oleg Kiselyov's \hyperlink[http://okmij.org/ftp/Scheme/assert-syntax-rule.txt]{good assert macro},
|
||||
;;> which is convenient but fallible. It is thus best to keep the
|
||||
;;> body of the assertion simple, moving any predicates you need to
|
||||
;;> external utilities, or provide an explicit \var{msg}.
|
||||
|
||||
(define-library (chibi assert)
|
||||
(export assert)
|
||||
(cond-expand
|
||||
(chibi
|
||||
(import (chibi))
|
||||
(begin
|
||||
(define-syntax syntax-identifier?
|
||||
(er-macro-transformer
|
||||
(lambda (expr rename compare)
|
||||
(if (identifier? (cadr expr))
|
||||
(car (cddr expr))
|
||||
(cadr (cddr expr))))))
|
||||
(define-syntax syntax-id-memq?
|
||||
(er-macro-transformer
|
||||
(lambda (expr rename compare)
|
||||
(let ((expr (cdr expr)))
|
||||
(if (any (lambda (x) (compare x (car expr))) (cadr expr))
|
||||
(car (cddr expr))
|
||||
(cadr (cddr expr)))))))))
|
||||
(else
|
||||
(import (scheme base))
|
||||
(begin
|
||||
;; from match.scm
|
||||
(define-syntax syntax-identifier?
|
||||
(syntax-rules ()
|
||||
((_ (x . y) success-k failure-k) failure-k)
|
||||
((_ #(x ...) success-k failure-k) failure-k)
|
||||
((_ x success-k failure-k)
|
||||
(let-syntax
|
||||
((sym?
|
||||
(syntax-rules ()
|
||||
((sym? x sk fk) sk)
|
||||
((sym? y sk fk) fk))))
|
||||
(sym? abracadabra success-k failure-k)))))
|
||||
(define-syntax syntax-id-memq?
|
||||
(syntax-rules ()
|
||||
((syntax-memq? id (ids ...) sk fk)
|
||||
(let-syntax
|
||||
((memq?
|
||||
(syntax-rules (ids ...)
|
||||
((memq? id sk2 fk2) fk2)
|
||||
((memq? any-other sk2 fk2) sk2))))
|
||||
(memq? random-symbol-to-match sk fk))))))))
|
||||
(begin
|
||||
(define-syntax extract-vars
|
||||
(syntax-rules ()
|
||||
((report-vars (op arg0 arg1 ...) (next ...) res)
|
||||
(syntax-id-memq? op (quote quasiquote lambda let let* letrec letrec*
|
||||
let-syntax letrec-syntax let-values let*-values
|
||||
receive match case define define-syntax do)
|
||||
(next ... res)
|
||||
(extract-vars arg0
|
||||
(extract-vars (op arg1 ...) (next ...))
|
||||
res)))
|
||||
((report-vars (op . x) (next ...) res)
|
||||
(next ... res))
|
||||
((report-vars x (next ...) (res ...))
|
||||
(syntax-identifier? x
|
||||
(syntax-id-memq? x (res ...)
|
||||
(next ... (res ...))
|
||||
(next ... (res ... x)))
|
||||
(next ... (res ...))))))
|
||||
(define-syntax qq-vars
|
||||
(syntax-rules ()
|
||||
((qq-vars (next ...) (var ...))
|
||||
(next ... `(var ,var) ...))))
|
||||
(define-syntax report-final
|
||||
(syntax-rules ()
|
||||
((report-final expr msg ...)
|
||||
(error "assertion failed" 'expr msg ...))))
|
||||
(define-syntax assert
|
||||
(syntax-rules ()
|
||||
((assert test)
|
||||
(or test
|
||||
(extract-vars test (qq-vars (report-final test)) ())))
|
||||
((assert test msg ...)
|
||||
(or test
|
||||
(report-final test msg ...)))
|
||||
((assert) #t)))))
|
427
lib/chibi/ast.c
427
lib/chibi/ast.c
|
@ -1,40 +1,18 @@
|
|||
/* ast.c -- interface to the Abstract Syntax Tree */
|
||||
/* Copyright (c) 2009-2015 Alex Shinn. All rights reserved. */
|
||||
/* Copyright (c) 2009-2012 Alex Shinn. All rights reserved. */
|
||||
/* BSD-style license: http://synthcode.com/license.txt */
|
||||
|
||||
#include <chibi/eval.h>
|
||||
|
||||
#ifndef PLAN9
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#if defined(__MINGW32__) || defined(__MINGW64__)
|
||||
/* Workaround MinGW header implementation */
|
||||
errno_t getenv_s(size_t*, char*, size_t, const char*);
|
||||
#endif
|
||||
int setenv(const char *name, const char *value, int overwrite)
|
||||
{
|
||||
int errcode = 0;
|
||||
if (!overwrite) {
|
||||
size_t envsize = 0;
|
||||
errcode = getenv_s(&envsize, NULL, 0, name);
|
||||
if (errcode || envsize) return errcode;
|
||||
}
|
||||
return _putenv_s(name, value);
|
||||
}
|
||||
int unsetenv(const char *name)
|
||||
{
|
||||
return setenv(name, "", 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ! SEXP_USE_BOEHM
|
||||
extern sexp sexp_gc (sexp ctx, size_t *sum_freed);
|
||||
#endif
|
||||
|
||||
static void sexp_define_type_predicate (sexp ctx, sexp env, const char *cname, sexp_uint_t type) {
|
||||
static void sexp_define_type_predicate (sexp ctx, sexp env, char *cname, sexp_uint_t type) {
|
||||
sexp_gc_var2(name, op);
|
||||
sexp_gc_preserve2(ctx, name, op);
|
||||
name = sexp_c_string(ctx, cname, -1);
|
||||
|
@ -44,8 +22,7 @@ static void sexp_define_type_predicate (sexp ctx, sexp env, const char *cname, s
|
|||
}
|
||||
|
||||
static void sexp_define_accessors (sexp ctx, sexp env, sexp_uint_t ctype,
|
||||
sexp_uint_t cindex,
|
||||
const char* get, const char *set) {
|
||||
sexp_uint_t cindex, char* get, char *set) {
|
||||
sexp type, index;
|
||||
sexp_gc_var2(name, op);
|
||||
sexp_gc_preserve2(ctx, name, op);
|
||||
|
@ -62,65 +39,28 @@ static void sexp_define_accessors (sexp ctx, sexp env, sexp_uint_t ctype,
|
|||
sexp_gc_release2(ctx);
|
||||
}
|
||||
|
||||
sexp sexp_get_env_cell (sexp ctx, sexp self, sexp_sint_t n, sexp env, sexp id, sexp createp) {
|
||||
static sexp sexp_get_env_cell (sexp ctx, sexp self, sexp_sint_t n, sexp env, sexp id) {
|
||||
sexp cell;
|
||||
sexp_assert_type(ctx, sexp_envp, SEXP_ENV, env);
|
||||
cell = sexp_env_cell(ctx, env, id, 0);
|
||||
if (! cell) {
|
||||
if (sexp_synclop(id)) {
|
||||
env = sexp_synclo_env(id);
|
||||
id = sexp_synclo_expr(id);
|
||||
}
|
||||
cell = sexp_env_cell(ctx, env, id, 0);
|
||||
if (!cell && sexp_truep(createp))
|
||||
cell = sexp_env_cell_define(ctx, env, id, SEXP_UNDEF, NULL);
|
||||
cell = sexp_env_cell(env, id, 0);
|
||||
while ((! cell) && sexp_synclop(id)) {
|
||||
env = sexp_synclo_env(id);
|
||||
id = sexp_synclo_expr(id);
|
||||
}
|
||||
return cell ? cell : SEXP_FALSE;
|
||||
}
|
||||
|
||||
sexp sexp_get_procedure_code (sexp ctx, sexp self, sexp_sint_t n, sexp proc) {
|
||||
static sexp sexp_get_procedure_code (sexp ctx, sexp self, sexp_sint_t n, sexp proc) {
|
||||
sexp_assert_type(ctx, sexp_procedurep, SEXP_PROCEDURE, proc);
|
||||
return sexp_procedure_code(proc);
|
||||
}
|
||||
|
||||
sexp sexp_get_procedure_vars (sexp ctx, sexp self, sexp_sint_t n, sexp proc) {
|
||||
static sexp sexp_get_procedure_vars (sexp ctx, sexp self, sexp_sint_t n, sexp proc) {
|
||||
sexp_assert_type(ctx, sexp_procedurep, SEXP_PROCEDURE, proc);
|
||||
return sexp_procedure_vars(proc);
|
||||
}
|
||||
|
||||
sexp sexp_get_procedure_arity (sexp ctx, sexp self, sexp_sint_t n, sexp proc) {
|
||||
sexp_assert_type(ctx, sexp_procedurep, SEXP_PROCEDURE, proc);
|
||||
return sexp_make_fixnum(sexp_procedure_num_args(proc));
|
||||
}
|
||||
|
||||
sexp sexp_get_procedure_variadic_p (sexp ctx, sexp self, sexp_sint_t n, sexp proc) {
|
||||
sexp_assert_type(ctx, sexp_procedurep, SEXP_PROCEDURE, proc);
|
||||
return sexp_make_boolean(sexp_procedure_variadic_p(proc));
|
||||
}
|
||||
|
||||
sexp sexp_get_procedure_variable_transformer_p (sexp ctx, sexp self, sexp_sint_t n, sexp proc) {
|
||||
sexp_assert_type(ctx, sexp_procedurep, SEXP_PROCEDURE, proc);
|
||||
return sexp_make_boolean(sexp_procedure_variable_transformer_p(proc));
|
||||
}
|
||||
|
||||
sexp sexp_get_procedure_flags (sexp ctx, sexp self, sexp_sint_t n, sexp proc) {
|
||||
sexp_assert_type(ctx, sexp_procedurep, SEXP_PROCEDURE, proc);
|
||||
return (sexp) (sexp_uint_t) sexp_procedure_flags(proc);
|
||||
}
|
||||
|
||||
sexp sexp_make_variable_transformer_op (sexp ctx, sexp self, sexp_sint_t n, sexp base_proc) {
|
||||
sexp flags;
|
||||
sexp_assert_type(ctx, sexp_procedurep, SEXP_PROCEDURE, base_proc);
|
||||
if (sexp_procedure_variable_transformer_p(base_proc))
|
||||
return base_proc;
|
||||
flags = sexp_make_fixnum(sexp_unbox_fixnum(sexp_procedure_flags(base_proc)) | SEXP_PROC_VARIABLE_TRANSFORMER);
|
||||
return sexp_make_procedure(ctx, flags,
|
||||
sexp_make_fixnum(sexp_procedure_num_args(base_proc)),
|
||||
sexp_procedure_code(base_proc),
|
||||
sexp_procedure_vars(base_proc));
|
||||
}
|
||||
|
||||
sexp sexp_get_opcode_name (sexp ctx, sexp self, sexp_sint_t n, sexp op) {
|
||||
static sexp sexp_get_opcode_name (sexp ctx, sexp self, sexp_sint_t n, sexp op) {
|
||||
if (! sexp_opcodep(op))
|
||||
return sexp_type_exception(ctx, self, SEXP_OPCODE, op);
|
||||
else if (! sexp_opcode_name(op))
|
||||
|
@ -147,7 +87,7 @@ static sexp sexp_translate_opcode_type (sexp ctx, sexp type) {
|
|||
return res;
|
||||
}
|
||||
|
||||
sexp sexp_get_opcode_ret_type (sexp ctx, sexp self, sexp_sint_t n, sexp op) {
|
||||
static sexp sexp_get_opcode_ret_type (sexp ctx, sexp self, sexp_sint_t n, sexp op) {
|
||||
sexp res;
|
||||
if (!op)
|
||||
return sexp_type_by_index(ctx, SEXP_OBJECT);
|
||||
|
@ -161,7 +101,7 @@ sexp sexp_get_opcode_ret_type (sexp ctx, sexp self, sexp_sint_t n, sexp op) {
|
|||
return sexp_translate_opcode_type(ctx, res);
|
||||
}
|
||||
|
||||
sexp sexp_get_opcode_param_type (sexp ctx, sexp self, sexp_sint_t n, sexp op, sexp k) {
|
||||
static sexp sexp_get_opcode_param_type (sexp ctx, sexp self, sexp_sint_t n, sexp op, sexp k) {
|
||||
sexp res;
|
||||
int p = sexp_unbox_fixnum(k);
|
||||
if (! sexp_opcodep(op))
|
||||
|
@ -180,7 +120,7 @@ sexp sexp_get_opcode_param_type (sexp ctx, sexp self, sexp_sint_t n, sexp op, se
|
|||
default:
|
||||
res = sexp_opcode_arg3_type(op);
|
||||
if (res && sexp_vectorp(res)) {
|
||||
if (sexp_vector_length(res) > (unsigned)(sexp_unbox_fixnum(k)-2))
|
||||
if (sexp_vector_length(res) > (sexp_unbox_fixnum(k)-2))
|
||||
res = sexp_vector_ref(res, sexp_fx_sub(k, SEXP_TWO));
|
||||
else
|
||||
res = sexp_type_by_index(ctx, SEXP_OBJECT);
|
||||
|
@ -190,17 +130,17 @@ sexp sexp_get_opcode_param_type (sexp ctx, sexp self, sexp_sint_t n, sexp op, se
|
|||
return sexp_translate_opcode_type(ctx, res);
|
||||
}
|
||||
|
||||
sexp sexp_get_opcode_class (sexp ctx, sexp self, sexp_sint_t n, sexp op) {
|
||||
static sexp sexp_get_opcode_class (sexp ctx, sexp self, sexp_sint_t n, sexp op) {
|
||||
sexp_assert_type(ctx, sexp_opcodep, SEXP_OPCODE, op);
|
||||
return sexp_make_fixnum(sexp_opcode_class(op));
|
||||
}
|
||||
|
||||
sexp sexp_get_opcode_code (sexp ctx, sexp self, sexp_sint_t n, sexp op) {
|
||||
static sexp sexp_get_opcode_code (sexp ctx, sexp self, sexp_sint_t n, sexp op) {
|
||||
sexp_assert_type(ctx, sexp_opcodep, SEXP_OPCODE, op);
|
||||
return sexp_make_fixnum(sexp_opcode_code(op));
|
||||
}
|
||||
|
||||
sexp sexp_get_opcode_data (sexp ctx, sexp self, sexp_sint_t n, sexp op) {
|
||||
static sexp sexp_get_opcode_data (sexp ctx, sexp self, sexp_sint_t n, sexp op) {
|
||||
sexp data;
|
||||
sexp_assert_type(ctx, sexp_opcodep, SEXP_OPCODE, op);
|
||||
data = sexp_opcode_data(op);
|
||||
|
@ -211,43 +151,29 @@ sexp sexp_get_opcode_data (sexp ctx, sexp self, sexp_sint_t n, sexp op) {
|
|||
sexp_type_by_index(ctx, sexp_unbox_fixnum(data)) : data;
|
||||
}
|
||||
|
||||
sexp sexp_get_opcode_num_params (sexp ctx, sexp self, sexp_sint_t n, sexp op) {
|
||||
static sexp sexp_get_opcode_num_params (sexp ctx, sexp self, sexp_sint_t n, sexp op) {
|
||||
sexp_assert_type(ctx, sexp_opcodep, SEXP_OPCODE, op);
|
||||
return sexp_make_fixnum(sexp_opcode_num_args(op));
|
||||
}
|
||||
|
||||
sexp sexp_get_opcode_variadic_p (sexp ctx, sexp self, sexp_sint_t n, sexp op) {
|
||||
static sexp sexp_get_opcode_variadic_p (sexp ctx, sexp self, sexp_sint_t n, sexp op) {
|
||||
sexp_assert_type(ctx, sexp_opcodep, SEXP_OPCODE, op);
|
||||
return sexp_make_boolean(sexp_opcode_variadic_p(op));
|
||||
}
|
||||
|
||||
sexp sexp_get_port_line (sexp ctx, sexp self, sexp_sint_t n, sexp p) {
|
||||
static sexp sexp_get_port_line (sexp ctx, sexp self, sexp_sint_t n, sexp p) {
|
||||
sexp_assert_type(ctx, sexp_portp, SEXP_IPORT, p);
|
||||
return sexp_make_fixnum(sexp_port_line(p));
|
||||
}
|
||||
|
||||
sexp sexp_set_port_line (sexp ctx, sexp self, sexp_sint_t n, sexp p, sexp i) {
|
||||
static sexp sexp_set_port_line (sexp ctx, sexp self, sexp_sint_t n, sexp p, sexp i) {
|
||||
sexp_assert_type(ctx, sexp_portp, SEXP_IPORT, p);
|
||||
sexp_assert_type(ctx, sexp_fixnump, SEXP_FIXNUM, i);
|
||||
sexp_port_line(p) = sexp_unbox_fixnum(i);
|
||||
return SEXP_VOID;
|
||||
}
|
||||
|
||||
sexp sexp_get_port_sourcep (sexp ctx, sexp self, sexp_sint_t n, sexp p) {
|
||||
sexp_assert_type(ctx, sexp_portp, SEXP_IPORT, p);
|
||||
return sexp_make_boolean(sexp_port_sourcep(p));
|
||||
}
|
||||
|
||||
sexp sexp_set_port_sourcep (sexp ctx, sexp self, sexp_sint_t n, sexp p, sexp b) {
|
||||
sexp_assert_type(ctx, sexp_portp, SEXP_IPORT, p);
|
||||
sexp_assert_type(ctx, sexp_booleanp, SEXP_BOOLEAN, b);
|
||||
sexp_port_sourcep(p) = sexp_truep(b);
|
||||
return SEXP_VOID;
|
||||
}
|
||||
|
||||
sexp sexp_type_of (sexp ctx, sexp self, sexp_sint_t n, sexp x) {
|
||||
if (!x)
|
||||
return sexp_type_by_index(ctx, SEXP_OBJECT);
|
||||
static sexp sexp_type_of (sexp ctx, sexp self, sexp_sint_t n, sexp x) {
|
||||
if (sexp_pointerp(x))
|
||||
return sexp_object_type(ctx, x);
|
||||
else if (sexp_fixnump(x))
|
||||
|
@ -268,91 +194,38 @@ sexp sexp_type_of (sexp ctx, sexp self, sexp_sint_t n, sexp x) {
|
|||
return sexp_type_by_index(ctx, SEXP_OBJECT);
|
||||
}
|
||||
|
||||
sexp sexp_env_parent_set_op (sexp ctx, sexp self, sexp_sint_t n, sexp e1, sexp e2) {
|
||||
sexp_assert_type(ctx, sexp_envp, SEXP_ENV, e1);
|
||||
if (sexp_truep(e2)) sexp_assert_type(ctx, sexp_envp, SEXP_ENV, e2);
|
||||
sexp_env_parent(e1) = e2;
|
||||
return SEXP_VOID;
|
||||
}
|
||||
|
||||
sexp sexp_env_lambda_op (sexp ctx, sexp self, sexp_sint_t n, sexp e) {
|
||||
static sexp sexp_env_parent_op (sexp ctx, sexp self, sexp_sint_t n, sexp e) {
|
||||
sexp_assert_type(ctx, sexp_envp, SEXP_ENV, e);
|
||||
return sexp_env_lambda(e) ? sexp_env_lambda(e) : SEXP_FALSE;
|
||||
return sexp_env_parent(e) ? sexp_env_parent(e) : SEXP_FALSE;
|
||||
}
|
||||
|
||||
sexp sexp_env_lambda_set_op (sexp ctx, sexp self, sexp_sint_t n, sexp e, sexp lam) {
|
||||
sexp_assert_type(ctx, sexp_envp, SEXP_ENV, e);
|
||||
sexp_assert_type(ctx, sexp_lambdap, SEXP_LAMBDA, lam);
|
||||
sexp_env_lambda(e) = lam;
|
||||
return SEXP_VOID;
|
||||
}
|
||||
|
||||
sexp sexp_env_syntactic_op (sexp ctx, sexp self, sexp_sint_t n, sexp e) {
|
||||
sexp_assert_type(ctx, sexp_envp, SEXP_ENV, e);
|
||||
return sexp_make_boolean(sexp_env_syntactic_p(e));
|
||||
}
|
||||
|
||||
sexp sexp_env_syntactic_set_op (sexp ctx, sexp self, sexp_sint_t n, sexp e, sexp synp) {
|
||||
sexp_assert_type(ctx, sexp_envp, SEXP_ENV, e);
|
||||
sexp_env_syntactic_p(e) = sexp_truep(synp);
|
||||
return SEXP_VOID;
|
||||
}
|
||||
|
||||
sexp sexp_env_define_op (sexp ctx, sexp self, sexp_sint_t n, sexp env, sexp name, sexp value) {
|
||||
sexp_assert_type(ctx, sexp_envp, SEXP_ENV, env);
|
||||
sexp_assert_type(ctx, sexp_idp, SEXP_SYMBOL, name);
|
||||
return sexp_env_cell_define(ctx, env, name, value, NULL);
|
||||
}
|
||||
|
||||
sexp sexp_env_push_op (sexp ctx, sexp self, sexp_sint_t n, sexp env, sexp name, sexp value) {
|
||||
sexp_gc_var1(tmp);
|
||||
sexp_assert_type(ctx, sexp_envp, SEXP_ENV, env);
|
||||
sexp_assert_type(ctx, sexp_idp, SEXP_SYMBOL, name);
|
||||
sexp_gc_preserve1(ctx, tmp);
|
||||
sexp_env_push(ctx, env, tmp, name, value);
|
||||
sexp_gc_release1(ctx);
|
||||
return SEXP_VOID;
|
||||
}
|
||||
|
||||
sexp sexp_core_code_op (sexp ctx, sexp self, sexp_sint_t n, sexp c) {
|
||||
sexp_assert_type(ctx, sexp_corep, SEXP_CORE, c);
|
||||
return sexp_make_fixnum(sexp_core_code(c));
|
||||
}
|
||||
|
||||
sexp sexp_type_name_op (sexp ctx, sexp self, sexp_sint_t n, sexp t) {
|
||||
static sexp sexp_type_name_op (sexp ctx, sexp self, sexp_sint_t n, sexp t) {
|
||||
sexp_assert_type(ctx, sexp_typep, SEXP_TYPE, t);
|
||||
return sexp_type_name(t);
|
||||
}
|
||||
|
||||
sexp sexp_type_cpl_op (sexp ctx, sexp self, sexp_sint_t n, sexp t) {
|
||||
static sexp sexp_type_cpl_op (sexp ctx, sexp self, sexp_sint_t n, sexp t) {
|
||||
sexp_assert_type(ctx, sexp_typep, SEXP_TYPE, t);
|
||||
return sexp_type_cpl(t);
|
||||
}
|
||||
|
||||
sexp sexp_type_slots_op (sexp ctx, sexp self, sexp_sint_t n, sexp t) {
|
||||
static sexp sexp_type_slots_op (sexp ctx, sexp self, sexp_sint_t n, sexp t) {
|
||||
sexp_assert_type(ctx, sexp_typep, SEXP_TYPE, t);
|
||||
return sexp_type_slots(t);
|
||||
}
|
||||
|
||||
sexp sexp_type_num_slots_op (sexp ctx, sexp self, sexp_sint_t n, sexp t) {
|
||||
static sexp sexp_type_num_slots_op (sexp ctx, sexp self, sexp_sint_t n, sexp t) {
|
||||
sexp_assert_type(ctx, sexp_typep, SEXP_TYPE, t);
|
||||
return sexp_truep(sexp_type_slots(t)) ? sexp_length(ctx, sexp_type_slots(t))
|
||||
: sexp_make_fixnum(sexp_type_field_eq_len_base(t));
|
||||
}
|
||||
|
||||
sexp sexp_type_printer_op (sexp ctx, sexp self, sexp_sint_t n, sexp t) {
|
||||
static sexp sexp_type_printer_op (sexp ctx, sexp self, sexp_sint_t n, sexp t) {
|
||||
sexp_assert_type(ctx, sexp_typep, SEXP_TYPE, t);
|
||||
return sexp_type_print(t) ? sexp_type_print(t) : SEXP_FALSE;
|
||||
}
|
||||
|
||||
sexp sexp_type_printer_set_op (sexp ctx, sexp self, sexp_sint_t n, sexp t, sexp p) {
|
||||
sexp_assert_type(ctx, sexp_typep, SEXP_TYPE, t);
|
||||
sexp_assert_type(ctx, sexp_applicablep, SEXP_PROCEDURE, p);
|
||||
sexp_type_print(t) = p;
|
||||
return SEXP_VOID;
|
||||
}
|
||||
|
||||
sexp sexp_object_size (sexp ctx, sexp self, sexp_sint_t n, sexp x) {
|
||||
static sexp sexp_object_size (sexp ctx, sexp self, sexp_sint_t n, sexp x) {
|
||||
sexp t;
|
||||
if ((! sexp_pointerp(x)) || (sexp_pointer_tag(x) >= sexp_context_num_types(ctx)))
|
||||
return SEXP_ZERO;
|
||||
|
@ -360,40 +233,15 @@ sexp sexp_object_size (sexp ctx, sexp self, sexp_sint_t n, sexp x) {
|
|||
return sexp_make_fixnum(sexp_type_size_of_object(t, x));
|
||||
}
|
||||
|
||||
sexp sexp_immutablep_op (sexp ctx, sexp self, sexp_sint_t n, sexp x) {
|
||||
return sexp_pointerp(x) ? sexp_make_boolean(sexp_immutablep(x)) : SEXP_TRUE;
|
||||
}
|
||||
|
||||
sexp sexp_immutable_string_op (sexp ctx, sexp self, sexp_sint_t n, sexp s) {
|
||||
sexp res;
|
||||
sexp_assert_type(ctx, sexp_stringp, SEXP_STRING, s);
|
||||
#if SEXP_USE_PACKED_STRINGS
|
||||
/* no sharing with packed strings */
|
||||
res = sexp_c_string(ctx, sexp_string_data(s), sexp_string_size(s));
|
||||
#else
|
||||
res = sexp_alloc_type(ctx, string, SEXP_STRING);
|
||||
sexp_string_bytes(res) = sexp_string_bytes(s);
|
||||
sexp_string_offset(res) = sexp_string_offset(s);
|
||||
sexp_string_size(res) = sexp_string_size(s);
|
||||
sexp_copy_on_writep(s) = 1;
|
||||
#endif
|
||||
sexp_immutablep(res) = 1;
|
||||
return res;
|
||||
}
|
||||
|
||||
sexp sexp_integer_to_immediate (sexp ctx, sexp self, sexp_sint_t n, sexp i, sexp dflt) {
|
||||
static sexp sexp_integer_to_immediate (sexp ctx, sexp self, sexp_sint_t n, sexp i, sexp dflt) {
|
||||
sexp x = (sexp)sexp_unbox_fixnum(i);
|
||||
sexp_assert_type(ctx, sexp_fixnump, SEXP_FIXNUM, i);
|
||||
if (!x || sexp_pointerp(x))
|
||||
if (sexp_pointerp(x))
|
||||
return dflt;
|
||||
return x;
|
||||
}
|
||||
|
||||
sexp sexp_object_to_integer (sexp ctx, sexp self, sexp_sint_t n, sexp x) {
|
||||
return sexp_make_integer(ctx, (sexp_uint_t)x);
|
||||
}
|
||||
|
||||
sexp sexp_make_lambda_op (sexp ctx, sexp self, sexp_sint_t n, sexp name, sexp params, sexp body, sexp locals) {
|
||||
static sexp sexp_make_lambda_op (sexp ctx, sexp self, sexp_sint_t n, sexp name, sexp params, sexp body, sexp locals) {
|
||||
sexp res = sexp_alloc_type(ctx, lambda, SEXP_LAMBDA);
|
||||
sexp_lambda_name(res) = name;
|
||||
sexp_lambda_params(res) = params;
|
||||
|
@ -407,7 +255,7 @@ sexp sexp_make_lambda_op (sexp ctx, sexp self, sexp_sint_t n, sexp name, sexp pa
|
|||
return res;
|
||||
}
|
||||
|
||||
sexp sexp_copy_lambda (sexp ctx, sexp self, sexp_sint_t n, sexp lambda) {
|
||||
static sexp sexp_copy_lambda (sexp ctx, sexp self, sexp_sint_t n, sexp lambda) {
|
||||
sexp res = sexp_alloc_type(ctx, lambda, SEXP_LAMBDA);
|
||||
sexp_lambda_name(res) = sexp_lambda_name(lambda);
|
||||
sexp_lambda_params(res) = sexp_lambda_params(lambda);
|
||||
|
@ -421,21 +269,21 @@ sexp sexp_copy_lambda (sexp ctx, sexp self, sexp_sint_t n, sexp lambda) {
|
|||
return res;
|
||||
}
|
||||
|
||||
sexp sexp_make_set_op (sexp ctx, sexp self, sexp_sint_t n, sexp var, sexp value) {
|
||||
static sexp sexp_make_set_op (sexp ctx, sexp self, sexp_sint_t n, sexp var, sexp value) {
|
||||
sexp res = sexp_alloc_type(ctx, set, SEXP_SET);
|
||||
sexp_set_var(res) = var;
|
||||
sexp_set_value(res) = value;
|
||||
return res;
|
||||
}
|
||||
|
||||
sexp sexp_make_ref_op (sexp ctx, sexp self, sexp_sint_t n, sexp name, sexp cell) {
|
||||
static sexp sexp_make_ref_op (sexp ctx, sexp self, sexp_sint_t n, sexp name, sexp cell) {
|
||||
sexp res = sexp_alloc_type(ctx, ref, SEXP_REF);
|
||||
sexp_ref_name(res) = name;
|
||||
sexp_ref_cell(res) = cell;
|
||||
return res;
|
||||
}
|
||||
|
||||
sexp sexp_make_cnd_op (sexp ctx, sexp self, sexp_sint_t n, sexp test, sexp pass, sexp fail) {
|
||||
static sexp sexp_make_cnd_op (sexp ctx, sexp self, sexp_sint_t n, sexp test, sexp pass, sexp fail) {
|
||||
sexp res = sexp_alloc_type(ctx, cnd, SEXP_CND);
|
||||
sexp_cnd_test(res) = test;
|
||||
sexp_cnd_pass(res) = pass;
|
||||
|
@ -443,26 +291,19 @@ sexp sexp_make_cnd_op (sexp ctx, sexp self, sexp_sint_t n, sexp test, sexp pass,
|
|||
return res;
|
||||
}
|
||||
|
||||
sexp sexp_make_seq (sexp ctx, sexp self, sexp_sint_t n, sexp ls) {
|
||||
static sexp sexp_make_seq (sexp ctx, sexp self, sexp_sint_t n, sexp ls) {
|
||||
sexp res = sexp_alloc_type(ctx, seq, SEXP_SEQ);
|
||||
sexp_seq_ls(res) = ls;
|
||||
return res;
|
||||
}
|
||||
|
||||
sexp sexp_make_lit_op (sexp ctx, sexp self, sexp_sint_t n, sexp value) {
|
||||
static sexp sexp_make_lit_op (sexp ctx, sexp self, sexp_sint_t n, sexp value) {
|
||||
sexp res = sexp_alloc_type(ctx, lit, SEXP_LIT);
|
||||
sexp_lit_value(res) = value;
|
||||
return res;
|
||||
}
|
||||
|
||||
sexp sexp_make_macro_op (sexp ctx, sexp self, sexp_sint_t n, sexp proc, sexp env) {
|
||||
sexp res = sexp_alloc_type(ctx, macro, SEXP_MACRO);
|
||||
sexp_macro_proc(res) = proc;
|
||||
sexp_macro_env(res) = env;
|
||||
return res;
|
||||
}
|
||||
|
||||
sexp sexp_analyze_op (sexp ctx, sexp self, sexp_sint_t n, sexp x, sexp e) {
|
||||
static sexp sexp_analyze_op (sexp ctx, sexp self, sexp_sint_t n, sexp x, sexp e) {
|
||||
sexp ctx2 = ctx;
|
||||
if (sexp_envp(e)) {
|
||||
ctx2 = sexp_make_child_context(ctx, NULL);
|
||||
|
@ -471,12 +312,7 @@ sexp sexp_analyze_op (sexp ctx, sexp self, sexp_sint_t n, sexp x, sexp e) {
|
|||
return sexp_analyze(ctx2, x);
|
||||
}
|
||||
|
||||
sexp sexp_extend_env_op (sexp ctx, sexp self, sexp_sint_t n, sexp env, sexp vars, sexp value) {
|
||||
sexp_assert_type(ctx, sexp_envp, SEXP_ENV, env);
|
||||
return sexp_extend_env(ctx, env, vars, value);
|
||||
}
|
||||
|
||||
sexp sexp_optimize (sexp ctx, sexp self, sexp_sint_t n, sexp x) {
|
||||
static sexp sexp_optimize (sexp ctx, sexp self, sexp_sint_t n, sexp x) {
|
||||
sexp_gc_var2(ls, res);
|
||||
sexp_gc_preserve2(ctx, ls, res);
|
||||
res = x;
|
||||
|
@ -488,7 +324,7 @@ sexp sexp_optimize (sexp ctx, sexp self, sexp_sint_t n, sexp x) {
|
|||
return res;
|
||||
}
|
||||
|
||||
sexp sexp_gc_op (sexp ctx, sexp self, sexp_sint_t n) {
|
||||
static sexp sexp_gc_op (sexp ctx, sexp self, sexp_sint_t n) {
|
||||
size_t sum_freed=0;
|
||||
#if SEXP_USE_BOEHM
|
||||
GC_gcollect();
|
||||
|
@ -498,95 +334,23 @@ sexp sexp_gc_op (sexp ctx, sexp self, sexp_sint_t n) {
|
|||
return sexp_make_unsigned_integer(ctx, sum_freed);
|
||||
}
|
||||
|
||||
sexp sexp_gc_count_op (sexp ctx, sexp self, sexp_sint_t n) {
|
||||
return sexp_make_unsigned_integer(ctx, sexp_context_gc_count(ctx));
|
||||
}
|
||||
|
||||
sexp sexp_gc_usecs_op (sexp ctx, sexp self, sexp_sint_t n) {
|
||||
return sexp_make_unsigned_integer(ctx, sexp_context_gc_usecs(ctx));
|
||||
}
|
||||
|
||||
#if SEXP_USE_GREEN_THREADS
|
||||
sexp sexp_set_atomic (sexp ctx, sexp self, sexp_sint_t n, sexp new_val) {
|
||||
#ifdef SEXP_USE_GREEN_THREADS
|
||||
static sexp sexp_set_atomic (sexp ctx, sexp self, sexp_sint_t n, sexp new) {
|
||||
sexp res = sexp_global(ctx, SEXP_G_ATOMIC_P);
|
||||
sexp_global(ctx, SEXP_G_ATOMIC_P) = new_val;
|
||||
sexp_global(ctx, SEXP_G_ATOMIC_P) = new;
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
sexp sexp_thread_interrupt (sexp ctx, sexp self, sexp_sint_t n, sexp thread) {
|
||||
sexp_assert_type(ctx, sexp_contextp, SEXP_CONTEXT, thread);
|
||||
sexp_context_interruptp(thread) = 1;
|
||||
return sexp_make_boolean(ctx == thread);
|
||||
}
|
||||
|
||||
sexp sexp_thread_list (sexp ctx, sexp self, sexp_sint_t n) {
|
||||
sexp_gc_var1(res);
|
||||
sexp_gc_preserve1(ctx, res);
|
||||
res = SEXP_NULL;
|
||||
#if SEXP_USE_GREEN_THREADS
|
||||
sexp ls;
|
||||
for (ls=sexp_global(ctx, SEXP_G_THREADS_FRONT); sexp_pairp(ls); ls=sexp_cdr(ls))
|
||||
sexp_push(ctx, res, sexp_car(ls));
|
||||
for (ls=sexp_global(ctx, SEXP_G_THREADS_PAUSED); sexp_pairp(ls); ls=sexp_cdr(ls))
|
||||
sexp_push(ctx, res, sexp_car(ls));
|
||||
#endif
|
||||
if (sexp_not(sexp_memq(ctx, ctx, res))) sexp_push(ctx, res, ctx);
|
||||
sexp_gc_release1(ctx);
|
||||
return res;
|
||||
}
|
||||
|
||||
sexp sexp_string_contains (sexp ctx, sexp self, sexp_sint_t n, sexp x, sexp y, sexp start) {
|
||||
static sexp sexp_string_contains (sexp ctx, sexp self, sexp_sint_t n, sexp x, sexp y) {
|
||||
const char *res;
|
||||
sexp_assert_type(ctx, sexp_stringp, SEXP_STRING, x);
|
||||
sexp_assert_type(ctx, sexp_stringp, SEXP_STRING, y);
|
||||
sexp_assert_type(ctx, sexp_string_cursorp, SEXP_STRING_CURSOR, start);
|
||||
if (sexp_unbox_string_cursor(start) > sexp_string_size(x))
|
||||
return sexp_user_exception(ctx, self, "string-contains: start out of range", start);
|
||||
res = strstr(sexp_string_data(x) + sexp_unbox_string_cursor(start), sexp_string_data(y));
|
||||
return res ? sexp_make_string_cursor(res-sexp_string_data(x)) : SEXP_FALSE;
|
||||
res = strstr(sexp_string_data(x), sexp_string_data(y));
|
||||
return res ? sexp_make_fixnum(res-sexp_string_data(x)) : SEXP_FALSE;
|
||||
}
|
||||
|
||||
sexp sexp_string_cursor_copy (sexp ctx, sexp self, sexp_sint_t n, sexp dst, sexp sfrom, sexp src, sexp sstart, sexp send) {
|
||||
unsigned char *pfrom, *pto, *pstart, *pend, *prev, *p;
|
||||
sexp_sint_t from = sexp_unbox_fixnum(sfrom), to = sexp_string_size(dst),
|
||||
start = sexp_unbox_fixnum(sstart), end = sexp_unbox_fixnum(send);
|
||||
sexp_assert_type(ctx, sexp_stringp, SEXP_STRING, dst);
|
||||
sexp_assert_type(ctx, sexp_stringp, SEXP_STRING, src);
|
||||
sexp_assert_type(ctx, sexp_fixnump, SEXP_FIXNUM, sfrom);
|
||||
sexp_assert_type(ctx, sexp_fixnump, SEXP_FIXNUM, sstart);
|
||||
sexp_assert_type(ctx, sexp_fixnump, SEXP_FIXNUM, send);
|
||||
if (from < 0 || from > to)
|
||||
return sexp_user_exception(ctx, self, "string-cursor-copy!: from out of range", sfrom);
|
||||
if (start < 0 || start > (sexp_sint_t)sexp_string_size(src))
|
||||
return sexp_user_exception(ctx, self, "string-cursor-copy!: start out of range", sstart);
|
||||
if (end < start || end > (sexp_sint_t)sexp_string_size(src))
|
||||
return sexp_user_exception(ctx, self, "string-cursor-copy!: end out of range", send);
|
||||
pfrom = (unsigned char*)sexp_string_data(dst) + from;
|
||||
pto = (unsigned char*)sexp_string_data(dst) + to;
|
||||
pstart = (unsigned char*)sexp_string_data(src) + start;
|
||||
pend = (unsigned char*)sexp_string_data(src) + end;
|
||||
for ( ; pfrom < pto && pstart < pend; ++pfrom, ++pstart)
|
||||
*pfrom = *pstart;
|
||||
/* adjust for incomplete trailing chars */
|
||||
prev = (unsigned char*)sexp_string_utf8_prev(pfrom);
|
||||
if (sexp_utf8_initial_byte_count(*prev) > pfrom - prev) {
|
||||
for (p = prev; p < pfrom; ++p)
|
||||
*p = '\0';
|
||||
pstart -= pfrom - prev;
|
||||
}
|
||||
return sexp_make_fixnum(pstart - (unsigned char*)sexp_string_data(src));
|
||||
}
|
||||
|
||||
sexp sexp_errno (sexp ctx, sexp self, sexp_sint_t n) {
|
||||
#ifdef PLAN9
|
||||
return SEXP_FALSE;
|
||||
#else
|
||||
return sexp_make_fixnum(errno);
|
||||
#endif
|
||||
}
|
||||
|
||||
sexp sexp_error_string (sexp ctx, sexp self, sexp_sint_t n, sexp x) {
|
||||
static sexp sexp_error_string (sexp ctx, sexp self, sexp_sint_t n, sexp x) {
|
||||
#ifdef PLAN9
|
||||
return SEXP_FALSE;
|
||||
#else
|
||||
|
@ -601,46 +365,22 @@ sexp sexp_error_string (sexp ctx, sexp self, sexp_sint_t n, sexp x) {
|
|||
#endif
|
||||
}
|
||||
|
||||
sexp sexp_update_free_vars (sexp ctx, sexp self, sexp_sint_t n, sexp x) {
|
||||
static sexp sexp_update_free_vars (sexp ctx, sexp self, sexp_sint_t n, sexp x) {
|
||||
return sexp_free_vars(ctx, x, SEXP_NULL);
|
||||
}
|
||||
|
||||
sexp sexp_setenv (sexp ctx, sexp self, sexp_sint_t n, sexp name, sexp value) {
|
||||
sexp_assert_type(ctx, sexp_stringp, SEXP_STRING, name);
|
||||
sexp_assert_type(ctx, sexp_stringp, SEXP_STRING, value);
|
||||
return sexp_make_boolean(setenv(sexp_string_data(name), sexp_string_data(value), 1));
|
||||
}
|
||||
|
||||
sexp sexp_unsetenv (sexp ctx, sexp self, sexp_sint_t n, sexp name) {
|
||||
sexp_assert_type(ctx, sexp_stringp, SEXP_STRING, name);
|
||||
return sexp_make_boolean(unsetenv(sexp_string_data(name)));
|
||||
}
|
||||
|
||||
sexp sexp_abort (sexp ctx, sexp self, sexp_sint_t n, sexp value) {
|
||||
sexp res = sexp_make_trampoline(ctx, SEXP_FALSE, value);
|
||||
sexp_exception_message(res) = SEXP_TRAMPOLINE;
|
||||
return res;
|
||||
}
|
||||
|
||||
#define sexp_define_type(ctx, name, tag) \
|
||||
sexp_env_define(ctx, env, sexp_intern(ctx, name, -1), sexp_type_by_index(ctx, tag));
|
||||
|
||||
sexp sexp_init_library (sexp ctx, sexp self, sexp_sint_t n, sexp env, const char* version, const sexp_abi_identifier_t abi) {
|
||||
sexp_gc_var2(sym, str);
|
||||
sexp sexp_init_library (sexp ctx, sexp self, sexp_sint_t n, sexp env, const char* version, sexp_abi_identifier_t abi) {
|
||||
if (!(sexp_version_compatible(ctx, version, sexp_version)
|
||||
&& sexp_abi_compatible(ctx, abi, SEXP_ABI_IDENTIFIER)))
|
||||
return SEXP_ABI_ERROR;
|
||||
return sexp_global(ctx, SEXP_G_ABI_ERROR);
|
||||
sexp_define_type(ctx, "Object", SEXP_OBJECT);
|
||||
sexp_define_type(ctx, "Number", SEXP_NUMBER);
|
||||
sexp_define_type(ctx, "Bignum", SEXP_BIGNUM);
|
||||
sexp_define_type(ctx, "Flonum", SEXP_FLONUM);
|
||||
sexp_define_type(ctx, "Integer", SEXP_FIXNUM);
|
||||
#if SEXP_USE_RATIOS
|
||||
sexp_define_type(ctx, "Ratio", SEXP_RATIO);
|
||||
#endif
|
||||
#if SEXP_USE_COMPLEX
|
||||
sexp_define_type(ctx, "Complex", SEXP_COMPLEX);
|
||||
#endif
|
||||
sexp_define_type(ctx, "Symbol", SEXP_SYMBOL);
|
||||
sexp_define_type(ctx, "Char", SEXP_CHAR);
|
||||
sexp_define_type(ctx, "Boolean", SEXP_BOOLEAN);
|
||||
|
@ -650,7 +390,6 @@ sexp sexp_init_library (sexp ctx, sexp self, sexp_sint_t n, sexp env, const char
|
|||
sexp_define_type(ctx, "Vector", SEXP_VECTOR);
|
||||
sexp_define_type(ctx, "Input-Port", SEXP_IPORT);
|
||||
sexp_define_type(ctx, "Output-Port", SEXP_OPORT);
|
||||
sexp_define_type(ctx, "File-Descriptor", SEXP_FILENO);
|
||||
sexp_define_type(ctx, "Opcode", SEXP_OPCODE);
|
||||
sexp_define_type(ctx, "Procedure", SEXP_PROCEDURE);
|
||||
sexp_define_type(ctx, "Bytecode", SEXP_BYTECODE);
|
||||
|
@ -659,14 +398,12 @@ sexp sexp_init_library (sexp ctx, sexp self, sexp_sint_t n, sexp env, const char
|
|||
sexp_define_type(ctx, "Lam", SEXP_LAMBDA);
|
||||
sexp_define_type(ctx, "Cnd", SEXP_CND);
|
||||
sexp_define_type(ctx, "Set", SEXP_SET);
|
||||
sexp_define_type(ctx, "Set-Syn", SEXP_SET_SYN);
|
||||
sexp_define_type(ctx, "Ref", SEXP_REF);
|
||||
sexp_define_type(ctx, "Seq", SEXP_SEQ);
|
||||
sexp_define_type(ctx, "Lit", SEXP_LIT);
|
||||
sexp_define_type(ctx, "Sc", SEXP_SYNCLO);
|
||||
sexp_define_type(ctx, "Context", SEXP_CONTEXT);
|
||||
sexp_define_type(ctx, "Exception", SEXP_EXCEPTION);
|
||||
sexp_define_type(ctx, "Core", SEXP_CORE);
|
||||
sexp_define_type_predicate(ctx, env, "environment?", SEXP_ENV);
|
||||
sexp_define_type_predicate(ctx, env, "bytecode?", SEXP_BYTECODE);
|
||||
sexp_define_type_predicate(ctx, env, "macro?", SEXP_MACRO);
|
||||
|
@ -677,10 +414,10 @@ sexp sexp_init_library (sexp ctx, sexp self, sexp_sint_t n, sexp env, const char
|
|||
sexp_define_type_predicate(ctx, env, "ref?", SEXP_REF);
|
||||
sexp_define_type_predicate(ctx, env, "seq?", SEXP_SEQ);
|
||||
sexp_define_type_predicate(ctx, env, "lit?", SEXP_LIT);
|
||||
sexp_define_type_predicate(ctx, env, "opcode?", SEXP_OPCODE);
|
||||
sexp_define_type_predicate(ctx, env, "type?", SEXP_TYPE);
|
||||
sexp_define_type_predicate(ctx, env, "core?", SEXP_CORE);
|
||||
sexp_define_type_predicate(ctx, env, "context?", SEXP_CONTEXT);
|
||||
sexp_define_type_predicate(ctx, env, "file-descriptor?", SEXP_FILENO);
|
||||
sexp_define_type_predicate(ctx, env, "exception?", SEXP_EXCEPTION);
|
||||
sexp_define_accessors(ctx, env, SEXP_SYNCLO, 0, "syntactic-closure-env", NULL);
|
||||
sexp_define_accessors(ctx, env, SEXP_SYNCLO, 1, "syntactic-closure-vars", NULL);
|
||||
sexp_define_accessors(ctx, env, SEXP_SYNCLO, 2, "syntactic-closure-expr", NULL);
|
||||
|
@ -700,28 +437,21 @@ sexp sexp_init_library (sexp ctx, sexp self, sexp_sint_t n, sexp env, const char
|
|||
sexp_define_accessors(ctx, env, SEXP_CND, 2, "cnd-fail", "cnd-fail-set!");
|
||||
sexp_define_accessors(ctx, env, SEXP_SET, 0, "set-var", "set-var-set!");
|
||||
sexp_define_accessors(ctx, env, SEXP_SET, 1, "set-value", "set-value-set!");
|
||||
sexp_define_accessors(ctx, env, SEXP_SET, 2, "set-source", "set-source-set!");
|
||||
sexp_define_accessors(ctx, env, SEXP_REF, 0, "ref-name", "ref-name-set!");
|
||||
sexp_define_accessors(ctx, env, SEXP_REF, 1, "ref-cell", "ref-cell-set!");
|
||||
sexp_define_accessors(ctx, env, SEXP_SEQ, 0, "seq-ls", "seq-ls-set!");
|
||||
sexp_define_accessors(ctx, env, SEXP_LIT, 0, "lit-value", "lit-value-set!");
|
||||
sexp_define_accessors(ctx, env, SEXP_BYTECODE, 0, "bytecode-name", "bytecode-name-set!");
|
||||
sexp_define_accessors(ctx, env, SEXP_BYTECODE, 1, "bytecode-literals", NULL);
|
||||
sexp_define_accessors(ctx, env, SEXP_BYTECODE, 2, "bytecode-source", NULL);
|
||||
sexp_define_accessors(ctx, env, SEXP_BYTECODE, 1, "bytecode-name", "bytecode-name-set!");
|
||||
sexp_define_accessors(ctx, env, SEXP_BYTECODE, 2, "bytecode-literals", NULL);
|
||||
sexp_define_accessors(ctx, env, SEXP_BYTECODE, 3, "bytecode-source", NULL);
|
||||
sexp_define_accessors(ctx, env, SEXP_EXCEPTION, 0, "exception-kind", NULL);
|
||||
sexp_define_accessors(ctx, env, SEXP_EXCEPTION, 1, "exception-message", NULL);
|
||||
sexp_define_accessors(ctx, env, SEXP_EXCEPTION, 4, "exception-source", NULL);
|
||||
sexp_define_accessors(ctx, env, SEXP_EXCEPTION, 2, "exception-irritants", NULL);
|
||||
sexp_define_accessors(ctx, env, SEXP_MACRO, 0, "macro-procedure", NULL);
|
||||
sexp_define_accessors(ctx, env, SEXP_MACRO, 1, "macro-env", NULL);
|
||||
sexp_define_accessors(ctx, env, SEXP_MACRO, 2, "macro-source", NULL);
|
||||
sexp_define_accessors(ctx, env, SEXP_MACRO, 3, "macro-aux", "macro-aux-set!");
|
||||
sexp_define_foreign(ctx, env, "make-procedure", 4, sexp_make_procedure_op);
|
||||
sexp_define_foreign(ctx, env, "procedure-code", 1, sexp_get_procedure_code);
|
||||
sexp_define_foreign(ctx, env, "procedure-vars", 1, sexp_get_procedure_vars);
|
||||
sexp_define_foreign(ctx, env, "procedure-arity", 1, sexp_get_procedure_arity);
|
||||
sexp_define_foreign(ctx, env, "procedure-variadic?", 1, sexp_get_procedure_variadic_p);
|
||||
sexp_define_foreign(ctx, env, "procedure-variable-transformer?", 1, sexp_get_procedure_variable_transformer_p);
|
||||
sexp_define_foreign(ctx, env, "procedure-flags", 1, sexp_get_procedure_flags);
|
||||
sexp_define_foreign(ctx, env, "make-variable-transformer", 1, sexp_make_variable_transformer_op);
|
||||
sexp_define_foreign(ctx, env, "copy-lambda", 1, sexp_copy_lambda);
|
||||
sexp_define_foreign_opt(ctx, env, "make-lambda", 4, sexp_make_lambda_op, SEXP_NULL);
|
||||
sexp_define_foreign_opt(ctx, env, "make-cnd", 3, sexp_make_cnd_op, SEXP_VOID);
|
||||
|
@ -729,11 +459,10 @@ sexp sexp_init_library (sexp ctx, sexp self, sexp_sint_t n, sexp env, const char
|
|||
sexp_define_foreign(ctx, env, "make-set", 2, sexp_make_set_op);
|
||||
sexp_define_foreign(ctx, env, "make-lit", 1, sexp_make_lit_op);
|
||||
sexp_define_foreign(ctx, env, "make-seq", 1, sexp_make_seq);
|
||||
sexp_define_foreign(ctx, env, "make-macro", 2, sexp_make_macro_op);
|
||||
sexp_define_foreign_opt(ctx, env, "analyze", 2, sexp_analyze_op, SEXP_FALSE);
|
||||
sexp_define_foreign(ctx, env, "optimize", 1, sexp_optimize);
|
||||
sexp_define_foreign(ctx, env, "extend-env", 3, sexp_extend_env_op);
|
||||
sexp_define_foreign_opt(ctx, env, "env-cell", 3, sexp_get_env_cell, SEXP_FALSE);
|
||||
sexp_define_foreign(ctx, env, "extend-env", 2, sexp_extend_env);
|
||||
sexp_define_foreign(ctx, env, "env-cell", 2, sexp_get_env_cell);
|
||||
sexp_define_foreign(ctx, env, "opcode-name", 1, sexp_get_opcode_name);
|
||||
sexp_define_foreign(ctx, env, "opcode-class", 1, sexp_get_opcode_class);
|
||||
sexp_define_foreign(ctx, env, "opcode-code", 1, sexp_get_opcode_code);
|
||||
|
@ -744,49 +473,21 @@ sexp sexp_init_library (sexp ctx, sexp self, sexp_sint_t n, sexp env, const char
|
|||
sexp_define_foreign(ctx, env, "opcode-param-type", 2, sexp_get_opcode_param_type);
|
||||
sexp_define_foreign(ctx, env, "port-line", 1, sexp_get_port_line);
|
||||
sexp_define_foreign(ctx, env, "port-line-set!", 2, sexp_set_port_line);
|
||||
sexp_define_foreign(ctx, env, "port-source?", 1, sexp_get_port_sourcep);
|
||||
sexp_define_foreign(ctx, env, "port-source?-set!", 2, sexp_set_port_sourcep);
|
||||
sexp_define_foreign(ctx, env, "type-of", 1, sexp_type_of);
|
||||
sexp_define_foreign(ctx, env, "type-name", 1, sexp_type_name_op);
|
||||
sexp_define_foreign(ctx, env, "type-cpl", 1, sexp_type_cpl_op);
|
||||
sexp_define_foreign(ctx, env, "type-slots", 1, sexp_type_slots_op);
|
||||
sexp_define_foreign(ctx, env, "type-num-slots", 1, sexp_type_num_slots_op);
|
||||
sexp_define_foreign(ctx, env, "type-printer", 1, sexp_type_printer_op);
|
||||
sexp_define_foreign(ctx, env, "type-printer-set!", 2, sexp_type_printer_set_op);
|
||||
sexp_define_foreign(ctx, env, "env-parent-set!", 2, sexp_env_parent_set_op);
|
||||
sexp_define_foreign(ctx, env, "env-lambda", 1, sexp_env_lambda_op);
|
||||
sexp_define_foreign(ctx, env, "env-lambda-set!", 2, sexp_env_lambda_set_op);
|
||||
sexp_define_foreign(ctx, env, "env-syntactic?", 1, sexp_env_syntactic_op);
|
||||
sexp_define_foreign(ctx, env, "env-syntactic?-set!", 2, sexp_env_syntactic_set_op);
|
||||
sexp_define_foreign(ctx, env, "env-define!", 3, sexp_env_define_op);
|
||||
sexp_define_foreign(ctx, env, "env-push!", 3, sexp_env_push_op);
|
||||
sexp_define_foreign(ctx, env, "core-code", 1, sexp_core_code_op);
|
||||
sexp_define_foreign(ctx, env, "environment-parent", 1, sexp_env_parent_op);
|
||||
sexp_define_foreign(ctx, env, "object-size", 1, sexp_object_size);
|
||||
sexp_define_foreign(ctx, env, "immutable?", 1, sexp_immutablep_op);
|
||||
sexp_define_foreign(ctx, env, "immutable-string", 1, sexp_immutable_string_op);
|
||||
sexp_define_foreign_opt(ctx, env, "integer->immediate", 2, sexp_integer_to_immediate, SEXP_FALSE);
|
||||
sexp_define_foreign_opt(ctx, env, "object->integer", 1, sexp_object_to_integer, SEXP_FALSE);
|
||||
sexp_define_foreign(ctx, env, "gc", 0, sexp_gc_op);
|
||||
sexp_define_foreign(ctx, env, "gc-count", 0, sexp_gc_count_op);
|
||||
sexp_define_foreign(ctx, env, "gc-usecs", 0, sexp_gc_usecs_op);
|
||||
#if SEXP_USE_GREEN_THREADS
|
||||
#ifdef SEXP_USE_GREEN_THREADS
|
||||
sexp_define_foreign(ctx, env, "%set-atomic!", 1, sexp_set_atomic);
|
||||
#endif
|
||||
sexp_define_foreign(ctx, env, "%thread-interrupt!", 1, sexp_thread_interrupt);
|
||||
sexp_define_foreign(ctx, env, "thread-list", 0, sexp_thread_list);
|
||||
sexp_define_foreign_opt(ctx, env, "string-contains", 3, sexp_string_contains, sexp_make_string_cursor(0));
|
||||
sexp_define_foreign(ctx, env, "string-cursor-copy!", 5, sexp_string_cursor_copy);
|
||||
sexp_define_foreign(ctx, env, "errno", 0, sexp_errno);
|
||||
sexp_define_foreign(ctx, env, "string-contains", 2, sexp_string_contains);
|
||||
sexp_define_foreign_opt(ctx, env, "integer->error-string", 1, sexp_error_string, SEXP_FALSE);
|
||||
sexp_define_foreign(ctx, env, "update-free-vars!", 1, sexp_update_free_vars);
|
||||
sexp_define_foreign(ctx, env, "setenv", 2, sexp_setenv);
|
||||
sexp_define_foreign(ctx, env, "unsetenv", 1, sexp_unsetenv);
|
||||
sexp_define_foreign(ctx, env, "abort", 1, sexp_abort);
|
||||
sexp_gc_preserve2(ctx, sym, str);
|
||||
sym = sexp_intern(ctx, "chibi-version", -1);
|
||||
str = sexp_c_string(ctx, sexp_version, -1);
|
||||
sexp_immutablep(str) = 1;
|
||||
sexp_env_define(ctx, env, sym, str);
|
||||
sexp_gc_release2(ctx);
|
||||
return SEXP_VOID;
|
||||
}
|
||||
|
|
|
@ -6,16 +6,16 @@
|
|||
;;> the compiler, and other core types less commonly
|
||||
;;> needed in user code, plus related utilities.
|
||||
|
||||
;;> \section{Analysis and Expansion}
|
||||
;;> @subsubsection{Analysis and Expansion}
|
||||
|
||||
;;> \procedure{(analyze x [env])}
|
||||
;;> @subsubsubsection{@scheme{(analyze x [env])}}
|
||||
|
||||
;;> Expands and analyzes the expression \var{x} and returns the
|
||||
;;> Expands and analyzes the expression @var{x} and returns the
|
||||
;;> resulting AST.
|
||||
|
||||
;;> \procedure{(optimize ast)}
|
||||
;;> @subsubsubsection{@scheme{(optimize ast)}}
|
||||
|
||||
;;> Runs an optimization pass on \var{ast} and returns the
|
||||
;;> Runs an optimization pass on @var{ast} and returns the
|
||||
;;> resulting simplified expression.
|
||||
|
||||
(define (ast-renames ast)
|
||||
|
@ -78,13 +78,13 @@
|
|||
((null? ls) '())
|
||||
(else (f ls))))
|
||||
|
||||
;;> Performs a full syntax expansion of the form \var{x} and
|
||||
;;> Performs a full syntax expansion of the form @var{x} and
|
||||
;;> returns the resulting s-expression.
|
||||
|
||||
(define (macroexpand x)
|
||||
(ast->sexp (analyze x)))
|
||||
|
||||
;;> Convert \var{ast} to a s-expression, renaming variables if
|
||||
;;> Convert @var{ast} to a s-expression, renaming variables if
|
||||
;;> necessary.
|
||||
|
||||
(define (ast->sexp ast)
|
||||
|
@ -109,106 +109,78 @@
|
|||
((opcode? x) (cond ((opcode-name x) => string->symbol) (else x)))
|
||||
(else x)))))
|
||||
|
||||
;;> \section{Identifier Macros}
|
||||
|
||||
;;> \procedure{(make-variable-transformer proc)}
|
||||
|
||||
;;> Returns a new procedure wrapping the input procedure \var{proc}.
|
||||
;;> The returned procedure, if used as a macro transformer procedure,
|
||||
;;> can expand an instance of \scheme{set!} with its keyword on the
|
||||
;;> left hand side.
|
||||
|
||||
;;> \macro{(identifier-syntax clauses ...)}
|
||||
|
||||
;;> A high-level form for creating identifier macros. See
|
||||
;;> \hyperlink["http://www.r6rs.org/final/html/r6rs/r6rs-Z-H-14.html#node_idx_796"]{the R6RS specification.}
|
||||
|
||||
(define-syntax identifier-syntax
|
||||
(syntax-rules (set!)
|
||||
((_ template)
|
||||
(syntax-rules ()
|
||||
((_ xs (... ...))
|
||||
(template xs (... ...)))
|
||||
(x template)))
|
||||
((_ (id_1 template_1) ((set! id_2 pattern) template_2))
|
||||
(make-variable-transformer
|
||||
(syntax-rules (set!)
|
||||
((set! id_2 pattern) template_2)
|
||||
((id_1 xs (... ...)) (template_1 xs (... ...)))
|
||||
(id_1 template_1))))))
|
||||
|
||||
;;> \section{Types}
|
||||
;;> @subsubsection{Types}
|
||||
|
||||
;;> All objects have an associated type, and types may have parent
|
||||
;;> types. When using
|
||||
;;> \hyperlink["http://srfi.schemers.org/srfi-9/srfi-9/html"]{SRFI-9}
|
||||
;;> \scheme{define-record-type}, the name is bound to a first class
|
||||
;;> @hyperlink["http://srfi.schemers.org/srfi-9/srfi-9/html"]{SRFI-9}
|
||||
;;> @scheme{define-record-type}, the name is bound to a first class
|
||||
;;> type object.
|
||||
|
||||
;;> The following core types are also available by name, and may be
|
||||
;;> used in the \scheme{match} \scheme{($ ...)} syntax.
|
||||
;;> used in the @scheme{match} @scheme{($ ...)} syntax.
|
||||
|
||||
;;> \itemlist[
|
||||
;;> \item{\scheme{Object} - the parent of all types}
|
||||
;;> \item{\scheme{Number} - abstract numeric type}
|
||||
;;> \item{\scheme{Bignum} - arbitrary precision exact integers}
|
||||
;;> \item{\scheme{Flonum} - inexact real numbers}
|
||||
;;> \item{\scheme{Integer} - abstract integer type}
|
||||
;;> \item{\scheme{Symbol} - symbols}
|
||||
;;> \item{\scheme{Char} - character}
|
||||
;;> \item{\scheme{Boolean} - \scheme{#t} or \scheme{#f}}
|
||||
;;> \item{\scheme{String} - strings of characters}
|
||||
;;> \item{\scheme{Byte-Vector} - uniform vector of octets}
|
||||
;;> \item{\scheme{Pair} - a \var{car} and \var{cdr}, the basis for lists}
|
||||
;;> \item{\scheme{Vector} - vectors}
|
||||
;;> \item{\scheme{Opcode} - a primitive opcode or C function}
|
||||
;;> \item{\scheme{Procedure} - a closure}
|
||||
;;> \item{\scheme{Bytecode} - the compiled code for a closure}
|
||||
;;> \item{\scheme{Env} - an environment structure}
|
||||
;;> \item{\scheme{Macro} - a macro object, usually not first-class}
|
||||
;;> \item{\scheme{Lam} - a lambda AST type}
|
||||
;;> \item{\scheme{Cnd} - an conditional AST type (i.e. \scheme{if})}
|
||||
;;> \item{\scheme{Ref} - a reference AST type}
|
||||
;;> \item{\scheme{Set} - a mutation AST type (i.e. \scheme{set!})}
|
||||
;;> \item{\scheme{Seq} - a sequence AST type}
|
||||
;;> \item{\scheme{Lit} - a literal AST type}
|
||||
;;> \item{\scheme{Sc} - a syntactic closure}
|
||||
;;> \item{\scheme{Context} - a context object (including threads)}
|
||||
;;> \item{\scheme{Exception} - an exception object}
|
||||
;;> @itemlist[
|
||||
;;> @item{@scheme{<object>} - the parent of all types}
|
||||
;;> @item{@scheme{<number>} - abstract numeric type}
|
||||
;;> @item{@scheme{<bignum>} - arbitrary precision exact integers}
|
||||
;;> @item{@scheme{<flonum>} - inexact real numbers}
|
||||
;;> @item{@scheme{<integer>} - abstract integer type}
|
||||
;;> @item{@scheme{<symbol>} - symbols}
|
||||
;;> @item{@scheme{<char>} - character}
|
||||
;;> @item{@scheme{<boolean>} - @scheme{#t} or @scheme{#f}}
|
||||
;;> @item{@scheme{<string>} - strings of characters}
|
||||
;;> @item{@scheme{<byte-vector>} - uniform vector of octets}
|
||||
;;> @item{@scheme{<pair>} - a @var{car} and @var{cdr}, the basis for lists}
|
||||
;;> @item{@scheme{<vector>} - vectors}
|
||||
;;> @item{@scheme{<opcode>} - a primitive opcode or C function}
|
||||
;;> @item{@scheme{<procedure>} - a closure}
|
||||
;;> @item{@scheme{<bytecode>} - the compiled code for a closure}
|
||||
;;> @item{@scheme{<env>} - an environment structure}
|
||||
;;> @item{@scheme{<macro>} - a macro object, usually not first-class}
|
||||
;;> @item{@scheme{<lam>} - a lambda AST type}
|
||||
;;> @item{@scheme{<cnd>} - an conditional AST type (i.e. @scheme{if})}
|
||||
;;> @item{@scheme{<ref>} - a reference AST type}
|
||||
;;> @item{@scheme{<set>} - a mutation AST type (i.e. @scheme{set!})}
|
||||
;;> @item{@scheme{<seq>} - a sequence AST type}
|
||||
;;> @item{@scheme{<lit>} - a literal AST type}
|
||||
;;> @item{@scheme{<sc>} - a syntactic closure}
|
||||
;;> @item{@scheme{<context>} - a context object (including threads)}
|
||||
;;> @item{@scheme{<exception>} - an exception object}
|
||||
;;> ]
|
||||
|
||||
;;> The following extended type predicates may also be used to test
|
||||
;;> individual objects for their type:
|
||||
|
||||
;;> \itemlist[
|
||||
;;> \item{\scheme{environment?}}
|
||||
;;> \item{\scheme{bytecode?}}
|
||||
;;> \item{\scheme{macro?}}
|
||||
;;> \item{\scheme{syntactic-closure?}}
|
||||
;;> \item{\scheme{lambda?}}
|
||||
;;> \item{\scheme{cnd?}}
|
||||
;;> \item{\scheme{ref?}}
|
||||
;;> \item{\scheme{set?}}
|
||||
;;> \item{\scheme{seq?}}
|
||||
;;> \item{\scheme{lit?}}
|
||||
;;> \item{\scheme{opcode?}}
|
||||
;;> \item{\scheme{type?}}
|
||||
;;> \item{\scheme{context?}}
|
||||
;;> \item{\scheme{exception?}}
|
||||
;;> @itemlist[
|
||||
;;> @item{@scheme{environment?}}
|
||||
;;> @item{@scheme{bytecode?}}
|
||||
;;> @item{@scheme{macro?}}
|
||||
;;> @item{@scheme{syntactic-closure?}}
|
||||
;;> @item{@scheme{lambda?}}
|
||||
;;> @item{@scheme{cnd?}}
|
||||
;;> @item{@scheme{ref?}}
|
||||
;;> @item{@scheme{set?}}
|
||||
;;> @item{@scheme{seq?}}
|
||||
;;> @item{@scheme{lit?}}
|
||||
;;> @item{@scheme{opcode?}}
|
||||
;;> @item{@scheme{type?}}
|
||||
;;> @item{@scheme{context?}}
|
||||
;;> @item{@scheme{exception?}}
|
||||
;;> ]
|
||||
|
||||
;;> \procedure{(type-of x)}
|
||||
;;> @subsubsubsection{@scheme{(type-of x)}}
|
||||
|
||||
;;> Returns the type of any object \var{x}.
|
||||
;;> Returns the type of any object @var{x}.
|
||||
|
||||
;;> \procedure{(type-name type)}
|
||||
;;> @subsubsubsection{@scheme{(type-name type)}}
|
||||
|
||||
;;> Returns the name of type \var{type}.
|
||||
;;> Returns the name of type @var{type}.
|
||||
|
||||
;;> \procedure{(type-parent type)}
|
||||
;;> @subsubsubsection{@scheme{(type-parent type)}}
|
||||
|
||||
;;> Returns the immediate parent of type \var{type},
|
||||
;;> or \scheme{#f} for a type with no parent.
|
||||
;;> Returns the immediate parent of type @var{type},
|
||||
;;> or @scheme{#f} for a type with no parent.
|
||||
|
||||
(define (type-parent type)
|
||||
(let ((v (type-cpl type)))
|
||||
|
@ -216,26 +188,26 @@
|
|||
(> (vector-length v) 1)
|
||||
(vector-ref v (- (vector-length v) 2)))))
|
||||
|
||||
;;> \procedure{(type-cpl type)}
|
||||
;;> @subsubsubsection{@scheme{(type-cpl type)}}
|
||||
|
||||
;;> Returns the class precedence list of type \var{type} as a
|
||||
;;> vector, or \scheme{#f} for a type with no parent.
|
||||
;;> Returns the class precedence list of type @var{type} as a
|
||||
;;> vector, or @scheme{#f} for a type with no parent.
|
||||
|
||||
;;> \procedure{(type-slots type)}
|
||||
;;> @subsubsubsection{@scheme{(type-slots type)}}
|
||||
|
||||
;;> Returns the slot list of type \var{type}.
|
||||
;;> Returns the slot list of type @var{type}.
|
||||
|
||||
;;> \section{Accessors}
|
||||
;;> @subsubsection{Accessors}
|
||||
|
||||
;;> This section describes additional accessors on AST and other core
|
||||
;;> types.
|
||||
|
||||
;;> \subsection{Procedures}
|
||||
;;> @subsubsubsection{Procedures}
|
||||
|
||||
;;> \itemlist[
|
||||
;;> \item{\scheme{(procedure-code f)} - the compiled bytecode object}
|
||||
;;> \item{\scheme{(procedure-vars f)} - the variables closed over by \var{f}}
|
||||
;;> \item{\scheme{(procedure-name f)} - the name of \var{f} if known, else \scheme{#f}}
|
||||
;;> @itemlist[
|
||||
;;> @item{@scheme{(procedure-code f)} - the compiled bytecode object}
|
||||
;;> @item{@scheme{(procedure-vars f)} - the variables closed over by @var{f}}
|
||||
;;> @item{@scheme{(procedure-name f)} - the name of @var{f} if known, else @scheme{#f}}
|
||||
;;> ]
|
||||
|
||||
(define (procedure-name x)
|
||||
|
@ -244,182 +216,149 @@
|
|||
(define (procedure-name-set! x name)
|
||||
(bytecode-name-set! (procedure-code x) name))
|
||||
|
||||
;;> \subsection{Macros}
|
||||
;;> @subsubsubsection{Macros}
|
||||
|
||||
;;> \itemlist[
|
||||
;;> \item{\scheme{(macro-procedure f)} - the macro procedure}
|
||||
;;> \item{\scheme{(macro-env f)} - the environment the macro was defined in}
|
||||
;;> \item{\scheme{(macro-source f)} - the source location the macro was defined in}
|
||||
;;> \item{\scheme{(macro-aux f)} - custom auxiliary data stored with the macro}
|
||||
;;> \item{\scheme{(macro-aux-set! f x)}}
|
||||
;;> @itemlist[
|
||||
;;> @item{@scheme{(macro-procedure f)} - the macro procedure}
|
||||
;;> @item{@scheme{(macro-env f)} - the environment the macro was defined in}
|
||||
;;> @item{@scheme{(macro-source f)} - the source location the macro was defined in}
|
||||
;;> ]
|
||||
|
||||
;;> \subsection{Bytecode Objects}
|
||||
;;> @subsubsubsection{Bytecode Objects}
|
||||
|
||||
;;> \itemlist[
|
||||
;;> \item{\scheme{(bytecode-name bc)} - the macro procedure}
|
||||
;;> \item{\scheme{(bytecode-literals bc)} - literals the bytecode references}
|
||||
;;> \item{\scheme{(bytecode-source bc)} - the source location the procedure was defined in}
|
||||
;;> @itemlist[
|
||||
;;> @item{@scheme{(bytecode-name bc)} - the macro procedure}
|
||||
;;> @item{@scheme{(bytecode-literals bc)} - literals the bytecode references}
|
||||
;;> @item{@scheme{(bytecode-source bc)} - the source location the procedure was defined in}
|
||||
;;> ]
|
||||
|
||||
;;> \subsection{Syntactic Closures}
|
||||
;;> @subsubsubsection{Syntactic Closures}
|
||||
|
||||
;;> \itemlist[
|
||||
;;> \item{\scheme{(syntactic-closure-env sc)}}
|
||||
;;> \item{\scheme{(syntactic-closure-vars sc)}}
|
||||
;;> \item{\scheme{(syntactic-closure-expr sc)}}
|
||||
;;> @itemlist[
|
||||
;;> @item{@scheme{(syntactic-closure-env sc)}}
|
||||
;;> @item{@scheme{(syntactic-closure-vars sc)}}
|
||||
;;> @item{@scheme{(syntactic-closure-expr sc)}}
|
||||
;;> ]
|
||||
|
||||
;;> Return the environment, free variables, and expression
|
||||
;;> associated with \var{sc} respectively.
|
||||
;;> associated with @var{sc} respectively.
|
||||
|
||||
;;> \subsection{Exceptions}
|
||||
;;> @subsubsubsection{Exceptions}
|
||||
|
||||
;;> \itemlist[
|
||||
;;> \item{\scheme{(exception-kind exn)}}
|
||||
;;> \item{\scheme{(exception-message exn)}}
|
||||
;;> \item{\scheme{(exception-irritants exn)}}
|
||||
;;> @itemlist[
|
||||
;;> @item{@scheme{(exception-kind exn)}}
|
||||
;;> @item{@scheme{(exception-message exn)}}
|
||||
;;> @item{@scheme{(exception-irritants exn)}}
|
||||
;;> ]
|
||||
|
||||
;;> Return the kind, message, and irritants
|
||||
;;> associated with \var{exn} respectively.
|
||||
;;> associated with @var{exn} respectively.
|
||||
|
||||
;;> \subsection{Lambdas}
|
||||
;;> @subsubsubsection{Lambdas}
|
||||
|
||||
;;> \itemlist[
|
||||
;;> \item{\scheme{(lambda-name lam)} - the name of the lambda, if known}
|
||||
;;> \item{\scheme{(lambda-name-set! lam x)}}
|
||||
;;> \item{\scheme{(lambda-params lam)} - the lambda parameter list}
|
||||
;;> \item{\scheme{(lambda-params-set! lam x)}}
|
||||
;;> \item{\scheme{(lambda-body lam)} - the body of the lambda}
|
||||
;;> \item{\scheme{(lambda-body-set! lam x)}}
|
||||
;;> \item{\scheme{(lambda-defs lam)} - internal definitions of the lambda}
|
||||
;;> \item{\scheme{(lambda-defs-set! lam x)}}
|
||||
;;> \item{\scheme{(lambda-locals lam)} - local variables as a list of identifiers}
|
||||
;;> \item{\scheme{(lambda-locals-set! lam x)}}
|
||||
;;> \item{\scheme{(lambda-flags lam)} - various flags describing the lambda}
|
||||
;;> \item{\scheme{(lambda-flags-set! lam x)}}
|
||||
;;> \item{\scheme{(lambda-free-vars lam)} - free variables the lambda will need to close over}
|
||||
;;> \item{\scheme{(lambda-free-vars-set! lam x)}}
|
||||
;;> \item{\scheme{(lambda-set-vars lam)} - variables the lambda mutates}
|
||||
;;> \item{\scheme{(lambda-set-vars-set! lam x)}}
|
||||
;;> \item{\scheme{(lambda-return-type lam)} - the return type of the lambda}
|
||||
;;> \item{\scheme{(lambda-return-type-set! lam x)}}
|
||||
;;> \item{\scheme{(lambda-param-types lam)} - the types of the input parameters}
|
||||
;;> \item{\scheme{(lambda-param-types-set! lam x)}}
|
||||
;;> \item{\scheme{(lambda-source lam)} - the source code of the lambda}
|
||||
;;> \item{\scheme{(lambda-source-set! lam x)}}
|
||||
;;> @itemlist[
|
||||
;;> @item{@scheme{(lambda-name lam)} - the name of the lambda, if known}
|
||||
;;> @item{@scheme{(lambda-name-set! lam x)}}
|
||||
;;> @item{@scheme{(lambda-params lam)} - the lambda parameter list}
|
||||
;;> @item{@scheme{(lambda-params-set! lam x)}}
|
||||
;;> @item{@scheme{(lambda-body lam)} - the body of the lambda}
|
||||
;;> @item{@scheme{(lambda-body-set! lam x)}}
|
||||
;;> @item{@scheme{(lambda-defs lam)} - internal definitions of the lambda}
|
||||
;;> @item{@scheme{(lambda-defs-set! lam x)}}
|
||||
;;> @item{@scheme{(lambda-locals lam)} - local variables as a list of identifiers}
|
||||
;;> @item{@scheme{(lambda-locals-set! lam x)}}
|
||||
;;> @item{@scheme{(lambda-flags lam)} - various flags describing the lambda}
|
||||
;;> @item{@scheme{(lambda-flags-set! lam x)}}
|
||||
;;> @item{@scheme{(lambda-free-vars lam)} - free variables the lambda will need to close over}
|
||||
;;> @item{@scheme{(lambda-free-vars-set! lam x)}}
|
||||
;;> @item{@scheme{(lambda-set-vars lam)} - variables the lambda mutates}
|
||||
;;> @item{@scheme{(lambda-set-vars-set! lam x)}}
|
||||
;;> @item{@scheme{(lambda-return-type lam)} - the return type of the lambda}
|
||||
;;> @item{@scheme{(lambda-return-type-set! lam x)}}
|
||||
;;> @item{@scheme{(lambda-param-types lam)} - the types of the input parameters}
|
||||
;;> @item{@scheme{(lambda-param-types-set! lam x)}}
|
||||
;;> @item{@scheme{(lambda-source lam)} - the source code of the lambda}
|
||||
;;> @item{@scheme{(lambda-source-set! lam x)}}
|
||||
;;> ]
|
||||
|
||||
;;> \subsection{Conditionals}
|
||||
;;> @subsubsubsection{Conditionals}
|
||||
|
||||
;;> \itemlist[
|
||||
;;> \item{\scheme{(cnd-test cnd)} - the test for the conditional}
|
||||
;;> \item{\scheme{(cnd-test-set! cnd x)}}
|
||||
;;> \item{\scheme{(cnd-pass cnd)} - the success branch}
|
||||
;;> \item{\scheme{(cnd-pass-set! cnd x)}}
|
||||
;;> \item{\scheme{(cnd-fail cnd)} - the failure branch}
|
||||
;;> \item{\scheme{(cnd-fail-set! cnd x)}}
|
||||
;;> @itemlist[
|
||||
;;> @item{@scheme{(cnd-test cnd)} - the test for the conditional}
|
||||
;;> @item{@scheme{(cnd-test-set! cnd x)}}
|
||||
;;> @item{@scheme{(cnd-pass cnd)} - the success branch}
|
||||
;;> @item{@scheme{(cnd-pass-set! cnd x)}}
|
||||
;;> @item{@scheme{(cnd-fail cnd)} - the failure branch}
|
||||
;;> @item{@scheme{(cnd-fail-set! cnd x)}}
|
||||
;;> ]
|
||||
|
||||
;;> \subsection{Sequences}
|
||||
;;> @subsubsubsection{Sequences}
|
||||
|
||||
;;> \itemlist[
|
||||
;;> \item{\scheme{(seq-ls seq)} - the list of sequence expressions}
|
||||
;;> \item{\scheme{(seq-ls-set! seq x)}}
|
||||
;;> @itemlist[
|
||||
;;> @item{@scheme{(seq-ls seq)} - the list of sequence expressions}
|
||||
;;> @item{@scheme{(seq-ls-set! seq x)}}
|
||||
;;> ]
|
||||
|
||||
;;> \subsection{References}
|
||||
;;> @subsubsubsection{References}
|
||||
|
||||
;;> \itemlist[
|
||||
;;> \item{\scheme{(ref-name ref)} - the name of the referenced variable}
|
||||
;;> \item{\scheme{(ref-name-set! ref x)}}
|
||||
;;> \item{\scheme{(ref-cell ref)} - the environment cell the reference resolves to}
|
||||
;;> \item{\scheme{(ref-cell-set! ref x)}}
|
||||
;;> @itemlist[
|
||||
;;> @item{@scheme{(ref-name ref)} - the name of the referenced variable}
|
||||
;;> @item{@scheme{(ref-name-set! ref x)}}
|
||||
;;> @item{@scheme{(ref-cell ref)} - the environment cell the reference resolves to}
|
||||
;;> @item{@scheme{(ref-cell-set! ref x)}}
|
||||
;;> ]
|
||||
|
||||
;;> \subsection{Mutations}
|
||||
;;> @subsubsubsection{Mutations}
|
||||
|
||||
;;> \itemlist[
|
||||
;;> \item{\scheme{(set-var set)} - a reference to the mutated variable}
|
||||
;;> \item{\scheme{(set-var-set! set x)}}
|
||||
;;> \item{\scheme{(set-value set)} - the value to set the variable to}
|
||||
;;> \item{\scheme{(set-value-set! set x)}}
|
||||
;;> @itemlist[
|
||||
;;> @item{@scheme{(set-var set)} - a reference to the mutated variable}
|
||||
;;> @item{@scheme{(set-var-set! set x)}}
|
||||
;;> @item{@scheme{(set-value set)} - the value to set the variable to}
|
||||
;;> @item{@scheme{(set-value-set! set x)}}
|
||||
;;> ]
|
||||
|
||||
;;> \subsection{Literals}
|
||||
;;> @subsubsubsection{Literals}
|
||||
|
||||
;;> \itemlist[
|
||||
;;> \item{\scheme{(lit-value lit)} - the literal value}
|
||||
;;> \item{\scheme{(lit-value-set! lit x)}}
|
||||
;;> @itemlist[
|
||||
;;> @item{@scheme{(lit-value lit)} - the literal value}
|
||||
;;> @item{@scheme{(lit-value-set! lit x)}}
|
||||
;;> ]
|
||||
|
||||
;;> \subsection{Pairs}
|
||||
;;> @subsubsubsection{Pairs}
|
||||
|
||||
;;> \itemlist[
|
||||
;;> \item{\scheme{(pair-source x)}}
|
||||
;;> \item{\scheme{(pair-source-set! x source)}}
|
||||
;;> @itemlist[
|
||||
;;> @item{@scheme{(pair-source x)}}
|
||||
;;> @item{@scheme{(pair-source-set! x source)}}
|
||||
;;> ]
|
||||
|
||||
;;> Set or return the source code info associated with a pair x.
|
||||
;;> Source info is represented as another pair whose \var{car} is
|
||||
;;> the source file name and whose \var{cdr} is the line number.
|
||||
;;> Source info is represented as another pair whose @var{car} is
|
||||
;;> the source file name and whose @var{cdr} is the line number.
|
||||
|
||||
;;> \section{Miscellaneous Utilities}
|
||||
;;> @subsubsection{Miscellaneous Utilities}
|
||||
|
||||
;;> \procedure{(gc)}
|
||||
;;> @subsubsubsection{@scheme{(gc)}}
|
||||
|
||||
;;> Force a garbage collection.
|
||||
|
||||
;;> \procedure{(object-size x)}
|
||||
;;> @subsubsubsection{@scheme{(object-size x)}}
|
||||
|
||||
;;> Returns the heap space directly used by \var{x}, not
|
||||
;;> counting any elements of \var{x}.
|
||||
;;> Returns the heap space directly used by @var{x}, not
|
||||
;;> counting any elements of @var{x}.
|
||||
|
||||
;;> \procedure{(integer->immediate n)}
|
||||
;;> @subsubsubsection{@scheme{(integer->immediate n)}}
|
||||
|
||||
;;> Returns the interpretation of the integer \var{n} as
|
||||
;;> Returns the interpretation of the integer @var{n} as
|
||||
;;> an immediate object, useful for debugging.
|
||||
|
||||
;;> \procedure{(string-contains str pat [start])}
|
||||
;;> @subsubsubsection{@scheme{(string-contains str pat)}}
|
||||
|
||||
;;> Returns the first string cursor of \var{pat} in \var{str},
|
||||
;;> of \scheme{#f} if it's not found.
|
||||
;;> Returns the first string cursor of @var{pat} in @var{str},
|
||||
;;> of @scheme{#f} if it's not found.
|
||||
|
||||
(cond-expand
|
||||
(safe-string-cursors
|
||||
(define orig-string-contains string-contains)
|
||||
(set! string-contains
|
||||
(lambda (str pat . o)
|
||||
(let ((res
|
||||
(if (pair? o)
|
||||
(orig-string-contains str pat (string-cursor-where (car o)))
|
||||
(orig-string-contains str pat))))
|
||||
(and res (make-string-cursor str res (string-size str)))))))
|
||||
(else
|
||||
))
|
||||
;;> @subsubsubsection{@scheme{(atomically expr)}}
|
||||
|
||||
;;> \procedure{(string-cursor-copy! dst src from start end)}
|
||||
|
||||
;;> Copies the characters from \var{src}[\var{start}..\var{end}]
|
||||
;;> to \var{dst} starting at \var{from}.
|
||||
|
||||
;;> \procedure{(safe-setenv name value)}
|
||||
|
||||
;;> Equivalent to \scheme{setenv} but does nothing and returns
|
||||
;;> \scheme{#f} if \var{value} is a function definition. Used to
|
||||
;;> circumvent the vulnerability of the shellshock bug.
|
||||
|
||||
(define (safe-setenv name value)
|
||||
(define (function-def? str)
|
||||
(and (> (string-size value) 5)
|
||||
(equal? "() {" (substring value 0 4))))
|
||||
(and (not (function-def? value))
|
||||
(setenv name value)))
|
||||
|
||||
;;> \procedure{(atomically expr)}
|
||||
|
||||
;;> Run \var{expr} atomically, disabling yields. Ideally should only be
|
||||
;;> Run @var{expr} atomically, disabling yields. Ideally should only be
|
||||
;;> used for brief, deterministic expressions. If used incorrectly (e.g.
|
||||
;;> running an infinite loop) can render the system unusable.
|
||||
;;> Never expose to a sandbox.
|
||||
|
@ -436,7 +375,3 @@
|
|||
(else
|
||||
(define-syntax atomically
|
||||
(syntax-rules () ((atomically . body) (begin . body))))))
|
||||
|
||||
(define (thread-interrupt! thread)
|
||||
(if (%thread-interrupt! thread)
|
||||
(yield!)))
|
||||
|
|
|
@ -1,17 +1,15 @@
|
|||
|
||||
(define-library (chibi ast)
|
||||
(export
|
||||
analyze optimize env-cell ast->sexp macroexpand identifier-syntax
|
||||
type-of
|
||||
analyze optimize env-cell ast->sexp macroexpand type-of
|
||||
Object Input-Port Output-Port Opcode Procedure Bytecode Macro Env
|
||||
Number Bignum Flonum Integer Complex Char Boolean
|
||||
Symbol String Byte-Vector Vector Pair File-Descriptor
|
||||
Context Lam Cnd Set Set-Syn Ref Seq Lit Sc Exception Core
|
||||
syntactic-closure? lambda? cnd? set? ref? seq? lit? type? core?
|
||||
environment? bytecode? exception? macro? context? file-descriptor?
|
||||
Number Bignum Flonum Integer Char Boolean
|
||||
Symbol String Byte-Vector Vector Pair
|
||||
Context Lam Cnd Set Ref Seq Lit Sc Exception
|
||||
syntactic-closure? lambda? cnd? set? ref? seq? lit? type?
|
||||
environment? bytecode? exception? macro? context?
|
||||
syntactic-closure-expr syntactic-closure-env syntactic-closure-vars
|
||||
copy-lambda make-lambda make-cnd make-ref make-set make-seq make-lit
|
||||
make-macro
|
||||
lambda-name lambda-params lambda-body lambda-defs lambda-locals
|
||||
lambda-flags lambda-free-vars lambda-set-vars lambda-return-type
|
||||
lambda-param-types lambda-source
|
||||
|
@ -21,29 +19,21 @@
|
|||
lambda-source-set!
|
||||
cnd-test cnd-pass cnd-fail
|
||||
cnd-test-set! cnd-pass-set! cnd-fail-set!
|
||||
set-var set-value set-var-set! set-value-set! set-source set-source-set!
|
||||
set-var set-value set-var-set! set-value-set!
|
||||
ref-name ref-cell ref-name-set! ref-cell-set!
|
||||
seq-ls seq-ls-set! lit-value lit-value-set!
|
||||
exception-kind exception-message exception-irritants exception-source
|
||||
exception-kind exception-message exception-irritants
|
||||
opcode-name opcode-num-params opcode-return-type opcode-param-type
|
||||
opcode-class opcode-code opcode-data opcode-variadic? opcode?
|
||||
macro-procedure macro-env macro-source macro-aux macro-aux-set!
|
||||
opcode-class opcode-code opcode-data opcode-variadic?
|
||||
macro-procedure macro-env macro-source
|
||||
procedure-code procedure-vars procedure-name procedure-name-set!
|
||||
procedure-arity procedure-variadic? procedure-variable-transformer?
|
||||
procedure-flags make-variable-transformer make-procedure procedure?
|
||||
bytecode-name bytecode-literals bytecode-source
|
||||
port-line port-line-set! port-source? port-source?-set!
|
||||
extend-env env-parent env-parent-set! env-lambda env-lambda-set!
|
||||
env-define! env-push! env-syntactic? env-syntactic?-set! core-code
|
||||
type-name type-cpl type-parent type-slots type-num-slots
|
||||
type-printer type-printer-set!
|
||||
object-size object->integer integer->immediate gc gc-usecs gc-count
|
||||
atomically thread-list abort
|
||||
string-contains string-cursor-copy! errno integer->error-string
|
||||
flatten-dot update-free-vars! setenv unsetenv safe-setenv
|
||||
immutable? immutable-string make-immutable!
|
||||
thread-interrupt!
|
||||
chibi-version)
|
||||
port-line port-line-set!
|
||||
environment-parent
|
||||
type-name type-cpl type-parent type-slots type-num-slots type-printer
|
||||
object-size integer->immediate gc atomically
|
||||
string-contains integer->error-string
|
||||
flatten-dot update-free-vars!)
|
||||
(import (chibi))
|
||||
(include-shared "ast")
|
||||
(include "ast.scm"))
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
(define-library (chibi base64-test)
|
||||
(export run-tests)
|
||||
(import (scheme base) (chibi base64) (chibi string) (chibi test))
|
||||
(begin
|
||||
(define (run-tests)
|
||||
(test-begin "base64")
|
||||
|
||||
(test "YW55IGNhcm5hbCBwbGVhc3VyZS4="
|
||||
(base64-encode-string "any carnal pleasure."))
|
||||
(test "YW55IGNhcm5hbCBwbGVhc3VyZQ=="
|
||||
(base64-encode-string "any carnal pleasure"))
|
||||
(test "YW55IGNhcm5hbCBwbGVhc3Vy"
|
||||
(base64-encode-string "any carnal pleasur"))
|
||||
(test "YW55IGNhcm5hbCBwbGVhc3U="
|
||||
(base64-encode-string "any carnal pleasu"))
|
||||
(test "YW55IGNhcm5hbCBwbGVhcw=="
|
||||
(base64-encode-string "any carnal pleas"))
|
||||
|
||||
(test "any carnal pleas"
|
||||
(base64-decode-string "YW55IGNhcm5hbCBwbGVhcw=="))
|
||||
(test "any carnal pleasu"
|
||||
(base64-decode-string "YW55IGNhcm5hbCBwbGVhc3U="))
|
||||
(test "any carnal pleasur"
|
||||
(base64-decode-string "YW55IGNhcm5hbCBwbGVhc3Vy"))
|
||||
(test "any carnal pleas"
|
||||
(base64-decode-string "YW55IGNhcm5hbCBwbGVhcw"))
|
||||
(test "any carnal pleasu"
|
||||
(base64-decode-string "YW55IGNhcm5hbCBwbGVhc3U"))
|
||||
|
||||
(test "YW55IGNhcm5hbCBwbGVhc3VyZS4="
|
||||
(call-with-output-string
|
||||
(lambda (out)
|
||||
(call-with-input-string "any carnal pleasure."
|
||||
(lambda (in) (base64-encode in out))))))
|
||||
|
||||
(test "any carnal pleasure."
|
||||
(call-with-output-string
|
||||
(lambda (out)
|
||||
(call-with-input-string "YW55IGNhcm5hbCBwbGVhc3VyZS4="
|
||||
(lambda (in) (base64-decode in out))))))
|
||||
|
||||
(test-end))))
|
|
@ -1,8 +1,30 @@
|
|||
;; Copyright (c) 2005-2014 Alex Shinn. All rights reserved.
|
||||
;; Copyright (c) 2005-2009 Alex Shinn. All rights reserved.
|
||||
;; BSD-style license: http://synthcode.com/license.txt
|
||||
|
||||
;;> RFC 3548 base64 encoding and decoding utilities.
|
||||
;;> This API is compatible with the Gauche library rfc.base64.
|
||||
;; Procedure: base64-encode-string str
|
||||
;; Return a base64 encoded representation of string according to the
|
||||
;; official base64 standard as described in RFC3548.
|
||||
|
||||
;; Procedure: base64-decode-string str
|
||||
;; Return a base64 decoded representation of string, also interpreting
|
||||
;; the alternate 62 & 63 valued characters as described in RFC3548.
|
||||
;; Other out-of-band characters are silently stripped, and = signals
|
||||
;; the end of the encoded string. No errors will be raised.
|
||||
|
||||
;; Procedure: base64-encode [port]
|
||||
;; Procedure: base64-decode [port]
|
||||
;; Variations of the above which read and write to ports.
|
||||
|
||||
;; Procedure: base64-encode-header enc str [start-col max-col nl]
|
||||
;; Return a base64 encoded representation of string as above,
|
||||
;; wrapped in =?ENC?B?...?= as per RFC1522, split across multiple
|
||||
;; MIME-header lines as needed to keep each lines length less than
|
||||
;; MAX-COL. The string is encoded as is, and the encoding ENC is
|
||||
;; just used for the prefix, i.e. you are responsible for ensuring
|
||||
;; STR is already encoded according to ENC. The optional argument
|
||||
;; NL is the newline separator, defaulting to CRLF.
|
||||
|
||||
;; This API is compatible with the Gauche library rfc.base64.
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; string utils
|
||||
|
@ -45,24 +67,24 @@
|
|||
(vector-set! res (char->integer #\=) *pad-char*)
|
||||
res))
|
||||
|
||||
(define (base64-decode-u8 u8)
|
||||
(vector-ref *base64-decode-table* u8))
|
||||
(define (base64-decode-char c)
|
||||
(vector-ref *base64-decode-table* (char->integer c)))
|
||||
|
||||
(define *base64-encode-table*
|
||||
(let ((res (make-vector 64)))
|
||||
(let lp ((i 0)) ; map letters
|
||||
(cond
|
||||
((<= i 25)
|
||||
(vector-set! res i (+ i 65))
|
||||
(vector-set! res (+ i 26) (+ i 97))
|
||||
(vector-set! res i (integer->char (+ i 65)))
|
||||
(vector-set! res (+ i 26) (integer->char (+ i 97)))
|
||||
(lp (+ i 1)))))
|
||||
(let lp ((i 0)) ; map numbers
|
||||
(cond
|
||||
((<= i 9)
|
||||
(vector-set! res (+ i 52) (+ i 48))
|
||||
(vector-set! res (+ i 52) (integer->char (+ i 48)))
|
||||
(lp (+ i 1)))))
|
||||
(vector-set! res 62 (char->integer #\+))
|
||||
(vector-set! res 63 (char->integer #\/))
|
||||
(vector-set! res 62 #\+)
|
||||
(vector-set! res 63 #\/)
|
||||
res))
|
||||
|
||||
(define (enc i)
|
||||
|
@ -81,30 +103,21 @@
|
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; decoding
|
||||
|
||||
;;> Return a base64 decoded representation of string, also interpreting
|
||||
;;> the alternate 62 & 63 valued characters as described in RFC3548.
|
||||
;;> Other out-of-band characters are silently stripped, and = signals
|
||||
;;> the end of the encoded string. No errors will be raised.
|
||||
|
||||
;; Create a result buffer with the maximum possible length for the
|
||||
;; input, and pass it to the internal base64-decode-string! utility.
|
||||
;; If the resulting length used is exact, we can return that buffer,
|
||||
;; otherwise we return the appropriate substring.
|
||||
|
||||
(define (base64-decode-string str)
|
||||
(utf8->string (base64-decode-bytevector (string->utf8 str))))
|
||||
|
||||
(define (base64-decode-bytevector src)
|
||||
(let* ((len (bytevector-length src))
|
||||
(define (base64-decode-string src)
|
||||
(let* ((len (string-length src))
|
||||
(dst-len (* 3 (arithmetic-shift (+ 3 len) -2)))
|
||||
(dst (make-bytevector dst-len)))
|
||||
(base64-decode-bytevector!
|
||||
(dst (make-string dst-len)))
|
||||
(base64-decode-string!
|
||||
src 0 len dst
|
||||
(lambda (src-offset res-len b1 b2 b3)
|
||||
(let ((res-len (base64-decode-finish dst res-len b1 b2 b3)))
|
||||
(if (= res-len dst-len)
|
||||
dst
|
||||
(bytevector-copy dst 0 res-len)))))))
|
||||
(substring dst 0 res-len)))))))
|
||||
|
||||
;; This is a little funky.
|
||||
;;
|
||||
|
@ -116,7 +129,7 @@
|
|||
;; really bad about optimizing nested loops of primitives, so we
|
||||
;; flatten this into a single loop, using conditionals to determine
|
||||
;; which character is currently being read.
|
||||
(define (base64-decode-bytevector! src start end dst kont)
|
||||
(define (base64-decode-string! src start end dst kont)
|
||||
(let lp ((i start)
|
||||
(j 0)
|
||||
(b1 *outside-char*)
|
||||
|
@ -124,7 +137,7 @@
|
|||
(b3 *outside-char*))
|
||||
(if (>= i end)
|
||||
(kont i j b1 b2 b3)
|
||||
(let ((c (base64-decode-u8 (bytevector-u8-ref src i))))
|
||||
(let ((c (base64-decode-char (string-ref src i))))
|
||||
(cond
|
||||
((eqv? c *pad-char*)
|
||||
(kont i j b1 b2 b3))
|
||||
|
@ -137,23 +150,23 @@
|
|||
((eqv? b3 *outside-char*)
|
||||
(lp (+ i 1) j b1 b2 c))
|
||||
(else
|
||||
(bytevector-u8-set!
|
||||
dst
|
||||
j
|
||||
(bitwise-ior (arithmetic-shift b1 2)
|
||||
(bit-field b2 4 6)))
|
||||
(bytevector-u8-set!
|
||||
dst
|
||||
(+ j 1)
|
||||
(bitwise-ior
|
||||
(arithmetic-shift (bit-field b2 0 4) 4)
|
||||
(bit-field b3 2 6)))
|
||||
(bytevector-u8-set!
|
||||
dst
|
||||
(+ j 2)
|
||||
(bitwise-ior
|
||||
(arithmetic-shift (bit-field b3 0 2) 6)
|
||||
c))
|
||||
(string-set! dst
|
||||
j
|
||||
(integer->char
|
||||
(bitwise-ior (arithmetic-shift b1 2)
|
||||
(extract-bit-field 2 4 b2))))
|
||||
(string-set! dst
|
||||
(+ j 1)
|
||||
(integer->char
|
||||
(bitwise-ior
|
||||
(arithmetic-shift (extract-bit-field 4 0 b2) 4)
|
||||
(extract-bit-field 4 2 b3))))
|
||||
(string-set! dst
|
||||
(+ j 2)
|
||||
(integer->char
|
||||
(bitwise-ior
|
||||
(arithmetic-shift (extract-bit-field 2 0 b3) 6)
|
||||
c)))
|
||||
(lp (+ i 1) (+ j 3)
|
||||
*outside-char* *outside-char* *outside-char*)))))))
|
||||
|
||||
|
@ -166,181 +179,148 @@
|
|||
((eqv? b1 *outside-char*)
|
||||
j)
|
||||
((eqv? b2 *outside-char*)
|
||||
(bytevector-u8-set! dst j (arithmetic-shift b1 2))
|
||||
(string-set! dst j (integer->char (arithmetic-shift b1 2)))
|
||||
(+ j 1))
|
||||
(else
|
||||
(bytevector-u8-set! dst
|
||||
j
|
||||
(bitwise-ior (arithmetic-shift b1 2)
|
||||
(bit-field b2 4 6)))
|
||||
(string-set! dst
|
||||
j
|
||||
(integer->char
|
||||
(bitwise-ior (arithmetic-shift b1 2)
|
||||
(extract-bit-field 2 4 b2))))
|
||||
(cond
|
||||
((eqv? b3 *outside-char*)
|
||||
(+ j 1))
|
||||
(else
|
||||
(bytevector-u8-set! dst
|
||||
(+ j 1)
|
||||
(bitwise-ior
|
||||
(arithmetic-shift (bit-field b2 0 4) 4)
|
||||
(bit-field b3 2 6)))
|
||||
(string-set! dst
|
||||
(+ j 1)
|
||||
(integer->char
|
||||
(bitwise-ior
|
||||
(arithmetic-shift (extract-bit-field 4 0 b2) 4)
|
||||
(extract-bit-field 4 2 b3))))
|
||||
(+ j 2))))))
|
||||
|
||||
;;> Variation of the above to read and write to ports.
|
||||
|
||||
;; General port decoder: work in single blocks at a time to avoid
|
||||
;; allocating memory (crucial for Scheme implementations that don't
|
||||
;; allow large strings).
|
||||
(define (base64-decode . o)
|
||||
(let ((in (if (pair? o) (car o) (current-input-port)))
|
||||
(out (if (and (pair? o) (pair? (cdr o)))
|
||||
(cadr o)
|
||||
(current-output-port))))
|
||||
(cond
|
||||
((not (binary-port? in))
|
||||
(let ((str (port->string in)))
|
||||
(write-string (base64-decode-string str) out)))
|
||||
(else
|
||||
(let ((src (make-bytevector decode-src-length))
|
||||
(dst (make-bytevector decode-dst-length)))
|
||||
(let lp ((offset 0))
|
||||
(let ((src-len
|
||||
(+ offset
|
||||
(read-bytevector! src in offset decode-src-length))))
|
||||
(cond
|
||||
((= src-len decode-src-length)
|
||||
;; read a full chunk: decode, write and loop
|
||||
(base64-decode-bytevector!
|
||||
src 0 decode-src-length dst
|
||||
(lambda (src-offset dst-len b1 b2 b3)
|
||||
(cond
|
||||
((and (< src-offset src-len)
|
||||
(eqv? #x3D (bytevector-u8-ref src src-offset)))
|
||||
;; done
|
||||
(let ((dst-len (base64-decode-finish dst dst-len b1 b2 b3)))
|
||||
(write-bytevector dst out 0 dst-len)))
|
||||
((eqv? b1 *outside-char*)
|
||||
(write-bytevector dst out 0 dst-len)
|
||||
(lp 0))
|
||||
(else
|
||||
(write-bytevector dst out 0 dst-len)
|
||||
;; one to three chars left in buffer
|
||||
(bytevector-u8-set! src 0 (enc b1))
|
||||
(cond
|
||||
((eqv? b2 *outside-char*)
|
||||
(lp 1))
|
||||
(else
|
||||
(bytevector-u8-set! src 1 (enc b2))
|
||||
(cond
|
||||
((eqv? b3 *outside-char*)
|
||||
(lp 2))
|
||||
(else
|
||||
(bytevector-u8-set! src 2 (enc b3))
|
||||
(lp 3))))))))))
|
||||
(else
|
||||
;; end of source - just decode and write once
|
||||
(base64-decode-bytevector!
|
||||
src 0 src-len dst
|
||||
(lambda (src-offset dst-len b1 b2 b3)
|
||||
(let ((src (make-string decode-src-length))
|
||||
(dst (make-string decode-dst-length)))
|
||||
(let lp ((offset 0))
|
||||
(let ((src-len (+ offset
|
||||
(read-string! decode-src-length src in offset))))
|
||||
(cond
|
||||
((= src-len decode-src-length)
|
||||
;; read a full chunk: decode, write and loop
|
||||
(base64-decode-string!
|
||||
src 0 decode-src-length dst
|
||||
(lambda (src-offset dst-len b1 b2 b3)
|
||||
(cond
|
||||
((and (< src-offset src-len)
|
||||
(eqv? #\= (string-ref src src-offset)))
|
||||
;; done
|
||||
(let ((dst-len (base64-decode-finish dst dst-len b1 b2 b3)))
|
||||
(write-bytevector dst out 0 dst-len)))))))))))))
|
||||
(write-string dst out 0 dst-len)))
|
||||
((eqv? b1 *outside-char*)
|
||||
(write-string dst out 0 dst-len)
|
||||
(lp 0))
|
||||
(else
|
||||
(write-string dst out 0 dst-len)
|
||||
;; one to three chars left in buffer
|
||||
(string-set! src 0 (enc b1))
|
||||
(cond
|
||||
((eqv? b2 *outside-char*)
|
||||
(lp 1))
|
||||
(else
|
||||
(string-set! src 1 (enc b2))
|
||||
(cond
|
||||
((eqv? b3 *outside-char*)
|
||||
(lp 2))
|
||||
(else
|
||||
(string-set! src 2 (enc b3))
|
||||
(lp 3))))))))))
|
||||
(else
|
||||
;; end of source - just decode and write once
|
||||
(base64-decode-string!
|
||||
src 0 src-len dst
|
||||
(lambda (src-offset dst-len b1 b2 b3)
|
||||
(let ((dst-len (base64-decode-finish dst dst-len b1 b2 b3)))
|
||||
(write-string dst out 0 dst-len)))))))))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; encoding
|
||||
|
||||
;;> Return a base64 encoded representation of string according to the
|
||||
;;> official base64 standard as described in RFC3548.
|
||||
|
||||
(define (base64-encode-string str)
|
||||
(utf8->string (base64-encode-bytevector (string->utf8 str))))
|
||||
|
||||
(define (base64-encode-bytevector bv)
|
||||
(let* ((len (bytevector-length bv))
|
||||
(let* ((len (string-length str))
|
||||
(quot (quotient len 3))
|
||||
(rem (- len (* quot 3)))
|
||||
(res-len (arithmetic-shift (+ quot (if (zero? rem) 0 1)) 2))
|
||||
(res (make-bytevector res-len)))
|
||||
(base64-encode-bytevector! bv 0 len res)
|
||||
(res (make-string res-len)))
|
||||
(base64-encode-string! str 0 len res)
|
||||
res))
|
||||
|
||||
(define (base64-encode-bytevector! bv start end res)
|
||||
(let ((limit (- end 2)))
|
||||
(define (base64-encode-string! str start end res)
|
||||
(let* ((res-len (string-length res))
|
||||
(limit (- end 2)))
|
||||
(let lp ((i start) (j 0))
|
||||
(if (>= i limit)
|
||||
(case (- end i)
|
||||
((1)
|
||||
(let ((b1 (bytevector-u8-ref bv i)))
|
||||
(bytevector-u8-set! res j (enc (arithmetic-shift b1 -2)))
|
||||
(bytevector-u8-set!
|
||||
res
|
||||
(+ j 1)
|
||||
(enc (arithmetic-shift (bitwise-and #b11 b1) 4)))
|
||||
(bytevector-u8-set! res (+ j 2) (char->integer #\=))
|
||||
(bytevector-u8-set! res (+ j 3) (char->integer #\=))
|
||||
(+ j 4)))
|
||||
(let ((b1 (char->integer (string-ref str i))))
|
||||
(string-set! res j (enc (arithmetic-shift b1 -2)))
|
||||
(string-set! res
|
||||
(+ j 1)
|
||||
(enc (arithmetic-shift (bitwise-and #b11 b1) 4)))
|
||||
(string-set! res (+ j 2) #\=)
|
||||
(string-set! res (+ j 3) #\=)))
|
||||
((2)
|
||||
(let ((b1 (bytevector-u8-ref bv i))
|
||||
(b2 (bytevector-u8-ref bv (+ i 1))))
|
||||
(bytevector-u8-set! res j (enc (arithmetic-shift b1 -2)))
|
||||
(bytevector-u8-set!
|
||||
res
|
||||
(+ j 1)
|
||||
(enc (bitwise-ior
|
||||
(arithmetic-shift (bitwise-and #b11 b1) 4)
|
||||
(bit-field b2 4 8))))
|
||||
(bytevector-u8-set!
|
||||
res
|
||||
(+ j 2)
|
||||
(enc (arithmetic-shift (bit-field b2 0 4) 2)))
|
||||
(bytevector-u8-set! res (+ j 3) (char->integer #\=))
|
||||
(+ j 4)))
|
||||
(else
|
||||
j))
|
||||
(let ((b1 (bytevector-u8-ref bv i))
|
||||
(b2 (bytevector-u8-ref bv (+ i 1)))
|
||||
(b3 (bytevector-u8-ref bv (+ i 2))))
|
||||
(bytevector-u8-set! res j (enc (arithmetic-shift b1 -2)))
|
||||
(bytevector-u8-set!
|
||||
res
|
||||
(+ j 1)
|
||||
(enc (bitwise-ior
|
||||
(arithmetic-shift (bitwise-and #b11 b1) 4)
|
||||
(bit-field b2 4 8))))
|
||||
(bytevector-u8-set!
|
||||
res
|
||||
(+ j 2)
|
||||
(enc (bitwise-ior
|
||||
(arithmetic-shift (bit-field b2 0 4) 2)
|
||||
(bit-field b3 6 8))))
|
||||
(bytevector-u8-set! res (+ j 3) (enc (bitwise-and #b111111 b3)))
|
||||
(let ((b1 (char->integer (string-ref str i)))
|
||||
(b2 (char->integer (string-ref str (+ i 1)))))
|
||||
(string-set! res j (enc (arithmetic-shift b1 -2)))
|
||||
(string-set! res
|
||||
(+ j 1)
|
||||
(enc (bitwise-ior
|
||||
(arithmetic-shift (bitwise-and #b11 b1) 4)
|
||||
(extract-bit-field 4 4 b2))))
|
||||
(string-set! res
|
||||
(+ j 2)
|
||||
(enc (arithmetic-shift (extract-bit-field 4 0 b2)
|
||||
2)))
|
||||
(string-set! res (+ j 3) #\=))))
|
||||
(let ((b1 (char->integer (string-ref str i)))
|
||||
(b2 (char->integer (string-ref str (+ i 1))))
|
||||
(b3 (char->integer (string-ref str (+ i 2)))))
|
||||
(string-set! res j (enc (arithmetic-shift b1 -2)))
|
||||
(string-set! res
|
||||
(+ j 1)
|
||||
(enc (bitwise-ior
|
||||
(arithmetic-shift (bitwise-and #b11 b1) 4)
|
||||
(extract-bit-field 4 4 b2))))
|
||||
(string-set! res
|
||||
(+ j 2)
|
||||
(enc (bitwise-ior
|
||||
(arithmetic-shift (extract-bit-field 4 0 b2) 2)
|
||||
(extract-bit-field 2 6 b3))))
|
||||
(string-set! res (+ j 3) (enc (bitwise-and #b111111 b3)))
|
||||
(lp (+ i 3) (+ j 4)))))))
|
||||
|
||||
;;> Variation of the above to read and write to ports.
|
||||
|
||||
(define (base64-encode . o)
|
||||
(let ((in (if (pair? o) (car o) (current-input-port)))
|
||||
(out (if (and (pair? o) (pair? (cdr o)))
|
||||
(cadr o)
|
||||
(current-output-port))))
|
||||
(cond
|
||||
((not (binary-port? in))
|
||||
(let ((str (port->string in)))
|
||||
(write-string (base64-encode-string str) out)))
|
||||
(else
|
||||
(let ((src (make-bytevector encode-src-length))
|
||||
(dst (make-bytevector
|
||||
(arithmetic-shift (quotient encode-src-length 3) 2))))
|
||||
(let lp ()
|
||||
(let ((n (read-bytevector! src in 0 2048)))
|
||||
(base64-encode-bytevector! src 0 n dst)
|
||||
(write-bytevector dst out 0 (* 4 (quotient (+ n 2) 3)))
|
||||
(if (= n 2048)
|
||||
(lp)
|
||||
(flush-output-port out)))))))))
|
||||
|
||||
;;> Return a base64 encoded representation of the string \var{str} as
|
||||
;;> above, wrapped in =?ENC?B?...?= as per RFC1522, split across
|
||||
;;> multiple MIME-header lines as needed to keep each lines length
|
||||
;;> less than \var{max-col}. The string is encoded as is, and the
|
||||
;;> encoding \var{enc} is just used for the prefix, i.e. you are
|
||||
;;> responsible for ensuring \var{str} is already encoded according to
|
||||
;;> \var{enc}. The optional argument \var{nl} is the newline
|
||||
;;> separator, defaulting to \var{crlf}.
|
||||
(let ((src (make-string encode-src-length))
|
||||
(dst (make-string
|
||||
(arithmetic-shift (quotient encode-src-length 3) 2))))
|
||||
(let lp ()
|
||||
(let ((n (read-string! 2048 src in)))
|
||||
(base64-encode-string! src 0 n dst)
|
||||
(write-string dst out 0 (* 3 (quotient (+ n 3) 4)))
|
||||
(if (= n 2048)
|
||||
(lp)))))))
|
||||
|
||||
(define (base64-encode-header encoding str . o)
|
||||
(define (round4 i) (arithmetic-shift (arithmetic-shift i -2) 2))
|
||||
|
@ -364,8 +344,8 @@
|
|||
(string-append
|
||||
prefix (substring str 0 first-max-col) "?=" nl "\t" prefix)
|
||||
"")
|
||||
(string-join (string-chop (substring str first-max-col len)
|
||||
effective-max-col)
|
||||
(string-append "?=" nl "\t" prefix))
|
||||
(string-concatenate (string-chop (substring str first-max-col len)
|
||||
effective-max-col)
|
||||
(string-append "?=" nl "\t" prefix))
|
||||
"?=")))))
|
||||
|
||||
|
|
|
@ -1,37 +1,7 @@
|
|||
|
||||
(define-library (chibi base64)
|
||||
(export base64-encode base64-encode-string base64-encode-bytevector
|
||||
base64-decode base64-decode-string base64-decode-bytevector
|
||||
(export base64-encode base64-encode-string
|
||||
base64-decode base64-decode-string
|
||||
base64-encode-header)
|
||||
(import (scheme base)
|
||||
(chibi string))
|
||||
(cond-expand
|
||||
((library (srfi 151))
|
||||
(import (srfi 151)))
|
||||
((library (srfi 33))
|
||||
(import (srfi 33))
|
||||
(begin
|
||||
(define (%mask size) (bitwise-not (arithmetic-shift -1 size)))
|
||||
(define (bit-field n start end)
|
||||
(bitwise-and (arithmetic-shift n (- start)) (mask (- end start))))))
|
||||
(else
|
||||
(import (srfi 60))
|
||||
(begin
|
||||
(define (%mask size) (bitwise-not (arithmetic-shift -1 size)))
|
||||
(define (bit-field n start end)
|
||||
(bitwise-and (arithmetic-shift n (- start)) (mask (- end start)))))))
|
||||
(cond-expand
|
||||
(chibi (import (chibi io)))
|
||||
(else
|
||||
(begin
|
||||
(define (port->string in)
|
||||
(let ((out (open-output-string)))
|
||||
(let lp ()
|
||||
(let ((ch (read-char in)))
|
||||
(cond
|
||||
((eof-object? ch)
|
||||
(get-output-string out))
|
||||
(else
|
||||
(write-char ch out)
|
||||
(lp))))))))))
|
||||
(import (chibi) (srfi 33) (chibi io))
|
||||
(include "base64.scm"))
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; binary records, simpler version with type-checking on set! removed
|
||||
|
||||
(define-syntax defrec
|
||||
(syntax-rules (make: pred: read: write: block:)
|
||||
((defrec () n m p r w
|
||||
((field-tmp field-read field-read-expr field-write field-write-expr field-get) ...)
|
||||
((field getter . s) ...))
|
||||
(begin
|
||||
(define-record-type n (m field ...) p
|
||||
(field getter . s) ...)
|
||||
(define n 'n) ; chicken define-record-type doesn't define the rtd
|
||||
(define r
|
||||
(let ((field-read field-read-expr) ...)
|
||||
(lambda (in)
|
||||
(let* ((field-tmp (field-read in)) ...)
|
||||
(m field ...)))))
|
||||
(define w
|
||||
(let ((field-write field-write-expr) ...)
|
||||
(lambda (x out)
|
||||
(field-write (field-get x) out) ...)))))
|
||||
((defrec ((make: x) . rest) n m p r w b f)
|
||||
(defrec rest n x p r w b f))
|
||||
((defrec ((pred: x) . rest) n m p r w b f)
|
||||
(defrec rest n m x r w b f))
|
||||
((defrec ((read: x) . rest) n m p r w b f)
|
||||
(defrec rest n m p x w b f))
|
||||
((defrec ((write: x) . rest) n m p r w b f)
|
||||
(defrec rest n m p r x b f))
|
||||
((defrec ((block: (field (type . args) getter . s) . fields) . rest) n m p r w
|
||||
(b ...) (f ...))
|
||||
(defrec ((block: . fields) . rest) n m p r w
|
||||
(b ...
|
||||
(field read-tmp (type read: args) write-tmp (type write: args) getter))
|
||||
(f ...
|
||||
(field getter . s))))
|
||||
((defrec ((block: (field . x)) . rest) n m p r w b f)
|
||||
(syntax-error "invalid field in block" (field . x)))
|
||||
((defrec ((block: data . fields) . rest) n m p r w (b ...) f)
|
||||
(defrec ((block: . fields) . rest) n m p r w
|
||||
(b ...
|
||||
(tmp-data read-tmp (read-literal 'data) write-tmp (write-literal 'data) (lambda (x) x)))
|
||||
f))
|
||||
((defrec ((block:) . rest) n m p r w b f)
|
||||
(defrec rest n m p r w b f))
|
||||
))
|
||||
|
||||
(define-syntax define-binary-record-type
|
||||
(syntax-rules ()
|
||||
((define-binary-record-type name x ...)
|
||||
(defrec (x ...) name hidden-make hidden-pred hidden-read hidden-write
|
||||
() ()))))
|
|
@ -1,31 +0,0 @@
|
|||
|
||||
(define-library (chibi binary-record-test)
|
||||
(export run-tests)
|
||||
(import (scheme base) (chibi binary-record) (chibi test))
|
||||
(begin
|
||||
(define-binary-record-type gif-header
|
||||
(make: make-gif-header)
|
||||
(pred: gif-header?)
|
||||
(read: read-gif-header)
|
||||
(write: write-gif-header)
|
||||
(block:
|
||||
"GIF89a"
|
||||
(width (u16/le) gif-header-width)
|
||||
(height (u16/le) gif-header-height)
|
||||
(gct (u8) gif-header-gct)
|
||||
(bgcolor (u8) gif-header-gbcolor)
|
||||
(aspect-ratio (u8) gif-header-aspect-ratio)
|
||||
))
|
||||
(define (gif->bytevector gif)
|
||||
(let ((out (open-output-bytevector)))
|
||||
(write-gif-header gif out)
|
||||
(get-output-bytevector out)))
|
||||
(define (bytevector->gif bv)
|
||||
(read-gif-header (open-input-bytevector bv)))
|
||||
(define (run-tests)
|
||||
(test-begin "(chibi binary-record)")
|
||||
(let ((gif (make-gif-header 4096 2160 #xF7 1 2)))
|
||||
(test #u8(#x47 #x49 #x46 #x38 #x39 #x61 0 #x10 #x70 #x08 #xF7 #x01 #x02)
|
||||
(gif->bytevector gif))
|
||||
(test gif (bytevector->gif (gif->bytevector gif))))
|
||||
(test-end))))
|
|
@ -1,160 +0,0 @@
|
|||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Binary Records
|
||||
|
||||
;;> \macro{(define-binary-record-type <name> [<bindings> ...] (block: <fields> ...))}
|
||||
;;>
|
||||
;;> Defines a new record type that supports serializing to and from
|
||||
;;> binary ports. The generated procedures accept keyword-style
|
||||
;;> arguments:
|
||||
;;>
|
||||
;;> \itemlist[
|
||||
;;> \item{\scheme{(make: <constructor-name>)}}
|
||||
;;> \item{\scheme{(pred: <predicate-name>)}}
|
||||
;;> \item{\scheme{(read: <reader-name>)}}
|
||||
;;> \item{\scheme{(write: <writer-name>)}}
|
||||
;;> \item{\scheme{(block: <fields> ...)}}
|
||||
;;> ]
|
||||
;;>
|
||||
;;> The fields are also similar to \scheme{define-record-type} but
|
||||
;;> with an additional type:
|
||||
;;>
|
||||
;;> \scheme{(field (type args ...) getter setter)}
|
||||
;;>
|
||||
;;> Built-in types include:
|
||||
;;>
|
||||
;;> \itemlist[
|
||||
;;> \item{\scheme{(u8)} - a single byte in [0, 255]}
|
||||
;;> \item{\scheme{(u16/le)} - a little-endian short integer}
|
||||
;;> \item{\scheme{(u16/be)} - a big-endian short integer}
|
||||
;;> \item{\scheme{(fixed-string <length>)} - a fixed-length utf-8 string}
|
||||
;;> \item{\scheme{(padded-string <length> (pad <pad-char>))} - a utf-8 string padded to a given length}
|
||||
;;> \item{\scheme{(octal <length>)} - an integer in octal string format}
|
||||
;;> \item{\scheme{(decimal <length>)} - an integer in decimal string format}
|
||||
;;> \item{\scheme{(hexadecimal <length>)} - an integer in hexadecimal string format}
|
||||
;;> ]
|
||||
;;>
|
||||
;;> In addition, the field can be a literal (char, string or
|
||||
;;> bytevector), for instance as a file magic sequence or fixed
|
||||
;;> separator. The fields (and any constants) are serialized in the
|
||||
;;> order they appear in the block. For example, the header of a GIF
|
||||
;;> file could be defined as:
|
||||
;;>
|
||||
;;> \example{
|
||||
;;> (define-binary-record-type gif-header
|
||||
;;> (make: make-gif-header)
|
||||
;;> (pred: gif-header?)
|
||||
;;> (read: read-gif-header)
|
||||
;;> (write: write-gif-header)
|
||||
;;> (block:
|
||||
;;> "GIF89a"
|
||||
;;> (width (u16/le) gif-header-width)
|
||||
;;> (height (u16/le) gif-header-height)
|
||||
;;> (gct (u8) gif-header-gct)
|
||||
;;> (bgcolor (u8) gif-header-gbcolor)
|
||||
;;> (aspect-ratio (u8) gif-header-aspect-ratio)
|
||||
;;> ))
|
||||
;;> }
|
||||
;;>
|
||||
;;> For a more complex example see the \scheme{(chibi tar)}
|
||||
;;> implementation.
|
||||
;;>
|
||||
;;> The binary type itself is a macro used to expand to a predicate
|
||||
;;> and reader/writer procedures, which can be defined with
|
||||
;;> \scheme{define-binary-type}. For example,
|
||||
;;>
|
||||
;;> \example{
|
||||
;;> (define-binary-type (u8)
|
||||
;;> (lambda (x) (and (exact-integer? x) (<= 0 x 255)))
|
||||
;;> read-u8
|
||||
;;> write-u8)
|
||||
;;> }
|
||||
|
||||
(define-syntax define-binary-record-type
|
||||
(syntax-rules ()
|
||||
((define-binary-record-type name x ...)
|
||||
(defrec (x ...) name hidden-make hidden-pred hidden-read hidden-write
|
||||
() () ()))))
|
||||
|
||||
(define-syntax defrec
|
||||
(syntax-rules (make: pred: read: write: block:)
|
||||
((defrec () n m p r w
|
||||
((field-tmp field-read field-read-expr field-write field-write-expr field-get) ...)
|
||||
((field getter . s) ...)
|
||||
(def-setter ...))
|
||||
(begin
|
||||
(define-record-type n (m field ...) p
|
||||
(field getter . s) ...)
|
||||
(define r
|
||||
(let ((field-read field-read-expr) ...)
|
||||
(lambda (in)
|
||||
(let* ((field-tmp (field-read in)) ...)
|
||||
(m field ...)))))
|
||||
(define w
|
||||
(let ((field-write field-write-expr) ...)
|
||||
(lambda (x out)
|
||||
(field-write (field-get x) out) ...)))
|
||||
def-setter ...)
|
||||
;; workaround for impls which strip hygiene from top-level defs
|
||||
;; for some reason, works in chicken but not across libraries
|
||||
;;
|
||||
;; (begin
|
||||
;; (define-values (n m p getter ... setter ...)
|
||||
;; (let ()
|
||||
;; (define-record-type n (m field ...) p
|
||||
;; (field getter . s) ...)
|
||||
;; (def setter val) ...
|
||||
;; (values (record-rtd n) m p getter ... setter ...)))
|
||||
;; (define r
|
||||
;; (let ((field-read field-read-expr) ...)
|
||||
;; (lambda (in)
|
||||
;; (let* ((field-tmp (field-read in)) ...)
|
||||
;; (m field ...)))))
|
||||
;; (define w
|
||||
;; (let ((field-write field-write-expr) ...)
|
||||
;; (lambda (x out)
|
||||
;; (field-write (field-get x) out) ...))))
|
||||
)
|
||||
((defrec ((make: x) . rest) n m p r w b f s)
|
||||
(defrec rest n x p r w b f s))
|
||||
((defrec ((pred: x) . rest) n m p r w b f s)
|
||||
(defrec rest n m x r w b f s))
|
||||
((defrec ((read: x) . rest) n m p r w b f s)
|
||||
(defrec rest n m p x w b f s))
|
||||
((defrec ((write: x) . rest) n m p r w b f s)
|
||||
(defrec rest n m p r x b f s))
|
||||
((defrec ((block: (field (type . args) getter setter) . fields) . rest) n m p r w b f s)
|
||||
(defrec ((block: (field (type . args) getter setter tmp-setter) . fields) . rest) n m p r w b f s))
|
||||
((defrec ((block: (field (type . args) getter setter tmp-setter) . fields) . rest) n m p r w
|
||||
(b ...) (f ...) (s ...))
|
||||
(defrec ((block: . fields) . rest) n m p r w
|
||||
(b ...
|
||||
(field read-tmp (type read: args) write-tmp (type write: args) getter))
|
||||
(f ...
|
||||
(field getter tmp-setter))
|
||||
(s ...
|
||||
(define setter
|
||||
(let ((pred? (type pred: args)))
|
||||
(lambda (x val)
|
||||
(if (not (pred? val))
|
||||
(error "invalid val for" 'field val))
|
||||
(tmp-setter x val)))))))
|
||||
((defrec ((block: (field (type . args) getter) . fields) . rest) n m p r w
|
||||
(b ...) (f ...) s)
|
||||
(defrec ((block: . fields) . rest) n m p r w
|
||||
(b ...
|
||||
(field read-tmp (type read: args) write-tmp (type write: args) getter))
|
||||
(f ...
|
||||
(field getter))
|
||||
s))
|
||||
((defrec ((block: (field . x)) . rest) n m p r w b f s)
|
||||
(syntax-error "invalid field in block" (field . x)))
|
||||
((defrec ((block: data . fields) . rest) n m p r w (b ...) f s)
|
||||
(defrec ((block: . fields) . rest) n m p r w
|
||||
(b ...
|
||||
(tmp-data read-tmp (read-literal 'data) write-tmp (write-literal 'data) (lambda (x) x)))
|
||||
f
|
||||
s))
|
||||
((defrec ((block:) . rest) n m p r w b f s)
|
||||
(defrec rest n m p r w b f s))
|
||||
))
|
|
@ -1,46 +0,0 @@
|
|||
|
||||
(define-library (chibi binary-record)
|
||||
(import (scheme base) (srfi 1))
|
||||
(cond-expand
|
||||
((library (srfi 151)) (import (srfi 151)))
|
||||
((library (srfi 33)) (import (srfi 33)))
|
||||
(else (import (srfi 60))))
|
||||
(cond-expand
|
||||
((library (srfi 130)) (import (srfi 130)))
|
||||
(else (import (srfi 13))))
|
||||
(cond-expand
|
||||
;; ((library (auto))
|
||||
;; (import (only (auto) make: pred: read: write: block:)))
|
||||
(else
|
||||
;; indirect exports for chicken
|
||||
(export defrec define-auxiliary-syntax syntax-let-optionals*)
|
||||
(begin
|
||||
(define-syntax define-auxiliary-syntax
|
||||
(syntax-rules ()
|
||||
((define-auxiliary-syntax name)
|
||||
(define-syntax name
|
||||
(syntax-rules ()
|
||||
((name . x)
|
||||
(syntax-error "invalid use of auxiliary syntax"
|
||||
(name . x))))))))
|
||||
(define-auxiliary-syntax make:)
|
||||
(define-auxiliary-syntax pred:)
|
||||
(define-auxiliary-syntax read:)
|
||||
(define-auxiliary-syntax write:)
|
||||
(define-auxiliary-syntax block:))))
|
||||
(export
|
||||
;; interface
|
||||
define-binary-record-type
|
||||
;; binary types
|
||||
u8 u16/le u16/be padded-string fixed-string
|
||||
octal decimal hexadecimal
|
||||
;; auxiliary syntax
|
||||
make: pred: read: write: block:
|
||||
;; new types
|
||||
define-binary-type)
|
||||
(include "binary-types.scm")
|
||||
(cond-expand
|
||||
(chicken
|
||||
(include "binary-record-chicken.scm"))
|
||||
(else
|
||||
(include "binary-record.scm"))))
|
|
@ -1,160 +0,0 @@
|
|||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; utilities
|
||||
|
||||
(define (read-u16/be in)
|
||||
(let* ((i (read-u8 in))
|
||||
(j (read-u8 in)))
|
||||
(if (eof-object? j)
|
||||
(error "end of input")
|
||||
(+ (arithmetic-shift i 8) j))))
|
||||
|
||||
(define (read-u16/le in)
|
||||
(let* ((i (read-u8 in))
|
||||
(j (read-u8 in)))
|
||||
(if (eof-object? j)
|
||||
(error "end of input")
|
||||
(+ (arithmetic-shift j 8) i))))
|
||||
|
||||
(define (assert-read-u8 in i)
|
||||
(let ((i2 (read-u8 in)))
|
||||
(if (not (eqv? i i2))
|
||||
(error "unmatched value, expected: " i " but got: " i2)
|
||||
i2)))
|
||||
|
||||
(define (assert-read-char in ch)
|
||||
(let ((ch2 (read-char in)))
|
||||
(if (not (eqv? ch ch2))
|
||||
(error "unmatched value, expected: " ch " but got: " ch2)
|
||||
ch2)))
|
||||
|
||||
(define (assert-read-string in s)
|
||||
(let ((s2 (read-string (string-length s) in)))
|
||||
(if (not (equal? s s2))
|
||||
(error "unmatched value, expected: " s " but got: " s2)
|
||||
s2)))
|
||||
|
||||
(define (assert-read-bytevector in bv)
|
||||
(let ((bv2 (read-bytevector (bytevector-length bv) in)))
|
||||
(if (not (equal? bv bv2))
|
||||
(error "unmatched value, expected: " bv " but got: " bv2)
|
||||
bv2)))
|
||||
|
||||
(define (assert-read-integer in len radix)
|
||||
(let* ((s (string-trim-both (read-string len in)
|
||||
(lambda (ch) (or (eqv? ch #\space) (eqv? ch #\null)))))
|
||||
(n (if (equal? s "") 0 (string->number s radix))))
|
||||
(or n (error "invalid number syntax: " s))))
|
||||
|
||||
(define (read-padded-string in len pad)
|
||||
(string-trim-right (read-string len in) pad))
|
||||
|
||||
(define (read-literal val)
|
||||
(cond
|
||||
((integer? val) (lambda (in) (assert-read-u8 in val)))
|
||||
((char? val) (lambda (in) (assert-read-char in val)))
|
||||
((string? val) (lambda (in) (assert-read-string in val)))
|
||||
((bytevector? val) (lambda (in) (assert-read-bytevector in val)))
|
||||
(else (error "unknown binary literal: " val))))
|
||||
|
||||
(define (write-literal val)
|
||||
(cond
|
||||
((integer? val) (lambda (x out) (write-u8 val out)))
|
||||
((char? val) (lambda (x out) (write-char val out)))
|
||||
((string? val) (lambda (x out) (write-string val out)))
|
||||
((bytevector? val) (lambda (x out) (write-bytevector val out)))
|
||||
(else (error "unknown binary literal: " val))))
|
||||
|
||||
(define (write-padded-integer out n radix len left-pad-ch right-pad-ch)
|
||||
(let ((s (string-pad (number->string n radix) (- len 1) left-pad-ch)))
|
||||
(cond
|
||||
((>= (string-length s) len)
|
||||
(error "number too large for width" n radix len))
|
||||
(else
|
||||
(write-string s out)
|
||||
(write-char right-pad-ch out)))))
|
||||
|
||||
(define (write-u16/be n out)
|
||||
(write-u8 (arithmetic-shift n -8) out)
|
||||
(write-u8 (bitwise-and n #xFF) out))
|
||||
|
||||
(define (write-u16/le n out)
|
||||
(write-u8 (bitwise-and n #xFF) out)
|
||||
(write-u8 (arithmetic-shift n -8) out))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; syntax
|
||||
|
||||
(define-syntax syntax-let-optionals*
|
||||
(syntax-rules ()
|
||||
((syntax-let-optionals* () type-args expr)
|
||||
expr)
|
||||
((syntax-let-optionals* ((param default) . rest) (arg0 . args) expr)
|
||||
(let ((param arg0))
|
||||
(syntax-let-optionals* rest args expr)))
|
||||
((syntax-let-optionals* ((param default) . rest) () expr)
|
||||
(let ((param default))
|
||||
(syntax-let-optionals* rest () expr)))
|
||||
((syntax-let-optionals* (param . rest) (arg0 . args) expr)
|
||||
(let ((param arg0))
|
||||
(syntax-let-optionals* rest args expr)))
|
||||
((syntax-let-optionals* (param . rest) () expr)
|
||||
(syntax-error "missing required parameter" param expr))))
|
||||
|
||||
(define-syntax define-binary-type
|
||||
(syntax-rules ()
|
||||
((define-binary-type (name params ...) gen-pred gen-read gen-write)
|
||||
(define-syntax name
|
||||
(syntax-rules (pred: read: write:)
|
||||
((name pred: type-args)
|
||||
(syntax-let-optionals* (params ...) type-args gen-pred))
|
||||
((name read: type-args)
|
||||
(syntax-let-optionals* (params ...) type-args gen-read))
|
||||
((name write: type-args)
|
||||
(syntax-let-optionals* (params ...) type-args gen-write)))))))
|
||||
|
||||
(define-binary-type (u8)
|
||||
(lambda (x) (and (exact-integer? x) (<= 0 x 255)))
|
||||
read-u8
|
||||
write-u8)
|
||||
|
||||
(define-binary-type (u16/le)
|
||||
(lambda (x) (and (exact-integer? x) (<= 0 x 65536)))
|
||||
read-u16/le
|
||||
write-u16/le)
|
||||
|
||||
(define-binary-type (u16/be)
|
||||
(lambda (x) (and (exact-integer? x) (<= 0 x 65536)))
|
||||
read-u16/be
|
||||
write-u16/be)
|
||||
|
||||
(define-binary-type (padded-string len (pad #\null))
|
||||
(lambda (x) (and (string? x) (<= (string-length x) len)))
|
||||
(lambda (in) (read-padded-string in len pad))
|
||||
(lambda (str out)
|
||||
(write-string (string-pad-right str len pad) out)))
|
||||
|
||||
(define-binary-type (fixed-string len)
|
||||
(lambda (x) (and (string? x) (= (string-length x) len)))
|
||||
(lambda (in)
|
||||
(read-string len in))
|
||||
(lambda (str out)
|
||||
(write-string str out)))
|
||||
|
||||
(define-binary-type (octal len)
|
||||
exact-integer?
|
||||
(lambda (in) (assert-read-integer in len 8))
|
||||
(lambda (n out)
|
||||
(write-padded-integer out n 8 len #\0 #\null)))
|
||||
|
||||
(define-binary-type (decimal len)
|
||||
exact-integer?
|
||||
(lambda (in) (assert-read-integer in len 10))
|
||||
(lambda (n out)
|
||||
(write-padded-integer out n 10 len #\0 #\null)))
|
||||
|
||||
(define-binary-type (hexadecimal len)
|
||||
exact-integer?
|
||||
(lambda (in) (assert-read-integer in len 16))
|
||||
(lambda (n out)
|
||||
(write-padded-integer out n 16 len #\0 #\null)))
|
|
@ -1,81 +0,0 @@
|
|||
|
||||
(define-library (chibi bytevector-test)
|
||||
(export run-tests)
|
||||
(import (scheme base) (chibi bytevector) (chibi test))
|
||||
(begin
|
||||
|
||||
(define floats
|
||||
`(0.0 -1.0 #i1/3 1.192092896E-07 ,(+ 1 1.192092896E-07)
|
||||
1e-23 -1e-23
|
||||
3.40282346638528860e+38 -3.40282346638528860e+38
|
||||
1.40129846432481707e-45 -1.40129846432481707e-45
|
||||
3.14159265358979323846))
|
||||
|
||||
(define f32-le
|
||||
'#u8(#x00 #x00 #x00 #x00 #x00 #x00 #x80 #xbf
|
||||
#xab #xaa #xaa #x3e #x00 #x00 #x00 #x34
|
||||
#x01 #x00 #x80 #x3f #x9a #x6d #x41 #x19
|
||||
#x9a #x6d #x41 #x99 #xff #xff #x7f #x7f
|
||||
#xff #xff #x7f #xff #x01 #x00 #x00 #x00
|
||||
#x01 #x00 #x00 #x80 #xdb #x0f #x49 #x40))
|
||||
|
||||
(define f64-le
|
||||
'#u8(#x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00
|
||||
#x00 #x00 #x00 #x00 #x00 #x00 #xf0 #xbf
|
||||
#x55 #x55 #x55 #x55 #x55 #x55 #xd5 #x3f
|
||||
#x68 #x5f #x1c #x00 #x00 #x00 #x80 #x3e
|
||||
#x00 #x00 #x00 #x20 #x00 #x00 #xf0 #x3f
|
||||
#x51 #xb2 #x12 #x40 #xb3 #x2d #x28 #x3b
|
||||
#x51 #xb2 #x12 #x40 #xb3 #x2d #x28 #xbb
|
||||
#x00 #x00 #x00 #xe0 #xff #xff #xef #x47
|
||||
#x00 #x00 #x00 #xe0 #xff #xff #xef #xc7
|
||||
#x00 #x00 #x00 #x00 #x00 #x00 #xa0 #x36
|
||||
#x00 #x00 #x00 #x00 #x00 #x00 #xa0 #xb6
|
||||
#x18 #x2d #x44 #x54 #xfb #x21 #x09 #x40))
|
||||
|
||||
(define (run-tests)
|
||||
(test-begin "bytevector")
|
||||
|
||||
(test-group "reading ieee"
|
||||
|
||||
(do ((ls floats (cdr ls))
|
||||
(i 0 (+ i 4)))
|
||||
((null? ls))
|
||||
(test (car ls) (bytevector-ieee-single-native-ref f32-le i)))
|
||||
|
||||
(do ((ls floats (cdr ls))
|
||||
(i 0 (+ i 8)))
|
||||
((null? ls))
|
||||
(test (car ls) (bytevector-ieee-double-native-ref f64-le i))))
|
||||
|
||||
(test-group "writing ieee"
|
||||
|
||||
(do ((ls floats (cdr ls))
|
||||
(i 0 (+ i 4)))
|
||||
((null? ls))
|
||||
(let ((bv (make-bytevector 4 0)))
|
||||
(bytevector-ieee-single-native-set! bv 0 (car ls))
|
||||
(test (bytevector-copy f32-le i (+ i 4)) (values bv))))
|
||||
|
||||
(do ((ls floats (cdr ls))
|
||||
(i 0 (+ i 8)))
|
||||
((null? ls))
|
||||
(let ((bv (make-bytevector 8 0)))
|
||||
(bytevector-ieee-double-native-set! bv 0 (car ls))
|
||||
;;(test (bytevector-copy f64-le i (+ i 8)) (values bv))
|
||||
(test (car ls)
|
||||
(bytevector-ieee-double-native-ref bv 0)))))
|
||||
|
||||
(test-group "ber integers"
|
||||
(do ((ls '(0 1 128 16383 32767
|
||||
18446744073709551615
|
||||
340282366920938463463374607431768211456)
|
||||
(cdr ls)))
|
||||
((null? ls))
|
||||
(let ((bv (make-bytevector 256)))
|
||||
(do ((offsets '(0 1 27) (cdr offsets)))
|
||||
((null? offsets))
|
||||
(bytevector-ber-set! bv (car ls) (car offsets))
|
||||
(test (car ls) (bytevector-ber-ref bv (car offsets)))))))
|
||||
|
||||
(test-end))))
|
|
@ -1,146 +0,0 @@
|
|||
|
||||
;;> \section{Additional accessors}
|
||||
|
||||
;;> Retrieve a 16-bit unsigned integer value from the given bytevector
|
||||
;;> \var{bv} at offset \var{i}, in little-endian order.
|
||||
|
||||
(define (bytevector-u16-ref-le bv i)
|
||||
(+ (bytevector-u8-ref bv i)
|
||||
(arithmetic-shift (bytevector-u8-ref bv (+ i 1)) 8)))
|
||||
|
||||
;;> Retrieve a 16-bit unsigned integer value from the given bytevector
|
||||
;;> \var{bv} at offset \var{i}, in big-endian order.
|
||||
|
||||
(define (bytevector-u16-ref-be bv i)
|
||||
(+ (arithmetic-shift (bytevector-u8-ref bv i) 8)
|
||||
(bytevector-u8-ref bv (+ i 1))))
|
||||
|
||||
;;> Retrieve a 32-bit unsigned integer value from the given bytevector
|
||||
;;> \var{bv} at offset \var{i}, in little-endian order.
|
||||
|
||||
(define (bytevector-u32-ref-le bv i)
|
||||
(+ (bytevector-u8-ref bv i)
|
||||
(arithmetic-shift (bytevector-u8-ref bv (+ i 1)) 8)
|
||||
(arithmetic-shift (bytevector-u8-ref bv (+ i 2)) 16)
|
||||
(arithmetic-shift (bytevector-u8-ref bv (+ i 3)) 24)))
|
||||
|
||||
;;> Retrieve a 32-bit unsigned integer value from the given bytevector
|
||||
;;> \var{bv} at offset \var{i}, in big-endian order.
|
||||
|
||||
(define (bytevector-u32-ref-be bv i)
|
||||
(+ (arithmetic-shift (bytevector-u8-ref bv i) 24)
|
||||
(arithmetic-shift (bytevector-u8-ref bv (+ i 1)) 16)
|
||||
(arithmetic-shift (bytevector-u8-ref bv (+ i 2)) 8)
|
||||
(bytevector-u8-ref bv (+ i 3))))
|
||||
|
||||
;;> \section{Bignum encodings}
|
||||
|
||||
;;> A BER compressed integer (X.209) is an unsigned integer in base 128,
|
||||
;;> most significant digit first, where the high bit is set on all but the
|
||||
;;> final (least significant) byte. Thus any size integer can be
|
||||
;;> encoded, but the encoding is efficient and small integers don't take
|
||||
;;> up any more space than they would in normal char/short/int encodings.
|
||||
|
||||
(define (bytevector-ber-ref bv . o)
|
||||
(let ((end (if (and (pair? o) (pair? (cdr o)))
|
||||
(cadr o)
|
||||
(bytevector-length bv))))
|
||||
(let lp ((acc 0) (i (if (pair? o) (car o) 0)))
|
||||
(if (>= i end)
|
||||
(error "unterminated ber integer in bytevector" bv)
|
||||
(let ((b (bytevector-u8-ref bv i)))
|
||||
(if (< b 128)
|
||||
(+ acc b)
|
||||
(lp (arithmetic-shift (+ acc (bitwise-and b 127)) 7)
|
||||
(+ i 1))))))))
|
||||
|
||||
(define (bytevector-ber-set! bv n . o)
|
||||
;;(assert (integer? number) (not (negative? number)))
|
||||
(let ((start (if (pair? o) (car o) 0))
|
||||
(end (if (and (pair? o) (pair? (cdr o)))
|
||||
(cadr o)
|
||||
(bytevector-length bv))))
|
||||
(let lp ((n (arithmetic-shift n -7))
|
||||
(ls (list (bitwise-and n 127))))
|
||||
(if (zero? n)
|
||||
(do ((i start (+ i 1))
|
||||
(ls ls (cdr ls)))
|
||||
((null? ls))
|
||||
(if (>= i end)
|
||||
(error "integer doesn't fit in bytevector as ber"
|
||||
bv n start end)
|
||||
(bytevector-u8-set! bv i (car ls))))
|
||||
(lp (arithmetic-shift n -7)
|
||||
(cons (+ 128 (bitwise-and n 127)) ls))))))
|
||||
|
||||
;;> \section{Integer conversion}
|
||||
|
||||
;;> Convert an unsigned integer \var{n} to a bytevector representing
|
||||
;;> the base-256 big-endian form (the zero index holds the MSB).
|
||||
|
||||
(define (integer->bytevector n)
|
||||
(cond
|
||||
((zero? n)
|
||||
(make-bytevector 1 0))
|
||||
((negative? n)
|
||||
(error "can't convert a negative integer to bytevector" n))
|
||||
(else
|
||||
(let lp ((n n) (res '()))
|
||||
(if (zero? n)
|
||||
(let* ((len (length res))
|
||||
(bv (make-bytevector len 0)))
|
||||
(do ((i 0 (+ i 1))
|
||||
(ls res (cdr ls)))
|
||||
((= i len) bv)
|
||||
(bytevector-u8-set! bv i (car ls))))
|
||||
(lp (quotient n 256) (cons (remainder n 256) res)))))))
|
||||
|
||||
;;> The inverse of \scheme{integer->bytevector}. Convert a bytevector
|
||||
;;> representing the base-256 big-endian form (the zero index holds
|
||||
;;> the MSB) to the corresponding unsigned integer.
|
||||
|
||||
(define (bytevector->integer bv)
|
||||
(let ((len (bytevector-length bv)))
|
||||
(let lp ((i 0) (n 0))
|
||||
(if (>= i len)
|
||||
n
|
||||
(lp (+ i 1)
|
||||
(+ (arithmetic-shift n 8)
|
||||
(bytevector-u8-ref bv i)))))))
|
||||
|
||||
;;> Utility to pad a bytevector with zeros. Padding is added to the
|
||||
;;> left so as not to change the big-endian value.
|
||||
|
||||
(define (bytevector-pad-left bv len)
|
||||
(let ((diff (- len (bytevector-length bv))))
|
||||
(if (positive? diff)
|
||||
(bytevector-append bv (make-bytevector diff 0))
|
||||
bv)))
|
||||
|
||||
;;> \section{Hex string conversion}
|
||||
|
||||
;;> Big-endian conversion, guaranteed padded to even length.
|
||||
|
||||
(define (integer->hex-string n)
|
||||
(let* ((res (number->string n 16))
|
||||
(len (string-length res)))
|
||||
(if (even? len)
|
||||
res
|
||||
(string-append "0" res))))
|
||||
|
||||
(define (hex-string->integer str)
|
||||
(string->number str 16))
|
||||
|
||||
(define (bytevector->hex-string bv)
|
||||
(let ((out (open-output-string))
|
||||
(len (bytevector-length bv)))
|
||||
(let lp ((i 0))
|
||||
(cond
|
||||
((>= i len)
|
||||
(get-output-string out))
|
||||
(else
|
||||
(write-string (integer->hex-string (bytevector-u8-ref bv i)) out)
|
||||
(lp (+ i 1)))))))
|
||||
|
||||
(define (hex-string->bytevector str)
|
||||
(integer->bytevector (hex-string->integer str)))
|
|
@ -1,41 +0,0 @@
|
|||
|
||||
;;> Additional bytevector utilities.
|
||||
|
||||
(define-library (chibi bytevector)
|
||||
(export
|
||||
bytevector-u16-ref-le bytevector-u16-ref-be
|
||||
bytevector-u32-ref-le bytevector-u32-ref-be
|
||||
bytevector-ber-ref bytevector-ber-set!
|
||||
bytevector-pad-left
|
||||
integer->bytevector bytevector->integer
|
||||
integer->hex-string hex-string->integer
|
||||
bytevector->hex-string hex-string->bytevector
|
||||
bytevector-ieee-single-ref
|
||||
bytevector-ieee-single-native-ref
|
||||
bytevector-ieee-single-set!
|
||||
bytevector-ieee-single-native-set!
|
||||
bytevector-ieee-double-ref
|
||||
bytevector-ieee-double-native-ref
|
||||
bytevector-ieee-double-set!
|
||||
bytevector-ieee-double-native-set!
|
||||
)
|
||||
(import (scheme base) (scheme inexact))
|
||||
(cond-expand
|
||||
(big-endian
|
||||
(begin
|
||||
(define-syntax native-endianness
|
||||
(syntax-rules () ((_) 'big)))))
|
||||
(else
|
||||
(begin
|
||||
(define-syntax native-endianness
|
||||
(syntax-rules () ((_) 'little))))))
|
||||
(cond-expand
|
||||
((library (srfi 151)) (import (srfi 151)))
|
||||
((library (srfi 33)) (import (srfi 33)))
|
||||
(else (import (srfi 60))))
|
||||
(include "bytevector.scm")
|
||||
(cond-expand
|
||||
(chibi
|
||||
(import (except (scheme bytevector) bytevector-copy!)))
|
||||
(else
|
||||
(include "ieee-754.scm"))))
|
|
@ -26,7 +26,7 @@
|
|||
(set-cdr! rear new))
|
||||
(else ; sending to empty channel
|
||||
(channel-front-set! chan new)
|
||||
(condition-variable-broadcast! (channel-condvar chan)))))
|
||||
(condition-variable-signal! (channel-condvar chan)))))
|
||||
(mutex-unlock! (channel-mutex chan)))
|
||||
|
||||
(define (channel-receive! chan)
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
|
||||
(define-library (chibi channel)
|
||||
(cond-expand
|
||||
(chibi (import (chibi) (srfi 9)))
|
||||
(else (import (scheme base))))
|
||||
(import (srfi 18))
|
||||
(import (chibi) (srfi 9) (srfi 18))
|
||||
(export Channel make-channel channel? channel-empty?
|
||||
channel-send! channel-receive!)
|
||||
(include "channel.scm"))
|
||||
|
|
|
@ -1,12 +1,9 @@
|
|||
|
||||
;;> A minimal character set library.
|
||||
|
||||
(define-library (chibi char-set)
|
||||
(import (chibi char-set base) (chibi char-set extras))
|
||||
(import (chibi) (chibi char-set base) (chibi char-set extras))
|
||||
(export
|
||||
Char-Set char-set? char-set-contains?
|
||||
char-set ucs-range->char-set char-set-copy char-set-size
|
||||
char-set-fold char-set-for-each
|
||||
list->char-set char-set->list string->char-set char-set->string
|
||||
char-set-adjoin! char-set-adjoin char-set-union char-set-union!
|
||||
char-set-intersection char-set-intersection!
|
||||
|
|
|
@ -1,42 +1,42 @@
|
|||
;; char-set:lower-case
|
||||
(define char-set:lower-case (immutable-char-set (%make-iset 97 127 67108863 #f #f)))
|
||||
(define char-set:lower-case (immutable-char-set (%make-iset 97 122 #f #f #f)))
|
||||
|
||||
;; char-set:upper-case
|
||||
(define char-set:upper-case (immutable-char-set (%make-iset 65 127 67108863 #f #f)))
|
||||
(define char-set:upper-case (immutable-char-set (%make-iset 65 90 #f #f #f)))
|
||||
|
||||
;; char-set:title-case
|
||||
(define char-set:title-case (immutable-char-set (%make-iset 0 0 0 #f #f)))
|
||||
|
||||
;; char-set:letter
|
||||
(define char-set:letter (immutable-char-set (%make-iset 65 127 288230371923853311 #f #f)))
|
||||
(define char-set:letter (immutable-char-set (%make-iset 97 122 #f (%make-iset 65 90 #f #f #f) #f)))
|
||||
|
||||
;; char-set:punctuation
|
||||
(define char-set:punctuation (immutable-char-set (%make-iset 33 127 6189700203056200029306911735 #f #f)))
|
||||
(define char-set:punctuation (immutable-char-set (%make-iset 63 64 #f (%make-iset 44 47 #f (%make-iset 37 42 #f (%make-iset 33 35 #f #f #f) #f) (%make-iset 58 59 #f #f #f)) (%make-iset 123 123 #f (%make-iset 95 95 #f (%make-iset 91 93 #f #f #f) #f) (%make-iset 125 125 #f #f #f)))))
|
||||
|
||||
;; char-set:symbol
|
||||
(define char-set:symbol (immutable-char-set (%make-iset 36 127 1547425050547877224499904641 #f #f)))
|
||||
(define char-set:symbol (immutable-char-set (%make-iset 94 94 #f (%make-iset 43 43 #f (%make-iset 36 36 #f #f #f) (%make-iset 60 62 #f #f #f)) (%make-iset 124 124 #f (%make-iset 96 96 #f #f #f) (%make-iset 126 126 #f #f #f)))))
|
||||
|
||||
;; char-set:blank
|
||||
(define char-set:blank (immutable-char-set (%make-iset 9 32 8388609 #f #f)))
|
||||
(define char-set:blank (immutable-char-set (%make-iset 32 32 #f (%make-iset 9 9 #f #f #f) #f)))
|
||||
|
||||
;; char-set:whitespace
|
||||
(define char-set:whitespace (immutable-char-set (%make-iset 9 127 8388639 #f #f)))
|
||||
(define char-set:whitespace (immutable-char-set (%make-iset 32 32 #f (%make-iset 9 13 #f #f #f) #f)))
|
||||
|
||||
;; char-set:digit
|
||||
(define char-set:digit (immutable-char-set (%make-iset 48 57 #f #f #f)))
|
||||
|
||||
;; char-set:letter+digit
|
||||
(define char-set:letter+digit (immutable-char-set (%make-iset 48 127 37778931308803301180415 #f #f)))
|
||||
(define char-set:letter+digit (immutable-char-set (%make-iset 65 90 #f (%make-iset 48 57 #f #f #f) (%make-iset 97 122 #f #f #f))))
|
||||
|
||||
;; char-set:hex-digit
|
||||
(define char-set:hex-digit (immutable-char-set (%make-iset 48 102 35465847073801215 #f #f)))
|
||||
(define char-set:hex-digit (immutable-char-set (%make-iset 65 70 #f (%make-iset 48 57 #f #f #f) (%make-iset 97 102 #f #f #f))))
|
||||
|
||||
;; char-set:iso-control
|
||||
(define char-set:iso-control (immutable-char-set (%make-iset 0 127 170141183460469231731687303720179073023 #f #f)))
|
||||
(define char-set:iso-control (immutable-char-set (%make-iset 127 127 #f (%make-iset 0 31 #f #f #f) #f)))
|
||||
|
||||
;; char-set:graphic
|
||||
(define char-set:graphic (immutable-char-set (%make-iset 33 127 19807040628566084398385987583 #f #f)))
|
||||
(define char-set:graphic (immutable-char-set (%make-iset 33 126 #f #f #f)))
|
||||
|
||||
;; char-set:printing
|
||||
(define char-set:printing (immutable-char-set (%make-iset 9 127 332306998946228968225951765061697567 #f #f)))
|
||||
(define char-set:printing (immutable-char-set (%make-iset 32 126 #f (%make-iset 9 13 #f #f #f) #f)))
|
||||
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
|
||||
(define-library (chibi char-set ascii)
|
||||
(import (chibi) (chibi iset base) (chibi char-set base))
|
||||
(export char-set:lower-case char-set:upper-case char-set:title-case
|
||||
(import (chibi) (chibi iset base))
|
||||
(export char-set-contains?
|
||||
char-set:lower-case char-set:upper-case char-set:title-case
|
||||
char-set:letter char-set:digit char-set:letter+digit
|
||||
char-set:graphic char-set:printing char-set:whitespace
|
||||
char-set:iso-control char-set:punctuation char-set:symbol
|
||||
char-set:hex-digit char-set:blank)
|
||||
char-set:hex-digit char-set:blank char-set:ascii
|
||||
char-set:empty char-set:full)
|
||||
(include "ascii.scm"))
|
||||
|
|
|
@ -1,23 +1,14 @@
|
|||
|
||||
(define-library (chibi char-set base)
|
||||
(cond-expand
|
||||
(chibi
|
||||
(import (chibi))
|
||||
(begin
|
||||
(define-syntax immutable-char-set
|
||||
(sc-macro-transformer
|
||||
(lambda (expr use-env)
|
||||
(eval (cadr expr) use-env))))))
|
||||
(else
|
||||
(import (scheme base))
|
||||
(begin
|
||||
(define-syntax immutable-char-set
|
||||
(syntax-rules () ((immutable-char-set cs) cs))))))
|
||||
(import (chibi iset base))
|
||||
(import (chibi) (chibi iset base))
|
||||
(export (rename Integer-Set Char-Set)
|
||||
(rename iset? char-set?)
|
||||
immutable-char-set
|
||||
char-set-contains?)
|
||||
(begin
|
||||
(define-syntax immutable-char-set
|
||||
(sc-macro-transformer
|
||||
(lambda (expr use-env)
|
||||
(eval (cadr expr) use-env))))
|
||||
(define (char-set-contains? cset ch)
|
||||
(iset-contains? cset (char->integer ch)))))
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,29 +0,0 @@
|
|||
;; Character sets for Unicode boundaries, TR29.
|
||||
;; This code is written by Alex Shinn and placed in the
|
||||
;; Public Domain. All warranties are disclaimed.
|
||||
|
||||
;;> Char-sets used for
|
||||
;;> \hyperlink["http://unicode.org/reports/tr29/"]{TR29} word
|
||||
;;> boundaries.
|
||||
|
||||
(define-library (chibi char-set boundary)
|
||||
(cond-expand
|
||||
(chibi (import (chibi)))
|
||||
(else (import (scheme base))))
|
||||
(cond-expand
|
||||
((library (chibi char-set)) (import (chibi char-set)))
|
||||
(else
|
||||
(import (srfi 14))
|
||||
(begin (define (immutable-char-set cs) cs))))
|
||||
(export char-set:regional-indicator
|
||||
char-set:extend-or-spacing-mark
|
||||
char-set:hangul-l
|
||||
char-set:hangul-v
|
||||
char-set:hangul-t
|
||||
char-set:hangul-lv
|
||||
char-set:hangul-lvt)
|
||||
;; generated with:
|
||||
;; tools/extract-unicode-props.scm --derived GraphemeBreakProperty.txt
|
||||
;; Control extend-or-spacing-mark=Extend,SpacingMark Regional_Indicator
|
||||
;; hangul-l=:L hangul-v=:V hangul-t=:T hangul-lv=:LV hangul-lvt=:LVT
|
||||
(include "boundary.scm"))
|
|
@ -2,24 +2,16 @@
|
|||
(define (char-set . args)
|
||||
(list->char-set args))
|
||||
|
||||
(define (ucs-range->char-set start end . o)
|
||||
(let ((res (make-iset start (- end 1))))
|
||||
(if (and (pair? o) (pair? (cdr o)))
|
||||
(iset-union res (cadr o))
|
||||
res)))
|
||||
;; This is a mistake in the SRFI-14 design - end should be inclusive.
|
||||
(define (ucs-range->char-set start end)
|
||||
(make-iset start (- end 1)))
|
||||
|
||||
(define char-set-copy iset-copy)
|
||||
|
||||
(define char-set-size iset-size)
|
||||
|
||||
(define (char-set-fold kons knil cset)
|
||||
(iset-fold (lambda (i acc) (kons (integer->char i) acc)) knil cset))
|
||||
|
||||
(define (char-set-for-each proc cset)
|
||||
(iset-for-each (lambda (i) (proc (integer->char i))) cset))
|
||||
|
||||
(define (list->char-set ls . o)
|
||||
(apply list->iset (map char->integer ls) o))
|
||||
(define (list->char-set ls)
|
||||
(list->iset (map char->integer ls)))
|
||||
(define (char-set->list cset)
|
||||
(map integer->char (iset->list cset)))
|
||||
|
||||
|
@ -28,10 +20,10 @@
|
|||
(define (char-set->string cset)
|
||||
(list->string (char-set->list cset)))
|
||||
|
||||
(define (char-set-adjoin! cset . o)
|
||||
(apply iset-adjoin! cset (map char->integer o)))
|
||||
(define (char-set-adjoin cset . o)
|
||||
(apply iset-adjoin cset (map char->integer o)))
|
||||
(define (char-set-adjoin! cset ch)
|
||||
(iset-adjoin! cset (char->integer ch)))
|
||||
(define (char-set-adjoin cset ch)
|
||||
(iset-adjoin cset (char->integer ch)))
|
||||
|
||||
(define char-set-union iset-union)
|
||||
(define char-set-union! iset-union!)
|
||||
|
|
|
@ -1,13 +1,9 @@
|
|||
|
||||
(define-library (chibi char-set extras)
|
||||
(cond-expand
|
||||
(chibi (import (chibi)))
|
||||
(else (import (scheme base))))
|
||||
(import (chibi iset) (chibi char-set base))
|
||||
(import (chibi) (chibi iset) (chibi char-set base))
|
||||
(include "extras.scm")
|
||||
(export
|
||||
char-set ucs-range->char-set char-set-copy char-set-size
|
||||
char-set-fold char-set-for-each
|
||||
list->char-set char-set->list string->char-set char-set->string
|
||||
char-set-adjoin! char-set-adjoin char-set-union char-set-union!
|
||||
char-set-intersection char-set-intersection!
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,511 +0,0 @@
|
|||
;; config.scm -- general configuration management
|
||||
;; Copyright (c) 2012 Alex Shinn. All rights reserved.
|
||||
;; BSD-style license: http://synthcode.com/license.txt
|
||||
|
||||
;;> This is a library for unified configuration management.
|
||||
;;> Essentially it provides an abstract collection data type for
|
||||
;;> looking up named values, two or more of which can be chained
|
||||
;;> together. Values from more recent collections can be preferred as
|
||||
;;> with an environment, or the values at multiple levels can be
|
||||
;;> flattened together. Convenience routines are provided from
|
||||
;;> loading these collections from files while allowing extensions
|
||||
;;> such as configurations from command-line options.
|
||||
|
||||
;;> \section{Background}
|
||||
;;>
|
||||
;;> As any application grows to sufficient complexity, it acquires
|
||||
;;> options and behaviors that one may want to modify at startup or
|
||||
;;> runtime. The traditional approach is a combination of
|
||||
;;> command-line options, config files, environment variables, and/or
|
||||
;;> other specialized settings. These all have various pros and cons:
|
||||
;;>
|
||||
;;> \table[(@ (border 1) (style border-collapse:collapse) (width "100%"))]{
|
||||
;;> \tr{\th{name} \th{pros} \th{cons}}
|
||||
;;> \tr{\td{environment variables}
|
||||
;;> \td{implicit - no need to retype; can share between applications}
|
||||
;;> \td{unclear when set; unexpected differences between users; limited size}}
|
||||
;;> \tr{\td{command-line options}
|
||||
;;> \td{explicit - visible each time a command is run; }
|
||||
;;> \td{verbose; limited size}}
|
||||
;;> \tr{\td{config files}
|
||||
;;> \td{implicit; preserved - can be shared and version controlled}
|
||||
;;> \td{requires a parser}}
|
||||
;;> }
|
||||
;;>
|
||||
;;> Environment variables are convenient for broad preferences, used
|
||||
;;> by many different applications, and unlikely to change per user.
|
||||
;;> Command-line options are best for settings that are likely to
|
||||
;;> change between invocations of a program. Anything else is best
|
||||
;;> stored in a config file. If there are settings that multiple
|
||||
;;> users of a group or whole system are likely to want to share, then
|
||||
;;> it makes sense to cascade multiple config files.
|
||||
|
||||
;;> \section{Syntax}
|
||||
;;>
|
||||
;;> With any other language there is a question of config file syntax,
|
||||
;;> and a few popular choices exist such as .ini syntax. With Scheme
|
||||
;;> the obvious choice is sexps, generally as an alist. We use a
|
||||
;;> single alist for the whole file, with symbols for keys and
|
||||
;;> arbitrary sexps for values. The alists are intended primarily for
|
||||
;;> editing by hand and need not be dotted, but the interface allows
|
||||
;;> dotted values. Disambiguation is handled as with two separate
|
||||
;;> functions, \scheme{(conf-get config key)} and
|
||||
;;> \scheme{(conf-get-list config key)}, which both retrieve the value
|
||||
;;> associated with \var{key} from \var{config}, in the latter case
|
||||
;;> coercing to a list. The result is determined according to the
|
||||
;;> structure of the alist cell as follows:
|
||||
;;>
|
||||
;;> \table[(@ (border 1) (style border-collapse:collapse) (width "100%"))]{
|
||||
;;> \tr{\th{Cell} \th{\scheme{conf-get} result} \th{\scheme{conf-get-list} result}}
|
||||
;;> \tr{\td{\scheme{(key)}} \td{\scheme{()}} \td{\scheme{()}}}
|
||||
;;> \tr{\td{\scheme{(key . non-list-value)}} \td{\scheme{non-list-value}} \td{\scheme{(non-list-value)}}}
|
||||
;;> \tr{\td{\scheme{(key non-list-value)}} \td{\scheme{non-list-value}} \td{\scheme{(non-list-value)}}}
|
||||
;;> \tr{\td{\scheme{(key (value1 value2 ...))}} \td{\scheme{(value1 value2 ...)}} \td{\scheme{(value1 value2 ...)}}}
|
||||
;;> \tr{\td{\scheme{(key value1 value2 ...)}} \td{\scheme{(value1 value2 ...)}} \td{\scheme{(value1 value2 ...)}}}
|
||||
;;> }
|
||||
;;>
|
||||
;;> Thus writing the non-dotted value will always do what you want.
|
||||
;;> Specifically, the only thing to be careful of is if you want a
|
||||
;;> single-element list value, even with \scheme{conf-get}, you should
|
||||
;;> write \scheme{(key (value))}.
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;;> \section{Interface}
|
||||
|
||||
;;> Returns true iff \var{x} is a config object.
|
||||
|
||||
(define-record-type Config
|
||||
(%make-conf alist parent source timestamp)
|
||||
conf?
|
||||
(alist conf-alist conf-alist-set!)
|
||||
(parent conf-parent conf-parent-set!)
|
||||
(source conf-source conf-source-set!)
|
||||
(timestamp conf-timestamp conf-timestamp-set!))
|
||||
|
||||
(define (make-conf alist parent source timestamp)
|
||||
(if (not (alist? alist))
|
||||
(error "config requires an alist" alist)
|
||||
(%make-conf alist parent source timestamp)))
|
||||
|
||||
(define (assq-tail key alist)
|
||||
(let lp ((ls alist))
|
||||
(and (pair? ls)
|
||||
(if (and (pair? (car ls)) (eq? key (caar ls)))
|
||||
ls
|
||||
(lp (cdr ls))))))
|
||||
|
||||
(define (assq-chain key alist)
|
||||
(let ((x (assq-tail (car key) alist)))
|
||||
(and x
|
||||
(if (null? (cdr key))
|
||||
(car x)
|
||||
(or (assq-chain (cdr key) (cdar x))
|
||||
(assq-chain key (cdr x)))))))
|
||||
|
||||
(define (assq-split key alist)
|
||||
(let lp ((ls alist) (rev '()))
|
||||
(cond
|
||||
((null? ls) #f)
|
||||
((and (pair? (car ls)) (eq? key (caar ls))) (cons (reverse rev) ls))
|
||||
(else (lp (cdr ls) (cons (car ls) rev))))))
|
||||
|
||||
(define (read-from-file file . opt)
|
||||
(guard (exn
|
||||
(else
|
||||
(warn "couldn't load config:" file)
|
||||
(print-exception exn)
|
||||
(print-stack-trace exn)
|
||||
(and (pair? opt) (car opt))))
|
||||
(call-with-input-file file read)))
|
||||
|
||||
(define (alist? x)
|
||||
(and (list? x) (every pair? x)))
|
||||
|
||||
;;> \procedure{(assoc-get alist key [equal? [default]])}
|
||||
|
||||
;;> Utility analogous to \scheme{conf-get} on a pure alist. Returns
|
||||
;;> the value of the cell in \var{alist} whose car is \var{equal?} to
|
||||
;;> \var{key}, where the value is determined as the \var{cadr} if the
|
||||
;;> cell is a proper list of two elements and the \var{cdr} otherwise.
|
||||
;;> If no cell is found, returns \var{default}, or \scheme{#f} if
|
||||
;;> unspecified.
|
||||
|
||||
(define (assoc-get alist key . o)
|
||||
(let ((equal (or (and (pair? o) (car o)) equal?)))
|
||||
(let lp ((ls alist))
|
||||
(cond
|
||||
((not (pair? ls)) (and (pair? o) (pair? (cdr o)) (cadr o)))
|
||||
((and (pair? (car ls)) (equal key (caar ls)))
|
||||
(if (and (pair? (cdar ls)) (null? (cdr (cdar ls))))
|
||||
(car (cdar ls))
|
||||
(cdar ls)))
|
||||
(else (lp (cdr ls)))))))
|
||||
|
||||
;;> \procedure{(assoc-get-list alist key [default])}
|
||||
|
||||
;;> Equivalent to \scheme{assoc-get} but coerces its result to a list
|
||||
;;> as described in the syntax section.
|
||||
|
||||
(define (assoc-get-list alist key . o)
|
||||
(let ((res (assoc-get alist key)))
|
||||
(if res
|
||||
(if (or (pair? res) (null? res)) res (list res))
|
||||
(if (pair? o) (car o) '()))))
|
||||
|
||||
;;> Returns just the base of \var{config} without any parent.
|
||||
|
||||
(define (conf-head config)
|
||||
(make-conf
|
||||
(conf-alist config) #f (conf-source config) (conf-timestamp config)))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Loading from files.
|
||||
|
||||
;;> \procedure{(conf-load file [conf])}
|
||||
|
||||
;;> Loads the config file \var{file}, prepending to \var{conf} if
|
||||
;;> provided.
|
||||
|
||||
(define (conf-load file . o)
|
||||
(make-conf
|
||||
(read-from-file file '())
|
||||
(and (pair? o) (car o))
|
||||
file
|
||||
(current-second)))
|
||||
|
||||
;;> Search for and load any files named \var{file} in the
|
||||
;;> \var{config-path}, which should be a list of strings.
|
||||
|
||||
(define (conf-load-in-path config-path file)
|
||||
(cond
|
||||
((equal? file "")
|
||||
(error "can't load from empty filename" file))
|
||||
((eqv? #\/ (string-ref file 0))
|
||||
(conf-load file))
|
||||
(else
|
||||
(let lp ((ls (reverse config-path)) (res #f))
|
||||
(if (null? ls)
|
||||
(or res (make-conf '() #f #f (current-second)))
|
||||
(let ((path (string-append (car ls) "/" file)))
|
||||
(if (file-exists? path)
|
||||
(lp (cdr ls) (conf-load path res))
|
||||
(lp (cdr ls) res))))))))
|
||||
|
||||
;;> \procedure{(conf-load-cascaded config-path file [include-keyword])}
|
||||
|
||||
;;> Similar to conf-load-in-path, but also recursively loads any
|
||||
;;> "include" config files, indicated by a top-level
|
||||
;;> \var{include-keyword} with either a string or symbol value.
|
||||
;;> Includes are loaded relative to the current file, and cycles
|
||||
;;> automatically ignored.
|
||||
|
||||
(define (conf-load-cascaded config-path file . o)
|
||||
(define (path-directory file)
|
||||
(let lp ((i (string-length file)))
|
||||
(cond ((zero? i) "./")
|
||||
((eqv? #\/ (string-ref file (- i 1))) (substring file 0 i))
|
||||
(else (lp (- i 1))))))
|
||||
(define (path-relative file from)
|
||||
(if (eqv? #\/ (string-ref file 0))
|
||||
file
|
||||
(string-append (path-directory from) file)))
|
||||
(let ((include-keyword (if (pair? o) (car o) 'include)))
|
||||
(let load ((ls (list (cons file (and (pair? o) (pair? (cdr o)) (cadr o)))))
|
||||
(seen '())
|
||||
(res '()))
|
||||
(cond
|
||||
((null? ls)
|
||||
res)
|
||||
(else
|
||||
(let ((file (if (symbol? (caar ls))
|
||||
(symbol->string (caar ls))
|
||||
(caar ls)))
|
||||
(depth (cdar ls)))
|
||||
(cond
|
||||
((member file seen)
|
||||
(load (cdr ls) seen res))
|
||||
((and (number? depth) (<= depth 0))
|
||||
(load (cdr ls) seen res))
|
||||
(else
|
||||
(let* ((config (conf-load-in-path config-path file))
|
||||
(includes (conf-get-list config include-keyword)))
|
||||
(load (append (cdr ls)
|
||||
(map (lambda (x)
|
||||
(cons (path-relative x file)
|
||||
(and (number? depth) (- depth 1))))
|
||||
includes))
|
||||
(cons file seen)
|
||||
(append res config)))))))))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(define (conf-get-cell config key)
|
||||
(cond
|
||||
((pair? key)
|
||||
(cond
|
||||
((null? (cdr key)) (conf-get-cell config (car key)))
|
||||
((assq-chain key (conf-alist config)))
|
||||
((conf-parent config) => (lambda (p) (conf-get-cell p key)))
|
||||
(else #f)))
|
||||
(else
|
||||
(let search ((config config))
|
||||
(and config
|
||||
(or (assq key (conf-alist config))
|
||||
(search (conf-parent config))))))))
|
||||
|
||||
;;> \procedure{(conf-get config key [default])}
|
||||
|
||||
;;> Basic config lookup - retrieves the value from \var{config}
|
||||
;;> associated with \var{key}. If not present, return \var{default}.
|
||||
;;> In \scheme{conf-get} and related accessors \var{key} can be either
|
||||
;;> a symbol, or a list of symbols. In the latter case, each symbol
|
||||
;;> is used as a key in turn, with the value taken as an alist to
|
||||
;;> further lookup values in.
|
||||
|
||||
(define (conf-get config key . opt)
|
||||
(let ((cell (conf-get-cell config key)))
|
||||
(if (not cell)
|
||||
(and (pair? opt) (car opt))
|
||||
(if (and (pair? (cdr cell)) (null? (cddr cell)))
|
||||
(cadr cell)
|
||||
(cdr cell)))))
|
||||
|
||||
;;> \procedure{(conf-get-list config key [default])}
|
||||
|
||||
;;> Equivalent to \scheme{conf-get} but coerces its result to a list
|
||||
;;> as described in the syntax section.
|
||||
|
||||
(define (conf-get-list config key . opt)
|
||||
(let ((res (conf-get config key)))
|
||||
(if res
|
||||
(if (or (pair? res) (null? res)) res (list res))
|
||||
(if (pair? opt) (car opt) '()))))
|
||||
|
||||
;;> Equivalent to \scheme{conf-get} but always returns the
|
||||
;;> \scheme{cdr} as-is without possibly taking its \scheme{car}.
|
||||
|
||||
(define (conf-get-cdr config key . opt)
|
||||
(let ((cell (conf-get-cell config key)))
|
||||
(if (not cell)
|
||||
(and (pair? opt) (car opt))
|
||||
(cdr cell))))
|
||||
|
||||
;;> Equivalent to \scheme{conf-get-list} but returns a list of all
|
||||
;;> cascaded configs appended together.
|
||||
|
||||
(define (conf-get-multi config key)
|
||||
(if (not config)
|
||||
'()
|
||||
(append (conf-get-list (conf-head config) key)
|
||||
(conf-get-multi (conf-parent config) key))))
|
||||
|
||||
;;> Extends the config with anadditional alist.
|
||||
|
||||
(define (conf-extend config alist . o)
|
||||
(let ((source (and (pair? o) (car o))))
|
||||
(if (pair? alist)
|
||||
(make-conf alist config source (current-second))
|
||||
config)))
|
||||
|
||||
;;> Joins two configs.
|
||||
|
||||
(define (conf-append a b)
|
||||
(let ((parent (if (conf-parent a) (conf-append (conf-parent a) b) b)))
|
||||
(make-conf (conf-alist a) parent (conf-source a) (conf-timestamp a))))
|
||||
|
||||
;;> Utility to create an alist cell representing the chained key
|
||||
;;> \var{key} mapped to \var{value}.
|
||||
|
||||
(define (conf-unfold-key key value)
|
||||
(if (null? (cdr key))
|
||||
(cons (car key) value)
|
||||
(list (car key) (conf-unfold-key (cdr key) value))))
|
||||
|
||||
;;> Replace a new definition into the first config alist.
|
||||
|
||||
(define (conf-set config key value)
|
||||
(make-conf
|
||||
(let lp ((key (if (not (list? key)) (list key) key))
|
||||
(alist (conf-alist config)))
|
||||
(cond
|
||||
((null? (cdr key))
|
||||
(cons (cons (car key) value)
|
||||
(remove (lambda (x) (and (pair? x) (eq? (car key) (car x))))
|
||||
alist)))
|
||||
((assq-split (car key) alist)
|
||||
=> (lambda (x)
|
||||
(let ((left (car x))
|
||||
(right (cdr x)))
|
||||
(append left
|
||||
(cons (cons (car key) (lp (cdr key) (cdar right)))
|
||||
(cdr right))))))
|
||||
(else
|
||||
(cons (conf-unfold-key key value) alist))))
|
||||
(conf-parent config)
|
||||
(conf-source config)
|
||||
(conf-timestamp config)))
|
||||
|
||||
;;> Lift specialized sections to the top-level of a config.
|
||||
|
||||
(define (conf-specialize config key name)
|
||||
(let lp ((cfg config) (res '()))
|
||||
(if (not cfg)
|
||||
(make-conf (reverse res) config #f (current-second))
|
||||
(let* ((specialized (assq key (conf-alist cfg)))
|
||||
(named (and specialized (assq name (cdr specialized))))
|
||||
(next (conf-parent cfg)))
|
||||
(if named
|
||||
(lp next (cons (cdr named) res))
|
||||
(lp next res))))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;;> \section{Config Verification}
|
||||
|
||||
(define (conf-default-warn . args)
|
||||
(for-each
|
||||
(lambda (a) ((if (string? a) display write) a (current-error-port)))
|
||||
args)
|
||||
(newline (current-error-port))
|
||||
#f)
|
||||
|
||||
(define (conf-verify-symbol->predicate sym)
|
||||
(case sym
|
||||
((integer) integer?)
|
||||
((number) number?)
|
||||
((list) list?)
|
||||
((alist) alist?)
|
||||
((boolean) boolean?)
|
||||
((char) char?)
|
||||
((string) string?)
|
||||
((symbol) symbol?)
|
||||
((pair) pair?)
|
||||
((filename dirname) string?)
|
||||
(else (error "no known conf predicate for" sym))))
|
||||
|
||||
;; non-short-circuit versions to report all warnings
|
||||
|
||||
(define (and* . args)
|
||||
(every (lambda (x) x) args))
|
||||
|
||||
(define (every* pred ls)
|
||||
(apply and* (map pred ls)))
|
||||
|
||||
(define (conf-verify-match def cell warn)
|
||||
(define (cell-value)
|
||||
(if (and (pair? (cdr cell)) (null? (cddr cell))) (cadr cell) (cdr cell)))
|
||||
(define (cell-list)
|
||||
(if (and (pair? (cdr cell)) (null? (cddr cell)) (not (pair? (cadr cell))))
|
||||
(list (cadr cell))
|
||||
(cdr cell)))
|
||||
(cond
|
||||
((procedure? def)
|
||||
(or (def (cell-value))
|
||||
(warn "bad conf value for " (car cell) ": " (cell-value))))
|
||||
((symbol? def)
|
||||
(case def
|
||||
((existing-filename)
|
||||
(cond
|
||||
((not (string? (cell-value)))
|
||||
(warn "bad conf value for " (car cell)
|
||||
": expected a filename but got " (cell-value)))
|
||||
((not (file-exists? (cell-value)))
|
||||
(warn "conf setting ~S references a non-existent file: ~S"
|
||||
(car cell) (cell-value)))
|
||||
(else
|
||||
#t)))
|
||||
((existing-dirname)
|
||||
(cond
|
||||
((not (string? (cell-value)))
|
||||
(warn "bad conf value for " (car cell)
|
||||
": expected a dirname but got " (cell-value)))
|
||||
((not (file-directory? (cell-value)))
|
||||
(cond
|
||||
((file-exists? (cell-value))
|
||||
(warn "conf setting " (car cell)
|
||||
" expected a directory but found a file: " (cell-value)))
|
||||
(else
|
||||
(warn "conf setting " (car cell)
|
||||
" references a non-existent directory: " (cell-value)))))
|
||||
(else
|
||||
#t)))
|
||||
((integer number char string symbol filename dirname boolean pair)
|
||||
(or ((conf-verify-symbol->predicate def) (cell-value))
|
||||
(warn "bad conf value for " (car cell)
|
||||
": expected " def " but got " (cell-value))))
|
||||
((list alist)
|
||||
(or ((conf-verify-symbol->predicate def) (cell-list))
|
||||
(warn "bad conf value for " (car cell)
|
||||
": expected " def " but got " (cell-list))))
|
||||
(else
|
||||
(warn "bad conf spec list: " def))))
|
||||
((pair? def)
|
||||
(case (car def)
|
||||
((cons)
|
||||
(and*
|
||||
(conf-verify-match
|
||||
(cadr def) (cons `(car ,(car cell)) (car (cell-list))) warn)
|
||||
(conf-verify-match
|
||||
(car (cddr def)) (cons `(car ,(car cell)) (cdr (cell-list))) warn)))
|
||||
((list)
|
||||
(and (list? (cell-list))
|
||||
(every* (lambda (x)
|
||||
;; (cons `(list ,(car cell)) x)
|
||||
(conf-verify-match (cadr def) x warn))
|
||||
(cell-list))))
|
||||
((alist)
|
||||
(let ((key-def (cadr def))
|
||||
(val-def (if (pair? (cddr def)) (car (cddr def)) (lambda (x) #t))))
|
||||
(and (alist? (cell-list))
|
||||
(every* (lambda (x)
|
||||
(and (pair? x)
|
||||
(conf-verify-match key-def (car x) warn)
|
||||
(conf-verify-match val-def (cell-value) warn)))
|
||||
(cell-list)))))
|
||||
((conf)
|
||||
(and (alist? (cell-list))
|
||||
(conf-verify (cdr def) (list (cell-list)) warn)))
|
||||
((or)
|
||||
(or (any (lambda (x) (conf-verify-match x cell (lambda (x) x)))
|
||||
(cdr def))
|
||||
(warn "bad spec value for " (car cell)
|
||||
": expected " def " but got " (cell-value))))
|
||||
((member)
|
||||
(or (member (cell-value) (cdr def))
|
||||
(warn "bad spec value " (cell-value)
|
||||
" for " (car cell) ", expected one of " (cdr def))))
|
||||
((quote)
|
||||
(or (equal? (cadr def) (cell-value))
|
||||
(warn "bad conf value for " (car cell)
|
||||
": expected '" (cadr def) " but got " (cell-value))))
|
||||
(else
|
||||
(warn "bad conf list spec name: " (car def)))))
|
||||
(else
|
||||
(or (equal? def (cell-value))
|
||||
(warn "bad conf value for " (car cell)
|
||||
": expected " def " but got " (cell-value))))))
|
||||
|
||||
(define (conf-verify-one spec cell warn)
|
||||
(cond
|
||||
((not (pair? cell))
|
||||
(warn "bad config entry: " cell))
|
||||
((not (symbol? (car cell)))
|
||||
(warn "non-symbol config entry name: " (car cell)))
|
||||
(else
|
||||
(let ((def (assq (car cell) spec)))
|
||||
(cond
|
||||
((not def)
|
||||
(warn "unknown config entry: " (car cell)))
|
||||
((null? (cdr def)))
|
||||
(else (conf-verify-match (cadr def) cell warn)))))))
|
||||
|
||||
(define (conf-verify spec config . o)
|
||||
(let ((warn (if (pair? o) (car o) conf-default-warn)))
|
||||
(let lp ((config config))
|
||||
(cond
|
||||
(config
|
||||
(for-each
|
||||
(lambda (cell) (conf-verify-one spec cell warn))
|
||||
(conf-alist config))
|
||||
(lp (conf-parent config)))))))
|
|
@ -1,27 +0,0 @@
|
|||
|
||||
(define-library (chibi config)
|
||||
(export make-conf conf? conf-load conf-load-in-path conf-load-cascaded
|
||||
conf-verify conf-extend conf-append conf-set conf-unfold-key
|
||||
conf-get conf-get-list conf-get-cdr conf-get-multi
|
||||
conf-specialize read-from-file conf-source conf-head conf-parent
|
||||
assoc-get assoc-get-list)
|
||||
(import (scheme base) (scheme read) (scheme write) (scheme file)
|
||||
(scheme time) (srfi 1))
|
||||
;; This is only used for config verification, it's acceptable to
|
||||
;; substitute file existence for the stronger directory check.
|
||||
(cond-expand
|
||||
(chibi
|
||||
(import (only (meta) warn))
|
||||
(import (only (chibi) print-exception print-stack-trace))
|
||||
(import (only (chibi filesystem) file-directory?)))
|
||||
(else
|
||||
(begin
|
||||
(define file-directory? file-exists?)
|
||||
(define (print-exception exn) (write exn))
|
||||
(define (print-stack-trace . o) #f)
|
||||
(define (warn msg . args)
|
||||
(let ((err (current-error-port)))
|
||||
(display msg err)
|
||||
(for-each (lambda (x) (display " " err) (write x err)) args)
|
||||
(newline err))))))
|
||||
(include "config.scm"))
|
|
@ -1,39 +0,0 @@
|
|||
(c-include-verbatim "sha2.c")
|
||||
|
||||
;; \procedure{(start-sha type)}
|
||||
;;
|
||||
;; Allocates a new opaque computation context for a SHA-\var{type}
|
||||
;; digest, where \var{type} can be one of the following constants:
|
||||
;; \scheme{type-sha-224}, \scheme{type-sha-256}.
|
||||
|
||||
(define-c-struct sha_context)
|
||||
|
||||
(define-c sexp (start-sha "sexp_start_sha")
|
||||
((value ctx sexp) (value self sexp) unsigned-int (value NULL sha_context)))
|
||||
|
||||
(define-c-const unsigned-int (type-sha-224 "SHA_TYPE_224"))
|
||||
(define-c-const unsigned-int (type-sha-256 "SHA_TYPE_256"))
|
||||
|
||||
;; \procedure{(add-sha-data! sha-context data)}
|
||||
;;
|
||||
;; Adds a new piece of data into the given context. \var{data} can be
|
||||
;; a bytevector or a string. Bytevectors are added as sequences bytes.
|
||||
;; Strings are added as sequences of byte representations of their
|
||||
;; chars (which is either UTF-8 or ASCII code point sequence, depending
|
||||
;; on whether Chibi was compiled with Unicode support).
|
||||
;;
|
||||
;; It is an error to add more data into a context that was finalized
|
||||
;; by \scheme{get-sha}. This procedure returns an unspecified value.
|
||||
|
||||
(define-c sexp (add-sha-data! "sexp_add_sha_data")
|
||||
((value ctx sexp) (value self sexp) sha_context sexp))
|
||||
|
||||
;; \procedure{(get-sha sha-context)}
|
||||
;;
|
||||
;; Finalizes computation and returns resulting SHA-2 digest as a hex
|
||||
;; string (in lowercase). It is not possible to add more data with
|
||||
;; \scheme{add-sha-data!} after this call. Though, digest string can
|
||||
;; be retrieved multiple times from the same computation context.
|
||||
|
||||
(define-c sexp (get-sha "sexp_get_sha")
|
||||
((value ctx sexp) (value self sexp) sha_context))
|
|
@ -1,13 +0,0 @@
|
|||
(define-library (chibi crypto md5-test)
|
||||
(export run-tests)
|
||||
(import (scheme base) (chibi crypto md5) (chibi test))
|
||||
(begin
|
||||
(define (run-tests)
|
||||
(test-begin "md5")
|
||||
(test "d41d8cd98f00b204e9800998ecf8427e"
|
||||
(md5 ""))
|
||||
(test "900150983cd24fb0d6963f7d28e17f72"
|
||||
(md5 "abc"))
|
||||
(test "9e107d9d372bb6826bd81d3542a419d6"
|
||||
(md5 "The quick brown fox jumps over the lazy dog"))
|
||||
(test-end))))
|
|
@ -1,366 +0,0 @@
|
|||
;; md5.scm -- pure R7RS md5 implementation (originally from hato)
|
||||
;; Copyright (c) 2009-2014 Alex Shinn. All rights reserved.
|
||||
;; BSD-style license: http://synthcode.com/license.txt
|
||||
|
||||
;; Break computations down into 16-bit words to keep everything in
|
||||
;; fixnum even on 32-bit machines.
|
||||
|
||||
;; All values are in little-endian.
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Utilities.
|
||||
|
||||
(define (extract-byte n i)
|
||||
(bitwise-and #xFF (arithmetic-shift n (* i -8))))
|
||||
|
||||
;; integer->hex-string is big-endian, so we adjust here
|
||||
(define (hex-byte n)
|
||||
(if (< n 16)
|
||||
(string-append "0" (number->string n 16))
|
||||
(number->string n 16)))
|
||||
|
||||
(define (hex n)
|
||||
(string-append (hex-byte (remainder n 256))
|
||||
(hex-byte (quotient n 256))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;; 3. MD5 Algorithm Description
|
||||
|
||||
;; We begin by supposing that we have a b-bit message as input, and that
|
||||
;; we wish to find its message digest. Here b is an arbitrary
|
||||
;; nonnegative integer; b may be zero, it need not be a multiple of
|
||||
;; eight, and it may be arbitrarily large. We imagine the bits of the
|
||||
;; message written down as follows:
|
||||
|
||||
;; m_0 m_1 ... m_{b-1}
|
||||
|
||||
;; The following five steps are performed to compute the message digest
|
||||
;; of the message.
|
||||
|
||||
;; 3.1 Step 1. Append Padding Bits
|
||||
|
||||
;; The message is "padded" (extended) so that its length (in bits) is
|
||||
;; congruent to 448, modulo 512. That is, the message is extended so
|
||||
;; that it is just 64 bits shy of being a multiple of 512 bits long.
|
||||
;; Padding is always performed, even if the length of the message is
|
||||
;; already congruent to 448, modulo 512.
|
||||
|
||||
;; Padding is performed as follows: a single "1" bit is appended to the
|
||||
;; message, and then "0" bits are appended so that the length in bits of
|
||||
;; the padded message becomes congruent to 448, modulo 512. In all, at
|
||||
;; least one bit and at most 512 bits are appended.
|
||||
|
||||
;; 3.2 Step 2. Append Length
|
||||
|
||||
;; A 64-bit representation of b (the length of the message before the
|
||||
;; padding bits were added) is appended to the result of the previous
|
||||
;; step. In the unlikely event that b is greater than 2^64, then only
|
||||
;; the low-order 64 bits of b are used. (These bits are appended as two
|
||||
;; 32-bit words and appended low-order word first in accordance with the
|
||||
;; previous conventions.)
|
||||
|
||||
;; At this point the resulting message (after padding with bits and with
|
||||
;; b) has a length that is an exact multiple of 512 bits. Equivalently,
|
||||
;; this message has a length that is an exact multiple of 16 (32-bit)
|
||||
;; words. Let M[0 ... N-1] denote the words of the resulting message,
|
||||
;; where N is a multiple of 16.
|
||||
|
||||
;; 3.3 Step 3. Initialize MD Buffer
|
||||
|
||||
;; A four-word buffer (A,B,C,D) is used to compute the message digest.
|
||||
;; Here each of A, B, C, D is a 32-bit register. These registers are
|
||||
;; initialized to the following values in hexadecimal, low-order bytes
|
||||
;; first):
|
||||
|
||||
;; word A: 01 23 45 67
|
||||
;; word B: 89 ab cd ef
|
||||
;; word C: fe dc ba 98
|
||||
;; word D: 76 54 32 10
|
||||
|
||||
;; 3.4 Step 4. Process Message in 16-Word Blocks
|
||||
|
||||
;; We first define four auxiliary functions that each take as input
|
||||
;; three 32-bit words and produce as output one 32-bit word.
|
||||
|
||||
;; F(X,Y,Z) = XY v not(X) Z
|
||||
;; G(X,Y,Z) = XZ v Y not(Z)
|
||||
;; H(X,Y,Z) = X xor Y xor Z
|
||||
;; I(X,Y,Z) = Y xor (X v not(Z))
|
||||
|
||||
;; In each bit position F acts as a conditional: if X then Y else Z.
|
||||
;; The function F could have been defined using + instead of v since XY
|
||||
;; and not(X)Z will never have 1's in the same bit position.) It is
|
||||
;; interesting to note that if the bits of X, Y, and Z are independent
|
||||
;; and unbiased, the each bit of F(X,Y,Z) will be independent and
|
||||
;; unbiased.
|
||||
|
||||
;; The functions G, H, and I are similar to the function F, in that they
|
||||
;; act in "bitwise parallel" to produce their output from the bits of X,
|
||||
;; Y, and Z, in such a manner that if the corresponding bits of X, Y,
|
||||
;; and Z are independent and unbiased, then each bit of G(X,Y,Z),
|
||||
;; H(X,Y,Z), and I(X,Y,Z) will be independent and unbiased. Note that
|
||||
;; the function H is the bit-wise "xor" or "parity" function of its
|
||||
;; inputs.
|
||||
|
||||
;; This step uses a 64-element table T[1 ... 64] constructed from the
|
||||
;; sine function. Let T[i] denote the i-th element of the table, which
|
||||
;; is equal to the integer part of 4294967296 times abs(sin(i)), where i
|
||||
;; is in radians. The elements of the table are given in the appendix.
|
||||
|
||||
;; (define T
|
||||
;; (do ((i 64 (- i 1))
|
||||
;; (ls '()
|
||||
;; (cons (u32 (exact (truncate (* 4294967296 (abs (sin i))))))
|
||||
;; ls)))
|
||||
;; ((< i 0) (list->vector ls))))
|
||||
|
||||
(define T
|
||||
'#(0 0 #xd76a #xa478 #xe8c7 #xb756 #x2420 #x70db #xc1bd #xceee
|
||||
#xf57c #x0faf #x4787 #xc62a #xa830 #x4613 #xfd46 #x9501 #x6980 #x98d8
|
||||
#x8b44 #xf7af #xffff #x5bb1 #x895c #xd7be #x6b90 #x1122 #xfd98 #x7193
|
||||
#xa679 #x438e #x49b4 #x0821 #xf61e #x2562 #xc040 #xb340 #x265e #x5a51
|
||||
#xe9b6 #xc7aa #xd62f #x105d #x0244 #x1453 #xd8a1 #xe681 #xe7d3 #xfbc8
|
||||
#x21e1 #xcde6 #xc337 #x07d6 #xf4d5 #x0d87 #x455a #x14ed #xa9e3 #xe905
|
||||
#xfcef #xa3f8 #x676f #x02d9 #x8d2a #x4c8a #xfffa #x3942 #x8771 #xf681
|
||||
#x6d9d #x6122 #xfde5 #x380c #xa4be #xea44 #x4bde #xcfa9 #xf6bb #x4b60
|
||||
#xbebf #xbc70 #x289b #x7ec6 #xeaa1 #x27fa #xd4ef #x3085 #x0488 #x1d05
|
||||
#xd9d4 #xd039 #xe6db #x99e5 #x1fa2 #x7cf8 #xc4ac #x5665 #xf429 #x2244
|
||||
#x432a #xff97 #xab94 #x23a7 #xfc93 #xa039 #x655b #x59c3 #x8f0c #xcc92
|
||||
#xffef #xf47d #x8584 #x5dd1 #x6fa8 #x7e4f #xfe2c #xe6e0 #xa301 #x4314
|
||||
#x4e08 #x11a1 #xf753 #x7e82 #xbd3a #xf235 #x2ad7 #xd2bb #xeb86 #xd391))
|
||||
|
||||
;;> Returns the md5 checksum of \var{src} as a lowercase hex-string.
|
||||
;;> \var{src} can be any of a string (interpreted as utf8), a
|
||||
;;> bytevector, or a binary input port.
|
||||
|
||||
(define (md5 src)
|
||||
(let ((in (cond ((string? src) (open-input-bytevector (string->utf8 src)))
|
||||
((bytevector? src) (open-input-bytevector src))
|
||||
((input-port? src) src)
|
||||
(else (error "unknown digest source: " src))))
|
||||
;; 3.3 Step 3. Initialize MD Buffer
|
||||
(buf (make-bytevector 64 0))
|
||||
(vec (make-vector 32))
|
||||
(A1 #x6745) (A0 #x2301)
|
||||
(B1 #xefcd) (B0 #xab89)
|
||||
(C1 #x98ba) (C0 #xdcfe)
|
||||
(D1 #x1032) (D0 #x5476))
|
||||
;; Process each 16-word block.
|
||||
(let lp ((i 0)
|
||||
(pad #x80))
|
||||
(let* ((n (read-bytevector! buf in))
|
||||
(n (if (eof-object? n) 0 n)))
|
||||
(cond
|
||||
((< n 64)
|
||||
(let ((len (* 8 (+ i n))))
|
||||
;; 3.1 Step 1. Append Padding Bits
|
||||
(bytevector-u8-set! buf n pad)
|
||||
(do ((j (+ n 1) (+ j 1))) ((>= j 64))
|
||||
(bytevector-u8-set! buf j 0))
|
||||
;; 3.2 Step 2. Append Length
|
||||
(cond
|
||||
((< n 56)
|
||||
(bytevector-u8-set! buf 56 (extract-byte len 0))
|
||||
(bytevector-u8-set! buf 57 (extract-byte len 1))
|
||||
(bytevector-u8-set! buf 58 (extract-byte len 2))
|
||||
(bytevector-u8-set! buf 59 (extract-byte len 3))
|
||||
(bytevector-u8-set! buf 60 (extract-byte len 4))
|
||||
(bytevector-u8-set! buf 61 (extract-byte len 5))
|
||||
(bytevector-u8-set! buf 62 (extract-byte len 6))
|
||||
(bytevector-u8-set! buf 63 (extract-byte len 7)))))))
|
||||
;; 3.4 Step 4. Process Message in 16-Word Blocks
|
||||
;;
|
||||
;; Copy block i into X.
|
||||
(do ((j 0 (+ j 1)))
|
||||
((= j 16))
|
||||
(vector-set! vec (* j 2) (bytevector-u16-ref-le buf (* j 4)))
|
||||
(vector-set! vec
|
||||
(+ (* j 2) 1)
|
||||
(bytevector-u16-ref-le buf (+ (* j 4) 2))))
|
||||
;; Save A as AA, B as BB, C as CC, and D as DD.
|
||||
(let ((AA0 A0) (AA1 A1)
|
||||
(BB0 B0) (BB1 B1)
|
||||
(CC0 C0) (CC1 C1)
|
||||
(DD0 D0) (DD1 D1)
|
||||
(T1 0) (T0 0))
|
||||
(letrec-syntax
|
||||
((add
|
||||
(syntax-rules ()
|
||||
((add d1 d0 a1 a0 b1 b0)
|
||||
(begin
|
||||
(set! d0 (+ a0 b0))
|
||||
(set! d1 (bitwise-and
|
||||
(+ a1 b1 (arithmetic-shift d0 -16))
|
||||
#xFFFF))
|
||||
(set! d0 (bitwise-and d0 #xFFFF))))))
|
||||
(rot
|
||||
(syntax-rules ()
|
||||
((rot d1 d0 a1 a0 s)
|
||||
(let ((tmp a1))
|
||||
(set! d1 (bitwise-and
|
||||
(bitwise-ior (arithmetic-shift a1 s)
|
||||
(arithmetic-shift a1 (- s 32))
|
||||
(arithmetic-shift a0 (- s 16)))
|
||||
#xFFFF))
|
||||
(set! d0 (bitwise-and
|
||||
(bitwise-ior (arithmetic-shift a0 s)
|
||||
(arithmetic-shift a0 (- s 32))
|
||||
(arithmetic-shift tmp (- s 16)))
|
||||
#xFFFF))))))
|
||||
(bit-not
|
||||
(syntax-rules ()
|
||||
((bit-not a) (- (expt 2 16) a 1))))
|
||||
(FF
|
||||
(syntax-rules ()
|
||||
((FF d1 d0 x1 x0 y1 y0 z1 z0)
|
||||
(begin
|
||||
(set! d1 (bitwise-ior (bitwise-and x1 y1)
|
||||
(bitwise-and (bit-not x1) z1)))
|
||||
(set! d0 (bitwise-ior (bitwise-and x0 y0)
|
||||
(bitwise-and (bit-not x0) z0)))
|
||||
))))
|
||||
(GG
|
||||
(syntax-rules ()
|
||||
((GG d1 d0 x1 x0 y1 y0 z1 z0)
|
||||
(begin
|
||||
(set! d1 (bitwise-ior (bitwise-and x1 z1)
|
||||
(bitwise-and y1 (bit-not z1))))
|
||||
(set! d0 (bitwise-ior (bitwise-and x0 z0)
|
||||
(bitwise-and y0 (bit-not z0))))
|
||||
))))
|
||||
(HH
|
||||
(syntax-rules ()
|
||||
((HH d1 d0 x1 x0 y1 y0 z1 z0)
|
||||
(begin (set! d1 (bitwise-xor x1 y1 z1))
|
||||
(set! d0 (bitwise-xor x0 y0 z0))))))
|
||||
(II
|
||||
(syntax-rules ()
|
||||
((II d1 d0 x1 x0 y1 y0 z1 z0)
|
||||
(begin
|
||||
(set! d1 (bitwise-xor y1 (bitwise-ior x1 (bit-not z1))))
|
||||
(set! d0 (bitwise-xor y0 (bitwise-ior x0 (bit-not z0))))
|
||||
))))
|
||||
(R
|
||||
(syntax-rules ()
|
||||
((R op T1 T0 a1 a0 b1 b0 c1 c0 d1 d0 vec k s i)
|
||||
(begin
|
||||
(op T1 T0 b1 b0 c1 c0 d1 d0)
|
||||
(add T1 T0 T1 T0
|
||||
(vector-ref vec (+ (* k 2) 1))
|
||||
(vector-ref vec (* k 2)))
|
||||
(add T1 T0 T1 T0
|
||||
(vector-ref T (* i 2))
|
||||
(vector-ref T (+ (* i 2) 1)))
|
||||
(add a1 a0 a1 a0 T1 T0)
|
||||
(rot a1 a0 a1 a0 s)
|
||||
(add a1 a0 a1 a0 b1 b0)))))
|
||||
(R1 (syntax-rules ()
|
||||
((R1 T1 T0 a1 a0 b1 b0 c1 c0 d1 d0 vec k s i)
|
||||
(R FF T1 T0 a1 a0 b1 b0 c1 c0 d1 d0 vec k s i))))
|
||||
(R2 (syntax-rules ()
|
||||
((R2 T1 T0 a1 a0 b1 b0 c1 c0 d1 d0 vec k s i)
|
||||
(R GG T1 T0 a1 a0 b1 b0 c1 c0 d1 d0 vec k s i))))
|
||||
(R3 (syntax-rules ()
|
||||
((R3 T1 T0 a1 a0 b1 b0 c1 c0 d1 d0 vec k s i)
|
||||
(R HH T1 T0 a1 a0 b1 b0 c1 c0 d1 d0 vec k s i))))
|
||||
(R4 (syntax-rules ()
|
||||
((R4 T1 T0 a1 a0 b1 b0 c1 c0 d1 d0 vec k s i)
|
||||
(R II T1 T0 a1 a0 b1 b0 c1 c0 d1 d0 vec k s i)))))
|
||||
;; Round 1: Let [abcd k s i] denote the operation
|
||||
;; a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s)
|
||||
(R1 T1 T0 A1 A0 B1 B0 C1 C0 D1 D0 vec 0 7 1)
|
||||
(R1 T1 T0 D1 D0 A1 A0 B1 B0 C1 C0 vec 1 12 2)
|
||||
(R1 T1 T0 C1 C0 D1 D0 A1 A0 B1 B0 vec 2 17 3)
|
||||
(R1 T1 T0 B1 B0 C1 C0 D1 D0 A1 A0 vec 3 22 4)
|
||||
(R1 T1 T0 A1 A0 B1 B0 C1 C0 D1 D0 vec 4 7 5)
|
||||
(R1 T1 T0 D1 D0 A1 A0 B1 B0 C1 C0 vec 5 12 6)
|
||||
(R1 T1 T0 C1 C0 D1 D0 A1 A0 B1 B0 vec 6 17 7)
|
||||
(R1 T1 T0 B1 B0 C1 C0 D1 D0 A1 A0 vec 7 22 8)
|
||||
(R1 T1 T0 A1 A0 B1 B0 C1 C0 D1 D0 vec 8 7 9)
|
||||
(R1 T1 T0 D1 D0 A1 A0 B1 B0 C1 C0 vec 9 12 10)
|
||||
(R1 T1 T0 C1 C0 D1 D0 A1 A0 B1 B0 vec 10 17 11)
|
||||
(R1 T1 T0 B1 B0 C1 C0 D1 D0 A1 A0 vec 11 22 12)
|
||||
(R1 T1 T0 A1 A0 B1 B0 C1 C0 D1 D0 vec 12 7 13)
|
||||
(R1 T1 T0 D1 D0 A1 A0 B1 B0 C1 C0 vec 13 12 14)
|
||||
(R1 T1 T0 C1 C0 D1 D0 A1 A0 B1 B0 vec 14 17 15)
|
||||
(R1 T1 T0 B1 B0 C1 C0 D1 D0 A1 A0 vec 15 22 16)
|
||||
;; Round 2: Let [abcd k s i] denote the operation
|
||||
;; a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s)
|
||||
(R2 T1 T0 A1 A0 B1 B0 C1 C0 D1 D0 vec 1 5 17)
|
||||
(R2 T1 T0 D1 D0 A1 A0 B1 B0 C1 C0 vec 6 9 18)
|
||||
(R2 T1 T0 C1 C0 D1 D0 A1 A0 B1 B0 vec 11 14 19)
|
||||
(R2 T1 T0 B1 B0 C1 C0 D1 D0 A1 A0 vec 0 20 20)
|
||||
(R2 T1 T0 A1 A0 B1 B0 C1 C0 D1 D0 vec 5 5 21)
|
||||
(R2 T1 T0 D1 D0 A1 A0 B1 B0 C1 C0 vec 10 9 22)
|
||||
(R2 T1 T0 C1 C0 D1 D0 A1 A0 B1 B0 vec 15 14 23)
|
||||
(R2 T1 T0 B1 B0 C1 C0 D1 D0 A1 A0 vec 4 20 24)
|
||||
(R2 T1 T0 A1 A0 B1 B0 C1 C0 D1 D0 vec 9 5 25)
|
||||
(R2 T1 T0 D1 D0 A1 A0 B1 B0 C1 C0 vec 14 9 26)
|
||||
(R2 T1 T0 C1 C0 D1 D0 A1 A0 B1 B0 vec 3 14 27)
|
||||
(R2 T1 T0 B1 B0 C1 C0 D1 D0 A1 A0 vec 8 20 28)
|
||||
(R2 T1 T0 A1 A0 B1 B0 C1 C0 D1 D0 vec 13 5 29)
|
||||
(R2 T1 T0 D1 D0 A1 A0 B1 B0 C1 C0 vec 2 9 30)
|
||||
(R2 T1 T0 C1 C0 D1 D0 A1 A0 B1 B0 vec 7 14 31)
|
||||
(R2 T1 T0 B1 B0 C1 C0 D1 D0 A1 A0 vec 12 20 32)
|
||||
;; Round 3: Let [abcd k s i] denote the operation
|
||||
;; a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s)
|
||||
(R3 T1 T0 A1 A0 B1 B0 C1 C0 D1 D0 vec 5 4 33)
|
||||
(R3 T1 T0 D1 D0 A1 A0 B1 B0 C1 C0 vec 8 11 34)
|
||||
(R3 T1 T0 C1 C0 D1 D0 A1 A0 B1 B0 vec 11 16 35)
|
||||
(R3 T1 T0 B1 B0 C1 C0 D1 D0 A1 A0 vec 14 23 36)
|
||||
(R3 T1 T0 A1 A0 B1 B0 C1 C0 D1 D0 vec 1 4 37)
|
||||
(R3 T1 T0 D1 D0 A1 A0 B1 B0 C1 C0 vec 4 11 38)
|
||||
(R3 T1 T0 C1 C0 D1 D0 A1 A0 B1 B0 vec 7 16 39)
|
||||
(R3 T1 T0 B1 B0 C1 C0 D1 D0 A1 A0 vec 10 23 40)
|
||||
(R3 T1 T0 A1 A0 B1 B0 C1 C0 D1 D0 vec 13 4 41)
|
||||
(R3 T1 T0 D1 D0 A1 A0 B1 B0 C1 C0 vec 0 11 42)
|
||||
(R3 T1 T0 C1 C0 D1 D0 A1 A0 B1 B0 vec 3 16 43)
|
||||
(R3 T1 T0 B1 B0 C1 C0 D1 D0 A1 A0 vec 6 23 44)
|
||||
(R3 T1 T0 A1 A0 B1 B0 C1 C0 D1 D0 vec 9 4 45)
|
||||
(R3 T1 T0 D1 D0 A1 A0 B1 B0 C1 C0 vec 12 11 46)
|
||||
(R3 T1 T0 C1 C0 D1 D0 A1 A0 B1 B0 vec 15 16 47)
|
||||
(R3 T1 T0 B1 B0 C1 C0 D1 D0 A1 A0 vec 2 23 48)
|
||||
;; Round 4: Let [abcd k s i] denote the operation
|
||||
;; a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s)
|
||||
(R4 T1 T0 A1 A0 B1 B0 C1 C0 D1 D0 vec 0 6 49)
|
||||
(R4 T1 T0 D1 D0 A1 A0 B1 B0 C1 C0 vec 7 10 50)
|
||||
(R4 T1 T0 C1 C0 D1 D0 A1 A0 B1 B0 vec 14 15 51)
|
||||
(R4 T1 T0 B1 B0 C1 C0 D1 D0 A1 A0 vec 5 21 52)
|
||||
(R4 T1 T0 A1 A0 B1 B0 C1 C0 D1 D0 vec 12 6 53)
|
||||
(R4 T1 T0 D1 D0 A1 A0 B1 B0 C1 C0 vec 3 10 54)
|
||||
(R4 T1 T0 C1 C0 D1 D0 A1 A0 B1 B0 vec 10 15 55)
|
||||
(R4 T1 T0 B1 B0 C1 C0 D1 D0 A1 A0 vec 1 21 56)
|
||||
(R4 T1 T0 A1 A0 B1 B0 C1 C0 D1 D0 vec 8 6 57)
|
||||
(R4 T1 T0 D1 D0 A1 A0 B1 B0 C1 C0 vec 15 10 58)
|
||||
(R4 T1 T0 C1 C0 D1 D0 A1 A0 B1 B0 vec 6 15 59)
|
||||
(R4 T1 T0 B1 B0 C1 C0 D1 D0 A1 A0 vec 13 21 60)
|
||||
(R4 T1 T0 A1 A0 B1 B0 C1 C0 D1 D0 vec 4 6 61)
|
||||
(R4 T1 T0 D1 D0 A1 A0 B1 B0 C1 C0 vec 11 10 62)
|
||||
(R4 T1 T0 C1 C0 D1 D0 A1 A0 B1 B0 vec 2 15 63)
|
||||
(R4 T1 T0 B1 B0 C1 C0 D1 D0 A1 A0 vec 9 21 64)
|
||||
;; Then in increment each of the four registers by the
|
||||
;; value it had before this block was started.
|
||||
(add A1 A0 A1 A0 AA1 AA0)
|
||||
(add B1 B0 B1 B0 BB1 BB0)
|
||||
(add C1 C0 C1 C0 CC1 CC0)
|
||||
(add D1 D0 D1 D0 DD1 DD0)
|
||||
(cond
|
||||
((< n 64)
|
||||
;; 3.5 Step 5. Output
|
||||
;;
|
||||
;; The message digest produced as output is A, B, C,
|
||||
;; D. That is, we begin with the low-order byte of A,
|
||||
;; and end with the high-order byte of D.
|
||||
(if (>= n 56)
|
||||
(lp (+ i n) 0)
|
||||
(string-append
|
||||
(hex A0) (hex A1)
|
||||
(hex B0) (hex B1)
|
||||
(hex C0) (hex C1)
|
||||
(hex D0) (hex D1))))
|
||||
(else
|
||||
(lp (+ i 64) pad)))))))))
|
||||
|
||||
;; This completes the description of MD5. A reference implementation in
|
||||
;; C is given in the appendix.
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue