Compare commits
No commits in common. "6897f09e59329c46500b5274b1e738c3d84dff76" and "b8af92a1384834fe7dbdec01c76d1d0871921766" have entirely different histories.
6897f09e59
...
b8af92a138
9
.gitmodules
vendored
|
@ -7,12 +7,3 @@
|
|||
[submodule "source/engine/thirdparty/cgltf"]
|
||||
path = source/engine/thirdparty/cgltf
|
||||
url = https://github.com/jkuhlmann/cgltf.git
|
||||
[submodule "quickjs"]
|
||||
path = quickjs
|
||||
url = https://github.com/bellard/quickjs.git
|
||||
[submodule "source/engine/thirdparty/TinySoundFont"]
|
||||
path = source/engine/thirdparty/TinySoundFont
|
||||
url = https://github.com/schellingb/TinySoundFont.git
|
||||
[submodule "source/engine/thirdparty/dr_libs"]
|
||||
path = source/engine/thirdparty/dr_libs
|
||||
url = https://github.com/mackron/dr_libs.git
|
||||
|
|
7
LICENSE
|
@ -9,14 +9,9 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
(1) The above copyright notice and this permission notice shall be included in
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
(2) Any games or other derivative software must display the "Prosperon" logo
|
||||
at near the beginning of the software's startup, before the chief purpose
|
||||
of the software is underway.
|
||||
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
|
|
23
Makefile
|
@ -24,6 +24,9 @@ LEAK ?= 0
|
|||
INFO :=
|
||||
LD = $(CC)
|
||||
|
||||
#ifeq ($(CC), clang)
|
||||
# AR = llvm-ar
|
||||
#endif
|
||||
ifeq ($(CC), x86_64-w64-mingw32-gcc)
|
||||
AR = x86_64-w64-mingw32-ar
|
||||
endif
|
||||
|
@ -50,14 +53,6 @@ endif
|
|||
|
||||
CPPFLAGS += -ffast-math
|
||||
|
||||
ifeq ($(CC), emcc)
|
||||
LDFLAGS += #--closure 1
|
||||
CPPFLAGS += -O0
|
||||
OPT = 0
|
||||
DBG = 0
|
||||
AR = emar
|
||||
endif
|
||||
|
||||
ifeq ($(DBG),1)
|
||||
CPPFLAGS += -g
|
||||
INFO += _dbg
|
||||
|
@ -128,10 +123,12 @@ ifeq ($(OS), Windows_NT)
|
|||
UNZIP = unzip -o -q $(DISTDIR)/$(DIST) -d $(DESTDIR)
|
||||
else ifeq ($(CC), emcc)
|
||||
OS := Web
|
||||
LDFLAGS += -sMIN_WEBGL_VERSION=2 -sMAX_WEBGL_VERSION=2 -pthread -sTOTAL_MEMORY=128MB
|
||||
LDFLAGS += -sMIN_WEBGL_VERSION=2 -sMAX_WEBGL_VERSION=2 -pthread -sTOTAL_MEMORY=450MB
|
||||
CPPFLAGS += -pthread
|
||||
LDLIBS += pthread quickjs GL openal c m dl
|
||||
CC = emcc
|
||||
EXT = .html
|
||||
|
||||
else
|
||||
UNAME != uname -s
|
||||
ifeq ($(UNAME), Linux)
|
||||
|
@ -158,8 +155,8 @@ endif
|
|||
OBJDIR = $(BIN)/obj
|
||||
|
||||
# All other sources
|
||||
OBJS != find source/engine -type f -name '*.c' | grep -vE 'test|tool|example'
|
||||
CPPOBJS != find source/engine -type f -name '*.cpp' | grep -vE 'test|tool|example'
|
||||
OBJS != find source/engine -type f -name '*.c' | grep -vE 'test|tool'
|
||||
CPPOBJS != find source/engine -type f -name '*.cpp' | grep -vE 'test|tool'
|
||||
OBJS += $(CPPOBJS)
|
||||
OBJS += $(shell find source/engine -type f -name '*.m')
|
||||
OBJS := $(patsubst %.cpp, %.o, $(OBJS))
|
||||
|
@ -169,7 +166,7 @@ OBJS := $(addprefix $(BIN)/obj/, $(OBJS))
|
|||
|
||||
engineincs != find source/engine -maxdepth 1 -type d
|
||||
includeflag != find source -type d -name include
|
||||
includeflag += $(engineincs) source/engine/thirdparty/tinycdb source/shaders source/engine/thirdparty/sokol source/engine/thirdparty/stb source/engine/thirdparty/cgltf source/engine/thirdparty/TinySoundFont source/engine/thirdparty/dr_libs
|
||||
includeflag += $(engineincs) source/engine/thirdparty/tinycdb source/shaders source/engine/thirdparty/sokol source/engine/thirdparty/stb source/engine/thirdparty/cgltf
|
||||
includeflag := $(addprefix -I, $(includeflag))
|
||||
|
||||
# Adding different SDKs
|
||||
|
@ -259,7 +256,7 @@ input.md: $(INPUTMD)
|
|||
|
||||
$(BIN)/libquickjs.a: $(QUICKJS_O)
|
||||
make -C quickjs clean
|
||||
make -C quickjs SYSRT=$(SYSRT) TTARGET=$(TTARGET) ARCH=$(ARCH) DBG=$(DBG) OPT=$(OPT) AR=$(AR) OS=$(OS) libquickjs.a HOST_CC=$(CC) LEAK=$(LEAK)
|
||||
make -C quickjs SYSRT=$(SYSRT) TTARGET=$(TTARGET) ARCH=$(ARCH) DBG=$(DBG) OPT=$(OPT) AR=$(AR) OS=$(OS) libquickjs.a libquickjs.lto.a HOST_CC=$(CC) LEAK=$(LEAK)
|
||||
@mkdir -p $(BIN)
|
||||
cp -rf quickjs/libquickjs.* $(BIN)
|
||||
|
||||
|
|
6
README
|
@ -1,6 +0,0 @@
|
|||
![alt text](doc/prosperon_orb_horizontal.gif)
|
||||
The easily moddable, programming minded, 2D-first game engine. The aim is to make the fastest way to make games.
|
||||
|
||||
See the [documentation](doc/prosperon.org) for more information, including how to compile.
|
||||
|
||||
*Prosperon is useful, but is a work in progress. Breaking changes are frequent.*
|
2498
data/fastest_coeffs.h
Normal file
1908
data/gamecontrollerdb.txt
Normal file
340273
data/high_qual_coeffs.h
Normal file
22472
data/mid_qual_coeffs.h
Normal file
|
@ -33,9 +33,6 @@ Install the most [[https://prosperon.dev/download][recent binaries]] into your ~
|
|||
*** Windows
|
||||
Copy the executable into any folder and run it. If no game is deteced, it scaffolds for you.
|
||||
|
||||
*** Building
|
||||
You will need ~sokol-shdc~ in the top of your directory. Then, ~make shaders~ and ~make~. The command ~make install~ copies it to your home's ~.bin~ path.
|
||||
|
||||
** Playing your first game
|
||||
Download any of the completed example projects. Run ~prosperon play~ in the folder.
|
||||
|
||||
|
|
4
fonts/dos.font
Normal file
|
@ -0,0 +1,4 @@
|
|||
(font
|
||||
:path "LessPerfectDOSVGA.ttf"
|
||||
:size 16
|
||||
)
|
BIN
icons/icons8-bug-16.png
Normal file
After Width: | Height: | Size: 298 B |
BIN
icons/icons8-console-16.png
Normal file
After Width: | Height: | Size: 187 B |
BIN
icons/icons8-factory-16.png
Normal file
After Width: | Height: | Size: 225 B |
BIN
icons/icons8-gear-16.png
Normal file
After Width: | Height: | Size: 293 B |
BIN
icons/icons8-light-switch-16.png
Normal file
After Width: | Height: | Size: 157 B |
BIN
icons/icons8-lock-16.png
Normal file
After Width: | Height: | Size: 197 B |
BIN
icons/icons8-music-16.png
Normal file
After Width: | Height: | Size: 226 B |
BIN
icons/icons8-pause-16.png
Normal file
After Width: | Height: | Size: 108 B |
BIN
icons/icons8-radio-tower-16.png
Normal file
After Width: | Height: | Size: 339 B |
BIN
icons/icons8-record-16.png
Normal file
After Width: | Height: | Size: 234 B |
BIN
icons/icons8-resume-button-16.png
Normal file
After Width: | Height: | Size: 187 B |
BIN
icons/icons8-shuffle-16.png
Normal file
After Width: | Height: | Size: 224 B |
BIN
icons/icons8-skip-to-start-16.png
Normal file
After Width: | Height: | Size: 206 B |
BIN
icons/icons8-spotlight-16.png
Normal file
After Width: | Height: | Size: 304 B |
BIN
icons/no_tex.png
Normal file
After Width: | Height: | Size: 5.2 KiB |
1
quickjs
|
@ -1 +0,0 @@
|
|||
Subproject commit 6a89d7c27099be84e5312a7ec73205d6a7abe1b4
|
148
quickjs/Changelog
Normal file
|
@ -0,0 +1,148 @@
|
|||
2021-03-27:
|
||||
|
||||
- faster Array.prototype.push and Array.prototype.unshift
|
||||
- added JS_UpdateStackTop()
|
||||
- fixed Windows console
|
||||
- misc bug fixes
|
||||
|
||||
2020-11-08:
|
||||
|
||||
- improved function parameter initializers
|
||||
- added std.setenv(), std.unsetenv() and std.getenviron()
|
||||
- added JS_EvalThis()
|
||||
- misc bug fixes
|
||||
|
||||
2020-09-06:
|
||||
|
||||
- added logical assignment operators
|
||||
- added IsHTMLDDA support
|
||||
- faster for-of loops
|
||||
- os.Worker now takes a module filename as parameter
|
||||
- qjsc: added -D option to compile dynamically loaded modules or workers
|
||||
- misc bug fixes
|
||||
|
||||
2020-07-05:
|
||||
|
||||
- modified JS_GetPrototype() to return a live value
|
||||
- REPL: support unicode characters larger than 16 bits
|
||||
- added os.Worker
|
||||
- improved object serialization
|
||||
- added std.parseExtJSON
|
||||
- misc bug fixes
|
||||
|
||||
2020-04-12:
|
||||
|
||||
- added cross realm support
|
||||
- added AggregateError and Promise.any
|
||||
- added env, uid and gid options in os.exec()
|
||||
- misc bug fixes
|
||||
|
||||
2020-03-16:
|
||||
|
||||
- reworked error handling in std and os libraries: suppressed I/O
|
||||
exceptions in std FILE functions and return a positive errno value
|
||||
when it is explicit
|
||||
- output exception messages to stderr
|
||||
- added std.loadFile(), std.strerror(), std.FILE.prototype.tello()
|
||||
- added JS_GetRuntimeOpaque(), JS_SetRuntimeOpaque(), JS_NewUint32()
|
||||
- updated to Unicode 13.0.0
|
||||
- misc bug fixes
|
||||
|
||||
2020-01-19:
|
||||
|
||||
- keep CONFIG_BIGNUM in the makefile
|
||||
- added os.chdir()
|
||||
- qjs: added -I option
|
||||
- more memory checks in the bignum operations
|
||||
- modified operator overloading semantics to be closer to the TC39
|
||||
proposal
|
||||
- suppressed "use bigint" mode. Simplified "use math" mode
|
||||
- BigDecimal: changed suffix from 'd' to 'm'
|
||||
- misc bug fixes
|
||||
|
||||
2020-01-05:
|
||||
|
||||
- always compile the bignum code. Added '--bignum' option to qjs.
|
||||
- added BigDecimal
|
||||
- added String.prototype.replaceAll
|
||||
- misc bug fixes
|
||||
|
||||
2019-12-21:
|
||||
|
||||
- added nullish coalescing operator (ES2020)
|
||||
- added optional chaining (ES2020)
|
||||
- removed recursions in garbage collector
|
||||
- test stack overflow in the parser
|
||||
- improved backtrace logic
|
||||
- added JS_SetHostPromiseRejectionTracker()
|
||||
- allow exotic constructors
|
||||
- improved c++ compatibility
|
||||
- misc bug fixes
|
||||
|
||||
2019-10-27:
|
||||
|
||||
- added example of C class in a module (examples/test_point.js)
|
||||
- added JS_GetTypedArrayBuffer()
|
||||
- misc bug fixes
|
||||
|
||||
2019-09-18:
|
||||
|
||||
- added os.exec and other system calls
|
||||
- exported JS_ValueToAtom()
|
||||
- qjsc: added 'qjsc_' prefix to the generated C identifiers
|
||||
- added cross-compilation support
|
||||
- misc bug fixes
|
||||
|
||||
2019-09-01:
|
||||
|
||||
- added globalThis
|
||||
- documented JS_EVAL_FLAG_COMPILE_ONLY
|
||||
- added import.meta.url and import.meta.main
|
||||
- added 'debugger' statement
|
||||
- misc bug fixes
|
||||
|
||||
2019-08-18:
|
||||
|
||||
- added os.realpath, os.getcwd, os.mkdir, os.stat, os.lstat,
|
||||
os.readlink, os.readdir, os.utimes, std.popen
|
||||
- module autodetection
|
||||
- added import.meta
|
||||
- misc bug fixes
|
||||
|
||||
2019-08-10:
|
||||
|
||||
- added public class fields and private class fields, methods and
|
||||
accessors (TC39 proposal)
|
||||
- changed JS_ToCStringLen() prototype
|
||||
- qjsc: handle '-' in module names and modules with the same filename
|
||||
- added std.urlGet
|
||||
- exported JS_GetOwnPropertyNames() and JS_GetOwnProperty()
|
||||
- exported some bigint C functions
|
||||
- added support for eshost in run-test262
|
||||
- misc bug fixes
|
||||
|
||||
2019-07-28:
|
||||
|
||||
- added dynamic import
|
||||
- added Promise.allSettled
|
||||
- added String.prototype.matchAll
|
||||
- added Object.fromEntries
|
||||
- reduced number of ticks in await
|
||||
- added BigInt support in Atomics
|
||||
- exported JS_NewPromiseCapability()
|
||||
- misc async function and async generator fixes
|
||||
- enabled hashbang support by default
|
||||
|
||||
2019-07-21:
|
||||
|
||||
- updated test262 tests
|
||||
- updated to Unicode version 12.1.0
|
||||
- fixed missing Date object in qjsc
|
||||
- fixed multi-context creation
|
||||
- misc ES2020 related fixes
|
||||
- simplified power and division operators in bignum extension
|
||||
- fixed several crash conditions
|
||||
|
||||
2019-07-09:
|
||||
|
||||
- first public release
|
22
quickjs/LICENSE
Normal file
|
@ -0,0 +1,22 @@
|
|||
QuickJS Javascript Engine
|
||||
|
||||
Copyright (c) 2017-2021 Fabrice Bellard
|
||||
Copyright (c) 2017-2021 Charlie Gordon
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
486
quickjs/Makefile
Normal file
|
@ -0,0 +1,486 @@
|
|||
#
|
||||
# QuickJS Javascript Engine
|
||||
#
|
||||
# Copyright (c) 2017-2021 Fabrice Bellard
|
||||
# Copyright (c) 2017-2021 Charlie Gordon
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
ifeq ($(shell uname -s),Darwin)
|
||||
ifeq ($(HOST_CC),clang)
|
||||
CFLAGS += -arch $(ARCH)
|
||||
endif
|
||||
endif
|
||||
|
||||
# Windows cross compilation from Linux
|
||||
#CONFIG_WIN32=y
|
||||
# use link time optimization (smaller and faster executables but slower build)
|
||||
CONFIG_LTO=y
|
||||
# consider warnings as errors (for development)
|
||||
#CONFIG_WERROR=y
|
||||
# force 32 bit build for some utilities
|
||||
#CONFIG_M32=y
|
||||
|
||||
# use clang instead of gcc
|
||||
ifeq ($(HOST_CC),clang)
|
||||
CONFIG_CLANG=y
|
||||
CONFIG_DEFAULT_AR=y
|
||||
endif
|
||||
|
||||
|
||||
# installation directory
|
||||
prefix=/usr/local
|
||||
|
||||
# use the gprof profiler
|
||||
#CONFIG_PROFILE=y
|
||||
# use address sanitizer
|
||||
#CONFIG_ASAN=y
|
||||
# include the code for BigInt/BigFloat/BigDecimal and math mode
|
||||
CONFIG_BIGNUM=y
|
||||
|
||||
OBJDIR=.obj
|
||||
|
||||
ifdef CONFIG_WIN32
|
||||
ifdef CONFIG_M32
|
||||
CROSS_PREFIX=i686-w64-mingw32-
|
||||
else
|
||||
CROSS_PREFIX=x86_64-w64-mingw32-
|
||||
endif
|
||||
EXE=.exe
|
||||
else
|
||||
CROSS_PREFIX=
|
||||
EXE=
|
||||
endif
|
||||
ifeq ($(CC), clang)
|
||||
CC=$(CROSS_PREFIX)clang
|
||||
CFLAGS += -g -Wall -MMD -MF $(OBJDIR)/$(@F).d
|
||||
CFLAGS += -Wextra
|
||||
CFLAGS += -Wno-sign-compare
|
||||
CFLAGS += -Wno-missing-field-initializers
|
||||
CFLAGS += -Wno-unused-function -Wno-unused-const-variable
|
||||
CFLAGS += -Wundef -Wuninitialized
|
||||
CFLAGS += -Wunused -Wno-unused-parameter
|
||||
CFLAGS += -Wwrite-strings
|
||||
CFLAGS += -Wchar-subscripts -funsigned-char
|
||||
CFLAGS += -MMD -MF $(OBJDIR)/$(@F).d
|
||||
ifneq ($(TTARGET),)
|
||||
CFLAGS += --target=$(TTARGET)
|
||||
CFLAGS += -isysroot $(SYSRT)
|
||||
endif
|
||||
ifdef CONFIG_DEFAULT_AR
|
||||
AR=$(CROSS_PREFIX)ar
|
||||
else
|
||||
ifdef CONFIG_LTO
|
||||
AR=$(CROSS_PREFIX)llvm-ar
|
||||
else
|
||||
AR=$(CROSS_PREFIX)ar
|
||||
endif
|
||||
endif
|
||||
else
|
||||
CC=$(CROSS_PREFIX)gcc
|
||||
CFLAGS += -g -Wall -MMD -MF $(OBJDIR)/$(@F).d
|
||||
CFLAGS += -Wno-array-bounds -Wno-format-truncation
|
||||
CFLAGS += -Wno-unused-function -Wno-unused-const-variable
|
||||
ifdef CONFIG_LTO
|
||||
AR=$(CROSS_PREFIX)gcc-ar
|
||||
else
|
||||
AR=$(CROSS_PREFIX)ar
|
||||
endif
|
||||
endif
|
||||
STRIP=$(CROSS_PREFIX)strip
|
||||
ifdef CONFIG_WERROR
|
||||
CFLAGS+=-Werror
|
||||
endif
|
||||
DEFINES:=-D_GNU_SOURCE -DCONFIG_VERSION=\"$(shell cat VERSION)\"
|
||||
ifdef CONFIG_BIGNUM
|
||||
DEFINES+=-DCONFIG_BIGNUM
|
||||
endif
|
||||
ifdef CONFIG_WIN32
|
||||
DEFINES+=-D__USE_MINGW_ANSI_STDIO # for standard snprintf behavior
|
||||
endif
|
||||
|
||||
CFLAGS+=$(DEFINES)
|
||||
CFLAGS_DEBUG=$(CFLAGS) -O0
|
||||
CFLAGS_SMALL=$(CFLAGS) -Os
|
||||
CFLAGS_OPT=$(CFLAGS) -O2
|
||||
CFLAGS_NOLTO:=$(CFLAGS_OPT)
|
||||
LDFLAGS=-g
|
||||
ifdef CONFIG_LTO
|
||||
CFLAGS_SMALL+=-flto
|
||||
CFLAGS_OPT+=-flto
|
||||
LDFLAGS+=-flto
|
||||
endif
|
||||
ifdef CONFIG_PROFILE
|
||||
CFLAGS+=-p
|
||||
LDFLAGS+=-p
|
||||
endif
|
||||
ifdef CONFIG_ASAN
|
||||
CFLAGS+=-fsanitize=address -fno-omit-frame-pointer
|
||||
LDFLAGS+=-fsanitize=address -fno-omit-frame-pointer
|
||||
endif
|
||||
ifdef CONFIG_WIN32
|
||||
LDEXPORT=
|
||||
else
|
||||
LDEXPORT=-rdynamic
|
||||
endif
|
||||
|
||||
ifeq ($(OPT), small)
|
||||
USEFLAGS = $(CFLAGS_SMALL)
|
||||
else ifeq ($(OPT), 1)
|
||||
USEFLAGS = $(CFLAGS_OPT)
|
||||
else
|
||||
USEFLAGS = $(CFLAGS_DEBUG)
|
||||
endif
|
||||
|
||||
PROGS=qjs$(EXE) qjsc$(EXE) run-test262
|
||||
ifneq ($(CROSS_PREFIX),)
|
||||
QJSC_CC=gcc
|
||||
QJSC=./host-qjsc
|
||||
PROGS+=$(QJSC)
|
||||
else
|
||||
QJSC_CC=$(CC)
|
||||
QJSC=./qjsc$(EXE)
|
||||
endif
|
||||
ifndef CONFIG_WIN32
|
||||
PROGS+=qjscalc
|
||||
endif
|
||||
ifdef CONFIG_M32
|
||||
PROGS+=qjs32 qjs32_s
|
||||
endif
|
||||
PROGS+=libquickjs.a
|
||||
ifdef CONFIG_LTO
|
||||
PROGS+=libquickjs.lto.a
|
||||
endif
|
||||
|
||||
# examples
|
||||
ifeq ($(CROSS_PREFIX),)
|
||||
ifdef CONFIG_ASAN
|
||||
PROGS+=
|
||||
else
|
||||
PROGS+=examples/hello examples/hello_module examples/test_fib
|
||||
ifndef CONFIG_DARWIN
|
||||
PROGS+=examples/fib.so examples/point.so
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
all: $(OBJDIR) $(OBJDIR)/quickjs.check.o $(OBJDIR)/qjs.check.o $(PROGS)
|
||||
|
||||
QJS_LIB_OBJS=$(OBJDIR)/quickjs.o $(OBJDIR)/libregexp.o $(OBJDIR)/libunicode.o $(OBJDIR)/cutils.o $(OBJDIR)/quickjs-libc.o
|
||||
|
||||
QJS_OBJS=$(OBJDIR)/qjs.o $(OBJDIR)/repl.o $(QJS_LIB_OBJS)
|
||||
ifdef CONFIG_BIGNUM
|
||||
QJS_LIB_OBJS+=$(OBJDIR)/libbf.o
|
||||
QJS_OBJS+=$(OBJDIR)/qjscalc.o
|
||||
endif
|
||||
|
||||
HOST_LIBS=-lm -ldl -lpthread
|
||||
LIBS=-lm
|
||||
ifndef CONFIG_WIN32
|
||||
LIBS+=-ldl -lpthread
|
||||
endif
|
||||
LIBS+=$(EXTRA_LIBS)
|
||||
|
||||
$(OBJDIR):
|
||||
mkdir -p $(OBJDIR) $(OBJDIR)/examples $(OBJDIR)/tests
|
||||
|
||||
qjs$(EXE): $(QJS_OBJS)
|
||||
$(CC) $(LDFLAGS) $(LDEXPORT) -o $@ $^ $(LIBS)
|
||||
|
||||
qjs-debug$(EXE): $(patsubst %.o, %.debug.o, $(QJS_OBJS))
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
|
||||
qjsc$(EXE): $(OBJDIR)/qjsc.o $(QJS_LIB_OBJS)
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
|
||||
ifneq ($(CROSS_PREFIX),)
|
||||
|
||||
$(QJSC): $(OBJDIR)/qjsc.host.o \
|
||||
$(patsubst %.o, %.host.o, $(QJS_LIB_OBJS))
|
||||
$(HOST_CC) $(LDFLAGS) -o $@ $^ $(HOST_LIBS)
|
||||
|
||||
endif #CROSS_PREFIX
|
||||
|
||||
QJSC_DEFINES:=-DCONFIG_CC=\"$(QJSC_CC)\" -DCONFIG_PREFIX=\"$(prefix)\"
|
||||
ifdef CONFIG_LTO
|
||||
QJSC_DEFINES+=-DCONFIG_LTO
|
||||
endif
|
||||
QJSC_HOST_DEFINES:=-DCONFIG_CC=\"$(HOST_CC)\" -DCONFIG_PREFIX=\"$(prefix)\"
|
||||
|
||||
$(OBJDIR)/qjsc.o: CFLAGS+=$(QJSC_DEFINES)
|
||||
$(OBJDIR)/qjsc.host.o: CFLAGS+=$(QJSC_HOST_DEFINES)
|
||||
|
||||
qjs32: $(patsubst %.o, %.m32.o, $(QJS_OBJS))
|
||||
$(CC) -m32 $(LDFLAGS) $(LDEXPORT) -o $@ $^ $(LIBS)
|
||||
|
||||
qjs32_s: $(patsubst %.o, %.m32s.o, $(QJS_OBJS))
|
||||
$(CC) -m32 $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
@size $@
|
||||
|
||||
qjscalc: qjs
|
||||
ln -sf $< $@
|
||||
|
||||
ifdef CONFIG_LTO
|
||||
LTOEXT=.lto
|
||||
else
|
||||
LTOEXT=
|
||||
endif
|
||||
|
||||
libquickjs$(LTOEXT).a: $(QJS_LIB_OBJS)
|
||||
$(AR) rcs $@ $^
|
||||
|
||||
ifdef CONFIG_LTO
|
||||
libquickjs.a: $(patsubst %.o, %.nolto.o, $(QJS_LIB_OBJS))
|
||||
$(AR) rcs $@ $^
|
||||
endif # CONFIG_LTO
|
||||
|
||||
repl.c: $(QJSC) repl.js
|
||||
$(QJSC) -c -o $@ -m repl.js
|
||||
|
||||
qjscalc.c: $(QJSC) qjscalc.js
|
||||
$(QJSC) -fbignum -c -o $@ qjscalc.js
|
||||
|
||||
ifneq ($(wildcard unicode/UnicodeData.txt),)
|
||||
$(OBJDIR)/libunicode.o $(OBJDIR)/libunicode.m32.o $(OBJDIR)/libunicode.m32s.o \
|
||||
$(OBJDIR)/libunicode.nolto.o: libunicode-table.h
|
||||
|
||||
libunicode-table.h: unicode_gen
|
||||
./unicode_gen unicode $@
|
||||
endif
|
||||
|
||||
run-test262: $(OBJDIR)/run-test262.o $(QJS_LIB_OBJS)
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
|
||||
run-test262-debug: $(patsubst %.o, %.debug.o, $(OBJDIR)/run-test262.o $(QJS_LIB_OBJS))
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
|
||||
run-test262-32: $(patsubst %.o, %.m32.o, $(OBJDIR)/run-test262.o $(QJS_LIB_OBJS))
|
||||
$(CC) -m32 $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
|
||||
# object suffix order: nolto, [m32|m32s]
|
||||
|
||||
$(OBJDIR)/%.o: %.c | $(OBJDIR)
|
||||
$(CC) $(CFLAGS_OPT) -c -o $@ $<
|
||||
|
||||
$(OBJDIR)/%.host.o: %.c | $(OBJDIR)
|
||||
$(HOST_CC) $(CFLAGS_OPT) -c -o $@ $<
|
||||
|
||||
$(OBJDIR)/%.pic.o: %.c | $(OBJDIR)
|
||||
$(CC) $(CFLAGS_OPT) -fPIC -DJS_SHARED_LIBRARY -c -o $@ $<
|
||||
|
||||
$(OBJDIR)/%.nolto.o: %.c | $(OBJDIR)
|
||||
$(CC) $(CFLAGS_NOLTO) -c -o $@ $<
|
||||
|
||||
$(OBJDIR)/%.m32.o: %.c | $(OBJDIR)
|
||||
$(CC) -m32 $(CFLAGS_OPT) -c -o $@ $<
|
||||
|
||||
$(OBJDIR)/%.m32s.o: %.c | $(OBJDIR)
|
||||
$(CC) -m32 $(CFLAGS_SMALL) -c -o $@ $<
|
||||
|
||||
$(OBJDIR)/%.debug.o: %.c | $(OBJDIR)
|
||||
$(CC) $(CFLAGS_DEBUG) -c -o $@ $<
|
||||
|
||||
$(OBJDIR)/%.check.o: %.c | $(OBJDIR)
|
||||
$(CC) $(CFLAGS) -DCONFIG_CHECK_JSVALUE -c -o $@ $<
|
||||
|
||||
regexp_test: libregexp.c libunicode.c cutils.c
|
||||
$(CC) $(LDFLAGS) $(CFLAGS) -DTEST -o $@ libregexp.c libunicode.c cutils.c $(LIBS)
|
||||
|
||||
unicode_gen: $(OBJDIR)/unicode_gen.host.o $(OBJDIR)/cutils.host.o libunicode.c unicode_gen_def.h
|
||||
$(HOST_CC) $(LDFLAGS) $(CFLAGS) -o $@ $(OBJDIR)/unicode_gen.host.o $(OBJDIR)/cutils.host.o
|
||||
|
||||
clean:
|
||||
rm -f repl.c qjscalc.c out.c
|
||||
rm -f *.a *.o *.d *~ unicode_gen regexp_test $(PROGS)
|
||||
rm -f hello.c test_fib.c
|
||||
rm -f examples/*.so tests/*.so
|
||||
rm -rf $(OBJDIR)/ *.dSYM/ qjs-debug
|
||||
rm -rf run-test262-debug run-test262-32
|
||||
|
||||
install: all
|
||||
mkdir -p "$(DESTDIR)$(prefix)/bin"
|
||||
$(STRIP) qjs qjsc
|
||||
install -m755 qjs qjsc "$(DESTDIR)$(prefix)/bin"
|
||||
ln -sf qjs "$(DESTDIR)$(prefix)/bin/qjscalc"
|
||||
mkdir -p "$(DESTDIR)$(prefix)/lib/quickjs"
|
||||
install -m644 libquickjs.a "$(DESTDIR)$(prefix)/lib/quickjs"
|
||||
ifdef CONFIG_LTO
|
||||
install -m644 libquickjs.lto.a "$(DESTDIR)$(prefix)/lib/quickjs"
|
||||
endif
|
||||
mkdir -p "$(DESTDIR)$(prefix)/include/quickjs"
|
||||
install -m644 quickjs.h quickjs-libc.h "$(DESTDIR)$(prefix)/include/quickjs"
|
||||
|
||||
###############################################################################
|
||||
# examples
|
||||
|
||||
# example of static JS compilation
|
||||
HELLO_SRCS=examples/hello.js
|
||||
HELLO_OPTS=-fno-string-normalize -fno-map -fno-promise -fno-typedarray \
|
||||
-fno-typedarray -fno-regexp -fno-json -fno-eval -fno-proxy \
|
||||
-fno-date -fno-module-loader
|
||||
ifdef CONFIG_BIGNUM
|
||||
HELLO_OPTS+=-fno-bigint
|
||||
endif
|
||||
|
||||
hello.c: $(QJSC) $(HELLO_SRCS)
|
||||
$(QJSC) -e $(HELLO_OPTS) -o $@ $(HELLO_SRCS)
|
||||
|
||||
ifdef CONFIG_M32
|
||||
examples/hello: $(OBJDIR)/hello.m32s.o $(patsubst %.o, %.m32s.o, $(QJS_LIB_OBJS))
|
||||
$(CC) -m32 $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
else
|
||||
examples/hello: $(OBJDIR)/hello.o $(QJS_LIB_OBJS)
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
endif
|
||||
|
||||
# example of static JS compilation with modules
|
||||
HELLO_MODULE_SRCS=examples/hello_module.js
|
||||
HELLO_MODULE_OPTS=-fno-string-normalize -fno-map -fno-promise -fno-typedarray \
|
||||
-fno-typedarray -fno-regexp -fno-json -fno-eval -fno-proxy \
|
||||
-fno-date -m
|
||||
examples/hello_module: $(QJSC) libquickjs$(LTOEXT).a $(HELLO_MODULE_SRCS)
|
||||
$(QJSC) $(HELLO_MODULE_OPTS) -o $@ $(HELLO_MODULE_SRCS)
|
||||
|
||||
# use of an external C module (static compilation)
|
||||
|
||||
test_fib.c: $(QJSC) examples/test_fib.js
|
||||
$(QJSC) -e -M examples/fib.so,fib -m -o $@ examples/test_fib.js
|
||||
|
||||
examples/test_fib: $(OBJDIR)/test_fib.o $(OBJDIR)/examples/fib.o libquickjs$(LTOEXT).a
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
|
||||
examples/fib.so: $(OBJDIR)/examples/fib.pic.o
|
||||
$(CC) $(LDFLAGS) -shared -o $@ $^
|
||||
|
||||
examples/point.so: $(OBJDIR)/examples/point.pic.o
|
||||
$(CC) $(LDFLAGS) -shared -o $@ $^
|
||||
|
||||
###############################################################################
|
||||
# documentation
|
||||
|
||||
DOCS=doc/quickjs.pdf doc/quickjs.html doc/jsbignum.pdf doc/jsbignum.html
|
||||
|
||||
build_doc: $(DOCS)
|
||||
|
||||
clean_doc:
|
||||
rm -f $(DOCS)
|
||||
|
||||
doc/%.pdf: doc/%.texi
|
||||
texi2pdf --clean -o $@ -q $<
|
||||
|
||||
doc/%.html.pre: doc/%.texi
|
||||
makeinfo --html --no-headers --no-split --number-sections -o $@ $<
|
||||
|
||||
doc/%.html: doc/%.html.pre
|
||||
sed -e 's|</style>|</style>\n<meta name="viewport" content="width=device-width, initial-scale=1.0">|' < $< > $@
|
||||
|
||||
###############################################################################
|
||||
# tests
|
||||
|
||||
ifndef CONFIG_DARWIN
|
||||
test: tests/bjson.so examples/point.so
|
||||
endif
|
||||
ifdef CONFIG_M32
|
||||
test: qjs32
|
||||
endif
|
||||
|
||||
test: qjs
|
||||
./qjs tests/test_closure.js
|
||||
./qjs tests/test_language.js
|
||||
./qjs tests/test_builtin.js
|
||||
./qjs tests/test_loop.js
|
||||
./qjs tests/test_std.js
|
||||
./qjs tests/test_worker.js
|
||||
ifndef CONFIG_DARWIN
|
||||
ifdef CONFIG_BIGNUM
|
||||
./qjs --bignum tests/test_bjson.js
|
||||
else
|
||||
./qjs tests/test_bjson.js
|
||||
endif
|
||||
./qjs examples/test_point.js
|
||||
endif
|
||||
ifdef CONFIG_BIGNUM
|
||||
./qjs --bignum tests/test_op_overloading.js
|
||||
./qjs --bignum tests/test_bignum.js
|
||||
./qjs --qjscalc tests/test_qjscalc.js
|
||||
endif
|
||||
ifdef CONFIG_M32
|
||||
./qjs32 tests/test_closure.js
|
||||
./qjs32 tests/test_language.js
|
||||
./qjs32 tests/test_builtin.js
|
||||
./qjs32 tests/test_loop.js
|
||||
./qjs32 tests/test_std.js
|
||||
./qjs32 tests/test_worker.js
|
||||
ifdef CONFIG_BIGNUM
|
||||
./qjs32 --bignum tests/test_op_overloading.js
|
||||
./qjs32 --bignum tests/test_bignum.js
|
||||
./qjs32 --qjscalc tests/test_qjscalc.js
|
||||
endif
|
||||
endif
|
||||
|
||||
stats: qjs qjs32
|
||||
./qjs -qd
|
||||
./qjs32 -qd
|
||||
|
||||
microbench: qjs
|
||||
./qjs tests/microbench.js
|
||||
|
||||
microbench-32: qjs32
|
||||
./qjs32 tests/microbench.js
|
||||
|
||||
# ES5 tests (obsolete)
|
||||
test2o: run-test262
|
||||
time ./run-test262 -m -c test262o.conf
|
||||
|
||||
test2o-32: run-test262-32
|
||||
time ./run-test262-32 -m -c test262o.conf
|
||||
|
||||
test2o-update: run-test262
|
||||
./run-test262 -u -c test262o.conf
|
||||
|
||||
# Test262 tests
|
||||
test2-default: run-test262
|
||||
time ./run-test262 -m -c test262.conf
|
||||
|
||||
test2: run-test262
|
||||
time ./run-test262 -m -c test262.conf -a
|
||||
|
||||
test2-32: run-test262-32
|
||||
time ./run-test262-32 -m -c test262.conf -a
|
||||
|
||||
test2-update: run-test262
|
||||
./run-test262 -u -c test262.conf -a
|
||||
|
||||
test2-check: run-test262
|
||||
time ./run-test262 -m -c test262.conf -E -a
|
||||
|
||||
testall: all test microbench test2o test2
|
||||
|
||||
testall-32: all test-32 microbench-32 test2o-32 test2-32
|
||||
|
||||
testall-complete: testall testall-32
|
||||
|
||||
bench-v8: qjs
|
||||
make -C tests/bench-v8
|
||||
./qjs -d tests/bench-v8/combined.js
|
||||
|
||||
tests/bjson.so: $(OBJDIR)/tests/bjson.pic.o
|
||||
$(CC) $(LDFLAGS) -shared -o $@ $^ $(LIBS)
|
||||
|
||||
-include $(wildcard $(OBJDIR)/*.d)
|
70
quickjs/TODO
Normal file
|
@ -0,0 +1,70 @@
|
|||
Bugs:
|
||||
- modules: better error handling with cyclic module references
|
||||
|
||||
Misc ideas:
|
||||
- use custom printf to avoid compatibility issues with floating point numbers
|
||||
- consistent naming for preprocessor defines
|
||||
- unify coding style and naming conventions
|
||||
- use names from the ECMA spec in library implementation
|
||||
- use byte code emitters with typed arguments (for clarity)
|
||||
- use 2 bytecode DynBufs in JSFunctionDef, one for reading, one for writing
|
||||
and use the same wrappers in all phases
|
||||
- use more generic method for line numbers in resolve_variables and resolve_labels
|
||||
- use custom timezone support to avoid C library compatibility issues
|
||||
|
||||
Memory:
|
||||
- use memory pools for objects, etc?
|
||||
- test border cases for max number of atoms, object properties, string length
|
||||
- add emergency malloc mode for out of memory exceptions.
|
||||
- test all DynBuf memory errors
|
||||
- test all js_realloc memory errors
|
||||
- improve JS_ComputeMemoryUsage() with more info
|
||||
|
||||
Built-in standard library:
|
||||
- BSD sockets
|
||||
- modules: use realpath in module name normalizer and put it in quickjs-libc
|
||||
- modules: if no ".", use a well known module loading path ?
|
||||
- get rid of __loadScript, use more common name
|
||||
|
||||
REPL:
|
||||
- debugger
|
||||
- readline: support MS Windows terminal
|
||||
- readline: handle dynamic terminal resizing
|
||||
- readline: handle double width unicode characters
|
||||
- multiline editing
|
||||
- runtime object and function inspectors
|
||||
- interactive object browser
|
||||
- use more generic approach to display evaluation results
|
||||
- improve directive handling: dispatch, colorize, completion...
|
||||
- save history
|
||||
- close all predefined methods in repl.js and jscalc.js
|
||||
|
||||
Optimization ideas:
|
||||
- 64-bit atoms in 64-bit mode ?
|
||||
- 64-bit small bigint in 64-bit mode ?
|
||||
- reuse stack slots for disjoint scopes, if strip
|
||||
- add heuristic to avoid some cycles in closures
|
||||
- small String (0-2 charcodes) with immediate storage
|
||||
- perform static string concatenation at compile time
|
||||
- optimize string concatenation with ropes or miniropes?
|
||||
- add implicit numeric strings for Uint32 numbers?
|
||||
- optimize `s += a + b`, `s += a.b` and similar simple expressions
|
||||
- ensure string canonical representation and optimise comparisons and hashes?
|
||||
- remove JSObject.first_weak_ref, use bit+context based hashed array for weak references
|
||||
- property access optimization on the global object, functions,
|
||||
prototypes and special non extensible objects.
|
||||
- create object literals with the correct length by backpatching length argument
|
||||
- remove redundant set_loc_uninitialized/check_uninitialized opcodes
|
||||
- peephole optim: push_atom_value, to_propkey -> push_atom_value
|
||||
- peephole optim: put_loc x, get_loc_check x -> set_loc x
|
||||
- convert slow array to fast array when all properties != length are numeric
|
||||
- optimize destructuring assignments for global and local variables
|
||||
- implement some form of tail-call-optimization
|
||||
- optimize OP_apply
|
||||
- optimize f(...b)
|
||||
|
||||
Test262o: 0/11262 errors, 463 excluded
|
||||
Test262o commit: 7da91bceb9ce7613f87db47ddd1292a2dda58b42 (es5-tests branch)
|
||||
|
||||
Result: 35/75280 errors, 909 excluded, 585 skipped
|
||||
Test262 commit: 31126581e7290f9233c29cefd93f66c6ac78f1c9
|
1
quickjs/VERSION
Normal file
|
@ -0,0 +1 @@
|
|||
2021-03-27
|
631
quickjs/cutils.c
Normal file
|
@ -0,0 +1,631 @@
|
|||
/*
|
||||
* C utilities
|
||||
*
|
||||
* Copyright (c) 2017 Fabrice Bellard
|
||||
* Copyright (c) 2018 Charlie Gordon
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cutils.h"
|
||||
|
||||
void pstrcpy(char *buf, int buf_size, const char *str)
|
||||
{
|
||||
int c;
|
||||
char *q = buf;
|
||||
|
||||
if (buf_size <= 0)
|
||||
return;
|
||||
|
||||
for(;;) {
|
||||
c = *str++;
|
||||
if (c == 0 || q >= buf + buf_size - 1)
|
||||
break;
|
||||
*q++ = c;
|
||||
}
|
||||
*q = '\0';
|
||||
}
|
||||
|
||||
/* strcat and truncate. */
|
||||
char *pstrcat(char *buf, int buf_size, const char *s)
|
||||
{
|
||||
int len;
|
||||
len = strlen(buf);
|
||||
if (len < buf_size)
|
||||
pstrcpy(buf + len, buf_size - len, s);
|
||||
return buf;
|
||||
}
|
||||
|
||||
int strstart(const char *str, const char *val, const char **ptr)
|
||||
{
|
||||
const char *p, *q;
|
||||
p = str;
|
||||
q = val;
|
||||
while (*q != '\0') {
|
||||
if (*p != *q)
|
||||
return 0;
|
||||
p++;
|
||||
q++;
|
||||
}
|
||||
if (ptr)
|
||||
*ptr = p;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int has_suffix(const char *str, const char *suffix)
|
||||
{
|
||||
size_t len = strlen(str);
|
||||
size_t slen = strlen(suffix);
|
||||
return (len >= slen && !memcmp(str + len - slen, suffix, slen));
|
||||
}
|
||||
|
||||
/* Dynamic buffer package */
|
||||
|
||||
static void *dbuf_default_realloc(void *opaque, void *ptr, size_t size)
|
||||
{
|
||||
return realloc(ptr, size);
|
||||
}
|
||||
|
||||
void dbuf_init2(DynBuf *s, void *opaque, DynBufReallocFunc *realloc_func)
|
||||
{
|
||||
memset(s, 0, sizeof(*s));
|
||||
if (!realloc_func)
|
||||
realloc_func = dbuf_default_realloc;
|
||||
s->opaque = opaque;
|
||||
s->realloc_func = realloc_func;
|
||||
}
|
||||
|
||||
void dbuf_init(DynBuf *s)
|
||||
{
|
||||
dbuf_init2(s, NULL, NULL);
|
||||
}
|
||||
|
||||
/* return < 0 if error */
|
||||
int dbuf_realloc(DynBuf *s, size_t new_size)
|
||||
{
|
||||
size_t size;
|
||||
uint8_t *new_buf;
|
||||
if (new_size > s->allocated_size) {
|
||||
if (s->error)
|
||||
return -1;
|
||||
size = s->allocated_size * 3 / 2;
|
||||
if (size > new_size)
|
||||
new_size = size;
|
||||
new_buf = s->realloc_func(s->opaque, s->buf, new_size);
|
||||
if (!new_buf) {
|
||||
s->error = TRUE;
|
||||
return -1;
|
||||
}
|
||||
s->buf = new_buf;
|
||||
s->allocated_size = new_size;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dbuf_write(DynBuf *s, size_t offset, const uint8_t *data, size_t len)
|
||||
{
|
||||
size_t end;
|
||||
end = offset + len;
|
||||
if (dbuf_realloc(s, end))
|
||||
return -1;
|
||||
memcpy(s->buf + offset, data, len);
|
||||
if (end > s->size)
|
||||
s->size = end;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dbuf_put(DynBuf *s, const uint8_t *data, size_t len)
|
||||
{
|
||||
if (unlikely((s->size + len) > s->allocated_size)) {
|
||||
if (dbuf_realloc(s, s->size + len))
|
||||
return -1;
|
||||
}
|
||||
memcpy(s->buf + s->size, data, len);
|
||||
s->size += len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dbuf_put_self(DynBuf *s, size_t offset, size_t len)
|
||||
{
|
||||
if (unlikely((s->size + len) > s->allocated_size)) {
|
||||
if (dbuf_realloc(s, s->size + len))
|
||||
return -1;
|
||||
}
|
||||
memcpy(s->buf + s->size, s->buf + offset, len);
|
||||
s->size += len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dbuf_putc(DynBuf *s, uint8_t c)
|
||||
{
|
||||
return dbuf_put(s, &c, 1);
|
||||
}
|
||||
|
||||
int dbuf_putstr(DynBuf *s, const char *str)
|
||||
{
|
||||
return dbuf_put(s, (const uint8_t *)str, strlen(str));
|
||||
}
|
||||
|
||||
int __attribute__((format(printf, 2, 3))) dbuf_printf(DynBuf *s,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char buf[128];
|
||||
int len;
|
||||
|
||||
va_start(ap, fmt);
|
||||
len = vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||
va_end(ap);
|
||||
if (len < sizeof(buf)) {
|
||||
/* fast case */
|
||||
return dbuf_put(s, (uint8_t *)buf, len);
|
||||
} else {
|
||||
if (dbuf_realloc(s, s->size + len + 1))
|
||||
return -1;
|
||||
va_start(ap, fmt);
|
||||
vsnprintf((char *)(s->buf + s->size), s->allocated_size - s->size,
|
||||
fmt, ap);
|
||||
va_end(ap);
|
||||
s->size += len;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dbuf_free(DynBuf *s)
|
||||
{
|
||||
/* we test s->buf as a fail safe to avoid crashing if dbuf_free()
|
||||
is called twice */
|
||||
if (s->buf) {
|
||||
s->realloc_func(s->opaque, s->buf, 0);
|
||||
}
|
||||
memset(s, 0, sizeof(*s));
|
||||
}
|
||||
|
||||
/* Note: at most 31 bits are encoded. At most UTF8_CHAR_LEN_MAX bytes
|
||||
are output. */
|
||||
int unicode_to_utf8(uint8_t *buf, unsigned int c)
|
||||
{
|
||||
uint8_t *q = buf;
|
||||
|
||||
if (c < 0x80) {
|
||||
*q++ = c;
|
||||
} else {
|
||||
if (c < 0x800) {
|
||||
*q++ = (c >> 6) | 0xc0;
|
||||
} else {
|
||||
if (c < 0x10000) {
|
||||
*q++ = (c >> 12) | 0xe0;
|
||||
} else {
|
||||
if (c < 0x00200000) {
|
||||
*q++ = (c >> 18) | 0xf0;
|
||||
} else {
|
||||
if (c < 0x04000000) {
|
||||
*q++ = (c >> 24) | 0xf8;
|
||||
} else if (c < 0x80000000) {
|
||||
*q++ = (c >> 30) | 0xfc;
|
||||
*q++ = ((c >> 24) & 0x3f) | 0x80;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
*q++ = ((c >> 18) & 0x3f) | 0x80;
|
||||
}
|
||||
*q++ = ((c >> 12) & 0x3f) | 0x80;
|
||||
}
|
||||
*q++ = ((c >> 6) & 0x3f) | 0x80;
|
||||
}
|
||||
*q++ = (c & 0x3f) | 0x80;
|
||||
}
|
||||
return q - buf;
|
||||
}
|
||||
|
||||
static const unsigned int utf8_min_code[5] = {
|
||||
0x80, 0x800, 0x10000, 0x00200000, 0x04000000,
|
||||
};
|
||||
|
||||
static const unsigned char utf8_first_code_mask[5] = {
|
||||
0x1f, 0xf, 0x7, 0x3, 0x1,
|
||||
};
|
||||
|
||||
/* return -1 if error. *pp is not updated in this case. max_len must
|
||||
be >= 1. The maximum length for a UTF8 byte sequence is 6 bytes. */
|
||||
int unicode_from_utf8(const uint8_t *p, int max_len, const uint8_t **pp)
|
||||
{
|
||||
int l, c, b, i;
|
||||
|
||||
c = *p++;
|
||||
if (c < 0x80) {
|
||||
*pp = p;
|
||||
return c;
|
||||
}
|
||||
switch(c) {
|
||||
case 0xc0: case 0xc1: case 0xc2: case 0xc3:
|
||||
case 0xc4: case 0xc5: case 0xc6: case 0xc7:
|
||||
case 0xc8: case 0xc9: case 0xca: case 0xcb:
|
||||
case 0xcc: case 0xcd: case 0xce: case 0xcf:
|
||||
case 0xd0: case 0xd1: case 0xd2: case 0xd3:
|
||||
case 0xd4: case 0xd5: case 0xd6: case 0xd7:
|
||||
case 0xd8: case 0xd9: case 0xda: case 0xdb:
|
||||
case 0xdc: case 0xdd: case 0xde: case 0xdf:
|
||||
l = 1;
|
||||
break;
|
||||
case 0xe0: case 0xe1: case 0xe2: case 0xe3:
|
||||
case 0xe4: case 0xe5: case 0xe6: case 0xe7:
|
||||
case 0xe8: case 0xe9: case 0xea: case 0xeb:
|
||||
case 0xec: case 0xed: case 0xee: case 0xef:
|
||||
l = 2;
|
||||
break;
|
||||
case 0xf0: case 0xf1: case 0xf2: case 0xf3:
|
||||
case 0xf4: case 0xf5: case 0xf6: case 0xf7:
|
||||
l = 3;
|
||||
break;
|
||||
case 0xf8: case 0xf9: case 0xfa: case 0xfb:
|
||||
l = 4;
|
||||
break;
|
||||
case 0xfc: case 0xfd:
|
||||
l = 5;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
/* check that we have enough characters */
|
||||
if (l > (max_len - 1))
|
||||
return -1;
|
||||
c &= utf8_first_code_mask[l - 1];
|
||||
for(i = 0; i < l; i++) {
|
||||
b = *p++;
|
||||
if (b < 0x80 || b >= 0xc0)
|
||||
return -1;
|
||||
c = (c << 6) | (b & 0x3f);
|
||||
}
|
||||
if (c < utf8_min_code[l - 1])
|
||||
return -1;
|
||||
*pp = p;
|
||||
return c;
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
#if defined(EMSCRIPTEN) || defined(__ANDROID__)
|
||||
|
||||
static void *rqsort_arg;
|
||||
static int (*rqsort_cmp)(const void *, const void *, void *);
|
||||
|
||||
static int rqsort_cmp2(const void *p1, const void *p2)
|
||||
{
|
||||
return rqsort_cmp(p1, p2, rqsort_arg);
|
||||
}
|
||||
|
||||
/* not reentrant, but not needed with emscripten */
|
||||
void rqsort(void *base, size_t nmemb, size_t size,
|
||||
int (*cmp)(const void *, const void *, void *),
|
||||
void *arg)
|
||||
{
|
||||
rqsort_arg = arg;
|
||||
rqsort_cmp = cmp;
|
||||
qsort(base, nmemb, size, rqsort_cmp2);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
typedef void (*exchange_f)(void *a, void *b, size_t size);
|
||||
typedef int (*cmp_f)(const void *, const void *, void *opaque);
|
||||
|
||||
static void exchange_bytes(void *a, void *b, size_t size) {
|
||||
uint8_t *ap = (uint8_t *)a;
|
||||
uint8_t *bp = (uint8_t *)b;
|
||||
|
||||
while (size-- != 0) {
|
||||
uint8_t t = *ap;
|
||||
*ap++ = *bp;
|
||||
*bp++ = t;
|
||||
}
|
||||
}
|
||||
|
||||
static void exchange_one_byte(void *a, void *b, size_t size) {
|
||||
uint8_t *ap = (uint8_t *)a;
|
||||
uint8_t *bp = (uint8_t *)b;
|
||||
uint8_t t = *ap;
|
||||
*ap = *bp;
|
||||
*bp = t;
|
||||
}
|
||||
|
||||
static void exchange_int16s(void *a, void *b, size_t size) {
|
||||
uint16_t *ap = (uint16_t *)a;
|
||||
uint16_t *bp = (uint16_t *)b;
|
||||
|
||||
for (size /= sizeof(uint16_t); size-- != 0;) {
|
||||
uint16_t t = *ap;
|
||||
*ap++ = *bp;
|
||||
*bp++ = t;
|
||||
}
|
||||
}
|
||||
|
||||
static void exchange_one_int16(void *a, void *b, size_t size) {
|
||||
uint16_t *ap = (uint16_t *)a;
|
||||
uint16_t *bp = (uint16_t *)b;
|
||||
uint16_t t = *ap;
|
||||
*ap = *bp;
|
||||
*bp = t;
|
||||
}
|
||||
|
||||
static void exchange_int32s(void *a, void *b, size_t size) {
|
||||
uint32_t *ap = (uint32_t *)a;
|
||||
uint32_t *bp = (uint32_t *)b;
|
||||
|
||||
for (size /= sizeof(uint32_t); size-- != 0;) {
|
||||
uint32_t t = *ap;
|
||||
*ap++ = *bp;
|
||||
*bp++ = t;
|
||||
}
|
||||
}
|
||||
|
||||
static void exchange_one_int32(void *a, void *b, size_t size) {
|
||||
uint32_t *ap = (uint32_t *)a;
|
||||
uint32_t *bp = (uint32_t *)b;
|
||||
uint32_t t = *ap;
|
||||
*ap = *bp;
|
||||
*bp = t;
|
||||
}
|
||||
|
||||
static void exchange_int64s(void *a, void *b, size_t size) {
|
||||
uint64_t *ap = (uint64_t *)a;
|
||||
uint64_t *bp = (uint64_t *)b;
|
||||
|
||||
for (size /= sizeof(uint64_t); size-- != 0;) {
|
||||
uint64_t t = *ap;
|
||||
*ap++ = *bp;
|
||||
*bp++ = t;
|
||||
}
|
||||
}
|
||||
|
||||
static void exchange_one_int64(void *a, void *b, size_t size) {
|
||||
uint64_t *ap = (uint64_t *)a;
|
||||
uint64_t *bp = (uint64_t *)b;
|
||||
uint64_t t = *ap;
|
||||
*ap = *bp;
|
||||
*bp = t;
|
||||
}
|
||||
|
||||
static void exchange_int128s(void *a, void *b, size_t size) {
|
||||
uint64_t *ap = (uint64_t *)a;
|
||||
uint64_t *bp = (uint64_t *)b;
|
||||
|
||||
for (size /= sizeof(uint64_t) * 2; size-- != 0; ap += 2, bp += 2) {
|
||||
uint64_t t = ap[0];
|
||||
uint64_t u = ap[1];
|
||||
ap[0] = bp[0];
|
||||
ap[1] = bp[1];
|
||||
bp[0] = t;
|
||||
bp[1] = u;
|
||||
}
|
||||
}
|
||||
|
||||
static void exchange_one_int128(void *a, void *b, size_t size) {
|
||||
uint64_t *ap = (uint64_t *)a;
|
||||
uint64_t *bp = (uint64_t *)b;
|
||||
uint64_t t = ap[0];
|
||||
uint64_t u = ap[1];
|
||||
ap[0] = bp[0];
|
||||
ap[1] = bp[1];
|
||||
bp[0] = t;
|
||||
bp[1] = u;
|
||||
}
|
||||
|
||||
static inline exchange_f exchange_func(const void *base, size_t size) {
|
||||
switch (((uintptr_t)base | (uintptr_t)size) & 15) {
|
||||
case 0:
|
||||
if (size == sizeof(uint64_t) * 2)
|
||||
return exchange_one_int128;
|
||||
else
|
||||
return exchange_int128s;
|
||||
case 8:
|
||||
if (size == sizeof(uint64_t))
|
||||
return exchange_one_int64;
|
||||
else
|
||||
return exchange_int64s;
|
||||
case 4:
|
||||
case 12:
|
||||
if (size == sizeof(uint32_t))
|
||||
return exchange_one_int32;
|
||||
else
|
||||
return exchange_int32s;
|
||||
case 2:
|
||||
case 6:
|
||||
case 10:
|
||||
case 14:
|
||||
if (size == sizeof(uint16_t))
|
||||
return exchange_one_int16;
|
||||
else
|
||||
return exchange_int16s;
|
||||
default:
|
||||
if (size == 1)
|
||||
return exchange_one_byte;
|
||||
else
|
||||
return exchange_bytes;
|
||||
}
|
||||
}
|
||||
|
||||
static void heapsortx(void *base, size_t nmemb, size_t size, cmp_f cmp, void *opaque)
|
||||
{
|
||||
uint8_t *basep = (uint8_t *)base;
|
||||
size_t i, n, c, r;
|
||||
exchange_f swap = exchange_func(base, size);
|
||||
|
||||
if (nmemb > 1) {
|
||||
i = (nmemb / 2) * size;
|
||||
n = nmemb * size;
|
||||
|
||||
while (i > 0) {
|
||||
i -= size;
|
||||
for (r = i; (c = r * 2 + size) < n; r = c) {
|
||||
if (c < n - size && cmp(basep + c, basep + c + size, opaque) <= 0)
|
||||
c += size;
|
||||
if (cmp(basep + r, basep + c, opaque) > 0)
|
||||
break;
|
||||
swap(basep + r, basep + c, size);
|
||||
}
|
||||
}
|
||||
for (i = n - size; i > 0; i -= size) {
|
||||
swap(basep, basep + i, size);
|
||||
|
||||
for (r = 0; (c = r * 2 + size) < i; r = c) {
|
||||
if (c < i - size && cmp(basep + c, basep + c + size, opaque) <= 0)
|
||||
c += size;
|
||||
if (cmp(basep + r, basep + c, opaque) > 0)
|
||||
break;
|
||||
swap(basep + r, basep + c, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void *med3(void *a, void *b, void *c, cmp_f cmp, void *opaque)
|
||||
{
|
||||
return cmp(a, b, opaque) < 0 ?
|
||||
(cmp(b, c, opaque) < 0 ? b : (cmp(a, c, opaque) < 0 ? c : a )) :
|
||||
(cmp(b, c, opaque) > 0 ? b : (cmp(a, c, opaque) < 0 ? a : c ));
|
||||
}
|
||||
|
||||
/* pointer based version with local stack and insertion sort threshhold */
|
||||
void rqsort(void *base, size_t nmemb, size_t size, cmp_f cmp, void *opaque)
|
||||
{
|
||||
struct { uint8_t *base; size_t count; int depth; } stack[50], *sp = stack;
|
||||
uint8_t *ptr, *pi, *pj, *plt, *pgt, *top, *m;
|
||||
size_t m4, i, lt, gt, span, span2;
|
||||
int c, depth;
|
||||
exchange_f swap = exchange_func(base, size);
|
||||
exchange_f swap_block = exchange_func(base, size | 128);
|
||||
|
||||
if (nmemb < 2 || size <= 0)
|
||||
return;
|
||||
|
||||
sp->base = (uint8_t *)base;
|
||||
sp->count = nmemb;
|
||||
sp->depth = 0;
|
||||
sp++;
|
||||
|
||||
while (sp > stack) {
|
||||
sp--;
|
||||
ptr = sp->base;
|
||||
nmemb = sp->count;
|
||||
depth = sp->depth;
|
||||
|
||||
while (nmemb > 6) {
|
||||
if (++depth > 50) {
|
||||
/* depth check to ensure worst case logarithmic time */
|
||||
heapsortx(ptr, nmemb, size, cmp, opaque);
|
||||
nmemb = 0;
|
||||
break;
|
||||
}
|
||||
/* select median of 3 from 1/4, 1/2, 3/4 positions */
|
||||
/* should use median of 5 or 9? */
|
||||
m4 = (nmemb >> 2) * size;
|
||||
m = med3(ptr + m4, ptr + 2 * m4, ptr + 3 * m4, cmp, opaque);
|
||||
swap(ptr, m, size); /* move the pivot to the start or the array */
|
||||
i = lt = 1;
|
||||
pi = plt = ptr + size;
|
||||
gt = nmemb;
|
||||
pj = pgt = top = ptr + nmemb * size;
|
||||
for (;;) {
|
||||
while (pi < pj && (c = cmp(ptr, pi, opaque)) >= 0) {
|
||||
if (c == 0) {
|
||||
swap(plt, pi, size);
|
||||
lt++;
|
||||
plt += size;
|
||||
}
|
||||
i++;
|
||||
pi += size;
|
||||
}
|
||||
while (pi < (pj -= size) && (c = cmp(ptr, pj, opaque)) <= 0) {
|
||||
if (c == 0) {
|
||||
gt--;
|
||||
pgt -= size;
|
||||
swap(pgt, pj, size);
|
||||
}
|
||||
}
|
||||
if (pi >= pj)
|
||||
break;
|
||||
swap(pi, pj, size);
|
||||
i++;
|
||||
pi += size;
|
||||
}
|
||||
/* array has 4 parts:
|
||||
* from 0 to lt excluded: elements identical to pivot
|
||||
* from lt to pi excluded: elements smaller than pivot
|
||||
* from pi to gt excluded: elements greater than pivot
|
||||
* from gt to n excluded: elements identical to pivot
|
||||
*/
|
||||
/* move elements identical to pivot in the middle of the array: */
|
||||
/* swap values in ranges [0..lt[ and [i-lt..i[
|
||||
swapping the smallest span between lt and i-lt is sufficient
|
||||
*/
|
||||
span = plt - ptr;
|
||||
span2 = pi - plt;
|
||||
lt = i - lt;
|
||||
if (span > span2)
|
||||
span = span2;
|
||||
swap_block(ptr, pi - span, span);
|
||||
/* swap values in ranges [gt..top[ and [i..top-(top-gt)[
|
||||
swapping the smallest span between top-gt and gt-i is sufficient
|
||||
*/
|
||||
span = top - pgt;
|
||||
span2 = pgt - pi;
|
||||
pgt = top - span2;
|
||||
gt = nmemb - (gt - i);
|
||||
if (span > span2)
|
||||
span = span2;
|
||||
swap_block(pi, top - span, span);
|
||||
|
||||
/* now array has 3 parts:
|
||||
* from 0 to lt excluded: elements smaller than pivot
|
||||
* from lt to gt excluded: elements identical to pivot
|
||||
* from gt to n excluded: elements greater than pivot
|
||||
*/
|
||||
/* stack the larger segment and keep processing the smaller one
|
||||
to minimize stack use for pathological distributions */
|
||||
if (lt > nmemb - gt) {
|
||||
sp->base = ptr;
|
||||
sp->count = lt;
|
||||
sp->depth = depth;
|
||||
sp++;
|
||||
ptr = pgt;
|
||||
nmemb -= gt;
|
||||
} else {
|
||||
sp->base = pgt;
|
||||
sp->count = nmemb - gt;
|
||||
sp->depth = depth;
|
||||
sp++;
|
||||
nmemb = lt;
|
||||
}
|
||||
}
|
||||
/* Use insertion sort for small fragments */
|
||||
for (pi = ptr + size, top = ptr + nmemb * size; pi < top; pi += size) {
|
||||
for (pj = pi; pj > ptr && cmp(pj - size, pj, opaque) > 0; pj -= size)
|
||||
swap(pj, pj - size, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
300
quickjs/cutils.h
Normal file
|
@ -0,0 +1,300 @@
|
|||
/*
|
||||
* C utilities
|
||||
*
|
||||
* Copyright (c) 2017 Fabrice Bellard
|
||||
* Copyright (c) 2018 Charlie Gordon
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef CUTILS_H
|
||||
#define CUTILS_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
/* set if CPU is big endian */
|
||||
#undef WORDS_BIGENDIAN
|
||||
|
||||
#define likely(x) __builtin_expect(!!(x), 1)
|
||||
#define unlikely(x) __builtin_expect(!!(x), 0)
|
||||
#define force_inline inline __attribute__((always_inline))
|
||||
#define no_inline __attribute__((noinline))
|
||||
#define __maybe_unused __attribute__((unused))
|
||||
|
||||
#define xglue(x, y) x ## y
|
||||
#define glue(x, y) xglue(x, y)
|
||||
#define stringify(s) tostring(s)
|
||||
#define tostring(s) #s
|
||||
|
||||
#ifndef offsetof
|
||||
#define offsetof(type, field) ((size_t) &((type *)0)->field)
|
||||
#endif
|
||||
#ifndef countof
|
||||
#define countof(x) (sizeof(x) / sizeof((x)[0]))
|
||||
#endif
|
||||
|
||||
/* return the pointer of type 'type *' containing 'ptr' as field 'member' */
|
||||
#define container_of(ptr, type, member) ((type *)((uint8_t *)(ptr) - offsetof(type, member)))
|
||||
|
||||
typedef int BOOL;
|
||||
|
||||
#ifndef FALSE
|
||||
enum {
|
||||
FALSE = 0,
|
||||
TRUE = 1,
|
||||
};
|
||||
#endif
|
||||
|
||||
void pstrcpy(char *buf, int buf_size, const char *str);
|
||||
char *pstrcat(char *buf, int buf_size, const char *s);
|
||||
int strstart(const char *str, const char *val, const char **ptr);
|
||||
int has_suffix(const char *str, const char *suffix);
|
||||
|
||||
static inline int max_int(int a, int b)
|
||||
{
|
||||
if (a > b)
|
||||
return a;
|
||||
else
|
||||
return b;
|
||||
}
|
||||
|
||||
static inline int min_int(int a, int b)
|
||||
{
|
||||
if (a < b)
|
||||
return a;
|
||||
else
|
||||
return b;
|
||||
}
|
||||
|
||||
static inline uint32_t max_uint32(uint32_t a, uint32_t b)
|
||||
{
|
||||
if (a > b)
|
||||
return a;
|
||||
else
|
||||
return b;
|
||||
}
|
||||
|
||||
static inline uint32_t min_uint32(uint32_t a, uint32_t b)
|
||||
{
|
||||
if (a < b)
|
||||
return a;
|
||||
else
|
||||
return b;
|
||||
}
|
||||
|
||||
static inline int64_t max_int64(int64_t a, int64_t b)
|
||||
{
|
||||
if (a > b)
|
||||
return a;
|
||||
else
|
||||
return b;
|
||||
}
|
||||
|
||||
static inline int64_t min_int64(int64_t a, int64_t b)
|
||||
{
|
||||
if (a < b)
|
||||
return a;
|
||||
else
|
||||
return b;
|
||||
}
|
||||
|
||||
/* WARNING: undefined if a = 0 */
|
||||
static inline int clz32(unsigned int a)
|
||||
{
|
||||
return __builtin_clz(a);
|
||||
}
|
||||
|
||||
/* WARNING: undefined if a = 0 */
|
||||
static inline int clz64(uint64_t a)
|
||||
{
|
||||
return __builtin_clzll(a);
|
||||
}
|
||||
|
||||
/* WARNING: undefined if a = 0 */
|
||||
static inline int ctz32(unsigned int a)
|
||||
{
|
||||
return __builtin_ctz(a);
|
||||
}
|
||||
|
||||
/* WARNING: undefined if a = 0 */
|
||||
static inline int ctz64(uint64_t a)
|
||||
{
|
||||
return __builtin_ctzll(a);
|
||||
}
|
||||
|
||||
struct __attribute__((packed)) packed_u64 {
|
||||
uint64_t v;
|
||||
};
|
||||
|
||||
struct __attribute__((packed)) packed_u32 {
|
||||
uint32_t v;
|
||||
};
|
||||
|
||||
struct __attribute__((packed)) packed_u16 {
|
||||
uint16_t v;
|
||||
};
|
||||
|
||||
static inline uint64_t get_u64(const uint8_t *tab)
|
||||
{
|
||||
return ((const struct packed_u64 *)tab)->v;
|
||||
}
|
||||
|
||||
static inline int64_t get_i64(const uint8_t *tab)
|
||||
{
|
||||
return (int64_t)((const struct packed_u64 *)tab)->v;
|
||||
}
|
||||
|
||||
static inline void put_u64(uint8_t *tab, uint64_t val)
|
||||
{
|
||||
((struct packed_u64 *)tab)->v = val;
|
||||
}
|
||||
|
||||
static inline uint32_t get_u32(const uint8_t *tab)
|
||||
{
|
||||
return ((const struct packed_u32 *)tab)->v;
|
||||
}
|
||||
|
||||
static inline int32_t get_i32(const uint8_t *tab)
|
||||
{
|
||||
return (int32_t)((const struct packed_u32 *)tab)->v;
|
||||
}
|
||||
|
||||
static inline void put_u32(uint8_t *tab, uint32_t val)
|
||||
{
|
||||
((struct packed_u32 *)tab)->v = val;
|
||||
}
|
||||
|
||||
static inline uint32_t get_u16(const uint8_t *tab)
|
||||
{
|
||||
return ((const struct packed_u16 *)tab)->v;
|
||||
}
|
||||
|
||||
static inline int32_t get_i16(const uint8_t *tab)
|
||||
{
|
||||
return (int16_t)((const struct packed_u16 *)tab)->v;
|
||||
}
|
||||
|
||||
static inline void put_u16(uint8_t *tab, uint16_t val)
|
||||
{
|
||||
((struct packed_u16 *)tab)->v = val;
|
||||
}
|
||||
|
||||
static inline uint32_t get_u8(const uint8_t *tab)
|
||||
{
|
||||
return *tab;
|
||||
}
|
||||
|
||||
static inline int32_t get_i8(const uint8_t *tab)
|
||||
{
|
||||
return (int8_t)*tab;
|
||||
}
|
||||
|
||||
static inline void put_u8(uint8_t *tab, uint8_t val)
|
||||
{
|
||||
*tab = val;
|
||||
}
|
||||
|
||||
static inline uint16_t bswap16(uint16_t x)
|
||||
{
|
||||
return (x >> 8) | (x << 8);
|
||||
}
|
||||
|
||||
static inline uint32_t bswap32(uint32_t v)
|
||||
{
|
||||
return ((v & 0xff000000) >> 24) | ((v & 0x00ff0000) >> 8) |
|
||||
((v & 0x0000ff00) << 8) | ((v & 0x000000ff) << 24);
|
||||
}
|
||||
|
||||
static inline uint64_t bswap64(uint64_t v)
|
||||
{
|
||||
return ((v & ((uint64_t)0xff << (7 * 8))) >> (7 * 8)) |
|
||||
((v & ((uint64_t)0xff << (6 * 8))) >> (5 * 8)) |
|
||||
((v & ((uint64_t)0xff << (5 * 8))) >> (3 * 8)) |
|
||||
((v & ((uint64_t)0xff << (4 * 8))) >> (1 * 8)) |
|
||||
((v & ((uint64_t)0xff << (3 * 8))) << (1 * 8)) |
|
||||
((v & ((uint64_t)0xff << (2 * 8))) << (3 * 8)) |
|
||||
((v & ((uint64_t)0xff << (1 * 8))) << (5 * 8)) |
|
||||
((v & ((uint64_t)0xff << (0 * 8))) << (7 * 8));
|
||||
}
|
||||
|
||||
/* XXX: should take an extra argument to pass slack information to the caller */
|
||||
typedef void *DynBufReallocFunc(void *opaque, void *ptr, size_t size);
|
||||
|
||||
typedef struct DynBuf {
|
||||
uint8_t *buf;
|
||||
size_t size;
|
||||
size_t allocated_size;
|
||||
BOOL error; /* true if a memory allocation error occurred */
|
||||
DynBufReallocFunc *realloc_func;
|
||||
void *opaque; /* for realloc_func */
|
||||
} DynBuf;
|
||||
|
||||
void dbuf_init(DynBuf *s);
|
||||
void dbuf_init2(DynBuf *s, void *opaque, DynBufReallocFunc *realloc_func);
|
||||
int dbuf_realloc(DynBuf *s, size_t new_size);
|
||||
int dbuf_write(DynBuf *s, size_t offset, const uint8_t *data, size_t len);
|
||||
int dbuf_put(DynBuf *s, const uint8_t *data, size_t len);
|
||||
int dbuf_put_self(DynBuf *s, size_t offset, size_t len);
|
||||
int dbuf_putc(DynBuf *s, uint8_t c);
|
||||
int dbuf_putstr(DynBuf *s, const char *str);
|
||||
static inline int dbuf_put_u16(DynBuf *s, uint16_t val)
|
||||
{
|
||||
return dbuf_put(s, (uint8_t *)&val, 2);
|
||||
}
|
||||
static inline int dbuf_put_u32(DynBuf *s, uint32_t val)
|
||||
{
|
||||
return dbuf_put(s, (uint8_t *)&val, 4);
|
||||
}
|
||||
static inline int dbuf_put_u64(DynBuf *s, uint64_t val)
|
||||
{
|
||||
return dbuf_put(s, (uint8_t *)&val, 8);
|
||||
}
|
||||
int __attribute__((format(printf, 2, 3))) dbuf_printf(DynBuf *s,
|
||||
const char *fmt, ...);
|
||||
void dbuf_free(DynBuf *s);
|
||||
static inline BOOL dbuf_error(DynBuf *s) {
|
||||
return s->error;
|
||||
}
|
||||
static inline void dbuf_set_error(DynBuf *s)
|
||||
{
|
||||
s->error = TRUE;
|
||||
}
|
||||
|
||||
#define UTF8_CHAR_LEN_MAX 6
|
||||
|
||||
int unicode_to_utf8(uint8_t *buf, unsigned int c);
|
||||
int unicode_from_utf8(const uint8_t *p, int max_len, const uint8_t **pp);
|
||||
|
||||
static inline int from_hex(int c)
|
||||
{
|
||||
if (c >= '0' && c <= '9')
|
||||
return c - '0';
|
||||
else if (c >= 'A' && c <= 'F')
|
||||
return c - 'A' + 10;
|
||||
else if (c >= 'a' && c <= 'f')
|
||||
return c - 'a' + 10;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
void rqsort(void *base, size_t nmemb, size_t size,
|
||||
int (*cmp)(const void *, const void *, void *),
|
||||
void *arg);
|
||||
|
||||
#endif /* CUTILS_H */
|
589
quickjs/doc/jsbignum.texi
Normal file
|
@ -0,0 +1,589 @@
|
|||
\input texinfo
|
||||
|
||||
@iftex
|
||||
@afourpaper
|
||||
@headings double
|
||||
@end iftex
|
||||
|
||||
@titlepage
|
||||
@afourpaper
|
||||
@sp 7
|
||||
@center @titlefont{Javascript Bignum Extensions}
|
||||
@sp 3
|
||||
@center Version 2020-01-11
|
||||
@sp 3
|
||||
@center Author: Fabrice Bellard
|
||||
@end titlepage
|
||||
|
||||
@setfilename jsbignum.info
|
||||
@settitle Javascript Bignum Extensions
|
||||
|
||||
@contents
|
||||
|
||||
@chapter Introduction
|
||||
|
||||
The Bignum extensions add the following features to the Javascript
|
||||
language while being 100% backward compatible:
|
||||
|
||||
@itemize
|
||||
|
||||
@item Operator overloading with a dispatch logic inspired from the proposal available at @url{https://github.com/tc39/proposal-operator-overloading/}.
|
||||
|
||||
@item Arbitrarily large floating point numbers (@code{BigFloat}) in base 2 using the IEEE 754 semantics.
|
||||
|
||||
@item Arbitrarily large floating point numbers (@code{BigDecimal}) in base 10 based on the proposal available at
|
||||
@url{https://github.com/littledan/proposal-bigdecimal}.
|
||||
|
||||
@item @code{math} mode: arbitrarily large integers and floating point numbers are available by default. The integer division and power can be overloaded for example to return a fraction. The modulo operator (@code{%}) is defined as the Euclidian
|
||||
remainder. @code{^} is an alias to the power operator
|
||||
(@code{**}). @code{^^} is used as the exclusive or operator.
|
||||
|
||||
@end itemize
|
||||
|
||||
The extensions are independent from each other except the @code{math}
|
||||
mode which relies on BigFloat and operator overloading.
|
||||
|
||||
@chapter Operator overloading
|
||||
|
||||
Operator overloading is inspired from the proposal available at
|
||||
@url{https://github.com/tc39/proposal-operator-overloading/}. It
|
||||
implements the same dispatch logic but finds the operator sets by
|
||||
looking at the @code{Symbol.operatorSet} property in the objects. The
|
||||
changes were done in order to simplify the implementation.
|
||||
|
||||
More precisely, the following modifications were made:
|
||||
|
||||
@itemize
|
||||
|
||||
@item @code{with operators from} is not supported. Operator overloading is always enabled.
|
||||
|
||||
@item The dispatch is not based on a static @code{[[OperatorSet]]} field in all instances. Instead, a dynamic lookup of the @code{Symbol.operatorSet} property is done. This property is typically added in the prototype of each object.
|
||||
|
||||
@item @code{Operators.create(...dictionaries)} is used to create a new OperatorSet object. The @code{Operators} function is supported as an helper to be closer to the TC39 proposal.
|
||||
|
||||
@item @code{[]} cannot be overloaded.
|
||||
|
||||
@item In math mode, the BigInt division and power operators can be overloaded with @code{Operators.updateBigIntOperators(dictionary)}.
|
||||
|
||||
@end itemize
|
||||
|
||||
@chapter BigInt extensions
|
||||
|
||||
A few properties are added to the BigInt object:
|
||||
|
||||
@table @code
|
||||
|
||||
@item tdiv(a, b)
|
||||
Return @math{trunc(a/b)}. @code{b = 0} raises a RangeError
|
||||
exception.
|
||||
|
||||
@item fdiv(a, b)
|
||||
Return @math{\lfloor a/b \rfloor}. @code{b = 0} raises a RangeError
|
||||
exception.
|
||||
|
||||
@item cdiv(a, b)
|
||||
Return @math{\lceil a/b \rceil}. @code{b = 0} raises a RangeError
|
||||
exception.
|
||||
|
||||
@item ediv(a, b)
|
||||
Return @math{sgn(b) \lfloor a/{|b|} \rfloor} (Euclidian
|
||||
division). @code{b = 0} raises a RangeError exception.
|
||||
|
||||
@item tdivrem(a, b)
|
||||
@item fdivrem(a, b)
|
||||
@item cdivrem(a, b)
|
||||
@item edivrem(a, b)
|
||||
Return an array of two elements. The first element is the quotient,
|
||||
the second is the remainder. The same rounding is done as the
|
||||
corresponding division operation.
|
||||
|
||||
@item sqrt(a)
|
||||
Return @math{\lfloor \sqrt(a) \rfloor}. A RangeError exception is
|
||||
raised if @math{a < 0}.
|
||||
|
||||
@item sqrtrem(a)
|
||||
Return an array of two elements. The first element is @math{\lfloor
|
||||
\sqrt{a} \rfloor}. The second element is @math{a-\lfloor \sqrt{a}
|
||||
\rfloor^2}. A RangeError exception is raised if @math{a < 0}.
|
||||
|
||||
@item floorLog2(a)
|
||||
Return -1 if @math{a \leq 0} otherwise return @math{\lfloor \log2(a) \rfloor}.
|
||||
|
||||
@item ctz(a)
|
||||
Return the number of trailing zeros in the two's complement binary representation of a. Return -1 if @math{a=0}.
|
||||
|
||||
@end table
|
||||
|
||||
@chapter BigFloat
|
||||
|
||||
@section Introduction
|
||||
|
||||
This extension adds the @code{BigFloat} primitive type. The
|
||||
@code{BigFloat} type represents floating point numbers in base 2
|
||||
with the IEEE 754 semantics. A floating
|
||||
point number is represented as a sign, mantissa and exponent. The
|
||||
special values @code{NaN}, @code{+/-Infinity}, @code{+0} and @code{-0}
|
||||
are supported. The mantissa and exponent can have any bit length with
|
||||
an implementation specific minimum and maximum.
|
||||
|
||||
@section Floating point rounding
|
||||
|
||||
Each floating point operation operates with infinite precision and
|
||||
then rounds the result according to the specified floating point
|
||||
environment (@code{BigFloatEnv} object). The status flags of the
|
||||
environment are also set according to the result of the operation.
|
||||
|
||||
If no floating point environment is provided, the global floating
|
||||
point environment is used.
|
||||
|
||||
The rounding mode of the global floating point environment is always
|
||||
@code{RNDN} (``round to nearest with ties to even'')@footnote{The
|
||||
rationale is that the rounding mode changes must always be
|
||||
explicit.}. The status flags of the global environment cannot be
|
||||
read@footnote{The rationale is to avoid side effects for the built-in
|
||||
operators.}. The precision of the global environment is
|
||||
@code{BigFloatEnv.prec}. The number of exponent bits of the global
|
||||
environment is @code{BigFloatEnv.expBits}. The global environment
|
||||
subnormal flag is set to @code{true}.
|
||||
|
||||
For example, @code{prec = 53} and @code{ expBits = 11} exactly give
|
||||
the same precision as the IEEE 754 64 bit floating point format. The
|
||||
default precision is @code{prec = 113} and @code{ expBits = 15} (IEEE
|
||||
754 128 bit floating point format).
|
||||
|
||||
The global floating point environment can only be modified temporarily
|
||||
when calling a function (see @code{BigFloatEnv.setPrec}). Hence a
|
||||
function can change the global floating point environment for its
|
||||
callees but not for its caller.
|
||||
|
||||
@section Operators
|
||||
|
||||
The builtin operators are extended so that a BigFloat is returned if
|
||||
at least one operand is a BigFloat. The computations are always done
|
||||
with infinite precision and rounded according to the global floating
|
||||
point environment.
|
||||
|
||||
@code{typeof} applied on a @code{BigFloat} returns @code{bigfloat}.
|
||||
|
||||
BigFloat can be compared with all the other numeric types and the
|
||||
result follows the expected mathematical relations.
|
||||
|
||||
However, since BigFloat and Number are different types they are never
|
||||
equal when using the strict comparison operators (e.g. @code{0.0 ===
|
||||
0.0l} is false).
|
||||
|
||||
@section BigFloat literals
|
||||
|
||||
BigFloat literals are floating point numbers with a trailing @code{l}
|
||||
suffix. BigFloat literals have an infinite precision. They are rounded
|
||||
according to the global floating point environment when they are
|
||||
evaluated.@footnote{Base 10 floating point literals cannot usually be
|
||||
exactly represented as base 2 floating point number. In order to
|
||||
ensure that the literal is represented accurately with the current
|
||||
precision, it must be evaluated at runtime.}
|
||||
|
||||
@section Builtin Object changes
|
||||
|
||||
@subsection @code{BigFloat} function
|
||||
|
||||
The @code{BigFloat} function cannot be invoked as a constructor. When
|
||||
invoked as a function: the parameter is converted to a primitive
|
||||
type. If the result is a numeric type, it is converted to BigFloat
|
||||
without rounding. If the result is a string, it is converted to
|
||||
BigFloat using the precision of the global floating point environment.
|
||||
|
||||
@code{BigFloat} properties:
|
||||
|
||||
@table @code
|
||||
|
||||
@item LN2
|
||||
@item PI
|
||||
Getter. Return the value of the corresponding mathematical constant
|
||||
rounded to nearest, ties to even with the current global
|
||||
precision. The constant values are cached for small precisions.
|
||||
|
||||
@item MIN_VALUE
|
||||
@item MAX_VALUE
|
||||
@item EPSILON
|
||||
Getter. Return the minimum, maximum and epsilon @code{BigFloat} values
|
||||
(same definition as the corresponding @code{Number} constants).
|
||||
|
||||
@item fpRound(a[, e])
|
||||
Round the floating point number @code{a} according to the floating
|
||||
point environment @code{e} or the global environment if @code{e} is
|
||||
undefined.
|
||||
|
||||
@item parseFloat(a[, radix[, e]])
|
||||
Parse the string @code{a} as a floating point number in radix
|
||||
@code{radix}. The radix is 0 (default) or from 2 to 36. The radix 0
|
||||
means radix 10 unless there is a hexadecimal or binary prefix. The
|
||||
result is rounded according to the floating point environment @code{e}
|
||||
or the global environment if @code{e} is undefined.
|
||||
|
||||
@item isFinite(a)
|
||||
Return true if @code{a} is a finite bigfloat.
|
||||
|
||||
@item isNaN(a)
|
||||
Return true if @code{a} is a NaN bigfloat.
|
||||
|
||||
@item add(a, b[, e])
|
||||
@item sub(a, b[, e])
|
||||
@item mul(a, b[, e])
|
||||
@item div(a, b[, e])
|
||||
Perform the specified floating point operation and round the floating
|
||||
point number @code{a} according to the floating point environment
|
||||
@code{e} or the global environment if @code{e} is undefined. If
|
||||
@code{e} is specified, the floating point status flags are updated.
|
||||
|
||||
@item floor(x)
|
||||
@item ceil(x)
|
||||
@item round(x)
|
||||
@item trunc(x)
|
||||
Round to an integer. No additional rounding is performed.
|
||||
|
||||
@item abs(x)
|
||||
Return the absolute value of x. No additional rounding is performed.
|
||||
|
||||
@item fmod(x, y[, e])
|
||||
@item remainder(x, y[, e])
|
||||
Floating point remainder. The quotient is truncated to zero (fmod) or
|
||||
to the nearest integer with ties to even (remainder). @code{e} is an
|
||||
optional floating point environment.
|
||||
|
||||
@item sqrt(x[, e])
|
||||
Square root. Return a rounded floating point number. @code{e} is an
|
||||
optional floating point environment.
|
||||
|
||||
@item sin(x[, e])
|
||||
@item cos(x[, e])
|
||||
@item tan(x[, e])
|
||||
@item asin(x[, e])
|
||||
@item acos(x[, e])
|
||||
@item atan(x[, e])
|
||||
@item atan2(x, y[, e])
|
||||
@item exp(x[, e])
|
||||
@item log(x[, e])
|
||||
@item pow(x, y[, e])
|
||||
Transcendental operations. Return a rounded floating point
|
||||
number. @code{e} is an optional floating point environment.
|
||||
|
||||
@end table
|
||||
|
||||
@subsection @code{BigFloat.prototype}
|
||||
|
||||
The following properties are modified:
|
||||
|
||||
@table @code
|
||||
@item valueOf()
|
||||
Return the bigfloat primitive value corresponding to @code{this}.
|
||||
|
||||
@item toString(radix)
|
||||
|
||||
For floating point numbers:
|
||||
|
||||
@itemize
|
||||
@item
|
||||
If the radix is a power of two, the conversion is done with infinite
|
||||
precision.
|
||||
@item
|
||||
Otherwise, the number is rounded to nearest with ties to even using
|
||||
the global precision. It is then converted to string using the minimum
|
||||
number of digits so that its conversion back to a floating point using
|
||||
the global precision and round to nearest gives the same number.
|
||||
|
||||
@end itemize
|
||||
|
||||
The exponent letter is @code{e} for base 10, @code{p} for bases 2, 8,
|
||||
16 with a binary exponent and @code{@@} for the other bases.
|
||||
|
||||
@item toPrecision(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)
|
||||
@item toFixed(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)
|
||||
@item toExponential(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)
|
||||
Same semantics as the corresponding @code{Number} functions with
|
||||
BigFloats. There is no limit on the accepted precision @code{p}. The
|
||||
rounding mode and radix can be optionally specified. The radix must be
|
||||
between 2 and 36.
|
||||
|
||||
@end table
|
||||
|
||||
@subsection @code{BigFloatEnv} constructor
|
||||
|
||||
The @code{BigFloatEnv([p, [,rndMode]]} constructor cannot be invoked as a
|
||||
function. The floating point environment contains:
|
||||
|
||||
@itemize
|
||||
@item the mantissa precision in bits
|
||||
|
||||
@item the exponent size in bits assuming an IEEE 754 representation;
|
||||
|
||||
@item the subnormal flag (if true, subnormal floating point numbers can
|
||||
be generated by the floating point operations).
|
||||
|
||||
@item the rounding mode
|
||||
|
||||
@item the floating point status. The status flags can only be set by the floating point operations. They can be reset with @code{BigFloatEnv.prototype.clearStatus()} or with the various status flag setters.
|
||||
|
||||
@end itemize
|
||||
|
||||
@code{new BigFloatEnv([p, [,rndMode]]} creates a new floating point
|
||||
environment. The status flags are reset. If no parameter is given the
|
||||
precision, exponent bits and subnormal flags are copied from the
|
||||
global floating point environment. Otherwise, the precision is set to
|
||||
@code{p}, the number of exponent bits is set to @code{expBitsMax} and the
|
||||
subnormal flags is set to @code{false}. If @code{rndMode} is
|
||||
@code{undefined}, the rounding mode is set to @code{RNDN}.
|
||||
|
||||
@code{BigFloatEnv} properties:
|
||||
|
||||
@table @code
|
||||
|
||||
@item prec
|
||||
Getter. Return the precision in bits of the global floating point
|
||||
environment. The initial value is @code{113}.
|
||||
|
||||
@item expBits
|
||||
Getter. Return the exponent size in bits of the global floating point
|
||||
environment assuming an IEEE 754 representation. The initial value is
|
||||
@code{15}.
|
||||
|
||||
@item setPrec(f, p[, e])
|
||||
Set the precision of the global floating point environment to @code{p}
|
||||
and the exponent size to @code{e} then call the function
|
||||
@code{f}. Then the Float precision and exponent size are reset to
|
||||
their precious value and the return value of @code{f} is returned (or
|
||||
an exception is raised if @code{f} raised an exception). If @code{e}
|
||||
is @code{undefined} it is set to @code{BigFloatEnv.expBitsMax}.
|
||||
|
||||
@item precMin
|
||||
Read-only integer. Return the minimum allowed precision. Must be at least 2.
|
||||
|
||||
@item precMax
|
||||
Read-only integer. Return the maximum allowed precision. Must be at least 113.
|
||||
|
||||
@item expBitsMin
|
||||
Read-only integer. Return the minimum allowed exponent size in
|
||||
bits. Must be at least 3.
|
||||
|
||||
@item expBitsMax
|
||||
Read-only integer. Return the maximum allowed exponent size in
|
||||
bits. Must be at least 15.
|
||||
|
||||
@item RNDN
|
||||
Read-only integer. Round to nearest, with ties to even rounding mode.
|
||||
|
||||
@item RNDZ
|
||||
Read-only integer. Round to zero rounding mode.
|
||||
|
||||
@item RNDD
|
||||
Read-only integer. Round to -Infinity rounding mode.
|
||||
|
||||
@item RNDU
|
||||
Read-only integer. Round to +Infinity rounding mode.
|
||||
|
||||
@item RNDNA
|
||||
Read-only integer. Round to nearest, with ties away from zero rounding mode.
|
||||
|
||||
@item RNDA
|
||||
Read-only integer. Round away from zero rounding mode.
|
||||
|
||||
@item RNDF@footnote{Could be removed in case a deterministic behavior for floating point operations is required.}
|
||||
Read-only integer. Faithful rounding mode. The result is
|
||||
non-deterministically rounded to -Infinity or +Infinity. This rounding
|
||||
mode usually gives a faster and deterministic running time for the
|
||||
floating point operations.
|
||||
|
||||
@end table
|
||||
|
||||
@code{BigFloatEnv.prototype} properties:
|
||||
|
||||
@table @code
|
||||
|
||||
@item prec
|
||||
Getter and setter (Integer). Return or set the precision in bits.
|
||||
|
||||
@item expBits
|
||||
Getter and setter (Integer). Return or set the exponent size in bits
|
||||
assuming an IEEE 754 representation.
|
||||
|
||||
@item rndMode
|
||||
Getter and setter (Integer). Return or set the rounding mode.
|
||||
|
||||
@item subnormal
|
||||
Getter and setter (Boolean). subnormal flag. It is false when
|
||||
@code{expBits = expBitsMax}.
|
||||
|
||||
@item clearStatus()
|
||||
Clear the status flags.
|
||||
|
||||
@item invalidOperation
|
||||
@item divideByZero
|
||||
@item overflow
|
||||
@item underflow
|
||||
@item inexact
|
||||
Getter and setter (Boolean). Status flags.
|
||||
|
||||
@end table
|
||||
|
||||
@chapter BigDecimal
|
||||
|
||||
This extension adds the @code{BigDecimal} primitive type. The
|
||||
@code{BigDecimal} type represents floating point numbers in base
|
||||
10. It is inspired from the proposal available at
|
||||
@url{https://github.com/littledan/proposal-bigdecimal}.
|
||||
|
||||
The @code{BigDecimal} floating point numbers are always normalized and
|
||||
finite. There is no concept of @code{-0}, @code{Infinity} or
|
||||
@code{NaN}. By default, all the computations are done with infinite
|
||||
precision.
|
||||
|
||||
@section Operators
|
||||
|
||||
The following builtin operators support BigDecimal:
|
||||
|
||||
@table @code
|
||||
|
||||
@item +
|
||||
@item -
|
||||
@item *
|
||||
Both operands must be BigDecimal. The result is computed with infinite
|
||||
precision.
|
||||
@item %
|
||||
Both operands must be BigDecimal. The result is computed with infinite
|
||||
precision. A range error is throws in case of division by zero.
|
||||
|
||||
@item /
|
||||
Both operands must be BigDecimal. A range error is throws in case of
|
||||
division by zero or if the result cannot be represented with infinite
|
||||
precision (use @code{BigDecimal.div} to specify the rounding).
|
||||
|
||||
@item **
|
||||
Both operands must be BigDecimal. The exponent must be a positive
|
||||
integer. The result is computed with infinite precision.
|
||||
|
||||
@item ===
|
||||
When one of the operand is a BigDecimal, return true if both operands
|
||||
are a BigDecimal and if they are equal.
|
||||
|
||||
@item ==
|
||||
@item !=
|
||||
@item <=
|
||||
@item >=
|
||||
@item <
|
||||
@item >
|
||||
|
||||
Numerical comparison. When one of the operand is not a BigDecimal, it is
|
||||
converted to BigDecimal by using ToString(). Hence comparisons between
|
||||
Number and BigDecimal do not use the exact mathematical value of the
|
||||
Number value.
|
||||
|
||||
@end table
|
||||
|
||||
@section BigDecimal literals
|
||||
|
||||
BigDecimal literals are decimal floating point numbers with a trailing
|
||||
@code{m} suffix.
|
||||
|
||||
@section Builtin Object changes
|
||||
|
||||
@subsection The @code{BigDecimal} function.
|
||||
|
||||
It returns @code{0m} if no parameter is provided. Otherwise the first
|
||||
parameter is converted to a bigdecimal by using ToString(). Hence
|
||||
Number values are not converted to their exact numerical value as
|
||||
BigDecimal.
|
||||
|
||||
@subsection Properties of the @code{BigDecimal} object
|
||||
|
||||
@table @code
|
||||
|
||||
@item add(a, b[, e])
|
||||
@item sub(a, b[, e])
|
||||
@item mul(a, b[, e])
|
||||
@item div(a, b[, e])
|
||||
@item mod(a, b[, e])
|
||||
@item sqrt(a, e)
|
||||
@item round(a, e)
|
||||
Perform the specified floating point operation and round the floating
|
||||
point result according to the rounding object @code{e}. If the
|
||||
rounding object is not present, the operation is executed with
|
||||
infinite precision.
|
||||
|
||||
For @code{div}, a @code{RangeError} exception is thrown in case of
|
||||
division by zero or if the result cannot be represented with infinite
|
||||
precision if no rounding object is present.
|
||||
|
||||
For @code{sqrt}, a range error is thrown if @code{a} is less than
|
||||
zero.
|
||||
|
||||
The rounding object must contain the following properties:
|
||||
@code{roundingMode} is a string specifying the rounding mode
|
||||
(@code{"floor"}, @code{"ceiling"}, @code{"down"}, @code{"up"},
|
||||
@code{"half-even"}, @code{"half-up"}). Either
|
||||
@code{maximumSignificantDigits} or @code{maximumFractionDigits} must
|
||||
be present to specify respectively the number of significant digits
|
||||
(must be >= 1) or the number of digits after the decimal point (must
|
||||
be >= 0).
|
||||
|
||||
@end table
|
||||
|
||||
@subsection Properties of the @code{BigDecimal.prototype} object
|
||||
|
||||
@table @code
|
||||
@item valueOf()
|
||||
Return the bigdecimal primitive value corresponding to @code{this}.
|
||||
|
||||
@item toString()
|
||||
Convert @code{this} to a string with infinite precision in base 10.
|
||||
|
||||
@item toPrecision(p, rnd_mode = "half-up")
|
||||
@item toFixed(p, rnd_mode = "half-up")
|
||||
@item toExponential(p, rnd_mode = "half-up")
|
||||
Convert the BigDecimal @code{this} to string with the specified
|
||||
precision @code{p}. There is no limit on the accepted precision
|
||||
@code{p}. The rounding mode can be optionally
|
||||
specified. @code{toPrecision} outputs either in decimal fixed notation
|
||||
or in decimal exponential notation with a @code{p} digits of
|
||||
precision. @code{toExponential} outputs in decimal exponential
|
||||
notation with @code{p} digits after the decimal point. @code{toFixed}
|
||||
outputs in decimal notation with @code{p} digits after the decimal
|
||||
point.
|
||||
|
||||
@end table
|
||||
|
||||
@chapter Math mode
|
||||
|
||||
A new @emph{math mode} is enabled with the @code{"use math"}
|
||||
directive. It propagates the same way as the @emph{strict mode}. It is
|
||||
designed so that arbitrarily large integers and floating point numbers
|
||||
are available by default. In order to minimize the number of changes
|
||||
in the Javascript semantics, integers are represented either as Number
|
||||
or BigInt depending on their magnitude. Floating point numbers are
|
||||
always represented as BigFloat.
|
||||
|
||||
The following changes are made to the Javascript semantics:
|
||||
|
||||
@itemize
|
||||
|
||||
@item Floating point literals (i.e. number with a decimal point or an exponent) are @code{BigFloat} by default (i.e. a @code{l} suffix is implied). Hence @code{typeof 1.0 === "bigfloat"}.
|
||||
|
||||
@item Integer literals (i.e. numbers without a decimal point or an exponent) with or without the @code{n} suffix are @code{BigInt} if their value cannot be represented as a safe integer. A safe integer is defined as a integer whose absolute value is smaller or equal to @code{2**53-1}. Hence @code{typeof 1 === "number "}, @code{typeof 1n === "number"} but @code{typeof 9007199254740992 === "bigint" }.
|
||||
|
||||
@item All the bigint builtin operators and functions are modified so that their result is returned as a Number if it is a safe integer. Otherwise the result stays a BigInt.
|
||||
|
||||
@item The builtin operators are modified so that they return an exact result (which can be a BigInt) if their operands are safe integers. Operands between Number and BigInt are accepted provided the Number operand is a safe integer. The integer power with a negative exponent returns a BigFloat as result. The integer division returns a BigFloat as result.
|
||||
|
||||
@item The @code{^} operator is an alias to the power operator (@code{**}).
|
||||
|
||||
@item The power operator (both @code{^} and @code{**}) grammar is modified so that @code{-2^2} is allowed and yields @code{-4}.
|
||||
|
||||
@item The logical xor operator is still available with the @code{^^} operator.
|
||||
|
||||
@item The modulo operator (@code{%}) returns the Euclidian remainder (always positive) instead of the truncated remainder.
|
||||
|
||||
@item The integer division operator can be overloaded with @code{Operators.updateBigIntOperators(dictionary)}.
|
||||
|
||||
@item The integer power operator with a non zero negative exponent can be overloaded with @code{Operators.updateBigIntOperators(dictionary)}.
|
||||
|
||||
@end itemize
|
||||
|
||||
@bye
|
1097
quickjs/doc/quickjs.texi
Normal file
8473
quickjs/libbf.c
Normal file
535
quickjs/libbf.h
Normal file
|
@ -0,0 +1,535 @@
|
|||
/*
|
||||
* Tiny arbitrary precision floating point library
|
||||
*
|
||||
* Copyright (c) 2017-2021 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef LIBBF_H
|
||||
#define LIBBF_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(__SIZEOF_INT128__) && (INTPTR_MAX >= INT64_MAX)
|
||||
#define LIMB_LOG2_BITS 6
|
||||
#else
|
||||
#define LIMB_LOG2_BITS 5
|
||||
#endif
|
||||
|
||||
#define LIMB_BITS (1 << LIMB_LOG2_BITS)
|
||||
|
||||
#if LIMB_BITS == 64
|
||||
typedef __int128 int128_t;
|
||||
typedef unsigned __int128 uint128_t;
|
||||
typedef int64_t slimb_t;
|
||||
typedef uint64_t limb_t;
|
||||
typedef uint128_t dlimb_t;
|
||||
#define BF_RAW_EXP_MIN INT64_MIN
|
||||
#define BF_RAW_EXP_MAX INT64_MAX
|
||||
|
||||
#define LIMB_DIGITS 19
|
||||
#define BF_DEC_BASE UINT64_C(10000000000000000000)
|
||||
|
||||
#else
|
||||
|
||||
typedef int32_t slimb_t;
|
||||
typedef uint32_t limb_t;
|
||||
typedef uint64_t dlimb_t;
|
||||
#define BF_RAW_EXP_MIN INT32_MIN
|
||||
#define BF_RAW_EXP_MAX INT32_MAX
|
||||
|
||||
#define LIMB_DIGITS 9
|
||||
#define BF_DEC_BASE 1000000000U
|
||||
|
||||
#endif
|
||||
|
||||
/* in bits */
|
||||
/* minimum number of bits for the exponent */
|
||||
#define BF_EXP_BITS_MIN 3
|
||||
/* maximum number of bits for the exponent */
|
||||
#define BF_EXP_BITS_MAX (LIMB_BITS - 3)
|
||||
/* extended range for exponent, used internally */
|
||||
#define BF_EXT_EXP_BITS_MAX (BF_EXP_BITS_MAX + 1)
|
||||
/* minimum possible precision */
|
||||
#define BF_PREC_MIN 2
|
||||
/* minimum possible precision */
|
||||
#define BF_PREC_MAX (((limb_t)1 << (LIMB_BITS - 2)) - 2)
|
||||
/* some operations support infinite precision */
|
||||
#define BF_PREC_INF (BF_PREC_MAX + 1) /* infinite precision */
|
||||
|
||||
#if LIMB_BITS == 64
|
||||
#define BF_CHKSUM_MOD (UINT64_C(975620677) * UINT64_C(9795002197))
|
||||
#else
|
||||
#define BF_CHKSUM_MOD 975620677U
|
||||
#endif
|
||||
|
||||
#define BF_EXP_ZERO BF_RAW_EXP_MIN
|
||||
#define BF_EXP_INF (BF_RAW_EXP_MAX - 1)
|
||||
#define BF_EXP_NAN BF_RAW_EXP_MAX
|
||||
|
||||
/* +/-zero is represented with expn = BF_EXP_ZERO and len = 0,
|
||||
+/-infinity is represented with expn = BF_EXP_INF and len = 0,
|
||||
NaN is represented with expn = BF_EXP_NAN and len = 0 (sign is ignored)
|
||||
*/
|
||||
typedef struct {
|
||||
struct bf_context_t *ctx;
|
||||
int sign;
|
||||
slimb_t expn;
|
||||
limb_t len;
|
||||
limb_t *tab;
|
||||
} bf_t;
|
||||
|
||||
typedef struct {
|
||||
/* must be kept identical to bf_t */
|
||||
struct bf_context_t *ctx;
|
||||
int sign;
|
||||
slimb_t expn;
|
||||
limb_t len;
|
||||
limb_t *tab;
|
||||
} bfdec_t;
|
||||
|
||||
typedef enum {
|
||||
BF_RNDN, /* round to nearest, ties to even */
|
||||
BF_RNDZ, /* round to zero */
|
||||
BF_RNDD, /* round to -inf (the code relies on (BF_RNDD xor BF_RNDU) = 1) */
|
||||
BF_RNDU, /* round to +inf */
|
||||
BF_RNDNA, /* round to nearest, ties away from zero */
|
||||
BF_RNDA, /* round away from zero */
|
||||
BF_RNDF, /* faithful rounding (nondeterministic, either RNDD or RNDU,
|
||||
inexact flag is always set) */
|
||||
} bf_rnd_t;
|
||||
|
||||
/* allow subnormal numbers. Only available if the number of exponent
|
||||
bits is <= BF_EXP_BITS_USER_MAX and prec != BF_PREC_INF. */
|
||||
#define BF_FLAG_SUBNORMAL (1 << 3)
|
||||
/* 'prec' is the precision after the radix point instead of the whole
|
||||
mantissa. Can only be used with bf_round() and
|
||||
bfdec_[add|sub|mul|div|sqrt|round](). */
|
||||
#define BF_FLAG_RADPNT_PREC (1 << 4)
|
||||
|
||||
#define BF_RND_MASK 0x7
|
||||
#define BF_EXP_BITS_SHIFT 5
|
||||
#define BF_EXP_BITS_MASK 0x3f
|
||||
|
||||
/* shortcut for bf_set_exp_bits(BF_EXT_EXP_BITS_MAX) */
|
||||
#define BF_FLAG_EXT_EXP (BF_EXP_BITS_MASK << BF_EXP_BITS_SHIFT)
|
||||
|
||||
/* contains the rounding mode and number of exponents bits */
|
||||
typedef uint32_t bf_flags_t;
|
||||
|
||||
typedef void *bf_realloc_func_t(void *opaque, void *ptr, size_t size);
|
||||
|
||||
typedef struct {
|
||||
bf_t val;
|
||||
limb_t prec;
|
||||
} BFConstCache;
|
||||
|
||||
typedef struct bf_context_t {
|
||||
void *realloc_opaque;
|
||||
bf_realloc_func_t *realloc_func;
|
||||
BFConstCache log2_cache;
|
||||
BFConstCache pi_cache;
|
||||
struct BFNTTState *ntt_state;
|
||||
} bf_context_t;
|
||||
|
||||
static inline int bf_get_exp_bits(bf_flags_t flags)
|
||||
{
|
||||
int e;
|
||||
e = (flags >> BF_EXP_BITS_SHIFT) & BF_EXP_BITS_MASK;
|
||||
if (e == BF_EXP_BITS_MASK)
|
||||
return BF_EXP_BITS_MAX + 1;
|
||||
else
|
||||
return BF_EXP_BITS_MAX - e;
|
||||
}
|
||||
|
||||
static inline bf_flags_t bf_set_exp_bits(int n)
|
||||
{
|
||||
return ((BF_EXP_BITS_MAX - n) & BF_EXP_BITS_MASK) << BF_EXP_BITS_SHIFT;
|
||||
}
|
||||
|
||||
/* returned status */
|
||||
#define BF_ST_INVALID_OP (1 << 0)
|
||||
#define BF_ST_DIVIDE_ZERO (1 << 1)
|
||||
#define BF_ST_OVERFLOW (1 << 2)
|
||||
#define BF_ST_UNDERFLOW (1 << 3)
|
||||
#define BF_ST_INEXACT (1 << 4)
|
||||
/* indicate that a memory allocation error occured. NaN is returned */
|
||||
#define BF_ST_MEM_ERROR (1 << 5)
|
||||
|
||||
#define BF_RADIX_MAX 36 /* maximum radix for bf_atof() and bf_ftoa() */
|
||||
|
||||
static inline slimb_t bf_max(slimb_t a, slimb_t b)
|
||||
{
|
||||
if (a > b)
|
||||
return a;
|
||||
else
|
||||
return b;
|
||||
}
|
||||
|
||||
static inline slimb_t bf_min(slimb_t a, slimb_t b)
|
||||
{
|
||||
if (a < b)
|
||||
return a;
|
||||
else
|
||||
return b;
|
||||
}
|
||||
|
||||
void bf_context_init(bf_context_t *s, bf_realloc_func_t *realloc_func,
|
||||
void *realloc_opaque);
|
||||
void bf_context_end(bf_context_t *s);
|
||||
/* free memory allocated for the bf cache data */
|
||||
void bf_clear_cache(bf_context_t *s);
|
||||
|
||||
static inline void *bf_realloc(bf_context_t *s, void *ptr, size_t size)
|
||||
{
|
||||
return s->realloc_func(s->realloc_opaque, ptr, size);
|
||||
}
|
||||
|
||||
/* 'size' must be != 0 */
|
||||
static inline void *bf_malloc(bf_context_t *s, size_t size)
|
||||
{
|
||||
return bf_realloc(s, NULL, size);
|
||||
}
|
||||
|
||||
static inline void bf_free(bf_context_t *s, void *ptr)
|
||||
{
|
||||
/* must test ptr otherwise equivalent to malloc(0) */
|
||||
if (ptr)
|
||||
bf_realloc(s, ptr, 0);
|
||||
}
|
||||
|
||||
void bf_init(bf_context_t *s, bf_t *r);
|
||||
|
||||
static inline void bf_delete(bf_t *r)
|
||||
{
|
||||
bf_context_t *s = r->ctx;
|
||||
/* we accept to delete a zeroed bf_t structure */
|
||||
if (s && r->tab) {
|
||||
bf_realloc(s, r->tab, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void bf_neg(bf_t *r)
|
||||
{
|
||||
r->sign ^= 1;
|
||||
}
|
||||
|
||||
static inline int bf_is_finite(const bf_t *a)
|
||||
{
|
||||
return (a->expn < BF_EXP_INF);
|
||||
}
|
||||
|
||||
static inline int bf_is_nan(const bf_t *a)
|
||||
{
|
||||
return (a->expn == BF_EXP_NAN);
|
||||
}
|
||||
|
||||
static inline int bf_is_zero(const bf_t *a)
|
||||
{
|
||||
return (a->expn == BF_EXP_ZERO);
|
||||
}
|
||||
|
||||
static inline void bf_memcpy(bf_t *r, const bf_t *a)
|
||||
{
|
||||
*r = *a;
|
||||
}
|
||||
|
||||
int bf_set_ui(bf_t *r, uint64_t a);
|
||||
int bf_set_si(bf_t *r, int64_t a);
|
||||
void bf_set_nan(bf_t *r);
|
||||
void bf_set_zero(bf_t *r, int is_neg);
|
||||
void bf_set_inf(bf_t *r, int is_neg);
|
||||
int bf_set(bf_t *r, const bf_t *a);
|
||||
void bf_move(bf_t *r, bf_t *a);
|
||||
int bf_get_float64(const bf_t *a, double *pres, bf_rnd_t rnd_mode);
|
||||
int bf_set_float64(bf_t *a, double d);
|
||||
|
||||
int bf_cmpu(const bf_t *a, const bf_t *b);
|
||||
int bf_cmp_full(const bf_t *a, const bf_t *b);
|
||||
int bf_cmp(const bf_t *a, const bf_t *b);
|
||||
static inline int bf_cmp_eq(const bf_t *a, const bf_t *b)
|
||||
{
|
||||
return bf_cmp(a, b) == 0;
|
||||
}
|
||||
|
||||
static inline int bf_cmp_le(const bf_t *a, const bf_t *b)
|
||||
{
|
||||
return bf_cmp(a, b) <= 0;
|
||||
}
|
||||
|
||||
static inline int bf_cmp_lt(const bf_t *a, const bf_t *b)
|
||||
{
|
||||
return bf_cmp(a, b) < 0;
|
||||
}
|
||||
|
||||
int bf_add(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags);
|
||||
int bf_sub(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags);
|
||||
int bf_add_si(bf_t *r, const bf_t *a, int64_t b1, limb_t prec, bf_flags_t flags);
|
||||
int bf_mul(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags);
|
||||
int bf_mul_ui(bf_t *r, const bf_t *a, uint64_t b1, limb_t prec, bf_flags_t flags);
|
||||
int bf_mul_si(bf_t *r, const bf_t *a, int64_t b1, limb_t prec,
|
||||
bf_flags_t flags);
|
||||
int bf_mul_2exp(bf_t *r, slimb_t e, limb_t prec, bf_flags_t flags);
|
||||
int bf_div(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags);
|
||||
#define BF_DIVREM_EUCLIDIAN BF_RNDF
|
||||
int bf_divrem(bf_t *q, bf_t *r, const bf_t *a, const bf_t *b,
|
||||
limb_t prec, bf_flags_t flags, int rnd_mode);
|
||||
int bf_rem(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
|
||||
bf_flags_t flags, int rnd_mode);
|
||||
int bf_remquo(slimb_t *pq, bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
|
||||
bf_flags_t flags, int rnd_mode);
|
||||
/* round to integer with infinite precision */
|
||||
int bf_rint(bf_t *r, int rnd_mode);
|
||||
int bf_round(bf_t *r, limb_t prec, bf_flags_t flags);
|
||||
int bf_sqrtrem(bf_t *r, bf_t *rem1, const bf_t *a);
|
||||
int bf_sqrt(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
|
||||
slimb_t bf_get_exp_min(const bf_t *a);
|
||||
int bf_logic_or(bf_t *r, const bf_t *a, const bf_t *b);
|
||||
int bf_logic_xor(bf_t *r, const bf_t *a, const bf_t *b);
|
||||
int bf_logic_and(bf_t *r, const bf_t *a, const bf_t *b);
|
||||
|
||||
/* additional flags for bf_atof */
|
||||
/* do not accept hex radix prefix (0x or 0X) if radix = 0 or radix = 16 */
|
||||
#define BF_ATOF_NO_HEX (1 << 16)
|
||||
/* accept binary (0b or 0B) or octal (0o or 0O) radix prefix if radix = 0 */
|
||||
#define BF_ATOF_BIN_OCT (1 << 17)
|
||||
/* Do not parse NaN or Inf */
|
||||
#define BF_ATOF_NO_NAN_INF (1 << 18)
|
||||
/* return the exponent separately */
|
||||
#define BF_ATOF_EXPONENT (1 << 19)
|
||||
|
||||
int bf_atof(bf_t *a, const char *str, const char **pnext, int radix,
|
||||
limb_t prec, bf_flags_t flags);
|
||||
/* this version accepts prec = BF_PREC_INF and returns the radix
|
||||
exponent */
|
||||
int bf_atof2(bf_t *r, slimb_t *pexponent,
|
||||
const char *str, const char **pnext, int radix,
|
||||
limb_t prec, bf_flags_t flags);
|
||||
int bf_mul_pow_radix(bf_t *r, const bf_t *T, limb_t radix,
|
||||
slimb_t expn, limb_t prec, bf_flags_t flags);
|
||||
|
||||
|
||||
/* Conversion of floating point number to string. Return a null
|
||||
terminated string or NULL if memory error. *plen contains its
|
||||
length if plen != NULL. The exponent letter is "e" for base 10,
|
||||
"p" for bases 2, 8, 16 with a binary exponent and "@" for the other
|
||||
bases. */
|
||||
|
||||
#define BF_FTOA_FORMAT_MASK (3 << 16)
|
||||
|
||||
/* fixed format: prec significant digits rounded with (flags &
|
||||
BF_RND_MASK). Exponential notation is used if too many zeros are
|
||||
needed.*/
|
||||
#define BF_FTOA_FORMAT_FIXED (0 << 16)
|
||||
/* fractional format: prec digits after the decimal point rounded with
|
||||
(flags & BF_RND_MASK) */
|
||||
#define BF_FTOA_FORMAT_FRAC (1 << 16)
|
||||
/* free format:
|
||||
|
||||
For binary radices with bf_ftoa() and for bfdec_ftoa(): use the minimum
|
||||
number of digits to represent 'a'. The precision and the rounding
|
||||
mode are ignored.
|
||||
|
||||
For the non binary radices with bf_ftoa(): use as many digits as
|
||||
necessary so that bf_atof() return the same number when using
|
||||
precision 'prec', rounding to nearest and the subnormal
|
||||
configuration of 'flags'. The result is meaningful only if 'a' is
|
||||
already rounded to 'prec' bits. If the subnormal flag is set, the
|
||||
exponent in 'flags' must also be set to the desired exponent range.
|
||||
*/
|
||||
#define BF_FTOA_FORMAT_FREE (2 << 16)
|
||||
/* same as BF_FTOA_FORMAT_FREE but uses the minimum number of digits
|
||||
(takes more computation time). Identical to BF_FTOA_FORMAT_FREE for
|
||||
binary radices with bf_ftoa() and for bfdec_ftoa(). */
|
||||
#define BF_FTOA_FORMAT_FREE_MIN (3 << 16)
|
||||
|
||||
/* force exponential notation for fixed or free format */
|
||||
#define BF_FTOA_FORCE_EXP (1 << 20)
|
||||
/* add 0x prefix for base 16, 0o prefix for base 8 or 0b prefix for
|
||||
base 2 if non zero value */
|
||||
#define BF_FTOA_ADD_PREFIX (1 << 21)
|
||||
/* return "Infinity" instead of "Inf" and add a "+" for positive
|
||||
exponents */
|
||||
#define BF_FTOA_JS_QUIRKS (1 << 22)
|
||||
|
||||
char *bf_ftoa(size_t *plen, const bf_t *a, int radix, limb_t prec,
|
||||
bf_flags_t flags);
|
||||
|
||||
/* modulo 2^n instead of saturation. NaN and infinity return 0 */
|
||||
#define BF_GET_INT_MOD (1 << 0)
|
||||
int bf_get_int32(int *pres, const bf_t *a, int flags);
|
||||
int bf_get_int64(int64_t *pres, const bf_t *a, int flags);
|
||||
int bf_get_uint64(uint64_t *pres, const bf_t *a);
|
||||
|
||||
/* the following functions are exported for testing only. */
|
||||
void mp_print_str(const char *str, const limb_t *tab, limb_t n);
|
||||
void bf_print_str(const char *str, const bf_t *a);
|
||||
int bf_resize(bf_t *r, limb_t len);
|
||||
int bf_get_fft_size(int *pdpl, int *pnb_mods, limb_t len);
|
||||
int bf_normalize_and_round(bf_t *r, limb_t prec1, bf_flags_t flags);
|
||||
int bf_can_round(const bf_t *a, slimb_t prec, bf_rnd_t rnd_mode, slimb_t k);
|
||||
slimb_t bf_mul_log2_radix(slimb_t a1, unsigned int radix, int is_inv,
|
||||
int is_ceil1);
|
||||
int mp_mul(bf_context_t *s, limb_t *result,
|
||||
const limb_t *op1, limb_t op1_size,
|
||||
const limb_t *op2, limb_t op2_size);
|
||||
limb_t mp_add(limb_t *res, const limb_t *op1, const limb_t *op2,
|
||||
limb_t n, limb_t carry);
|
||||
limb_t mp_add_ui(limb_t *tab, limb_t b, size_t n);
|
||||
int mp_sqrtrem(bf_context_t *s, limb_t *tabs, limb_t *taba, limb_t n);
|
||||
int mp_recip(bf_context_t *s, limb_t *tabr, const limb_t *taba, limb_t n);
|
||||
limb_t bf_isqrt(limb_t a);
|
||||
|
||||
/* transcendental functions */
|
||||
int bf_const_log2(bf_t *T, limb_t prec, bf_flags_t flags);
|
||||
int bf_const_pi(bf_t *T, limb_t prec, bf_flags_t flags);
|
||||
int bf_exp(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
|
||||
int bf_log(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
|
||||
#define BF_POW_JS_QUIRKS (1 << 16) /* (+/-1)^(+/-Inf) = NaN, 1^NaN = NaN */
|
||||
int bf_pow(bf_t *r, const bf_t *x, const bf_t *y, limb_t prec, bf_flags_t flags);
|
||||
int bf_cos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
|
||||
int bf_sin(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
|
||||
int bf_tan(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
|
||||
int bf_atan(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
|
||||
int bf_atan2(bf_t *r, const bf_t *y, const bf_t *x,
|
||||
limb_t prec, bf_flags_t flags);
|
||||
int bf_asin(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
|
||||
int bf_acos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
|
||||
|
||||
/* decimal floating point */
|
||||
|
||||
static inline void bfdec_init(bf_context_t *s, bfdec_t *r)
|
||||
{
|
||||
bf_init(s, (bf_t *)r);
|
||||
}
|
||||
static inline void bfdec_delete(bfdec_t *r)
|
||||
{
|
||||
bf_delete((bf_t *)r);
|
||||
}
|
||||
|
||||
static inline void bfdec_neg(bfdec_t *r)
|
||||
{
|
||||
r->sign ^= 1;
|
||||
}
|
||||
|
||||
static inline int bfdec_is_finite(const bfdec_t *a)
|
||||
{
|
||||
return (a->expn < BF_EXP_INF);
|
||||
}
|
||||
|
||||
static inline int bfdec_is_nan(const bfdec_t *a)
|
||||
{
|
||||
return (a->expn == BF_EXP_NAN);
|
||||
}
|
||||
|
||||
static inline int bfdec_is_zero(const bfdec_t *a)
|
||||
{
|
||||
return (a->expn == BF_EXP_ZERO);
|
||||
}
|
||||
|
||||
static inline void bfdec_memcpy(bfdec_t *r, const bfdec_t *a)
|
||||
{
|
||||
bf_memcpy((bf_t *)r, (const bf_t *)a);
|
||||
}
|
||||
|
||||
int bfdec_set_ui(bfdec_t *r, uint64_t a);
|
||||
int bfdec_set_si(bfdec_t *r, int64_t a);
|
||||
|
||||
static inline void bfdec_set_nan(bfdec_t *r)
|
||||
{
|
||||
bf_set_nan((bf_t *)r);
|
||||
}
|
||||
static inline void bfdec_set_zero(bfdec_t *r, int is_neg)
|
||||
{
|
||||
bf_set_zero((bf_t *)r, is_neg);
|
||||
}
|
||||
static inline void bfdec_set_inf(bfdec_t *r, int is_neg)
|
||||
{
|
||||
bf_set_inf((bf_t *)r, is_neg);
|
||||
}
|
||||
static inline int bfdec_set(bfdec_t *r, const bfdec_t *a)
|
||||
{
|
||||
return bf_set((bf_t *)r, (bf_t *)a);
|
||||
}
|
||||
static inline void bfdec_move(bfdec_t *r, bfdec_t *a)
|
||||
{
|
||||
bf_move((bf_t *)r, (bf_t *)a);
|
||||
}
|
||||
static inline int bfdec_cmpu(const bfdec_t *a, const bfdec_t *b)
|
||||
{
|
||||
return bf_cmpu((const bf_t *)a, (const bf_t *)b);
|
||||
}
|
||||
static inline int bfdec_cmp_full(const bfdec_t *a, const bfdec_t *b)
|
||||
{
|
||||
return bf_cmp_full((const bf_t *)a, (const bf_t *)b);
|
||||
}
|
||||
static inline int bfdec_cmp(const bfdec_t *a, const bfdec_t *b)
|
||||
{
|
||||
return bf_cmp((const bf_t *)a, (const bf_t *)b);
|
||||
}
|
||||
static inline int bfdec_cmp_eq(const bfdec_t *a, const bfdec_t *b)
|
||||
{
|
||||
return bfdec_cmp(a, b) == 0;
|
||||
}
|
||||
static inline int bfdec_cmp_le(const bfdec_t *a, const bfdec_t *b)
|
||||
{
|
||||
return bfdec_cmp(a, b) <= 0;
|
||||
}
|
||||
static inline int bfdec_cmp_lt(const bfdec_t *a, const bfdec_t *b)
|
||||
{
|
||||
return bfdec_cmp(a, b) < 0;
|
||||
}
|
||||
|
||||
int bfdec_add(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
|
||||
bf_flags_t flags);
|
||||
int bfdec_sub(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
|
||||
bf_flags_t flags);
|
||||
int bfdec_add_si(bfdec_t *r, const bfdec_t *a, int64_t b1, limb_t prec,
|
||||
bf_flags_t flags);
|
||||
int bfdec_mul(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
|
||||
bf_flags_t flags);
|
||||
int bfdec_mul_si(bfdec_t *r, const bfdec_t *a, int64_t b1, limb_t prec,
|
||||
bf_flags_t flags);
|
||||
int bfdec_div(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
|
||||
bf_flags_t flags);
|
||||
int bfdec_divrem(bfdec_t *q, bfdec_t *r, const bfdec_t *a, const bfdec_t *b,
|
||||
limb_t prec, bf_flags_t flags, int rnd_mode);
|
||||
int bfdec_rem(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
|
||||
bf_flags_t flags, int rnd_mode);
|
||||
int bfdec_rint(bfdec_t *r, int rnd_mode);
|
||||
int bfdec_sqrt(bfdec_t *r, const bfdec_t *a, limb_t prec, bf_flags_t flags);
|
||||
int bfdec_round(bfdec_t *r, limb_t prec, bf_flags_t flags);
|
||||
int bfdec_get_int32(int *pres, const bfdec_t *a);
|
||||
int bfdec_pow_ui(bfdec_t *r, const bfdec_t *a, limb_t b);
|
||||
|
||||
char *bfdec_ftoa(size_t *plen, const bfdec_t *a, limb_t prec, bf_flags_t flags);
|
||||
int bfdec_atof(bfdec_t *r, const char *str, const char **pnext,
|
||||
limb_t prec, bf_flags_t flags);
|
||||
|
||||
/* the following functions are exported for testing only. */
|
||||
extern const limb_t mp_pow_dec[LIMB_DIGITS + 1];
|
||||
void bfdec_print_str(const char *str, const bfdec_t *a);
|
||||
static inline int bfdec_resize(bfdec_t *r, limb_t len)
|
||||
{
|
||||
return bf_resize((bf_t *)r, len);
|
||||
}
|
||||
int bfdec_normalize_and_round(bfdec_t *r, limb_t prec1, bf_flags_t flags);
|
||||
|
||||
#endif /* LIBBF_H */
|
57
quickjs/libregexp-opcode.h
Normal file
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Regular Expression Engine
|
||||
*
|
||||
* Copyright (c) 2017-2018 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifdef DEF
|
||||
|
||||
DEF(invalid, 1) /* never used */
|
||||
DEF(char, 3)
|
||||
DEF(char32, 5)
|
||||
DEF(dot, 1)
|
||||
DEF(any, 1) /* same as dot but match any character including line terminator */
|
||||
DEF(line_start, 1)
|
||||
DEF(line_end, 1)
|
||||
DEF(goto, 5)
|
||||
DEF(split_goto_first, 5)
|
||||
DEF(split_next_first, 5)
|
||||
DEF(match, 1)
|
||||
DEF(save_start, 2) /* save start position */
|
||||
DEF(save_end, 2) /* save end position, must come after saved_start */
|
||||
DEF(save_reset, 3) /* reset save positions */
|
||||
DEF(loop, 5) /* decrement the top the stack and goto if != 0 */
|
||||
DEF(push_i32, 5) /* push integer on the stack */
|
||||
DEF(drop, 1)
|
||||
DEF(word_boundary, 1)
|
||||
DEF(not_word_boundary, 1)
|
||||
DEF(back_reference, 2)
|
||||
DEF(backward_back_reference, 2) /* must come after back_reference */
|
||||
DEF(range, 3) /* variable length */
|
||||
DEF(range32, 3) /* variable length */
|
||||
DEF(lookahead, 5)
|
||||
DEF(negative_lookahead, 5)
|
||||
DEF(push_char_pos, 1) /* push the character position on the stack */
|
||||
DEF(check_advance, 1) /* pop one stack element and check that it is different from the character position */
|
||||
DEF(prev, 1) /* go to the previous char */
|
||||
DEF(simple_greedy_quant, 17)
|
||||
|
||||
#endif /* DEF */
|
2529
quickjs/libregexp.c
Normal file
93
quickjs/libregexp.h
Normal file
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* Regular Expression Engine
|
||||
*
|
||||
* Copyright (c) 2017-2018 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef LIBREGEXP_H
|
||||
#define LIBREGEXP_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "libunicode.h"
|
||||
|
||||
#define LRE_BOOL int /* for documentation purposes */
|
||||
|
||||
#define LRE_FLAG_GLOBAL (1 << 0)
|
||||
#define LRE_FLAG_IGNORECASE (1 << 1)
|
||||
#define LRE_FLAG_MULTILINE (1 << 2)
|
||||
#define LRE_FLAG_DOTALL (1 << 3)
|
||||
#define LRE_FLAG_UTF16 (1 << 4)
|
||||
#define LRE_FLAG_STICKY (1 << 5)
|
||||
#define LRE_FLAG_INDICES (1 << 6) /* Unused by libregexp, just recorded. */
|
||||
|
||||
#define LRE_FLAG_NAMED_GROUPS (1 << 7) /* named groups are present in the regexp */
|
||||
|
||||
uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size,
|
||||
const char *buf, size_t buf_len, int re_flags,
|
||||
void *opaque);
|
||||
int lre_get_capture_count(const uint8_t *bc_buf);
|
||||
int lre_get_flags(const uint8_t *bc_buf);
|
||||
const char *lre_get_groupnames(const uint8_t *bc_buf);
|
||||
int lre_exec(uint8_t **capture,
|
||||
const uint8_t *bc_buf, const uint8_t *cbuf, int cindex, int clen,
|
||||
int cbuf_type, void *opaque);
|
||||
|
||||
int lre_parse_escape(const uint8_t **pp, int allow_utf16);
|
||||
LRE_BOOL lre_is_space(int c);
|
||||
|
||||
/* must be provided by the user */
|
||||
LRE_BOOL lre_check_stack_overflow(void *opaque, size_t alloca_size);
|
||||
void *lre_realloc(void *opaque, void *ptr, size_t size);
|
||||
|
||||
/* JS identifier test */
|
||||
extern uint32_t const lre_id_start_table_ascii[4];
|
||||
extern uint32_t const lre_id_continue_table_ascii[4];
|
||||
|
||||
static inline int lre_js_is_ident_first(int c)
|
||||
{
|
||||
if ((uint32_t)c < 128) {
|
||||
return (lre_id_start_table_ascii[c >> 5] >> (c & 31)) & 1;
|
||||
} else {
|
||||
#ifdef CONFIG_ALL_UNICODE
|
||||
return lre_is_id_start(c);
|
||||
#else
|
||||
return !lre_is_space(c);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static inline int lre_js_is_ident_next(int c)
|
||||
{
|
||||
if ((uint32_t)c < 128) {
|
||||
return (lre_id_continue_table_ascii[c >> 5] >> (c & 31)) & 1;
|
||||
} else {
|
||||
/* ZWNJ and ZWJ are accepted in identifiers */
|
||||
#ifdef CONFIG_ALL_UNICODE
|
||||
return lre_is_id_continue(c) || c == 0x200C || c == 0x200D;
|
||||
#else
|
||||
return !lre_is_space(c) || c == 0x200C || c == 0x200D;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#undef LRE_BOOL
|
||||
|
||||
#endif /* LIBREGEXP_H */
|
4486
quickjs/libunicode-table.h
Normal file
1788
quickjs/libunicode.c
Normal file
127
quickjs/libunicode.h
Normal file
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* Unicode utilities
|
||||
*
|
||||
* Copyright (c) 2017-2018 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef LIBUNICODE_H
|
||||
#define LIBUNICODE_H
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#define LRE_BOOL int /* for documentation purposes */
|
||||
|
||||
/* define it to include all the unicode tables (40KB larger) */
|
||||
#define CONFIG_ALL_UNICODE
|
||||
|
||||
#define LRE_CC_RES_LEN_MAX 3
|
||||
|
||||
typedef enum {
|
||||
UNICODE_NFC,
|
||||
UNICODE_NFD,
|
||||
UNICODE_NFKC,
|
||||
UNICODE_NFKD,
|
||||
} UnicodeNormalizationEnum;
|
||||
|
||||
int lre_case_conv(uint32_t *res, uint32_t c, int conv_type);
|
||||
int lre_canonicalize(uint32_t c, BOOL is_unicode);
|
||||
LRE_BOOL lre_is_cased(uint32_t c);
|
||||
LRE_BOOL lre_is_case_ignorable(uint32_t c);
|
||||
|
||||
/* char ranges */
|
||||
|
||||
typedef struct {
|
||||
int len; /* in points, always even */
|
||||
int size;
|
||||
uint32_t *points; /* points sorted by increasing value */
|
||||
void *mem_opaque;
|
||||
void *(*realloc_func)(void *opaque, void *ptr, size_t size);
|
||||
} CharRange;
|
||||
|
||||
typedef enum {
|
||||
CR_OP_UNION,
|
||||
CR_OP_INTER,
|
||||
CR_OP_XOR,
|
||||
} CharRangeOpEnum;
|
||||
|
||||
void cr_init(CharRange *cr, void *mem_opaque, void *(*realloc_func)(void *opaque, void *ptr, size_t size));
|
||||
void cr_free(CharRange *cr);
|
||||
int cr_realloc(CharRange *cr, int size);
|
||||
int cr_copy(CharRange *cr, const CharRange *cr1);
|
||||
|
||||
static inline int cr_add_point(CharRange *cr, uint32_t v)
|
||||
{
|
||||
if (cr->len >= cr->size) {
|
||||
if (cr_realloc(cr, cr->len + 1))
|
||||
return -1;
|
||||
}
|
||||
cr->points[cr->len++] = v;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int cr_add_interval(CharRange *cr, uint32_t c1, uint32_t c2)
|
||||
{
|
||||
if ((cr->len + 2) > cr->size) {
|
||||
if (cr_realloc(cr, cr->len + 2))
|
||||
return -1;
|
||||
}
|
||||
cr->points[cr->len++] = c1;
|
||||
cr->points[cr->len++] = c2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cr_union1(CharRange *cr, const uint32_t *b_pt, int b_len);
|
||||
|
||||
static inline int cr_union_interval(CharRange *cr, uint32_t c1, uint32_t c2)
|
||||
{
|
||||
uint32_t b_pt[2];
|
||||
b_pt[0] = c1;
|
||||
b_pt[1] = c2 + 1;
|
||||
return cr_union1(cr, b_pt, 2);
|
||||
}
|
||||
|
||||
int cr_op(CharRange *cr, const uint32_t *a_pt, int a_len,
|
||||
const uint32_t *b_pt, int b_len, int op);
|
||||
|
||||
int cr_invert(CharRange *cr);
|
||||
|
||||
int cr_regexp_canonicalize(CharRange *cr, BOOL is_unicode);
|
||||
|
||||
#ifdef CONFIG_ALL_UNICODE
|
||||
|
||||
LRE_BOOL lre_is_id_start(uint32_t c);
|
||||
LRE_BOOL lre_is_id_continue(uint32_t c);
|
||||
|
||||
int unicode_normalize(uint32_t **pdst, const uint32_t *src, int src_len,
|
||||
UnicodeNormalizationEnum n_type,
|
||||
void *opaque, void *(*realloc_func)(void *opaque, void *ptr, size_t size));
|
||||
|
||||
/* Unicode character range functions */
|
||||
|
||||
int unicode_script(CharRange *cr,
|
||||
const char *script_name, LRE_BOOL is_ext);
|
||||
int unicode_general_category(CharRange *cr, const char *gc_name);
|
||||
int unicode_prop(CharRange *cr, const char *prop_name);
|
||||
|
||||
#endif /* CONFIG_ALL_UNICODE */
|
||||
|
||||
#undef LRE_BOOL
|
||||
|
||||
#endif /* LIBUNICODE_H */
|
99
quickjs/list.h
Normal file
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Linux klist like system
|
||||
*
|
||||
* Copyright (c) 2016-2017 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef LIST_H
|
||||
#define LIST_H
|
||||
|
||||
#ifndef NULL
|
||||
#include <stddef.h>
|
||||
#endif
|
||||
|
||||
struct list_head {
|
||||
struct list_head *prev;
|
||||
struct list_head *next;
|
||||
};
|
||||
|
||||
#define LIST_HEAD_INIT(el) { &(el), &(el) }
|
||||
|
||||
/* return the pointer of type 'type *' containing 'el' as field 'member' */
|
||||
#define list_entry(el, type, member) container_of(el, type, member)
|
||||
|
||||
static inline void init_list_head(struct list_head *head)
|
||||
{
|
||||
head->prev = head;
|
||||
head->next = head;
|
||||
}
|
||||
|
||||
/* insert 'el' between 'prev' and 'next' */
|
||||
static inline void __list_add(struct list_head *el,
|
||||
struct list_head *prev, struct list_head *next)
|
||||
{
|
||||
prev->next = el;
|
||||
el->prev = prev;
|
||||
el->next = next;
|
||||
next->prev = el;
|
||||
}
|
||||
|
||||
/* add 'el' at the head of the list 'head' (= after element head) */
|
||||
static inline void list_add(struct list_head *el, struct list_head *head)
|
||||
{
|
||||
__list_add(el, head, head->next);
|
||||
}
|
||||
|
||||
/* add 'el' at the end of the list 'head' (= before element head) */
|
||||
static inline void list_add_tail(struct list_head *el, struct list_head *head)
|
||||
{
|
||||
__list_add(el, head->prev, head);
|
||||
}
|
||||
|
||||
static inline void list_del(struct list_head *el)
|
||||
{
|
||||
struct list_head *prev, *next;
|
||||
prev = el->prev;
|
||||
next = el->next;
|
||||
prev->next = next;
|
||||
next->prev = prev;
|
||||
el->prev = NULL; /* fail safe */
|
||||
el->next = NULL; /* fail safe */
|
||||
}
|
||||
|
||||
static inline int list_empty(struct list_head *el)
|
||||
{
|
||||
return el->next == el;
|
||||
}
|
||||
|
||||
#define list_for_each(el, head) \
|
||||
for(el = (head)->next; el != (head); el = el->next)
|
||||
|
||||
#define list_for_each_safe(el, el1, head) \
|
||||
for(el = (head)->next, el1 = el->next; el != (head); \
|
||||
el = el1, el1 = el->next)
|
||||
|
||||
#define list_for_each_prev(el, head) \
|
||||
for(el = (head)->prev; el != (head); el = el->prev)
|
||||
|
||||
#define list_for_each_prev_safe(el, el1, head) \
|
||||
for(el = (head)->prev, el1 = el->prev; el != (head); \
|
||||
el = el1, el1 = el->prev)
|
||||
|
||||
#endif /* LIST_H */
|
273
quickjs/quickjs-atom.h
Normal file
|
@ -0,0 +1,273 @@
|
|||
/*
|
||||
* QuickJS atom definitions
|
||||
*
|
||||
* Copyright (c) 2017-2018 Fabrice Bellard
|
||||
* Copyright (c) 2017-2018 Charlie Gordon
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifdef DEF
|
||||
|
||||
/* Note: first atoms are considered as keywords in the parser */
|
||||
DEF(null, "null") /* must be first */
|
||||
DEF(false, "false")
|
||||
DEF(true, "true")
|
||||
DEF(if, "if")
|
||||
DEF(else, "else")
|
||||
DEF(return, "return")
|
||||
DEF(var, "var")
|
||||
DEF(this, "this")
|
||||
DEF(delete, "delete")
|
||||
DEF(void, "void")
|
||||
DEF(typeof, "typeof")
|
||||
DEF(new, "new")
|
||||
DEF(in, "in")
|
||||
DEF(instanceof, "instanceof")
|
||||
DEF(do, "do")
|
||||
DEF(while, "while")
|
||||
DEF(for, "for")
|
||||
DEF(break, "break")
|
||||
DEF(continue, "continue")
|
||||
DEF(switch, "switch")
|
||||
DEF(case, "case")
|
||||
DEF(default, "default")
|
||||
DEF(throw, "throw")
|
||||
DEF(try, "try")
|
||||
DEF(catch, "catch")
|
||||
DEF(finally, "finally")
|
||||
DEF(function, "function")
|
||||
DEF(debugger, "debugger")
|
||||
DEF(with, "with")
|
||||
/* FutureReservedWord */
|
||||
DEF(class, "class")
|
||||
DEF(const, "const")
|
||||
DEF(enum, "enum")
|
||||
DEF(export, "export")
|
||||
DEF(extends, "extends")
|
||||
DEF(import, "import")
|
||||
DEF(super, "super")
|
||||
/* FutureReservedWords when parsing strict mode code */
|
||||
DEF(implements, "implements")
|
||||
DEF(interface, "interface")
|
||||
DEF(let, "let")
|
||||
DEF(package, "package")
|
||||
DEF(private, "private")
|
||||
DEF(protected, "protected")
|
||||
DEF(public, "public")
|
||||
DEF(static, "static")
|
||||
DEF(yield, "yield")
|
||||
DEF(await, "await")
|
||||
|
||||
/* empty string */
|
||||
DEF(empty_string, "")
|
||||
/* identifiers */
|
||||
DEF(length, "length")
|
||||
DEF(fileName, "fileName")
|
||||
DEF(lineNumber, "lineNumber")
|
||||
DEF(message, "message")
|
||||
DEF(cause, "cause")
|
||||
DEF(errors, "errors")
|
||||
DEF(stack, "stack")
|
||||
DEF(name, "name")
|
||||
DEF(toString, "toString")
|
||||
DEF(toLocaleString, "toLocaleString")
|
||||
DEF(valueOf, "valueOf")
|
||||
DEF(eval, "eval")
|
||||
DEF(prototype, "prototype")
|
||||
DEF(constructor, "constructor")
|
||||
DEF(configurable, "configurable")
|
||||
DEF(writable, "writable")
|
||||
DEF(enumerable, "enumerable")
|
||||
DEF(value, "value")
|
||||
DEF(get, "get")
|
||||
DEF(set, "set")
|
||||
DEF(of, "of")
|
||||
DEF(__proto__, "__proto__")
|
||||
DEF(undefined, "undefined")
|
||||
DEF(number, "number")
|
||||
DEF(boolean, "boolean")
|
||||
DEF(string, "string")
|
||||
DEF(object, "object")
|
||||
DEF(symbol, "symbol")
|
||||
DEF(integer, "integer")
|
||||
DEF(unknown, "unknown")
|
||||
DEF(arguments, "arguments")
|
||||
DEF(callee, "callee")
|
||||
DEF(caller, "caller")
|
||||
DEF(_eval_, "<eval>")
|
||||
DEF(_ret_, "<ret>")
|
||||
DEF(_var_, "<var>")
|
||||
DEF(_arg_var_, "<arg_var>")
|
||||
DEF(_with_, "<with>")
|
||||
DEF(lastIndex, "lastIndex")
|
||||
DEF(target, "target")
|
||||
DEF(index, "index")
|
||||
DEF(input, "input")
|
||||
DEF(defineProperties, "defineProperties")
|
||||
DEF(apply, "apply")
|
||||
DEF(join, "join")
|
||||
DEF(concat, "concat")
|
||||
DEF(split, "split")
|
||||
DEF(construct, "construct")
|
||||
DEF(getPrototypeOf, "getPrototypeOf")
|
||||
DEF(setPrototypeOf, "setPrototypeOf")
|
||||
DEF(isExtensible, "isExtensible")
|
||||
DEF(preventExtensions, "preventExtensions")
|
||||
DEF(has, "has")
|
||||
DEF(deleteProperty, "deleteProperty")
|
||||
DEF(defineProperty, "defineProperty")
|
||||
DEF(getOwnPropertyDescriptor, "getOwnPropertyDescriptor")
|
||||
DEF(ownKeys, "ownKeys")
|
||||
DEF(add, "add")
|
||||
DEF(done, "done")
|
||||
DEF(next, "next")
|
||||
DEF(values, "values")
|
||||
DEF(source, "source")
|
||||
DEF(flags, "flags")
|
||||
DEF(global, "global")
|
||||
DEF(unicode, "unicode")
|
||||
DEF(raw, "raw")
|
||||
DEF(new_target, "new.target")
|
||||
DEF(this_active_func, "this.active_func")
|
||||
DEF(home_object, "<home_object>")
|
||||
DEF(computed_field, "<computed_field>")
|
||||
DEF(static_computed_field, "<static_computed_field>") /* must come after computed_fields */
|
||||
DEF(class_fields_init, "<class_fields_init>")
|
||||
DEF(brand, "<brand>")
|
||||
DEF(hash_constructor, "#constructor")
|
||||
DEF(as, "as")
|
||||
DEF(from, "from")
|
||||
DEF(meta, "meta")
|
||||
DEF(_default_, "*default*")
|
||||
DEF(_star_, "*")
|
||||
DEF(Module, "Module")
|
||||
DEF(then, "then")
|
||||
DEF(resolve, "resolve")
|
||||
DEF(reject, "reject")
|
||||
DEF(promise, "promise")
|
||||
DEF(proxy, "proxy")
|
||||
DEF(revoke, "revoke")
|
||||
DEF(async, "async")
|
||||
DEF(exec, "exec")
|
||||
DEF(groups, "groups")
|
||||
DEF(indices, "indices")
|
||||
DEF(status, "status")
|
||||
DEF(reason, "reason")
|
||||
DEF(globalThis, "globalThis")
|
||||
DEF(bigint, "bigint")
|
||||
#ifdef CONFIG_BIGNUM
|
||||
DEF(bigfloat, "bigfloat")
|
||||
DEF(bigdecimal, "bigdecimal")
|
||||
DEF(roundingMode, "roundingMode")
|
||||
DEF(maximumSignificantDigits, "maximumSignificantDigits")
|
||||
DEF(maximumFractionDigits, "maximumFractionDigits")
|
||||
#endif
|
||||
/* the following 3 atoms are only used with CONFIG_ATOMICS */
|
||||
DEF(not_equal, "not-equal")
|
||||
DEF(timed_out, "timed-out")
|
||||
DEF(ok, "ok")
|
||||
/* */
|
||||
DEF(toJSON, "toJSON")
|
||||
/* class names */
|
||||
DEF(Object, "Object")
|
||||
DEF(Array, "Array")
|
||||
DEF(Error, "Error")
|
||||
DEF(Number, "Number")
|
||||
DEF(String, "String")
|
||||
DEF(Boolean, "Boolean")
|
||||
DEF(Symbol, "Symbol")
|
||||
DEF(Arguments, "Arguments")
|
||||
DEF(Math, "Math")
|
||||
DEF(JSON, "JSON")
|
||||
DEF(Date, "Date")
|
||||
DEF(Function, "Function")
|
||||
DEF(GeneratorFunction, "GeneratorFunction")
|
||||
DEF(ForInIterator, "ForInIterator")
|
||||
DEF(RegExp, "RegExp")
|
||||
DEF(ArrayBuffer, "ArrayBuffer")
|
||||
DEF(SharedArrayBuffer, "SharedArrayBuffer")
|
||||
/* must keep same order as class IDs for typed arrays */
|
||||
DEF(Uint8ClampedArray, "Uint8ClampedArray")
|
||||
DEF(Int8Array, "Int8Array")
|
||||
DEF(Uint8Array, "Uint8Array")
|
||||
DEF(Int16Array, "Int16Array")
|
||||
DEF(Uint16Array, "Uint16Array")
|
||||
DEF(Int32Array, "Int32Array")
|
||||
DEF(Uint32Array, "Uint32Array")
|
||||
DEF(BigInt64Array, "BigInt64Array")
|
||||
DEF(BigUint64Array, "BigUint64Array")
|
||||
DEF(Float32Array, "Float32Array")
|
||||
DEF(Float64Array, "Float64Array")
|
||||
DEF(DataView, "DataView")
|
||||
DEF(BigInt, "BigInt")
|
||||
#ifdef CONFIG_BIGNUM
|
||||
DEF(BigFloat, "BigFloat")
|
||||
DEF(BigFloatEnv, "BigFloatEnv")
|
||||
DEF(BigDecimal, "BigDecimal")
|
||||
DEF(OperatorSet, "OperatorSet")
|
||||
DEF(Operators, "Operators")
|
||||
#endif
|
||||
DEF(Map, "Map")
|
||||
DEF(Set, "Set") /* Map + 1 */
|
||||
DEF(WeakMap, "WeakMap") /* Map + 2 */
|
||||
DEF(WeakSet, "WeakSet") /* Map + 3 */
|
||||
DEF(Map_Iterator, "Map Iterator")
|
||||
DEF(Set_Iterator, "Set Iterator")
|
||||
DEF(Array_Iterator, "Array Iterator")
|
||||
DEF(String_Iterator, "String Iterator")
|
||||
DEF(RegExp_String_Iterator, "RegExp String Iterator")
|
||||
DEF(Generator, "Generator")
|
||||
DEF(Proxy, "Proxy")
|
||||
DEF(Promise, "Promise")
|
||||
DEF(PromiseResolveFunction, "PromiseResolveFunction")
|
||||
DEF(PromiseRejectFunction, "PromiseRejectFunction")
|
||||
DEF(AsyncFunction, "AsyncFunction")
|
||||
DEF(AsyncFunctionResolve, "AsyncFunctionResolve")
|
||||
DEF(AsyncFunctionReject, "AsyncFunctionReject")
|
||||
DEF(AsyncGeneratorFunction, "AsyncGeneratorFunction")
|
||||
DEF(AsyncGenerator, "AsyncGenerator")
|
||||
DEF(EvalError, "EvalError")
|
||||
DEF(RangeError, "RangeError")
|
||||
DEF(ReferenceError, "ReferenceError")
|
||||
DEF(SyntaxError, "SyntaxError")
|
||||
DEF(TypeError, "TypeError")
|
||||
DEF(URIError, "URIError")
|
||||
DEF(InternalError, "InternalError")
|
||||
/* private symbols */
|
||||
DEF(Private_brand, "<brand>")
|
||||
/* symbols */
|
||||
DEF(Symbol_toPrimitive, "Symbol.toPrimitive")
|
||||
DEF(Symbol_iterator, "Symbol.iterator")
|
||||
DEF(Symbol_match, "Symbol.match")
|
||||
DEF(Symbol_matchAll, "Symbol.matchAll")
|
||||
DEF(Symbol_replace, "Symbol.replace")
|
||||
DEF(Symbol_search, "Symbol.search")
|
||||
DEF(Symbol_split, "Symbol.split")
|
||||
DEF(Symbol_toStringTag, "Symbol.toStringTag")
|
||||
DEF(Symbol_isConcatSpreadable, "Symbol.isConcatSpreadable")
|
||||
DEF(Symbol_hasInstance, "Symbol.hasInstance")
|
||||
DEF(Symbol_species, "Symbol.species")
|
||||
DEF(Symbol_unscopables, "Symbol.unscopables")
|
||||
DEF(Symbol_asyncIterator, "Symbol.asyncIterator")
|
||||
#ifdef CONFIG_BIGNUM
|
||||
DEF(Symbol_operatorSet, "Symbol.operatorSet")
|
||||
#endif
|
||||
|
||||
#endif /* DEF */
|
3999
quickjs/quickjs-libc.c
Normal file
59
quickjs/quickjs-libc.h
Normal file
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* QuickJS C library
|
||||
*
|
||||
* Copyright (c) 2017-2018 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef QUICKJS_LIBC_H
|
||||
#define QUICKJS_LIBC_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "quickjs.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
JSModuleDef *js_init_module_std(JSContext *ctx, const char *module_name);
|
||||
JSModuleDef *js_init_module_os(JSContext *ctx, const char *module_name);
|
||||
void js_std_add_helpers(JSContext *ctx, int argc, char **argv);
|
||||
void js_std_loop(JSContext *ctx);
|
||||
void js_std_init_handlers(JSRuntime *rt);
|
||||
void js_std_free_handlers(JSRuntime *rt);
|
||||
void js_std_dump_error(JSContext *ctx);
|
||||
uint8_t *js_load_file(JSContext *ctx, size_t *pbuf_len, const char *filename);
|
||||
int js_module_set_import_meta(JSContext *ctx, JSValueConst func_val,
|
||||
JS_BOOL use_realpath, JS_BOOL is_main);
|
||||
JSModuleDef *js_module_loader(JSContext *ctx,
|
||||
const char *module_name, void *opaque);
|
||||
void js_std_eval_binary(JSContext *ctx, const uint8_t *buf, size_t buf_len,
|
||||
int flags);
|
||||
void js_std_promise_rejection_tracker(JSContext *ctx, JSValueConst promise,
|
||||
JSValueConst reason,
|
||||
JS_BOOL is_handled, void *opaque);
|
||||
void js_std_set_worker_new_context_func(JSContext *(*func)(JSRuntime *rt));
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" { */
|
||||
#endif
|
||||
|
||||
#endif /* QUICKJS_LIBC_H */
|
372
quickjs/quickjs-opcode.h
Normal file
|
@ -0,0 +1,372 @@
|
|||
/*
|
||||
* QuickJS opcode definitions
|
||||
*
|
||||
* Copyright (c) 2017-2018 Fabrice Bellard
|
||||
* Copyright (c) 2017-2018 Charlie Gordon
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifdef FMT
|
||||
FMT(none)
|
||||
FMT(none_int)
|
||||
FMT(none_loc)
|
||||
FMT(none_arg)
|
||||
FMT(none_var_ref)
|
||||
FMT(u8)
|
||||
FMT(i8)
|
||||
FMT(loc8)
|
||||
FMT(const8)
|
||||
FMT(label8)
|
||||
FMT(u16)
|
||||
FMT(i16)
|
||||
FMT(label16)
|
||||
FMT(npop)
|
||||
FMT(npopx)
|
||||
FMT(npop_u16)
|
||||
FMT(loc)
|
||||
FMT(arg)
|
||||
FMT(var_ref)
|
||||
FMT(u32)
|
||||
FMT(i32)
|
||||
FMT(const)
|
||||
FMT(label)
|
||||
FMT(atom)
|
||||
FMT(atom_u8)
|
||||
FMT(atom_u16)
|
||||
FMT(atom_label_u8)
|
||||
FMT(atom_label_u16)
|
||||
FMT(label_u16)
|
||||
#undef FMT
|
||||
#endif /* FMT */
|
||||
|
||||
#ifdef DEF
|
||||
|
||||
#ifndef def
|
||||
#define def(id, size, n_pop, n_push, f) DEF(id, size, n_pop, n_push, f)
|
||||
#endif
|
||||
|
||||
DEF(invalid, 1, 0, 0, none) /* never emitted */
|
||||
|
||||
/* push values */
|
||||
DEF( push_i32, 5, 0, 1, i32)
|
||||
DEF( push_const, 5, 0, 1, const)
|
||||
DEF( fclosure, 5, 0, 1, const) /* must follow push_const */
|
||||
DEF(push_atom_value, 5, 0, 1, atom)
|
||||
DEF( private_symbol, 5, 0, 1, atom)
|
||||
DEF( undefined, 1, 0, 1, none)
|
||||
DEF( null, 1, 0, 1, none)
|
||||
DEF( push_this, 1, 0, 1, none) /* only used at the start of a function */
|
||||
DEF( push_false, 1, 0, 1, none)
|
||||
DEF( push_true, 1, 0, 1, none)
|
||||
DEF( object, 1, 0, 1, none)
|
||||
DEF( special_object, 2, 0, 1, u8) /* only used at the start of a function */
|
||||
DEF( rest, 3, 0, 1, u16) /* only used at the start of a function */
|
||||
|
||||
DEF( drop, 1, 1, 0, none) /* a -> */
|
||||
DEF( nip, 1, 2, 1, none) /* a b -> b */
|
||||
DEF( nip1, 1, 3, 2, none) /* a b c -> b c */
|
||||
DEF( dup, 1, 1, 2, none) /* a -> a a */
|
||||
DEF( dup1, 1, 2, 3, none) /* a b -> a a b */
|
||||
DEF( dup2, 1, 2, 4, none) /* a b -> a b a b */
|
||||
DEF( dup3, 1, 3, 6, none) /* a b c -> a b c a b c */
|
||||
DEF( insert2, 1, 2, 3, none) /* obj a -> a obj a (dup_x1) */
|
||||
DEF( insert3, 1, 3, 4, none) /* obj prop a -> a obj prop a (dup_x2) */
|
||||
DEF( insert4, 1, 4, 5, none) /* this obj prop a -> a this obj prop a */
|
||||
DEF( perm3, 1, 3, 3, none) /* obj a b -> a obj b */
|
||||
DEF( perm4, 1, 4, 4, none) /* obj prop a b -> a obj prop b */
|
||||
DEF( perm5, 1, 5, 5, none) /* this obj prop a b -> a this obj prop b */
|
||||
DEF( swap, 1, 2, 2, none) /* a b -> b a */
|
||||
DEF( swap2, 1, 4, 4, none) /* a b c d -> c d a b */
|
||||
DEF( rot3l, 1, 3, 3, none) /* x a b -> a b x */
|
||||
DEF( rot3r, 1, 3, 3, none) /* a b x -> x a b */
|
||||
DEF( rot4l, 1, 4, 4, none) /* x a b c -> a b c x */
|
||||
DEF( rot5l, 1, 5, 5, none) /* x a b c d -> a b c d x */
|
||||
|
||||
DEF(call_constructor, 3, 2, 1, npop) /* func new.target args -> ret. arguments are not counted in n_pop */
|
||||
DEF( call, 3, 1, 1, npop) /* arguments are not counted in n_pop */
|
||||
DEF( tail_call, 3, 1, 0, npop) /* arguments are not counted in n_pop */
|
||||
DEF( call_method, 3, 2, 1, npop) /* arguments are not counted in n_pop */
|
||||
DEF(tail_call_method, 3, 2, 0, npop) /* arguments are not counted in n_pop */
|
||||
DEF( array_from, 3, 0, 1, npop) /* arguments are not counted in n_pop */
|
||||
DEF( apply, 3, 3, 1, u16)
|
||||
DEF( return, 1, 1, 0, none)
|
||||
DEF( return_undef, 1, 0, 0, none)
|
||||
DEF(check_ctor_return, 1, 1, 2, none)
|
||||
DEF( check_ctor, 1, 0, 0, none)
|
||||
DEF( check_brand, 1, 2, 2, none) /* this_obj func -> this_obj func */
|
||||
DEF( add_brand, 1, 2, 0, none) /* this_obj home_obj -> */
|
||||
DEF( return_async, 1, 1, 0, none)
|
||||
DEF( throw, 1, 1, 0, none)
|
||||
DEF( throw_error, 6, 0, 0, atom_u8)
|
||||
DEF( eval, 5, 1, 1, npop_u16) /* func args... -> ret_val */
|
||||
DEF( apply_eval, 3, 2, 1, u16) /* func array -> ret_eval */
|
||||
DEF( regexp, 1, 2, 1, none) /* create a RegExp object from the pattern and a
|
||||
bytecode string */
|
||||
DEF( get_super, 1, 1, 1, none)
|
||||
DEF( import, 1, 1, 1, none) /* dynamic module import */
|
||||
|
||||
DEF( check_var, 5, 0, 1, atom) /* check if a variable exists */
|
||||
DEF( get_var_undef, 5, 0, 1, atom) /* push undefined if the variable does not exist */
|
||||
DEF( get_var, 5, 0, 1, atom) /* throw an exception if the variable does not exist */
|
||||
DEF( put_var, 5, 1, 0, atom) /* must come after get_var */
|
||||
DEF( put_var_init, 5, 1, 0, atom) /* must come after put_var. Used to initialize a global lexical variable */
|
||||
DEF( put_var_strict, 5, 2, 0, atom) /* for strict mode variable write */
|
||||
|
||||
DEF( get_ref_value, 1, 2, 3, none)
|
||||
DEF( put_ref_value, 1, 3, 0, none)
|
||||
|
||||
DEF( define_var, 6, 0, 0, atom_u8)
|
||||
DEF(check_define_var, 6, 0, 0, atom_u8)
|
||||
DEF( define_func, 6, 1, 0, atom_u8)
|
||||
DEF( get_field, 5, 1, 1, atom)
|
||||
DEF( get_field2, 5, 1, 2, atom)
|
||||
DEF( put_field, 5, 2, 0, atom)
|
||||
DEF( get_private_field, 1, 2, 1, none) /* obj prop -> value */
|
||||
DEF( put_private_field, 1, 3, 0, none) /* obj value prop -> */
|
||||
DEF(define_private_field, 1, 3, 1, none) /* obj prop value -> obj */
|
||||
DEF( get_array_el, 1, 2, 1, none)
|
||||
DEF( get_array_el2, 1, 2, 2, none) /* obj prop -> obj value */
|
||||
DEF( put_array_el, 1, 3, 0, none)
|
||||
DEF(get_super_value, 1, 3, 1, none) /* this obj prop -> value */
|
||||
DEF(put_super_value, 1, 4, 0, none) /* this obj prop value -> */
|
||||
DEF( define_field, 5, 2, 1, atom)
|
||||
DEF( set_name, 5, 1, 1, atom)
|
||||
DEF(set_name_computed, 1, 2, 2, none)
|
||||
DEF( set_proto, 1, 2, 1, none)
|
||||
DEF(set_home_object, 1, 2, 2, none)
|
||||
DEF(define_array_el, 1, 3, 2, none)
|
||||
DEF( append, 1, 3, 2, none) /* append enumerated object, update length */
|
||||
DEF(copy_data_properties, 2, 3, 3, u8)
|
||||
DEF( define_method, 6, 2, 1, atom_u8)
|
||||
DEF(define_method_computed, 2, 3, 1, u8) /* must come after define_method */
|
||||
DEF( define_class, 6, 2, 2, atom_u8) /* parent ctor -> ctor proto */
|
||||
DEF( define_class_computed, 6, 3, 3, atom_u8) /* field_name parent ctor -> field_name ctor proto (class with computed name) */
|
||||
|
||||
DEF( get_loc, 3, 0, 1, loc)
|
||||
DEF( put_loc, 3, 1, 0, loc) /* must come after get_loc */
|
||||
DEF( set_loc, 3, 1, 1, loc) /* must come after put_loc */
|
||||
DEF( get_arg, 3, 0, 1, arg)
|
||||
DEF( put_arg, 3, 1, 0, arg) /* must come after get_arg */
|
||||
DEF( set_arg, 3, 1, 1, arg) /* must come after put_arg */
|
||||
DEF( get_var_ref, 3, 0, 1, var_ref)
|
||||
DEF( put_var_ref, 3, 1, 0, var_ref) /* must come after get_var_ref */
|
||||
DEF( set_var_ref, 3, 1, 1, var_ref) /* must come after put_var_ref */
|
||||
DEF(set_loc_uninitialized, 3, 0, 0, loc)
|
||||
DEF( get_loc_check, 3, 0, 1, loc)
|
||||
DEF( put_loc_check, 3, 1, 0, loc) /* must come after get_loc_check */
|
||||
DEF( put_loc_check_init, 3, 1, 0, loc)
|
||||
DEF(get_loc_checkthis, 3, 0, 1, loc)
|
||||
DEF(get_var_ref_check, 3, 0, 1, var_ref)
|
||||
DEF(put_var_ref_check, 3, 1, 0, var_ref) /* must come after get_var_ref_check */
|
||||
DEF(put_var_ref_check_init, 3, 1, 0, var_ref)
|
||||
DEF( close_loc, 3, 0, 0, loc)
|
||||
DEF( if_false, 5, 1, 0, label)
|
||||
DEF( if_true, 5, 1, 0, label) /* must come after if_false */
|
||||
DEF( goto, 5, 0, 0, label) /* must come after if_true */
|
||||
DEF( catch, 5, 0, 1, label)
|
||||
DEF( gosub, 5, 0, 0, label) /* used to execute the finally block */
|
||||
DEF( ret, 1, 1, 0, none) /* used to return from the finally block */
|
||||
DEF( nip_catch, 1, 2, 1, none) /* catch ... a -> a */
|
||||
|
||||
DEF( to_object, 1, 1, 1, none)
|
||||
//DEF( to_string, 1, 1, 1, none)
|
||||
DEF( to_propkey, 1, 1, 1, none)
|
||||
DEF( to_propkey2, 1, 2, 2, none)
|
||||
|
||||
DEF( with_get_var, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */
|
||||
DEF( with_put_var, 10, 2, 1, atom_label_u8) /* must be in the same order as scope_xxx */
|
||||
DEF(with_delete_var, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */
|
||||
DEF( with_make_ref, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */
|
||||
DEF( with_get_ref, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */
|
||||
DEF(with_get_ref_undef, 10, 1, 0, atom_label_u8)
|
||||
|
||||
DEF( make_loc_ref, 7, 0, 2, atom_u16)
|
||||
DEF( make_arg_ref, 7, 0, 2, atom_u16)
|
||||
DEF(make_var_ref_ref, 7, 0, 2, atom_u16)
|
||||
DEF( make_var_ref, 5, 0, 2, atom)
|
||||
|
||||
DEF( for_in_start, 1, 1, 1, none)
|
||||
DEF( for_of_start, 1, 1, 3, none)
|
||||
DEF(for_await_of_start, 1, 1, 3, none)
|
||||
DEF( for_in_next, 1, 1, 3, none)
|
||||
DEF( for_of_next, 2, 3, 5, u8)
|
||||
DEF(iterator_check_object, 1, 1, 1, none)
|
||||
DEF(iterator_get_value_done, 1, 1, 2, none)
|
||||
DEF( iterator_close, 1, 3, 0, none)
|
||||
DEF( iterator_next, 1, 4, 4, none)
|
||||
DEF( iterator_call, 2, 4, 5, u8)
|
||||
DEF( initial_yield, 1, 0, 0, none)
|
||||
DEF( yield, 1, 1, 2, none)
|
||||
DEF( yield_star, 1, 1, 2, none)
|
||||
DEF(async_yield_star, 1, 1, 2, none)
|
||||
DEF( await, 1, 1, 1, none)
|
||||
|
||||
/* arithmetic/logic operations */
|
||||
DEF( neg, 1, 1, 1, none)
|
||||
DEF( plus, 1, 1, 1, none)
|
||||
DEF( dec, 1, 1, 1, none)
|
||||
DEF( inc, 1, 1, 1, none)
|
||||
DEF( post_dec, 1, 1, 2, none)
|
||||
DEF( post_inc, 1, 1, 2, none)
|
||||
DEF( dec_loc, 2, 0, 0, loc8)
|
||||
DEF( inc_loc, 2, 0, 0, loc8)
|
||||
DEF( add_loc, 2, 1, 0, loc8)
|
||||
DEF( not, 1, 1, 1, none)
|
||||
DEF( lnot, 1, 1, 1, none)
|
||||
DEF( typeof, 1, 1, 1, none)
|
||||
DEF( delete, 1, 2, 1, none)
|
||||
DEF( delete_var, 5, 0, 1, atom)
|
||||
|
||||
DEF( mul, 1, 2, 1, none)
|
||||
DEF( div, 1, 2, 1, none)
|
||||
DEF( mod, 1, 2, 1, none)
|
||||
DEF( add, 1, 2, 1, none)
|
||||
DEF( sub, 1, 2, 1, none)
|
||||
DEF( pow, 1, 2, 1, none)
|
||||
DEF( shl, 1, 2, 1, none)
|
||||
DEF( sar, 1, 2, 1, none)
|
||||
DEF( shr, 1, 2, 1, none)
|
||||
DEF( lt, 1, 2, 1, none)
|
||||
DEF( lte, 1, 2, 1, none)
|
||||
DEF( gt, 1, 2, 1, none)
|
||||
DEF( gte, 1, 2, 1, none)
|
||||
DEF( instanceof, 1, 2, 1, none)
|
||||
DEF( in, 1, 2, 1, none)
|
||||
DEF( eq, 1, 2, 1, none)
|
||||
DEF( neq, 1, 2, 1, none)
|
||||
DEF( strict_eq, 1, 2, 1, none)
|
||||
DEF( strict_neq, 1, 2, 1, none)
|
||||
DEF( and, 1, 2, 1, none)
|
||||
DEF( xor, 1, 2, 1, none)
|
||||
DEF( or, 1, 2, 1, none)
|
||||
DEF(is_undefined_or_null, 1, 1, 1, none)
|
||||
DEF( private_in, 1, 2, 1, none)
|
||||
#ifdef CONFIG_BIGNUM
|
||||
DEF( mul_pow10, 1, 2, 1, none)
|
||||
DEF( math_mod, 1, 2, 1, none)
|
||||
#endif
|
||||
/* must be the last non short and non temporary opcode */
|
||||
DEF( nop, 1, 0, 0, none)
|
||||
|
||||
/* temporary opcodes: never emitted in the final bytecode */
|
||||
|
||||
def( enter_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */
|
||||
def( leave_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */
|
||||
|
||||
def( label, 5, 0, 0, label) /* emitted in phase 1, removed in phase 3 */
|
||||
|
||||
/* the following opcodes must be in the same order as the 'with_x' and
|
||||
get_var_undef, get_var and put_var opcodes */
|
||||
def(scope_get_var_undef, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */
|
||||
def( scope_get_var, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */
|
||||
def( scope_put_var, 7, 1, 0, atom_u16) /* emitted in phase 1, removed in phase 2 */
|
||||
def(scope_delete_var, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */
|
||||
def( scope_make_ref, 11, 0, 2, atom_label_u16) /* emitted in phase 1, removed in phase 2 */
|
||||
def( scope_get_ref, 7, 0, 2, atom_u16) /* emitted in phase 1, removed in phase 2 */
|
||||
def(scope_put_var_init, 7, 0, 2, atom_u16) /* emitted in phase 1, removed in phase 2 */
|
||||
def(scope_get_var_checkthis, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2, only used to return 'this' in derived class constructors */
|
||||
def(scope_get_private_field, 7, 1, 1, atom_u16) /* obj -> value, emitted in phase 1, removed in phase 2 */
|
||||
def(scope_get_private_field2, 7, 1, 2, atom_u16) /* obj -> obj value, emitted in phase 1, removed in phase 2 */
|
||||
def(scope_put_private_field, 7, 2, 0, atom_u16) /* obj value ->, emitted in phase 1, removed in phase 2 */
|
||||
def(scope_in_private_field, 7, 1, 1, atom_u16) /* obj -> res emitted in phase 1, removed in phase 2 */
|
||||
def(get_field_opt_chain, 5, 1, 1, atom) /* emitted in phase 1, removed in phase 2 */
|
||||
def(get_array_el_opt_chain, 1, 2, 1, none) /* emitted in phase 1, removed in phase 2 */
|
||||
def( set_class_name, 5, 1, 1, u32) /* emitted in phase 1, removed in phase 2 */
|
||||
|
||||
def( line_num, 5, 0, 0, u32) /* emitted in phase 1, removed in phase 3 */
|
||||
|
||||
#if SHORT_OPCODES
|
||||
DEF( push_minus1, 1, 0, 1, none_int)
|
||||
DEF( push_0, 1, 0, 1, none_int)
|
||||
DEF( push_1, 1, 0, 1, none_int)
|
||||
DEF( push_2, 1, 0, 1, none_int)
|
||||
DEF( push_3, 1, 0, 1, none_int)
|
||||
DEF( push_4, 1, 0, 1, none_int)
|
||||
DEF( push_5, 1, 0, 1, none_int)
|
||||
DEF( push_6, 1, 0, 1, none_int)
|
||||
DEF( push_7, 1, 0, 1, none_int)
|
||||
DEF( push_i8, 2, 0, 1, i8)
|
||||
DEF( push_i16, 3, 0, 1, i16)
|
||||
DEF( push_const8, 2, 0, 1, const8)
|
||||
DEF( fclosure8, 2, 0, 1, const8) /* must follow push_const8 */
|
||||
DEF(push_empty_string, 1, 0, 1, none)
|
||||
|
||||
DEF( get_loc8, 2, 0, 1, loc8)
|
||||
DEF( put_loc8, 2, 1, 0, loc8)
|
||||
DEF( set_loc8, 2, 1, 1, loc8)
|
||||
|
||||
DEF( get_loc0, 1, 0, 1, none_loc)
|
||||
DEF( get_loc1, 1, 0, 1, none_loc)
|
||||
DEF( get_loc2, 1, 0, 1, none_loc)
|
||||
DEF( get_loc3, 1, 0, 1, none_loc)
|
||||
DEF( put_loc0, 1, 1, 0, none_loc)
|
||||
DEF( put_loc1, 1, 1, 0, none_loc)
|
||||
DEF( put_loc2, 1, 1, 0, none_loc)
|
||||
DEF( put_loc3, 1, 1, 0, none_loc)
|
||||
DEF( set_loc0, 1, 1, 1, none_loc)
|
||||
DEF( set_loc1, 1, 1, 1, none_loc)
|
||||
DEF( set_loc2, 1, 1, 1, none_loc)
|
||||
DEF( set_loc3, 1, 1, 1, none_loc)
|
||||
DEF( get_arg0, 1, 0, 1, none_arg)
|
||||
DEF( get_arg1, 1, 0, 1, none_arg)
|
||||
DEF( get_arg2, 1, 0, 1, none_arg)
|
||||
DEF( get_arg3, 1, 0, 1, none_arg)
|
||||
DEF( put_arg0, 1, 1, 0, none_arg)
|
||||
DEF( put_arg1, 1, 1, 0, none_arg)
|
||||
DEF( put_arg2, 1, 1, 0, none_arg)
|
||||
DEF( put_arg3, 1, 1, 0, none_arg)
|
||||
DEF( set_arg0, 1, 1, 1, none_arg)
|
||||
DEF( set_arg1, 1, 1, 1, none_arg)
|
||||
DEF( set_arg2, 1, 1, 1, none_arg)
|
||||
DEF( set_arg3, 1, 1, 1, none_arg)
|
||||
DEF( get_var_ref0, 1, 0, 1, none_var_ref)
|
||||
DEF( get_var_ref1, 1, 0, 1, none_var_ref)
|
||||
DEF( get_var_ref2, 1, 0, 1, none_var_ref)
|
||||
DEF( get_var_ref3, 1, 0, 1, none_var_ref)
|
||||
DEF( put_var_ref0, 1, 1, 0, none_var_ref)
|
||||
DEF( put_var_ref1, 1, 1, 0, none_var_ref)
|
||||
DEF( put_var_ref2, 1, 1, 0, none_var_ref)
|
||||
DEF( put_var_ref3, 1, 1, 0, none_var_ref)
|
||||
DEF( set_var_ref0, 1, 1, 1, none_var_ref)
|
||||
DEF( set_var_ref1, 1, 1, 1, none_var_ref)
|
||||
DEF( set_var_ref2, 1, 1, 1, none_var_ref)
|
||||
DEF( set_var_ref3, 1, 1, 1, none_var_ref)
|
||||
|
||||
DEF( get_length, 1, 1, 1, none)
|
||||
|
||||
DEF( if_false8, 2, 1, 0, label8)
|
||||
DEF( if_true8, 2, 1, 0, label8) /* must come after if_false8 */
|
||||
DEF( goto8, 2, 0, 0, label8) /* must come after if_true8 */
|
||||
DEF( goto16, 3, 0, 0, label16)
|
||||
|
||||
DEF( call0, 1, 1, 1, npopx)
|
||||
DEF( call1, 1, 1, 1, npopx)
|
||||
DEF( call2, 1, 1, 1, npopx)
|
||||
DEF( call3, 1, 1, 1, npopx)
|
||||
|
||||
DEF( is_undefined, 1, 1, 1, none)
|
||||
DEF( is_null, 1, 1, 1, none)
|
||||
DEF(typeof_is_undefined, 1, 1, 1, none)
|
||||
DEF( typeof_is_function, 1, 1, 1, none)
|
||||
#endif
|
||||
|
||||
#undef DEF
|
||||
#undef def
|
||||
#endif /* DEF */
|
55548
quickjs/quickjs.c
Normal file
1060
quickjs/quickjs.h
Normal file
1
quickjs/readme.txt
Normal file
|
@ -0,0 +1 @@
|
|||
The main documentation is in doc/quickjs.pdf or doc/quickjs.html.
|
158
quickjs/release.sh
Executable file
|
@ -0,0 +1,158 @@
|
|||
#!/bin/sh
|
||||
# Release the QuickJS source code
|
||||
|
||||
set -e
|
||||
|
||||
version=`cat VERSION`
|
||||
|
||||
if [ "$1" = "-h" ] ; then
|
||||
echo "release.sh [release_list]"
|
||||
echo ""
|
||||
echo "release_list: extras binary win_binary quickjs"
|
||||
|
||||
exit 1
|
||||
fi
|
||||
|
||||
release_list="extras binary win_binary quickjs"
|
||||
|
||||
if [ "$1" != "" ] ; then
|
||||
release_list="$1"
|
||||
fi
|
||||
|
||||
#################################################"
|
||||
# extras
|
||||
|
||||
if echo $release_list | grep -w -q extras ; then
|
||||
|
||||
d="quickjs-${version}"
|
||||
name="quickjs-extras-${version}"
|
||||
outdir="/tmp/${d}"
|
||||
|
||||
rm -rf $outdir
|
||||
mkdir -p $outdir $outdir/unicode $outdir/tests
|
||||
|
||||
cp unicode/* $outdir/unicode
|
||||
cp -a tests/bench-v8 $outdir/tests
|
||||
|
||||
( cd /tmp && tar Jcvf /tmp/${name}.tar.xz ${d} )
|
||||
|
||||
fi
|
||||
|
||||
#################################################"
|
||||
# Windows binary release
|
||||
|
||||
if echo $release_list | grep -w -q win_binary ; then
|
||||
|
||||
# win64
|
||||
|
||||
dlldir=/usr/x86_64-w64-mingw32/sys-root/mingw/bin
|
||||
cross_prefix="x86_64-w64-mingw32-"
|
||||
d="quickjs-win-x86_64-${version}"
|
||||
outdir="/tmp/${d}"
|
||||
|
||||
rm -rf $outdir
|
||||
mkdir -p $outdir
|
||||
|
||||
make CONFIG_WIN32=y qjs.exe
|
||||
cp qjs.exe $outdir
|
||||
${cross_prefix}strip $outdir/qjs.exe
|
||||
cp $dlldir/libwinpthread-1.dll $outdir
|
||||
|
||||
( cd /tmp/$d && rm -f ../${d}.zip && zip -r ../${d}.zip . )
|
||||
|
||||
make CONFIG_WIN32=y clean
|
||||
|
||||
# win32
|
||||
|
||||
dlldir=/usr/i686-w64-mingw32/sys-root/mingw/bin
|
||||
cross_prefix="i686-w64-mingw32-"
|
||||
d="quickjs-win-i686-${version}"
|
||||
outdir="/tmp/${d}"
|
||||
|
||||
rm -rf $outdir
|
||||
mkdir -p $outdir
|
||||
|
||||
make clean
|
||||
make CONFIG_WIN32=y clean
|
||||
|
||||
make CONFIG_WIN32=y CONFIG_M32=y qjs.exe
|
||||
cp qjs.exe $outdir
|
||||
${cross_prefix}strip $outdir/qjs.exe
|
||||
cp $dlldir/libwinpthread-1.dll $outdir
|
||||
|
||||
( cd /tmp/$d && rm -f ../${d}.zip && zip -r ../${d}.zip . )
|
||||
|
||||
fi
|
||||
|
||||
#################################################"
|
||||
# Linux binary release
|
||||
|
||||
if echo $release_list | grep -w -q binary ; then
|
||||
|
||||
make clean
|
||||
make CONFIG_WIN32=y clean
|
||||
make -j4 qjs run-test262
|
||||
make -j4 CONFIG_M32=y qjs32 run-test262-32
|
||||
strip qjs run-test262 qjs32 run-test262-32
|
||||
|
||||
d="quickjs-linux-x86_64-${version}"
|
||||
outdir="/tmp/${d}"
|
||||
|
||||
rm -rf $outdir
|
||||
mkdir -p $outdir
|
||||
|
||||
cp qjs run-test262 $outdir
|
||||
|
||||
( cd /tmp/$d && rm -f ../${d}.zip && zip -r ../${d}.zip . )
|
||||
|
||||
d="quickjs-linux-i686-${version}"
|
||||
outdir="/tmp/${d}"
|
||||
|
||||
rm -rf $outdir
|
||||
mkdir -p $outdir
|
||||
|
||||
cp qjs32 $outdir/qjs
|
||||
cp run-test262-32 $outdir/run-test262
|
||||
|
||||
( cd /tmp/$d && rm -f ../${d}.zip && zip -r ../${d}.zip . )
|
||||
|
||||
fi
|
||||
|
||||
#################################################"
|
||||
# quickjs
|
||||
|
||||
if echo $release_list | grep -w -q quickjs ; then
|
||||
|
||||
make build_doc
|
||||
|
||||
d="quickjs-${version}"
|
||||
outdir="/tmp/${d}"
|
||||
|
||||
rm -rf $outdir
|
||||
mkdir -p $outdir $outdir/doc $outdir/tests $outdir/examples
|
||||
|
||||
cp Makefile VERSION TODO Changelog readme.txt LICENSE \
|
||||
release.sh unicode_download.sh \
|
||||
qjs.c qjsc.c qjscalc.js repl.js \
|
||||
quickjs.c quickjs.h quickjs-atom.h \
|
||||
quickjs-libc.c quickjs-libc.h quickjs-opcode.h \
|
||||
cutils.c cutils.h list.h \
|
||||
libregexp.c libregexp.h libregexp-opcode.h \
|
||||
libunicode.c libunicode.h libunicode-table.h \
|
||||
libbf.c libbf.h \
|
||||
unicode_gen.c unicode_gen_def.h \
|
||||
run-test262.c test262o.conf test262.conf \
|
||||
test262o_errors.txt test262_errors.txt \
|
||||
$outdir
|
||||
|
||||
cp tests/*.js tests/*.patch tests/bjson.c $outdir/tests
|
||||
|
||||
cp examples/*.js examples/*.c $outdir/examples
|
||||
|
||||
cp doc/quickjs.texi doc/quickjs.pdf doc/quickjs.html \
|
||||
doc/jsbignum.texi doc/jsbignum.html doc/jsbignum.pdf \
|
||||
$outdir/doc
|
||||
|
||||
( cd /tmp && tar Jcvf /tmp/${d}.tar.xz ${d} )
|
||||
|
||||
fi
|
19
quickjs/unicode_download.sh
Executable file
|
@ -0,0 +1,19 @@
|
|||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
url="ftp://ftp.unicode.org/Public/14.0.0/ucd"
|
||||
emoji_url="${url}/emoji/emoji-data.txt"
|
||||
|
||||
files="CaseFolding.txt DerivedNormalizationProps.txt PropList.txt \
|
||||
SpecialCasing.txt CompositionExclusions.txt ScriptExtensions.txt \
|
||||
UnicodeData.txt DerivedCoreProperties.txt NormalizationTest.txt Scripts.txt \
|
||||
PropertyValueAliases.txt"
|
||||
|
||||
mkdir -p unicode
|
||||
|
||||
for f in $files; do
|
||||
g="${url}/${f}"
|
||||
wget $g -O unicode/$f
|
||||
done
|
||||
|
||||
wget $emoji_url -O unicode/emoji-data.txt
|
3145
quickjs/unicode_gen.c
Normal file
291
quickjs/unicode_gen_def.h
Normal file
|
@ -0,0 +1,291 @@
|
|||
#ifdef UNICODE_GENERAL_CATEGORY
|
||||
DEF(Cn, "Unassigned") /* must be zero */
|
||||
DEF(Lu, "Uppercase_Letter")
|
||||
DEF(Ll, "Lowercase_Letter")
|
||||
DEF(Lt, "Titlecase_Letter")
|
||||
DEF(Lm, "Modifier_Letter")
|
||||
DEF(Lo, "Other_Letter")
|
||||
DEF(Mn, "Nonspacing_Mark")
|
||||
DEF(Mc, "Spacing_Mark")
|
||||
DEF(Me, "Enclosing_Mark")
|
||||
DEF(Nd, "Decimal_Number,digit")
|
||||
DEF(Nl, "Letter_Number")
|
||||
DEF(No, "Other_Number")
|
||||
DEF(Sm, "Math_Symbol")
|
||||
DEF(Sc, "Currency_Symbol")
|
||||
DEF(Sk, "Modifier_Symbol")
|
||||
DEF(So, "Other_Symbol")
|
||||
DEF(Pc, "Connector_Punctuation")
|
||||
DEF(Pd, "Dash_Punctuation")
|
||||
DEF(Ps, "Open_Punctuation")
|
||||
DEF(Pe, "Close_Punctuation")
|
||||
DEF(Pi, "Initial_Punctuation")
|
||||
DEF(Pf, "Final_Punctuation")
|
||||
DEF(Po, "Other_Punctuation")
|
||||
DEF(Zs, "Space_Separator")
|
||||
DEF(Zl, "Line_Separator")
|
||||
DEF(Zp, "Paragraph_Separator")
|
||||
DEF(Cc, "Control,cntrl")
|
||||
DEF(Cf, "Format")
|
||||
DEF(Cs, "Surrogate")
|
||||
DEF(Co, "Private_Use")
|
||||
/* synthetic properties */
|
||||
DEF(LC, "Cased_Letter")
|
||||
DEF(L, "Letter")
|
||||
DEF(M, "Mark,Combining_Mark")
|
||||
DEF(N, "Number")
|
||||
DEF(S, "Symbol")
|
||||
DEF(P, "Punctuation,punct")
|
||||
DEF(Z, "Separator")
|
||||
DEF(C, "Other")
|
||||
#endif
|
||||
|
||||
#ifdef UNICODE_SCRIPT
|
||||
/* scripts aliases names in PropertyValueAliases.txt */
|
||||
DEF(Unknown, "Zzzz")
|
||||
DEF(Adlam, "Adlm")
|
||||
DEF(Ahom, "Ahom")
|
||||
DEF(Anatolian_Hieroglyphs, "Hluw")
|
||||
DEF(Arabic, "Arab")
|
||||
DEF(Armenian, "Armn")
|
||||
DEF(Avestan, "Avst")
|
||||
DEF(Balinese, "Bali")
|
||||
DEF(Bamum, "Bamu")
|
||||
DEF(Bassa_Vah, "Bass")
|
||||
DEF(Batak, "Batk")
|
||||
DEF(Bengali, "Beng")
|
||||
DEF(Bhaiksuki, "Bhks")
|
||||
DEF(Bopomofo, "Bopo")
|
||||
DEF(Brahmi, "Brah")
|
||||
DEF(Braille, "Brai")
|
||||
DEF(Buginese, "Bugi")
|
||||
DEF(Buhid, "Buhd")
|
||||
DEF(Canadian_Aboriginal, "Cans")
|
||||
DEF(Carian, "Cari")
|
||||
DEF(Caucasian_Albanian, "Aghb")
|
||||
DEF(Chakma, "Cakm")
|
||||
DEF(Cham, "Cham")
|
||||
DEF(Cherokee, "Cher")
|
||||
DEF(Chorasmian, "Chrs")
|
||||
DEF(Common, "Zyyy")
|
||||
DEF(Coptic, "Copt,Qaac")
|
||||
DEF(Cuneiform, "Xsux")
|
||||
DEF(Cypriot, "Cprt")
|
||||
DEF(Cyrillic, "Cyrl")
|
||||
DEF(Cypro_Minoan, "Cpmn")
|
||||
DEF(Deseret, "Dsrt")
|
||||
DEF(Devanagari, "Deva")
|
||||
DEF(Dives_Akuru, "Diak")
|
||||
DEF(Dogra, "Dogr")
|
||||
DEF(Duployan, "Dupl")
|
||||
DEF(Egyptian_Hieroglyphs, "Egyp")
|
||||
DEF(Elbasan, "Elba")
|
||||
DEF(Elymaic, "Elym")
|
||||
DEF(Ethiopic, "Ethi")
|
||||
DEF(Georgian, "Geor")
|
||||
DEF(Glagolitic, "Glag")
|
||||
DEF(Gothic, "Goth")
|
||||
DEF(Grantha, "Gran")
|
||||
DEF(Greek, "Grek")
|
||||
DEF(Gujarati, "Gujr")
|
||||
DEF(Gunjala_Gondi, "Gong")
|
||||
DEF(Gurmukhi, "Guru")
|
||||
DEF(Han, "Hani")
|
||||
DEF(Hangul, "Hang")
|
||||
DEF(Hanifi_Rohingya, "Rohg")
|
||||
DEF(Hanunoo, "Hano")
|
||||
DEF(Hatran, "Hatr")
|
||||
DEF(Hebrew, "Hebr")
|
||||
DEF(Hiragana, "Hira")
|
||||
DEF(Imperial_Aramaic, "Armi")
|
||||
DEF(Inherited, "Zinh,Qaai")
|
||||
DEF(Inscriptional_Pahlavi, "Phli")
|
||||
DEF(Inscriptional_Parthian, "Prti")
|
||||
DEF(Javanese, "Java")
|
||||
DEF(Kaithi, "Kthi")
|
||||
DEF(Kannada, "Knda")
|
||||
DEF(Katakana, "Kana")
|
||||
DEF(Kawi, "Kawi")
|
||||
DEF(Kayah_Li, "Kali")
|
||||
DEF(Kharoshthi, "Khar")
|
||||
DEF(Khmer, "Khmr")
|
||||
DEF(Khojki, "Khoj")
|
||||
DEF(Khitan_Small_Script, "Kits")
|
||||
DEF(Khudawadi, "Sind")
|
||||
DEF(Lao, "Laoo")
|
||||
DEF(Latin, "Latn")
|
||||
DEF(Lepcha, "Lepc")
|
||||
DEF(Limbu, "Limb")
|
||||
DEF(Linear_A, "Lina")
|
||||
DEF(Linear_B, "Linb")
|
||||
DEF(Lisu, "Lisu")
|
||||
DEF(Lycian, "Lyci")
|
||||
DEF(Lydian, "Lydi")
|
||||
DEF(Makasar, "Maka")
|
||||
DEF(Mahajani, "Mahj")
|
||||
DEF(Malayalam, "Mlym")
|
||||
DEF(Mandaic, "Mand")
|
||||
DEF(Manichaean, "Mani")
|
||||
DEF(Marchen, "Marc")
|
||||
DEF(Masaram_Gondi, "Gonm")
|
||||
DEF(Medefaidrin, "Medf")
|
||||
DEF(Meetei_Mayek, "Mtei")
|
||||
DEF(Mende_Kikakui, "Mend")
|
||||
DEF(Meroitic_Cursive, "Merc")
|
||||
DEF(Meroitic_Hieroglyphs, "Mero")
|
||||
DEF(Miao, "Plrd")
|
||||
DEF(Modi, "Modi")
|
||||
DEF(Mongolian, "Mong")
|
||||
DEF(Mro, "Mroo")
|
||||
DEF(Multani, "Mult")
|
||||
DEF(Myanmar, "Mymr")
|
||||
DEF(Nabataean, "Nbat")
|
||||
DEF(Nag_Mundari, "Nagm")
|
||||
DEF(Nandinagari, "Nand")
|
||||
DEF(New_Tai_Lue, "Talu")
|
||||
DEF(Newa, "Newa")
|
||||
DEF(Nko, "Nkoo")
|
||||
DEF(Nushu, "Nshu")
|
||||
DEF(Nyiakeng_Puachue_Hmong, "Hmnp")
|
||||
DEF(Ogham, "Ogam")
|
||||
DEF(Ol_Chiki, "Olck")
|
||||
DEF(Old_Hungarian, "Hung")
|
||||
DEF(Old_Italic, "Ital")
|
||||
DEF(Old_North_Arabian, "Narb")
|
||||
DEF(Old_Permic, "Perm")
|
||||
DEF(Old_Persian, "Xpeo")
|
||||
DEF(Old_Sogdian, "Sogo")
|
||||
DEF(Old_South_Arabian, "Sarb")
|
||||
DEF(Old_Turkic, "Orkh")
|
||||
DEF(Old_Uyghur, "Ougr")
|
||||
DEF(Oriya, "Orya")
|
||||
DEF(Osage, "Osge")
|
||||
DEF(Osmanya, "Osma")
|
||||
DEF(Pahawh_Hmong, "Hmng")
|
||||
DEF(Palmyrene, "Palm")
|
||||
DEF(Pau_Cin_Hau, "Pauc")
|
||||
DEF(Phags_Pa, "Phag")
|
||||
DEF(Phoenician, "Phnx")
|
||||
DEF(Psalter_Pahlavi, "Phlp")
|
||||
DEF(Rejang, "Rjng")
|
||||
DEF(Runic, "Runr")
|
||||
DEF(Samaritan, "Samr")
|
||||
DEF(Saurashtra, "Saur")
|
||||
DEF(Sharada, "Shrd")
|
||||
DEF(Shavian, "Shaw")
|
||||
DEF(Siddham, "Sidd")
|
||||
DEF(SignWriting, "Sgnw")
|
||||
DEF(Sinhala, "Sinh")
|
||||
DEF(Sogdian, "Sogd")
|
||||
DEF(Sora_Sompeng, "Sora")
|
||||
DEF(Soyombo, "Soyo")
|
||||
DEF(Sundanese, "Sund")
|
||||
DEF(Syloti_Nagri, "Sylo")
|
||||
DEF(Syriac, "Syrc")
|
||||
DEF(Tagalog, "Tglg")
|
||||
DEF(Tagbanwa, "Tagb")
|
||||
DEF(Tai_Le, "Tale")
|
||||
DEF(Tai_Tham, "Lana")
|
||||
DEF(Tai_Viet, "Tavt")
|
||||
DEF(Takri, "Takr")
|
||||
DEF(Tamil, "Taml")
|
||||
DEF(Tangut, "Tang")
|
||||
DEF(Telugu, "Telu")
|
||||
DEF(Thaana, "Thaa")
|
||||
DEF(Thai, "Thai")
|
||||
DEF(Tibetan, "Tibt")
|
||||
DEF(Tifinagh, "Tfng")
|
||||
DEF(Tirhuta, "Tirh")
|
||||
DEF(Tangsa, "Tnsa")
|
||||
DEF(Toto, "Toto")
|
||||
DEF(Ugaritic, "Ugar")
|
||||
DEF(Vai, "Vaii")
|
||||
DEF(Vithkuqi, "Vith")
|
||||
DEF(Wancho, "Wcho")
|
||||
DEF(Warang_Citi, "Wara")
|
||||
DEF(Yezidi, "Yezi")
|
||||
DEF(Yi, "Yiii")
|
||||
DEF(Zanabazar_Square, "Zanb")
|
||||
#endif
|
||||
|
||||
#ifdef UNICODE_PROP_LIST
|
||||
/* Prop list not exported to regexp */
|
||||
DEF(Hyphen, "")
|
||||
DEF(Other_Math, "")
|
||||
DEF(Other_Alphabetic, "")
|
||||
DEF(Other_Lowercase, "")
|
||||
DEF(Other_Uppercase, "")
|
||||
DEF(Other_Grapheme_Extend, "")
|
||||
DEF(Other_Default_Ignorable_Code_Point, "")
|
||||
DEF(Other_ID_Start, "")
|
||||
DEF(Other_ID_Continue, "")
|
||||
DEF(Prepended_Concatenation_Mark, "")
|
||||
/* additional computed properties for smaller tables */
|
||||
DEF(ID_Continue1, "")
|
||||
DEF(XID_Start1, "")
|
||||
DEF(XID_Continue1, "")
|
||||
DEF(Changes_When_Titlecased1, "")
|
||||
DEF(Changes_When_Casefolded1, "")
|
||||
DEF(Changes_When_NFKC_Casefolded1, "")
|
||||
|
||||
/* Prop list exported to JS */
|
||||
DEF(ASCII_Hex_Digit, "AHex")
|
||||
DEF(Bidi_Control, "Bidi_C")
|
||||
DEF(Dash, "")
|
||||
DEF(Deprecated, "Dep")
|
||||
DEF(Diacritic, "Dia")
|
||||
DEF(Extender, "Ext")
|
||||
DEF(Hex_Digit, "Hex")
|
||||
DEF(IDS_Binary_Operator, "IDSB")
|
||||
DEF(IDS_Trinary_Operator, "IDST")
|
||||
DEF(Ideographic, "Ideo")
|
||||
DEF(Join_Control, "Join_C")
|
||||
DEF(Logical_Order_Exception, "LOE")
|
||||
DEF(Noncharacter_Code_Point, "NChar")
|
||||
DEF(Pattern_Syntax, "Pat_Syn")
|
||||
DEF(Pattern_White_Space, "Pat_WS")
|
||||
DEF(Quotation_Mark, "QMark")
|
||||
DEF(Radical, "")
|
||||
DEF(Regional_Indicator, "RI")
|
||||
DEF(Sentence_Terminal, "STerm")
|
||||
DEF(Soft_Dotted, "SD")
|
||||
DEF(Terminal_Punctuation, "Term")
|
||||
DEF(Unified_Ideograph, "UIdeo")
|
||||
DEF(Variation_Selector, "VS")
|
||||
DEF(White_Space, "space")
|
||||
DEF(Bidi_Mirrored, "Bidi_M")
|
||||
DEF(Emoji, "")
|
||||
DEF(Emoji_Component, "EComp")
|
||||
DEF(Emoji_Modifier, "EMod")
|
||||
DEF(Emoji_Modifier_Base, "EBase")
|
||||
DEF(Emoji_Presentation, "EPres")
|
||||
DEF(Extended_Pictographic, "ExtPict")
|
||||
DEF(Default_Ignorable_Code_Point, "DI")
|
||||
DEF(ID_Start, "IDS")
|
||||
DEF(Case_Ignorable, "CI")
|
||||
|
||||
/* other binary properties */
|
||||
DEF(ASCII,"")
|
||||
DEF(Alphabetic, "Alpha")
|
||||
DEF(Any, "")
|
||||
DEF(Assigned,"")
|
||||
DEF(Cased, "")
|
||||
DEF(Changes_When_Casefolded, "CWCF")
|
||||
DEF(Changes_When_Casemapped, "CWCM")
|
||||
DEF(Changes_When_Lowercased, "CWL")
|
||||
DEF(Changes_When_NFKC_Casefolded, "CWKCF")
|
||||
DEF(Changes_When_Titlecased, "CWT")
|
||||
DEF(Changes_When_Uppercased, "CWU")
|
||||
DEF(Grapheme_Base, "Gr_Base")
|
||||
DEF(Grapheme_Extend, "Gr_Ext")
|
||||
DEF(ID_Continue, "IDC")
|
||||
DEF(Lowercase, "Lower")
|
||||
DEF(Math, "")
|
||||
DEF(Uppercase, "Upper")
|
||||
DEF(XID_Continue, "XIDC")
|
||||
DEF(XID_Start, "XIDS")
|
||||
|
||||
/* internal tables with index */
|
||||
DEF(Cased1, "")
|
||||
|
||||
#endif
|
4
readme.md
Normal file
|
@ -0,0 +1,4 @@
|
|||
# Prosperon Engine
|
||||
The easily extendable, developer minded, 2D-first game engine.
|
||||
|
||||
See the documentation [here](https://prosperon.dev/doc).
|
|
@ -5,7 +5,7 @@ actor.spawn = function(script, config){
|
|||
if (typeof script !== 'string') return undefined;
|
||||
if (!a_db[script]) a_db[script] = io.slurp(script);
|
||||
var padawan = Object.create(actor);
|
||||
eval_env(a_db[script], padawan, script);
|
||||
eval_env(a_db[script], padawan);
|
||||
|
||||
if (typeof config === 'object')
|
||||
Object.merge(padawan,config);
|
||||
|
@ -14,25 +14,18 @@ actor.spawn = function(script, config){
|
|||
padawan.timers = [];
|
||||
padawan.master = this;
|
||||
Object.hide(padawan, "master","timers", "padawans");
|
||||
check_registers(padawan);
|
||||
this.padawans.push(padawan);
|
||||
return padawan;
|
||||
};
|
||||
|
||||
actor.spawn.doc = `Create a new actor, using this actor as the master, initializing it with 'script' and with data (as a JSON or Nota file) from 'config'.`;
|
||||
|
||||
actor.rm_pawn = function(pawn)
|
||||
{
|
||||
this.padawans.remove(pawn);
|
||||
}
|
||||
|
||||
actor.timers = [];
|
||||
actor.kill = function(){
|
||||
if (this.__dead__) return;
|
||||
this.timers.forEach(t => t());
|
||||
Player.do_uncontrol(this);
|
||||
Event.rm_obj(this);
|
||||
if (this.master) this.master.rm_pawn(this);
|
||||
this.timers.forEach(t => t.kill());
|
||||
if (this.master)
|
||||
delete this.master[this.toString()];
|
||||
this.padawans.forEach(p => p.kill());
|
||||
this.padawans = [];
|
||||
this.__dead__ = true;
|
||||
|
@ -43,15 +36,32 @@ actor.kill = function(){
|
|||
actor.kill.doc = `Remove this actor and all its padawans from existence.`;
|
||||
|
||||
actor.delay = function(fn, seconds) {
|
||||
var t = timer.delay(fn.bind(this), seconds);
|
||||
var t = Object.create(timer);
|
||||
t.remain = seconds;
|
||||
t.kill = () => {
|
||||
timer.kill.call(t);
|
||||
delete this.timers[t.toString()];
|
||||
}
|
||||
t.fire = () => {
|
||||
if (this.__dead__) return;
|
||||
fn();
|
||||
t.kill();
|
||||
};
|
||||
Register.appupdate.register(t.update, t);
|
||||
this.timers.push(t);
|
||||
return t;
|
||||
return function() { t.kill(); };
|
||||
};
|
||||
|
||||
actor.delay.doc = `Call 'fn' after 'seconds' with 'this' set to the actor.`;
|
||||
|
||||
actor.padawans = [];
|
||||
|
||||
actor.remaster = function(to){
|
||||
delete this.master.padawans[this.toString()];
|
||||
this.master = to;
|
||||
to.padawans.push(this);
|
||||
};
|
||||
|
||||
global.app = Object.create(actor);
|
||||
|
||||
app.die = function()
|
||||
|
|
|
@ -6,24 +6,24 @@ this.realzoom = function() { return cmd(135); };
|
|||
|
||||
this.right = function()
|
||||
{
|
||||
return this.pos.x + (Game.width/2);
|
||||
return this.pos.x + (Window.width/2);
|
||||
}
|
||||
|
||||
this.left = function()
|
||||
{
|
||||
return this.pos.x - (Game.width/2);
|
||||
return this.pos.x - (Window.width/2);
|
||||
}
|
||||
|
||||
this.mixin({
|
||||
get zoom() {
|
||||
// var z = Game.native.y / Window.dimensions.y;
|
||||
return cmd(135);///z;
|
||||
var z = Game.native.y / Window.dimensions.y;
|
||||
return cmd(135)/z;
|
||||
},
|
||||
|
||||
set zoom(x) {
|
||||
x = Math.clamp(x,0.1,10);
|
||||
// var z = Game.native.y / Window.dimensions.y;
|
||||
// z *= x;
|
||||
cmd(62,x);
|
||||
var z = Game.native.y / Window.dimensions.y;
|
||||
z *= x;
|
||||
cmd(62,z);
|
||||
},
|
||||
});
|
|
@ -160,10 +160,6 @@ component.sprite.impl = {
|
|||
set angle(x) { cmd(218,this.id,x); },
|
||||
get scale() { return cmd(215, this.id); },
|
||||
set scale(x) { cmd(216, this.id, x); },
|
||||
grow(x) {
|
||||
this.scale = this.scale.scale(x);
|
||||
this.pos = this.pos.scale(x);
|
||||
},
|
||||
get drawmode() { return cmd(220,this.id); },
|
||||
set drawmode(x) { cmd(219,this.id,x); },
|
||||
emissive(x) { cmd(170, this.id, x); },
|
||||
|
@ -421,15 +417,9 @@ component.polygon2d = Object.copy(collider2d, {
|
|||
},
|
||||
});
|
||||
|
||||
function pointscaler(x) {
|
||||
if (typeof x === 'number') return;
|
||||
this.points = this.points.map(p => p.mult(x));
|
||||
}
|
||||
|
||||
component.polygon2d.impl = Object.mix(collider2d.impl, {
|
||||
sync() { cmd_poly2d(0, this.id, this.spoints());},
|
||||
query() { return cmd(80, this.shape); },
|
||||
grow: pointscaler,
|
||||
});
|
||||
|
||||
var polygon2d = component.polygon2d;
|
||||
|
@ -473,15 +463,15 @@ component.edge2d = Object.copy(collider2d, {
|
|||
|
||||
flipx: false,
|
||||
flipy: false,
|
||||
points:[],
|
||||
cpoints:[],
|
||||
toString() { return "edge2d"; },
|
||||
|
||||
hollow: false,
|
||||
hollowt: 0,
|
||||
|
||||
spoints() {
|
||||
if (!this.points) return [];
|
||||
var spoints = this.points.slice();
|
||||
if (!this.cpoints) return [];
|
||||
var spoints = this.cpoints.slice();
|
||||
|
||||
if (this.flipx) {
|
||||
if (Spline.is_bezier(this.type))
|
||||
|
@ -517,12 +507,12 @@ component.edge2d = Object.copy(collider2d, {
|
|||
},
|
||||
|
||||
setpoints(points) {
|
||||
this.points = points;
|
||||
this.cpoints = points;
|
||||
// this.sync();
|
||||
},
|
||||
|
||||
post() {
|
||||
this.points = [];
|
||||
this.cpoints = [];
|
||||
},
|
||||
|
||||
sample() {
|
||||
|
@ -556,25 +546,25 @@ component.edge2d = Object.copy(collider2d, {
|
|||
gizmo() {
|
||||
if (this.type === Spline.type.catmull || this.type === -1) {
|
||||
this.spoints().forEach(x => render.point(this.gameobject.this2screen(x), 3, Color.teal));
|
||||
this.points.forEach((x,i) => Debug.numbered_point(this.gameobject.this2screen(x), i));
|
||||
this.cpoints.forEach((x,i) => Debug.numbered_point(this.gameobject.this2screen(x), i));
|
||||
} else {
|
||||
for (var i = 0; i < this.points.length; i += 3)
|
||||
Debug.numbered_point(this.gameobject.this2screen(this.points[i]), i, Color.teal);
|
||||
for (var i = 0; i < this.cpoints.length; i += 3)
|
||||
Debug.numbered_point(this.gameobject.this2screen(this.cpoints[i]), i, Color.teal);
|
||||
|
||||
for (var i = 1; i < this.points.length; i+=3) {
|
||||
Debug.numbered_point(this.gameobject.this2screen(this.points[i]), i, Color.green);
|
||||
Debug.numbered_point(this.gameobject.this2screen(this.points[i+1]), i+1, Color.green);
|
||||
render.line([this.gameobject.this2screen(this.points[i-1]), this.gameobject.this2screen(this.points[i])], Color.yellow);
|
||||
render.line([this.gameobject.this2screen(this.points[i+1]), this.gameobject.this2screen(this.points[i+2])], Color.yellow);
|
||||
for (var i = 1; i < this.cpoints.length; i+=3) {
|
||||
Debug.numbered_point(this.gameobject.this2screen(this.cpoints[i]), i, Color.green);
|
||||
Debug.numbered_point(this.gameobject.this2screen(this.cpoints[i+1]), i+1, Color.green);
|
||||
render.line([this.gameobject.this2screen(this.cpoints[i-1]), this.gameobject.this2screen(this.cpoints[i])], Color.yellow);
|
||||
render.line([this.gameobject.this2screen(this.cpoints[i+1]), this.gameobject.this2screen(this.cpoints[i+2])], Color.yellow);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
finish_center(change) { this.points = this.points.map(function(x) { return x.sub(change); }); },
|
||||
finish_center(change) { this.cpoints = this.cpoints.map(function(x) { return x.sub(change); }); },
|
||||
|
||||
pick(pos) {
|
||||
var i = Gizmos.pick_gameobject_points(pos, this.gameobject, this.points);
|
||||
var p = this.points[i];
|
||||
var i = Gizmos.pick_gameobject_points(pos, this.gameobject, this.cpoints);
|
||||
var p = this.cpoints[i];
|
||||
if (!p) return undefined;
|
||||
|
||||
if (Spline.is_catmull(this.type) || this.type === -1)
|
||||
|
@ -587,38 +577,38 @@ component.edge2d = Object.copy(collider2d, {
|
|||
pos: p,
|
||||
sync: me.sync.bind(me)
|
||||
};
|
||||
if (Spline.bezier_is_handle(this.points,i))
|
||||
if (Spline.bezier_is_handle(this.cpoints,i))
|
||||
o.move = function(d) {
|
||||
d = that.dir_world2this(d);
|
||||
p.x += d.x;
|
||||
p.y += d.y;
|
||||
Spline.bezier_cp_mirror(me.points,i);
|
||||
Spline.bezier_cp_mirror(me.cpoints,i);
|
||||
};
|
||||
else
|
||||
o.move = function(d) {
|
||||
d = that.dir_world2this(d);
|
||||
p.x += d.x;
|
||||
p.y += d.y;
|
||||
var pp = Spline.bezier_point_handles(me.points,i);
|
||||
pp.forEach(ph => me.points[ph] = me.points[ph].add(d));
|
||||
var pp = Spline.bezier_point_handles(me.cpoints,i);
|
||||
pp.forEach(ph => me.cpoints[ph] = me.cpoints[ph].add(d));
|
||||
}
|
||||
return o;
|
||||
}
|
||||
},
|
||||
|
||||
rm_node(idx) {
|
||||
if (idx < 0 || idx >= this.points.length) return;
|
||||
if (idx < 0 || idx >= this.cpoints.length) return;
|
||||
if (Spline.is_catmull(this.type))
|
||||
this.points.splice(idx,1);
|
||||
this.cpoints.splice(idx,1);
|
||||
|
||||
if (Spline.is_bezier(this.type)) {
|
||||
Debug.assert(Spline.bezier_is_node(this.points, idx), 'Attempted to delete a bezier handle.');
|
||||
Debug.assert(Spline.bezier_is_node(this.cpoints, idx), 'Attempted to delete a bezier handle.');
|
||||
if (idx === 0)
|
||||
this.points.splice(idx,2);
|
||||
else if (idx === this.points.length-1)
|
||||
this.points.splice(this.points.length-2,2);
|
||||
this.cpoints.splice(idx,2);
|
||||
else if (idx === this.cpoints.length-1)
|
||||
this.cpoints.splice(this.cpoints.length-2,2);
|
||||
else
|
||||
this.points.splice(idx-1,3);
|
||||
this.cpoints.splice(idx-1,3);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -626,47 +616,46 @@ component.edge2d = Object.copy(collider2d, {
|
|||
pos = this.gameobject.world2this(pos);
|
||||
var idx = 0;
|
||||
if (Spline.is_catmull(this.type) || this.type === -1) {
|
||||
if (this.points.length >= 2)
|
||||
idx = cmd(59, pos, this.points, 400);
|
||||
if (this.cpoints.length >= 2)
|
||||
idx = cmd(59, pos, this.cpoints, 400);
|
||||
|
||||
if (idx === this.points.length)
|
||||
this.points.push(pos);
|
||||
if (idx === this.cpoints.length)
|
||||
this.cpoints.push(pos);
|
||||
else
|
||||
this.points.splice(idx, 0, pos);
|
||||
this.cpoints.splice(idx, 0, pos);
|
||||
}
|
||||
|
||||
if (Spline.is_bezier(this.type)) {
|
||||
idx = cmd(59, pos, Spline.bezier_nodes(this.points),400);
|
||||
idx = cmd(59, pos, Spline.bezier_nodes(this.cpoints),400);
|
||||
|
||||
if (idx < 0) return;
|
||||
|
||||
if (idx === 0) {
|
||||
this.points.unshift(pos.slice(), pos.add([-100,0]), Vector.reflect_point(this.points[1], this.points[0]));
|
||||
this.cpoints.unshift(pos.slice(), pos.add([-100,0]), Vector.reflect_point(this.cpoints[1], this.cpoints[0]));
|
||||
return;
|
||||
}
|
||||
if (idx === Spline.bezier_node_count(this.points)) {
|
||||
this.points.push(Vector.reflect_point(this.points.at(-2), this.points.at(-1)), pos.add([-100,0]), pos.slice());
|
||||
if (idx === Spline.bezier_node_count(this.cpoints)) {
|
||||
this.cpoints.push(Vector.reflect_point(this.cpoints.at(-2), this.cpoints.at(-1)), pos.add([-100,0]), pos.slice());
|
||||
return;
|
||||
}
|
||||
idx = 2 + (idx-1)*3;
|
||||
var adds = [pos.add([100,0]), pos.slice(), pos.add([-100,0])];
|
||||
this.points.splice(idx, 0, ...adds);
|
||||
this.cpoints.splice(idx, 0, ...adds);
|
||||
}
|
||||
},
|
||||
|
||||
pick_all() {
|
||||
var picks = [];
|
||||
this.points.forEach(x =>picks.push(make_point_obj(this,x)));
|
||||
this.cpoints.forEach(x =>picks.push(make_point_obj(this,x)));
|
||||
return picks;
|
||||
},
|
||||
});
|
||||
|
||||
component.edge2d.impl = Object.mix(collider2d.impl, {
|
||||
component.edge2d.impl = Object.mix({
|
||||
set thickness(x) {
|
||||
cmd_edge2d(1,this.id,x);
|
||||
},
|
||||
get thickness() { return cmd(112,this.id); },
|
||||
grow: pointscaler,
|
||||
sync() {
|
||||
var sensor = this.sensor;
|
||||
var points = this.sample();
|
||||
|
@ -674,7 +663,7 @@ component.edge2d.impl = Object.mix(collider2d.impl, {
|
|||
cmd_edge2d(0,this.id,points);
|
||||
this.sensor = sensor;
|
||||
},
|
||||
});
|
||||
}, component.edge2d.impl);
|
||||
|
||||
var bucket = component.edge2d;
|
||||
bucket.spoints.doc = "Returns the controls points after modifiers are applied, such as it being hollow or mirrored on its axises.";
|
||||
|
@ -696,7 +685,7 @@ bucket.inputs['M-v'].doc = "Decrease spline thickness.";
|
|||
bucket.inputs['M-v'].rep = true;
|
||||
|
||||
bucket.inputs['C-y'] = function() {
|
||||
this.points = this.spoints();
|
||||
this.cpoints = this.spoints();
|
||||
this.flipx = false;
|
||||
this.flipy = false;
|
||||
this.hollow = false;
|
||||
|
@ -720,7 +709,7 @@ bucket.inputs.minus = function() { this.angle *= 1.1; };
|
|||
bucket.inputs.minus.doc = "Decrease the number of samples on this spline.";
|
||||
bucket.inputs.minus.rep = true;
|
||||
|
||||
bucket.inputs['C-r'] = function() { this.points = this.points.reverse(); };
|
||||
bucket.inputs['C-r'] = function() { this.cpoints = this.cpoints.reverse(); };
|
||||
bucket.inputs['C-r'].doc = "Reverse the order of the spline's points.";
|
||||
|
||||
bucket.inputs['C-l'] = function() { this.looped = !this.looped};
|
||||
|
@ -729,7 +718,7 @@ bucket.inputs['C-l'].doc = "Toggle spline being looped.";
|
|||
bucket.inputs['C-c'] = function() {
|
||||
switch(this.type) {
|
||||
case Spline.type.bezier:
|
||||
this.points = Spline.bezier2catmull(this.points);
|
||||
this.cpoints = Spline.bezier2catmull(this.cpoints);
|
||||
break;
|
||||
}
|
||||
this.type = Spline.type.catmull;
|
||||
|
@ -740,7 +729,7 @@ bucket.inputs['C-c'].doc = "Set type of spline to catmull-rom.";
|
|||
bucket.inputs['C-b'] = function() {
|
||||
switch(this.type) {
|
||||
case Spline.type.catmull:
|
||||
this.points = Spline.catmull2bezier(Spline.catmull_caps(this.points));
|
||||
this.cpoints = Spline.catmull2bezier(Spline.catmull_caps(this.cpoints));
|
||||
break;
|
||||
}
|
||||
this.type = Spline.type.bezier;
|
||||
|
@ -751,13 +740,13 @@ bucket.inputs['C-o'].doc = "Set spline to linear.";
|
|||
|
||||
bucket.inputs['C-M-lm'] = function() {
|
||||
if (Spline.is_catmull(this.type)) {
|
||||
var idx = Math.grab_from_points(Mouse.worldpos, this.points.map(p => this.gameobject.this2world(p)), 25);
|
||||
var idx = Math.grab_from_points(Mouse.worldpos, this.cpoints.map(p => this.gameobject.this2world(p)), 25);
|
||||
if (idx === -1) return;
|
||||
} else {
|
||||
|
||||
}
|
||||
|
||||
this.points = this.points.newfirst(idx);
|
||||
this.cpoints = this.cpoints.newfirst(idx);
|
||||
};
|
||||
bucket.inputs['C-M-lm'].doc = "Select the given point as the '0' of this spline.";
|
||||
|
||||
|
@ -767,9 +756,9 @@ bucket.inputs['C-lm'].doc = "Add a point to the spline at the mouse position.";
|
|||
bucket.inputs['C-M-lm'] = function() {
|
||||
var idx = -1;
|
||||
if (Spline.is_catmull(this.type))
|
||||
idx = Math.grab_from_points(Mouse.worldpos, this.points.map(p => this.gameobject.this2world(p)), 25);
|
||||
idx = Math.grab_from_points(Mouse.worldpos, this.cpoints.map(p => this.gameobject.this2world(p)), 25);
|
||||
else {
|
||||
var nodes = Spline.bezier_nodes(this.points);
|
||||
var nodes = Spline.bezier_nodes(this.cpoints);
|
||||
idx = Math.grab_from_points(Mouse.worldpos, nodes.map(p => this.gameobject.this2world(p)), 25);
|
||||
idx *= 3;
|
||||
}
|
||||
|
@ -784,11 +773,11 @@ bucket.inputs.lm.released = function(){};
|
|||
bucket.inputs.lb = function() {
|
||||
var np = [];
|
||||
|
||||
this.points.forEach(function(c) {
|
||||
this.cpoints.forEach(function(c) {
|
||||
np.push(Vector.rotate(c, Math.deg2rad(-1)));
|
||||
});
|
||||
|
||||
this.points = np;
|
||||
this.cpoints = np;
|
||||
};
|
||||
bucket.inputs.lb.doc = "Rotate the points CCW.";
|
||||
bucket.inputs.lb.rep = true;
|
||||
|
@ -796,11 +785,11 @@ bucket.inputs.lb.rep = true;
|
|||
bucket.inputs.rb = function() {
|
||||
var np = [];
|
||||
|
||||
this.points.forEach(function(c) {
|
||||
this.cpoints.forEach(function(c) {
|
||||
np.push(Vector.rotate(c, Math.deg2rad(1)));
|
||||
});
|
||||
|
||||
this.points = np;
|
||||
this.cpoints = np;
|
||||
};
|
||||
bucket.inputs.rb.doc = "Rotate the points CW.";
|
||||
bucket.inputs.rb.rep = true;
|
||||
|
@ -831,11 +820,6 @@ component.circle2d.impl = Object.mix({
|
|||
get pos() { return cmd_circle2d(3,this.id); },
|
||||
set pos(x) { cmd_circle2d(1,this.id,x); },
|
||||
|
||||
grow(x) {
|
||||
if (typeof x === 'number') this.scale *= x;
|
||||
else if (typeof x === 'object') this.scale *= x[0];
|
||||
},
|
||||
|
||||
}, collider2d.impl);
|
||||
|
||||
return {component};
|
||||
|
|
|
@ -164,16 +164,18 @@ performance.test.call_fn_n.doc = "Calls fn1 n times, and then fn2.";
|
|||
performance.cpu.doc = `Output the time it takes to do a given function n number of times. Provide 'q' as "ns", "us", or "ms" to output the time taken in the requested resolution.`;
|
||||
|
||||
/* These controls are available during editing, and during play of debug builds */
|
||||
Debug.inputs = {};
|
||||
Debug.inputs.f1 = function () { Debug.draw_phys(!Debug.phys_drawing); };
|
||||
Debug.inputs.f1.doc = "Draw physics debugging aids.";
|
||||
//Debug.inputs.f3 = function() { Debug.draw_bb = !Debug.draw_bb; };
|
||||
//Debug.inputs.f3.doc = "Toggle drawing bounding boxes.";
|
||||
Debug.inputs.f4 = function() {
|
||||
Debug.draw_names = !Debug.draw_names;
|
||||
Debug.draw_gizmos = !Debug.draw_gizmos;
|
||||
var DebugControls = {};
|
||||
DebugControls.toString = function() { return "Debug"; };
|
||||
DebugControls.inputs = {};
|
||||
DebugControls.inputs.f1 = function () { Debug.draw_phys(!Debug.phys_drawing); };
|
||||
DebugControls.inputs.f1.doc = "Draw physics debugging aids.";
|
||||
//DebugControls.inputs.f3 = function() { Debug.draw_bb = !Debug.draw_bb; };
|
||||
//DebugControls.inputs.f3.doc = "Toggle drawing bounding boxes.";
|
||||
DebugControls.inputs.f4 = function() {
|
||||
// Debug.draw_names = !Debug.draw_names;
|
||||
// Debug.draw_gizmos = !Debug.draw_gizmos;
|
||||
};
|
||||
Debug.inputs.f4.doc = "Toggle drawing gizmos and names of objects.";
|
||||
DebugControls.inputs.f4.doc = "Toggle drawing gizmos and names of objects.";
|
||||
|
||||
Debug.Options.gif = {
|
||||
w: 640, /* Max width */
|
||||
|
@ -213,26 +215,26 @@ Debug.Options.gif = {
|
|||
},
|
||||
};
|
||||
|
||||
Debug.inputs.f8 = function() {
|
||||
DebugControls.inputs.f8 = function() {
|
||||
var now = new Date();
|
||||
Debug.Options.gif.file = now.toISOString() + ".gif";
|
||||
Debug.Options.gif.start();
|
||||
};
|
||||
Debug.inputs.f9 = function() {
|
||||
DebugControls.inputs.f9 = function() {
|
||||
Debug.Options.gif.stop();
|
||||
}
|
||||
|
||||
Debug.inputs.f10 = function() { Time.timescale = 0.1; };
|
||||
Debug.inputs.f10.doc = "Toggle timescale to 1/10.";
|
||||
Debug.inputs.f10.released = function () { Time.timescale = 1.0; };
|
||||
Debug.inputs.f12 = function() { GUI.defaults.debug = !GUI.defaults.debug; console.warn("GUI toggle debug");};
|
||||
Debug.inputs.f12.doc = "Toggle drawing GUI debugging aids.";
|
||||
DebugControls.inputs.f10 = function() { Time.timescale = 0.1; };
|
||||
DebugControls.inputs.f10.doc = "Toggle timescale to 1/10.";
|
||||
DebugControls.inputs.f10.released = function () { Time.timescale = 1.0; };
|
||||
DebugControls.inputs.f12 = function() { GUI.defaults.debug = !GUI.defaults.debug; console.warn("GUI toggle debug");};
|
||||
DebugControls.inputs.f12.doc = "Toggle drawing GUI debugging aids.";
|
||||
|
||||
Debug.inputs['M-1'] = render.normal;
|
||||
Debug.inputs['M-2'] = render.wireframe;
|
||||
DebugControls.inputs['M-1'] = render.normal;
|
||||
DebugControls.inputs['M-2'] = render.wireframe;
|
||||
|
||||
Debug.inputs['C-M-f'] = function() {};
|
||||
Debug.inputs['C-M-f'].doc = "Enter camera fly mode.";
|
||||
DebugControls.inputs['C-M-f'] = function() {};
|
||||
DebugControls.inputs['C-M-f'].doc = "Enter camera fly mode.";
|
||||
|
||||
var Time = {
|
||||
set timescale(x) { cmd(3, x); },
|
||||
|
@ -274,6 +276,9 @@ Time.doc.time = "Seconds elapsed since the game started.";
|
|||
Time.doc.pause = "Pause the game by setting the timescale to 0; remembers the current timescale on play.";
|
||||
Time.doc.play = "Resume the game after using Time.pause.";
|
||||
|
||||
player[0].control(DebugControls);
|
||||
Register.gui.register(Debug.draw, Debug);
|
||||
|
||||
Debug.api = {};
|
||||
Debug.api.doc_entry = function(obj, key)
|
||||
{
|
||||
|
|
|
@ -3,13 +3,6 @@
|
|||
selectable
|
||||
*/
|
||||
|
||||
global.mixin("config.js");
|
||||
Window.aspect(Window.mode.full);
|
||||
Game.loadurs();
|
||||
|
||||
player[0].control(Debug);
|
||||
Register.gui.register(Debug.draw, Debug);
|
||||
|
||||
var editor = {
|
||||
toString() { return "editor"; },
|
||||
grid_size: 100,
|
||||
|
@ -212,7 +205,7 @@ var editor = {
|
|||
player[0].control(limited_editor);
|
||||
editor.cbs.forEach(cb=>cb());
|
||||
editor.cbs = [];
|
||||
actor.spawn("game.js");
|
||||
global.mixin("game.js");
|
||||
},
|
||||
|
||||
cbs: [],
|
||||
|
@ -378,7 +371,7 @@ var editor = {
|
|||
x.gizmo();
|
||||
});
|
||||
|
||||
render.line(bbox.topoints(bbox.fromcwh([0,0],[Game.width,Game.height])).wrapped(1), Color.green);
|
||||
render.line(bbox.topoints(bbox.fromcwh([0,0],[Game.native.x,Game.native.y])).wrapped(1), Color.yellow);
|
||||
|
||||
/* Draw selection box */
|
||||
if (this.sel_start) {
|
||||
|
@ -400,7 +393,7 @@ var editor = {
|
|||
gui() {
|
||||
/* Clean out killed objects */
|
||||
this.selectlist = this.selectlist.filter(function(x) { return x.alive; });
|
||||
GUI.text([0,0], Window.world2screen([0,0]));
|
||||
Debug.coordinate(Window.world2screen([0,0]));
|
||||
|
||||
GUI.text("WORKING LAYER: " + this.working_layer, [0,520]);
|
||||
GUI.text("MODE: " + this.edit_mode, [0,500]);
|
||||
|
@ -487,7 +480,7 @@ var editor = {
|
|||
|
||||
editor.edit_level.objects.forEach(function(obj) {
|
||||
if (!obj._ed.selectable)
|
||||
GUI.text("lock", obj,screenpos());
|
||||
GUI.image("icons/icons8-lock-16.png", obj.screenpos());
|
||||
});
|
||||
|
||||
Debug.draw_grid(1, editor.grid_size, Color.Editor.grid.alpha(0.3));
|
||||
|
@ -625,23 +618,6 @@ editor.new_from_img = function(path)
|
|||
}
|
||||
|
||||
editor.inputs = {};
|
||||
editor.inputs['C-b'] = function() {
|
||||
if (this.selectlist.length !== 1) {
|
||||
console.warn(`Can only bake a single object at a time.`);
|
||||
return;
|
||||
}
|
||||
|
||||
var obj = this.selectlist[0];
|
||||
|
||||
obj.components.forEach(function(c) {
|
||||
if (typeof c.grow !== 'function') return;
|
||||
|
||||
c.grow(obj.scale);
|
||||
c.sync?.();
|
||||
});
|
||||
obj.scale = [1,1,1];
|
||||
}
|
||||
|
||||
editor.inputs.drop = function(str) {
|
||||
str = str.slice(os.cwd().length+1);
|
||||
if (!Resources.is_image(str)) {
|
||||
|
|
|
@ -29,38 +29,6 @@ function eval_env(script, env, file)
|
|||
return cmd(123,script,env,file);
|
||||
}
|
||||
|
||||
global.check_registers = function(obj)
|
||||
{
|
||||
if (typeof obj.update === 'function')
|
||||
obj.timers.push(Register.update.register(obj.update.bind(obj)));
|
||||
|
||||
if (typeof obj.physupdate === 'function')
|
||||
obj.timers.push(Register.physupdate.register(obj.physupdate.bind(obj)));
|
||||
|
||||
if (typeof obj.collide === 'function')
|
||||
register_collide(0, obj.collide.bind(obj), obj.body);
|
||||
|
||||
if (typeof obj.separate === 'function')
|
||||
register_collide(3,obj.separate.bind(obj), obj.body);
|
||||
|
||||
if (typeof obj.draw === 'function')
|
||||
obj.timers.push(Register.draw.register(obj.draw.bind(obj), obj));
|
||||
|
||||
if (typeof obj.debug === 'function')
|
||||
obj.timers.push(Register.debug.register(obj.debug.bind(obj)));
|
||||
|
||||
if (typeof obj.gui === 'function')
|
||||
obj.timers.push(Register.gui.register(obj.gui.bind(obj)));
|
||||
|
||||
for (var k in obj) {
|
||||
if (!k.startswith("on_")) continue;
|
||||
var signal = k.fromfirst("on_");
|
||||
Event.observe(signal, obj, obj[k]);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
eval_env.dov = `Counterpart to /load_env/, but with a string.`;
|
||||
|
||||
function feval_env(file, env)
|
||||
|
@ -91,6 +59,8 @@ global.Game = {
|
|||
cmd(257, fn);
|
||||
},
|
||||
|
||||
native: render.device.pc,
|
||||
|
||||
object_count() {
|
||||
return cmd(214);
|
||||
},
|
||||
|
@ -142,12 +112,6 @@ global.Game = {
|
|||
|
||||
this.wait_fns = [];
|
||||
},
|
||||
|
||||
set width(w) { cmd(125, w); },
|
||||
set height(h) { cmd(126, h); },
|
||||
get width() { return cmd(48); },
|
||||
get height() { return cmd(49); },
|
||||
dimensions() { return [this.width,this.height]; },
|
||||
};
|
||||
|
||||
Game.gc = function() { cmd(259); }
|
||||
|
@ -376,22 +340,13 @@ var Event = {
|
|||
},
|
||||
};
|
||||
|
||||
// Window
|
||||
|
||||
var Window = {
|
||||
fullscreen(f) { cmd(145, f); },
|
||||
dimensions() { return cmd(265); },
|
||||
get width() { return this.dimensions().x; },
|
||||
get height() { return this.dimensions().y; },
|
||||
mode: {
|
||||
stretch: 0,
|
||||
keep: 1,
|
||||
width: 2,
|
||||
height: 3,
|
||||
expand: 4,
|
||||
full: 5
|
||||
},
|
||||
aspect(x) { cmd(264, x); },
|
||||
set width(w) { cmd(125, w); },
|
||||
set height(h) { cmd(126, h); },
|
||||
get width() { return cmd(48); },
|
||||
get height() { return cmd(49); },
|
||||
get dimensions() { return [this.width, this.height]; },
|
||||
title(str) { cmd(134, str); },
|
||||
boundingbox() {
|
||||
return {
|
||||
|
@ -403,16 +358,12 @@ var Window = {
|
|||
},
|
||||
};
|
||||
|
||||
Game.width = 1920;
|
||||
Game.height = 1080;
|
||||
|
||||
Window.screen2world = function(screenpos) {
|
||||
if (Game.camera)
|
||||
return Game.camera.view2world(screenpos);
|
||||
|
||||
return screenpos;
|
||||
}
|
||||
|
||||
Window.world2screen = function(worldpos) {
|
||||
return Game.camera.world2view(worldpos);
|
||||
}
|
||||
|
@ -424,6 +375,7 @@ global.mixin("scripts/debug.js");
|
|||
global.mixin("scripts/spline.js");
|
||||
global.mixin("scripts/components.js");
|
||||
|
||||
|
||||
Window.doc = {};
|
||||
Window.doc.width = "Width of the game window.";
|
||||
Window.doc.height = "Height of the game window.";
|
||||
|
@ -468,3 +420,5 @@ Game.view_camera = function(cam)
|
|||
}
|
||||
|
||||
Window.title(`Prosperon v${prosperon.version}`);
|
||||
Window.width = 1280;
|
||||
Window.height = 720;
|
||||
|
|
|
@ -11,6 +11,40 @@ function obj_unique_name(name, obj)
|
|||
return n;
|
||||
}
|
||||
|
||||
function check_registers(obj)
|
||||
{
|
||||
if (typeof obj.update === 'function')
|
||||
obj.timers.push(Register.update.register(obj.update.bind(obj)));
|
||||
|
||||
if (typeof obj.physupdate === 'function')
|
||||
obj.timers.push(Register.physupdate.register(obj.physupdate.bind(obj)));
|
||||
|
||||
if (typeof obj.collide === 'function')
|
||||
register_collide(0, obj.collide.bind(obj), obj.body);
|
||||
|
||||
if (typeof obj.separate === 'function')
|
||||
register_collide(3,obj.separate.bind(obj), obj.body);
|
||||
|
||||
if (typeof obj.draw === 'function')
|
||||
obj.timers.push(Register.draw.register(obj.draw.bind(obj), obj));
|
||||
|
||||
if (typeof obj.debug === 'function')
|
||||
obj.timers.push(Register.debug.register(obj.debug.bind(obj)));
|
||||
|
||||
if (typeof obj.gui === 'function')
|
||||
obj.timers.push(Register.gui.register(obj.gui.bind(obj)));
|
||||
|
||||
for (var k in obj) {
|
||||
if (!k.startswith("on_")) continue;
|
||||
var signal = k.fromfirst("on_");
|
||||
Event.observe(signal, obj, obj[k]);
|
||||
};
|
||||
|
||||
obj.components.forEach(function(x) {
|
||||
if (typeof x.collide === 'function')
|
||||
register_collide(1, x.collide.bind(x), obj.body, x.shape);
|
||||
});
|
||||
}
|
||||
|
||||
var gameobject_impl = {
|
||||
get pos() {
|
||||
|
@ -42,6 +76,11 @@ var gameobject_impl = {
|
|||
get scale() {
|
||||
Debug.assert(this.master, `No master set on ${this.toString()}`);
|
||||
var pscale = [1,1,1];
|
||||
/* if (typeof this.master.scale === 'object')
|
||||
pscale = this.master.scale;
|
||||
else
|
||||
pscale = [1,1,1];
|
||||
*/
|
||||
return this.gscale().map((x,i) => x/(this.master.gscale()[i]*pscale[i]));
|
||||
},
|
||||
|
||||
|
@ -50,11 +89,11 @@ var gameobject_impl = {
|
|||
x = [x,x];
|
||||
|
||||
var pct = this.scale.map((s,i) => x[i]/s);
|
||||
this.grow(pct);
|
||||
this.spread(pct);
|
||||
|
||||
/* TRANSLATE ALL SUB OBJECTS */
|
||||
this.objects.forEach(obj => {
|
||||
obj.grow(pct);
|
||||
obj.spread(pct);
|
||||
obj.pos = obj.pos.map((x,i)=>x*pct[i]);
|
||||
});
|
||||
},
|
||||
|
@ -339,11 +378,6 @@ var gameobject = {
|
|||
};
|
||||
|
||||
check_registers(ent);
|
||||
ent.components.forEach(function(x) {
|
||||
if (typeof x.collide === 'function')
|
||||
register_collide(1, x.collide.bind(x), ent.body, x.shape);
|
||||
});
|
||||
|
||||
|
||||
if (typeof ent.load === 'function') ent.load();
|
||||
if (Game.playing())
|
||||
|
@ -443,7 +477,7 @@ var gameobject = {
|
|||
/* Moving, rotating, scaling functions, world relative */
|
||||
move(vec) { this.set_worldpos(this.worldpos().add(vec)); },
|
||||
rotate(x) { this.sworldangle(this.worldangle()+x); },
|
||||
grow(vec) { this.sgscale(this.gscale().map((x,i)=>x*vec[i])); },
|
||||
spread(vec) { this.sgscale(this.gscale().map((x,i)=>x*vec[i])); },
|
||||
|
||||
/* Make a unique object the same as its prototype */
|
||||
revert() {
|
||||
|
@ -475,8 +509,8 @@ var gameobject = {
|
|||
disable() { this.components.forEach(function(x) { x.disable(); });},
|
||||
enable() { this.components.forEach(function(x) { x.enable(); });},
|
||||
sync() {
|
||||
this.components.forEach(function(x) { x.sync?.(); });
|
||||
this.objects.forEach(function(x) { x.sync?.(); });
|
||||
this.components.forEach(function(x) { x.sync(); });
|
||||
this.objects.forEach(function(x) { x.sync(); });
|
||||
},
|
||||
|
||||
/* Bounding box of the object in world dimensions */
|
||||
|
@ -715,7 +749,38 @@ gameobject.doc = {
|
|||
warp_layer: 'Bitmask for selecting what warps should affect this entity.',
|
||||
};
|
||||
|
||||
global.ur = {};
|
||||
var resavi = function(ur, path)
|
||||
{
|
||||
if (!ur) return path;
|
||||
if (path[0] === '/') return path;
|
||||
|
||||
var res = ur.replaceAll('.', '/');
|
||||
var dir = path.dir();
|
||||
if (res.startsWith(dir))
|
||||
return path.base();
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
var resani = function(ur, path)
|
||||
{
|
||||
if (!path) return "";
|
||||
if (!ur) return path;
|
||||
if (path[0] === '/') return path.slice(1);
|
||||
|
||||
var res = ur.replaceAll('.', '/');
|
||||
var restry = res + "/" + path;
|
||||
while (!io.exists(restry)) {
|
||||
res = res.updir() + "/";
|
||||
if (res === "/")
|
||||
return path;
|
||||
|
||||
restry = res + path;
|
||||
}
|
||||
return restry;
|
||||
}
|
||||
|
||||
var ur;
|
||||
|
||||
if (io.exists(".prosperon/ur.json"))
|
||||
ur = json.decode(io.slurp(".prosperon/ur.json"));
|
||||
|
@ -795,9 +860,6 @@ function file2fqn(file)
|
|||
return ur[fqn];
|
||||
}
|
||||
|
||||
Game.loadurs = function() {
|
||||
ur = {};
|
||||
ur._list = [];
|
||||
/* FIND ALL URS IN A PROJECT */
|
||||
for (var file of io.glob("**.jso")) {
|
||||
if (file[0] === '.' || file[0] === '_') continue;
|
||||
|
@ -811,11 +873,13 @@ Game.loadurs = function() {
|
|||
topur.data = file;
|
||||
}
|
||||
|
||||
io.slurpwrite(".prosperon/ur.json", json.encode(ur));
|
||||
|
||||
ur.empty = {
|
||||
name: "empty"
|
||||
};
|
||||
};
|
||||
|
||||
return {
|
||||
gameobject
|
||||
gameobject,
|
||||
ur
|
||||
}
|
||||
|
|
|
@ -65,5 +65,3 @@ shape.circle.points = function(radius, n) {
|
|||
if (n <= 1) return [];
|
||||
return shape.arc(radius, 360, n);
|
||||
};
|
||||
|
||||
return {shape};
|
||||
|
|
|
@ -37,7 +37,7 @@ var GUI = {
|
|||
image(path,pos,color) {
|
||||
color ??= Color.black;
|
||||
var wh = cmd(64,path);
|
||||
gui_img(path,pos, [1.0,1.0], 0.0, false, [0.0,0.0], Color.white);
|
||||
gui_img(path,pos, [1.0,1.0], 0.0, 0.0, [0.0,0.0], 0.0, Color.black);
|
||||
return bbox.fromcwh([0,0], wh);
|
||||
},
|
||||
|
||||
|
@ -105,7 +105,7 @@ GUI.controls.check_submit = function() {
|
|||
var Mum = {
|
||||
padding:[0,0], /* Each element inset with this padding on all sides */
|
||||
offset:[0,0],
|
||||
font: "fonts/c64.ttf",
|
||||
font: "fonts/LessPerfectDOSVGA.ttf",
|
||||
selectable: false,
|
||||
selected: false,
|
||||
font_size: 1,
|
||||
|
|
14
scripts/nogame.js
Normal file
|
@ -0,0 +1,14 @@
|
|||
function nogamegui()
|
||||
{
|
||||
GUI.column({
|
||||
items: [
|
||||
GUI.text_fn("NO GAME LOADED", {font_size: 6}),
|
||||
GUI.text_fn("No game.js available.")
|
||||
],
|
||||
anchor: [0.5,0.5],
|
||||
|
||||
}).draw(Window.dimensions.scale(0.5));
|
||||
}
|
||||
|
||||
Register.gui.register(nogamegui);
|
||||
|
6
scripts/play.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
Game.play();
|
||||
|
||||
if (!io.exists("game.js"))
|
||||
load("scripts/nogame.js");
|
||||
else
|
||||
load("game.js");
|
|
@ -77,7 +77,7 @@ Resources.replpath = function(str, path)
|
|||
while (stem) {
|
||||
var tr = stem + "/" +str;
|
||||
if (io.exists(tr)) return tr;
|
||||
stem = stem.updir();
|
||||
stem = steam.updir();
|
||||
}
|
||||
|
||||
return str;
|
||||
|
@ -219,7 +219,6 @@ io.slurpbytes = function(path)
|
|||
|
||||
io.mkpath = function(dir)
|
||||
{
|
||||
if (!dir) return;
|
||||
var mkstack = [];
|
||||
while (!io.exists(dir)) {
|
||||
mkstack.push(dir.fromlast('/'));
|
||||
|
@ -267,15 +266,14 @@ io.mixin({
|
|||
},
|
||||
|
||||
glob(pat) {
|
||||
var paths = io.ls('.');
|
||||
var paths = io.ls();
|
||||
pat = pat.replaceAll(/([\[\]\(\)\^\$\.\|\+])/g, "\\$1");
|
||||
pat = pat.replaceAll('**', '.*');
|
||||
pat = pat.replaceAll(/[^\.]\*/g, '[^\\/]*');
|
||||
pat = pat.replaceAll('?', '.');
|
||||
|
||||
var regex = new RegExp("^"+pat+"$", "");
|
||||
paths = paths.filter(str => str.match(regex)).sort();
|
||||
return paths;
|
||||
return paths.filter(str => str.match(regex));
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -345,15 +343,10 @@ Cmdline.register_order("init", function() {
|
|||
}, "Turn the directory into a Prosperon game.");
|
||||
|
||||
Cmdline.register_order("debug", function() {
|
||||
Cmdline.orders.play([]);
|
||||
Cmdline.orders.play();
|
||||
}, "Play the game with debugging enabled.");
|
||||
|
||||
Cmdline.register_order("play", function(argv) {
|
||||
if (argv[0])
|
||||
io.chdir(argv[0]);
|
||||
|
||||
Game.loadurs();
|
||||
|
||||
Cmdline.register_order("play", function() {
|
||||
if (!io.exists(projectfile)) {
|
||||
say("No game to play. Try making one with 'prosperon init'.");
|
||||
return;
|
||||
|
@ -361,13 +354,12 @@ Cmdline.register_order("play", function(argv) {
|
|||
|
||||
var project = json.decode(io.slurp(projectfile));
|
||||
Game.title = project.title;
|
||||
Window.aspect(Window.mode.expand);
|
||||
global.mixin("config.js");
|
||||
if (project.title) Window.title(project.title);
|
||||
|
||||
Game.engine_start(function() {
|
||||
global.mixin("scripts/sound.js");
|
||||
global.game = actor.spawn("game.js");
|
||||
global.mixin("game.js");
|
||||
if (project.icon) Window.icon(project.icon);
|
||||
});
|
||||
}, "Play the game present in this folder.");
|
||||
|
@ -424,7 +416,6 @@ Cmdline.register_order("about", function(argv) {
|
|||
}, "Get information about this game.");
|
||||
|
||||
Cmdline.register_order("ur", function(argv) {
|
||||
Game.loadurs();
|
||||
for (var i of ur._list.sort()) say(i);
|
||||
}, "Get information about the ur types in your game.");
|
||||
|
||||
|
|
|
@ -553,8 +553,8 @@ void draw_grid(float width, float span, struct rgba color)
|
|||
float ubo[4];
|
||||
ubo[0] = offset.x;
|
||||
ubo[1] = offset.y;
|
||||
ubo[2] = mainwin.width;
|
||||
ubo[3] = mainwin.height;
|
||||
ubo[2] = mainwin.rwidth;
|
||||
ubo[3] = mainwin.rheight;
|
||||
|
||||
sg_apply_pipeline(grid_pipe);
|
||||
sg_apply_bindings(&grid_bind);
|
||||
|
|
|
@ -84,7 +84,7 @@ void font_init() {
|
|||
.label = "text buffer"
|
||||
});
|
||||
|
||||
font_set("fonts/c64.ttf");
|
||||
font_set("fonts/LessPerfectDOSVGA.ttf");
|
||||
bind_text.fs.images[0] = font->texID;
|
||||
bind_text.fs.samplers[0] = sg_make_sampler(&(sg_sampler_desc){});
|
||||
}
|
||||
|
@ -100,7 +100,7 @@ void font_set(const char *path)
|
|||
return;
|
||||
}
|
||||
|
||||
struct sFont *newfont = MakeFont(path, 8);
|
||||
struct sFont *newfont = MakeFont(path, 16);
|
||||
if (!newfont) {
|
||||
YughError("Could not make font from %s.", path);
|
||||
return;
|
||||
|
@ -253,19 +253,22 @@ void sdrawCharacter(struct Character c, HMM_Vec2 cursor, float scale, struct rgb
|
|||
|
||||
float lsize = 1.0 / 1024.0;
|
||||
|
||||
vert.pos.x = cursor.X + c.Bearing[0] * scale;
|
||||
vert.pos.y = cursor.Y - c.Bearing[1] * scale;
|
||||
vert.wh.x = c.Size[0] * scale;
|
||||
vert.wh.y = c.Size[1] * scale;
|
||||
float oline = 1.0;
|
||||
|
||||
vert.pos.x = cursor.X + c.Bearing[0] * scale + oline;
|
||||
vert.pos.y = cursor.Y - c.Bearing[1] * scale - oline;
|
||||
vert.wh.x = c.Size[0] * scale + (oline*2);
|
||||
vert.wh.y = c.Size[1] * scale + (oline*2);
|
||||
|
||||
// if (vert.pos.x > frame.l || vert.pos.y > frame.t || (vert.pos.y + vert.wh.y) < frame.b || (vert.pos.x + vert.wh.x) < frame.l) return;
|
||||
|
||||
vert.uv.u = c.rect.s0*USHRT_MAX;
|
||||
vert.uv.v = c.rect.t0*USHRT_MAX;
|
||||
vert.st.u = (c.rect.s1-c.rect.s0)*USHRT_MAX;
|
||||
vert.st.v = (c.rect.t1-c.rect.t0)*USHRT_MAX;
|
||||
vert.uv.u = (c.rect.s0 - oline*lsize)*USHRT_MAX;
|
||||
vert.uv.v = (c.rect.t0 - oline*lsize)*USHRT_MAX;
|
||||
vert.st.u = (c.rect.s1-c.rect.s0+oline*lsize*2.0)*USHRT_MAX;
|
||||
vert.st.v = (c.rect.t1-c.rect.t0+oline*lsize*2.0)*USHRT_MAX;
|
||||
vert.color = color;
|
||||
|
||||
// sg_append_buffer(bind_text.vertex_buffers[0], &vert, sizeof(struct text_vert));
|
||||
memcpy(text_buffer + curchar, &vert, sizeof(struct text_vert));
|
||||
curchar++;
|
||||
}
|
||||
|
@ -398,9 +401,7 @@ int renderText(const char *text, HMM_Vec2 pos, float scale, struct rgba color, f
|
|||
if (*wordstart == '\e')
|
||||
wordstart = esc_color(wordstart, &usecolor, color);
|
||||
|
||||
sdrawCharacter(font->Characters[*wordstart], HMM_AddV2(cursor, HMM_MulV2F((HMM_Vec2){1,-1},scale)), scale, (rgba){0,0,0,255});
|
||||
sdrawCharacter(font->Characters[*wordstart], cursor, scale, usecolor);
|
||||
|
||||
cursor.X += font->Characters[*wordstart].Advance * tracking * scale;
|
||||
wordstart++;
|
||||
check_caret(caret, wordstart-drawstart, cursor, scale, usecolor);
|
||||
|
|
|
@ -865,11 +865,11 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
|
|||
break;
|
||||
|
||||
case 48:
|
||||
ret = JS_NewInt64(js, mainwin.rwidth);
|
||||
ret = JS_NewInt64(js, mainwin.width);
|
||||
break;
|
||||
|
||||
case 49:
|
||||
ret = JS_NewInt64(js, mainwin.rheight);
|
||||
ret = JS_NewInt64(js, mainwin.height);
|
||||
break;
|
||||
|
||||
case 50:
|
||||
|
@ -1103,11 +1103,11 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
|
|||
break;
|
||||
|
||||
case 125:
|
||||
mainwin.rwidth = js2int(argv[1]);
|
||||
mainwin.width = js2int(argv[1]);
|
||||
break;
|
||||
|
||||
case 126:
|
||||
mainwin.rheight = js2int(argv[1]);
|
||||
mainwin.height = js2int(argv[1]);
|
||||
break;
|
||||
|
||||
case 127:
|
||||
|
@ -1456,12 +1456,6 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
|
|||
str = js2str(argv[1]);
|
||||
font_set(str);
|
||||
break;
|
||||
case 264:
|
||||
aspect_mode = js2int(argv[1]);
|
||||
break;
|
||||
case 265:
|
||||
ret = vec2js((HMM_Vec2){mainwin.width, mainwin.height});
|
||||
break;
|
||||
}
|
||||
|
||||
if (str) JS_FreeCString(js, str);
|
||||
|
@ -1878,14 +1872,14 @@ GETSET_PAIR(emitter, persist, number)
|
|||
GETSET_PAIR(emitter, persist_var, number)
|
||||
GETSET_PAIR(emitter, warp_mask, bitmask)
|
||||
|
||||
JSValue js_emitter_start (JSContext *js, JSValue this, int argc, JSValue *argv)
|
||||
JSValue js_emitter_start (JSContext *js, JSValue this)
|
||||
{
|
||||
emitter *n = js2emitter(this);
|
||||
start_emitter(n);
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
JSValue js_emitter_stop(JSContext *js, JSValue this, int argc, JSValue *argv)
|
||||
JSValue js_emitter_stop(JSContext *js, JSValue this)
|
||||
{
|
||||
emitter *n = js2emitter(this);
|
||||
stop_emitter(n);
|
||||
|
@ -1899,15 +1893,10 @@ JSValue js_emitter_emit(JSContext *js, JSValueConst this, int argc, JSValue *arg
|
|||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
JSValue js_os_cwd(JSContext *js, JSValueConst this, int argc, JSValue *argv)
|
||||
JSValue js_os_cwd(JSContext *js, JSValueConst this)
|
||||
{
|
||||
char cwd[PATH_MAX];
|
||||
#ifndef __EMSCRIPTEN__
|
||||
getcwd(cwd, sizeof(cwd));
|
||||
#else
|
||||
cwd[0] = '.';
|
||||
cwd[1] = 0;
|
||||
#endif
|
||||
return str2js(cwd);
|
||||
}
|
||||
|
||||
|
@ -1920,7 +1909,7 @@ JSValue js_os_env(JSContext *js, JSValueConst this, int argc, JSValue *argv)
|
|||
return ret;
|
||||
}
|
||||
|
||||
JSValue js_os_sys(JSContext *js, JSValueConst this, int argc, JSValue *argv)
|
||||
JSValue js_os_sys(JSContext *js, JSValueConst this)
|
||||
{
|
||||
#ifdef __linux__
|
||||
return str2js("linux");
|
||||
|
@ -1946,14 +1935,14 @@ JSValue js_io_exists(JSContext *js, JSValueConst this, int argc, JSValue *argv)
|
|||
return ret;
|
||||
}
|
||||
|
||||
JSValue js_io_ls(JSContext *js, JSValueConst this, int argc, JSValue *argv)
|
||||
JSValue js_io_ls(JSContext *js, JSValueConst this)
|
||||
{
|
||||
return strarr2js(ls("."));
|
||||
return strarr2js(ls(","));
|
||||
}
|
||||
|
||||
JSValue js_io_cp(JSContext *js, JSValueConst this, int argc, JSValue *argv)
|
||||
{
|
||||
char *f1, *f2;
|
||||
char *f1, f2;
|
||||
f1 = JS_ToCString(js, argv[0]);
|
||||
f2 = JS_ToCString(js, argv[1]);
|
||||
JSValue ret = int2js(cp(f1,f2));
|
||||
|
@ -1964,7 +1953,7 @@ JSValue js_io_cp(JSContext *js, JSValueConst this, int argc, JSValue *argv)
|
|||
|
||||
JSValue js_io_mv(JSContext *js, JSValueConst this, int argc, JSValue *argv)
|
||||
{
|
||||
char *f1, *f2;
|
||||
char *f1, f2;
|
||||
f1 = JS_ToCString(js, argv[0]);
|
||||
f2 = JS_ToCString(js, argv[1]);
|
||||
JSValue ret = int2js(rename(f1,f2));
|
||||
|
@ -1973,14 +1962,6 @@ JSValue js_io_mv(JSContext *js, JSValueConst this, int argc, JSValue *argv)
|
|||
return ret;
|
||||
}
|
||||
|
||||
JSValue js_io_chdir(JSContext *js, JSValueConst this, int argc, JSValue *argv)
|
||||
{
|
||||
char *path = JS_ToCString(js, argv[0]);
|
||||
JSValue ret = int2js(chdir(path));
|
||||
JS_FreeCString(js,path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
JSValue js_io_rm(JSContext *js, JSValueConst this, int argc, JSValue *argv)
|
||||
{
|
||||
char *file = JS_ToCString(js, argv[0]);
|
||||
|
@ -2055,7 +2036,6 @@ static const JSCFunctionListEntry js_io_funcs[] = {
|
|||
MIST_CFUNC_DEF("cp", 2, js_io_cp),
|
||||
MIST_CFUNC_DEF("mv", 2, js_io_mv),
|
||||
MIST_CFUNC_DEF("rm", 1, js_io_rm),
|
||||
MIST_CFUNC_DEF("chdir", 1, js_io_chdir),
|
||||
MIST_CFUNC_DEF("mkdir", 1, js_io_mkdir),
|
||||
MIST_CFUNC_DEF("chmod", 2, js_io_chmod),
|
||||
MIST_CFUNC_DEF("slurp", 1, js_io_slurp),
|
||||
|
@ -2098,7 +2078,7 @@ JSValue js_dsp_node_plugin(JSContext *js, JSValueConst this, int argc, JSValue *
|
|||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
JSValue js_dsp_node_unplug(JSContext *js, JSValueConst this, int argc, JSValue *argv)
|
||||
JSValue js_dsp_node_unplug(JSContext *js, JSValueConst this)
|
||||
{
|
||||
unplug_node(js2dsp_node(this));
|
||||
return JS_UNDEFINED;
|
||||
|
|
|
@ -75,6 +75,7 @@ void gif_rec_start(int w, int h, int cpf, int bitdepth)
|
|||
.render_target = true,
|
||||
.width = gif.w,
|
||||
.height = gif.h,
|
||||
// .pixel_format = SG_PIXELFORMAT_DEPTH,
|
||||
.label = "gif depth",
|
||||
});
|
||||
|
||||
|
@ -254,6 +255,7 @@ void render_init() {
|
|||
mainwin.height = sapp_height();
|
||||
sg_setup(&(sg_desc){
|
||||
.environment = sglue_environment(),
|
||||
// .mtl_force_managed_storage_mode = 1,
|
||||
.logger = { .func = sg_logging },
|
||||
.buffer_pool_size = 1024
|
||||
});
|
||||
|
@ -318,6 +320,7 @@ void render_init() {
|
|||
.size = sizeof(gif_quad),
|
||||
.data = gif_quad,
|
||||
});
|
||||
// sg_gif.bind.fs.images[0] = crt_post.img;
|
||||
sg_gif.bind.fs.samplers[0] = sg_make_sampler(&(sg_sampler_desc){});
|
||||
|
||||
/*
|
||||
|
@ -362,6 +365,11 @@ void render_init() {
|
|||
|
||||
}
|
||||
|
||||
void render_winsize()
|
||||
{
|
||||
// sg_gif.bind.fs.images[0] = crt_post.img;
|
||||
}
|
||||
|
||||
static cpBody *camera = NULL;
|
||||
void set_cam_body(cpBody *body) { camera = body; }
|
||||
cpVect cam_pos() { return camera ? cpBodyGetPosition(camera) : cpvzero; }
|
||||
|
@ -374,14 +382,14 @@ HMM_Vec2 world2screen(HMM_Vec2 pos)
|
|||
{
|
||||
pos = HMM_SubV2(pos, HMM_V2(cam_pos().x, cam_pos().y));
|
||||
pos = HMM_ScaleV2(pos, 1.0/zoom);
|
||||
pos = HMM_AddV2(pos, HMM_V2(mainwin.width/2.0, mainwin.height/2.0));
|
||||
pos = HMM_AddV2(pos, HMM_V2(mainwin.rwidth/2.0, mainwin.rheight/2.0));
|
||||
return pos;
|
||||
}
|
||||
|
||||
HMM_Vec2 screen2world(HMM_Vec2 pos)
|
||||
{
|
||||
pos = HMM_ScaleV2(pos, 1/mainwin.dpi);
|
||||
pos = HMM_SubV2(pos, HMM_V2(mainwin.width/2.0, mainwin.height/2.0));
|
||||
pos = HMM_SubV2(pos, HMM_V2(mainwin.rwidth/2.0, mainwin.rheight/2.0));
|
||||
pos = HMM_ScaleV2(pos, zoom);
|
||||
pos = HMM_AddV2(pos, HMM_V2(cam_pos().x, cam_pos().y));
|
||||
return pos;
|
||||
|
@ -392,64 +400,18 @@ HMM_Mat4 hudproj = {0.f};
|
|||
|
||||
HMM_Vec3 dirl_pos = {4, 100, 20};
|
||||
|
||||
#define MODE_STRETCH 0
|
||||
#define MODE_KEEP 1
|
||||
#define MODE_WIDTH 2
|
||||
#define MODE_HEIGHT 3
|
||||
#define MODE_EXPAND 4
|
||||
#define MODE_FULL 5
|
||||
|
||||
int aspect_mode = MODE_FULL;
|
||||
|
||||
void full_2d_pass(struct window *window)
|
||||
{
|
||||
float aspect = mainwin.width/mainwin.height;
|
||||
float raspect = mainwin.rwidth/mainwin.rheight;
|
||||
float pwidth = window->width*raspect/aspect;
|
||||
float left = (window->width-pwidth)/2;
|
||||
float pheight = window->height*aspect/raspect;
|
||||
float top = (window->height-pheight)/2;
|
||||
|
||||
float usewidth, useheight;
|
||||
usewidth = window->rwidth;
|
||||
useheight = window->rheight;
|
||||
|
||||
switch(aspect_mode) {
|
||||
case MODE_STRETCH:
|
||||
sg_apply_viewportf(0,0,window->width,window->height,1);
|
||||
break;
|
||||
case MODE_WIDTH:
|
||||
sg_apply_viewportf(0, top, window->width, pheight,1); // keep width
|
||||
break;
|
||||
case MODE_HEIGHT:
|
||||
sg_apply_viewportf(left,0,pwidth, window->height,1); // keep height
|
||||
break;
|
||||
case MODE_KEEP:
|
||||
sg_apply_viewportf(0,0,window->rwidth, window->rheight, 1); // no scaling
|
||||
break;
|
||||
case MODE_EXPAND:
|
||||
if (aspect < raspect)
|
||||
sg_apply_viewportf(0, top, window->width, pheight,1); // keep width
|
||||
else
|
||||
sg_apply_viewportf(left,0,pwidth, window->height,1); // keep height
|
||||
break;
|
||||
case MODE_FULL:
|
||||
usewidth = window->width;
|
||||
useheight = window->height;
|
||||
break;
|
||||
}
|
||||
|
||||
// 2D projection
|
||||
//////////// 2D projection
|
||||
cpVect pos = cam_pos();
|
||||
|
||||
projection = HMM_Orthographic_LH_NO(
|
||||
pos.x - zoom * usewidth / 2,
|
||||
pos.x + zoom * usewidth / 2,
|
||||
pos.y - zoom * useheight / 2,
|
||||
pos.y + zoom * useheight / 2, -10000.f, 10000.f);
|
||||
|
||||
hudproj = HMM_Orthographic_LH_ZO(0, usewidth, 0, useheight, -1.f, 1.f);
|
||||
pos.x - zoom * window->rwidth / 2,
|
||||
pos.x + zoom * window->rwidth / 2,
|
||||
pos.y - zoom * window->rheight / 2,
|
||||
pos.y + zoom * window->rheight / 2, -10000.f, 10000.f);
|
||||
|
||||
hudproj = HMM_Orthographic_LH_ZO(0, window->rwidth, 0, window->rheight, -1.f, 1.f);
|
||||
sprite_draw_all();
|
||||
model_draw_all();
|
||||
call_draw();
|
||||
|
@ -496,7 +458,6 @@ void full_3d_pass(struct window *window)
|
|||
}
|
||||
|
||||
void openglRender(struct window *window) {
|
||||
sg_swapchain sch = sglue_swapchain();
|
||||
sg_begin_pass(&(sg_pass){
|
||||
.action = pass_action,
|
||||
.swapchain = sglue_swapchain(),
|
||||
|
|
|
@ -58,7 +58,7 @@ void openglInit3d(struct window *window);
|
|||
void openglRender3d(struct window *window, camera3d *camera);
|
||||
void capture_screen(int x, int y, int w, int h, const char *path);
|
||||
|
||||
extern int aspect_mode;
|
||||
void render_winsize();
|
||||
|
||||
void debug_draw_phys(int draw);
|
||||
|
||||
|
|
|
@ -21,18 +21,10 @@
|
|||
#include <ftw.h>
|
||||
#endif
|
||||
|
||||
#define SOKOL_FETCH_IMPL
|
||||
#include "sokol/sokol_fetch.h"
|
||||
|
||||
#include "stb_ds.h"
|
||||
|
||||
#include "core.cdb.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <direct.h>
|
||||
#define mkdir(x,y) _mkdir(x)
|
||||
#endif
|
||||
|
||||
char **prefabs;
|
||||
|
||||
static const char *cur_ext = NULL;
|
||||
|
@ -43,41 +35,9 @@ char pathbuf[MAXPATH + 1];
|
|||
static struct cdb corecdb;
|
||||
static struct cdb game_cdb;
|
||||
|
||||
extern int LOADED_GAME = 0;
|
||||
uint8_t *gamebuf;
|
||||
|
||||
static void response_cb(const sfetch_response_t *r)
|
||||
{
|
||||
if (r->fetched) {
|
||||
cdb_initf(&game_cdb, r->data.ptr, r->data.size);
|
||||
LOADED_GAME = 1;
|
||||
}
|
||||
if (r->finished) {
|
||||
LOADED_GAME = -1;
|
||||
if (r->failed) {
|
||||
LOADED_GAME = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void resources_init() {
|
||||
sfetch_setup(&(sfetch_desc_t){
|
||||
.max_requests = 1024,
|
||||
.num_channels = 4,
|
||||
.num_lanes = 8,
|
||||
.logger = { .func = sg_logging },
|
||||
});
|
||||
gamebuf = malloc(64*1024*1024);
|
||||
|
||||
sfetch_handle_t h = sfetch_send(&(sfetch_request_t){
|
||||
.path="game.cdb",
|
||||
.callback = response_cb,
|
||||
.buffer = {
|
||||
.ptr = gamebuf,
|
||||
.size = 64*1024*1024
|
||||
}
|
||||
});
|
||||
|
||||
int fd = open("game.cdb", O_RDONLY);
|
||||
cdb_init(&game_cdb, fd);
|
||||
cdb_initf(&corecdb, core_cdb, core_cdb_len);
|
||||
}
|
||||
|
||||
|
@ -146,8 +106,7 @@ char **ls(const char *path)
|
|||
|
||||
arrfree(ls_paths);
|
||||
}
|
||||
|
||||
ftw(path, ls_ftw, 10);
|
||||
ftw(".", ls_ftw, 10);
|
||||
return ls_paths;
|
||||
}
|
||||
|
||||
|
@ -256,43 +215,19 @@ int cp(const char *p1, const char *p2)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int mkpath(char *path, mode_t mode)
|
||||
int mkpath(char *dir, mode_t mode)
|
||||
{
|
||||
char tmp[256];
|
||||
char *p = NULL;
|
||||
size_t len;
|
||||
struct stat sb;
|
||||
|
||||
strncpy(tmp, path, sizeof(tmp));
|
||||
len = strlen(tmp);
|
||||
if (len > 0 && tmp[len - 1] == '/')
|
||||
tmp[len - 1] = 0;
|
||||
|
||||
for (p = tmp + 1; *p; p++) {
|
||||
if (*p == '/') {
|
||||
*p = 0;
|
||||
if (stat(tmp, &sb) != 0) {
|
||||
if (errno != ENOENT || mkdir(tmp, mode) != 0) {
|
||||
return -1;
|
||||
}
|
||||
} else if (!S_ISDIR(sb.st_mode)) {
|
||||
errno = ENOTDIR;
|
||||
return -1;
|
||||
}
|
||||
*p = '/';
|
||||
}
|
||||
}
|
||||
|
||||
if (stat(tmp, &sb) != 0) {
|
||||
if (errno != ENOENT || mkdir(tmp, mode) != 0) {
|
||||
return -1;
|
||||
}
|
||||
} else if (!S_ISDIR(sb.st_mode)) {
|
||||
errno = ENOTDIR;
|
||||
return -1;
|
||||
if (!dir) {
|
||||
errno = EINVAL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (strlen(dir) == 1 && dir[0] == '/')
|
||||
return 0;
|
||||
|
||||
// mkpath(dirname(strdupa(dir)), mode);
|
||||
|
||||
return mkdir(dir, mode);
|
||||
}
|
||||
|
||||
int slurp_write(const char *txt, const char *filename, size_t len) {
|
||||
|
@ -357,5 +292,5 @@ void pack_engine(const char *fname){
|
|||
YughError("Cannot pack engine on a web build.");
|
||||
}
|
||||
|
||||
char **ls(const char *path) { return NULL; }
|
||||
char **ls(char *path) { return NULL; }
|
||||
#endif
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
#include "string.h"
|
||||
|
||||
extern char *DATA_PATH;
|
||||
extern int LOADED_GAME;
|
||||
|
||||
void resources_init();
|
||||
char *get_filename_from_path(char *path, int extension);
|
||||
|
|
|
@ -1,306 +0,0 @@
|
|||
/*
|
||||
sokol_gfx_ext.h - extensions for sokol_gfx
|
||||
https://github.com/edubart/sokol_gp
|
||||
*/
|
||||
|
||||
#if defined(SOKOL_IMPL) && !defined(SOKOL_GFX_EXT_IMPL)
|
||||
#define SOKOL_GFX_EXT_IMPL
|
||||
#endif
|
||||
|
||||
#ifndef SOKOL_GFX_EXT_INCLUDED
|
||||
#define SOKOL_GFX_EXT_INCLUDED
|
||||
|
||||
#ifndef SOKOL_GFX_INCLUDED
|
||||
#error "Please include sokol_gfx.h before sokol_gfx_ext.h"
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
SOKOL_GFX_API_DECL void sg_query_image_pixels(sg_image img_id, sg_sampler smp_id, void* pixels, int size);
|
||||
SOKOL_GFX_API_DECL void sg_query_pixels(int x, int y, int w, int h, bool origin_top_left, void *pixels, int size);
|
||||
|
||||
#endif // SOKOL_GFX_EXT_INCLUDED
|
||||
|
||||
#ifdef SOKOL_GFX_EXT_IMPL
|
||||
#ifndef SOKOL_GFX_EXT_IMPL_INCLUDED
|
||||
#define SOKOL_GFX_EXT_IMPL_INCLUDED
|
||||
|
||||
#ifndef SOKOL_GFX_IMPL_INCLUDED
|
||||
#error "Please include sokol_gfx.h implementation before sokol_gp.h implementation"
|
||||
#endif
|
||||
|
||||
#if defined(_SOKOL_ANY_GL)
|
||||
|
||||
static void _sg_gl_query_image_pixels(_sg_image_t* img, _sg_sampler_t *smp, void* pixels) {
|
||||
SOKOL_ASSERT(img->gl.target == GL_TEXTURE_2D);
|
||||
SOKOL_ASSERT(0 != img->gl.tex[img->cmn.active_slot]);
|
||||
#if defined(SOKOL_GLCORE33)
|
||||
_sg_gl_cache_store_texture_sampler_binding(0);
|
||||
_sg_gl_cache_bind_texture_sampler(0, img->gl.target, img->gl.tex[img->cmn.active_slot], smp->gl.smp);
|
||||
glGetTexImage(img->gl.target, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||
_SG_GL_CHECK_ERROR();
|
||||
_sg_gl_cache_restore_texture_sampler_binding(0);
|
||||
#else
|
||||
static GLuint newFbo = 0;
|
||||
GLuint oldFbo = 0;
|
||||
if(newFbo == 0) {
|
||||
glGenFramebuffers(1, &newFbo);
|
||||
}
|
||||
glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&oldFbo);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, newFbo);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, img->gl.tex[img->cmn.active_slot], 0);
|
||||
glReadPixels(0, 0, img->cmn.width, img->cmn.height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, oldFbo);
|
||||
//glDeleteFramebuffers(1, &newFbo);
|
||||
_SG_GL_CHECK_ERROR();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void _sg_gl_query_pixels(int x, int y, int w, int h, bool origin_top_left, void *pixels) {
|
||||
SOKOL_ASSERT(pixels);
|
||||
GLuint gl_fb;
|
||||
GLint dims[4];
|
||||
glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&gl_fb);
|
||||
_SG_GL_CHECK_ERROR();
|
||||
glGetIntegerv(GL_VIEWPORT, dims);
|
||||
int cur_height = dims[3];
|
||||
y = origin_top_left ? (cur_height - (y+h)) : y;
|
||||
_SG_GL_CHECK_ERROR();
|
||||
#if defined(SOKOL_GLES2) // use NV extension instead
|
||||
glReadBufferNV(gl_fb == 0 ? GL_BACK : GL_COLOR_ATTACHMENT0);
|
||||
#else
|
||||
glReadBuffer(gl_fb == 0 ? GL_BACK : GL_COLOR_ATTACHMENT0);
|
||||
#endif
|
||||
_SG_GL_CHECK_ERROR();
|
||||
glReadPixels(x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||
_SG_GL_CHECK_ERROR();
|
||||
}
|
||||
|
||||
#elif defined(SOKOL_D3D11)
|
||||
|
||||
static inline void _sgext_d3d11_Texture2D_GetDesc(ID3D11Texture2D* self, D3D11_TEXTURE2D_DESC* pDesc) {
|
||||
self->lpVtbl->GetDesc(self, pDesc);
|
||||
}
|
||||
|
||||
static inline void _sgext_d3d11_SamplerState_GetDesc(ID3D11SamplerState* self, D3D11_SAMPLER_DESC* pDesc) {
|
||||
self->lpVtbl->GetDesc(self, pDesc);
|
||||
}
|
||||
|
||||
static inline void _sgext_d3d11_CopySubresourceRegion(ID3D11DeviceContext* self, ID3D11Resource *pDstResource, UINT DstSubresource, UINT DstX, UINT DstY, UINT DstZ, ID3D11Resource *pSrcResource, UINT SrcSubresource, const D3D11_BOX *pSrcBox) {
|
||||
self->lpVtbl->CopySubresourceRegion(self, pDstResource, DstSubresource, DstX, DstY, DstZ, pSrcResource, SrcSubresource, pSrcBox);
|
||||
}
|
||||
|
||||
static inline void _sgext_d3d11_OMGetRenderTargets(ID3D11DeviceContext* self, UINT NumViews, ID3D11RenderTargetView **ppRenderTargetViews, ID3D11DepthStencilView **ppDepthStencilView) {
|
||||
self->lpVtbl->OMGetRenderTargets(self, NumViews, ppRenderTargetViews, ppDepthStencilView);
|
||||
}
|
||||
|
||||
static inline void _sgext_d3d11_RenderTargetView_GetResource(ID3D11RenderTargetView* self, ID3D11Resource** ppResource) {
|
||||
self->lpVtbl->GetResource(self, ppResource);
|
||||
}
|
||||
|
||||
static void _sg_d3d11_query_image_pixels(_sg_image_t* img, void* pixels) {
|
||||
SOKOL_ASSERT(_sg.d3d11.ctx);
|
||||
SOKOL_ASSERT(img->d3d11.tex2d);
|
||||
HRESULT hr;
|
||||
_SOKOL_UNUSED(hr);
|
||||
|
||||
// create staging texture
|
||||
ID3D11Texture2D* staging_tex = NULL;
|
||||
D3D11_TEXTURE2D_DESC staging_desc = {
|
||||
.Width = (UINT)img->cmn.width,
|
||||
.Height = (UINT)img->cmn.height,
|
||||
.MipLevels = 1,
|
||||
.ArraySize = 1,
|
||||
.Format = img->d3d11.format,
|
||||
.SampleDesc = {
|
||||
.Count = 1,
|
||||
.Quality = 0,
|
||||
},
|
||||
.Usage = D3D11_USAGE_STAGING,
|
||||
.BindFlags = 0,
|
||||
.CPUAccessFlags = D3D11_CPU_ACCESS_READ,
|
||||
.MiscFlags = 0
|
||||
};
|
||||
hr = _sg_d3d11_CreateTexture2D(_sg.d3d11.dev, &staging_desc, NULL, &staging_tex);
|
||||
SOKOL_ASSERT(SUCCEEDED(hr));
|
||||
|
||||
// copy pixels to staging texture
|
||||
_sgext_d3d11_CopySubresourceRegion(_sg.d3d11.ctx,
|
||||
(ID3D11Resource*)staging_tex,
|
||||
0, 0, 0, 0,
|
||||
(ID3D11Resource*)img->d3d11.tex2d,
|
||||
0, NULL);
|
||||
|
||||
// map the staging texture's data to CPU-accessible memory
|
||||
D3D11_MAPPED_SUBRESOURCE msr = {.pData = NULL};
|
||||
hr = _sg_d3d11_Map(_sg.d3d11.ctx, (ID3D11Resource*)staging_tex, 0, D3D11_MAP_READ, 0, &msr);
|
||||
SOKOL_ASSERT(SUCCEEDED(hr));
|
||||
memcpy(pixels, msr.pData, img->cmn.width * img->cmn.height * 4);
|
||||
|
||||
// unmap the texture
|
||||
_sg_d3d11_Unmap(_sg.d3d11.ctx, (ID3D11Resource*)staging_tex, 0);
|
||||
|
||||
if(staging_tex) _sg_d3d11_Release(staging_tex);
|
||||
}
|
||||
|
||||
static void _sg_d3d11_query_pixels(int x, int y, int w, int h, bool origin_top_left, void *pixels) {
|
||||
// get current render target
|
||||
ID3D11RenderTargetView* render_target_view = NULL;
|
||||
_sgext_d3d11_OMGetRenderTargets(_sg.d3d11.ctx, 1, &render_target_view, NULL);
|
||||
|
||||
// fallback to window render target
|
||||
if(!render_target_view)
|
||||
render_target_view = (ID3D11RenderTargetView*)_sg.d3d11.cur_pass.render_view;
|
||||
SOKOL_ASSERT(render_target_view);
|
||||
|
||||
// get the back buffer texture
|
||||
ID3D11Texture2D *back_buffer = NULL;
|
||||
_sgext_d3d11_RenderTargetView_GetResource(render_target_view, (ID3D11Resource**)&back_buffer);
|
||||
SOKOL_ASSERT(back_buffer);
|
||||
|
||||
// create a staging texture to copy the screen's data to
|
||||
D3D11_TEXTURE2D_DESC staging_desc;
|
||||
_sgext_d3d11_Texture2D_GetDesc(back_buffer, &staging_desc);
|
||||
staging_desc.Width = w;
|
||||
staging_desc.Height = h;
|
||||
staging_desc.BindFlags = 0;
|
||||
staging_desc.MiscFlags = 0;
|
||||
staging_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
||||
staging_desc.Usage = D3D11_USAGE_STAGING;
|
||||
ID3D11Texture2D *staging_tex = NULL;
|
||||
HRESULT hr = _sg_d3d11_CreateTexture2D(_sg.d3d11.dev, &staging_desc, NULL, &staging_tex);
|
||||
SOKOL_ASSERT(SUCCEEDED(hr));
|
||||
_SOKOL_UNUSED(hr);
|
||||
|
||||
// copy the desired portion of the back buffer to the staging texture
|
||||
// y = (origin_top_left ? y : (_sg.d3d11.cur_height - (y + h)));
|
||||
|
||||
D3D11_BOX src_box = {
|
||||
.left = (UINT)x,
|
||||
.top = (UINT)y,
|
||||
.front = 0,
|
||||
.right = (UINT)(x + w),
|
||||
.bottom = (UINT)(y + w),
|
||||
.back = 1,
|
||||
};
|
||||
_sgext_d3d11_CopySubresourceRegion(_sg.d3d11.ctx,
|
||||
(ID3D11Resource*)staging_tex,
|
||||
0, 0, 0, 0,
|
||||
(ID3D11Resource*)back_buffer,
|
||||
0, &src_box);
|
||||
|
||||
// map the staging texture's data to CPU-accessible memory
|
||||
D3D11_MAPPED_SUBRESOURCE msr = {.pData = NULL};
|
||||
hr = _sg_d3d11_Map(_sg.d3d11.ctx, (ID3D11Resource*)staging_tex, 0, D3D11_MAP_READ, 0, &msr);
|
||||
SOKOL_ASSERT(SUCCEEDED(hr));
|
||||
|
||||
memcpy(pixels, msr.pData, w * h * 4);
|
||||
// unmap the texture
|
||||
_sg_d3d11_Unmap(_sg.d3d11.ctx, (ID3D11Resource*)staging_tex, 0);
|
||||
|
||||
if(back_buffer) _sg_d3d11_Release(back_buffer);
|
||||
if(staging_tex) _sg_d3d11_Release(staging_tex);
|
||||
}
|
||||
|
||||
#elif defined(SOKOL_METAL)
|
||||
|
||||
#ifdef TARGET_OS_IPHONE
|
||||
|
||||
static void _sg_metal_commit_command_buffer(){};
|
||||
static void _sg_metal_encode_texture_pixels(int x, int y, int w, int h, bool origin_top_left, id<MTLTexture> mtl_src_texture, void* pixels) {};
|
||||
static void _sg_metal_query_image_pixels(_sg_image_t* img, void* pixels) {};
|
||||
static void _sg_metal_query_pixels(int x, int y, int w, int h, bool origin_top_left, void *pixels) {};
|
||||
|
||||
#else
|
||||
|
||||
#import <Metal/Metal.h>
|
||||
#import <QuartzCore/CAMetalLayer.h>
|
||||
|
||||
|
||||
static void _sg_metal_commit_command_buffer() {
|
||||
SOKOL_ASSERT(!_sg.mtl.in_pass);
|
||||
if(_sg.mtl.cmd_buffer) {
|
||||
#if defined(_SG_TARGET_MACOS)
|
||||
[_sg.mtl.uniform_buffers[_sg.mtl.cur_frame_rotate_index] didModifyRange:NSMakeRange(0, _sg.mtl.cur_ub_offset)];
|
||||
#endif
|
||||
[_sg.mtl.cmd_buffer commit];
|
||||
[_sg.mtl.cmd_buffer waitUntilCompleted];
|
||||
_sg.mtl.cmd_buffer = [_sg.mtl.cmd_queue commandBufferWithUnretainedReferences];
|
||||
}
|
||||
}
|
||||
|
||||
static void _sg_metal_encode_texture_pixels(int x, int y, int w, int h, bool origin_top_left, id<MTLTexture> mtl_src_texture, void* pixels) {
|
||||
SOKOL_ASSERT(!_sg.mtl.in_pass);
|
||||
_sg_metal_commit_command_buffer();
|
||||
MTLTextureDescriptor* mtl_dst_texture_desc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:mtl_src_texture.pixelFormat width:w height:h mipmapped:NO];
|
||||
mtl_dst_texture_desc.storageMode = MTLStorageModeManaged;
|
||||
mtl_dst_texture_desc.resourceOptions = MTLResourceStorageModeManaged;
|
||||
mtl_dst_texture_desc.usage = MTLTextureUsageShaderRead + MTLTextureUsageShaderWrite;
|
||||
id<MTLTexture> mtl_dst_texture = [mtl_src_texture.device newTextureWithDescriptor:mtl_dst_texture_desc];
|
||||
id<MTLCommandBuffer> cmd_buffer = [_sg.mtl.cmd_queue commandBuffer];
|
||||
id<MTLBlitCommandEncoder> blit_encoder = [cmd_buffer blitCommandEncoder];
|
||||
[blit_encoder copyFromTexture:mtl_src_texture
|
||||
sourceSlice:0
|
||||
sourceLevel:0
|
||||
sourceOrigin:MTLOriginMake(x,(origin_top_left ? y : (mtl_src_texture.height - (y + h))),0)
|
||||
sourceSize:MTLSizeMake(w,h,1)
|
||||
toTexture:mtl_dst_texture
|
||||
destinationSlice:0
|
||||
destinationLevel:0
|
||||
destinationOrigin:MTLOriginMake(0,0,0)
|
||||
];
|
||||
[blit_encoder synchronizeTexture:mtl_dst_texture slice:0 level:0];
|
||||
[blit_encoder endEncoding];
|
||||
[cmd_buffer commit];
|
||||
[cmd_buffer waitUntilCompleted];
|
||||
|
||||
MTLRegion mtl_region = MTLRegionMake2D(0, 0, w, h);
|
||||
[mtl_dst_texture getBytes:pixels bytesPerRow:w * 4 fromRegion:mtl_region mipmapLevel:0];
|
||||
}
|
||||
|
||||
static void _sg_metal_query_image_pixels(_sg_image_t* img, void* pixels) {
|
||||
id<MTLTexture> mtl_src_texture = _sg.mtl.idpool.pool[img->mtl.tex[0]];
|
||||
_sg_metal_encode_texture_pixels(0, 0, mtl_src_texture.width, mtl_src_texture.height, true, mtl_src_texture, pixels);
|
||||
}
|
||||
|
||||
static void _sg_metal_query_pixels(int x, int y, int w, int h, bool origin_top_left, void *pixels) {
|
||||
id<CAMetalDrawable> mtl_drawable = (__bridge id<CAMetalDrawable>)_sg.mtl.drawable_cb();
|
||||
_sg_metal_encode_texture_pixels(x, y, w, h, origin_top_left, mtl_drawable.texture, pixels);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void sg_query_image_pixels(sg_image img_id, sg_sampler smp_id, void* pixels, int size) {
|
||||
SOKOL_ASSERT(pixels);
|
||||
SOKOL_ASSERT(img_id.id != SG_INVALID_ID);
|
||||
_sg_image_t* img = _sg_lookup_image(&_sg.pools, img_id.id);
|
||||
_sg_sampler_t *smp = _sg_lookup_sampler(&_sg.pools, smp_id.id);
|
||||
SOKOL_ASSERT(img);
|
||||
SOKOL_ASSERT(size >= (img->cmn.width * img->cmn.height * 4));
|
||||
_SOKOL_UNUSED(size);
|
||||
#if defined(_SOKOL_ANY_GL)
|
||||
_sg_gl_query_image_pixels(img, smp, pixels);
|
||||
#elif defined(SOKOL_D3D11)
|
||||
_sg_d3d11_query_image_pixels(img, pixels);
|
||||
#elif defined(SOKOL_METAL)
|
||||
_sg_metal_query_image_pixels(img, pixels);
|
||||
#endif
|
||||
}
|
||||
|
||||
void sg_query_pixels(int x, int y, int w, int h, bool origin_top_left, void *pixels, int size) {
|
||||
SOKOL_ASSERT(pixels);
|
||||
SOKOL_ASSERT(size >= w*h);
|
||||
_SOKOL_UNUSED(size);
|
||||
#if defined(_SOKOL_ANY_GL)
|
||||
_sg_gl_query_pixels(x, y, w, h, origin_top_left, pixels);
|
||||
#elif defined(SOKOL_D3D11)
|
||||
_sg_d3d11_query_pixels(x, y, w, h, origin_top_left, pixels);
|
||||
#elif defined(SOKOL_METAL)
|
||||
_sg_metal_query_pixels(x, y, w, h, origin_top_left, pixels);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // SOKOL_GFX_EXT_IMPL_INCLUDED
|
||||
#endif // SOKOL_GFX_EXT_IMPL
|
12374
source/engine/sound/dr_flac.h
Normal file
4785
source/engine/sound/dr_mp3.h
Normal file
8305
source/engine/sound/dr_wav.h
Normal file
|
@ -144,9 +144,14 @@ void sprite_initialize() {
|
|||
[1].format = SG_VERTEXFORMAT_FLOAT2,
|
||||
[2].format = SG_VERTEXFORMAT_UBYTE4N,
|
||||
[3].format = SG_VERTEXFORMAT_UBYTE4N}},
|
||||
// [4].format = SG_VERTEXFORMAT_FLOAT}},
|
||||
.primitive_type = SG_PRIMITIVETYPE_TRIANGLE_STRIP,
|
||||
.label = "sprite pipeline",
|
||||
.colors[0].blend = blend_trans,
|
||||
.depth = {
|
||||
.write_enabled = true,
|
||||
.compare = SG_COMPAREFUNC_LESS_EQUAL,
|
||||
}
|
||||
});
|
||||
|
||||
bind_sprite.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
|
||||
|
@ -235,7 +240,7 @@ void gui_draw_img(const char *img, transform2d t, int wrap, HMM_Vec2 wrapoffset,
|
|||
sg_apply_pipeline(pip_sprite);
|
||||
sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(hudproj));
|
||||
struct Texture *tex = texture_pullfromfile(img);
|
||||
tex_draw(tex, transform2d2mat(t), ST_UNIT, color, wrap, wrapoffset, (HMM_Vec2){wrapscale,wrapscale}, (struct rgba){0,0,0,0}, 0);
|
||||
tex_draw(tex, transform2d2mat(t), tex_get_rect(tex), color, wrap, wrapoffset, (HMM_Vec2){wrapscale,wrapscale}, (struct rgba){0,0,0,0}, 0);
|
||||
}
|
||||
|
||||
void slice9_draw(const char *img, HMM_Vec2 pos, HMM_Vec2 dimensions, struct rgba color)
|
||||
|
@ -244,7 +249,7 @@ void slice9_draw(const char *img, HMM_Vec2 pos, HMM_Vec2 dimensions, struct rgba
|
|||
sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(hudproj));
|
||||
struct Texture *tex = texture_pullfromfile(img);
|
||||
|
||||
struct glrect r = ST_UNIT;
|
||||
struct glrect r = tex_get_rect(tex);
|
||||
|
||||
struct slice9_vert verts[4];
|
||||
|
||||
|
|
|
@ -285,6 +285,8 @@ struct Texture *texture_fromdata(void *raw, long size)
|
|||
|
||||
struct Texture *texture_loadfromfile(const char *path) { return texture_pullfromfile(path); }
|
||||
|
||||
struct glrect tex_get_rect(struct Texture *tex) { return ST_UNIT; }
|
||||
|
||||
HMM_Vec2 tex_get_dimensions(struct Texture *tex) {
|
||||
if (!tex) return (HMM_Vec2){0,0};
|
||||
HMM_Vec2 d;
|
||||
|
|
1
source/engine/thirdparty/TinySoundFont
vendored
|
@ -1 +0,0 @@
|
|||
Subproject commit 92a8f0e9fe3c98358be7d8564db21fc4b1142d04
|
1
source/engine/thirdparty/dr_libs
vendored
|
@ -1 +0,0 @@
|
|||
Subproject commit da35f9d6c7374a95353fd1df1d394d44ab66cf01
|
531
source/engine/tml.h
Normal file
|
@ -0,0 +1,531 @@
|
|||
/* TinyMidiLoader - v0.7 - Minimalistic midi parsing library - https://github.com/schellingb/TinySoundFont
|
||||
no warranty implied; use at your own risk
|
||||
Do this:
|
||||
#define TML_IMPLEMENTATION
|
||||
before you include this file in *one* C or C++ file to create the implementation.
|
||||
// i.e. it should look like this:
|
||||
#include ...
|
||||
#include ...
|
||||
#define TML_IMPLEMENTATION
|
||||
#include "tml.h"
|
||||
|
||||
[OPTIONAL] #define TML_NO_STDIO to remove stdio dependency
|
||||
[OPTIONAL] #define TML_MALLOC, TML_REALLOC, and TML_FREE to avoid stdlib.h
|
||||
[OPTIONAL] #define TML_MEMCPY to avoid string.h
|
||||
|
||||
LICENSE (ZLIB)
|
||||
|
||||
Copyright (C) 2017, 2018, 2020 Bernhard Schelling
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef TML_INCLUDE_TML_INL
|
||||
#define TML_INCLUDE_TML_INL
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Define this if you want the API functions to be static
|
||||
#ifdef TML_STATIC
|
||||
#define TMLDEF static
|
||||
#else
|
||||
#define TMLDEF extern
|
||||
#endif
|
||||
|
||||
// Channel message type
|
||||
enum TMLMessageType
|
||||
{
|
||||
TML_NOTE_OFF = 0x80, TML_NOTE_ON = 0x90, TML_KEY_PRESSURE = 0xA0, TML_CONTROL_CHANGE = 0xB0, TML_PROGRAM_CHANGE = 0xC0, TML_CHANNEL_PRESSURE = 0xD0, TML_PITCH_BEND = 0xE0, TML_SET_TEMPO = 0x51
|
||||
};
|
||||
|
||||
// Midi controller numbers
|
||||
enum TMLController
|
||||
{
|
||||
TML_BANK_SELECT_MSB, TML_MODULATIONWHEEL_MSB, TML_BREATH_MSB, TML_FOOT_MSB = 4, TML_PORTAMENTO_TIME_MSB, TML_DATA_ENTRY_MSB, TML_VOLUME_MSB,
|
||||
TML_BALANCE_MSB, TML_PAN_MSB = 10, TML_EXPRESSION_MSB, TML_EFFECTS1_MSB, TML_EFFECTS2_MSB, TML_GPC1_MSB = 16, TML_GPC2_MSB, TML_GPC3_MSB, TML_GPC4_MSB,
|
||||
TML_BANK_SELECT_LSB = 32, TML_MODULATIONWHEEL_LSB, TML_BREATH_LSB, TML_FOOT_LSB = 36, TML_PORTAMENTO_TIME_LSB, TML_DATA_ENTRY_LSB, TML_VOLUME_LSB,
|
||||
TML_BALANCE_LSB, TML_PAN_LSB = 42, TML_EXPRESSION_LSB, TML_EFFECTS1_LSB, TML_EFFECTS2_LSB, TML_GPC1_LSB = 48, TML_GPC2_LSB, TML_GPC3_LSB, TML_GPC4_LSB,
|
||||
TML_SUSTAIN_SWITCH = 64, TML_PORTAMENTO_SWITCH, TML_SOSTENUTO_SWITCH, TML_SOFT_PEDAL_SWITCH, TML_LEGATO_SWITCH, TML_HOLD2_SWITCH,
|
||||
TML_SOUND_CTRL1, TML_SOUND_CTRL2, TML_SOUND_CTRL3, TML_SOUND_CTRL4, TML_SOUND_CTRL5, TML_SOUND_CTRL6,
|
||||
TML_SOUND_CTRL7, TML_SOUND_CTRL8, TML_SOUND_CTRL9, TML_SOUND_CTRL10, TML_GPC5, TML_GPC6, TML_GPC7, TML_GPC8,
|
||||
TML_PORTAMENTO_CTRL, TML_FX_REVERB = 91, TML_FX_TREMOLO, TML_FX_CHORUS, TML_FX_CELESTE_DETUNE, TML_FX_PHASER,
|
||||
TML_DATA_ENTRY_INCR, TML_DATA_ENTRY_DECR, TML_NRPN_LSB, TML_NRPN_MSB, TML_RPN_LSB, TML_RPN_MSB,
|
||||
TML_ALL_SOUND_OFF = 120, TML_ALL_CTRL_OFF, TML_LOCAL_CONTROL, TML_ALL_NOTES_OFF, TML_OMNI_OFF, TML_OMNI_ON, TML_POLY_OFF, TML_POLY_ON
|
||||
};
|
||||
|
||||
// A single MIDI message linked to the next message in time
|
||||
typedef struct tml_message
|
||||
{
|
||||
// Time of the message in milliseconds
|
||||
unsigned int time;
|
||||
|
||||
// Type (see TMLMessageType) and channel number
|
||||
unsigned char type, channel;
|
||||
|
||||
// 2 byte of parameter data based on the type:
|
||||
// - key, velocity for TML_NOTE_ON and TML_NOTE_OFF messages
|
||||
// - key, key_pressure for TML_KEY_PRESSURE messages
|
||||
// - control, control_value for TML_CONTROL_CHANGE messages (see TMLController)
|
||||
// - program for TML_PROGRAM_CHANGE messages
|
||||
// - channel_pressure for TML_CHANNEL_PRESSURE messages
|
||||
// - pitch_bend for TML_PITCH_BEND messages
|
||||
union
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4201) //nonstandard extension used: nameless struct/union
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wpedantic" //ISO C++ prohibits anonymous structs
|
||||
#endif
|
||||
|
||||
struct { union { char key, control, program, channel_pressure; }; union { char velocity, key_pressure, control_value; }; };
|
||||
struct { unsigned short pitch_bend; };
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning( pop )
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
};
|
||||
|
||||
// The pointer to the next message in time following this event
|
||||
struct tml_message* next;
|
||||
} tml_message;
|
||||
|
||||
// The load functions will return a pointer to a struct tml_message.
|
||||
// Normally the linked list gets traversed by following the next pointers.
|
||||
// Make sure to keep the pointer to the first message to free the memory.
|
||||
// On error the tml_load* functions will return NULL most likely due to an
|
||||
// invalid MIDI stream (or if the file did not exist in tml_load_filename).
|
||||
|
||||
#ifndef TML_NO_STDIO
|
||||
// Directly load a MIDI file from a .mid file path
|
||||
TMLDEF tml_message* tml_load_filename(const char* filename);
|
||||
#endif
|
||||
|
||||
// Load a MIDI file from a block of memory
|
||||
TMLDEF tml_message* tml_load_memory(const void* buffer, int size);
|
||||
|
||||
// Get infos about this loaded MIDI file, returns the note count
|
||||
// NULL can be passed for any output value pointer if not needed.
|
||||
// used_channels: Will be set to how many channels play notes
|
||||
// (i.e. 1 if channel 15 is used but no other)
|
||||
// used_programs: Will be set to how many different programs are used
|
||||
// total_notes: Will be set to the total number of note on messages
|
||||
// time_first_note: Will be set to the time of the first note on message
|
||||
// time_length: Will be set to the total time in milliseconds
|
||||
TMLDEF int tml_get_info(tml_message* first_message, int* used_channels, int* used_programs, int* total_notes, unsigned int* time_first_note, unsigned int* time_length);
|
||||
|
||||
// Read the tempo (microseconds per quarter note) value from a message with the type TML_SET_TEMPO
|
||||
TMLDEF int tml_get_tempo_value(tml_message* set_tempo_message);
|
||||
|
||||
// Free all the memory of the linked message list (can also call free() manually)
|
||||
TMLDEF void tml_free(tml_message* f);
|
||||
|
||||
// Stream structure for the generic loading
|
||||
struct tml_stream
|
||||
{
|
||||
// Custom data given to the functions as the first parameter
|
||||
void* data;
|
||||
|
||||
// Function pointer will be called to read 'size' bytes into ptr (returns number of read bytes)
|
||||
int (*read)(void* data, void* ptr, unsigned int size);
|
||||
};
|
||||
|
||||
// Generic Midi loading method using the stream structure above
|
||||
TMLDEF tml_message* tml_load(struct tml_stream* stream);
|
||||
|
||||
// If this library is used together with TinySoundFont, tsf_stream (equivalent to tml_stream) can also be used
|
||||
struct tsf_stream;
|
||||
TMLDEF tml_message* tml_load_tsf_stream(struct tsf_stream* stream);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
// end header
|
||||
// ---------------------------------------------------------------------------------------------------------
|
||||
#endif //TML_INCLUDE_TML_INL
|
||||
|
||||
#ifdef TML_IMPLEMENTATION
|
||||
|
||||
#if !defined(TML_MALLOC) || !defined(TML_FREE) || !defined(TML_REALLOC)
|
||||
# include <stdlib.h>
|
||||
# define TML_MALLOC malloc
|
||||
# define TML_FREE free
|
||||
# define TML_REALLOC realloc
|
||||
#endif
|
||||
|
||||
#if !defined(TML_MEMCPY)
|
||||
# include <string.h>
|
||||
# define TML_MEMCPY memcpy
|
||||
#endif
|
||||
|
||||
#ifndef TML_NO_STDIO
|
||||
# include <stdio.h>
|
||||
#endif
|
||||
|
||||
#define TML_NULL 0
|
||||
|
||||
////crash on errors and warnings to find broken midi files while debugging
|
||||
//#define TML_ERROR(msg) *(int*)0 = 0xbad;
|
||||
//#define TML_WARN(msg) *(int*)0 = 0xf00d;
|
||||
|
||||
////print errors and warnings
|
||||
//#define TML_ERROR(msg) printf("ERROR: %s\n", msg);
|
||||
//#define TML_WARN(msg) printf("WARNING: %s\n", msg);
|
||||
|
||||
#ifndef TML_ERROR
|
||||
#define TML_ERROR(msg)
|
||||
#endif
|
||||
|
||||
#ifndef TML_WARN
|
||||
#define TML_WARN(msg)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef TML_NO_STDIO
|
||||
static int tml_stream_stdio_read(FILE* f, void* ptr, unsigned int size) { return (int)fread(ptr, 1, size, f); }
|
||||
TMLDEF tml_message* tml_load_filename(const char* filename)
|
||||
{
|
||||
struct tml_message* res;
|
||||
struct tml_stream stream = { TML_NULL, (int(*)(void*,void*,unsigned int))&tml_stream_stdio_read };
|
||||
#if __STDC_WANT_SECURE_LIB__
|
||||
FILE* f = TML_NULL; fopen_s(&f, filename, "rb");
|
||||
#else
|
||||
FILE* f = fopen(filename, "rb");
|
||||
#endif
|
||||
if (!f) { TML_ERROR("File not found"); return 0; }
|
||||
stream.data = f;
|
||||
res = tml_load(&stream);
|
||||
fclose(f);
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct tml_stream_memory { const char* buffer; unsigned int total, pos; };
|
||||
static int tml_stream_memory_read(struct tml_stream_memory* m, void* ptr, unsigned int size) { if (size > m->total - m->pos) size = m->total - m->pos; TML_MEMCPY(ptr, m->buffer+m->pos, size); m->pos += size; return size; }
|
||||
TMLDEF struct tml_message* tml_load_memory(const void* buffer, int size)
|
||||
{
|
||||
struct tml_stream stream = { TML_NULL, (int(*)(void*,void*,unsigned int))&tml_stream_memory_read };
|
||||
struct tml_stream_memory f = { 0, 0, 0 };
|
||||
f.buffer = (const char*)buffer;
|
||||
f.total = size;
|
||||
stream.data = &f;
|
||||
return tml_load(&stream);
|
||||
}
|
||||
|
||||
struct tml_track
|
||||
{
|
||||
unsigned int Idx, End, Ticks;
|
||||
};
|
||||
|
||||
struct tml_tempomsg
|
||||
{
|
||||
unsigned int time;
|
||||
unsigned char type, Tempo[3];
|
||||
tml_message* next;
|
||||
};
|
||||
|
||||
struct tml_parser
|
||||
{
|
||||
unsigned char *buf, *buf_end;
|
||||
int last_status, message_array_size, message_count;
|
||||
};
|
||||
|
||||
enum TMLSystemType
|
||||
{
|
||||
TML_TEXT = 0x01, TML_COPYRIGHT = 0x02, TML_TRACK_NAME = 0x03, TML_INST_NAME = 0x04, TML_LYRIC = 0x05, TML_MARKER = 0x06, TML_CUE_POINT = 0x07,
|
||||
TML_EOT = 0x2f, TML_SMPTE_OFFSET = 0x54, TML_TIME_SIGNATURE = 0x58, TML_KEY_SIGNATURE = 0x59, TML_SEQUENCER_EVENT = 0x7f,
|
||||
TML_SYSEX = 0xf0, TML_TIME_CODE = 0xf1, TML_SONG_POSITION = 0xf2, TML_SONG_SELECT = 0xf3, TML_TUNE_REQUEST = 0xf6, TML_EOX = 0xf7, TML_SYNC = 0xf8,
|
||||
TML_TICK = 0xf9, TML_START = 0xfa, TML_CONTINUE = 0xfb, TML_STOP = 0xfc, TML_ACTIVE_SENSING = 0xfe, TML_SYSTEM_RESET = 0xff
|
||||
};
|
||||
|
||||
static int tml_readbyte(struct tml_parser* p)
|
||||
{
|
||||
return (p->buf == p->buf_end ? -1 : *(p->buf++));
|
||||
}
|
||||
|
||||
static int tml_readvariablelength(struct tml_parser* p)
|
||||
{
|
||||
unsigned int res = 0, i = 0;
|
||||
unsigned char c;
|
||||
for (; i != 4; i++)
|
||||
{
|
||||
if (p->buf == p->buf_end) { TML_WARN("Unexpected end of file"); return -1; }
|
||||
c = *(p->buf++);
|
||||
if (c & 0x80) res = ((res | (c & 0x7F)) << 7);
|
||||
else return (int)(res | c);
|
||||
}
|
||||
TML_WARN("Invalid variable length byte count"); return -1;
|
||||
}
|
||||
|
||||
static int tml_parsemessage(tml_message** f, struct tml_parser* p)
|
||||
{
|
||||
int deltatime = tml_readvariablelength(p), status = tml_readbyte(p);
|
||||
tml_message* evt;
|
||||
|
||||
if (deltatime & 0xFFF00000) deltatime = 0; //throw away delays that are insanely high for malformatted midis
|
||||
if (status < 0) { TML_WARN("Unexpected end of file"); return -1; }
|
||||
if ((status & 0x80) == 0)
|
||||
{
|
||||
// Invalid, use same status as before
|
||||
if ((p->last_status & 0x80) == 0) { TML_WARN("Undefined status and invalid running status"); return -1; }
|
||||
p->buf--;
|
||||
status = p->last_status;
|
||||
}
|
||||
else p->last_status = status;
|
||||
|
||||
if (p->message_array_size == p->message_count)
|
||||
{
|
||||
//start allocated memory size of message array at 64, double each time until 8192, then add 1024 entries until done
|
||||
p->message_array_size += (!p->message_array_size ? 64 : (p->message_array_size > 4096 ? 1024 : p->message_array_size));
|
||||
*f = (tml_message*)TML_REALLOC(*f, p->message_array_size * sizeof(tml_message));
|
||||
if (!*f) { TML_ERROR("Out of memory"); return -1; }
|
||||
}
|
||||
evt = *f + p->message_count;
|
||||
|
||||
//check what message we have
|
||||
if ((status == TML_SYSEX) || (status == TML_EOX)) //sysex
|
||||
{
|
||||
//sysex messages are not handled
|
||||
p->buf += tml_readvariablelength(p);
|
||||
if (p->buf > p->buf_end) { TML_WARN("Unexpected end of file"); p->buf = p->buf_end; return -1; }
|
||||
evt->type = 0;
|
||||
}
|
||||
else if (status == 0xFF) //meta events
|
||||
{
|
||||
int meta_type = tml_readbyte(p), buflen = tml_readvariablelength(p);
|
||||
unsigned char* metadata = p->buf;
|
||||
if (meta_type < 0) { TML_WARN("Unexpected end of file"); return -1; }
|
||||
if (buflen > 0 && (p->buf += buflen) > p->buf_end) { TML_WARN("Unexpected end of file"); p->buf = p->buf_end; return -1; }
|
||||
|
||||
switch (meta_type)
|
||||
{
|
||||
case TML_EOT:
|
||||
if (buflen != 0) { TML_WARN("Invalid length for EndOfTrack event"); return -1; }
|
||||
if (!deltatime) return TML_EOT; //no need to store this message
|
||||
evt->type = TML_EOT;
|
||||
break;
|
||||
|
||||
case TML_SET_TEMPO:
|
||||
if (buflen != 3) { TML_WARN("Invalid length for SetTempo meta event"); return -1; }
|
||||
evt->type = TML_SET_TEMPO;
|
||||
((struct tml_tempomsg*)evt)->Tempo[0] = metadata[0];
|
||||
((struct tml_tempomsg*)evt)->Tempo[1] = metadata[1];
|
||||
((struct tml_tempomsg*)evt)->Tempo[2] = metadata[2];
|
||||
break;
|
||||
|
||||
default:
|
||||
evt->type = 0;
|
||||
}
|
||||
}
|
||||
else //channel message
|
||||
{
|
||||
int param;
|
||||
if ((param = tml_readbyte(p)) < 0) { TML_WARN("Unexpected end of file"); return -1; }
|
||||
evt->key = (param & 0x7f);
|
||||
evt->channel = (status & 0x0f);
|
||||
switch (evt->type = (status & 0xf0))
|
||||
{
|
||||
case TML_NOTE_OFF:
|
||||
case TML_NOTE_ON:
|
||||
case TML_KEY_PRESSURE:
|
||||
case TML_CONTROL_CHANGE:
|
||||
if ((param = tml_readbyte(p)) < 0) { TML_WARN("Unexpected end of file"); return -1; }
|
||||
evt->velocity = (param & 0x7f);
|
||||
break;
|
||||
|
||||
case TML_PITCH_BEND:
|
||||
if ((param = tml_readbyte(p)) < 0) { TML_WARN("Unexpected end of file"); return -1; }
|
||||
evt->pitch_bend = ((param & 0x7f) << 7) | evt->key;
|
||||
break;
|
||||
|
||||
case TML_PROGRAM_CHANGE:
|
||||
case TML_CHANNEL_PRESSURE:
|
||||
evt->velocity = 0;
|
||||
break;
|
||||
|
||||
default: //ignore system/manufacture messages
|
||||
evt->type = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (deltatime || evt->type)
|
||||
{
|
||||
evt->time = deltatime;
|
||||
p->message_count++;
|
||||
}
|
||||
return evt->type;
|
||||
}
|
||||
|
||||
TMLDEF tml_message* tml_load(struct tml_stream* stream)
|
||||
{
|
||||
int num_tracks, division, trackbufsize = 0;
|
||||
unsigned char midi_header[14], *trackbuf = TML_NULL;
|
||||
struct tml_message* messages = TML_NULL;
|
||||
struct tml_track *tracks, *t, *tracksEnd;
|
||||
struct tml_parser p = { TML_NULL, TML_NULL, 0, 0, 0 };
|
||||
|
||||
// Parse MIDI header
|
||||
if (stream->read(stream->data, midi_header, 14) != 14) { TML_ERROR("Unexpected end of file"); return messages; }
|
||||
if (midi_header[0] != 'M' || midi_header[1] != 'T' || midi_header[2] != 'h' || midi_header[3] != 'd' ||
|
||||
midi_header[7] != 6 || midi_header[9] > 2) { TML_ERROR("Doesn't look like a MIDI file: invalid MThd header"); return messages; }
|
||||
if (midi_header[12] & 0x80) { TML_ERROR("File uses unsupported SMPTE timing"); return messages; }
|
||||
num_tracks = (int)(midi_header[10] << 8) | midi_header[11];
|
||||
division = (int)(midi_header[12] << 8) | midi_header[13]; //division is ticks per beat (quarter-note)
|
||||
if (num_tracks <= 0 && division <= 0) { TML_ERROR("Doesn't look like a MIDI file: invalid track or division values"); return messages; }
|
||||
|
||||
// Allocate temporary tracks array for parsing
|
||||
tracks = (struct tml_track*)TML_MALLOC(sizeof(struct tml_track) * num_tracks);
|
||||
tracksEnd = &tracks[num_tracks];
|
||||
for (t = tracks; t != tracksEnd; t++) t->Idx = t->End = t->Ticks = 0;
|
||||
|
||||
// Read all messages for all tracks
|
||||
for (t = tracks; t != tracksEnd; t++)
|
||||
{
|
||||
unsigned char track_header[8];
|
||||
int track_length;
|
||||
if (stream->read(stream->data, track_header, 8) != 8) { TML_WARN("Unexpected end of file"); break; }
|
||||
if (track_header[0] != 'M' || track_header[1] != 'T' || track_header[2] != 'r' || track_header[3] != 'k')
|
||||
{ TML_WARN("Invalid MTrk header"); break; }
|
||||
|
||||
// Get size of track data and read into buffer (allocate bigger buffer if needed)
|
||||
track_length = track_header[7] | (track_header[6] << 8) | (track_header[5] << 16) | (track_header[4] << 24);
|
||||
if (track_length < 0) { TML_WARN("Invalid MTrk header"); break; }
|
||||
if (trackbufsize < track_length) { TML_FREE(trackbuf); trackbuf = (unsigned char*)TML_MALLOC(trackbufsize = track_length); }
|
||||
if (stream->read(stream->data, trackbuf, track_length) != track_length) { TML_WARN("Unexpected end of file"); break; }
|
||||
|
||||
t->Idx = p.message_count;
|
||||
for (p.buf_end = (p.buf = trackbuf) + track_length; p.buf != p.buf_end;)
|
||||
{
|
||||
int type = tml_parsemessage(&messages, &p);
|
||||
if (type == TML_EOT || type < 0) break; //file end or illegal data encountered
|
||||
}
|
||||
if (p.buf != p.buf_end) { TML_WARN( "Track length did not match data length"); }
|
||||
t->End = p.message_count;
|
||||
}
|
||||
TML_FREE(trackbuf);
|
||||
|
||||
// Change message time signature from delta ticks to actual msec values and link messages ordered by time
|
||||
if (p.message_count)
|
||||
{
|
||||
tml_message *PrevMessage = TML_NULL, *Msg, *MsgEnd, Swap;
|
||||
unsigned int ticks = 0, tempo_ticks = 0; //tick counter and value at last tempo change
|
||||
int step_smallest, msec, tempo_msec = 0; //msec value at last tempo change
|
||||
double ticks2time = 500000 / (1000.0 * division); //milliseconds per tick
|
||||
|
||||
// Loop through all messages over all tracks ordered by time
|
||||
for (step_smallest = 0; step_smallest != 0x7fffffff; ticks += step_smallest)
|
||||
{
|
||||
step_smallest = 0x7fffffff;
|
||||
msec = tempo_msec + (int)((ticks - tempo_ticks) * ticks2time);
|
||||
for (t = tracks; t != tracksEnd; t++)
|
||||
{
|
||||
if (t->Idx == t->End) continue;
|
||||
for (Msg = &messages[t->Idx], MsgEnd = &messages[t->End]; Msg != MsgEnd && t->Ticks + Msg->time == ticks; Msg++, t->Idx++)
|
||||
{
|
||||
t->Ticks += Msg->time;
|
||||
if (Msg->type == TML_SET_TEMPO)
|
||||
{
|
||||
unsigned char* Tempo = ((struct tml_tempomsg*)Msg)->Tempo;
|
||||
ticks2time = ((Tempo[0]<<16)|(Tempo[1]<<8)|Tempo[2])/(1000.0 * division);
|
||||
tempo_msec = msec;
|
||||
tempo_ticks = ticks;
|
||||
}
|
||||
if (Msg->type)
|
||||
{
|
||||
Msg->time = msec;
|
||||
if (PrevMessage) { PrevMessage->next = Msg; PrevMessage = Msg; }
|
||||
else { Swap = *Msg; *Msg = *messages; *messages = Swap; PrevMessage = messages; }
|
||||
}
|
||||
}
|
||||
if (Msg != MsgEnd && t->Ticks + Msg->time > ticks)
|
||||
{
|
||||
int step = (int)(t->Ticks + Msg->time - ticks);
|
||||
if (step < step_smallest) step_smallest = step;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (PrevMessage) PrevMessage->next = TML_NULL;
|
||||
else p.message_count = 0;
|
||||
}
|
||||
TML_FREE(tracks);
|
||||
|
||||
if (p.message_count == 0)
|
||||
{
|
||||
TML_FREE(messages);
|
||||
messages = TML_NULL;
|
||||
}
|
||||
|
||||
return messages;
|
||||
}
|
||||
|
||||
TMLDEF tml_message* tml_load_tsf_stream(struct tsf_stream* stream)
|
||||
{
|
||||
return tml_load((struct tml_stream*)stream);
|
||||
}
|
||||
|
||||
TMLDEF int tml_get_info(tml_message* Msg, int* out_used_channels, int* out_used_programs, int* out_total_notes, unsigned int* out_time_first_note, unsigned int* out_time_length)
|
||||
{
|
||||
int used_programs = 0, used_channels = 0, total_notes = 0;
|
||||
unsigned int time_first_note = 0xffffffff, time_length = 0;
|
||||
unsigned char channels[16] = { 0 }, programs[128] = { 0 };
|
||||
for (;Msg; Msg = Msg->next)
|
||||
{
|
||||
time_length = Msg->time;
|
||||
if (Msg->type == TML_PROGRAM_CHANGE && !programs[(int)Msg->program]) { programs[(int)Msg->program] = 1; used_programs++; }
|
||||
if (Msg->type != TML_NOTE_ON) continue;
|
||||
if (time_first_note == 0xffffffff) time_first_note = time_length;
|
||||
if (!channels[Msg->channel]) { channels[Msg->channel] = 1; used_channels++; }
|
||||
total_notes++;
|
||||
}
|
||||
if (time_first_note == 0xffffffff) time_first_note = 0;
|
||||
if (out_used_channels ) *out_used_channels = used_channels;
|
||||
if (out_used_programs ) *out_used_programs = used_programs;
|
||||
if (out_total_notes ) *out_total_notes = total_notes;
|
||||
if (out_time_first_note) *out_time_first_note = time_first_note;
|
||||
if (out_time_length ) *out_time_length = time_length;
|
||||
return total_notes;
|
||||
}
|
||||
|
||||
TMLDEF int tml_get_tempo_value(tml_message* msg)
|
||||
{
|
||||
unsigned char* Tempo;
|
||||
if (!msg || msg->type != TML_SET_TEMPO) return 0;
|
||||
Tempo = ((struct tml_tempomsg*)msg)->Tempo;
|
||||
return ((Tempo[0]<<16)|(Tempo[1]<<8)|Tempo[2]);
|
||||
}
|
||||
|
||||
TMLDEF void tml_free(tml_message* f)
|
||||
{
|
||||
TML_FREE(f);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //TML_IMPLEMENTATION
|
1898
source/engine/tsf.h
Normal file
|
@ -26,11 +26,10 @@ void window_resize(int width, int height)
|
|||
mainwin.dpi = sapp_dpi_scale();
|
||||
mainwin.width = sapp_width();
|
||||
mainwin.height = sapp_height();
|
||||
mainwin.rwidth = mainwin.width/mainwin.dpi;
|
||||
mainwin.rheight = mainwin.height/mainwin.dpi;
|
||||
|
||||
float aspect = mainwin.width/mainwin.height;
|
||||
float raspect = mainwin.rwidth/mainwin.rheight;
|
||||
mainwin.pheight = mainwin.rheight;
|
||||
mainwin.pwidth = mainwin.rwidth*aspect/raspect;
|
||||
render_winsize();
|
||||
|
||||
JSValue vals[2] = { int2js(width), int2js(height) };
|
||||
send_signal("window_resize", 2, vals);
|
||||
|
|
|
@ -3,10 +3,11 @@
|
|||
|
||||
struct window {
|
||||
int id;
|
||||
float width, height; // The actual width and height of the window
|
||||
float rwidth, rheight; // The desired rendering resolution, what the assets are at
|
||||
float pwidth, pheight; // The calculated width and height passed to rendering
|
||||
int width;
|
||||
int height;
|
||||
double dpi;
|
||||
int rwidth;
|
||||
int rheight;
|
||||
int render;
|
||||
int mouseFocus;
|
||||
int keyboardFocus;
|
||||
|
|
|
@ -46,7 +46,6 @@
|
|||
#include "sokol/sokol_audio.h"
|
||||
#include "sokol/sokol_time.h"
|
||||
#include "sokol/sokol_args.h"
|
||||
#include "sokol/sokol_fetch.h"
|
||||
#include <stb_ds.h>
|
||||
#include <stb_truetype.h>
|
||||
#include "stb_image.h"
|
||||
|
@ -154,7 +153,6 @@ void c_frame()
|
|||
}
|
||||
|
||||
void c_clean() {
|
||||
sfetch_shutdown();
|
||||
gif_rec_end("out.gif");
|
||||
out_memusage(".prosperon/jsmem.txt");
|
||||
script_stop();
|
||||
|
@ -282,6 +280,26 @@ int main(int argc, char **argv) {
|
|||
signal(SIGFPE, seghandle);
|
||||
// signal(SIGBUS, seghandle);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef STEAM
|
||||
steaminit();
|
||||
#endif
|
||||
|
||||
#ifdef DISCORD
|
||||
struct IDiscordCore *core;
|
||||
DiscordCreate(DISCORD_VERSION, &(struct DiscordCreateParams){
|
||||
.client_id = 1176355046590533714,
|
||||
.flags = DiscordCreateFlags_Default
|
||||
}, &core);
|
||||
struct IDiscordUserManager *dum;
|
||||
struct IDiscordActivityManager *dam;
|
||||
dam = core->get_activity_manager(core);
|
||||
|
||||
struct DiscordActivity da;
|
||||
sprintf(da.state, "Playing Solo Pinball");
|
||||
sprintf(da.details, "COMPetitive");
|
||||
dam->update_activity(dam, &da, NULL, NULL);
|
||||
#endif
|
||||
|
||||
resources_init();
|
||||
|
@ -301,10 +319,6 @@ int main(int argc, char **argv) {
|
|||
strcat(cmdstr, argv[i]);
|
||||
if (argc > i+1) strcat(cmdstr, " ");
|
||||
}
|
||||
|
||||
while (!LOADED_GAME)
|
||||
sfetch_dowork();
|
||||
|
||||
script_evalf("cmd_args('%s');", cmdstr);
|
||||
|
||||
out_memusage(".prosperon/jsmem.txt");
|
||||
|
|
|
@ -8,6 +8,7 @@ in vec4 vColor;
|
|||
|
||||
out vec2 TexCoords;
|
||||
out vec4 fColor;
|
||||
out vec2 fst;
|
||||
|
||||
uniform vs_params { mat4 projection; };
|
||||
|
||||
|
@ -16,6 +17,7 @@ void main()
|
|||
gl_Position = projection * vec4(pos + (vert * wh), 0.0, 1.0);
|
||||
|
||||
TexCoords = uv + vec2(vert.x*st.x, st.y - vert.y*st.y);
|
||||
fst = st / wh;
|
||||
|
||||
fColor = vColor;
|
||||
}
|
||||
|
@ -24,17 +26,49 @@ void main()
|
|||
@fs fs
|
||||
in vec2 TexCoords;
|
||||
in vec4 fColor;
|
||||
in vec2 fst;
|
||||
|
||||
out vec4 color;
|
||||
|
||||
uniform texture2D text;
|
||||
uniform sampler smp;
|
||||
|
||||
float osize = 1.0;
|
||||
|
||||
void main()
|
||||
{
|
||||
float lettera = texture(sampler2D(text,smp),TexCoords).r;
|
||||
if (lettera < 0.1f) discard;
|
||||
color = fColor;
|
||||
|
||||
if (lettera <= 0.1f)
|
||||
{
|
||||
vec2 uvpos = TexCoords - fst;
|
||||
for (int x = 0; x < 3; x++) {
|
||||
for (int y = 0; y < 3; y++) {
|
||||
float pa = texture(sampler2D(text,smp), uvpos + (fst*vec2(x,y))).r;
|
||||
if (pa > 0.1) {
|
||||
color = vec4(0.0,0.0,0.0, fColor.a);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
discard;
|
||||
}
|
||||
|
||||
// vec2 lsize = fst / textureSize(dtext,0).xy;
|
||||
/* vec2 uvpos = TexCoords - fst;
|
||||
for (int x = 0; x < 3; x++) {
|
||||
for (int y = 0; 0 < 3; y++) {
|
||||
float pa = texture(sampler2D(text,smp), uvpos + (fst * vec2(x,y))).r;
|
||||
|
||||
if (pa <= 0.1) {
|
||||
color = vec4(0.0,0.0,0.0,fColor.a);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
color = vec4(fColor.xyz, fColor.a);
|
||||
}
|
||||
@end
|
||||
|
||||
|
|
40
tests/bind_v_call.js
Normal file
|
@ -0,0 +1,40 @@
|
|||
var binds = [];
|
||||
var cbs = [];
|
||||
var fats = [];
|
||||
var count = 1000000;
|
||||
|
||||
var a = {
|
||||
n: 1
|
||||
}
|
||||
|
||||
function test_a() {
|
||||
this.n++;
|
||||
}
|
||||
|
||||
var start = Date.now();
|
||||
for (var i = 0; i < count; i++)
|
||||
binds.push(test_a.bind(a));
|
||||
console.log(`Make bind time: ${Date.now()-start} ms`);
|
||||
|
||||
start = Date.now();
|
||||
for (var i = 0; i < count; i++)
|
||||
fats.push(() => test_a.call(a));
|
||||
console.log(`Make fat time: ${Date.now()-start} ms`);
|
||||
|
||||
start = Date.now();
|
||||
for (var i = 0; i < count; i++) {
|
||||
binds[i]();
|
||||
}
|
||||
console.log(`Bind time: ${Date.now()-start} ms`);
|
||||
|
||||
start = Date.now();
|
||||
for (var i = 0; i < count; i++) {
|
||||
fats[i]();
|
||||
}
|
||||
console.log(`Fat time: ${Date.now()-start} ms`);
|
||||
|
||||
start = Date.now();
|
||||
for (var i = 0; i < count; i++)
|
||||
test_a.call(a);
|
||||
|
||||
console.log(`Call time: ${Date.now()-start} ms`);
|
24
tests/bind_v_fn.js
Normal file
|
@ -0,0 +1,24 @@
|
|||
var binds = [];
|
||||
var a = {
|
||||
n: 1,
|
||||
test() { this.n++; }
|
||||
};
|
||||
var count = 10000000;
|
||||
|
||||
var start = Date.now();
|
||||
for (var i = 0; i < count; i++)
|
||||
binds.push(a.test.bind(a));
|
||||
|
||||
console.log(`Make bind time: ${Date.now()-start} ms`);
|
||||
|
||||
start = Date.now();
|
||||
for (var i = 0; i < count; i++)
|
||||
binds[i]();
|
||||
|
||||
console.log(`Bind time: ${Date.now()-start} ms`);
|
||||
|
||||
start = Date.now();
|
||||
for (var i = 0; i < count; i++)
|
||||
a['test']();
|
||||
|
||||
console.log(`Call time: ${Date.now()-start} ms`);
|