merge sokol
217
.clang-format
Normal file
|
@ -0,0 +1,217 @@
|
|||
---
|
||||
Language: Cpp
|
||||
# BasedOnStyle: LLVM
|
||||
AccessModifierOffset: -2
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignArrayOfStructures: None
|
||||
AlignConsecutiveAssignments:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
PadOperators: true
|
||||
AlignConsecutiveBitFields:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
PadOperators: false
|
||||
AlignConsecutiveDeclarations:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
PadOperators: false
|
||||
AlignConsecutiveMacros:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
PadOperators: false
|
||||
AlignEscapedNewlines: Right
|
||||
AlignOperands: Align
|
||||
AlignTrailingComments: true
|
||||
AllowAllArgumentsOnNextLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortEnumsOnASingleLine: true
|
||||
AllowShortBlocksOnASingleLine: Never
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: AllIfsAndElse
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: MultiLine
|
||||
AttributeMacros:
|
||||
- __capability
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: false
|
||||
AfterClass: false
|
||||
AfterControlStatement: Never
|
||||
AfterEnum: false
|
||||
AfterFunction: false
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
BeforeLambdaBody: false
|
||||
BeforeWhile: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: true
|
||||
SplitEmptyNamespace: true
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeConceptDeclarations: Always
|
||||
BreakBeforeBraces: Attach
|
||||
BreakBeforeInheritanceComma: false
|
||||
BreakInheritanceList: BeforeColon
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 0
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
QualifierAlignment: Leave
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DeriveLineEnding: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
EmptyLineAfterAccessModifier: Never
|
||||
EmptyLineBeforeAccessModifier: LogicalBlock
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
PackConstructorInitializers: BinPack
|
||||
BasedOnStyle: ''
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
AllowAllConstructorInitializersOnNextLine: true
|
||||
FixNamespaceComments: true
|
||||
ForEachMacros:
|
||||
- foreach
|
||||
- Q_FOREACH
|
||||
- BOOST_FOREACH
|
||||
IfMacros:
|
||||
- KJ_IF_MAYBE
|
||||
IncludeBlocks: Preserve
|
||||
IncludeCategories:
|
||||
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
|
||||
Priority: 2
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
|
||||
Priority: 3
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
- Regex: '.*'
|
||||
Priority: 1
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
IncludeIsMainRegex: '(Test)?$'
|
||||
IncludeIsMainSourceRegex: ''
|
||||
IndentAccessModifiers: false
|
||||
IndentCaseLabels: false
|
||||
IndentCaseBlocks: false
|
||||
IndentGotoLabels: true
|
||||
IndentPPDirectives: None
|
||||
IndentExternBlock: AfterExternBlock
|
||||
IndentRequiresClause: true
|
||||
IndentWidth: 2
|
||||
IndentWrappedFunctionNames: false
|
||||
InsertBraces: false
|
||||
InsertTrailingCommas: None
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
LambdaBodyIndentation: Signature
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
ObjCBinPackProtocolList: Auto
|
||||
ObjCBlockIndentWidth: 2
|
||||
ObjCBreakBeforeNestedBlockParam: true
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PenaltyBreakAssignment: 2
|
||||
PenaltyBreakBeforeFirstCallParameter: 19
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakOpenParenthesis: 0
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyBreakTemplateDeclaration: 10
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 60
|
||||
PenaltyIndentedWhitespace: 0
|
||||
PointerAlignment: Right
|
||||
PPIndentWidth: -1
|
||||
ReferenceAlignment: Pointer
|
||||
ReflowComments: true
|
||||
RemoveBracesLLVM: false
|
||||
RequiresClausePosition: OwnLine
|
||||
SeparateDefinitionBlocks: Leave
|
||||
ShortNamespaceLines: 1
|
||||
SortIncludes: CaseSensitive
|
||||
SortJavaStaticImport: Before
|
||||
SortUsingDeclarations: true
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCaseColon: false
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeParensOptions:
|
||||
AfterControlStatements: true
|
||||
AfterForeachMacros: true
|
||||
AfterFunctionDefinitionName: false
|
||||
AfterFunctionDeclarationName: false
|
||||
AfterIfMacros: true
|
||||
AfterOverloadedOperator: false
|
||||
AfterRequiresInClause: false
|
||||
AfterRequiresInExpression: false
|
||||
BeforeNonEmptyParentheses: false
|
||||
SpaceAroundPointerQualifiers: Default
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceInEmptyBlock: false
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: Never
|
||||
SpacesInConditionalStatement: false
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInLineCommentPrefix:
|
||||
Minimum: 1
|
||||
Maximum: -1
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
SpaceBeforeSquareBrackets: false
|
||||
BitFieldColonSpacing: Both
|
||||
Standard: Latest
|
||||
StatementAttributeLikeMacros:
|
||||
- Q_EMIT
|
||||
StatementMacros:
|
||||
- Q_UNUSED
|
||||
- QT_REQUIRE_VERSION
|
||||
TabWidth: 8
|
||||
UseCRLF: false
|
||||
UseTab: Never
|
||||
WhitespaceSensitiveMacros:
|
||||
- STRINGIZE
|
||||
- PP_STRINGIZE
|
||||
- BOOST_PP_STRINGIZE
|
||||
- NS_SWIFT_NAME
|
||||
- CF_SWIFT_NAME
|
||||
IndentWidth: 2
|
||||
...
|
||||
|
1
.gitignore
vendored
|
@ -1,4 +1,5 @@
|
|||
.git/
|
||||
.obj/
|
||||
bin/
|
||||
build/
|
||||
*.o
|
||||
|
|
145
Makefile
|
@ -3,27 +3,40 @@ MAKEFLAGS = --jobs=$(PROCS)
|
|||
|
||||
UNAME != uname
|
||||
|
||||
QFLAGS = -O3 -DDBG=0 -DED=1
|
||||
INFO = rel
|
||||
# Options
|
||||
# DBG --- build with debugging symbols and logging
|
||||
# ED --- build with or without editor
|
||||
# OPT --- Optimize
|
||||
|
||||
QFLAGS :=
|
||||
|
||||
ifdef DBG
|
||||
QFLAGS += -O0 -g -DDBG
|
||||
INFO = dbg
|
||||
|
||||
ifeq ($(CC),tcc)
|
||||
QFLAGS +=
|
||||
endif
|
||||
|
||||
else
|
||||
QFLAGS += -O2
|
||||
INFO = rel
|
||||
CC = gcc
|
||||
endif
|
||||
|
||||
ifdef OPT
|
||||
QFLAGS += -flto
|
||||
endif
|
||||
|
||||
ifdef ED
|
||||
QFLAGS += -DED
|
||||
endif
|
||||
|
||||
PTYPE != uname -m
|
||||
|
||||
# Options
|
||||
# DBG=0,1 --- build with debugging symbols and logging
|
||||
# ED=0,1 --- build with or without editor
|
||||
BIN = bin/$(CC)/$(INFO)/
|
||||
|
||||
|
||||
ifeq ($(DBG), 1)
|
||||
QFLAGS = -O0 -g -DDBG=1 -DED=1
|
||||
INFO = dbg
|
||||
endif
|
||||
|
||||
ifeq ($(ED), 0)
|
||||
QFLAGS = -DED=0
|
||||
INFO = ed
|
||||
endif
|
||||
|
||||
BIN = bin/
|
||||
objprefix = $(BIN)obj/$(INFO)
|
||||
objprefix = $(BIN)obj
|
||||
|
||||
define prefix
|
||||
echo $(1) | tr " " "\n" | sed 's/.*/$(2)&$(3)/'
|
||||
|
@ -36,76 +49,96 @@ define rm
|
|||
rm $${tmp}
|
||||
endef
|
||||
|
||||
define findindir
|
||||
find $(1) -maxdepth 1 -type f -name '$(2)'
|
||||
endef
|
||||
|
||||
# All other sources
|
||||
edirs != find source -type d -name include
|
||||
edirs += source/engine source/engine/thirdparty/Nuklear
|
||||
ehead != $(call findindir, source/engine,*.h)
|
||||
subengs = sound 3d
|
||||
|
||||
ifeq ($(DBG), 1)
|
||||
subengs += debug
|
||||
endif
|
||||
|
||||
edirs += source/engine $(addprefix source/engine/, $(subengs)) source/engine/thirdparty/Nuklear
|
||||
ehead != find source/engine source/engine/sound source/engine/debug -maxdepth 1 -type f -name *.h
|
||||
eobjects != find source/engine -type f -name '*.c' | sed -r 's|^(.*)\.c|$(objprefix)/\1.o|' # Gets all .c files and makes .o refs
|
||||
eobjects != $(call rm,$(eobjects),sqlite pl_mpeg_extract_frames pl_mpeg_player yugine nuklear)
|
||||
|
||||
includeflag != $(call prefix,$(edirs),-I)
|
||||
engincs != find source/engine -maxdepth 1 -type d
|
||||
includeflag != find source -type d -name include
|
||||
includeflag += $(engincs) source/engine/thirdparty/Nuklear
|
||||
includeflag := $(addprefix -I, $(includeflag))
|
||||
|
||||
WARNING_FLAGS = -Wall -pedantic -Wextra -Wwrite-strings -Wno-incompatible-function-pointer-types -Wno-incompatible-pointer-types -Wno-unused-function
|
||||
WARNING_FLAGS = -Wall -Wno-incompatible-function-pointer-types -Wno-unused-function# -pedantic -Wextra -Wwrite-strings -Wno-incompatible-function-pointer-types -Wno-incompatible-pointer-types -Wno-unused-function
|
||||
|
||||
SEM = 0.0.1
|
||||
COM != git rev-parse --short HEAD
|
||||
COM != fossil describe
|
||||
VER = $(SEM)-$(COM)
|
||||
|
||||
COMPILER_FLAGS = $(includeflag) $(QFLAGS) -MD $(WARNING_FLAGS) -DVER=\"$(VER)\" -DINFO=\"$(INFO)\" -c $< -o $@
|
||||
COMPILER_FLAGS = $(includeflag) $(QFLAGS) -MD $(WARNING_FLAGS) -I. -DCP_USE_DOUBLES=0 -DTINYSPLINE_FLOAT_PRECISION -DVER=\"$(VER)\" -DINFO=\"$(INFO)\" -c $< -o $@
|
||||
|
||||
LIBPATH = -Lbin -L/usr/local/lib
|
||||
LIBPATH = -L$(BIN)
|
||||
|
||||
ifeq ($(OS), WIN32)
|
||||
LINKER_FLAGS = $(QFLAGS)
|
||||
ELIBS = engine pthread mruby glfw3 opengl32 gdi32 ws2_32 ole32 winmm setupapi m
|
||||
LINKER_FLAGS = $(QFLAGS) -static
|
||||
ELIBS = engine ucrt yughc glfw3 opengl32 gdi32 ws2_32 ole32 winmm setupapi m
|
||||
CLIBS =
|
||||
EXT = .exe
|
||||
else
|
||||
LINKER_FLAGS = $(QFLAGS)
|
||||
ELIBS = engine pthread yughc portaudio asound jack glfw3 c m dl
|
||||
LINKER_FLAGS = $(QFLAGS) -L/usr/local/lib -pthread -rdynamic
|
||||
ELIBS = engine pthread yughc quickjs glfw3 GL c m dl
|
||||
CLIBS =
|
||||
EXT =
|
||||
endif
|
||||
|
||||
ELIBS != $(call prefix, $(ELIBS), -l)
|
||||
ELIBS := $(CLIBS) $(ELIBS)
|
||||
NAME = yugine$(EXT)
|
||||
|
||||
ELIBS != $(call prefix, $(ELIBS), -l)
|
||||
CLIBS != $(call prefix, $(CLIBS), -l);
|
||||
|
||||
objects = $(eobjects)
|
||||
DEPENDS = $(objects:.o=.d)
|
||||
-include $(DEPENDS)
|
||||
|
||||
yuginec = source/engine/yugine.c
|
||||
|
||||
ENGINE = $(BIN)libengine.a
|
||||
INCLUDE = $(BIN)include
|
||||
|
||||
SCRIPTS = $(shell ls source/scripts/*.js)
|
||||
|
||||
LINK = $(LIBPATH) $(LINKER_FLAGS) $(ELIBS)
|
||||
|
||||
MYTAG = $(VER)_$(PTYPE)_$(INFO)
|
||||
|
||||
.PHONY: yugine
|
||||
DIST = $(NAME)-$(MYTAG).tar.gz
|
||||
|
||||
yugine: $(objprefix)/source/engine/yugine.o $(ENGINE)
|
||||
@echo $(CC)
|
||||
@echo Linking yugine
|
||||
$(CC) $< $(LINK) -o yugine
|
||||
yugine: $(BIN)yugine
|
||||
|
||||
$(NAME): $(BIN)$(NAME)
|
||||
|
||||
$(BIN)$(NAME): $(objprefix)/source/engine/yugine.o $(ENGINE) $(BIN)libquickjs.a
|
||||
@echo Linking $(NAME)
|
||||
$(CC) $< $(LINK) -o $(BIN)$(NAME)
|
||||
@echo Finished build
|
||||
|
||||
dist: yugine
|
||||
mkdir -p bin/dist
|
||||
cp yugine bin/dist
|
||||
cp -rf assets/fonts bin/dist
|
||||
cp -rf source/scripts bin/dist
|
||||
cp -rf source/shaders bin/dist
|
||||
tar -czf yugine-$(MYTAG).tar.gz --directory bin/dist .
|
||||
$(BIN)$(DIST): $(BIN)$(NAME) source/shaders/* $(SCRIPTS) assets/*
|
||||
@echo Creating distribution $(DIST)
|
||||
@mkdir -p $(BIN)dist
|
||||
@cp $(BIN)$(NAME) $(BIN)dist
|
||||
@cp -rf assets/* $(BIN)dist
|
||||
@cp -rf source/shaders $(BIN)dist
|
||||
@cp -r source/scripts $(BIN)dist
|
||||
@tar czf $(DIST) --directory $(BIN)dist .
|
||||
@mv $(DIST) $(BIN)
|
||||
|
||||
install: yugine
|
||||
cp yugine ~/.local/bin
|
||||
$(BIN)libquickjs.a:
|
||||
make -C quickjs clean
|
||||
make -C quickjs libquickjs.a libquickjs.lto.a CC=$(CC)
|
||||
cp quickjs/libquickjs.* $(BIN)
|
||||
|
||||
dist: $(BIN)$(DIST)
|
||||
|
||||
install: $(BIN)$(DIST)
|
||||
@echo Unpacking $(DIST) in $(DESTDIR)
|
||||
@cp $(BIN)$(DIST) $(DESTDIR)
|
||||
@tar xzf $(DESTDIR)/$(DIST) -C $(DESTDIR)
|
||||
@rm $(DESTDIR)/$(DIST)
|
||||
|
||||
$(ENGINE): $(eobjects)
|
||||
@echo Making library engine.a
|
||||
|
@ -118,8 +151,12 @@ $(objprefix)/%.o:%.c
|
|||
@echo Making C object $@
|
||||
@$(CC) $(COMPILER_FLAGS)
|
||||
|
||||
.PHONY: docs
|
||||
docs:
|
||||
asciidoctor docs/*.adoc
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@echo Cleaning project
|
||||
@find $(BIN) -type f -delete
|
||||
@rm -rf source/portaudio/build source/glfw/build
|
||||
@rm -rf bin/*
|
||||
@rm -f *.gz
|
||||
|
|
1908
assets/data/gamecontrollerdb.txt
Normal file
BIN
assets/fonts/LessPerfectDOSVGA.ttf
Normal file
4
assets/fonts/dos.font
Normal file
|
@ -0,0 +1,4 @@
|
|||
(font
|
||||
:path "LessPerfectDOSVGA.ttf"
|
||||
:size 16
|
||||
)
|
BIN
assets/icons/icons8-bug-16.png
Normal file
After Width: | Height: | Size: 298 B |
BIN
assets/icons/icons8-console-16.png
Normal file
After Width: | Height: | Size: 187 B |
BIN
assets/icons/icons8-factory-16.png
Normal file
After Width: | Height: | Size: 225 B |
BIN
assets/icons/icons8-gear-16.png
Normal file
After Width: | Height: | Size: 293 B |
BIN
assets/icons/icons8-light-switch-16.png
Normal file
After Width: | Height: | Size: 157 B |
BIN
assets/icons/icons8-lock-16.png
Normal file
After Width: | Height: | Size: 197 B |
BIN
assets/icons/icons8-music-16.png
Normal file
After Width: | Height: | Size: 226 B |
BIN
assets/icons/icons8-pause-16.png
Normal file
After Width: | Height: | Size: 108 B |
BIN
assets/icons/icons8-radio-tower-16.png
Normal file
After Width: | Height: | Size: 339 B |
BIN
assets/icons/icons8-record-16.png
Normal file
After Width: | Height: | Size: 234 B |
BIN
assets/icons/icons8-resume-button-16.png
Normal file
After Width: | Height: | Size: 187 B |
BIN
assets/icons/icons8-shuffle-16.png
Normal file
After Width: | Height: | Size: 224 B |
BIN
assets/icons/icons8-skip-to-start-16.png
Normal file
After Width: | Height: | Size: 206 B |
BIN
assets/icons/icons8-spotlight-16.png
Normal file
After Width: | Height: | Size: 304 B |
BIN
assets/icons/no_tex.png
Normal file
After Width: | Height: | Size: 5.2 KiB |
13
docs/2d.md
|
@ -1,13 +0,0 @@
|
|||
# Yugine 2D Tooling
|
||||
|
||||
## 2D game editing
|
||||
2D game levels take place on a 2D plane. Objects can be on layers from -127 to 127. When you start editing, you begin with placing objects on layer 0.This makes it easy to add foreground and background graphics. In addition, each layer has a parallax value from -127 to 127. A parallax value of 1 means the sprite moves at a 1:1 ratio with the camera, ie, if the camera "moves" one pixel to the right, the object will appear to move 1 pixel to the left across the screen. Positive parallax values denote faster movement, so a parallax value of 100 indicates the object will move 100 pixels to the left if the camera moves 1 pixel to the right. Negative parallax values indicate slower movement, so a value of -100 indicates that the object will move 1 pixel to the left for every 100 pixels to the right the camera moves. A parallax value of 0 indicates the object will not move when the camera moves. This might be used for static stars in the background of a space level, for example.
|
||||
|
||||
If two sprites on the same layer overlap, it is undefined behavior. Be sure they do not overlap!
|
||||
|
||||
Instead of selecting what layer each element is on, it might be useful to group them. Gameobject fields can be set to a specific layer. You can choose to have each object's layer determined by its type instead of individually. For example, in a platformer it often makes sense to have all Monsters and the Player on the same layer.
|
||||
|
||||
There are three viewing modes in 2D mode:
|
||||
- Game view: how the level will be seen when the game is run.
|
||||
- Layer view: View only one layer at a time.
|
||||
- Onion view: View a selected layer; all layers behind that layer are drawn as normal, and all layers on top are drawn transparently.
|
11
docs/3d.md
|
@ -1,11 +0,0 @@
|
|||
# Yugine 3D Tooling
|
||||
|
||||
Yowza! 3D graphical features include:
|
||||
|
||||
### Rendering
|
||||
A forward rendering pipeline with MSAA options.
|
||||
|
||||
### Debug modes
|
||||
Grid drawing is handled as three separate axises. Most game engines enable the X and Z axis drawing to create a 2D grid on the ground. Each axis has markers for a set number of units so you can orient yourself whereever you are in the game world. You set these markers.
|
||||
|
||||
If you only enable the X axis grid, there will just be a line along the X axis that shows you the units you're at. X and Z enabled create a 2D grid on the ground; X, Y and Z enabled create a grid going into the sky as well as the grid along theh ground.
|
183
docs/editor.md
|
@ -0,0 +1,183 @@
|
|||
# Yugine Editor
|
||||
|
||||
The main editor view is made up of objects. Each object can have a
|
||||
number of components attached to it. When an object is selected, its
|
||||
name, position, and list of components are listed.
|
||||
|
||||
## Basic controls
|
||||
|Ctrl-Z|Undo|
|
||||
|Ctrl-Shift-Z|Redo|
|
||||
|Ctrl-A|Select all|
|
||||
|Ctrl-S|Save|
|
||||
|Ctrl-N|New|
|
||||
|Ctrl-O|Open level|
|
||||
|Ctrl-X|Cut|
|
||||
|Ctrl-C|Copy|
|
||||
|Ctrl-V|Paste|
|
||||
|Alt-O|Add level to current level|
|
||||
|Alt-A|or Alt-P Add a prefab|
|
||||
|Ctrl-I|Objects on the level|
|
||||
|Ctrl-E|Asset viewer. When on a component like a sprite, serves to select that sprite's texture|
|
||||
|Ctrl-[|Downsize grid|
|
||||
|Ctrl-]|Upsize grid|
|
||||
|Backtick|REPL|
|
||||
|Ctrl-[1-9]|to set camera positions|
|
||||
|[1-9]|to recall camera positions|
|
||||
|0|Set camera to home view|
|
||||
|ESC|quit|
|
||||
|Alt-1|Normal view|
|
||||
|Alt-2|Wireframe view|
|
||||
|Shift-Middle|Set editor cursor to mouse position (Cursor affects how objects rotate)|
|
||||
|Shift-Ctrl-Middle|Set cursor to object selection|
|
||||
|Shift-Right|Remove cursor|
|
||||
|
||||
## Editor Mode select
|
||||
|
||||
|Alt-F1|Basic mode|
|
||||
|Alt-F2|Brush mode|
|
||||
- Clicking will place what is on clipboard
|
||||
|
||||
## Object controls
|
||||
|
||||
|G|Translate|
|
||||
|Alt-G|Snap objects to cursor|
|
||||
|S|Scale|
|
||||
|R|Rotate|
|
||||
|Ctrl-P|Save object changes to prefab|
|
||||
|Ctrl-shift-P|Save object changes as a unique prefab ("Parent")|
|
||||
|Ctrl-shift-T|Save object changes to a side prefab ("Type")|
|
||||
|Ctrl-J|Bake name to expose to level script|
|
||||
|Alt-J|Remove baked name|
|
||||
|Ctrl-Y|Show obj chain|
|
||||
|Alt-Y|Start prototype explorer|
|
||||
|Ctrl-U|Revert object or component to match prototype|
|
||||
|Alt-U|Make object unique. If a level, allows setting of internal object position and rotation.|
|
||||
|Ctrl-shift-G|Save group as a level|
|
||||
|Arrows|Translate 1 px|
|
||||
|Shift-Arrows|Translate 10 px|
|
||||
|Tab|Select component|
|
||||
|F|Zoom to object(s)|
|
||||
|Ctrl-F|Focus on a selected sublevel. Edit and save it in place.|
|
||||
|Ctrl-Shift-F|Go up one level in the editing chain.|
|
||||
|M|Flip horizontally|
|
||||
|Ctrl-M|Flip vertically|
|
||||
|Ctrl-D|Duplicate|
|
||||
|H|Hide|
|
||||
|Ctrl-H|Unhide all|
|
||||
|T|Lock|
|
||||
|Alt-T|Unlock all|
|
||||
|Q|Toggle component help|
|
||||
|Ctrl-Shift-Alt-Click|Set object center|
|
||||
|
||||
## Mouse controls
|
||||
|
||||
|Left|Select|
|
||||
|Middle|Quick grab|
|
||||
|Right|Unselect|
|
||||
|
||||
## Level controls
|
||||
|Ctrl-L|Open level script|
|
||||
|
||||
## Game controls
|
||||
|F1|Debug draw|
|
||||
|F2|Config menu|
|
||||
|F3|Show bounding boxes|
|
||||
|F4|Show gizmos|
|
||||
|F5|Start|
|
||||
|F6|Pause|
|
||||
|F7|Stop|
|
||||
|F10|Toggle slow motion|
|
||||
|
||||
== Components
|
||||
Components all have their own set of controls. Many act similar to
|
||||
objects. If a component has a position attribute, it will react as
|
||||
expected to object grabbing; same with scaling, rotation, and so on.
|
||||
|
||||
If a component uses an asset, the asset viewer will serve to pick new
|
||||
assets for it.
|
||||
|
||||
## Spline controls
|
||||
|Ctrl-click|Add a point|
|
||||
|Shift-click|remove a point|
|
||||
|+,-|Increase or decrease spline segments|
|
||||
|Ctrl-+,-|Increase or decrease spline degrees. Put this to 1 for the spline to go point to point|
|
||||
|Alt-B,V|Increase or decrease spline thickness|
|
||||
|
||||
.Collider controls
|
||||
|Alt-S|Toggle sensor|
|
||||
|
||||
## Yugine Programming
|
||||
|
||||
### Object functions
|
||||
|
||||
* start(): Called when the object is created, before the first update is ran
|
||||
* update(dt): Called once per frame
|
||||
* physupdate(dt): Called once per physics calculation
|
||||
* stop(): Called when the object is killed
|
||||
* collide(hit): Called when this object collides with another. If on a collider, specific to that collider
|
||||
- hit.hit: Gameobject ID of what's being hit
|
||||
- hit.velocity: Velocity of impact
|
||||
- hit.normal: Normal of impact
|
||||
|
||||
### Colliders
|
||||
Colliders visually look different based on their status. Objects can
|
||||
be in one of three states
|
||||
|
||||
- Dynamic: respond to physics
|
||||
- Kinematic: modeled with infinite momentum. An "unstoppable force"
|
||||
controlled by a user.
|
||||
- Static: modeled with infinite mass. An "immovable object" that
|
||||
shouldn't move.
|
||||
|
||||
Objects can then have colliders on them, each collider being a sensor,
|
||||
or solid. Sensors respond to collision signals, while solid ones also
|
||||
do not let objects through.
|
||||
|
||||
|
||||
|
||||
### Input
|
||||
Input works by adding functions to an object, and then "controlling"
|
||||
them. The format for a function is "input_[key]_[action]". [Action]
|
||||
can be any of
|
||||
|
||||
- down: Called once per frame the key is down
|
||||
- pressed: Called when the key is pressed
|
||||
- released: called when the key is released
|
||||
|
||||
For example, "input_p_pressed()" will be called when p is pressed, and not again
|
||||
until it is released and pressed again.
|
||||
|
||||
### Your game
|
||||
|
||||
When the engine runs, it executes config.js, and then game.js. A
|
||||
window should be created in config.js, and custom code for prototypes
|
||||
should be executed.
|
||||
|
||||
game.js is the place to open your first level.
|
||||
|
||||
### Levels
|
||||
|
||||
A level is a collection of objects. A level has a script associated
|
||||
with it. The script is ran when the level is loaded.
|
||||
|
||||
Levels can be added to other levels. Each is independent and unique.
|
||||
In this way, complicated behavior can easily be added up. For example,
|
||||
a world might have a door that opens with a lever. The door and lever
|
||||
can be saved off as their own level, and the level script can contain
|
||||
the code that causes the door to open when the lever is thrown. Then,
|
||||
as many door-lever levels can be added to your game as you want.
|
||||
|
||||
The two primary ways to add objects to the game are World.spawn, and
|
||||
Level.add. World.spawn creates a single object in the world, Level.add
|
||||
adds an entire level, along with its script.
|
||||
|
||||
Levels also can be checked for "completion". A level can be loaded
|
||||
over many frames, and only have all of its contents appear once it's
|
||||
finished loading. World.spawn is immediate.
|
||||
|
||||
Level.clear removes the level from the game world.
|
||||
|
||||
.Level scripting
|
||||
Each level has a script which is ran when the level is loaded, or the
|
||||
game is played. A single object declared in it called "scene" can be
|
||||
used to expose itself to the rest of the game.
|
138
docs/game.md
Normal file
|
@ -0,0 +1,138 @@
|
|||
# Yugine
|
||||
|
||||
The yugine essentially is made of a sequence of levels. Levels can be
|
||||
nested, they can be streamed in, or loaded one at a time. Levels are
|
||||
made of levels.
|
||||
|
||||
Different "modes" of using the engine has unique sequences of level
|
||||
loading orders. Each level has an associated script file. Level
|
||||
loading functions call the script file, as well as the level file. The
|
||||
level file can be considered to be a container of objects that the
|
||||
associated script file can access.
|
||||
|
||||
* Game start
|
||||
1. Engine scripts
|
||||
2. config.js
|
||||
3. game.lvl & game.js
|
||||
|
||||
* Editor
|
||||
1. Engine scripts
|
||||
2. config.js
|
||||
3. editor.js
|
||||
|
||||
* Editor play
|
||||
* F5 debug.lvl. Used for custom debug level testing. If doesn't exist, game.lvl is loaded.
|
||||
* F6 game.lvl
|
||||
* F7 Currently edited level
|
||||
|
||||
While playing ...
|
||||
|
||||
* F7 Stop
|
||||
|
||||
## Level model
|
||||
The game world is made up of objects. Levels are collections of
|
||||
objects. The topmost level is called "World". Objects are spawned into
|
||||
a specific level. If none are explicitly given, objects are spawned
|
||||
into World. Objects in turn are made up of components - sprites,
|
||||
colliders, and so on. Accessing an object might go like this:
|
||||
|
||||
World.level1.enemy1.sprite.path = "brick.png";
|
||||
|
||||
To set the image of enemy1 in level 1's sprite.
|
||||
|
||||
### Level functions
|
||||
|name| description|
|
||||
|---|---|
|
||||
|levels| a list of all levels loaded in this one|
|
||||
|objects| a list of all objects belonging to this level (objects + levels)|
|
||||
|object_count| objects.length()|
|
||||
|spawn(type)| creates an object from the supplied type in the level|
|
||||
|create()| creates an empty level inside of this one|
|
||||
|loadfile(file)| loads file as a level inside of this one; returns it. Mainly for editor|
|
||||
|loadlevel(file)| loads file as a level and does running required for gameplay|
|
||||
|load(level_json)| clears this level and spawns all objects specified in the level_json|
|
||||
|clear()| kills all objects in this level|
|
||||
|kill()| cleans up the level and kills it|
|
||||
|
||||
## Objects
|
||||
Objects are things that exist in the game world.
|
||||
|
||||
|name| description|
|
||||
|---|---|
|
||||
|level| the level this object belongs to|
|
||||
|pos| the global position|
|
||||
|relpos| the position relative to its level|
|
||||
angle| the global angle|
|
||||
|relangle| angle relative to its level|
|
||||
|velocity| velocity of the object|
|
||||
|angularvelocity| angular velocity of the object|
|
||||
|alive| true if the object is valid|
|
||||
|varname| the variable name of the object (used for friendly naming)|
|
||||
|friction| physics attribnute|
|
||||
|elasticity| physics attribute|
|
||||
|flipx| true if the object is flipped on its x axis|
|
||||
|flipy| true if the object is mirrored on its y axis|
|
||||
|body| the internal gameobject id of the object|
|
||||
|controlled| true if the object is controlled by something|
|
||||
|phys| set to dynamic; kinematic; or static; explained below|
|
||||
|moi| the moment of inertia of the object|
|
||||
|mass| mass of the object|
|
||||
|visible| true if the object is visible. Set to false to disable all visible features belonging to it|
|
||||
|in_air()| true if the object is not on the ground|
|
||||
|on_ground()| !in_air()|
|
||||
|layer| collision layer for the physics engine|
|
||||
|draw_layer| draw order. higher numbers draw on top of lower ones|
|
||||
|scale| change to make the object larger or smaller|
|
||||
|from| the object this object was created from|
|
||||
|boundingbox| the boundingbox of this object in world dimensions|
|
||||
|push(vec)| push this object each frame with vec velocity|
|
||||
|width| the boundingbox defined width|
|
||||
|height| the boundingbox defined height|
|
||||
|kill| destroy the object|
|
||||
|stop| ???|
|
||||
|world2this(pos)| return the pos in world coordinates to relative this object|
|
||||
|this2world(pos)| return the pos in this coordinates relative to the world|
|
||||
|make(props, level)| instantiate an object based on this, with additional props, in level|
|
||||
|
||||
## Editor related object features
|
||||
|
||||
|gizmo| path to an image to draw in editor mode|
|
||||
|
||||
## Functions for object control
|
||||
|
||||
|clone(name; ext)| create a copy of this object and extend it with ext; does not spawn|
|
||||
|instadup()| create an exact duplicate of this object in the World|
|
||||
|revert()| remove everything that makes the object unique; make it exactly like what it was spawned from|
|
||||
|
||||
## Physics
|
||||
All objects belong to the physics engine, but may be totally ignored by it.
|
||||
|
||||
|static| does not and will not move|
|
||||
|dynamic| moves under the auspices of the physics engine|
|
||||
|kinematic| moves under the auspices of the player or other control mechanism|
|
||||
|
||||
Physics properties work as such
|
||||
|
||||
|mass| affects how much a given force will move an object|
|
||||
|elasticity| affects momentum loss on collisions; multiplicative between two objects for each collision; 1 for no loss; 0 for total stoppage; >1 for a chaotic increasing entropy simulation|
|
||||
|friction| affects momentum loss when rubbing against another surface; multiplicative between the two objects|
|
||||
|
||||
## Textures & images
|
||||
A sprite is a display of a specific texture in the game world. The
|
||||
underlying texture has values associated with it, like how it should
|
||||
be rendered: is it a sprite, is it a texture, does it have mipmaps,
|
||||
etc. Textures are all file based, and are only accessed through the
|
||||
explicit path to their associated image file.
|
||||
|
||||
## Finding & Addressing Objects
|
||||
|
||||
|
||||
## Editor & Debugging
|
||||
Although intertwined, debugging functions and the editor are separate entities.
|
||||
|
||||
### Debugging
|
||||
Debugging functions are mapped to the F buttons, and are always available during gameplay in a debug build. Pressing the F button toggles the feature; pressing it with ALT shows a legend for that feature; pressing it with CTRL shows additional info
|
||||
|
||||
|F1| Draw physics info|
|
||||
|F3| Draw bounding boxes|
|
||||
|F12| Drawing gui debugging info|
|
|
@ -1,13 +0,0 @@
|
|||
# Yugine Gameobjects
|
||||
|
||||
## The world
|
||||
|
||||
A game is defined by the world. The "world" is a list of gameobjects. Each gameobject has a unique ID it can be referenced by. Gameobjects have a position and rotation in the world
|
||||
|
||||
## Components
|
||||
Components are part of a gameobjects. Different components, and varying values on those components, are what make game objects unique.
|
||||
|
||||
## Prefabs
|
||||
A "prefab" is simply a gameobject blueprint. It defines the gameobject and all of its components.
|
||||
|
||||
Prefabs have a hierarchy you can trace. Each prefab descendent can have modified values compared to its parent. When the parent changes, the lower prefabs change, too, IF they have no altered the given value from the parent.
|
22
docs/gui.md
|
@ -1,22 +0,0 @@
|
|||
# Yugine GUI
|
||||
|
||||
The GUI is a 2D layer which is always on top of everything and does not move with the camera. The GUI acts like a sub level, each element can have a layer value from -127 to 127 to indicate its draw position. If two GUI elements on the same layer overlap, it is undefined behavior.
|
||||
|
||||
A "Subgui" has its own layer order from -127 to 127. It itself is on one layer of the base GUI.
|
||||
|
||||
### GUI Scripting
|
||||
Each GUI element has a "Draw" boolean. If it is true, the GUI draws. If a Subgui's 'Draw' is set to 'True', it and all of its subelements draw.
|
||||
|
||||
Each GUI element has a script to allow it to hook into a component of the game. When it draws, its script is executed. Any component of the GUI element can be set in its script. A simple thing to do would be for a text script's instruction to be to set the value of the text to the player's health.
|
||||
|
||||
The GUI has read only access to the game state. Each gameobject has a boolean for "GUI". If set to 'True', that gameobject becomes readable by the GUI. It is accessed as 'gameobjectname->...'. The GUI can read all elements of the struct.
|
||||
|
||||
### GUI animations
|
||||
Each GUI element has a set number of animation slots which can be utilized.
|
||||
|
||||
- Start: Animation that is played once when the GUI element is set to Draw.
|
||||
- Repeat: Animation that is always played on a loop when the GUI element is Drawing, after the Start animation is finished.
|
||||
- Hover: Looped animation played when the GUI element is selected.
|
||||
- Quit: SIngle play animation when Draw is set to False.
|
||||
|
||||
In addition, there are 'Seconds' fields for Start-Repeat, Repeat-Hover, Hover-Repeat, and Hover-Quit. This field represents the time it takes to transition from one animation to the next. If set to 0, the animation immediately jumps to the beginning of the next animation. If set to a number, the GUI element will smoothly interpolate from its ending state to the beginning of the first frame of the next animation. For example, if a HUD element is bouncing up and down on hover, when you go to the next element the bouncing element jumps to its static state. It can instead smoothly return to where it started using this field.
|
273
docs/index.md
|
@ -1,273 +0,0 @@
|
|||
# The Yugine NAME TBD
|
||||
The Yugine is an engine for people who can code. If you learn to code, you will be rewarded with the ability to make games way faster than you can with any other tool.
|
||||
|
||||
## Compiling
|
||||
The main component of the Yugine is the library that enables the engine, yugine.a. Use this to create variations on the engine. The standard engine is a single "engine.c" file that enables all systems and initiates a standard game loop. It's compiled with a simple command, "tcc engine.c -o engine -static -lyugine -Iyugine". The editor that ships with it is compiled similarly. The editor and engine files should include preprocessor macros at the top of the files to customize the engine.
|
||||
|
||||
The engine is supposed to be extendable with C code easily.
|
||||
|
||||
### Included compiler
|
||||
The yugine includes a C compiler with it. Objects can be scripted with direct C, for extremely fast performance. Each time you press "play", the C is compiled and executed as if it's part of the original engine. The C "scripts" are compiled using the embedded TCC (tiny C compiler).
|
||||
|
||||
### Why C instead of C++??? Or anything else that's "easier"???
|
||||
C is the most simple programming language there is. Simple as.
|
||||
|
||||
## It's an operating system
|
||||
A game engine is like an operating system. You have low level code managing threads, loading files when needed, and so on. Then you have a higher level interpreted language for manipulating it (like a standard OS terminal/command line). That's all this is; multiple little C programs for manipulating stuff that makes a game work, and a scripting language used to string them together at 300 FPS.
|
||||
|
||||
There are multiple levels on which the engine can be modified. Like most game engines, you can create games with it; UNLIKE most game engines, it is as easy to make game editors as it is to make the games themselves. This makes making games faster and easier, of any sort.
|
||||
|
||||
### Modifying code
|
||||
The Yugine is the most generic version of the engine. It calls the engine library and runs everything as standard as possible. It is a simple short file that calls the standard basic API to get the engine running. You can hook into the engine API to make your own core engine; call the editor or not, change the rendering schedule, when input is gathered, etc.
|
||||
|
||||
### Editing in-engine
|
||||
In the engine, you make objects. These can be scripted with Scheme.
|
||||
|
||||
## Scheme
|
||||
The crown jewel idea behind this engine is its integration with Scheme. It's the scripting language for the engine, selected to be implemented for its extreme versatility and decent speed. Our Scheme implementation is faster than Lua, but multitudes more expressive, and, eventually, can compile down to C for distribution. If you're going to use a scripting language instead of C, choose one that's as far away from C as possible.
|
||||
|
||||
### Game languages
|
||||
Computer game development would be benefitted greatly by a similar number of languages used by an OS (for example: C, regex, sed, awk, make, bash scripting ...). Some day in the future we have languages for all the things we need them for, but in the mean time, Scheme is extremely good for developing little computer languages, and is the principal reason for its use in the engine. The Zork games and many following Infocom games were developed with a language made using Lisp, for example. It would be doable to recreate SCUMM using Scheme and incorporate it into a game with modern graphics. Wow!
|
||||
|
||||
Usually you have some cumbersome UI to input data into complicated structures to get the following things to work. Because, in Scheme. data is code and code is data, it's much more natural to express this stuff as written commands.
|
||||
- Game scripting. Calling library functions and making things in the game move.
|
||||
- AI. Lisp is known as an AI language, and here it is used to make writing AI easier than ever. Instead of clunky GUI behavior trees with lines, you can write out what you want your enemies to behave like.
|
||||
- Cutscenes. One of the first big game softwares I worked on was a cutscene maker. You could tell characters to move here or there, then say this line, then ask a question; I had to implement some crude form of coroutines and the ability to loop back around to previous points in the dialogue depending on what a player did. No more! For directly included in the language of scheme are continuations! And coroutines can be implemented in a mere 4 lines of code. Best of all, instead of little islands of data connected with arrows (don't they always end up like this?) you can write it like it's supposed to be written: a little (movie) script.
|
||||
- Formatting text. Scheme gives a natural way to write formatted text. No more opening and closing braces for your various text formatting, now it's all (). Plus, since data is code and code is data, you don't even need any code hooks to grab data like a player's name. The entire engine, every object in it, and any data associated with those objects, are available to be rendered as text.
|
||||
|
||||
## Kernel side and user side
|
||||
The "kernel" of the engine and the "user side" operate on totally different planes. Data has to be transformed to work on one side or the other anyway, so we make maximal use of that. Most game engines are at a tug of war with themselves, where on one hand you want to code in such a way to keep the processor happy (long arrays of the same operation on the same data type!), while also coding in a way to keep the designers happy (object model). C++ tried to get the best of both worlds, but instead it sucks. Jon Blow is doing something interesting with Jai, where you can swap between these two "views". I hope this turns out well, but I'm convinced that you should just separate systems level programming and user level programming from each other. Hence, C and Scheme, polar opposite languages.
|
||||
|
||||
In this engine, all data is internally represented in CPU optimal formatting. When you are poking around in Scheme, though, the data is put into the view of the objects they compose. You can edit freely in a way that makes the most sense for how games are composed, without sacrificing an ounce of speed.
|
||||
|
||||
## Compiling
|
||||
Various subsystems in the engine, including the editor, can be stripped at compile time. Running make creates the editor with all subsystems in place. If you instead run make with
|
||||
- EDITOR=0
|
||||
Removes all editor functionality.
|
||||
- DEBUG=0
|
||||
Removes writing debug logs, measuring FPS, the ability to draw physics shapes, various debugging viewmodes, etc.
|
||||
|
||||
It is intended for a script to be written to invoke make with whichever specifications you need.
|
||||
|
||||
The following commands can remove subsystems which a specific game might not need. In the editor, running the "COMPILE INFO" command will tell you which flags you can set to OFF for the game you are currently editing. These are pulled out of the game to increase speed, rather than to decrease size (so anything which it doesn't matter for performance if it is left in is not presented as an option)
|
||||
- 3D=0
|
||||
Removes 3D rendering
|
||||
- AUDIO=0
|
||||
etc ...
|
||||
|
||||
## Basic usage
|
||||
|
||||
If the editor is run, you are presented with a list of projects. If there are no projects listed, one can browse to an empty folder to create a project. If a project is selected, it opens. The editor.info file contains a list of paths for all known projects. If the editor is launched while in a game path, the editor starts immediately editing that game.
|
||||
|
||||
Each project has a game.project file that specifies info about the game, including which engine version the game was built with, which version of the game it is, and graphical settings. The game starts by loading the level specified in this file (set during editing). If the computer the game is run on cannot use a specified graphics setting, the game automatically applies what it thinks would work best (ie if the target is 1080p and the computer is 720p, it assumes fullscreen and so sets the resolution to 720p).
|
||||
|
||||
## Scenes
|
||||
|
||||
A "scene" is a list of classes and starting values for those classes.
|
||||
|
||||
This is the an improved godot, but with some extra features and focus:
|
||||
- More tools to actually make the game
|
||||
- First class localization tools
|
||||
- Easier to work with
|
||||
|
||||
## Controls
|
||||
### EDITOR
|
||||
Middle mouse - select object
|
||||
|
||||
Space - Toggle global/local transform
|
||||
|
||||
1 - Render mode LIT
|
||||
2 - Render mode UNLIT
|
||||
3 - Render mode WIRE
|
||||
4 - Show directional shadow map
|
||||
5 - Toggle gizmos visible
|
||||
6 - Toggle physics visible
|
||||
7 - Toggle detail lighting (only albedo)
|
||||
8 - Lighting only (lit only with gray material)
|
||||
9 - POV Depth map
|
||||
0 - Ambient occlusion
|
||||
|
||||
(UE4 viewmodes: https://docs.unrealengine.com/4.26/en-US/BuildingWorlds/LevelEditor/Viewports/ViewModes/)
|
||||
|
||||
CTRL + D - Duplicate object
|
||||
|
||||
Delete - delete object
|
||||
|
||||
F2 - Rename object
|
||||
|
||||
G - Translate object
|
||||
R - Rotate object
|
||||
T - Scale object
|
||||
|
||||
F3 - Toggle game stats display
|
||||
F4 - Toggle hierarchy menu
|
||||
F5 - Toggle lighting menu
|
||||
F6 - Toggle game settings menu
|
||||
F7 - Viewmode menu
|
||||
|
||||
H - Toggle object hidden
|
||||
K - Toggle grid visible
|
||||
|
||||
F - Focus on model
|
||||
|
||||
Y - Reload shaders
|
||||
|
||||
## Gameobject
|
||||
A gameobject is anything with a transform.
|
||||
|
||||
Only one level deep inheritance. Each object inherits GameObject. Then, that object defines in its constructor how it looks. What mesh does it use, etc (if it uses a mesh).
|
||||
|
||||
Gameobjects are completely defined in the source code. A designer can only add gameobjects to the game world; a programmer must add components together to create new gameobjects.
|
||||
|
||||
## Object data
|
||||
Prefabs and import data are sidecar files. They sit right next to the .c and .h files and are named instances you can load. For a prefab of point light, you have point_light.1.prefab
|
||||
|
||||
Import data also sits right next to the asset in the file directory. The name for asset.jpg is asset.import
|
||||
|
||||
## Resources
|
||||
On engine startup, links to all assets are placed in a hidden .resources folder at the root of the project. Any content in the assets folder will get a symlink in the .resources folder. Humans shouldn't edit the .resources folder. There is one file in the resource folder for each asset found in the assets folder. They also define import options for the assets.
|
||||
|
||||
Filetypes include:
|
||||
*Images*
|
||||
.png
|
||||
.jpg
|
||||
.tif
|
||||
|
||||
*Sounds*
|
||||
.wav
|
||||
.aiff
|
||||
.voc
|
||||
.mod
|
||||
.midi
|
||||
.ogg
|
||||
.mp3
|
||||
.flac
|
||||
|
||||
*3D Models*
|
||||
.gltf
|
||||
|
||||
*Shaders*
|
||||
.glsl
|
||||
|
||||
*Fonts*
|
||||
.ttf
|
||||
.bff (bitmap font)
|
||||
|
||||
And yugine generated things:
|
||||
.yugh (level)
|
||||
.prefab (An object with some defined characteristics)
|
||||
|
||||
# Internals
|
||||
## Render pipeline
|
||||
|
||||
3D rendering goes as the following:
|
||||
Textures --->
|
||||
Model----------------> Static actor
|
||||
Meshes ----->
|
||||
Raw dataCombination of dataGame world spawn of it
|
||||
|
||||
## Resources
|
||||
Assets you add are used as resources in the game engine. Each asset has a number of "contexts". You decide how each context is handled for each asset. There are also default contexts you can set. As an example, a .png file can be used as a exture, as a sprite, as a font, as an animation, and so on. It can be used for one of these or more than one. When you use an image as a texture, in most game engines you create the texture and link the image to it; in ours, you simply use the image, and the game uses the appropriate context for the situation.
|
||||
|
||||
### Resource Views
|
||||
There is a single resource panel which you can then filter based on what you want to see. You can filter by:
|
||||
File type: .png, .jpg, ...
|
||||
Resource type: image, video, model, ...
|
||||
Resource context: texture, sprite, ... (They're only listed here if they are actually used in the game as one of these)
|
||||
|
||||
Plus, you can filter by folder. Most of the time I browse by filter and a search, but you can also filter by grouped objects. So a goblin might have a model, a texture, and some audio files. You can view everything that belongs to the goblin prefab.
|
||||
|
||||
### 3D cursor
|
||||
In this 3d game engine, you're editing in 3d. Makes sense to have a 3d cursor to do so!
|
||||
|
||||
SPHERE SELECT
|
||||
Left click, and then use the mouse wheel to enlarge your selection sphere. Release the left mouse to select everything in the sphere.
|
||||
|
||||
CUBE SELECT
|
||||
Left click and drag to draw a square on any surface. Scroll UP to increase the selection volume out from the surface, and scroll DOWN to decrease it (and even make it negative).
|
||||
|
||||
## Real time editing
|
||||
You can edit levels in real time with work partners. Start a server and send your partner your IP address and server password. They will gain the ability to edit your game. The host can remove editors from the server, ban them, and restrict their editing privledges (edit, play). Each editor in the room has a color assigned to them. When they select an object to move, the object is shaded their color and their name is overlayed so you know who is editing what.
|
||||
|
||||
When the edits are done, the host can distribute his copy of the game to everybody else, or they can click the download button to get the edits in full.
|
||||
|
||||
## Levels
|
||||
A level can be either 3D or 2D. All levels feature familiar drag and drop editing, scripting, and so on.
|
||||
|
||||
|
||||
## Device view: specifics on resolution, screen sizes, and color gamuts
|
||||
You can emulate devices on your screen to see what it will physically look like on the target device. This is particularly useful for devices smaller than your editing screen, like tablets and the play date. You can also emulate device color gamuts. When editing, images will be scaled to fit the target device, based on the project target. For example, on a 4k project, a 200 pixel wide sprite will be rendered as a 100 pixel wide sprite when viewed on a 2k device emulator.
|
||||
|
||||
PlayDate: 400x240 pixels, 2.7 inches/68mm, 1 bit color.
|
||||
|
||||
This preview window has a free camera you can view the current scene with. It cannot be zoomed like the main editor can be. The window cannot be resized; it is determined by the selected device settings.
|
||||
|
||||
### Color scopes
|
||||
The engine has a standard array of colorscopes for the user.
|
||||
|
||||
## Playing the game
|
||||
When the Play button is selected, the device window becomes what you play the game on.
|
||||
|
||||
## Baking
|
||||
Baking assets involves converting assets for use on a target device or platform. When a game is played, the engine will scale sprites in real time. If the assets have been baked, it will instead use the scaled assets. Baking sprites means to resize them to to not waste space on the target platform's screen, as well as pack them into atlases. Sounds need to be converted for each platform as well. In the bake menu, select a platform and device to bake the assets for. Once the platform and device have been baked, the game can be exported for that platform.
|
||||
|
||||
## Exporting
|
||||
An exported game varies by platform, but generally it is basically a single big blob file of all the game's assets with the platform's executable as a sidecar. All baked assets for a platform are put inside of the blob file, and the executable expects the blob file to be next to it.
|
||||
|
||||
Game folder
|
||||
- engine.exe
|
||||
- content.blob
|
||||
|
||||
### Blob file
|
||||
- struct blob
|
||||
- - int blobid (identifies this as a blob)
|
||||
- - int files (number of assets the blob contains)
|
||||
- - int gameversion
|
||||
- - int engineverison
|
||||
- offset array[int files] (array of hashed values of the filepaths containing the byte offset of the data
|
||||
- data
|
||||
|
||||
To get a filepath's data from the blob, the filepath is hashed, then it is looked up in the offset array. The data can be grabbed by copying it from the start of it to the start of the next file (ie file[hash+1]), because the data is stored in offset array order.
|
||||
|
||||
### Patching
|
||||
A patch can be created in the engine. To create a patch, specify the last release you want to patch from, and then export a blob. The new blob will contain only modified files compared with the old blob. Place the patch blob next to the old blob. When an asset is searched for, it will be searched for first in the new blob, and if not found will be searched for in the old blob. If an asset is found in neither, it will be searched for in the filepath.
|
||||
|
||||
If another patch is made, all three blobs must be present (ie patch 1.3 requires the 1.2 patch which requires the base game).
|
||||
|
||||
The game code comes with the ability to merge patches as a CLI. It merges everything into a blob for the most recent patch, ie updates the 1.3<-1.2<-base blobs to a 1.3 blob.
|
||||
|
||||
### Expansions
|
||||
Expansions are delivered as their own blobs, with their own patch paths. When an expansion blob is exported, if its blob is placed in the directory with the game runtime, it will be pulled in when the game starts. The main blob should be patched to accomodate "knowing" if the expansion is present or not, so you can for example add a new menu item on the start menu if an expansion is present.
|
||||
|
||||
### Selecting assets for export
|
||||
Starting with the game start level, all assets required for it to run are marked for export. Then scripts are investigated: if they include a reference to a level, or asset, or other script, all of these are looked at and their referenced assets pulled in. In this way, nothing that is not seen in the running game will be pulled into the blob. Any test levels will not be included in the export (unless you reference it somewhere in the game)
|
||||
|
||||
To give somebody a development build, simply zip up the entire project and give it to them.
|
||||
|
||||
## Physics
|
||||
Each gameobject has a value field that represents what it is, from 0 to 15. Objects which move should be checked as "Kinematic", which then reveals two more bitmask fields: a 16 bit bitmask to represent what it should send trigger events to, and a 16 bit bitmask to represent what it should be blocked by. The 16 fields can freely be renamed by the game designer. Gameobjects can only be one thing.
|
||||
|
||||
For example, bit 1 may be assigned to Environment. A tree would have bit 1 on its object field set to True. The player would then assign bit 1 on its Block block bitfield to "true", so that it cannot walk through the environment. Bit 2 you may assign to Triggers. The player would assign its Trigger bit 2 to true so that it recieves "Hit" events without actually being stopped by it.
|
||||
|
||||
Sometimes, two non stationary objects can collide. As long as EITHER object has their Block bit set for the other object, a collision occurs and each object recieves a Block message. A trigger message is only sent to either object if they are set to recieve trigger events.
|
||||
|
||||
### Physics properties
|
||||
Objects have
|
||||
|
||||
## Scripting
|
||||
Each gameobject has a script attached to it. When the gameobject is selected, its script appears in the Script window.
|
||||
|
||||
## GUI
|
||||
|
||||
## The gamestate
|
||||
The gamestate is a global variable that holds all of the current information for the game. Various elements of the game engine has access to the gamestate in different capacities. The GUI can read the entire game state; a player can read and write his own status onto the gamestate.
|
||||
|
||||
## AI
|
||||
|
||||
|
||||
## Yugh scheme
|
||||
Yugh scheme is the style of scheme used for scripting in game events. It is built on top of S7 scheme.
|
||||
|
||||
Scheme hooks into the engine are highly abstracted away from the engine code. For example, the command "move" takes a single value as units/second. No matter if it is called in the update loop, or the physics loop, the given number will be multiplied by the relevant delta to make it work the same either way. In addition, if used on a static object, the object won't move; if used on a kinematic object it will move as expected; and if used on a dynamic object it will add the given number as a velocity, pushing the dynamic object instead of taking complete control.
|
||||
|
||||
Rather than overriding hooks into engine loops, there are distinct scripts for every hook you can want. If you don't write script into them, they won't be used. There are hooks into rendering loops, animation states (for example, footfall moments in an animatio to play sounds), and more.
|
2
docs/input.md
Normal file
|
@ -0,0 +1,2 @@
|
|||
# Yugine Input Guide
|
||||
|
|
@ -1,3 +1,11 @@
|
|||
# Yugine Scripting
|
||||
# Yugine Scripting Guide
|
||||
|
||||
Scripting is done with mruby. MAY CHANGE.
|
||||
All objects in the Yugine can have an associated script. This script can perform setup, teardown, and handles responses for the object.
|
||||
|
||||
|function|description|
|
||||
|---|---|
|
||||
|setup|called before the object is loaded|
|
||||
|start|called when the object is loaded|
|
||||
|update(dt)|called once per game frame|
|
||||
|physupdate(dt)|called once per physics tick|
|
||||
|stop|called when the object is killed|
|
10
docs/video.md
Normal file
|
@ -0,0 +1,10 @@
|
|||
# Yugine video playing
|
||||
|
||||
Yugine plays the open source MPEG-TS muxer, using MPEG1 video and MP2 audio.
|
||||
|
||||
MPEG-1 video works best at about 1.5 Mbit/s, in SD [720x480] video.
|
||||
For HD [1920x1080] video, use 9 Mbit/s.
|
||||
|
||||
ffmpeg -i "input.video" -vcodec mpeg1video -b:v 1.5M -s 720x480 -acodec mp2 "out.ts"
|
||||
ffmpeg -i "input.video" -vcodec mpeg1video -b:v 9M -s 1920x1080 -acodec mp2 "out.ts"
|
||||
|
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.
|
470
quickjs/Makefile
Normal file
|
@ -0,0 +1,470 @@
|
|||
#
|
||||
# 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)
|
||||
CONFIG_DARWIN=y
|
||||
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
|
||||
|
||||
ifdef CONFIG_DARWIN
|
||||
# use clang instead of gcc
|
||||
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
|
||||
ifdef CONFIG_CLANG
|
||||
HOST_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 += -Wundef -Wuninitialized
|
||||
CFLAGS += -Wunused -Wno-unused-parameter
|
||||
CFLAGS += -Wwrite-strings
|
||||
CFLAGS += -Wchar-subscripts -funsigned-char
|
||||
CFLAGS += -MMD -MF $(OBJDIR)/$(@F).d
|
||||
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
|
||||
HOST_CC=gcc
|
||||
CC=$(CROSS_PREFIX)gcc
|
||||
CFLAGS=-g -Wall -MMD -MF $(OBJDIR)/$(@F).d
|
||||
CFLAGS += -Wno-array-bounds -Wno-format-truncation
|
||||
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
|
||||
|
||||
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
|
297
quickjs/cutils.h
Normal file
|
@ -0,0 +1,297 @@
|
|||
/*
|
||||
* 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
|
||||
|
||||
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
72
quickjs/examples/fib.c
Normal file
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* QuickJS: Example of C module
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#include "../quickjs.h"
|
||||
|
||||
#define countof(x) (sizeof(x) / sizeof((x)[0]))
|
||||
|
||||
static int fib(int n)
|
||||
{
|
||||
if (n <= 0)
|
||||
return 0;
|
||||
else if (n == 1)
|
||||
return 1;
|
||||
else
|
||||
return fib(n - 1) + fib(n - 2);
|
||||
}
|
||||
|
||||
static JSValue js_fib(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *argv)
|
||||
{
|
||||
int n, res;
|
||||
if (JS_ToInt32(ctx, &n, argv[0]))
|
||||
return JS_EXCEPTION;
|
||||
res = fib(n);
|
||||
return JS_NewInt32(ctx, res);
|
||||
}
|
||||
|
||||
static const JSCFunctionListEntry js_fib_funcs[] = {
|
||||
JS_CFUNC_DEF("fib", 1, js_fib ),
|
||||
};
|
||||
|
||||
static int js_fib_init(JSContext *ctx, JSModuleDef *m)
|
||||
{
|
||||
return JS_SetModuleExportList(ctx, m, js_fib_funcs,
|
||||
countof(js_fib_funcs));
|
||||
}
|
||||
|
||||
#ifdef JS_SHARED_LIBRARY
|
||||
#define JS_INIT_MODULE js_init_module
|
||||
#else
|
||||
#define JS_INIT_MODULE js_init_module_fib
|
||||
#endif
|
||||
|
||||
JSModuleDef *JS_INIT_MODULE(JSContext *ctx, const char *module_name)
|
||||
{
|
||||
JSModuleDef *m;
|
||||
m = JS_NewCModule(ctx, module_name, js_fib_init);
|
||||
if (!m)
|
||||
return NULL;
|
||||
JS_AddModuleExportList(ctx, m, js_fib_funcs, countof(js_fib_funcs));
|
||||
return m;
|
||||
}
|
10
quickjs/examples/fib_module.js
Normal file
|
@ -0,0 +1,10 @@
|
|||
/* fib module */
|
||||
export function fib(n)
|
||||
{
|
||||
if (n <= 0)
|
||||
return 0;
|
||||
else if (n == 1)
|
||||
return 1;
|
||||
else
|
||||
return fib(n - 1) + fib(n - 2);
|
||||
}
|
1
quickjs/examples/hello.js
Normal file
|
@ -0,0 +1 @@
|
|||
console.log("Hello World");
|
6
quickjs/examples/hello_module.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
/* example of JS module */
|
||||
|
||||
import { fib } from "./fib_module.js";
|
||||
|
||||
console.log("Hello World");
|
||||
console.log("fib(10)=", fib(10));
|
68
quickjs/examples/pi_bigdecimal.js
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* PI computation in Javascript using the QuickJS bigdecimal type
|
||||
* (decimal floating point)
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
/* compute PI with a precision of 'prec' digits */
|
||||
function calc_pi(prec) {
|
||||
const CHUD_A = 13591409m;
|
||||
const CHUD_B = 545140134m;
|
||||
const CHUD_C = 640320m;
|
||||
const CHUD_C3 = 10939058860032000m; /* C^3/24 */
|
||||
const CHUD_DIGITS_PER_TERM = 14.18164746272548; /* log10(C/12)*3 */
|
||||
|
||||
/* return [P, Q, G] */
|
||||
function chud_bs(a, b, need_G) {
|
||||
var c, P, Q, G, P1, Q1, G1, P2, Q2, G2, b1;
|
||||
if (a == (b - 1n)) {
|
||||
b1 = BigDecimal(b);
|
||||
G = (2m * b1 - 1m) * (6m * b1 - 1m) * (6m * b1 - 5m);
|
||||
P = G * (CHUD_B * b1 + CHUD_A);
|
||||
if (b & 1n)
|
||||
P = -P;
|
||||
G = G;
|
||||
Q = b1 * b1 * b1 * CHUD_C3;
|
||||
} else {
|
||||
c = (a + b) >> 1n;
|
||||
[P1, Q1, G1] = chud_bs(a, c, true);
|
||||
[P2, Q2, G2] = chud_bs(c, b, need_G);
|
||||
P = P1 * Q2 + P2 * G1;
|
||||
Q = Q1 * Q2;
|
||||
if (need_G)
|
||||
G = G1 * G2;
|
||||
else
|
||||
G = 0m;
|
||||
}
|
||||
return [P, Q, G];
|
||||
}
|
||||
|
||||
var n, P, Q, G;
|
||||
/* number of serie terms */
|
||||
n = BigInt(Math.ceil(prec / CHUD_DIGITS_PER_TERM)) + 10n;
|
||||
[P, Q, G] = chud_bs(0n, n, false);
|
||||
Q = BigDecimal.div(Q, (P + Q * CHUD_A),
|
||||
{ roundingMode: "half-even",
|
||||
maximumSignificantDigits: prec });
|
||||
G = (CHUD_C / 12m) * BigDecimal.sqrt(CHUD_C,
|
||||
{ roundingMode: "half-even",
|
||||
maximumSignificantDigits: prec });
|
||||
return Q * G;
|
||||
}
|
||||
|
||||
(function() {
|
||||
var r, n_digits, n_bits;
|
||||
if (typeof scriptArgs != "undefined") {
|
||||
if (scriptArgs.length < 2) {
|
||||
print("usage: pi n_digits");
|
||||
return;
|
||||
}
|
||||
n_digits = scriptArgs[1] | 0;
|
||||
} else {
|
||||
n_digits = 1000;
|
||||
}
|
||||
/* we add more digits to reduce the probability of bad rounding for
|
||||
the last digits */
|
||||
r = calc_pi(n_digits + 20);
|
||||
print(r.toFixed(n_digits, "down"));
|
||||
})();
|
66
quickjs/examples/pi_bigfloat.js
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* PI computation in Javascript using the QuickJS bigfloat type
|
||||
* (binary floating point)
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
/* compute PI with a precision of 'prec' bits */
|
||||
function calc_pi() {
|
||||
const CHUD_A = 13591409n;
|
||||
const CHUD_B = 545140134n;
|
||||
const CHUD_C = 640320n;
|
||||
const CHUD_C3 = 10939058860032000n; /* C^3/24 */
|
||||
const CHUD_BITS_PER_TERM = 47.11041313821584202247; /* log2(C/12)*3 */
|
||||
|
||||
/* return [P, Q, G] */
|
||||
function chud_bs(a, b, need_G) {
|
||||
var c, P, Q, G, P1, Q1, G1, P2, Q2, G2;
|
||||
if (a == (b - 1n)) {
|
||||
G = (2n * b - 1n) * (6n * b - 1n) * (6n * b - 5n);
|
||||
P = BigFloat(G * (CHUD_B * b + CHUD_A));
|
||||
if (b & 1n)
|
||||
P = -P;
|
||||
G = BigFloat(G);
|
||||
Q = BigFloat(b * b * b * CHUD_C3);
|
||||
} else {
|
||||
c = (a + b) >> 1n;
|
||||
[P1, Q1, G1] = chud_bs(a, c, true);
|
||||
[P2, Q2, G2] = chud_bs(c, b, need_G);
|
||||
P = P1 * Q2 + P2 * G1;
|
||||
Q = Q1 * Q2;
|
||||
if (need_G)
|
||||
G = G1 * G2;
|
||||
else
|
||||
G = 0l;
|
||||
}
|
||||
return [P, Q, G];
|
||||
}
|
||||
|
||||
var n, P, Q, G;
|
||||
/* number of serie terms */
|
||||
n = BigInt(Math.ceil(BigFloatEnv.prec / CHUD_BITS_PER_TERM)) + 10n;
|
||||
[P, Q, G] = chud_bs(0n, n, false);
|
||||
Q = Q / (P + Q * BigFloat(CHUD_A));
|
||||
G = BigFloat((CHUD_C / 12n)) * BigFloat.sqrt(BigFloat(CHUD_C));
|
||||
return Q * G;
|
||||
}
|
||||
|
||||
(function() {
|
||||
var r, n_digits, n_bits;
|
||||
if (typeof scriptArgs != "undefined") {
|
||||
if (scriptArgs.length < 2) {
|
||||
print("usage: pi n_digits");
|
||||
return;
|
||||
}
|
||||
n_digits = scriptArgs[1];
|
||||
} else {
|
||||
n_digits = 1000;
|
||||
}
|
||||
n_bits = Math.ceil(n_digits * Math.log2(10));
|
||||
/* we add more bits to reduce the probability of bad rounding for
|
||||
the last digits */
|
||||
BigFloatEnv.setPrec( () => {
|
||||
r = calc_pi();
|
||||
print(r.toFixed(n_digits, BigFloatEnv.RNDZ));
|
||||
}, n_bits + 32);
|
||||
})();
|
118
quickjs/examples/pi_bigint.js
Normal file
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* PI computation in Javascript using the BigInt type
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
/* return floor(log2(a)) for a > 0 and 0 for a = 0 */
|
||||
function floor_log2(a)
|
||||
{
|
||||
var k_max, a1, k, i;
|
||||
k_max = 0n;
|
||||
while ((a >> (2n ** k_max)) != 0n) {
|
||||
k_max++;
|
||||
}
|
||||
k = 0n;
|
||||
a1 = a;
|
||||
for(i = k_max - 1n; i >= 0n; i--) {
|
||||
a1 = a >> (2n ** i);
|
||||
if (a1 != 0n) {
|
||||
a = a1;
|
||||
k |= (1n << i);
|
||||
}
|
||||
}
|
||||
return k;
|
||||
}
|
||||
|
||||
/* return ceil(log2(a)) for a > 0 */
|
||||
function ceil_log2(a)
|
||||
{
|
||||
return floor_log2(a - 1n) + 1n;
|
||||
}
|
||||
|
||||
/* return floor(sqrt(a)) (not efficient but simple) */
|
||||
function int_sqrt(a)
|
||||
{
|
||||
var l, u, s;
|
||||
if (a == 0n)
|
||||
return a;
|
||||
l = ceil_log2(a);
|
||||
u = 1n << ((l + 1n) / 2n);
|
||||
/* u >= floor(sqrt(a)) */
|
||||
for(;;) {
|
||||
s = u;
|
||||
u = ((a / s) + s) / 2n;
|
||||
if (u >= s)
|
||||
break;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/* return pi * 2**prec */
|
||||
function calc_pi(prec) {
|
||||
const CHUD_A = 13591409n;
|
||||
const CHUD_B = 545140134n;
|
||||
const CHUD_C = 640320n;
|
||||
const CHUD_C3 = 10939058860032000n; /* C^3/24 */
|
||||
const CHUD_BITS_PER_TERM = 47.11041313821584202247; /* log2(C/12)*3 */
|
||||
|
||||
/* return [P, Q, G] */
|
||||
function chud_bs(a, b, need_G) {
|
||||
var c, P, Q, G, P1, Q1, G1, P2, Q2, G2;
|
||||
if (a == (b - 1n)) {
|
||||
G = (2n * b - 1n) * (6n * b - 1n) * (6n * b - 5n);
|
||||
P = G * (CHUD_B * b + CHUD_A);
|
||||
if (b & 1n)
|
||||
P = -P;
|
||||
Q = b * b * b * CHUD_C3;
|
||||
} else {
|
||||
c = (a + b) >> 1n;
|
||||
[P1, Q1, G1] = chud_bs(a, c, true);
|
||||
[P2, Q2, G2] = chud_bs(c, b, need_G);
|
||||
P = P1 * Q2 + P2 * G1;
|
||||
Q = Q1 * Q2;
|
||||
if (need_G)
|
||||
G = G1 * G2;
|
||||
else
|
||||
G = 0n;
|
||||
}
|
||||
return [P, Q, G];
|
||||
}
|
||||
|
||||
var n, P, Q, G;
|
||||
/* number of serie terms */
|
||||
n = BigInt(Math.ceil(Number(prec) / CHUD_BITS_PER_TERM)) + 10n;
|
||||
[P, Q, G] = chud_bs(0n, n, false);
|
||||
Q = (CHUD_C / 12n) * (Q << prec) / (P + Q * CHUD_A);
|
||||
G = int_sqrt(CHUD_C << (2n * prec));
|
||||
return (Q * G) >> prec;
|
||||
}
|
||||
|
||||
function main(args) {
|
||||
var r, n_digits, n_bits, out;
|
||||
if (args.length < 1) {
|
||||
print("usage: pi n_digits");
|
||||
return;
|
||||
}
|
||||
n_digits = args[0] | 0;
|
||||
|
||||
/* we add more bits to reduce the probability of bad rounding for
|
||||
the last digits */
|
||||
n_bits = BigInt(Math.ceil(n_digits * Math.log2(10))) + 32n;
|
||||
r = calc_pi(n_bits);
|
||||
r = ((10n ** BigInt(n_digits)) * r) >> n_bits;
|
||||
out = r.toString();
|
||||
print(out[0] + "." + out.slice(1));
|
||||
}
|
||||
|
||||
var args;
|
||||
if (typeof scriptArgs != "undefined") {
|
||||
args = scriptArgs;
|
||||
args.shift();
|
||||
} else if (typeof arguments != "undefined") {
|
||||
args = arguments;
|
||||
} else {
|
||||
/* default: 1000 digits */
|
||||
args=[1000];
|
||||
}
|
||||
|
||||
main(args);
|
151
quickjs/examples/point.c
Normal file
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
* QuickJS: Example of C module with a class
|
||||
*
|
||||
* Copyright (c) 2019 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.
|
||||
*/
|
||||
#include "../quickjs.h"
|
||||
#include <math.h>
|
||||
|
||||
#define countof(x) (sizeof(x) / sizeof((x)[0]))
|
||||
|
||||
/* Point Class */
|
||||
|
||||
typedef struct {
|
||||
int x;
|
||||
int y;
|
||||
} JSPointData;
|
||||
|
||||
static JSClassID js_point_class_id;
|
||||
|
||||
static void js_point_finalizer(JSRuntime *rt, JSValue val)
|
||||
{
|
||||
JSPointData *s = JS_GetOpaque(val, js_point_class_id);
|
||||
/* Note: 's' can be NULL in case JS_SetOpaque() was not called */
|
||||
js_free_rt(rt, s);
|
||||
}
|
||||
|
||||
static JSValue js_point_ctor(JSContext *ctx,
|
||||
JSValueConst new_target,
|
||||
int argc, JSValueConst *argv)
|
||||
{
|
||||
JSPointData *s;
|
||||
JSValue obj = JS_UNDEFINED;
|
||||
JSValue proto;
|
||||
|
||||
s = js_mallocz(ctx, sizeof(*s));
|
||||
if (!s)
|
||||
return JS_EXCEPTION;
|
||||
if (JS_ToInt32(ctx, &s->x, argv[0]))
|
||||
goto fail;
|
||||
if (JS_ToInt32(ctx, &s->y, argv[1]))
|
||||
goto fail;
|
||||
/* using new_target to get the prototype is necessary when the
|
||||
class is extended. */
|
||||
proto = JS_GetPropertyStr(ctx, new_target, "prototype");
|
||||
if (JS_IsException(proto))
|
||||
goto fail;
|
||||
obj = JS_NewObjectProtoClass(ctx, proto, js_point_class_id);
|
||||
JS_FreeValue(ctx, proto);
|
||||
if (JS_IsException(obj))
|
||||
goto fail;
|
||||
JS_SetOpaque(obj, s);
|
||||
return obj;
|
||||
fail:
|
||||
js_free(ctx, s);
|
||||
JS_FreeValue(ctx, obj);
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
|
||||
static JSValue js_point_get_xy(JSContext *ctx, JSValueConst this_val, int magic)
|
||||
{
|
||||
JSPointData *s = JS_GetOpaque2(ctx, this_val, js_point_class_id);
|
||||
if (!s)
|
||||
return JS_EXCEPTION;
|
||||
if (magic == 0)
|
||||
return JS_NewInt32(ctx, s->x);
|
||||
else
|
||||
return JS_NewInt32(ctx, s->y);
|
||||
}
|
||||
|
||||
static JSValue js_point_set_xy(JSContext *ctx, JSValueConst this_val, JSValue val, int magic)
|
||||
{
|
||||
JSPointData *s = JS_GetOpaque2(ctx, this_val, js_point_class_id);
|
||||
int v;
|
||||
if (!s)
|
||||
return JS_EXCEPTION;
|
||||
if (JS_ToInt32(ctx, &v, val))
|
||||
return JS_EXCEPTION;
|
||||
if (magic == 0)
|
||||
s->x = v;
|
||||
else
|
||||
s->y = v;
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
static JSValue js_point_norm(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *argv)
|
||||
{
|
||||
JSPointData *s = JS_GetOpaque2(ctx, this_val, js_point_class_id);
|
||||
if (!s)
|
||||
return JS_EXCEPTION;
|
||||
return JS_NewFloat64(ctx, sqrt((double)s->x * s->x + (double)s->y * s->y));
|
||||
}
|
||||
|
||||
static JSClassDef js_point_class = {
|
||||
"Point",
|
||||
.finalizer = js_point_finalizer,
|
||||
};
|
||||
|
||||
static const JSCFunctionListEntry js_point_proto_funcs[] = {
|
||||
JS_CGETSET_MAGIC_DEF("x", js_point_get_xy, js_point_set_xy, 0),
|
||||
JS_CGETSET_MAGIC_DEF("y", js_point_get_xy, js_point_set_xy, 1),
|
||||
JS_CFUNC_DEF("norm", 0, js_point_norm),
|
||||
};
|
||||
|
||||
static int js_point_init(JSContext *ctx, JSModuleDef *m)
|
||||
{
|
||||
JSValue point_proto, point_class;
|
||||
|
||||
/* create the Point class */
|
||||
JS_NewClassID(&js_point_class_id);
|
||||
JS_NewClass(JS_GetRuntime(ctx), js_point_class_id, &js_point_class);
|
||||
|
||||
point_proto = JS_NewObject(ctx);
|
||||
JS_SetPropertyFunctionList(ctx, point_proto, js_point_proto_funcs, countof(js_point_proto_funcs));
|
||||
|
||||
point_class = JS_NewCFunction2(ctx, js_point_ctor, "Point", 2, JS_CFUNC_constructor, 0);
|
||||
/* set proto.constructor and ctor.prototype */
|
||||
JS_SetConstructor(ctx, point_class, point_proto);
|
||||
JS_SetClassProto(ctx, js_point_class_id, point_proto);
|
||||
|
||||
JS_SetModuleExport(ctx, m, "Point", point_class);
|
||||
return 0;
|
||||
}
|
||||
|
||||
JSModuleDef *js_init_module(JSContext *ctx, const char *module_name)
|
||||
{
|
||||
JSModuleDef *m;
|
||||
m = JS_NewCModule(ctx, module_name, js_point_init);
|
||||
if (!m)
|
||||
return NULL;
|
||||
JS_AddModuleExport(ctx, m, "Point");
|
||||
return m;
|
||||
}
|
6
quickjs/examples/test_fib.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
/* example of JS module importing a C module */
|
||||
|
||||
import { fib } from "./fib.so";
|
||||
|
||||
console.log("Hello World");
|
||||
console.log("fib(10)=", fib(10));
|
40
quickjs/examples/test_point.js
Normal file
|
@ -0,0 +1,40 @@
|
|||
/* example of JS module importing a C module */
|
||||
import { Point } from "./point.so";
|
||||
|
||||
function assert(b, str)
|
||||
{
|
||||
if (b) {
|
||||
return;
|
||||
} else {
|
||||
throw Error("assertion failed: " + str);
|
||||
}
|
||||
}
|
||||
|
||||
class ColorPoint extends Point {
|
||||
constructor(x, y, color) {
|
||||
super(x, y);
|
||||
this.color = color;
|
||||
}
|
||||
get_color() {
|
||||
return this.color;
|
||||
}
|
||||
};
|
||||
|
||||
function main()
|
||||
{
|
||||
var pt, pt2;
|
||||
|
||||
pt = new Point(2, 3);
|
||||
assert(pt.x === 2);
|
||||
assert(pt.y === 3);
|
||||
pt.x = 4;
|
||||
assert(pt.x === 4);
|
||||
assert(pt.norm() == 5);
|
||||
|
||||
pt2 = new ColorPoint(2, 3, 0xffffff);
|
||||
assert(pt2.x === 2);
|
||||
assert(pt2.color === 0xffffff);
|
||||
assert(pt2.get_color() === 0xffffff);
|
||||
}
|
||||
|
||||
main();
|
8466
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 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 */
|
58
quickjs/libregexp-opcode.h
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* 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(bne_char_pos, 5) /* pop one stack element and jump if equal to the character
|
||||
position */
|
||||
DEF(prev, 1) /* go to the previous char */
|
||||
DEF(simple_greedy_quant, 17)
|
||||
|
||||
#endif /* DEF */
|
2610
quickjs/libregexp.c
Normal file
92
quickjs/libregexp.h
Normal file
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* 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_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 */
|
4449
quickjs/libunicode-table.h
Normal file
1556
quickjs/libunicode.c
Normal file
124
quickjs/libunicode.h
Normal file
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* 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);
|
||||
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);
|
||||
|
||||
#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 */
|
100
quickjs/list.h
Normal file
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* 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) \
|
||||
((type *)((uint8_t *)(el) - offsetof(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 */
|
570
quickjs/qjs.c
Normal file
|
@ -0,0 +1,570 @@
|
|||
/*
|
||||
* QuickJS stand alone interpreter
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#if defined(__APPLE__)
|
||||
#include <malloc/malloc.h>
|
||||
#elif defined(__linux__)
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
#include "cutils.h"
|
||||
#include "quickjs-libc.h"
|
||||
|
||||
extern const uint8_t qjsc_repl[];
|
||||
extern const uint32_t qjsc_repl_size;
|
||||
#ifdef CONFIG_BIGNUM
|
||||
extern const uint8_t qjsc_qjscalc[];
|
||||
extern const uint32_t qjsc_qjscalc_size;
|
||||
static int bignum_ext;
|
||||
#endif
|
||||
|
||||
static int eval_buf(JSContext *ctx, const void *buf, int buf_len,
|
||||
const char *filename, int eval_flags)
|
||||
{
|
||||
JSValue val;
|
||||
int ret;
|
||||
|
||||
if ((eval_flags & JS_EVAL_TYPE_MASK) == JS_EVAL_TYPE_MODULE) {
|
||||
/* for the modules, we compile then run to be able to set
|
||||
import.meta */
|
||||
val = JS_Eval(ctx, buf, buf_len, filename,
|
||||
eval_flags | JS_EVAL_FLAG_COMPILE_ONLY);
|
||||
if (!JS_IsException(val)) {
|
||||
js_module_set_import_meta(ctx, val, TRUE, TRUE);
|
||||
val = JS_EvalFunction(ctx, val);
|
||||
}
|
||||
} else {
|
||||
val = JS_Eval(ctx, buf, buf_len, filename, eval_flags);
|
||||
}
|
||||
if (JS_IsException(val)) {
|
||||
js_std_dump_error(ctx);
|
||||
ret = -1;
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
JS_FreeValue(ctx, val);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int eval_file(JSContext *ctx, const char *filename, int module)
|
||||
{
|
||||
uint8_t *buf;
|
||||
int ret, eval_flags;
|
||||
size_t buf_len;
|
||||
|
||||
buf = js_load_file(ctx, &buf_len, filename);
|
||||
if (!buf) {
|
||||
perror(filename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (module < 0) {
|
||||
module = (has_suffix(filename, ".mjs") ||
|
||||
JS_DetectModule((const char *)buf, buf_len));
|
||||
}
|
||||
if (module)
|
||||
eval_flags = JS_EVAL_TYPE_MODULE;
|
||||
else
|
||||
eval_flags = JS_EVAL_TYPE_GLOBAL;
|
||||
ret = eval_buf(ctx, buf, buf_len, filename, eval_flags);
|
||||
js_free(ctx, buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* also used to initialize the worker context */
|
||||
static JSContext *JS_NewCustomContext(JSRuntime *rt)
|
||||
{
|
||||
JSContext *ctx;
|
||||
ctx = JS_NewContext(rt);
|
||||
if (!ctx)
|
||||
return NULL;
|
||||
#ifdef CONFIG_BIGNUM
|
||||
if (bignum_ext) {
|
||||
JS_AddIntrinsicBigFloat(ctx);
|
||||
JS_AddIntrinsicBigDecimal(ctx);
|
||||
JS_AddIntrinsicOperators(ctx);
|
||||
JS_EnableBignumExt(ctx, TRUE);
|
||||
}
|
||||
#endif
|
||||
/* system modules */
|
||||
js_init_module_std(ctx, "std");
|
||||
js_init_module_os(ctx, "os");
|
||||
return ctx;
|
||||
}
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#define MALLOC_OVERHEAD 0
|
||||
#else
|
||||
#define MALLOC_OVERHEAD 8
|
||||
#endif
|
||||
|
||||
struct trace_malloc_data {
|
||||
uint8_t *base;
|
||||
};
|
||||
|
||||
static inline unsigned long long js_trace_malloc_ptr_offset(uint8_t *ptr,
|
||||
struct trace_malloc_data *dp)
|
||||
{
|
||||
return ptr - dp->base;
|
||||
}
|
||||
|
||||
/* default memory allocation functions with memory limitation */
|
||||
static inline size_t js_trace_malloc_usable_size(void *ptr)
|
||||
{
|
||||
#if defined(__APPLE__)
|
||||
return malloc_size(ptr);
|
||||
#elif defined(_WIN32)
|
||||
return _msize(ptr);
|
||||
#elif defined(EMSCRIPTEN)
|
||||
return 0;
|
||||
#elif defined(__linux__)
|
||||
return malloc_usable_size(ptr);
|
||||
#else
|
||||
/* change this to `return 0;` if compilation fails */
|
||||
return malloc_usable_size(ptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
#ifdef _WIN32
|
||||
/* mingw printf is used */
|
||||
__attribute__((format(gnu_printf, 2, 3)))
|
||||
#else
|
||||
__attribute__((format(printf, 2, 3)))
|
||||
#endif
|
||||
js_trace_malloc_printf(JSMallocState *s, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int c;
|
||||
|
||||
va_start(ap, fmt);
|
||||
while ((c = *fmt++) != '\0') {
|
||||
if (c == '%') {
|
||||
/* only handle %p and %zd */
|
||||
if (*fmt == 'p') {
|
||||
uint8_t *ptr = va_arg(ap, void *);
|
||||
if (ptr == NULL) {
|
||||
printf("NULL");
|
||||
} else {
|
||||
printf("H%+06lld.%zd",
|
||||
js_trace_malloc_ptr_offset(ptr, s->opaque),
|
||||
js_trace_malloc_usable_size(ptr));
|
||||
}
|
||||
fmt++;
|
||||
continue;
|
||||
}
|
||||
if (fmt[0] == 'z' && fmt[1] == 'd') {
|
||||
size_t sz = va_arg(ap, size_t);
|
||||
printf("%zd", sz);
|
||||
fmt += 2;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
putc(c, stdout);
|
||||
}
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
static void js_trace_malloc_init(struct trace_malloc_data *s)
|
||||
{
|
||||
free(s->base = malloc(8));
|
||||
}
|
||||
|
||||
static void *js_trace_malloc(JSMallocState *s, size_t size)
|
||||
{
|
||||
void *ptr;
|
||||
|
||||
/* Do not allocate zero bytes: behavior is platform dependent */
|
||||
assert(size != 0);
|
||||
|
||||
if (unlikely(s->malloc_size + size > s->malloc_limit))
|
||||
return NULL;
|
||||
ptr = malloc(size);
|
||||
js_trace_malloc_printf(s, "A %zd -> %p\n", size, ptr);
|
||||
if (ptr) {
|
||||
s->malloc_count++;
|
||||
s->malloc_size += js_trace_malloc_usable_size(ptr) + MALLOC_OVERHEAD;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static void js_trace_free(JSMallocState *s, void *ptr)
|
||||
{
|
||||
if (!ptr)
|
||||
return;
|
||||
|
||||
js_trace_malloc_printf(s, "F %p\n", ptr);
|
||||
s->malloc_count--;
|
||||
s->malloc_size -= js_trace_malloc_usable_size(ptr) + MALLOC_OVERHEAD;
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
static void *js_trace_realloc(JSMallocState *s, void *ptr, size_t size)
|
||||
{
|
||||
size_t old_size;
|
||||
|
||||
if (!ptr) {
|
||||
if (size == 0)
|
||||
return NULL;
|
||||
return js_trace_malloc(s, size);
|
||||
}
|
||||
old_size = js_trace_malloc_usable_size(ptr);
|
||||
if (size == 0) {
|
||||
js_trace_malloc_printf(s, "R %zd %p\n", size, ptr);
|
||||
s->malloc_count--;
|
||||
s->malloc_size -= old_size + MALLOC_OVERHEAD;
|
||||
free(ptr);
|
||||
return NULL;
|
||||
}
|
||||
if (s->malloc_size + size - old_size > s->malloc_limit)
|
||||
return NULL;
|
||||
|
||||
js_trace_malloc_printf(s, "R %zd %p", size, ptr);
|
||||
|
||||
ptr = realloc(ptr, size);
|
||||
js_trace_malloc_printf(s, " -> %p\n", ptr);
|
||||
if (ptr) {
|
||||
s->malloc_size += js_trace_malloc_usable_size(ptr) - old_size;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static const JSMallocFunctions trace_mf = {
|
||||
js_trace_malloc,
|
||||
js_trace_free,
|
||||
js_trace_realloc,
|
||||
#if defined(__APPLE__)
|
||||
malloc_size,
|
||||
#elif defined(_WIN32)
|
||||
(size_t (*)(const void *))_msize,
|
||||
#elif defined(EMSCRIPTEN)
|
||||
NULL,
|
||||
#elif defined(__linux__)
|
||||
(size_t (*)(const void *))malloc_usable_size,
|
||||
#else
|
||||
/* change this to `NULL,` if compilation fails */
|
||||
malloc_usable_size,
|
||||
#endif
|
||||
};
|
||||
|
||||
#define PROG_NAME "qjs"
|
||||
|
||||
void help(void)
|
||||
{
|
||||
printf("QuickJS version " CONFIG_VERSION "\n"
|
||||
"usage: " PROG_NAME " [options] [file [args]]\n"
|
||||
"-h --help list options\n"
|
||||
"-e --eval EXPR evaluate EXPR\n"
|
||||
"-i --interactive go to interactive mode\n"
|
||||
"-m --module load as ES6 module (default=autodetect)\n"
|
||||
" --script load as ES6 script (default=autodetect)\n"
|
||||
"-I --include file include an additional file\n"
|
||||
" --std make 'std' and 'os' available to the loaded script\n"
|
||||
#ifdef CONFIG_BIGNUM
|
||||
" --bignum enable the bignum extensions (BigFloat, BigDecimal)\n"
|
||||
" --qjscalc load the QJSCalc runtime (default if invoked as qjscalc)\n"
|
||||
#endif
|
||||
"-T --trace trace memory allocation\n"
|
||||
"-d --dump dump the memory usage stats\n"
|
||||
" --memory-limit n limit the memory usage to 'n' bytes\n"
|
||||
" --stack-size n limit the stack size to 'n' bytes\n"
|
||||
" --unhandled-rejection dump unhandled promise rejections\n"
|
||||
"-q --quit just instantiate the interpreter and quit\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
JSRuntime *rt;
|
||||
JSContext *ctx;
|
||||
struct trace_malloc_data trace_data = { NULL };
|
||||
int optind;
|
||||
char *expr = NULL;
|
||||
int interactive = 0;
|
||||
int dump_memory = 0;
|
||||
int trace_memory = 0;
|
||||
int empty_run = 0;
|
||||
int module = -1;
|
||||
int load_std = 0;
|
||||
int dump_unhandled_promise_rejection = 0;
|
||||
size_t memory_limit = 0;
|
||||
char *include_list[32];
|
||||
int i, include_count = 0;
|
||||
#ifdef CONFIG_BIGNUM
|
||||
int load_jscalc;
|
||||
#endif
|
||||
size_t stack_size = 0;
|
||||
|
||||
#ifdef CONFIG_BIGNUM
|
||||
/* load jscalc runtime if invoked as 'qjscalc' */
|
||||
{
|
||||
const char *p, *exename;
|
||||
exename = argv[0];
|
||||
p = strrchr(exename, '/');
|
||||
if (p)
|
||||
exename = p + 1;
|
||||
load_jscalc = !strcmp(exename, "qjscalc");
|
||||
}
|
||||
#endif
|
||||
|
||||
/* cannot use getopt because we want to pass the command line to
|
||||
the script */
|
||||
optind = 1;
|
||||
while (optind < argc && *argv[optind] == '-') {
|
||||
char *arg = argv[optind] + 1;
|
||||
const char *longopt = "";
|
||||
/* a single - is not an option, it also stops argument scanning */
|
||||
if (!*arg)
|
||||
break;
|
||||
optind++;
|
||||
if (*arg == '-') {
|
||||
longopt = arg + 1;
|
||||
arg += strlen(arg);
|
||||
/* -- stops argument scanning */
|
||||
if (!*longopt)
|
||||
break;
|
||||
}
|
||||
for (; *arg || *longopt; longopt = "") {
|
||||
char opt = *arg;
|
||||
if (opt)
|
||||
arg++;
|
||||
if (opt == 'h' || opt == '?' || !strcmp(longopt, "help")) {
|
||||
help();
|
||||
continue;
|
||||
}
|
||||
if (opt == 'e' || !strcmp(longopt, "eval")) {
|
||||
if (*arg) {
|
||||
expr = arg;
|
||||
break;
|
||||
}
|
||||
if (optind < argc) {
|
||||
expr = argv[optind++];
|
||||
break;
|
||||
}
|
||||
fprintf(stderr, "qjs: missing expression for -e\n");
|
||||
exit(2);
|
||||
}
|
||||
if (opt == 'I' || !strcmp(longopt, "include")) {
|
||||
if (optind >= argc) {
|
||||
fprintf(stderr, "expecting filename");
|
||||
exit(1);
|
||||
}
|
||||
if (include_count >= countof(include_list)) {
|
||||
fprintf(stderr, "too many included files");
|
||||
exit(1);
|
||||
}
|
||||
include_list[include_count++] = argv[optind++];
|
||||
continue;
|
||||
}
|
||||
if (opt == 'i' || !strcmp(longopt, "interactive")) {
|
||||
interactive++;
|
||||
continue;
|
||||
}
|
||||
if (opt == 'm' || !strcmp(longopt, "module")) {
|
||||
module = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(longopt, "script")) {
|
||||
module = 0;
|
||||
continue;
|
||||
}
|
||||
if (opt == 'd' || !strcmp(longopt, "dump")) {
|
||||
dump_memory++;
|
||||
continue;
|
||||
}
|
||||
if (opt == 'T' || !strcmp(longopt, "trace")) {
|
||||
trace_memory++;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(longopt, "std")) {
|
||||
load_std = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(longopt, "unhandled-rejection")) {
|
||||
dump_unhandled_promise_rejection = 1;
|
||||
continue;
|
||||
}
|
||||
#ifdef CONFIG_BIGNUM
|
||||
if (!strcmp(longopt, "bignum")) {
|
||||
bignum_ext = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(longopt, "qjscalc")) {
|
||||
load_jscalc = 1;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
if (opt == 'q' || !strcmp(longopt, "quit")) {
|
||||
empty_run++;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(longopt, "memory-limit")) {
|
||||
if (optind >= argc) {
|
||||
fprintf(stderr, "expecting memory limit");
|
||||
exit(1);
|
||||
}
|
||||
memory_limit = (size_t)strtod(argv[optind++], NULL);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(longopt, "stack-size")) {
|
||||
if (optind >= argc) {
|
||||
fprintf(stderr, "expecting stack size");
|
||||
exit(1);
|
||||
}
|
||||
stack_size = (size_t)strtod(argv[optind++], NULL);
|
||||
continue;
|
||||
}
|
||||
if (opt) {
|
||||
fprintf(stderr, "qjs: unknown option '-%c'\n", opt);
|
||||
} else {
|
||||
fprintf(stderr, "qjs: unknown option '--%s'\n", longopt);
|
||||
}
|
||||
help();
|
||||
}
|
||||
}
|
||||
|
||||
if (load_jscalc)
|
||||
bignum_ext = 1;
|
||||
|
||||
if (trace_memory) {
|
||||
js_trace_malloc_init(&trace_data);
|
||||
rt = JS_NewRuntime2(&trace_mf, &trace_data);
|
||||
} else {
|
||||
rt = JS_NewRuntime();
|
||||
}
|
||||
if (!rt) {
|
||||
fprintf(stderr, "qjs: cannot allocate JS runtime\n");
|
||||
exit(2);
|
||||
}
|
||||
if (memory_limit != 0)
|
||||
JS_SetMemoryLimit(rt, memory_limit);
|
||||
if (stack_size != 0)
|
||||
JS_SetMaxStackSize(rt, stack_size);
|
||||
js_std_set_worker_new_context_func(JS_NewCustomContext);
|
||||
js_std_init_handlers(rt);
|
||||
ctx = JS_NewCustomContext(rt);
|
||||
if (!ctx) {
|
||||
fprintf(stderr, "qjs: cannot allocate JS context\n");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
/* loader for ES6 modules */
|
||||
JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);
|
||||
|
||||
if (dump_unhandled_promise_rejection) {
|
||||
JS_SetHostPromiseRejectionTracker(rt, js_std_promise_rejection_tracker,
|
||||
NULL);
|
||||
}
|
||||
|
||||
if (!empty_run) {
|
||||
#ifdef CONFIG_BIGNUM
|
||||
if (load_jscalc) {
|
||||
js_std_eval_binary(ctx, qjsc_qjscalc, qjsc_qjscalc_size, 0);
|
||||
}
|
||||
#endif
|
||||
js_std_add_helpers(ctx, argc - optind, argv + optind);
|
||||
|
||||
/* make 'std' and 'os' visible to non module code */
|
||||
if (load_std) {
|
||||
const char *str = "import * as std from 'std';\n"
|
||||
"import * as os from 'os';\n"
|
||||
"globalThis.std = std;\n"
|
||||
"globalThis.os = os;\n";
|
||||
eval_buf(ctx, str, strlen(str), "<input>", JS_EVAL_TYPE_MODULE);
|
||||
}
|
||||
|
||||
for(i = 0; i < include_count; i++) {
|
||||
if (eval_file(ctx, include_list[i], module))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (expr) {
|
||||
if (eval_buf(ctx, expr, strlen(expr), "<cmdline>", 0))
|
||||
goto fail;
|
||||
} else
|
||||
if (optind >= argc) {
|
||||
/* interactive mode */
|
||||
interactive = 1;
|
||||
} else {
|
||||
const char *filename;
|
||||
filename = argv[optind];
|
||||
if (eval_file(ctx, filename, module))
|
||||
goto fail;
|
||||
}
|
||||
if (interactive) {
|
||||
js_std_eval_binary(ctx, qjsc_repl, qjsc_repl_size, 0);
|
||||
}
|
||||
js_std_loop(ctx);
|
||||
}
|
||||
|
||||
if (dump_memory) {
|
||||
JSMemoryUsage stats;
|
||||
JS_ComputeMemoryUsage(rt, &stats);
|
||||
JS_DumpMemoryUsage(stdout, &stats, rt);
|
||||
}
|
||||
js_std_free_handlers(rt);
|
||||
JS_FreeContext(ctx);
|
||||
JS_FreeRuntime(rt);
|
||||
|
||||
if (empty_run && dump_memory) {
|
||||
clock_t t[5];
|
||||
double best[5];
|
||||
int i, j;
|
||||
for (i = 0; i < 100; i++) {
|
||||
t[0] = clock();
|
||||
rt = JS_NewRuntime();
|
||||
t[1] = clock();
|
||||
ctx = JS_NewContext(rt);
|
||||
t[2] = clock();
|
||||
JS_FreeContext(ctx);
|
||||
t[3] = clock();
|
||||
JS_FreeRuntime(rt);
|
||||
t[4] = clock();
|
||||
for (j = 4; j > 0; j--) {
|
||||
double ms = 1000.0 * (t[j] - t[j - 1]) / CLOCKS_PER_SEC;
|
||||
if (i == 0 || best[j] > ms)
|
||||
best[j] = ms;
|
||||
}
|
||||
}
|
||||
printf("\nInstantiation times (ms): %.3f = %.3f+%.3f+%.3f+%.3f\n",
|
||||
best[1] + best[2] + best[3] + best[4],
|
||||
best[1], best[2], best[3], best[4]);
|
||||
}
|
||||
return 0;
|
||||
fail:
|
||||
js_std_free_handlers(rt);
|
||||
JS_FreeContext(ctx);
|
||||
JS_FreeRuntime(rt);
|
||||
return 1;
|
||||
}
|
762
quickjs/qjsc.c
Normal file
|
@ -0,0 +1,762 @@
|
|||
/*
|
||||
* QuickJS command line compiler
|
||||
*
|
||||
* Copyright (c) 2018-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.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#if !defined(_WIN32)
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
#include "cutils.h"
|
||||
#include "quickjs-libc.h"
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
char *short_name;
|
||||
int flags;
|
||||
} namelist_entry_t;
|
||||
|
||||
typedef struct namelist_t {
|
||||
namelist_entry_t *array;
|
||||
int count;
|
||||
int size;
|
||||
} namelist_t;
|
||||
|
||||
typedef struct {
|
||||
const char *option_name;
|
||||
const char *init_name;
|
||||
} FeatureEntry;
|
||||
|
||||
static namelist_t cname_list;
|
||||
static namelist_t cmodule_list;
|
||||
static namelist_t init_module_list;
|
||||
static uint64_t feature_bitmap;
|
||||
static FILE *outfile;
|
||||
static BOOL byte_swap;
|
||||
static BOOL dynamic_export;
|
||||
static const char *c_ident_prefix = "qjsc_";
|
||||
|
||||
#define FE_ALL (-1)
|
||||
|
||||
static const FeatureEntry feature_list[] = {
|
||||
{ "date", "Date" },
|
||||
{ "eval", "Eval" },
|
||||
{ "string-normalize", "StringNormalize" },
|
||||
{ "regexp", "RegExp" },
|
||||
{ "json", "JSON" },
|
||||
{ "proxy", "Proxy" },
|
||||
{ "map", "MapSet" },
|
||||
{ "typedarray", "TypedArrays" },
|
||||
{ "promise", "Promise" },
|
||||
#define FE_MODULE_LOADER 9
|
||||
{ "module-loader", NULL },
|
||||
#ifdef CONFIG_BIGNUM
|
||||
{ "bigint", "BigInt" },
|
||||
#endif
|
||||
};
|
||||
|
||||
void namelist_add(namelist_t *lp, const char *name, const char *short_name,
|
||||
int flags)
|
||||
{
|
||||
namelist_entry_t *e;
|
||||
if (lp->count == lp->size) {
|
||||
size_t newsize = lp->size + (lp->size >> 1) + 4;
|
||||
namelist_entry_t *a =
|
||||
realloc(lp->array, sizeof(lp->array[0]) * newsize);
|
||||
/* XXX: check for realloc failure */
|
||||
lp->array = a;
|
||||
lp->size = newsize;
|
||||
}
|
||||
e = &lp->array[lp->count++];
|
||||
e->name = strdup(name);
|
||||
if (short_name)
|
||||
e->short_name = strdup(short_name);
|
||||
else
|
||||
e->short_name = NULL;
|
||||
e->flags = flags;
|
||||
}
|
||||
|
||||
void namelist_free(namelist_t *lp)
|
||||
{
|
||||
while (lp->count > 0) {
|
||||
namelist_entry_t *e = &lp->array[--lp->count];
|
||||
free(e->name);
|
||||
free(e->short_name);
|
||||
}
|
||||
free(lp->array);
|
||||
lp->array = NULL;
|
||||
lp->size = 0;
|
||||
}
|
||||
|
||||
namelist_entry_t *namelist_find(namelist_t *lp, const char *name)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < lp->count; i++) {
|
||||
namelist_entry_t *e = &lp->array[i];
|
||||
if (!strcmp(e->name, name))
|
||||
return e;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void get_c_name(char *buf, size_t buf_size, const char *file)
|
||||
{
|
||||
const char *p, *r;
|
||||
size_t len, i;
|
||||
int c;
|
||||
char *q;
|
||||
|
||||
p = strrchr(file, '/');
|
||||
if (!p)
|
||||
p = file;
|
||||
else
|
||||
p++;
|
||||
r = strrchr(p, '.');
|
||||
if (!r)
|
||||
len = strlen(p);
|
||||
else
|
||||
len = r - p;
|
||||
pstrcpy(buf, buf_size, c_ident_prefix);
|
||||
q = buf + strlen(buf);
|
||||
for(i = 0; i < len; i++) {
|
||||
c = p[i];
|
||||
if (!((c >= '0' && c <= '9') ||
|
||||
(c >= 'A' && c <= 'Z') ||
|
||||
(c >= 'a' && c <= 'z'))) {
|
||||
c = '_';
|
||||
}
|
||||
if ((q - buf) < buf_size - 1)
|
||||
*q++ = c;
|
||||
}
|
||||
*q = '\0';
|
||||
}
|
||||
|
||||
static void dump_hex(FILE *f, const uint8_t *buf, size_t len)
|
||||
{
|
||||
size_t i, col;
|
||||
col = 0;
|
||||
for(i = 0; i < len; i++) {
|
||||
fprintf(f, " 0x%02x,", buf[i]);
|
||||
if (++col == 8) {
|
||||
fprintf(f, "\n");
|
||||
col = 0;
|
||||
}
|
||||
}
|
||||
if (col != 0)
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
|
||||
static void output_object_code(JSContext *ctx,
|
||||
FILE *fo, JSValueConst obj, const char *c_name,
|
||||
BOOL load_only)
|
||||
{
|
||||
uint8_t *out_buf;
|
||||
size_t out_buf_len;
|
||||
int flags;
|
||||
flags = JS_WRITE_OBJ_BYTECODE;
|
||||
if (byte_swap)
|
||||
flags |= JS_WRITE_OBJ_BSWAP;
|
||||
out_buf = JS_WriteObject(ctx, &out_buf_len, obj, flags);
|
||||
if (!out_buf) {
|
||||
js_std_dump_error(ctx);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
namelist_add(&cname_list, c_name, NULL, load_only);
|
||||
|
||||
fprintf(fo, "const uint32_t %s_size = %u;\n\n",
|
||||
c_name, (unsigned int)out_buf_len);
|
||||
fprintf(fo, "const uint8_t %s[%u] = {\n",
|
||||
c_name, (unsigned int)out_buf_len);
|
||||
dump_hex(fo, out_buf, out_buf_len);
|
||||
fprintf(fo, "};\n\n");
|
||||
|
||||
js_free(ctx, out_buf);
|
||||
}
|
||||
|
||||
static int js_module_dummy_init(JSContext *ctx, JSModuleDef *m)
|
||||
{
|
||||
/* should never be called when compiling JS code */
|
||||
abort();
|
||||
}
|
||||
|
||||
static void find_unique_cname(char *cname, size_t cname_size)
|
||||
{
|
||||
char cname1[1024];
|
||||
int suffix_num;
|
||||
size_t len, max_len;
|
||||
assert(cname_size >= 32);
|
||||
/* find a C name not matching an existing module C name by
|
||||
adding a numeric suffix */
|
||||
len = strlen(cname);
|
||||
max_len = cname_size - 16;
|
||||
if (len > max_len)
|
||||
cname[max_len] = '\0';
|
||||
suffix_num = 1;
|
||||
for(;;) {
|
||||
snprintf(cname1, sizeof(cname1), "%s_%d", cname, suffix_num);
|
||||
if (!namelist_find(&cname_list, cname1))
|
||||
break;
|
||||
suffix_num++;
|
||||
}
|
||||
pstrcpy(cname, cname_size, cname1);
|
||||
}
|
||||
|
||||
JSModuleDef *jsc_module_loader(JSContext *ctx,
|
||||
const char *module_name, void *opaque)
|
||||
{
|
||||
JSModuleDef *m;
|
||||
namelist_entry_t *e;
|
||||
|
||||
/* check if it is a declared C or system module */
|
||||
e = namelist_find(&cmodule_list, module_name);
|
||||
if (e) {
|
||||
/* add in the static init module list */
|
||||
namelist_add(&init_module_list, e->name, e->short_name, 0);
|
||||
/* create a dummy module */
|
||||
m = JS_NewCModule(ctx, module_name, js_module_dummy_init);
|
||||
} else if (has_suffix(module_name, ".so")) {
|
||||
fprintf(stderr, "Warning: binary module '%s' will be dynamically loaded\n", module_name);
|
||||
/* create a dummy module */
|
||||
m = JS_NewCModule(ctx, module_name, js_module_dummy_init);
|
||||
/* the resulting executable will export its symbols for the
|
||||
dynamic library */
|
||||
dynamic_export = TRUE;
|
||||
} else {
|
||||
size_t buf_len;
|
||||
uint8_t *buf;
|
||||
JSValue func_val;
|
||||
char cname[1024];
|
||||
|
||||
buf = js_load_file(ctx, &buf_len, module_name);
|
||||
if (!buf) {
|
||||
JS_ThrowReferenceError(ctx, "could not load module filename '%s'",
|
||||
module_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* compile the module */
|
||||
func_val = JS_Eval(ctx, (char *)buf, buf_len, module_name,
|
||||
JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY);
|
||||
js_free(ctx, buf);
|
||||
if (JS_IsException(func_val))
|
||||
return NULL;
|
||||
get_c_name(cname, sizeof(cname), module_name);
|
||||
if (namelist_find(&cname_list, cname)) {
|
||||
find_unique_cname(cname, sizeof(cname));
|
||||
}
|
||||
output_object_code(ctx, outfile, func_val, cname, TRUE);
|
||||
|
||||
/* the module is already referenced, so we must free it */
|
||||
m = JS_VALUE_GET_PTR(func_val);
|
||||
JS_FreeValue(ctx, func_val);
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
static void compile_file(JSContext *ctx, FILE *fo,
|
||||
const char *filename,
|
||||
const char *c_name1,
|
||||
int module)
|
||||
{
|
||||
uint8_t *buf;
|
||||
char c_name[1024];
|
||||
int eval_flags;
|
||||
JSValue obj;
|
||||
size_t buf_len;
|
||||
|
||||
buf = js_load_file(ctx, &buf_len, filename);
|
||||
if (!buf) {
|
||||
fprintf(stderr, "Could not load '%s'\n", filename);
|
||||
exit(1);
|
||||
}
|
||||
eval_flags = JS_EVAL_FLAG_COMPILE_ONLY;
|
||||
if (module < 0) {
|
||||
module = (has_suffix(filename, ".mjs") ||
|
||||
JS_DetectModule((const char *)buf, buf_len));
|
||||
}
|
||||
if (module)
|
||||
eval_flags |= JS_EVAL_TYPE_MODULE;
|
||||
else
|
||||
eval_flags |= JS_EVAL_TYPE_GLOBAL;
|
||||
obj = JS_Eval(ctx, (const char *)buf, buf_len, filename, eval_flags);
|
||||
if (JS_IsException(obj)) {
|
||||
js_std_dump_error(ctx);
|
||||
exit(1);
|
||||
}
|
||||
js_free(ctx, buf);
|
||||
if (c_name1) {
|
||||
pstrcpy(c_name, sizeof(c_name), c_name1);
|
||||
} else {
|
||||
get_c_name(c_name, sizeof(c_name), filename);
|
||||
}
|
||||
output_object_code(ctx, fo, obj, c_name, FALSE);
|
||||
JS_FreeValue(ctx, obj);
|
||||
}
|
||||
|
||||
static const char main_c_template1[] =
|
||||
"int main(int argc, char **argv)\n"
|
||||
"{\n"
|
||||
" JSRuntime *rt;\n"
|
||||
" JSContext *ctx;\n"
|
||||
" rt = JS_NewRuntime();\n"
|
||||
" js_std_set_worker_new_context_func(JS_NewCustomContext);\n"
|
||||
" js_std_init_handlers(rt);\n"
|
||||
;
|
||||
|
||||
static const char main_c_template2[] =
|
||||
" js_std_loop(ctx);\n"
|
||||
" JS_FreeContext(ctx);\n"
|
||||
" JS_FreeRuntime(rt);\n"
|
||||
" return 0;\n"
|
||||
"}\n";
|
||||
|
||||
#define PROG_NAME "qjsc"
|
||||
|
||||
void help(void)
|
||||
{
|
||||
printf("QuickJS Compiler version " CONFIG_VERSION "\n"
|
||||
"usage: " PROG_NAME " [options] [files]\n"
|
||||
"\n"
|
||||
"options are:\n"
|
||||
"-c only output bytecode in a C file\n"
|
||||
"-e output main() and bytecode in a C file (default = executable output)\n"
|
||||
"-o output set the output filename\n"
|
||||
"-N cname set the C name of the generated data\n"
|
||||
"-m compile as Javascript module (default=autodetect)\n"
|
||||
"-D module_name compile a dynamically loaded module or worker\n"
|
||||
"-M module_name[,cname] add initialization code for an external C module\n"
|
||||
"-x byte swapped output\n"
|
||||
"-p prefix set the prefix of the generated C names\n"
|
||||
"-S n set the maximum stack size to 'n' bytes (default=%d)\n",
|
||||
JS_DEFAULT_STACK_SIZE);
|
||||
#ifdef CONFIG_LTO
|
||||
{
|
||||
int i;
|
||||
printf("-flto use link time optimization\n");
|
||||
printf("-fbignum enable bignum extensions\n");
|
||||
printf("-fno-[");
|
||||
for(i = 0; i < countof(feature_list); i++) {
|
||||
if (i != 0)
|
||||
printf("|");
|
||||
printf("%s", feature_list[i].option_name);
|
||||
}
|
||||
printf("]\n"
|
||||
" disable selected language features (smaller code size)\n");
|
||||
}
|
||||
#endif
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_CC) && !defined(_WIN32)
|
||||
|
||||
int exec_cmd(char **argv)
|
||||
{
|
||||
int pid, status, ret;
|
||||
|
||||
pid = fork();
|
||||
if (pid == 0) {
|
||||
execvp(argv[0], argv);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for(;;) {
|
||||
ret = waitpid(pid, &status, 0);
|
||||
if (ret == pid && WIFEXITED(status))
|
||||
break;
|
||||
}
|
||||
return WEXITSTATUS(status);
|
||||
}
|
||||
|
||||
static int output_executable(const char *out_filename, const char *cfilename,
|
||||
BOOL use_lto, BOOL verbose, const char *exename)
|
||||
{
|
||||
const char *argv[64];
|
||||
const char **arg, *bn_suffix, *lto_suffix;
|
||||
char libjsname[1024];
|
||||
char exe_dir[1024], inc_dir[1024], lib_dir[1024], buf[1024], *p;
|
||||
int ret;
|
||||
|
||||
/* get the directory of the executable */
|
||||
pstrcpy(exe_dir, sizeof(exe_dir), exename);
|
||||
p = strrchr(exe_dir, '/');
|
||||
if (p) {
|
||||
*p = '\0';
|
||||
} else {
|
||||
pstrcpy(exe_dir, sizeof(exe_dir), ".");
|
||||
}
|
||||
|
||||
/* if 'quickjs.h' is present at the same path as the executable, we
|
||||
use it as include and lib directory */
|
||||
snprintf(buf, sizeof(buf), "%s/quickjs.h", exe_dir);
|
||||
if (access(buf, R_OK) == 0) {
|
||||
pstrcpy(inc_dir, sizeof(inc_dir), exe_dir);
|
||||
pstrcpy(lib_dir, sizeof(lib_dir), exe_dir);
|
||||
} else {
|
||||
snprintf(inc_dir, sizeof(inc_dir), "%s/include/quickjs", CONFIG_PREFIX);
|
||||
snprintf(lib_dir, sizeof(lib_dir), "%s/lib/quickjs", CONFIG_PREFIX);
|
||||
}
|
||||
|
||||
lto_suffix = "";
|
||||
bn_suffix = "";
|
||||
|
||||
arg = argv;
|
||||
*arg++ = CONFIG_CC;
|
||||
*arg++ = "-O2";
|
||||
#ifdef CONFIG_LTO
|
||||
if (use_lto) {
|
||||
*arg++ = "-flto";
|
||||
lto_suffix = ".lto";
|
||||
}
|
||||
#endif
|
||||
/* XXX: use the executable path to find the includes files and
|
||||
libraries */
|
||||
*arg++ = "-D";
|
||||
*arg++ = "_GNU_SOURCE";
|
||||
*arg++ = "-I";
|
||||
*arg++ = inc_dir;
|
||||
*arg++ = "-o";
|
||||
*arg++ = out_filename;
|
||||
if (dynamic_export)
|
||||
*arg++ = "-rdynamic";
|
||||
*arg++ = cfilename;
|
||||
snprintf(libjsname, sizeof(libjsname), "%s/libquickjs%s%s.a",
|
||||
lib_dir, bn_suffix, lto_suffix);
|
||||
*arg++ = libjsname;
|
||||
*arg++ = "-lm";
|
||||
*arg++ = "-ldl";
|
||||
*arg++ = "-lpthread";
|
||||
*arg = NULL;
|
||||
|
||||
if (verbose) {
|
||||
for(arg = argv; *arg != NULL; arg++)
|
||||
printf("%s ", *arg);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
ret = exec_cmd((char **)argv);
|
||||
unlink(cfilename);
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
static int output_executable(const char *out_filename, const char *cfilename,
|
||||
BOOL use_lto, BOOL verbose, const char *exename)
|
||||
{
|
||||
fprintf(stderr, "Executable output is not supported for this target\n");
|
||||
exit(1);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
typedef enum {
|
||||
OUTPUT_C,
|
||||
OUTPUT_C_MAIN,
|
||||
OUTPUT_EXECUTABLE,
|
||||
} OutputTypeEnum;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int c, i, verbose;
|
||||
const char *out_filename, *cname;
|
||||
char cfilename[1024];
|
||||
FILE *fo;
|
||||
JSRuntime *rt;
|
||||
JSContext *ctx;
|
||||
BOOL use_lto;
|
||||
int module;
|
||||
OutputTypeEnum output_type;
|
||||
size_t stack_size;
|
||||
#ifdef CONFIG_BIGNUM
|
||||
BOOL bignum_ext = FALSE;
|
||||
#endif
|
||||
namelist_t dynamic_module_list;
|
||||
|
||||
out_filename = NULL;
|
||||
output_type = OUTPUT_EXECUTABLE;
|
||||
cname = NULL;
|
||||
feature_bitmap = FE_ALL;
|
||||
module = -1;
|
||||
byte_swap = FALSE;
|
||||
verbose = 0;
|
||||
use_lto = FALSE;
|
||||
stack_size = 0;
|
||||
memset(&dynamic_module_list, 0, sizeof(dynamic_module_list));
|
||||
|
||||
/* add system modules */
|
||||
namelist_add(&cmodule_list, "std", "std", 0);
|
||||
namelist_add(&cmodule_list, "os", "os", 0);
|
||||
|
||||
for(;;) {
|
||||
c = getopt(argc, argv, "ho:cN:f:mxevM:p:S:D:");
|
||||
if (c == -1)
|
||||
break;
|
||||
switch(c) {
|
||||
case 'h':
|
||||
help();
|
||||
case 'o':
|
||||
out_filename = optarg;
|
||||
break;
|
||||
case 'c':
|
||||
output_type = OUTPUT_C;
|
||||
break;
|
||||
case 'e':
|
||||
output_type = OUTPUT_C_MAIN;
|
||||
break;
|
||||
case 'N':
|
||||
cname = optarg;
|
||||
break;
|
||||
case 'f':
|
||||
{
|
||||
const char *p;
|
||||
p = optarg;
|
||||
if (!strcmp(optarg, "lto")) {
|
||||
use_lto = TRUE;
|
||||
} else if (strstart(p, "no-", &p)) {
|
||||
use_lto = TRUE;
|
||||
for(i = 0; i < countof(feature_list); i++) {
|
||||
if (!strcmp(p, feature_list[i].option_name)) {
|
||||
feature_bitmap &= ~((uint64_t)1 << i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == countof(feature_list))
|
||||
goto bad_feature;
|
||||
} else
|
||||
#ifdef CONFIG_BIGNUM
|
||||
if (!strcmp(optarg, "bignum")) {
|
||||
bignum_ext = TRUE;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
bad_feature:
|
||||
fprintf(stderr, "unsupported feature: %s\n", optarg);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'm':
|
||||
module = 1;
|
||||
break;
|
||||
case 'M':
|
||||
{
|
||||
char *p;
|
||||
char path[1024];
|
||||
char cname[1024];
|
||||
pstrcpy(path, sizeof(path), optarg);
|
||||
p = strchr(path, ',');
|
||||
if (p) {
|
||||
*p = '\0';
|
||||
pstrcpy(cname, sizeof(cname), p + 1);
|
||||
} else {
|
||||
get_c_name(cname, sizeof(cname), path);
|
||||
}
|
||||
namelist_add(&cmodule_list, path, cname, 0);
|
||||
}
|
||||
break;
|
||||
case 'D':
|
||||
namelist_add(&dynamic_module_list, optarg, NULL, 0);
|
||||
break;
|
||||
case 'x':
|
||||
byte_swap = TRUE;
|
||||
break;
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
case 'p':
|
||||
c_ident_prefix = optarg;
|
||||
break;
|
||||
case 'S':
|
||||
stack_size = (size_t)strtod(optarg, NULL);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (optind >= argc)
|
||||
help();
|
||||
|
||||
if (!out_filename) {
|
||||
if (output_type == OUTPUT_EXECUTABLE) {
|
||||
out_filename = "a.out";
|
||||
} else {
|
||||
out_filename = "out.c";
|
||||
}
|
||||
}
|
||||
|
||||
if (output_type == OUTPUT_EXECUTABLE) {
|
||||
#if defined(_WIN32) || defined(__ANDROID__)
|
||||
/* XXX: find a /tmp directory ? */
|
||||
snprintf(cfilename, sizeof(cfilename), "out%d.c", getpid());
|
||||
#else
|
||||
snprintf(cfilename, sizeof(cfilename), "/tmp/out%d.c", getpid());
|
||||
#endif
|
||||
} else {
|
||||
pstrcpy(cfilename, sizeof(cfilename), out_filename);
|
||||
}
|
||||
|
||||
fo = fopen(cfilename, "w");
|
||||
if (!fo) {
|
||||
perror(cfilename);
|
||||
exit(1);
|
||||
}
|
||||
outfile = fo;
|
||||
|
||||
rt = JS_NewRuntime();
|
||||
ctx = JS_NewContext(rt);
|
||||
#ifdef CONFIG_BIGNUM
|
||||
if (bignum_ext) {
|
||||
JS_AddIntrinsicBigFloat(ctx);
|
||||
JS_AddIntrinsicBigDecimal(ctx);
|
||||
JS_AddIntrinsicOperators(ctx);
|
||||
JS_EnableBignumExt(ctx, TRUE);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* loader for ES6 modules */
|
||||
JS_SetModuleLoaderFunc(rt, NULL, jsc_module_loader, NULL);
|
||||
|
||||
fprintf(fo, "/* File generated automatically by the QuickJS compiler. */\n"
|
||||
"\n"
|
||||
);
|
||||
|
||||
if (output_type != OUTPUT_C) {
|
||||
fprintf(fo, "#include \"quickjs-libc.h\"\n"
|
||||
"\n"
|
||||
);
|
||||
} else {
|
||||
fprintf(fo, "#include <inttypes.h>\n"
|
||||
"\n"
|
||||
);
|
||||
}
|
||||
|
||||
for(i = optind; i < argc; i++) {
|
||||
const char *filename = argv[i];
|
||||
compile_file(ctx, fo, filename, cname, module);
|
||||
cname = NULL;
|
||||
}
|
||||
|
||||
for(i = 0; i < dynamic_module_list.count; i++) {
|
||||
if (!jsc_module_loader(ctx, dynamic_module_list.array[i].name, NULL)) {
|
||||
fprintf(stderr, "Could not load dynamic module '%s'\n",
|
||||
dynamic_module_list.array[i].name);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (output_type != OUTPUT_C) {
|
||||
fprintf(fo,
|
||||
"static JSContext *JS_NewCustomContext(JSRuntime *rt)\n"
|
||||
"{\n"
|
||||
" JSContext *ctx = JS_NewContextRaw(rt);\n"
|
||||
" if (!ctx)\n"
|
||||
" return NULL;\n");
|
||||
/* add the basic objects */
|
||||
fprintf(fo, " JS_AddIntrinsicBaseObjects(ctx);\n");
|
||||
for(i = 0; i < countof(feature_list); i++) {
|
||||
if ((feature_bitmap & ((uint64_t)1 << i)) &&
|
||||
feature_list[i].init_name) {
|
||||
fprintf(fo, " JS_AddIntrinsic%s(ctx);\n",
|
||||
feature_list[i].init_name);
|
||||
}
|
||||
}
|
||||
#ifdef CONFIG_BIGNUM
|
||||
if (bignum_ext) {
|
||||
fprintf(fo,
|
||||
" JS_AddIntrinsicBigFloat(ctx);\n"
|
||||
" JS_AddIntrinsicBigDecimal(ctx);\n"
|
||||
" JS_AddIntrinsicOperators(ctx);\n"
|
||||
" JS_EnableBignumExt(ctx, 1);\n");
|
||||
}
|
||||
#endif
|
||||
/* add the precompiled modules (XXX: could modify the module
|
||||
loader instead) */
|
||||
for(i = 0; i < init_module_list.count; i++) {
|
||||
namelist_entry_t *e = &init_module_list.array[i];
|
||||
/* initialize the static C modules */
|
||||
|
||||
fprintf(fo,
|
||||
" {\n"
|
||||
" extern JSModuleDef *js_init_module_%s(JSContext *ctx, const char *name);\n"
|
||||
" js_init_module_%s(ctx, \"%s\");\n"
|
||||
" }\n",
|
||||
e->short_name, e->short_name, e->name);
|
||||
}
|
||||
for(i = 0; i < cname_list.count; i++) {
|
||||
namelist_entry_t *e = &cname_list.array[i];
|
||||
if (e->flags) {
|
||||
fprintf(fo, " js_std_eval_binary(ctx, %s, %s_size, 1);\n",
|
||||
e->name, e->name);
|
||||
}
|
||||
}
|
||||
fprintf(fo,
|
||||
" return ctx;\n"
|
||||
"}\n\n");
|
||||
|
||||
fputs(main_c_template1, fo);
|
||||
|
||||
if (stack_size != 0) {
|
||||
fprintf(fo, " JS_SetMaxStackSize(rt, %u);\n",
|
||||
(unsigned int)stack_size);
|
||||
}
|
||||
|
||||
/* add the module loader if necessary */
|
||||
if (feature_bitmap & (1 << FE_MODULE_LOADER)) {
|
||||
fprintf(fo, " JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);\n");
|
||||
}
|
||||
|
||||
fprintf(fo,
|
||||
" ctx = JS_NewCustomContext(rt);\n"
|
||||
" js_std_add_helpers(ctx, argc, argv);\n");
|
||||
|
||||
for(i = 0; i < cname_list.count; i++) {
|
||||
namelist_entry_t *e = &cname_list.array[i];
|
||||
if (!e->flags) {
|
||||
fprintf(fo, " js_std_eval_binary(ctx, %s, %s_size, 0);\n",
|
||||
e->name, e->name);
|
||||
}
|
||||
}
|
||||
fputs(main_c_template2, fo);
|
||||
}
|
||||
|
||||
JS_FreeContext(ctx);
|
||||
JS_FreeRuntime(rt);
|
||||
|
||||
fclose(fo);
|
||||
|
||||
if (output_type == OUTPUT_EXECUTABLE) {
|
||||
return output_executable(out_filename, cfilename, use_lto, verbose,
|
||||
argv[0]);
|
||||
}
|
||||
namelist_free(&cname_list);
|
||||
namelist_free(&cmodule_list);
|
||||
namelist_free(&init_module_list);
|
||||
return 0;
|
||||
}
|
2657
quickjs/qjscalc.js
Normal file
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(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(status, "status")
|
||||
DEF(reason, "reason")
|
||||
DEF(globalThis, "globalThis")
|
||||
#ifdef CONFIG_BIGNUM
|
||||
DEF(bigint, "bigint")
|
||||
DEF(bigfloat, "bigfloat")
|
||||
DEF(bigdecimal, "bigdecimal")
|
||||
DEF(roundingMode, "roundingMode")
|
||||
DEF(maximumSignificantDigits, "maximumSignificantDigits")
|
||||
DEF(maximumFractionDigits, "maximumFractionDigits")
|
||||
#endif
|
||||
#ifdef CONFIG_ATOMICS
|
||||
DEF(not_equal, "not-equal")
|
||||
DEF(timed_out, "timed-out")
|
||||
DEF(ok, "ok")
|
||||
#endif
|
||||
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")
|
||||
#ifdef CONFIG_BIGNUM
|
||||
DEF(BigInt64Array, "BigInt64Array")
|
||||
DEF(BigUint64Array, "BigUint64Array")
|
||||
#endif
|
||||
DEF(Float32Array, "Float32Array")
|
||||
DEF(Float64Array, "Float64Array")
|
||||
DEF(DataView, "DataView")
|
||||
#ifdef CONFIG_BIGNUM
|
||||
DEF(BigInt, "BigInt")
|
||||
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 */
|
3927
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 */
|
365
quickjs/quickjs-opcode.h
Normal file
|
@ -0,0 +1,365 @@
|
|||
/*
|
||||
* 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_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( 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_close_return, 1, 4, 4, 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)
|
||||
#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 */
|
||||
|
||||
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_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, 1, 1, atom_u16) /* obj value ->, 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 */
|
54061
quickjs/quickjs.c
Normal file
1049
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
|
1566
quickjs/repl.js
Normal file
2107
quickjs/run-test262.c
Normal file
209
quickjs/test262.conf
Normal file
|
@ -0,0 +1,209 @@
|
|||
[config]
|
||||
# general settings for test262 ES6 version
|
||||
|
||||
# framework style: old, new
|
||||
style=new
|
||||
|
||||
# handle tests tagged as [noStrict]: yes, no, skip
|
||||
nostrict=yes
|
||||
|
||||
# handle tests tagged as [strictOnly]: yes, no, skip
|
||||
strict=yes
|
||||
|
||||
# test mode: default, default-nostrict, default-strict, strict, nostrict, both, all
|
||||
mode=default
|
||||
|
||||
# handle tests flagged as [async]: yes, no, skip
|
||||
# for these, load 'harness/doneprintHandle.js' prior to test
|
||||
# and expect `print('Test262:AsyncTestComplete')` to be called for
|
||||
# successful termination
|
||||
async=yes
|
||||
|
||||
# handle tests flagged as [module]: yes, no, skip
|
||||
module=yes
|
||||
|
||||
# output error messages: yes, no
|
||||
verbose=yes
|
||||
|
||||
# load harness files from this directory
|
||||
harnessdir=test262/harness
|
||||
|
||||
# names of harness include files to skip
|
||||
#harnessexclude=
|
||||
|
||||
# name of the error file for known errors
|
||||
errorfile=test262_errors.txt
|
||||
|
||||
# exclude tests enumerated in this file (see also [exclude] section)
|
||||
#excludefile=test262_exclude.txt
|
||||
|
||||
# report test results to this file
|
||||
reportfile=test262_report.txt
|
||||
|
||||
# enumerate tests from this directory
|
||||
testdir=test262/test
|
||||
|
||||
[features]
|
||||
# Standard language features and proposed extensions
|
||||
# list the features that are included
|
||||
# skipped features are tagged as such to avoid warnings
|
||||
|
||||
AggregateError
|
||||
align-detached-buffer-semantics-with-web-reality
|
||||
arbitrary-module-namespace-names=skip
|
||||
array-find-from-last=skip
|
||||
Array.prototype.at=skip
|
||||
Array.prototype.flat
|
||||
Array.prototype.flatMap
|
||||
Array.prototype.flatten
|
||||
Array.prototype.values
|
||||
ArrayBuffer
|
||||
arrow-function
|
||||
async-functions
|
||||
async-iteration
|
||||
Atomics
|
||||
Atomics.waitAsync=skip
|
||||
BigInt
|
||||
caller
|
||||
class
|
||||
class-fields-private
|
||||
class-fields-private-in=skip
|
||||
class-fields-public
|
||||
class-methods-private
|
||||
class-static-block=skip
|
||||
class-static-fields-public
|
||||
class-static-fields-private
|
||||
class-static-methods-private
|
||||
cleanupSome=skip
|
||||
coalesce-expression
|
||||
computed-property-names
|
||||
const
|
||||
cross-realm
|
||||
DataView
|
||||
DataView.prototype.getFloat32
|
||||
DataView.prototype.getFloat64
|
||||
DataView.prototype.getInt16
|
||||
DataView.prototype.getInt32
|
||||
DataView.prototype.getInt8
|
||||
DataView.prototype.getUint16
|
||||
DataView.prototype.getUint32
|
||||
DataView.prototype.setUint8
|
||||
default-parameters
|
||||
destructuring-assignment
|
||||
destructuring-binding
|
||||
dynamic-import
|
||||
error-cause=skip
|
||||
export-star-as-namespace-from-module
|
||||
FinalizationGroup=skip
|
||||
FinalizationRegistry=skip
|
||||
FinalizationRegistry.prototype.cleanupSome=skip
|
||||
Float32Array
|
||||
Float64Array
|
||||
for-in-order
|
||||
for-of
|
||||
generators
|
||||
globalThis
|
||||
hashbang
|
||||
host-gc-required=skip
|
||||
import.meta
|
||||
import-assertions=skip
|
||||
Int16Array
|
||||
Int32Array
|
||||
Int8Array
|
||||
IsHTMLDDA
|
||||
json-modules=skip
|
||||
json-superset
|
||||
legacy-regexp=skip
|
||||
let
|
||||
logical-assignment-operators
|
||||
Map
|
||||
new.target
|
||||
numeric-separator-literal
|
||||
object-rest
|
||||
object-spread
|
||||
Object.fromEntries
|
||||
Object.hasOwn
|
||||
Object.is
|
||||
optional-catch-binding
|
||||
optional-chaining
|
||||
Promise
|
||||
Promise.allSettled
|
||||
Promise.any
|
||||
Promise.prototype.finally
|
||||
Proxy
|
||||
proxy-missing-checks
|
||||
Reflect
|
||||
Reflect.construct
|
||||
Reflect.set
|
||||
Reflect.setPrototypeOf
|
||||
regexp-dotall
|
||||
regexp-lookbehind
|
||||
regexp-match-indices=skip
|
||||
regexp-named-groups
|
||||
regexp-unicode-property-escapes
|
||||
resizable-arraybuffer=skip
|
||||
rest-parameters
|
||||
Set
|
||||
ShadowRealm=skip
|
||||
SharedArrayBuffer
|
||||
string-trimming
|
||||
String.fromCodePoint
|
||||
String.prototype.endsWith
|
||||
String.prototype.includes
|
||||
String.prototype.at=skip
|
||||
String.prototype.matchAll
|
||||
String.prototype.replaceAll
|
||||
String.prototype.trimEnd
|
||||
String.prototype.trimStart
|
||||
super
|
||||
Symbol
|
||||
Symbol.asyncIterator
|
||||
Symbol.hasInstance
|
||||
Symbol.isConcatSpreadable
|
||||
Symbol.iterator
|
||||
Symbol.match
|
||||
Symbol.matchAll
|
||||
Symbol.prototype.description
|
||||
Symbol.replace
|
||||
Symbol.search
|
||||
Symbol.species
|
||||
Symbol.split
|
||||
Symbol.toPrimitive
|
||||
Symbol.toStringTag
|
||||
Symbol.unscopables
|
||||
tail-call-optimization=skip
|
||||
template
|
||||
Temporal=skip
|
||||
top-level-await=skip
|
||||
TypedArray
|
||||
TypedArray.prototype.at=skip
|
||||
u180e
|
||||
Uint16Array
|
||||
Uint32Array
|
||||
Uint8Array
|
||||
Uint8ClampedArray
|
||||
WeakMap
|
||||
WeakRef=skip
|
||||
WeakSet
|
||||
well-formed-json-stringify
|
||||
__getter__
|
||||
__proto__
|
||||
__setter__
|
||||
|
||||
[exclude]
|
||||
# list excluded tests and directories here
|
||||
|
||||
# intl not supported
|
||||
test262/test/intl402/
|
||||
|
||||
# incompatible with the "caller" feature
|
||||
test262/test/built-ins/Function/prototype/restricted-property-caller.js
|
||||
test262/test/built-ins/Function/prototype/restricted-property-arguments.js
|
||||
test262/test/built-ins/ThrowTypeError/unique-per-realm-function-proto.js
|
||||
|
||||
# slow tests
|
||||
#test262/test/built-ins/RegExp/CharacterClassEscapes/
|
||||
#test262/test/built-ins/RegExp/property-escapes/
|
||||
|
||||
[tests]
|
||||
# list test files or use config.testdir
|
35
quickjs/test262_errors.txt
Normal file
|
@ -0,0 +1,35 @@
|
|||
test262/test/built-ins/Function/internals/Construct/derived-this-uninitialized-realm.js:20: Test262Error: Expected a ReferenceError but got a ReferenceError
|
||||
test262/test/built-ins/Function/internals/Construct/derived-this-uninitialized-realm.js:20: strict mode: Test262Error: Expected a ReferenceError but got a ReferenceError
|
||||
test262/test/built-ins/RegExp/named-groups/non-unicode-property-names-valid.js:46: SyntaxError: invalid group name
|
||||
test262/test/built-ins/RegExp/named-groups/non-unicode-property-names-valid.js:46: strict mode: SyntaxError: invalid group name
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/BigInt/detached-buffer.js:46: Test262Error: (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/BigInt/detached-buffer.js:46: strict mode: Test262Error: (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/detached-buffer.js:47: Test262Error: (Testing with Float64Array.)
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/detached-buffer.js:47: strict mode: Test262Error: (Testing with Float64Array.)
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/detached-buffer-realm.js:37: strict mode: TypeError: out-of-bound numeric index (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/detached-buffer.js:34: TypeError: cannot convert bigint to number (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/detached-buffer.js:32: strict mode: TypeError: out-of-bound numeric index (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-minus-zero.js:20: Test262Error: Reflect.set("new TA([42n])", "-0", 1n) must return true Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-minus-zero.js:20: strict mode: Test262Error: Reflect.set("new TA([42n])", "-0", 1n) must return true Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-not-integer.js:21: Test262Error: Reflect.set("new TA([42n])", "1.1", 1n) must return true Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-not-integer.js:21: strict mode: Test262Error: Reflect.set("new TA([42n])", "1.1", 1n) must return true Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-out-of-bounds.js:27: Test262Error: Reflect.set("new TA([42n])", "-1", 1n) must return false Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-out-of-bounds.js:27: strict mode: Test262Error: Reflect.set("new TA([42n])", "-1", 1n) must return false Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/tonumber-value-detached-buffer.js:24: Test262Error: Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/tonumber-value-detached-buffer.js:24: strict mode: Test262Error: Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/Set/detached-buffer-realm.js:37: strict mode: TypeError: out-of-bound numeric index (Testing with Float64Array.)
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/Set/detached-buffer.js:32: strict mode: TypeError: out-of-bound numeric index (Testing with Float64Array.)
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-minus-zero.js:22: Test262Error: Reflect.set(sample, "-0", 1) must return true Expected SameValue(«false», «true») to be true (Testing with Float64Array.)
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-minus-zero.js:22: strict mode: Test262Error: Reflect.set(sample, "-0", 1) must return true Expected SameValue(«false», «true») to be true (Testing with Float64Array.)
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-not-integer.js:22: Test262Error: Reflect.set(sample, "1.1", 1) must return true Expected SameValue(«false», «true») to be true (Testing with Float64Array.)
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-not-integer.js:22: strict mode: Test262Error: Reflect.set(sample, "1.1", 1) must return true Expected SameValue(«false», «true») to be true (Testing with Float64Array.)
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-out-of-bounds.js:22: Test262Error: Reflect.set(sample, "-1", 1) must return true Expected SameValue(«false», «true») to be true (Testing with Float64Array.)
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-out-of-bounds.js:22: strict mode: Test262Error: Reflect.set(sample, "-1", 1) must return true Expected SameValue(«false», «true») to be true (Testing with Float64Array.)
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/Set/tonumber-value-detached-buffer.js:39: Test262Error: Expected SameValue(«false», «true») to be true (Testing with Float64Array.)
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/Set/tonumber-value-detached-buffer.js:39: strict mode: Test262Error: Expected SameValue(«false», «true») to be true (Testing with Float64Array.)
|
||||
test262/test/language/expressions/dynamic-import/usage-from-eval.js:26: TypeError: $DONE() not called
|
||||
test262/test/language/expressions/dynamic-import/usage-from-eval.js:26: strict mode: TypeError: $DONE() not called
|
||||
test262/test/language/expressions/optional-chaining/optional-call-preserves-this.js:21: TypeError: cannot read property 'c' of undefined
|
||||
test262/test/language/expressions/optional-chaining/optional-call-preserves-this.js:15: strict mode: TypeError: cannot read property '_b' of undefined
|
||||
test262/test/language/statements/for-of/head-lhs-async-invalid.js:14: unexpected error type: Test262: This statement should not be evaluated.
|
||||
test262/test/language/statements/for-of/head-lhs-async-invalid.js:14: strict mode: unexpected error type: Test262: This statement should not be evaluated.
|
410
quickjs/test262o.conf
Normal file
|
@ -0,0 +1,410 @@
|
|||
[config]
|
||||
# general settings for test262 ES5 version
|
||||
|
||||
# framework style: old, new
|
||||
style=old
|
||||
|
||||
# handle tests tagged as @noStrict: yes, no, skip
|
||||
nostrict=yes
|
||||
|
||||
# handle tests tagged as @strictOnly: yes, no, skip
|
||||
strict=yes
|
||||
|
||||
# test mode: default, default-nostrict, default-strict, strict, nostrict, both, all
|
||||
mode=default
|
||||
|
||||
# output error messages: yes, no
|
||||
verbose=yes
|
||||
|
||||
# load harness files this directory
|
||||
harnessdir=test262o/test/harness
|
||||
|
||||
# name of the error file for known errors
|
||||
errorfile=test262o_errors.txt
|
||||
|
||||
# exclude tests enumerated in this file
|
||||
#excludefile=test262o_excluded.txt
|
||||
|
||||
# report test results to this file
|
||||
reportfile=test262o_report.txt
|
||||
|
||||
# enumerate tests from this directory
|
||||
testdir=test262o/test/suite
|
||||
|
||||
[exclude]
|
||||
# list excluded tests and directories here
|
||||
|
||||
# intl not supported
|
||||
test262o/test/suite/intl402/
|
||||
|
||||
# ES6 != ES5: block scoped function definitions allowed in strict mode
|
||||
test262o/test/suite/bestPractice/Sbp_A1_T1.js
|
||||
test262o/test/suite/bestPractice/Sbp_A2_T1.js
|
||||
test262o/test/suite/bestPractice/Sbp_A2_T2.js
|
||||
test262o/test/suite/bestPractice/Sbp_A3_T1.js
|
||||
test262o/test/suite/bestPractice/Sbp_A3_T2.js
|
||||
test262o/test/suite/bestPractice/Sbp_A4_T1.js
|
||||
test262o/test/suite/bestPractice/Sbp_A4_T2.js
|
||||
test262o/test/suite/bestPractice/Sbp_A5_T2.js
|
||||
|
||||
# ES6 != ES5: `y={x};` is shorthand for `y={x:x}`
|
||||
test262o/test/suite/ch12/12.1/S12.1_A4_T2.js
|
||||
test262o/test/suite/ch12/12.6/12.6.4/S12.6.4_A15.js
|
||||
|
||||
# ES6 != ES5: function length property is configurable
|
||||
test262o/test/suite/ch11/11.4/11.4.1/11.4.1-5-a-28-s.js
|
||||
test262o/test/suite/ch13/13.2/13.2-15-1.js
|
||||
test262o/test/suite/ch15/15.1/15.1.2/15.1.2.1/S15.1.2.1_A4.2.js
|
||||
test262o/test/suite/ch15/15.1/15.1.2/15.1.2.2/S15.1.2.2_A9.2.js
|
||||
test262o/test/suite/ch15/15.1/15.1.2/15.1.2.3/S15.1.2.3_A7.2.js
|
||||
test262o/test/suite/ch15/15.1/15.1.2/15.1.2.4/S15.1.2.4_A2.2.js
|
||||
test262o/test/suite/ch15/15.1/15.1.2/15.1.2.5/S15.1.2.5_A2.2.js
|
||||
test262o/test/suite/ch15/15.1/15.1.3/15.1.3.1/S15.1.3.1_A5.2.js
|
||||
test262o/test/suite/ch15/15.1/15.1.3/15.1.3.2/S15.1.3.2_A5.2.js
|
||||
test262o/test/suite/ch15/15.1/15.1.3/15.1.3.3/S15.1.3.3_A5.2.js
|
||||
test262o/test/suite/ch15/15.1/15.1.3/15.1.3.4/S15.1.3.4_A5.2.js
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-186.js
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-187.js
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-191.js
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-194.js
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-201.js
|
||||
test262o/test/suite/ch15/15.2/15.2.4/15.2.4.2/S15.2.4.2_A9.js
|
||||
test262o/test/suite/ch15/15.2/15.2.4/15.2.4.3/S15.2.4.3_A9.js
|
||||
test262o/test/suite/ch15/15.2/15.2.4/15.2.4.4/S15.2.4.4_A9.js
|
||||
test262o/test/suite/ch15/15.2/15.2.4/15.2.4.5/S15.2.4.5_A9.js
|
||||
test262o/test/suite/ch15/15.2/15.2.4/15.2.4.6/S15.2.4.6_A9.js
|
||||
test262o/test/suite/ch15/15.2/15.2.4/15.2.4.7/S15.2.4.7_A9.js
|
||||
test262o/test/suite/ch15/15.3/15.3.3/15.3.3.2/15.3.3.2-1.js
|
||||
test262o/test/suite/ch15/15.3/15.3.4/15.3.4.2/S15.3.4.2_A9.js
|
||||
test262o/test/suite/ch15/15.3/15.3.4/15.3.4.3/S15.3.4.3_A9.js
|
||||
test262o/test/suite/ch15/15.3/15.3.4/15.3.4.4/S15.3.4.4_A9.js
|
||||
test262o/test/suite/ch15/15.3/15.3.4/15.3.4.5/15.3.4.5-15-2.js
|
||||
test262o/test/suite/ch15/15.3/15.3.5/S15.3.5.1_A2_T1.js
|
||||
test262o/test/suite/ch15/15.3/15.3.5/S15.3.5.1_A2_T2.js
|
||||
test262o/test/suite/ch15/15.3/15.3.5/S15.3.5.1_A2_T3.js
|
||||
test262o/test/suite/ch15/15.4/15.4.3/S15.4.3_A2.2.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.2/S15.4.4.2_A4.2.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.3/S15.4.4.3_A4.2.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.4/S15.4.4.4_A4.2.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.5/S15.4.4.5_A6.2.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.6/S15.4.4.6_A5.2.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.7/S15.4.4.7_A6.2.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.8/S15.4.4.8_A5.2.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.9/S15.4.4.9_A5.2.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.10/S15.4.4.10_A5.2.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.11/S15.4.4.11_A7.2.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.12/S15.4.4.12_A5.2.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.13/S15.4.4.13_A5.2.js
|
||||
test262o/test/suite/ch15/15.5/15.5.4/15.5.4.4/S15.5.4.4_A9.js
|
||||
test262o/test/suite/ch15/15.5/15.5.4/15.5.4.5/S15.5.4.5_A9.js
|
||||
test262o/test/suite/ch15/15.5/15.5.4/15.5.4.6/S15.5.4.6_A9.js
|
||||
test262o/test/suite/ch15/15.5/15.5.4/15.5.4.7/S15.5.4.7_A9.js
|
||||
test262o/test/suite/ch15/15.5/15.5.4/15.5.4.8/S15.5.4.8_A9.js
|
||||
test262o/test/suite/ch15/15.5/15.5.4/15.5.4.9/S15.5.4.9_A9.js
|
||||
test262o/test/suite/ch15/15.5/15.5.4/15.5.4.10/S15.5.4.10_A9.js
|
||||
test262o/test/suite/ch15/15.5/15.5.4/15.5.4.11/S15.5.4.11_A9.js
|
||||
test262o/test/suite/ch15/15.5/15.5.4/15.5.4.12/S15.5.4.12_A9.js
|
||||
test262o/test/suite/ch15/15.5/15.5.4/15.5.4.13/S15.5.4.13_A9.js
|
||||
test262o/test/suite/ch15/15.5/15.5.4/15.5.4.14/S15.5.4.14_A9.js
|
||||
test262o/test/suite/ch15/15.5/15.5.4/15.5.4.15/S15.5.4.15_A9.js
|
||||
test262o/test/suite/ch15/15.5/15.5.4/15.5.4.16/S15.5.4.16_A9.js
|
||||
test262o/test/suite/ch15/15.5/15.5.4/15.5.4.17/S15.5.4.17_A9.js
|
||||
test262o/test/suite/ch15/15.5/15.5.4/15.5.4.18/S15.5.4.18_A9.js
|
||||
test262o/test/suite/ch15/15.5/15.5.4/15.5.4.19/S15.5.4.19_A9.js
|
||||
test262o/test/suite/ch15/15.9/15.9.4/15.9.4.2/S15.9.4.2_A3_T2.js
|
||||
test262o/test/suite/ch15/15.9/15.9.4/15.9.4.3/S15.9.4.3_A3_T2.js
|
||||
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.1/S15.9.5.1_A3_T2.js
|
||||
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.2/S15.9.5.2_A3_T2.js
|
||||
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.3/S15.9.5.3_A3_T2.js
|
||||
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.4/S15.9.5.4_A3_T2.js
|
||||
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.5/S15.9.5.5_A3_T2.js
|
||||
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.6/S15.9.5.6_A3_T2.js
|
||||
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.7/S15.9.5.7_A3_T2.js
|
||||
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.8/S15.9.5.8_A3_T2.js
|
||||
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.9/S15.9.5.9_A3_T2.js
|
||||
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.10/S15.9.5.10_A3_T2.js
|
||||
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.11/S15.9.5.11_A3_T2.js
|
||||
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.12/S15.9.5.12_A3_T2.js
|
||||
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.13/S15.9.5.13_A3_T2.js
|
||||
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.14/S15.9.5.14_A3_T2.js
|
||||
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.15/S15.9.5.15_A3_T2.js
|
||||
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.16/S15.9.5.16_A3_T2.js
|
||||
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.17/S15.9.5.17_A3_T2.js
|
||||
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.18/S15.9.5.18_A3_T2.js
|
||||
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.19/S15.9.5.19_A3_T2.js
|
||||
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.20/S15.9.5.20_A3_T2.js
|
||||
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.21/S15.9.5.21_A3_T2.js
|
||||
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.22/S15.9.5.22_A3_T2.js
|
||||
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.23/S15.9.5.23_A3_T2.js
|
||||
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.24/S15.9.5.24_A3_T2.js
|
||||
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.25/S15.9.5.25_A3_T2.js
|
||||
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.26/S15.9.5.26_A3_T2.js
|
||||
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.27/S15.9.5.27_A3_T2.js
|
||||
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.28/S15.9.5.28_A3_T2.js
|
||||
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.29/S15.9.5.29_A3_T2.js
|
||||
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.30/S15.9.5.30_A3_T2.js
|
||||
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.31/S15.9.5.31_A3_T2.js
|
||||
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.32/S15.9.5.32_A3_T2.js
|
||||
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.33/S15.9.5.33_A3_T2.js
|
||||
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.34/S15.9.5.34_A3_T2.js
|
||||
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.35/S15.9.5.35_A3_T2.js
|
||||
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.36/S15.9.5.36_A3_T2.js
|
||||
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.37/S15.9.5.37_A3_T2.js
|
||||
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.38/S15.9.5.38_A3_T2.js
|
||||
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.39/S15.9.5.39_A3_T2.js
|
||||
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.40/S15.9.5.40_A3_T2.js
|
||||
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.41/S15.9.5.41_A3_T2.js
|
||||
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.42/S15.9.5.42_A3_T2.js
|
||||
test262o/test/suite/ch15/15.10/15.10.6/15.10.6.2/S15.10.6.2_A9.js
|
||||
test262o/test/suite/ch15/15.10/15.10.6/15.10.6.3/S15.10.6.3_A9.js
|
||||
test262o/test/suite/ch15/15.10/15.10.6/15.10.6.4/S15.10.6.4_A9.js
|
||||
|
||||
# ES6 != ES5: object literals may have duplicates
|
||||
test262o/test/suite/ch11/11.1/11.1.5/11.1.5-4-4-a-1-s.js
|
||||
test262o/test/suite/ch11/11.1/11.1.5/11.1.5_4-4-b-1.js
|
||||
test262o/test/suite/ch11/11.1/11.1.5/11.1.5_4-4-b-2.js
|
||||
test262o/test/suite/ch11/11.1/11.1.5/11.1.5_4-4-c-1.js
|
||||
test262o/test/suite/ch11/11.1/11.1.5/11.1.5_4-4-c-2.js
|
||||
test262o/test/suite/ch11/11.1/11.1.5/11.1.5_4-4-d-1.js
|
||||
test262o/test/suite/ch11/11.1/11.1.5/11.1.5_4-4-d-2.js
|
||||
test262o/test/suite/ch11/11.1/11.1.5/11.1.5_4-4-d-3.js
|
||||
test262o/test/suite/ch11/11.1/11.1.5/11.1.5_4-4-d-4.js
|
||||
|
||||
# ES6 != ES5: Date.prototype is no longer an instance of Date
|
||||
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.40/15.9.5.40_1.js
|
||||
|
||||
# ES6 != ES5: Object.getPrototypeOf converts argument to object
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-1-3.js
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-1-4.js
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-1.js
|
||||
|
||||
# ES6 != ES5: Object.getPrototypeOf(NativeError)
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-2-12.js
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-2-13.js
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-2-14.js
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-2-15.js
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-2-16.js
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-2-17.js
|
||||
|
||||
# ES6 != ES5: Object.getOwnPropertyDescriptor converts argument to object
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-1-3.js
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-1-4.js
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-1.js
|
||||
|
||||
# ES6 != ES5: Object.getOwnPropertyNames converts argument to object
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.4/15.2.3.4-1-4.js
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.4/15.2.3.4-1-5.js
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.4/15.2.3.4-1.js
|
||||
|
||||
# ES6 != ES5: Object.seal accepts all types
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.8/15.2.3.8-1-1.js
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.8/15.2.3.8-1-2.js
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.8/15.2.3.8-1-3.js
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.8/15.2.3.8-1-4.js
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.8/15.2.3.8-1.js
|
||||
|
||||
# ES6 != ES5: Object.freeze accepts all types
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.9/15.2.3.9-1-1.js
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.9/15.2.3.9-1-2.js
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.9/15.2.3.9-1-3.js
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.9/15.2.3.9-1-4.js
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.9/15.2.3.9-1.js
|
||||
|
||||
# ES6 != ES5: Object.preventExtensions accepts all types
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.10/15.2.3.10-1-1.js
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.10/15.2.3.10-1-2.js
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.10/15.2.3.10-1-3.js
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.10/15.2.3.10-1-4.js
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.10/15.2.3.10-1.js
|
||||
|
||||
# ES6 != ES5: Object.isSealed accepts all types
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.11/15.2.3.11-1.js
|
||||
|
||||
# ES6 != ES5: Object.isFrozen accepts all types
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.12/15.2.3.12-1-1.js
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.12/15.2.3.12-1-2.js
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.12/15.2.3.12-1-3.js
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.12/15.2.3.12-1-4.js
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.12/15.2.3.12-1.js
|
||||
|
||||
# ES6 != ES5: Object.isExtensible accepts all types
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.13/15.2.3.13-1-1.js
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.13/15.2.3.13-1-2.js
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.13/15.2.3.13-1-3.js
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.13/15.2.3.13-1-4.js
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.13/15.2.3.13-1.js
|
||||
|
||||
# ES6 != ES5: Object.keys converts argument to object
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.14/15.2.3.14-1-1.js
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.14/15.2.3.14-1-2.js
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.14/15.2.3.14-1-3.js
|
||||
|
||||
# ES6 != ES5: source and other properties of RegExp.prototype are not own properties
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-212.js
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-213.js
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-214.js
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-215.js
|
||||
|
||||
# ES6 != ES5: String numeric object properties are enumerated first
|
||||
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.4/15.2.3.4-4-44.js
|
||||
|
||||
# ES6: new RegExp(regex, flags) is valid
|
||||
test262o/test/suite/ch15/15.10/15.10.3/S15.10.3.1_A2_T1.js
|
||||
test262o/test/suite/ch15/15.10/15.10.3/S15.10.3.1_A2_T2.js
|
||||
test262o/test/suite/ch15/15.10/15.10.4/15.10.4.1/15.10.4.1-1.js
|
||||
test262o/test/suite/ch15/15.10/15.10.4/S15.10.4.1_A2_T1.js
|
||||
test262o/test/suite/ch15/15.10/15.10.4/S15.10.4.1_A2_T2.js
|
||||
|
||||
# ES6 != ES5: RegExp.prototype.test behavior
|
||||
test262o/test/suite/ch15/15.10/15.10.6/15.10.6.2/S15.10.6.2_A5_T3.js
|
||||
|
||||
# ES6 != ES5: source, global, ignoreCase, multiline, lastIndex are not data properties
|
||||
# of RegExp objects and RegExp.prototype is not a RegExp object
|
||||
test262o/test/suite/ch15/15.10/15.10.6/15.10.6.js
|
||||
test262o/test/suite/ch15/15.10/15.10.7/15.10.7.1/15.10.7.1-1.js
|
||||
test262o/test/suite/ch15/15.10/15.10.7/15.10.7.1/15.10.7.1-2.js
|
||||
test262o/test/suite/ch15/15.10/15.10.7/15.10.7.1/S15.10.7.1_A8.js
|
||||
test262o/test/suite/ch15/15.10/15.10.7/15.10.7.1/S15.10.7.1_A9.js
|
||||
test262o/test/suite/ch15/15.10/15.10.7/15.10.7.1/S15.10.7.1_A10.js
|
||||
test262o/test/suite/ch15/15.10/15.10.7/15.10.7.2/15.10.7.2-1.js
|
||||
test262o/test/suite/ch15/15.10/15.10.7/15.10.7.2/15.10.7.2-2.js
|
||||
test262o/test/suite/ch15/15.10/15.10.7/15.10.7.2/S15.10.7.2_A8.js
|
||||
test262o/test/suite/ch15/15.10/15.10.7/15.10.7.2/S15.10.7.2_A9.js
|
||||
test262o/test/suite/ch15/15.10/15.10.7/15.10.7.2/S15.10.7.2_A10.js
|
||||
test262o/test/suite/ch15/15.10/15.10.7/15.10.7.3/15.10.7.3-1.js
|
||||
test262o/test/suite/ch15/15.10/15.10.7/15.10.7.3/15.10.7.3-2.js
|
||||
test262o/test/suite/ch15/15.10/15.10.7/15.10.7.3/S15.10.7.3_A8.js
|
||||
test262o/test/suite/ch15/15.10/15.10.7/15.10.7.3/S15.10.7.3_A9.js
|
||||
test262o/test/suite/ch15/15.10/15.10.7/15.10.7.3/S15.10.7.3_A10.js
|
||||
test262o/test/suite/ch15/15.10/15.10.7/15.10.7.4/15.10.7.4-1.js
|
||||
test262o/test/suite/ch15/15.10/15.10.7/15.10.7.4/15.10.7.4-2.js
|
||||
test262o/test/suite/ch15/15.10/15.10.7/15.10.7.4/S15.10.7.4_A8.js
|
||||
test262o/test/suite/ch15/15.10/15.10.7/15.10.7.4/S15.10.7.4_A9.js
|
||||
test262o/test/suite/ch15/15.10/15.10.7/15.10.7.4/S15.10.7.4_A10.js
|
||||
test262o/test/suite/ch15/15.10/15.10.7/15.10.7.5/15.10.7.5-1.js
|
||||
test262o/test/suite/ch15/15.10/15.10.7/15.10.7.5/15.10.7.5-2.js
|
||||
|
||||
# ES6 != ES5: Error.prototype is a normal object
|
||||
test262o/test/suite/ch15/15.11/15.11.4/S15.11.4_A2.js
|
||||
|
||||
# ES6 different ToLength() semantics
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.5/S15.4.4.5_A4_T3.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.6/S15.4.4.6_A2_T2.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.6/S15.4.4.6_A3_T1.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.6/S15.4.4.6_A3_T2.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.6/S15.4.4.6_A3_T3.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.7/S15.4.4.7_A2_T2.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.7/S15.4.4.7_A4_T1.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.7/S15.4.4.7_A4_T3.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.8/S15.4.4.8_A3_T3.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.9/S15.4.4.9_A3_T3.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.10/S15.4.4.10_A3_T1.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.10/S15.4.4.10_A3_T2.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.10/S15.4.4.10_A3_T3.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.11/S15.4.4.11_A4_T3.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.12/S15.4.4.12_A3_T1.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.12/S15.4.4.12_A3_T3.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.13/S15.4.4.13_A3_T2.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.14/15.4.4.14-3-7.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.14/15.4.4.14-3-8.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.14/15.4.4.14-3-12.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.14/15.4.4.14-3-14.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.14/15.4.4.14-3-25.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.14/15.4.4.14-3-28.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.14/15.4.4.14-3-29.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.15/15.4.4.15-3-7.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.15/15.4.4.15-3-12.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.15/15.4.4.15-3-25.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.15/15.4.4.15-3-28.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.16/15.4.4.16-3-7.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.16/15.4.4.16-3-8.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.16/15.4.4.16-3-12.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.16/15.4.4.16-3-14.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.16/15.4.4.16-3-25.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.16/15.4.4.16-3-29.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.17/15.4.4.17-3-7.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.17/15.4.4.17-3-8.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.17/15.4.4.17-3-12.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.17/15.4.4.17-3-14.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.17/15.4.4.17-3-25.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.17/15.4.4.17-3-28.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.17/15.4.4.17-3-29.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.18/15.4.4.18-3-7.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.18/15.4.4.18-3-12.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.18/15.4.4.18-3-25.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.19/15.4.4.19-3-7.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.19/15.4.4.19-3-8.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.19/15.4.4.19-3-12.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.19/15.4.4.19-3-14.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.19/15.4.4.19-3-25.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.19/15.4.4.19-3-28.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.19/15.4.4.19-3-29.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.20/15.4.4.20-3-7.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.20/15.4.4.20-3-12.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.20/15.4.4.20-3-25.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.21/15.4.4.21-3-7.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.21/15.4.4.21-3-12.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.21/15.4.4.21-3-25.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.22/15.4.4.22-3-7.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.22/15.4.4.22-3-12.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.22/15.4.4.22-3-25.js
|
||||
|
||||
# ES6 different ToLength() semantics causes near infinite runtime
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.15/15.4.4.15-3-14.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.18/15.4.4.18-3-14.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.20/15.4.4.20-3-14.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.21/15.4.4.21-3-14.js
|
||||
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.22/15.4.4.22-3-14.js
|
||||
|
||||
# ES6 arguments/caller changes
|
||||
test262o/test/suite/ch10/10.6/10.6-13-b-1-s.js
|
||||
test262o/test/suite/ch10/10.6/10.6-13-b-2-s.js
|
||||
test262o/test/suite/ch10/10.6/10.6-13-b-3-s.js
|
||||
test262o/test/suite/ch10/10.6/10.6-14-1-s.js
|
||||
test262o/test/suite/ch10/10.6/10.6-14-b-1-s.js
|
||||
test262o/test/suite/ch10/10.6/10.6-14-b-4-s.js
|
||||
test262o/test/suite/ch13/13.2/13.2-29-s.js
|
||||
test262o/test/suite/ch13/13.2/13.2-30-s.js
|
||||
test262o/test/suite/ch13/13.2/13.2-31-s.js
|
||||
test262o/test/suite/ch13/13.2/13.2-32-s.js
|
||||
test262o/test/suite/ch13/13.2/13.2-33-s.js
|
||||
test262o/test/suite/ch13/13.2/13.2-34-s.js
|
||||
test262o/test/suite/ch13/13.2/13.2-35-s.js
|
||||
test262o/test/suite/ch13/13.2/13.2-36-s.js
|
||||
test262o/test/suite/ch13/13.2/S13.2.3_A1.js
|
||||
test262o/test/suite/ch15/15.3/15.3.4/15.3.4.5/15.3.4.5-20-1.js
|
||||
test262o/test/suite/ch15/15.3/15.3.4/15.3.4.5/15.3.4.5-20-4.js
|
||||
test262o/test/suite/ch15/15.3/15.3.4/15.3.4.5/15.3.4.5-20-5.js
|
||||
test262o/test/suite/ch15/15.3/15.3.4/15.3.4.5/15.3.4.5-21-1.js
|
||||
test262o/test/suite/ch15/15.3/15.3.4/15.3.4.5/15.3.4.5-21-4.js
|
||||
test262o/test/suite/ch15/15.3/15.3.4/15.3.4.5/15.3.4.5-21-5.js
|
||||
|
||||
# u180e is no longer considered as a space
|
||||
test262o/test/suite/ch09/9.3/9.3.1/S9.3.1_A2.js
|
||||
test262o/test/suite/ch09/9.3/9.3.1/S9.3.1_A3_T1.js
|
||||
test262o/test/suite/ch09/9.3/9.3.1/S9.3.1_A3_T2.js
|
||||
test262o/test/suite/ch15/15.1/15.1.2/15.1.2.2/S15.1.2.2_A2_T10.js
|
||||
test262o/test/suite/ch15/15.1/15.1.2/15.1.2.3/S15.1.2.3_A2_T10.js
|
||||
test262o/test/suite/ch15/15.5/15.5.4/15.5.4.20/15.5.4.20-3-2.js
|
||||
test262o/test/suite/ch15/15.5/15.5.4/15.5.4.20/15.5.4.20-3-3.js
|
||||
test262o/test/suite/ch15/15.5/15.5.4/15.5.4.20/15.5.4.20-3-4.js
|
||||
test262o/test/suite/ch15/15.5/15.5.4/15.5.4.20/15.5.4.20-3-5.js
|
||||
test262o/test/suite/ch15/15.5/15.5.4/15.5.4.20/15.5.4.20-3-6.js
|
||||
test262o/test/suite/ch15/15.10/15.10.2/15.10.2.12/S15.10.2.12_A1_T1.js
|
||||
test262o/test/suite/ch15/15.10/15.10.2/15.10.2.12/S15.10.2.12_A2_T1.js
|
||||
|
||||
# E6 eval return value is different
|
||||
test262o/test/suite/ch12/12.6/12.6.3/S12.6.3_A9.js
|
||||
test262o/test/suite/ch12/12.6/12.6.3/S12.6.3_A9.1.js
|
||||
|
||||
# ECMA 2019 optional-catch-binding feature allows try{}catch{}
|
||||
test262o/test/suite/ch12/12.14/S12.14_A16_T4.js
|
||||
|
||||
# Syntax error instead of ReferenceError in ES2020
|
||||
test262o/test/suite/ch11/11.13/11.13.1/11.13.1-1-1.js
|
||||
test262o/test/suite/ch11/11.13/11.13.1/11.13.1-1-2.js
|
||||
test262o/test/suite/ch11/11.13/11.13.1/11.13.1-1-3.js
|
||||
test262o/test/suite/ch11/11.13/11.13.1/11.13.1-1-4.js
|
||||
|
||||
[tests]
|
||||
# list test files or use config.testdir
|
96
quickjs/tests/bjson.c
Normal file
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* QuickJS: binary JSON module (test only)
|
||||
*
|
||||
* Copyright (c) 2017-2019 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.
|
||||
*/
|
||||
#include "../quickjs-libc.h"
|
||||
#include "../cutils.h"
|
||||
|
||||
static JSValue js_bjson_read(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *argv)
|
||||
{
|
||||
uint8_t *buf;
|
||||
uint64_t pos, len;
|
||||
JSValue obj;
|
||||
size_t size;
|
||||
int flags;
|
||||
|
||||
if (JS_ToIndex(ctx, &pos, argv[1]))
|
||||
return JS_EXCEPTION;
|
||||
if (JS_ToIndex(ctx, &len, argv[2]))
|
||||
return JS_EXCEPTION;
|
||||
buf = JS_GetArrayBuffer(ctx, &size, argv[0]);
|
||||
if (!buf)
|
||||
return JS_EXCEPTION;
|
||||
if (pos + len > size)
|
||||
return JS_ThrowRangeError(ctx, "array buffer overflow");
|
||||
flags = 0;
|
||||
if (JS_ToBool(ctx, argv[3]))
|
||||
flags |= JS_READ_OBJ_REFERENCE;
|
||||
obj = JS_ReadObject(ctx, buf + pos, len, flags);
|
||||
return obj;
|
||||
}
|
||||
|
||||
static JSValue js_bjson_write(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *argv)
|
||||
{
|
||||
size_t len;
|
||||
uint8_t *buf;
|
||||
JSValue array;
|
||||
int flags;
|
||||
|
||||
flags = 0;
|
||||
if (JS_ToBool(ctx, argv[1]))
|
||||
flags |= JS_WRITE_OBJ_REFERENCE;
|
||||
buf = JS_WriteObject(ctx, &len, argv[0], flags);
|
||||
if (!buf)
|
||||
return JS_EXCEPTION;
|
||||
array = JS_NewArrayBufferCopy(ctx, buf, len);
|
||||
js_free(ctx, buf);
|
||||
return array;
|
||||
}
|
||||
|
||||
static const JSCFunctionListEntry js_bjson_funcs[] = {
|
||||
JS_CFUNC_DEF("read", 4, js_bjson_read ),
|
||||
JS_CFUNC_DEF("write", 2, js_bjson_write ),
|
||||
};
|
||||
|
||||
static int js_bjson_init(JSContext *ctx, JSModuleDef *m)
|
||||
{
|
||||
return JS_SetModuleExportList(ctx, m, js_bjson_funcs,
|
||||
countof(js_bjson_funcs));
|
||||
}
|
||||
|
||||
#ifdef JS_SHARED_LIBRARY
|
||||
#define JS_INIT_MODULE js_init_module
|
||||
#else
|
||||
#define JS_INIT_MODULE js_init_module_bjson
|
||||
#endif
|
||||
|
||||
JSModuleDef *JS_INIT_MODULE(JSContext *ctx, const char *module_name)
|
||||
{
|
||||
JSModuleDef *m;
|
||||
m = JS_NewCModule(ctx, module_name, js_bjson_init);
|
||||
if (!m)
|
||||
return NULL;
|
||||
JS_AddModuleExportList(ctx, m, js_bjson_funcs, countof(js_bjson_funcs));
|
||||
return m;
|
||||
}
|
1065
quickjs/tests/microbench.js
Normal file
71
quickjs/tests/test262.patch
Normal file
|
@ -0,0 +1,71 @@
|
|||
diff --git a/harness/atomicsHelper.js b/harness/atomicsHelper.js
|
||||
index 9c1217351e..3c24755558 100644
|
||||
--- a/harness/atomicsHelper.js
|
||||
+++ b/harness/atomicsHelper.js
|
||||
@@ -227,10 +227,14 @@ $262.agent.waitUntil = function(typedArray, index, expected) {
|
||||
* }
|
||||
*/
|
||||
$262.agent.timeouts = {
|
||||
- yield: 100,
|
||||
- small: 200,
|
||||
- long: 1000,
|
||||
- huge: 10000,
|
||||
+// yield: 100,
|
||||
+// small: 200,
|
||||
+// long: 1000,
|
||||
+// huge: 10000,
|
||||
+ yield: 20,
|
||||
+ small: 20,
|
||||
+ long: 100,
|
||||
+ huge: 1000,
|
||||
};
|
||||
|
||||
/**
|
||||
diff --git a/harness/regExpUtils.js b/harness/regExpUtils.js
|
||||
index be7039fda0..7b38abf8df 100644
|
||||
--- a/harness/regExpUtils.js
|
||||
+++ b/harness/regExpUtils.js
|
||||
@@ -6,24 +6,27 @@ description: |
|
||||
defines: [buildString, testPropertyEscapes, matchValidator]
|
||||
---*/
|
||||
|
||||
+if ($262 && typeof $262.codePointRange === "function") {
|
||||
+ /* use C function to build the codePointRange (much faster with
|
||||
+ slow JS engines) */
|
||||
+ codePointRange = $262.codePointRange;
|
||||
+} else {
|
||||
+ codePointRange = function codePointRange(start, end) {
|
||||
+ const codePoints = [];
|
||||
+ let length = 0;
|
||||
+ for (codePoint = start; codePoint < end; codePoint++) {
|
||||
+ codePoints[length++] = codePoint;
|
||||
+ }
|
||||
+ return String.fromCodePoint.apply(null, codePoints);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
function buildString({ loneCodePoints, ranges }) {
|
||||
- const CHUNK_SIZE = 10000;
|
||||
- let result = Reflect.apply(String.fromCodePoint, null, loneCodePoints);
|
||||
- for (let i = 0; i < ranges.length; i++) {
|
||||
- const range = ranges[i];
|
||||
- const start = range[0];
|
||||
- const end = range[1];
|
||||
- const codePoints = [];
|
||||
- for (let length = 0, codePoint = start; codePoint <= end; codePoint++) {
|
||||
- codePoints[length++] = codePoint;
|
||||
- if (length === CHUNK_SIZE) {
|
||||
- result += Reflect.apply(String.fromCodePoint, null, codePoints);
|
||||
- codePoints.length = length = 0;
|
||||
- }
|
||||
+ let result = String.fromCodePoint.apply(null, loneCodePoints);
|
||||
+ for (const [start, end] of ranges) {
|
||||
+ result += codePointRange(start, end + 1);
|
||||
}
|
||||
- result += Reflect.apply(String.fromCodePoint, null, codePoints);
|
||||
- }
|
||||
- return result;
|
||||
+ return result;
|
||||
}
|
||||
|
||||
function testPropertyEscapes(regex, string, expression) {
|
326
quickjs/tests/test_bignum.js
Normal file
|
@ -0,0 +1,326 @@
|
|||
"use strict";
|
||||
|
||||
function assert(actual, expected, message) {
|
||||
if (arguments.length == 1)
|
||||
expected = true;
|
||||
|
||||
if (actual === expected)
|
||||
return;
|
||||
|
||||
if (actual !== null && expected !== null
|
||||
&& typeof actual == 'object' && typeof expected == 'object'
|
||||
&& actual.toString() === expected.toString())
|
||||
return;
|
||||
|
||||
throw Error("assertion failed: got |" + actual + "|" +
|
||||
", expected |" + expected + "|" +
|
||||
(message ? " (" + message + ")" : ""));
|
||||
}
|
||||
|
||||
function assertThrows(err, func)
|
||||
{
|
||||
var ex;
|
||||
ex = false;
|
||||
try {
|
||||
func();
|
||||
} catch(e) {
|
||||
ex = true;
|
||||
assert(e instanceof err);
|
||||
}
|
||||
assert(ex, true, "exception expected");
|
||||
}
|
||||
|
||||
// load more elaborate version of assert if available
|
||||
try { __loadScript("test_assert.js"); } catch(e) {}
|
||||
|
||||
/*----------------*/
|
||||
|
||||
function bigint_pow(a, n)
|
||||
{
|
||||
var r, i;
|
||||
r = 1n;
|
||||
for(i = 0n; i < n; i++)
|
||||
r *= a;
|
||||
return r;
|
||||
}
|
||||
|
||||
/* a must be < b */
|
||||
function test_less(a, b)
|
||||
{
|
||||
assert(a < b);
|
||||
assert(!(b < a));
|
||||
assert(a <= b);
|
||||
assert(!(b <= a));
|
||||
assert(b > a);
|
||||
assert(!(a > b));
|
||||
assert(b >= a);
|
||||
assert(!(a >= b));
|
||||
assert(a != b);
|
||||
assert(!(a == b));
|
||||
}
|
||||
|
||||
/* a must be numerically equal to b */
|
||||
function test_eq(a, b)
|
||||
{
|
||||
assert(a == b);
|
||||
assert(b == a);
|
||||
assert(!(a != b));
|
||||
assert(!(b != a));
|
||||
assert(a <= b);
|
||||
assert(b <= a);
|
||||
assert(!(a < b));
|
||||
assert(a >= b);
|
||||
assert(b >= a);
|
||||
assert(!(a > b));
|
||||
}
|
||||
|
||||
function test_bigint1()
|
||||
{
|
||||
var a, r;
|
||||
|
||||
test_less(2n, 3n);
|
||||
test_eq(3n, 3n);
|
||||
|
||||
test_less(2, 3n);
|
||||
test_eq(3, 3n);
|
||||
|
||||
test_less(2.1, 3n);
|
||||
test_eq(Math.sqrt(4), 2n);
|
||||
|
||||
a = bigint_pow(3n, 100n);
|
||||
assert((a - 1n) != a);
|
||||
assert(a == 515377520732011331036461129765621272702107522001n);
|
||||
assert(a == 0x5a4653ca673768565b41f775d6947d55cf3813d1n);
|
||||
|
||||
r = 1n << 31n;
|
||||
assert(r, 2147483648n, "1 << 31n === 2147483648n");
|
||||
|
||||
r = 1n << 32n;
|
||||
assert(r, 4294967296n, "1 << 32n === 4294967296n");
|
||||
}
|
||||
|
||||
function test_bigint2()
|
||||
{
|
||||
assert(BigInt(""), 0n);
|
||||
assert(BigInt(" 123"), 123n);
|
||||
assert(BigInt(" 123 "), 123n);
|
||||
assertThrows(SyntaxError, () => { BigInt("+") } );
|
||||
assertThrows(SyntaxError, () => { BigInt("-") } );
|
||||
assertThrows(SyntaxError, () => { BigInt("\x00a") } );
|
||||
assertThrows(SyntaxError, () => { BigInt(" 123 r") } );
|
||||
}
|
||||
|
||||
function test_divrem(div1, a, b, q)
|
||||
{
|
||||
var div, divrem, t;
|
||||
div = BigInt[div1];
|
||||
divrem = BigInt[div1 + "rem"];
|
||||
assert(div(a, b) == q);
|
||||
t = divrem(a, b);
|
||||
assert(t[0] == q);
|
||||
assert(a == b * q + t[1]);
|
||||
}
|
||||
|
||||
function test_idiv1(div, a, b, r)
|
||||
{
|
||||
test_divrem(div, a, b, r[0]);
|
||||
test_divrem(div, -a, b, r[1]);
|
||||
test_divrem(div, a, -b, r[2]);
|
||||
test_divrem(div, -a, -b, r[3]);
|
||||
}
|
||||
|
||||
/* QuickJS BigInt extensions */
|
||||
function test_bigint_ext()
|
||||
{
|
||||
var r;
|
||||
assert(BigInt.floorLog2(0n) === -1n);
|
||||
assert(BigInt.floorLog2(7n) === 2n);
|
||||
|
||||
assert(BigInt.sqrt(0xffffffc000000000000000n) === 17592185913343n);
|
||||
r = BigInt.sqrtrem(0xffffffc000000000000000n);
|
||||
assert(r[0] === 17592185913343n);
|
||||
assert(r[1] === 35167191957503n);
|
||||
|
||||
test_idiv1("tdiv", 3n, 2n, [1n, -1n, -1n, 1n]);
|
||||
test_idiv1("fdiv", 3n, 2n, [1n, -2n, -2n, 1n]);
|
||||
test_idiv1("cdiv", 3n, 2n, [2n, -1n, -1n, 2n]);
|
||||
test_idiv1("ediv", 3n, 2n, [1n, -2n, -1n, 2n]);
|
||||
}
|
||||
|
||||
function test_bigfloat()
|
||||
{
|
||||
var e, a, b, sqrt2;
|
||||
|
||||
assert(typeof 1n === "bigint");
|
||||
assert(typeof 1l === "bigfloat");
|
||||
assert(1 == 1.0l);
|
||||
assert(1 !== 1.0l);
|
||||
|
||||
test_less(2l, 3l);
|
||||
test_eq(3l, 3l);
|
||||
|
||||
test_less(2, 3l);
|
||||
test_eq(3, 3l);
|
||||
|
||||
test_less(2.1, 3l);
|
||||
test_eq(Math.sqrt(9), 3l);
|
||||
|
||||
test_less(2n, 3l);
|
||||
test_eq(3n, 3l);
|
||||
|
||||
e = new BigFloatEnv(128);
|
||||
assert(e.prec == 128);
|
||||
a = BigFloat.sqrt(2l, e);
|
||||
assert(a === BigFloat.parseFloat("0x1.6a09e667f3bcc908b2fb1366ea957d3e", 0, e));
|
||||
assert(e.inexact === true);
|
||||
assert(BigFloat.fpRound(a) == 0x1.6a09e667f3bcc908b2fb1366ea95l);
|
||||
|
||||
b = BigFloatEnv.setPrec(BigFloat.sqrt.bind(null, 2), 128);
|
||||
assert(a === b);
|
||||
|
||||
assert(BigFloat.isNaN(BigFloat(NaN)));
|
||||
assert(BigFloat.isFinite(1l));
|
||||
assert(!BigFloat.isFinite(1l/0l));
|
||||
|
||||
assert(BigFloat.abs(-3l) === 3l);
|
||||
assert(BigFloat.sign(-3l) === -1l);
|
||||
|
||||
assert(BigFloat.exp(0.2l) === 1.2214027581601698339210719946396742l);
|
||||
assert(BigFloat.log(3l) === 1.0986122886681096913952452369225256l);
|
||||
assert(BigFloat.pow(2.1l, 1.6l) === 3.277561666451861947162828744873745l);
|
||||
|
||||
assert(BigFloat.sin(-1l) === -0.841470984807896506652502321630299l);
|
||||
assert(BigFloat.cos(1l) === 0.5403023058681397174009366074429766l);
|
||||
assert(BigFloat.tan(0.1l) === 0.10033467208545054505808004578111154l);
|
||||
|
||||
assert(BigFloat.asin(0.3l) === 0.30469265401539750797200296122752915l);
|
||||
assert(BigFloat.acos(0.4l) === 1.1592794807274085998465837940224159l);
|
||||
assert(BigFloat.atan(0.7l) === 0.610725964389208616543758876490236l);
|
||||
assert(BigFloat.atan2(7.1l, -5.1l) === 2.1937053809751415549388104628759813l);
|
||||
|
||||
assert(BigFloat.floor(2.5l) === 2l);
|
||||
assert(BigFloat.ceil(2.5l) === 3l);
|
||||
assert(BigFloat.trunc(-2.5l) === -2l);
|
||||
assert(BigFloat.round(2.5l) === 3l);
|
||||
|
||||
assert(BigFloat.fmod(3l,2l) === 1l);
|
||||
assert(BigFloat.remainder(3l,2l) === -1l);
|
||||
|
||||
/* string conversion */
|
||||
assert((1234.125l).toString(), "1234.125");
|
||||
assert((1234.125l).toFixed(2), "1234.13");
|
||||
assert((1234.125l).toFixed(2, "down"), "1234.12");
|
||||
assert((1234.125l).toExponential(), "1.234125e+3");
|
||||
assert((1234.125l).toExponential(5), "1.23413e+3");
|
||||
assert((1234.125l).toExponential(5, BigFloatEnv.RNDZ), "1.23412e+3");
|
||||
assert((1234.125l).toPrecision(6), "1234.13");
|
||||
assert((1234.125l).toPrecision(6, BigFloatEnv.RNDZ), "1234.12");
|
||||
|
||||
/* string conversion with binary base */
|
||||
assert((0x123.438l).toString(16), "123.438");
|
||||
assert((0x323.438l).toString(16), "323.438");
|
||||
assert((0x723.438l).toString(16), "723.438");
|
||||
assert((0xf23.438l).toString(16), "f23.438");
|
||||
assert((0x123.438l).toFixed(2, BigFloatEnv.RNDNA, 16), "123.44");
|
||||
assert((0x323.438l).toFixed(2, BigFloatEnv.RNDNA, 16), "323.44");
|
||||
assert((0x723.438l).toFixed(2, BigFloatEnv.RNDNA, 16), "723.44");
|
||||
assert((0xf23.438l).toFixed(2, BigFloatEnv.RNDNA, 16), "f23.44");
|
||||
assert((0x0.0000438l).toFixed(6, BigFloatEnv.RNDNA, 16), "0.000044");
|
||||
assert((0x1230000000l).toFixed(1, BigFloatEnv.RNDNA, 16), "1230000000.0");
|
||||
assert((0x123.438l).toPrecision(5, BigFloatEnv.RNDNA, 16), "123.44");
|
||||
assert((0x123.438l).toPrecision(5, BigFloatEnv.RNDZ, 16), "123.43");
|
||||
assert((0x323.438l).toPrecision(5, BigFloatEnv.RNDNA, 16), "323.44");
|
||||
assert((0x723.438l).toPrecision(5, BigFloatEnv.RNDNA, 16), "723.44");
|
||||
assert((-0xf23.438l).toPrecision(5, BigFloatEnv.RNDD, 16), "-f23.44");
|
||||
assert((0x123.438l).toExponential(4, BigFloatEnv.RNDNA, 16), "1.2344p+8");
|
||||
}
|
||||
|
||||
function test_bigdecimal()
|
||||
{
|
||||
assert(1m === 1m);
|
||||
assert(1m !== 2m);
|
||||
test_less(1m, 2m);
|
||||
test_eq(2m, 2m);
|
||||
|
||||
test_less(1, 2m);
|
||||
test_eq(2, 2m);
|
||||
|
||||
test_less(1.1, 2m);
|
||||
test_eq(Math.sqrt(4), 2m);
|
||||
|
||||
test_less(2n, 3m);
|
||||
test_eq(3n, 3m);
|
||||
|
||||
assert(BigDecimal("1234.1") === 1234.1m);
|
||||
assert(BigDecimal(" 1234.1") === 1234.1m);
|
||||
assert(BigDecimal(" 1234.1 ") === 1234.1m);
|
||||
|
||||
assert(BigDecimal(0.1) === 0.1m);
|
||||
assert(BigDecimal(123) === 123m);
|
||||
assert(BigDecimal(true) === 1m);
|
||||
|
||||
assert(123m + 1m === 124m);
|
||||
assert(123m - 1m === 122m);
|
||||
|
||||
assert(3.2m * 3m === 9.6m);
|
||||
assert(10m / 2m === 5m);
|
||||
assertThrows(RangeError, () => { 10m / 3m } );
|
||||
|
||||
assert(10m % 3m === 1m);
|
||||
assert(-10m % 3m === -1m);
|
||||
|
||||
assert(1234.5m ** 3m === 1881365963.625m);
|
||||
assertThrows(RangeError, () => { 2m ** 3.1m } );
|
||||
assertThrows(RangeError, () => { 2m ** -3m } );
|
||||
|
||||
assert(BigDecimal.sqrt(2m,
|
||||
{ roundingMode: "half-even",
|
||||
maximumSignificantDigits: 4 }) === 1.414m);
|
||||
assert(BigDecimal.sqrt(101m,
|
||||
{ roundingMode: "half-even",
|
||||
maximumFractionDigits: 3 }) === 10.050m);
|
||||
assert(BigDecimal.sqrt(0.002m,
|
||||
{ roundingMode: "half-even",
|
||||
maximumFractionDigits: 3 }) === 0.045m);
|
||||
|
||||
assert(BigDecimal.round(3.14159m,
|
||||
{ roundingMode: "half-even",
|
||||
maximumFractionDigits: 3 }) === 3.142m);
|
||||
|
||||
assert(BigDecimal.add(3.14159m, 0.31212m,
|
||||
{ roundingMode: "half-even",
|
||||
maximumFractionDigits: 2 }) === 3.45m);
|
||||
assert(BigDecimal.sub(3.14159m, 0.31212m,
|
||||
{ roundingMode: "down",
|
||||
maximumFractionDigits: 2 }) === 2.82m);
|
||||
assert(BigDecimal.mul(3.14159m, 0.31212m,
|
||||
{ roundingMode: "half-even",
|
||||
maximumFractionDigits: 3 }) === 0.981m);
|
||||
assert(BigDecimal.mod(3.14159m, 0.31211m,
|
||||
{ roundingMode: "half-even",
|
||||
maximumFractionDigits: 4 }) === 0.0205m);
|
||||
assert(BigDecimal.div(20m, 3m,
|
||||
{ roundingMode: "half-even",
|
||||
maximumSignificantDigits: 3 }) === 6.67m);
|
||||
assert(BigDecimal.div(20m, 3m,
|
||||
{ roundingMode: "half-even",
|
||||
maximumFractionDigits: 50 }) ===
|
||||
6.66666666666666666666666666666666666666666666666667m);
|
||||
|
||||
/* string conversion */
|
||||
assert((1234.125m).toString(), "1234.125");
|
||||
assert((1234.125m).toFixed(2), "1234.13");
|
||||
assert((1234.125m).toFixed(2, "down"), "1234.12");
|
||||
assert((1234.125m).toExponential(), "1.234125e+3");
|
||||
assert((1234.125m).toExponential(5), "1.23413e+3");
|
||||
assert((1234.125m).toExponential(5, "down"), "1.23412e+3");
|
||||
assert((1234.125m).toPrecision(6), "1234.13");
|
||||
assert((1234.125m).toPrecision(6, "down"), "1234.12");
|
||||
assert((-1234.125m).toPrecision(6, "floor"), "-1234.13");
|
||||
}
|
||||
|
||||
test_bigint1();
|
||||
test_bigint2();
|
||||
test_bigint_ext();
|
||||
test_bigfloat();
|
||||
test_bigdecimal();
|
191
quickjs/tests/test_bjson.js
Normal file
|
@ -0,0 +1,191 @@
|
|||
import * as bjson from "./bjson.so";
|
||||
|
||||
function assert(actual, expected, message) {
|
||||
if (arguments.length == 1)
|
||||
expected = true;
|
||||
|
||||
if (actual === expected)
|
||||
return;
|
||||
|
||||
if (actual !== null && expected !== null
|
||||
&& typeof actual == 'object' && typeof expected == 'object'
|
||||
&& actual.toString() === expected.toString())
|
||||
return;
|
||||
|
||||
throw Error("assertion failed: got |" + actual + "|" +
|
||||
", expected |" + expected + "|" +
|
||||
(message ? " (" + message + ")" : ""));
|
||||
}
|
||||
|
||||
function toHex(a)
|
||||
{
|
||||
var i, s = "", tab, v;
|
||||
tab = new Uint8Array(a);
|
||||
for(i = 0; i < tab.length; i++) {
|
||||
v = tab[i].toString(16);
|
||||
if (v.length < 2)
|
||||
v = "0" + v;
|
||||
if (i !== 0)
|
||||
s += " ";
|
||||
s += v;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
function isArrayLike(a)
|
||||
{
|
||||
return Array.isArray(a) ||
|
||||
(a instanceof Uint8ClampedArray) ||
|
||||
(a instanceof Uint8Array) ||
|
||||
(a instanceof Uint16Array) ||
|
||||
(a instanceof Uint32Array) ||
|
||||
(a instanceof Int8Array) ||
|
||||
(a instanceof Int16Array) ||
|
||||
(a instanceof Int32Array) ||
|
||||
(a instanceof Float32Array) ||
|
||||
(a instanceof Float64Array);
|
||||
}
|
||||
|
||||
function toStr(a)
|
||||
{
|
||||
var s, i, props, prop;
|
||||
|
||||
switch(typeof(a)) {
|
||||
case "object":
|
||||
if (a === null)
|
||||
return "null";
|
||||
if (a instanceof Date) {
|
||||
s = "Date(" + toStr(a.valueOf()) + ")";
|
||||
} else if (a instanceof Number) {
|
||||
s = "Number(" + toStr(a.valueOf()) + ")";
|
||||
} else if (a instanceof String) {
|
||||
s = "String(" + toStr(a.valueOf()) + ")";
|
||||
} else if (a instanceof Boolean) {
|
||||
s = "Boolean(" + toStr(a.valueOf()) + ")";
|
||||
} else if (isArrayLike(a)) {
|
||||
s = "[";
|
||||
for(i = 0; i < a.length; i++) {
|
||||
if (i != 0)
|
||||
s += ",";
|
||||
s += toStr(a[i]);
|
||||
}
|
||||
s += "]";
|
||||
} else {
|
||||
props = Object.keys(a);
|
||||
s = "{";
|
||||
for(i = 0; i < props.length; i++) {
|
||||
if (i != 0)
|
||||
s += ",";
|
||||
prop = props[i];
|
||||
s += prop + ":" + toStr(a[prop]);
|
||||
}
|
||||
s += "}";
|
||||
}
|
||||
return s;
|
||||
case "undefined":
|
||||
return "undefined";
|
||||
case "string":
|
||||
return a.__quote();
|
||||
case "number":
|
||||
case "bigfloat":
|
||||
if (a == 0 && 1 / a < 0)
|
||||
return "-0";
|
||||
else
|
||||
return a.toString();
|
||||
break;
|
||||
default:
|
||||
return a.toString();
|
||||
}
|
||||
}
|
||||
|
||||
function bjson_test(a)
|
||||
{
|
||||
var buf, r, a_str, r_str;
|
||||
a_str = toStr(a);
|
||||
buf = bjson.write(a);
|
||||
if (0) {
|
||||
print(a_str, "->", toHex(buf));
|
||||
}
|
||||
r = bjson.read(buf, 0, buf.byteLength);
|
||||
r_str = toStr(r);
|
||||
if (a_str != r_str) {
|
||||
print(a_str);
|
||||
print(r_str);
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
/* test multiple references to an object including circular
|
||||
references */
|
||||
function bjson_test_reference()
|
||||
{
|
||||
var array, buf, i, n, array_buffer;
|
||||
n = 16;
|
||||
array = [];
|
||||
for(i = 0; i < n; i++)
|
||||
array[i] = {};
|
||||
array_buffer = new ArrayBuffer(n);
|
||||
for(i = 0; i < n; i++) {
|
||||
array[i].next = array[(i + 1) % n];
|
||||
array[i].idx = i;
|
||||
array[i].typed_array = new Uint8Array(array_buffer, i, 1);
|
||||
}
|
||||
buf = bjson.write(array, true);
|
||||
|
||||
array = bjson.read(buf, 0, buf.byteLength, true);
|
||||
|
||||
/* check the result */
|
||||
for(i = 0; i < n; i++) {
|
||||
assert(array[i].next, array[(i + 1) % n]);
|
||||
assert(array[i].idx, i);
|
||||
assert(array[i].typed_array.buffer, array_buffer);
|
||||
assert(array[i].typed_array.length, 1);
|
||||
assert(array[i].typed_array.byteOffset, i);
|
||||
}
|
||||
}
|
||||
|
||||
function bjson_test_all()
|
||||
{
|
||||
var obj;
|
||||
|
||||
bjson_test({x:1, y:2, if:3});
|
||||
bjson_test([1, 2, 3]);
|
||||
bjson_test([1.0, "aa", true, false, undefined, null, NaN, -Infinity, -0.0]);
|
||||
if (typeof BigInt !== "undefined") {
|
||||
bjson_test([BigInt("1"), -BigInt("0x123456789"),
|
||||
BigInt("0x123456789abcdef123456789abcdef")]);
|
||||
}
|
||||
if (typeof BigFloat !== "undefined") {
|
||||
BigFloatEnv.setPrec(function () {
|
||||
bjson_test([BigFloat("0.1"), BigFloat("-1e30"), BigFloat("0"),
|
||||
BigFloat("-0"), BigFloat("Infinity"), BigFloat("-Infinity"),
|
||||
0.0 / BigFloat("0"), BigFloat.MAX_VALUE,
|
||||
BigFloat.MIN_VALUE]);
|
||||
}, 113, 15);
|
||||
}
|
||||
if (typeof BigDecimal !== "undefined") {
|
||||
bjson_test([BigDecimal("0"),
|
||||
BigDecimal("0.8"), BigDecimal("123321312321321e100"),
|
||||
BigDecimal("-1233213123213214332333223332e100"),
|
||||
BigDecimal("1.233e-1000")]);
|
||||
}
|
||||
|
||||
bjson_test([new Date(1234), new String("abc"), new Number(-12.1), new Boolean(true)]);
|
||||
|
||||
bjson_test(new Int32Array([123123, 222111, -32222]));
|
||||
bjson_test(new Float64Array([123123, 222111.5]));
|
||||
|
||||
/* tested with a circular reference */
|
||||
obj = {};
|
||||
obj.x = obj;
|
||||
try {
|
||||
bjson.write(obj);
|
||||
assert(false);
|
||||
} catch(e) {
|
||||
assert(e instanceof TypeError);
|
||||
}
|
||||
|
||||
bjson_test_reference();
|
||||
}
|
||||
|
||||
bjson_test_all();
|
685
quickjs/tests/test_builtin.js
Normal file
|
@ -0,0 +1,685 @@
|
|||
"use strict";
|
||||
|
||||
function assert(actual, expected, message) {
|
||||
if (arguments.length == 1)
|
||||
expected = true;
|
||||
|
||||
if (actual === expected)
|
||||
return;
|
||||
|
||||
if (actual !== null && expected !== null
|
||||
&& typeof actual == 'object' && typeof expected == 'object'
|
||||
&& actual.toString() === expected.toString())
|
||||
return;
|
||||
|
||||
throw Error("assertion failed: got |" + actual + "|" +
|
||||
", expected |" + expected + "|" +
|
||||
(message ? " (" + message + ")" : ""));
|
||||
}
|
||||
|
||||
function assert_throws(expected_error, func)
|
||||
{
|
||||
var err = false;
|
||||
try {
|
||||
func();
|
||||
} catch(e) {
|
||||
err = true;
|
||||
if (!(e instanceof expected_error)) {
|
||||
throw Error("unexpected exception type");
|
||||
}
|
||||
}
|
||||
if (!err) {
|
||||
throw Error("expected exception");
|
||||
}
|
||||
}
|
||||
|
||||
// load more elaborate version of assert if available
|
||||
try { __loadScript("test_assert.js"); } catch(e) {}
|
||||
|
||||
/*----------------*/
|
||||
|
||||
function my_func(a, b)
|
||||
{
|
||||
return a + b;
|
||||
}
|
||||
|
||||
function test_function()
|
||||
{
|
||||
function f(a, b) {
|
||||
var i, tab = [];
|
||||
tab.push(this);
|
||||
for(i = 0; i < arguments.length; i++)
|
||||
tab.push(arguments[i]);
|
||||
return tab;
|
||||
}
|
||||
function constructor1(a) {
|
||||
this.x = a;
|
||||
}
|
||||
|
||||
var r, g;
|
||||
|
||||
r = my_func.call(null, 1, 2);
|
||||
assert(r, 3, "call");
|
||||
|
||||
r = my_func.apply(null, [1, 2]);
|
||||
assert(r, 3, "apply");
|
||||
|
||||
r = (function () { return 1; }).apply(null, undefined);
|
||||
assert(r, 1);
|
||||
|
||||
assert_throws(TypeError, (function() {
|
||||
Reflect.apply((function () { return 1; }), null, undefined);
|
||||
}));
|
||||
|
||||
r = new Function("a", "b", "return a + b;");
|
||||
assert(r(2,3), 5, "function");
|
||||
|
||||
g = f.bind(1, 2);
|
||||
assert(g.length, 1);
|
||||
assert(g.name, "bound f");
|
||||
assert(g(3), [1,2,3]);
|
||||
|
||||
g = constructor1.bind(null, 1);
|
||||
r = new g();
|
||||
assert(r.x, 1);
|
||||
}
|
||||
|
||||
function test()
|
||||
{
|
||||
var r, a, b, c, err;
|
||||
|
||||
r = Error("hello");
|
||||
assert(r.message, "hello", "Error");
|
||||
|
||||
a = new Object();
|
||||
a.x = 1;
|
||||
assert(a.x, 1, "Object");
|
||||
|
||||
assert(Object.getPrototypeOf(a), Object.prototype, "getPrototypeOf");
|
||||
Object.defineProperty(a, "y", { value: 3, writable: true, configurable: true, enumerable: true });
|
||||
assert(a.y, 3, "defineProperty");
|
||||
|
||||
Object.defineProperty(a, "z", { get: function () { return 4; }, set: function(val) { this.z_val = val; }, configurable: true, enumerable: true });
|
||||
assert(a.z, 4, "get");
|
||||
a.z = 5;
|
||||
assert(a.z_val, 5, "set");
|
||||
|
||||
a = { get z() { return 4; }, set z(val) { this.z_val = val; } };
|
||||
assert(a.z, 4, "get");
|
||||
a.z = 5;
|
||||
assert(a.z_val, 5, "set");
|
||||
|
||||
b = Object.create(a);
|
||||
assert(Object.getPrototypeOf(b), a, "create");
|
||||
c = {u:2};
|
||||
/* XXX: refcount bug in 'b' instead of 'a' */
|
||||
Object.setPrototypeOf(a, c);
|
||||
assert(Object.getPrototypeOf(a), c, "setPrototypeOf");
|
||||
|
||||
a = {};
|
||||
assert(a.toString(), "[object Object]", "toString");
|
||||
|
||||
a = {x:1};
|
||||
assert(Object.isExtensible(a), true, "extensible");
|
||||
Object.preventExtensions(a);
|
||||
|
||||
err = false;
|
||||
try {
|
||||
a.y = 2;
|
||||
} catch(e) {
|
||||
err = true;
|
||||
}
|
||||
assert(Object.isExtensible(a), false, "extensible");
|
||||
assert(typeof a.y, "undefined", "extensible");
|
||||
assert(err, true, "extensible");
|
||||
}
|
||||
|
||||
function test_enum()
|
||||
{
|
||||
var a, tab;
|
||||
a = {x:1,
|
||||
"18014398509481984": 1,
|
||||
"9007199254740992": 1,
|
||||
"9007199254740991": 1,
|
||||
"4294967296": 1,
|
||||
"4294967295": 1,
|
||||
y:1,
|
||||
"4294967294": 1,
|
||||
"1": 2};
|
||||
tab = Object.keys(a);
|
||||
// console.log("tab=" + tab.toString());
|
||||
assert(tab, ["1","4294967294","x","18014398509481984","9007199254740992","9007199254740991","4294967296","4294967295","y"], "keys");
|
||||
}
|
||||
|
||||
function test_array()
|
||||
{
|
||||
var a, err;
|
||||
|
||||
a = [1, 2, 3];
|
||||
assert(a.length, 3, "array");
|
||||
assert(a[2], 3, "array1");
|
||||
|
||||
a = new Array(10);
|
||||
assert(a.length, 10, "array2");
|
||||
|
||||
a = new Array(1, 2);
|
||||
assert(a.length === 2 && a[0] === 1 && a[1] === 2, true, "array3");
|
||||
|
||||
a = [1, 2, 3];
|
||||
a.length = 2;
|
||||
assert(a.length === 2 && a[0] === 1 && a[1] === 2, true, "array4");
|
||||
|
||||
a = [];
|
||||
a[1] = 10;
|
||||
a[4] = 3;
|
||||
assert(a.length, 5);
|
||||
|
||||
a = [1,2];
|
||||
a.length = 5;
|
||||
a[4] = 1;
|
||||
a.length = 4;
|
||||
assert(a[4] !== 1, true, "array5");
|
||||
|
||||
a = [1,2];
|
||||
a.push(3,4);
|
||||
assert(a.join(), "1,2,3,4", "join");
|
||||
|
||||
a = [1,2,3,4,5];
|
||||
Object.defineProperty(a, "3", { configurable: false });
|
||||
err = false;
|
||||
try {
|
||||
a.length = 2;
|
||||
} catch(e) {
|
||||
err = true;
|
||||
}
|
||||
assert(err && a.toString() === "1,2,3,4");
|
||||
}
|
||||
|
||||
function test_string()
|
||||
{
|
||||
var a;
|
||||
a = String("abc");
|
||||
assert(a.length, 3, "string");
|
||||
assert(a[1], "b", "string");
|
||||
assert(a.charCodeAt(1), 0x62, "string");
|
||||
assert(String.fromCharCode(65), "A", "string");
|
||||
assert(String.fromCharCode.apply(null, [65, 66, 67]), "ABC", "string");
|
||||
assert(a.charAt(1), "b");
|
||||
assert(a.charAt(-1), "");
|
||||
assert(a.charAt(3), "");
|
||||
|
||||
a = "abcd";
|
||||
assert(a.substring(1, 3), "bc", "substring");
|
||||
a = String.fromCharCode(0x20ac);
|
||||
assert(a.charCodeAt(0), 0x20ac, "unicode");
|
||||
assert(a, "€", "unicode");
|
||||
assert(a, "\u20ac", "unicode");
|
||||
assert(a, "\u{20ac}", "unicode");
|
||||
assert("a", "\x61", "unicode");
|
||||
|
||||
a = "\u{10ffff}";
|
||||
assert(a.length, 2, "unicode");
|
||||
assert(a, "\u{dbff}\u{dfff}", "unicode");
|
||||
assert(a.codePointAt(0), 0x10ffff);
|
||||
assert(String.fromCodePoint(0x10ffff), a);
|
||||
|
||||
assert("a".concat("b", "c"), "abc");
|
||||
|
||||
assert("abcabc".indexOf("cab"), 2);
|
||||
assert("abcabc".indexOf("cab2"), -1);
|
||||
assert("abc".indexOf("c"), 2);
|
||||
|
||||
assert("aaa".indexOf("a"), 0);
|
||||
assert("aaa".indexOf("a", NaN), 0);
|
||||
assert("aaa".indexOf("a", -Infinity), 0);
|
||||
assert("aaa".indexOf("a", -1), 0);
|
||||
assert("aaa".indexOf("a", -0), 0);
|
||||
assert("aaa".indexOf("a", 0), 0);
|
||||
assert("aaa".indexOf("a", 1), 1);
|
||||
assert("aaa".indexOf("a", 2), 2);
|
||||
assert("aaa".indexOf("a", 3), -1);
|
||||
assert("aaa".indexOf("a", 4), -1);
|
||||
assert("aaa".indexOf("a", Infinity), -1);
|
||||
|
||||
assert("aaa".indexOf(""), 0);
|
||||
assert("aaa".indexOf("", NaN), 0);
|
||||
assert("aaa".indexOf("", -Infinity), 0);
|
||||
assert("aaa".indexOf("", -1), 0);
|
||||
assert("aaa".indexOf("", -0), 0);
|
||||
assert("aaa".indexOf("", 0), 0);
|
||||
assert("aaa".indexOf("", 1), 1);
|
||||
assert("aaa".indexOf("", 2), 2);
|
||||
assert("aaa".indexOf("", 3), 3);
|
||||
assert("aaa".indexOf("", 4), 3);
|
||||
assert("aaa".indexOf("", Infinity), 3);
|
||||
|
||||
assert("aaa".lastIndexOf("a"), 2);
|
||||
assert("aaa".lastIndexOf("a", NaN), 2);
|
||||
assert("aaa".lastIndexOf("a", -Infinity), 0);
|
||||
assert("aaa".lastIndexOf("a", -1), 0);
|
||||
assert("aaa".lastIndexOf("a", -0), 0);
|
||||
assert("aaa".lastIndexOf("a", 0), 0);
|
||||
assert("aaa".lastIndexOf("a", 1), 1);
|
||||
assert("aaa".lastIndexOf("a", 2), 2);
|
||||
assert("aaa".lastIndexOf("a", 3), 2);
|
||||
assert("aaa".lastIndexOf("a", 4), 2);
|
||||
assert("aaa".lastIndexOf("a", Infinity), 2);
|
||||
|
||||
assert("aaa".lastIndexOf(""), 3);
|
||||
assert("aaa".lastIndexOf("", NaN), 3);
|
||||
assert("aaa".lastIndexOf("", -Infinity), 0);
|
||||
assert("aaa".lastIndexOf("", -1), 0);
|
||||
assert("aaa".lastIndexOf("", -0), 0);
|
||||
assert("aaa".lastIndexOf("", 0), 0);
|
||||
assert("aaa".lastIndexOf("", 1), 1);
|
||||
assert("aaa".lastIndexOf("", 2), 2);
|
||||
assert("aaa".lastIndexOf("", 3), 3);
|
||||
assert("aaa".lastIndexOf("", 4), 3);
|
||||
assert("aaa".lastIndexOf("", Infinity), 3);
|
||||
|
||||
assert("a,b,c".split(","), ["a","b","c"]);
|
||||
assert(",b,c".split(","), ["","b","c"]);
|
||||
assert("a,b,".split(","), ["a","b",""]);
|
||||
|
||||
assert("aaaa".split(), [ "aaaa" ]);
|
||||
assert("aaaa".split(undefined, 0), [ ]);
|
||||
assert("aaaa".split(""), [ "a", "a", "a", "a" ]);
|
||||
assert("aaaa".split("", 0), [ ]);
|
||||
assert("aaaa".split("", 1), [ "a" ]);
|
||||
assert("aaaa".split("", 2), [ "a", "a" ]);
|
||||
assert("aaaa".split("a"), [ "", "", "", "", "" ]);
|
||||
assert("aaaa".split("a", 2), [ "", "" ]);
|
||||
assert("aaaa".split("aa"), [ "", "", "" ]);
|
||||
assert("aaaa".split("aa", 0), [ ]);
|
||||
assert("aaaa".split("aa", 1), [ "" ]);
|
||||
assert("aaaa".split("aa", 2), [ "", "" ]);
|
||||
assert("aaaa".split("aaa"), [ "", "a" ]);
|
||||
assert("aaaa".split("aaaa"), [ "", "" ]);
|
||||
assert("aaaa".split("aaaaa"), [ "aaaa" ]);
|
||||
assert("aaaa".split("aaaaa", 0), [ ]);
|
||||
assert("aaaa".split("aaaaa", 1), [ "aaaa" ]);
|
||||
|
||||
assert(eval('"\0"'), "\0");
|
||||
|
||||
assert("abc".padStart(Infinity, ""), "abc");
|
||||
}
|
||||
|
||||
function test_math()
|
||||
{
|
||||
var a;
|
||||
a = 1.4;
|
||||
assert(Math.floor(a), 1);
|
||||
assert(Math.ceil(a), 2);
|
||||
assert(Math.imul(0x12345678, 123), -1088058456);
|
||||
assert(Math.fround(0.1), 0.10000000149011612);
|
||||
assert(Math.hypot() == 0);
|
||||
assert(Math.hypot(-2) == 2);
|
||||
assert(Math.hypot(3, 4) == 5);
|
||||
assert(Math.abs(Math.hypot(3, 4, 5) - 7.0710678118654755) <= 1e-15);
|
||||
}
|
||||
|
||||
function test_number()
|
||||
{
|
||||
assert(parseInt("123"), 123);
|
||||
assert(parseInt(" 123r"), 123);
|
||||
assert(parseInt("0x123"), 0x123);
|
||||
assert(parseInt("0o123"), 0);
|
||||
assert(+" 123 ", 123);
|
||||
assert(+"0b111", 7);
|
||||
assert(+"0o123", 83);
|
||||
assert(parseFloat("0x1234"), 0);
|
||||
assert(parseFloat("Infinity"), Infinity);
|
||||
assert(parseFloat("-Infinity"), -Infinity);
|
||||
assert(parseFloat("123.2"), 123.2);
|
||||
assert(parseFloat("123.2e3"), 123200);
|
||||
assert(Number.isNaN(Number("+")));
|
||||
assert(Number.isNaN(Number("-")));
|
||||
assert(Number.isNaN(Number("\x00a")));
|
||||
|
||||
assert((25).toExponential(0), "3e+1");
|
||||
assert((-25).toExponential(0), "-3e+1");
|
||||
assert((2.5).toPrecision(1), "3");
|
||||
assert((-2.5).toPrecision(1), "-3");
|
||||
assert((1.125).toFixed(2), "1.13");
|
||||
assert((-1.125).toFixed(2), "-1.13");
|
||||
}
|
||||
|
||||
function test_eval2()
|
||||
{
|
||||
var g_call_count = 0;
|
||||
/* force non strict mode for f1 and f2 */
|
||||
var f1 = new Function("eval", "eval(1, 2)");
|
||||
var f2 = new Function("eval", "eval(...[1, 2])");
|
||||
function g(a, b) {
|
||||
assert(a, 1);
|
||||
assert(b, 2);
|
||||
g_call_count++;
|
||||
}
|
||||
f1(g);
|
||||
f2(g);
|
||||
assert(g_call_count, 2);
|
||||
}
|
||||
|
||||
function test_eval()
|
||||
{
|
||||
function f(b) {
|
||||
var x = 1;
|
||||
return eval(b);
|
||||
}
|
||||
var r, a;
|
||||
|
||||
r = eval("1+1;");
|
||||
assert(r, 2, "eval");
|
||||
|
||||
r = eval("var my_var=2; my_var;");
|
||||
assert(r, 2, "eval");
|
||||
assert(typeof my_var, "undefined");
|
||||
|
||||
assert(eval("if (1) 2; else 3;"), 2);
|
||||
assert(eval("if (0) 2; else 3;"), 3);
|
||||
|
||||
assert(f.call(1, "this"), 1);
|
||||
|
||||
a = 2;
|
||||
assert(eval("a"), 2);
|
||||
|
||||
eval("a = 3");
|
||||
assert(a, 3);
|
||||
|
||||
assert(f("arguments.length", 1), 2);
|
||||
assert(f("arguments[1]", 1), 1);
|
||||
|
||||
a = 4;
|
||||
assert(f("a"), 4);
|
||||
f("a=3");
|
||||
assert(a, 3);
|
||||
|
||||
test_eval2();
|
||||
}
|
||||
|
||||
function test_typed_array()
|
||||
{
|
||||
var buffer, a, i, str;
|
||||
|
||||
a = new Uint8Array(4);
|
||||
assert(a.length, 4);
|
||||
for(i = 0; i < a.length; i++)
|
||||
a[i] = i;
|
||||
assert(a.join(","), "0,1,2,3");
|
||||
a[0] = -1;
|
||||
assert(a[0], 255);
|
||||
|
||||
a = new Int8Array(3);
|
||||
a[0] = 255;
|
||||
assert(a[0], -1);
|
||||
|
||||
a = new Int32Array(3);
|
||||
a[0] = Math.pow(2, 32) - 1;
|
||||
assert(a[0], -1);
|
||||
assert(a.BYTES_PER_ELEMENT, 4);
|
||||
|
||||
a = new Uint8ClampedArray(4);
|
||||
a[0] = -100;
|
||||
a[1] = 1.5;
|
||||
a[2] = 0.5;
|
||||
a[3] = 1233.5;
|
||||
assert(a.toString(), "0,2,0,255");
|
||||
|
||||
buffer = new ArrayBuffer(16);
|
||||
assert(buffer.byteLength, 16);
|
||||
a = new Uint32Array(buffer, 12, 1);
|
||||
assert(a.length, 1);
|
||||
a[0] = -1;
|
||||
|
||||
a = new Uint16Array(buffer, 2);
|
||||
a[0] = -1;
|
||||
|
||||
a = new Float32Array(buffer, 8, 1);
|
||||
a[0] = 1;
|
||||
|
||||
a = new Uint8Array(buffer);
|
||||
|
||||
str = a.toString();
|
||||
/* test little and big endian cases */
|
||||
if (str !== "0,0,255,255,0,0,0,0,0,0,128,63,255,255,255,255" &&
|
||||
str !== "0,0,255,255,0,0,0,0,63,128,0,0,255,255,255,255") {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
assert(a.buffer, buffer);
|
||||
|
||||
a = new Uint8Array([1, 2, 3, 4]);
|
||||
assert(a.toString(), "1,2,3,4");
|
||||
a.set([10, 11], 2);
|
||||
assert(a.toString(), "1,2,10,11");
|
||||
}
|
||||
|
||||
function test_json()
|
||||
{
|
||||
var a, s;
|
||||
s = '{"x":1,"y":true,"z":null,"a":[1,2,3],"s":"str"}';
|
||||
a = JSON.parse(s);
|
||||
assert(a.x, 1);
|
||||
assert(a.y, true);
|
||||
assert(a.z, null);
|
||||
assert(JSON.stringify(a), s);
|
||||
|
||||
/* indentation test */
|
||||
assert(JSON.stringify([[{x:1,y:{},z:[]},2,3]],undefined,1),
|
||||
`[
|
||||
[
|
||||
{
|
||||
"x": 1,
|
||||
"y": {},
|
||||
"z": []
|
||||
},
|
||||
2,
|
||||
3
|
||||
]
|
||||
]`);
|
||||
}
|
||||
|
||||
function test_date()
|
||||
{
|
||||
var d = new Date(1506098258091), a, s;
|
||||
assert(d.toISOString(), "2017-09-22T16:37:38.091Z");
|
||||
d.setUTCHours(18, 10, 11);
|
||||
assert(d.toISOString(), "2017-09-22T18:10:11.091Z");
|
||||
a = Date.parse(d.toISOString());
|
||||
assert((new Date(a)).toISOString(), d.toISOString());
|
||||
s = new Date("2020-01-01T01:01:01.1Z").toISOString();
|
||||
assert(s == "2020-01-01T01:01:01.100Z");
|
||||
s = new Date("2020-01-01T01:01:01.12Z").toISOString();
|
||||
assert(s == "2020-01-01T01:01:01.120Z");
|
||||
s = new Date("2020-01-01T01:01:01.123Z").toISOString();
|
||||
assert(s == "2020-01-01T01:01:01.123Z");
|
||||
s = new Date("2020-01-01T01:01:01.1234Z").toISOString();
|
||||
assert(s == "2020-01-01T01:01:01.123Z");
|
||||
s = new Date("2020-01-01T01:01:01.12345Z").toISOString();
|
||||
assert(s == "2020-01-01T01:01:01.123Z");
|
||||
s = new Date("2020-01-01T01:01:01.1235Z").toISOString();
|
||||
assert(s == "2020-01-01T01:01:01.124Z");
|
||||
s = new Date("2020-01-01T01:01:01.9999Z").toISOString();
|
||||
assert(s == "2020-01-01T01:01:02.000Z");
|
||||
}
|
||||
|
||||
function test_regexp()
|
||||
{
|
||||
var a, str;
|
||||
str = "abbbbbc";
|
||||
a = /(b+)c/.exec(str);
|
||||
assert(a[0], "bbbbbc");
|
||||
assert(a[1], "bbbbb");
|
||||
assert(a.index, 1);
|
||||
assert(a.input, str);
|
||||
a = /(b+)c/.test(str);
|
||||
assert(a, true);
|
||||
assert(/\x61/.exec("a")[0], "a");
|
||||
assert(/\u0061/.exec("a")[0], "a");
|
||||
assert(/\ca/.exec("\x01")[0], "\x01");
|
||||
assert(/\\a/.exec("\\a")[0], "\\a");
|
||||
assert(/\c0/.exec("\\c0")[0], "\\c0");
|
||||
|
||||
a = /(\.(?=com|org)|\/)/.exec("ah.com");
|
||||
assert(a.index === 2 && a[0] === ".");
|
||||
|
||||
a = /(\.(?!com|org)|\/)/.exec("ah.com");
|
||||
assert(a, null);
|
||||
|
||||
a = /(?=(a+))/.exec("baaabac");
|
||||
assert(a.index === 1 && a[0] === "" && a[1] === "aaa");
|
||||
|
||||
a = /(z)((a+)?(b+)?(c))*/.exec("zaacbbbcac");
|
||||
assert(a, ["zaacbbbcac","z","ac","a",,"c"]);
|
||||
|
||||
a = eval("/\0a/");
|
||||
assert(a.toString(), "/\0a/");
|
||||
assert(a.exec("\0a")[0], "\0a");
|
||||
|
||||
assert(/{1a}/.toString(), "/{1a}/");
|
||||
a = /a{1+/.exec("a{11");
|
||||
assert(a, ["a{11"] );
|
||||
}
|
||||
|
||||
function test_symbol()
|
||||
{
|
||||
var a, b, obj, c;
|
||||
a = Symbol("abc");
|
||||
obj = {};
|
||||
obj[a] = 2;
|
||||
assert(obj[a], 2);
|
||||
assert(typeof obj["abc"], "undefined");
|
||||
assert(String(a), "Symbol(abc)");
|
||||
b = Symbol("abc");
|
||||
assert(a == a);
|
||||
assert(a === a);
|
||||
assert(a != b);
|
||||
assert(a !== b);
|
||||
|
||||
b = Symbol.for("abc");
|
||||
c = Symbol.for("abc");
|
||||
assert(b === c);
|
||||
assert(b !== a);
|
||||
|
||||
assert(Symbol.keyFor(b), "abc");
|
||||
assert(Symbol.keyFor(a), undefined);
|
||||
|
||||
a = Symbol("aaa");
|
||||
assert(a.valueOf(), a);
|
||||
assert(a.toString(), "Symbol(aaa)");
|
||||
|
||||
b = Object(a);
|
||||
assert(b.valueOf(), a);
|
||||
assert(b.toString(), "Symbol(aaa)");
|
||||
}
|
||||
|
||||
function test_map()
|
||||
{
|
||||
var a, i, n, tab, o, v;
|
||||
n = 1000;
|
||||
a = new Map();
|
||||
tab = [];
|
||||
for(i = 0; i < n; i++) {
|
||||
v = { };
|
||||
o = { id: i };
|
||||
tab[i] = [o, v];
|
||||
a.set(o, v);
|
||||
}
|
||||
|
||||
assert(a.size, n);
|
||||
for(i = 0; i < n; i++) {
|
||||
assert(a.get(tab[i][0]), tab[i][1]);
|
||||
}
|
||||
|
||||
i = 0;
|
||||
a.forEach(function (v, o) {
|
||||
assert(o, tab[i++][0]);
|
||||
assert(a.has(o));
|
||||
assert(a.delete(o));
|
||||
assert(!a.has(o));
|
||||
});
|
||||
|
||||
assert(a.size, 0);
|
||||
}
|
||||
|
||||
function test_weak_map()
|
||||
{
|
||||
var a, i, n, tab, o, v, n2;
|
||||
a = new WeakMap();
|
||||
n = 10;
|
||||
tab = [];
|
||||
for(i = 0; i < n; i++) {
|
||||
v = { };
|
||||
o = { id: i };
|
||||
tab[i] = [o, v];
|
||||
a.set(o, v);
|
||||
}
|
||||
o = null;
|
||||
|
||||
n2 = n >> 1;
|
||||
for(i = 0; i < n2; i++) {
|
||||
a.delete(tab[i][0]);
|
||||
}
|
||||
for(i = n2; i < n; i++) {
|
||||
tab[i][0] = null; /* should remove the object from the WeakMap too */
|
||||
}
|
||||
/* the WeakMap should be empty here */
|
||||
}
|
||||
|
||||
function test_generator()
|
||||
{
|
||||
function *f() {
|
||||
var ret;
|
||||
yield 1;
|
||||
ret = yield 2;
|
||||
assert(ret, "next_arg");
|
||||
return 3;
|
||||
}
|
||||
function *f2() {
|
||||
yield 1;
|
||||
yield 2;
|
||||
return "ret_val";
|
||||
}
|
||||
function *f1() {
|
||||
var ret = yield *f2();
|
||||
assert(ret, "ret_val");
|
||||
return 3;
|
||||
}
|
||||
var g, v;
|
||||
g = f();
|
||||
v = g.next();
|
||||
assert(v.value === 1 && v.done === false);
|
||||
v = g.next();
|
||||
assert(v.value === 2 && v.done === false);
|
||||
v = g.next("next_arg");
|
||||
assert(v.value === 3 && v.done === true);
|
||||
v = g.next();
|
||||
assert(v.value === undefined && v.done === true);
|
||||
|
||||
g = f1();
|
||||
v = g.next();
|
||||
assert(v.value === 1 && v.done === false);
|
||||
v = g.next();
|
||||
assert(v.value === 2 && v.done === false);
|
||||
v = g.next();
|
||||
assert(v.value === 3 && v.done === true);
|
||||
v = g.next();
|
||||
assert(v.value === undefined && v.done === true);
|
||||
}
|
||||
|
||||
test();
|
||||
test_function();
|
||||
test_enum();
|
||||
test_array();
|
||||
test_string();
|
||||
test_math();
|
||||
test_number();
|
||||
test_eval();
|
||||
test_typed_array();
|
||||
test_json();
|
||||
test_date();
|
||||
test_regexp();
|
||||
test_symbol();
|
||||
test_map();
|
||||
test_weak_map();
|
||||
test_generator();
|
221
quickjs/tests/test_closure.js
Normal file
|
@ -0,0 +1,221 @@
|
|||
function assert(actual, expected, message) {
|
||||
if (arguments.length == 1)
|
||||
expected = true;
|
||||
|
||||
if (actual === expected)
|
||||
return;
|
||||
|
||||
if (actual !== null && expected !== null
|
||||
&& typeof actual == 'object' && typeof expected == 'object'
|
||||
&& actual.toString() === expected.toString())
|
||||
return;
|
||||
|
||||
throw Error("assertion failed: got |" + actual + "|" +
|
||||
", expected |" + expected + "|" +
|
||||
(message ? " (" + message + ")" : ""));
|
||||
}
|
||||
|
||||
// load more elaborate version of assert if available
|
||||
try { __loadScript("test_assert.js"); } catch(e) {}
|
||||
|
||||
/*----------------*/
|
||||
|
||||
var log_str = "";
|
||||
|
||||
function log(str)
|
||||
{
|
||||
log_str += str + ",";
|
||||
}
|
||||
|
||||
function f(a, b, c)
|
||||
{
|
||||
var x = 10;
|
||||
log("a="+a);
|
||||
function g(d) {
|
||||
function h() {
|
||||
log("d=" + d);
|
||||
log("x=" + x);
|
||||
}
|
||||
log("b=" + b);
|
||||
log("c=" + c);
|
||||
h();
|
||||
}
|
||||
g(4);
|
||||
return g;
|
||||
}
|
||||
|
||||
var g1 = f(1, 2, 3);
|
||||
g1(5);
|
||||
|
||||
assert(log_str, "a=1,b=2,c=3,d=4,x=10,b=2,c=3,d=5,x=10,", "closure1");
|
||||
|
||||
function test_closure1()
|
||||
{
|
||||
function f2()
|
||||
{
|
||||
var val = 1;
|
||||
|
||||
function set(a) {
|
||||
val = a;
|
||||
}
|
||||
function get(a) {
|
||||
return val;
|
||||
}
|
||||
return { "set": set, "get": get };
|
||||
}
|
||||
|
||||
var obj = f2();
|
||||
obj.set(10);
|
||||
var r;
|
||||
r = obj.get();
|
||||
assert(r, 10, "closure2");
|
||||
}
|
||||
|
||||
function test_closure2()
|
||||
{
|
||||
var expr_func = function myfunc1(n) {
|
||||
function myfunc2(n) {
|
||||
return myfunc1(n - 1);
|
||||
}
|
||||
if (n == 0)
|
||||
return 0;
|
||||
else
|
||||
return myfunc2(n);
|
||||
};
|
||||
var r;
|
||||
r = expr_func(1);
|
||||
assert(r, 0, "expr_func");
|
||||
}
|
||||
|
||||
function test_closure3()
|
||||
{
|
||||
function fib(n)
|
||||
{
|
||||
if (n <= 0)
|
||||
return 0;
|
||||
else if (n == 1)
|
||||
return 1;
|
||||
else
|
||||
return fib(n - 1) + fib(n - 2);
|
||||
}
|
||||
|
||||
var fib_func = function fib1(n)
|
||||
{
|
||||
if (n <= 0)
|
||||
return 0;
|
||||
else if (n == 1)
|
||||
return 1;
|
||||
else
|
||||
return fib1(n - 1) + fib1(n - 2);
|
||||
};
|
||||
|
||||
assert(fib(6), 8, "fib");
|
||||
assert(fib_func(6), 8, "fib_func");
|
||||
}
|
||||
|
||||
function test_arrow_function()
|
||||
{
|
||||
"use strict";
|
||||
|
||||
function f1() {
|
||||
return (() => arguments)();
|
||||
}
|
||||
function f2() {
|
||||
return (() => this)();
|
||||
}
|
||||
function f3() {
|
||||
return (() => eval("this"))();
|
||||
}
|
||||
function f4() {
|
||||
return (() => eval("new.target"))();
|
||||
}
|
||||
var a;
|
||||
|
||||
a = f1(1, 2);
|
||||
assert(a.length, 2);
|
||||
assert(a[0] === 1 && a[1] === 2);
|
||||
|
||||
assert(f2.call("this_val") === "this_val");
|
||||
assert(f3.call("this_val") === "this_val");
|
||||
assert(new f4() === f4);
|
||||
|
||||
var o1 = { f() { return this; } };
|
||||
var o2 = { f() {
|
||||
return (() => eval("super.f()"))();
|
||||
} };
|
||||
o2.__proto__ = o1;
|
||||
|
||||
assert(o2.f() === o2);
|
||||
}
|
||||
|
||||
function test_with()
|
||||
{
|
||||
var o1 = { x: "o1", y: "o1" };
|
||||
var x = "local";
|
||||
eval('var z="var_obj";');
|
||||
assert(z === "var_obj");
|
||||
with (o1) {
|
||||
assert(x === "o1");
|
||||
assert(eval("x") === "o1");
|
||||
var f = function () {
|
||||
o2 = { x: "o2" };
|
||||
with (o2) {
|
||||
assert(x === "o2");
|
||||
assert(y === "o1");
|
||||
assert(z === "var_obj");
|
||||
assert(eval("x") === "o2");
|
||||
assert(eval("y") === "o1");
|
||||
assert(eval("z") === "var_obj");
|
||||
assert(eval('eval("x")') === "o2");
|
||||
}
|
||||
};
|
||||
f();
|
||||
}
|
||||
}
|
||||
|
||||
function test_eval_closure()
|
||||
{
|
||||
var tab;
|
||||
|
||||
tab = [];
|
||||
for(let i = 0; i < 3; i++) {
|
||||
eval("tab.push(function g1() { return i; })");
|
||||
}
|
||||
for(let i = 0; i < 3; i++) {
|
||||
assert(tab[i]() === i);
|
||||
}
|
||||
|
||||
tab = [];
|
||||
for(let i = 0; i < 3; i++) {
|
||||
let f = function f() {
|
||||
eval("tab.push(function g2() { return i; })");
|
||||
};
|
||||
f();
|
||||
}
|
||||
for(let i = 0; i < 3; i++) {
|
||||
assert(tab[i]() === i);
|
||||
}
|
||||
}
|
||||
|
||||
function test_eval_const()
|
||||
{
|
||||
const a = 1;
|
||||
var success = false;
|
||||
var f = function () {
|
||||
eval("a = 1");
|
||||
};
|
||||
try {
|
||||
f();
|
||||
} catch(e) {
|
||||
success = (e instanceof TypeError);
|
||||
}
|
||||
assert(success);
|
||||
}
|
||||
|
||||
test_closure1();
|
||||
test_closure2();
|
||||
test_closure3();
|
||||
test_arrow_function();
|
||||
test_with();
|
||||
test_eval_closure();
|
||||
test_eval_const();
|
547
quickjs/tests/test_language.js
Normal file
|
@ -0,0 +1,547 @@
|
|||
function assert(actual, expected, message) {
|
||||
if (arguments.length == 1)
|
||||
expected = true;
|
||||
|
||||
if (actual === expected)
|
||||
return;
|
||||
|
||||
if (actual !== null && expected !== null
|
||||
&& typeof actual == 'object' && typeof expected == 'object'
|
||||
&& actual.toString() === expected.toString())
|
||||
return;
|
||||
|
||||
throw Error("assertion failed: got |" + actual + "|" +
|
||||
", expected |" + expected + "|" +
|
||||
(message ? " (" + message + ")" : ""));
|
||||
}
|
||||
|
||||
function assert_throws(expected_error, func)
|
||||
{
|
||||
var err = false;
|
||||
try {
|
||||
func();
|
||||
} catch(e) {
|
||||
err = true;
|
||||
if (!(e instanceof expected_error)) {
|
||||
throw Error("unexpected exception type");
|
||||
}
|
||||
}
|
||||
if (!err) {
|
||||
throw Error("expected exception");
|
||||
}
|
||||
}
|
||||
|
||||
// load more elaborate version of assert if available
|
||||
try { __loadScript("test_assert.js"); } catch(e) {}
|
||||
|
||||
/*----------------*/
|
||||
|
||||
function test_op1()
|
||||
{
|
||||
var r, a;
|
||||
r = 1 + 2;
|
||||
assert(r, 3, "1 + 2 === 3");
|
||||
|
||||
r = 1 - 2;
|
||||
assert(r, -1, "1 - 2 === -1");
|
||||
|
||||
r = -1;
|
||||
assert(r, -1, "-1 === -1");
|
||||
|
||||
r = +2;
|
||||
assert(r, 2, "+2 === 2");
|
||||
|
||||
r = 2 * 3;
|
||||
assert(r, 6, "2 * 3 === 6");
|
||||
|
||||
r = 4 / 2;
|
||||
assert(r, 2, "4 / 2 === 2");
|
||||
|
||||
r = 4 % 3;
|
||||
assert(r, 1, "4 % 3 === 3");
|
||||
|
||||
r = 4 << 2;
|
||||
assert(r, 16, "4 << 2 === 16");
|
||||
|
||||
r = 1 << 0;
|
||||
assert(r, 1, "1 << 0 === 1");
|
||||
|
||||
r = 1 << 31;
|
||||
assert(r, -2147483648, "1 << 31 === -2147483648");
|
||||
|
||||
r = 1 << 32;
|
||||
assert(r, 1, "1 << 32 === 1");
|
||||
|
||||
r = (1 << 31) < 0;
|
||||
assert(r, true, "(1 << 31) < 0 === true");
|
||||
|
||||
r = -4 >> 1;
|
||||
assert(r, -2, "-4 >> 1 === -2");
|
||||
|
||||
r = -4 >>> 1;
|
||||
assert(r, 0x7ffffffe, "-4 >>> 1 === 0x7ffffffe");
|
||||
|
||||
r = 1 & 1;
|
||||
assert(r, 1, "1 & 1 === 1");
|
||||
|
||||
r = 0 | 1;
|
||||
assert(r, 1, "0 | 1 === 1");
|
||||
|
||||
r = 1 ^ 1;
|
||||
assert(r, 0, "1 ^ 1 === 0");
|
||||
|
||||
r = ~1;
|
||||
assert(r, -2, "~1 === -2");
|
||||
|
||||
r = !1;
|
||||
assert(r, false, "!1 === false");
|
||||
|
||||
assert((1 < 2), true, "(1 < 2) === true");
|
||||
|
||||
assert((2 > 1), true, "(2 > 1) === true");
|
||||
|
||||
assert(('b' > 'a'), true, "('b' > 'a') === true");
|
||||
|
||||
assert(2 ** 8, 256, "2 ** 8 === 256");
|
||||
}
|
||||
|
||||
function test_cvt()
|
||||
{
|
||||
assert((NaN | 0) === 0);
|
||||
assert((Infinity | 0) === 0);
|
||||
assert(((-Infinity) | 0) === 0);
|
||||
assert(("12345" | 0) === 12345);
|
||||
assert(("0x12345" | 0) === 0x12345);
|
||||
assert(((4294967296 * 3 - 4) | 0) === -4);
|
||||
|
||||
assert(("12345" >>> 0) === 12345);
|
||||
assert(("0x12345" >>> 0) === 0x12345);
|
||||
assert((NaN >>> 0) === 0);
|
||||
assert((Infinity >>> 0) === 0);
|
||||
assert(((-Infinity) >>> 0) === 0);
|
||||
assert(((4294967296 * 3 - 4) >>> 0) === (4294967296 - 4));
|
||||
}
|
||||
|
||||
function test_eq()
|
||||
{
|
||||
assert(null == undefined);
|
||||
assert(undefined == null);
|
||||
assert(true == 1);
|
||||
assert(0 == false);
|
||||
assert("" == 0);
|
||||
assert("123" == 123);
|
||||
assert("122" != 123);
|
||||
assert((new Number(1)) == 1);
|
||||
assert(2 == (new Number(2)));
|
||||
assert((new String("abc")) == "abc");
|
||||
assert({} != "abc");
|
||||
}
|
||||
|
||||
function test_inc_dec()
|
||||
{
|
||||
var a, r;
|
||||
|
||||
a = 1;
|
||||
r = a++;
|
||||
assert(r === 1 && a === 2, true, "++");
|
||||
|
||||
a = 1;
|
||||
r = ++a;
|
||||
assert(r === 2 && a === 2, true, "++");
|
||||
|
||||
a = 1;
|
||||
r = a--;
|
||||
assert(r === 1 && a === 0, true, "--");
|
||||
|
||||
a = 1;
|
||||
r = --a;
|
||||
assert(r === 0 && a === 0, true, "--");
|
||||
|
||||
a = {x:true};
|
||||
a.x++;
|
||||
assert(a.x, 2, "++");
|
||||
|
||||
a = {x:true};
|
||||
a.x--;
|
||||
assert(a.x, 0, "--");
|
||||
|
||||
a = [true];
|
||||
a[0]++;
|
||||
assert(a[0], 2, "++");
|
||||
|
||||
a = {x:true};
|
||||
r = a.x++;
|
||||
assert(r === 1 && a.x === 2, true, "++");
|
||||
|
||||
a = {x:true};
|
||||
r = a.x--;
|
||||
assert(r === 1 && a.x === 0, true, "--");
|
||||
|
||||
a = [true];
|
||||
r = a[0]++;
|
||||
assert(r === 1 && a[0] === 2, true, "++");
|
||||
|
||||
a = [true];
|
||||
r = a[0]--;
|
||||
assert(r === 1 && a[0] === 0, true, "--");
|
||||
}
|
||||
|
||||
function F(x)
|
||||
{
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
function test_op2()
|
||||
{
|
||||
var a, b;
|
||||
a = new Object;
|
||||
a.x = 1;
|
||||
assert(a.x, 1, "new");
|
||||
b = new F(2);
|
||||
assert(b.x, 2, "new");
|
||||
|
||||
a = {x : 2};
|
||||
assert(("x" in a), true, "in");
|
||||
assert(("y" in a), false, "in");
|
||||
|
||||
a = {};
|
||||
assert((a instanceof Object), true, "instanceof");
|
||||
assert((a instanceof String), false, "instanceof");
|
||||
|
||||
assert((typeof 1), "number", "typeof");
|
||||
assert((typeof Object), "function", "typeof");
|
||||
assert((typeof null), "object", "typeof");
|
||||
assert((typeof unknown_var), "undefined", "typeof");
|
||||
|
||||
a = {x: 1, if: 2, async: 3};
|
||||
assert(a.if === 2);
|
||||
assert(a.async === 3);
|
||||
}
|
||||
|
||||
function test_delete()
|
||||
{
|
||||
var a, err;
|
||||
|
||||
a = {x: 1, y: 1};
|
||||
assert((delete a.x), true, "delete");
|
||||
assert(("x" in a), false, "delete");
|
||||
|
||||
/* the following are not tested by test262 */
|
||||
assert(delete "abc"[100], true);
|
||||
|
||||
err = false;
|
||||
try {
|
||||
delete null.a;
|
||||
} catch(e) {
|
||||
err = (e instanceof TypeError);
|
||||
}
|
||||
assert(err, true, "delete");
|
||||
|
||||
err = false;
|
||||
try {
|
||||
a = { f() { delete super.a; } };
|
||||
a.f();
|
||||
} catch(e) {
|
||||
err = (e instanceof ReferenceError);
|
||||
}
|
||||
assert(err, true, "delete");
|
||||
}
|
||||
|
||||
function test_prototype()
|
||||
{
|
||||
var f = function f() { };
|
||||
assert(f.prototype.constructor, f, "prototype");
|
||||
|
||||
var g = function g() { };
|
||||
/* QuickJS bug */
|
||||
Object.defineProperty(g, "prototype", { writable: false });
|
||||
assert(g.prototype.constructor, g, "prototype");
|
||||
}
|
||||
|
||||
function test_arguments()
|
||||
{
|
||||
function f2() {
|
||||
assert(arguments.length, 2, "arguments");
|
||||
assert(arguments[0], 1, "arguments");
|
||||
assert(arguments[1], 3, "arguments");
|
||||
}
|
||||
f2(1, 3);
|
||||
}
|
||||
|
||||
function test_class()
|
||||
{
|
||||
var o;
|
||||
class C {
|
||||
constructor() {
|
||||
this.x = 10;
|
||||
}
|
||||
f() {
|
||||
return 1;
|
||||
}
|
||||
static F() {
|
||||
return -1;
|
||||
}
|
||||
get y() {
|
||||
return 12;
|
||||
}
|
||||
};
|
||||
class D extends C {
|
||||
constructor() {
|
||||
super();
|
||||
this.z = 20;
|
||||
}
|
||||
g() {
|
||||
return 2;
|
||||
}
|
||||
static G() {
|
||||
return -2;
|
||||
}
|
||||
h() {
|
||||
return super.f();
|
||||
}
|
||||
static H() {
|
||||
return super["F"]();
|
||||
}
|
||||
}
|
||||
|
||||
assert(C.F() === -1);
|
||||
assert(Object.getOwnPropertyDescriptor(C.prototype, "y").get.name === "get y");
|
||||
|
||||
o = new C();
|
||||
assert(o.f() === 1);
|
||||
assert(o.x === 10);
|
||||
|
||||
assert(D.F() === -1);
|
||||
assert(D.G() === -2);
|
||||
assert(D.H() === -1);
|
||||
|
||||
o = new D();
|
||||
assert(o.f() === 1);
|
||||
assert(o.g() === 2);
|
||||
assert(o.x === 10);
|
||||
assert(o.z === 20);
|
||||
assert(o.h() === 1);
|
||||
|
||||
/* test class name scope */
|
||||
var E1 = class E { static F() { return E; } };
|
||||
assert(E1 === E1.F());
|
||||
};
|
||||
|
||||
function test_template()
|
||||
{
|
||||
var a, b;
|
||||
b = 123;
|
||||
a = `abc${b}d`;
|
||||
assert(a, "abc123d");
|
||||
|
||||
a = String.raw `abc${b}d`;
|
||||
assert(a, "abc123d");
|
||||
|
||||
a = "aaa";
|
||||
b = "bbb";
|
||||
assert(`aaa${a, b}ccc`, "aaabbbccc");
|
||||
}
|
||||
|
||||
function test_template_skip()
|
||||
{
|
||||
var a = "Bar";
|
||||
var { b = `${a + `a${a}` }baz` } = {};
|
||||
assert(b, "BaraBarbaz");
|
||||
}
|
||||
|
||||
function test_object_literal()
|
||||
{
|
||||
var x = 0, get = 1, set = 2; async = 3;
|
||||
a = { get: 2, set: 3, async: 4 };
|
||||
assert(JSON.stringify(a), '{"get":2,"set":3,"async":4}');
|
||||
|
||||
a = { x, get, set, async };
|
||||
assert(JSON.stringify(a), '{"x":0,"get":1,"set":2,"async":3}');
|
||||
}
|
||||
|
||||
function test_regexp_skip()
|
||||
{
|
||||
var a, b;
|
||||
[a, b = /abc\(/] = [1];
|
||||
assert(a === 1);
|
||||
|
||||
[a, b =/abc\(/] = [2];
|
||||
assert(a === 2);
|
||||
}
|
||||
|
||||
function test_labels()
|
||||
{
|
||||
do x: { break x; } while(0);
|
||||
if (1)
|
||||
x: { break x; }
|
||||
else
|
||||
x: { break x; }
|
||||
with ({}) x: { break x; };
|
||||
while (0) x: { break x; };
|
||||
}
|
||||
|
||||
function test_destructuring()
|
||||
{
|
||||
function * g () { return 0; };
|
||||
var [x] = g();
|
||||
assert(x, void 0);
|
||||
}
|
||||
|
||||
function test_spread()
|
||||
{
|
||||
var x;
|
||||
x = [1, 2, ...[3, 4]];
|
||||
assert(x.toString(), "1,2,3,4");
|
||||
|
||||
x = [ ...[ , ] ];
|
||||
assert(Object.getOwnPropertyNames(x).toString(), "0,length");
|
||||
}
|
||||
|
||||
function test_function_length()
|
||||
{
|
||||
assert( ((a, b = 1, c) => {}).length, 1);
|
||||
assert( (([a,b]) => {}).length, 1);
|
||||
assert( (({a,b}) => {}).length, 1);
|
||||
assert( ((c, [a,b] = 1, d) => {}).length, 1);
|
||||
}
|
||||
|
||||
function test_argument_scope()
|
||||
{
|
||||
var f;
|
||||
var c = "global";
|
||||
|
||||
f = function(a = eval("var arguments")) {};
|
||||
assert_throws(SyntaxError, f);
|
||||
|
||||
f = function(a = eval("1"), b = arguments[0]) { return b; };
|
||||
assert(f(12), 12);
|
||||
|
||||
f = function(a, b = arguments[0]) { return b; };
|
||||
assert(f(12), 12);
|
||||
|
||||
f = function(a, b = () => arguments) { return b; };
|
||||
assert(f(12)()[0], 12);
|
||||
|
||||
f = function(a = eval("1"), b = () => arguments) { return b; };
|
||||
assert(f(12)()[0], 12);
|
||||
|
||||
(function() {
|
||||
"use strict";
|
||||
f = function(a = this) { return a; };
|
||||
assert(f.call(123), 123);
|
||||
|
||||
f = function f(a = f) { return a; };
|
||||
assert(f(), f);
|
||||
|
||||
f = function f(a = eval("f")) { return a; };
|
||||
assert(f(), f);
|
||||
})();
|
||||
|
||||
f = (a = eval("var c = 1"), probe = () => c) => {
|
||||
var c = 2;
|
||||
assert(c, 2);
|
||||
assert(probe(), 1);
|
||||
}
|
||||
f();
|
||||
|
||||
f = (a = eval("var arguments = 1"), probe = () => arguments) => {
|
||||
var arguments = 2;
|
||||
assert(arguments, 2);
|
||||
assert(probe(), 1);
|
||||
}
|
||||
f();
|
||||
|
||||
f = function f(a = eval("var c = 1"), b = c, probe = () => c) {
|
||||
assert(b, 1);
|
||||
assert(c, 1);
|
||||
assert(probe(), 1)
|
||||
}
|
||||
f();
|
||||
|
||||
assert(c, "global");
|
||||
f = function f(a, b = c, probe = () => c) {
|
||||
eval("var c = 1");
|
||||
assert(c, 1);
|
||||
assert(b, "global");
|
||||
assert(probe(), "global")
|
||||
}
|
||||
f();
|
||||
assert(c, "global");
|
||||
|
||||
f = function f(a = eval("var c = 1"), probe = (d = eval("c")) => d) {
|
||||
assert(probe(), 1)
|
||||
}
|
||||
f();
|
||||
}
|
||||
|
||||
function test_function_expr_name()
|
||||
{
|
||||
var f;
|
||||
|
||||
/* non strict mode test : assignment to the function name silently
|
||||
fails */
|
||||
|
||||
f = function myfunc() {
|
||||
myfunc = 1;
|
||||
return myfunc;
|
||||
};
|
||||
assert(f(), f);
|
||||
|
||||
f = function myfunc() {
|
||||
myfunc = 1;
|
||||
(() => {
|
||||
myfunc = 1;
|
||||
})();
|
||||
return myfunc;
|
||||
};
|
||||
assert(f(), f);
|
||||
|
||||
f = function myfunc() {
|
||||
eval("myfunc = 1");
|
||||
return myfunc;
|
||||
};
|
||||
assert(f(), f);
|
||||
|
||||
/* strict mode test : assignment to the function name raises a
|
||||
TypeError exception */
|
||||
|
||||
f = function myfunc() {
|
||||
"use strict";
|
||||
myfunc = 1;
|
||||
};
|
||||
assert_throws(TypeError, f);
|
||||
|
||||
f = function myfunc() {
|
||||
"use strict";
|
||||
(() => {
|
||||
myfunc = 1;
|
||||
})();
|
||||
};
|
||||
assert_throws(TypeError, f);
|
||||
|
||||
f = function myfunc() {
|
||||
"use strict";
|
||||
eval("myfunc = 1");
|
||||
};
|
||||
assert_throws(TypeError, f);
|
||||
}
|
||||
|
||||
test_op1();
|
||||
test_cvt();
|
||||
test_eq();
|
||||
test_inc_dec();
|
||||
test_op2();
|
||||
test_delete();
|
||||
test_prototype();
|
||||
test_arguments();
|
||||
test_class();
|
||||
test_template();
|
||||
test_template_skip();
|
||||
test_object_literal();
|
||||
test_regexp_skip();
|
||||
test_labels();
|
||||
test_destructuring();
|
||||
test_spread();
|
||||
test_function_length();
|
||||
test_argument_scope();
|
||||
test_function_expr_name();
|
368
quickjs/tests/test_loop.js
Normal file
|
@ -0,0 +1,368 @@
|
|||
function assert(actual, expected, message) {
|
||||
if (arguments.length == 1)
|
||||
expected = true;
|
||||
|
||||
if (actual === expected)
|
||||
return;
|
||||
|
||||
if (actual !== null && expected !== null
|
||||
&& typeof actual == 'object' && typeof expected == 'object'
|
||||
&& actual.toString() === expected.toString())
|
||||
return;
|
||||
|
||||
throw Error("assertion failed: got |" + actual + "|" +
|
||||
", expected |" + expected + "|" +
|
||||
(message ? " (" + message + ")" : ""));
|
||||
}
|
||||
|
||||
// load more elaborate version of assert if available
|
||||
try { __loadScript("test_assert.js"); } catch(e) {}
|
||||
|
||||
/*----------------*/
|
||||
|
||||
function test_while()
|
||||
{
|
||||
var i, c;
|
||||
i = 0;
|
||||
c = 0;
|
||||
while (i < 3) {
|
||||
c++;
|
||||
i++;
|
||||
}
|
||||
assert(c === 3);
|
||||
}
|
||||
|
||||
function test_while_break()
|
||||
{
|
||||
var i, c;
|
||||
i = 0;
|
||||
c = 0;
|
||||
while (i < 3) {
|
||||
c++;
|
||||
if (i == 1)
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
assert(c === 2 && i === 1);
|
||||
}
|
||||
|
||||
function test_do_while()
|
||||
{
|
||||
var i, c;
|
||||
i = 0;
|
||||
c = 0;
|
||||
do {
|
||||
c++;
|
||||
i++;
|
||||
} while (i < 3);
|
||||
assert(c === 3 && i === 3);
|
||||
}
|
||||
|
||||
function test_for()
|
||||
{
|
||||
var i, c;
|
||||
c = 0;
|
||||
for(i = 0; i < 3; i++) {
|
||||
c++;
|
||||
}
|
||||
assert(c === 3 && i === 3);
|
||||
|
||||
c = 0;
|
||||
for(var j = 0; j < 3; j++) {
|
||||
c++;
|
||||
}
|
||||
assert(c === 3 && j === 3);
|
||||
}
|
||||
|
||||
function test_for_in()
|
||||
{
|
||||
var i, tab, a, b;
|
||||
|
||||
tab = [];
|
||||
for(i in {x:1, y: 2}) {
|
||||
tab.push(i);
|
||||
}
|
||||
assert(tab.toString(), "x,y", "for_in");
|
||||
|
||||
/* prototype chain test */
|
||||
a = {x:2, y: 2, "1": 3};
|
||||
b = {"4" : 3 };
|
||||
Object.setPrototypeOf(a, b);
|
||||
tab = [];
|
||||
for(i in a) {
|
||||
tab.push(i);
|
||||
}
|
||||
assert(tab.toString(), "1,x,y,4", "for_in");
|
||||
|
||||
/* non enumerable properties hide enumerables ones in the
|
||||
prototype chain */
|
||||
a = {y: 2, "1": 3};
|
||||
Object.defineProperty(a, "x", { value: 1 });
|
||||
b = {"x" : 3 };
|
||||
Object.setPrototypeOf(a, b);
|
||||
tab = [];
|
||||
for(i in a) {
|
||||
tab.push(i);
|
||||
}
|
||||
assert(tab.toString(), "1,y", "for_in");
|
||||
|
||||
/* array optimization */
|
||||
a = [];
|
||||
for(i = 0; i < 10; i++)
|
||||
a.push(i);
|
||||
tab = [];
|
||||
for(i in a) {
|
||||
tab.push(i);
|
||||
}
|
||||
assert(tab.toString(), "0,1,2,3,4,5,6,7,8,9", "for_in");
|
||||
|
||||
/* iterate with a field */
|
||||
a={x:0};
|
||||
tab = [];
|
||||
for(a.x in {x:1, y: 2}) {
|
||||
tab.push(a.x);
|
||||
}
|
||||
assert(tab.toString(), "x,y", "for_in");
|
||||
|
||||
/* iterate with a variable field */
|
||||
a=[0];
|
||||
tab = [];
|
||||
for(a[0] in {x:1, y: 2}) {
|
||||
tab.push(a[0]);
|
||||
}
|
||||
assert(tab.toString(), "x,y", "for_in");
|
||||
|
||||
/* variable definition in the for in */
|
||||
tab = [];
|
||||
for(var j in {x:1, y: 2}) {
|
||||
tab.push(j);
|
||||
}
|
||||
assert(tab.toString(), "x,y", "for_in");
|
||||
|
||||
/* variable assigment in the for in */
|
||||
tab = [];
|
||||
for(var k = 2 in {x:1, y: 2}) {
|
||||
tab.push(k);
|
||||
}
|
||||
assert(tab.toString(), "x,y", "for_in");
|
||||
}
|
||||
|
||||
function test_for_in2()
|
||||
{
|
||||
var i;
|
||||
tab = [];
|
||||
for(i in {x:1, y: 2, z:3}) {
|
||||
if (i === "y")
|
||||
continue;
|
||||
tab.push(i);
|
||||
}
|
||||
assert(tab.toString() == "x,z");
|
||||
|
||||
tab = [];
|
||||
for(i in {x:1, y: 2, z:3}) {
|
||||
if (i === "z")
|
||||
break;
|
||||
tab.push(i);
|
||||
}
|
||||
assert(tab.toString() == "x,y");
|
||||
}
|
||||
|
||||
function test_for_break()
|
||||
{
|
||||
var i, c;
|
||||
c = 0;
|
||||
L1: for(i = 0; i < 3; i++) {
|
||||
c++;
|
||||
if (i == 0)
|
||||
continue;
|
||||
while (1) {
|
||||
break L1;
|
||||
}
|
||||
}
|
||||
assert(c === 2 && i === 1);
|
||||
}
|
||||
|
||||
function test_switch1()
|
||||
{
|
||||
var i, a, s;
|
||||
s = "";
|
||||
for(i = 0; i < 3; i++) {
|
||||
a = "?";
|
||||
switch(i) {
|
||||
case 0:
|
||||
a = "a";
|
||||
break;
|
||||
case 1:
|
||||
a = "b";
|
||||
break;
|
||||
default:
|
||||
a = "c";
|
||||
break;
|
||||
}
|
||||
s += a;
|
||||
}
|
||||
assert(s === "abc" && i === 3);
|
||||
}
|
||||
|
||||
function test_switch2()
|
||||
{
|
||||
var i, a, s;
|
||||
s = "";
|
||||
for(i = 0; i < 4; i++) {
|
||||
a = "?";
|
||||
switch(i) {
|
||||
case 0:
|
||||
a = "a";
|
||||
break;
|
||||
case 1:
|
||||
a = "b";
|
||||
break;
|
||||
case 2:
|
||||
continue;
|
||||
default:
|
||||
a = "" + i;
|
||||
break;
|
||||
}
|
||||
s += a;
|
||||
}
|
||||
assert(s === "ab3" && i === 4);
|
||||
}
|
||||
|
||||
function test_try_catch1()
|
||||
{
|
||||
try {
|
||||
throw "hello";
|
||||
} catch (e) {
|
||||
assert(e, "hello", "catch");
|
||||
return;
|
||||
}
|
||||
assert(false, "catch");
|
||||
}
|
||||
|
||||
function test_try_catch2()
|
||||
{
|
||||
var a;
|
||||
try {
|
||||
a = 1;
|
||||
} catch (e) {
|
||||
a = 2;
|
||||
}
|
||||
assert(a, 1, "catch");
|
||||
}
|
||||
|
||||
function test_try_catch3()
|
||||
{
|
||||
var s;
|
||||
s = "";
|
||||
try {
|
||||
s += "t";
|
||||
} catch (e) {
|
||||
s += "c";
|
||||
} finally {
|
||||
s += "f";
|
||||
}
|
||||
assert(s, "tf", "catch");
|
||||
}
|
||||
|
||||
function test_try_catch4()
|
||||
{
|
||||
var s;
|
||||
s = "";
|
||||
try {
|
||||
s += "t";
|
||||
throw "c";
|
||||
} catch (e) {
|
||||
s += e;
|
||||
} finally {
|
||||
s += "f";
|
||||
}
|
||||
assert(s, "tcf", "catch");
|
||||
}
|
||||
|
||||
function test_try_catch5()
|
||||
{
|
||||
var s;
|
||||
s = "";
|
||||
for(;;) {
|
||||
try {
|
||||
s += "t";
|
||||
break;
|
||||
s += "b";
|
||||
} finally {
|
||||
s += "f";
|
||||
}
|
||||
}
|
||||
assert(s, "tf", "catch");
|
||||
}
|
||||
|
||||
function test_try_catch6()
|
||||
{
|
||||
function f() {
|
||||
try {
|
||||
s += 't';
|
||||
return 1;
|
||||
} finally {
|
||||
s += "f";
|
||||
}
|
||||
}
|
||||
var s = "";
|
||||
assert(f() === 1);
|
||||
assert(s, "tf", "catch6");
|
||||
}
|
||||
|
||||
function test_try_catch7()
|
||||
{
|
||||
var s;
|
||||
s = "";
|
||||
|
||||
try {
|
||||
try {
|
||||
s += "t";
|
||||
throw "a";
|
||||
} finally {
|
||||
s += "f";
|
||||
}
|
||||
} catch(e) {
|
||||
s += e;
|
||||
} finally {
|
||||
s += "g";
|
||||
}
|
||||
assert(s, "tfag", "catch");
|
||||
}
|
||||
|
||||
function test_try_catch8()
|
||||
{
|
||||
var i, s;
|
||||
|
||||
s = "";
|
||||
for(var i in {x:1, y:2}) {
|
||||
try {
|
||||
s += i;
|
||||
throw "a";
|
||||
} catch (e) {
|
||||
s += e;
|
||||
} finally {
|
||||
s += "f";
|
||||
}
|
||||
}
|
||||
assert(s === "xafyaf");
|
||||
}
|
||||
|
||||
test_while();
|
||||
test_while_break();
|
||||
test_do_while();
|
||||
test_for();
|
||||
test_for_break();
|
||||
test_switch1();
|
||||
test_switch2();
|
||||
test_for_in();
|
||||
test_for_in2();
|
||||
|
||||
test_try_catch1();
|
||||
test_try_catch2();
|
||||
test_try_catch3();
|
||||
test_try_catch4();
|
||||
test_try_catch5();
|
||||
test_try_catch6();
|
||||
test_try_catch7();
|
||||
test_try_catch8();
|
207
quickjs/tests/test_op_overloading.js
Normal file
|
@ -0,0 +1,207 @@
|
|||
"use strict";
|
||||
|
||||
function assert(actual, expected, message) {
|
||||
if (arguments.length == 1)
|
||||
expected = true;
|
||||
|
||||
if (actual === expected)
|
||||
return;
|
||||
|
||||
if (actual !== null && expected !== null
|
||||
&& typeof actual == 'object' && typeof expected == 'object'
|
||||
&& actual.toString() === expected.toString())
|
||||
return;
|
||||
|
||||
throw Error("assertion failed: got |" + actual + "|" +
|
||||
", expected |" + expected + "|" +
|
||||
(message ? " (" + message + ")" : ""));
|
||||
}
|
||||
|
||||
/* operators overloading with Operators.create() */
|
||||
function test_operators_create() {
|
||||
class Vec2
|
||||
{
|
||||
constructor(x, y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
static mul_scalar(p1, a) {
|
||||
var r = new Vec2();
|
||||
r.x = p1.x * a;
|
||||
r.y = p1.y * a;
|
||||
return r;
|
||||
}
|
||||
toString() {
|
||||
return "Vec2(" + this.x + "," + this.y + ")";
|
||||
}
|
||||
}
|
||||
|
||||
Vec2.prototype[Symbol.operatorSet] = Operators.create(
|
||||
{
|
||||
"+"(p1, p2) {
|
||||
var r = new Vec2();
|
||||
r.x = p1.x + p2.x;
|
||||
r.y = p1.y + p2.y;
|
||||
return r;
|
||||
},
|
||||
"-"(p1, p2) {
|
||||
var r = new Vec2();
|
||||
r.x = p1.x - p2.x;
|
||||
r.y = p1.y - p2.y;
|
||||
return r;
|
||||
},
|
||||
"=="(a, b) {
|
||||
return a.x == b.x && a.y == b.y;
|
||||
},
|
||||
"<"(a, b) {
|
||||
var r;
|
||||
/* lexicographic order */
|
||||
if (a.x == b.x)
|
||||
r = (a.y < b.y);
|
||||
else
|
||||
r = (a.x < b.x);
|
||||
return r;
|
||||
},
|
||||
"++"(a) {
|
||||
var r = new Vec2();
|
||||
r.x = a.x + 1;
|
||||
r.y = a.y + 1;
|
||||
return r;
|
||||
}
|
||||
},
|
||||
{
|
||||
left: Number,
|
||||
"*"(a, b) {
|
||||
return Vec2.mul_scalar(b, a);
|
||||
}
|
||||
},
|
||||
{
|
||||
right: Number,
|
||||
"*"(a, b) {
|
||||
return Vec2.mul_scalar(a, b);
|
||||
}
|
||||
});
|
||||
|
||||
var a = new Vec2(1, 2);
|
||||
var b = new Vec2(3, 4);
|
||||
var r;
|
||||
|
||||
r = a * 2 + 3 * b;
|
||||
assert(r.x === 11 && r.y === 16);
|
||||
assert(a == a, true);
|
||||
assert(a == b, false);
|
||||
assert(a != a, false);
|
||||
assert(a < b, true);
|
||||
assert(a <= b, true);
|
||||
assert(b < a, false);
|
||||
assert(b <= a, false);
|
||||
assert(a <= a, true);
|
||||
assert(a >= a, true);
|
||||
a++;
|
||||
assert(a.x === 2 && a.y === 3);
|
||||
r = ++a;
|
||||
assert(a.x === 3 && a.y === 4);
|
||||
assert(r === a);
|
||||
}
|
||||
|
||||
/* operators overloading thru inheritance */
|
||||
function test_operators()
|
||||
{
|
||||
var Vec2;
|
||||
|
||||
function mul_scalar(p1, a) {
|
||||
var r = new Vec2();
|
||||
r.x = p1.x * a;
|
||||
r.y = p1.y * a;
|
||||
return r;
|
||||
}
|
||||
|
||||
var vec2_ops = Operators({
|
||||
"+"(p1, p2) {
|
||||
var r = new Vec2();
|
||||
r.x = p1.x + p2.x;
|
||||
r.y = p1.y + p2.y;
|
||||
return r;
|
||||
},
|
||||
"-"(p1, p2) {
|
||||
var r = new Vec2();
|
||||
r.x = p1.x - p2.x;
|
||||
r.y = p1.y - p2.y;
|
||||
return r;
|
||||
},
|
||||
"=="(a, b) {
|
||||
return a.x == b.x && a.y == b.y;
|
||||
},
|
||||
"<"(a, b) {
|
||||
var r;
|
||||
/* lexicographic order */
|
||||
if (a.x == b.x)
|
||||
r = (a.y < b.y);
|
||||
else
|
||||
r = (a.x < b.x);
|
||||
return r;
|
||||
},
|
||||
"++"(a) {
|
||||
var r = new Vec2();
|
||||
r.x = a.x + 1;
|
||||
r.y = a.y + 1;
|
||||
return r;
|
||||
}
|
||||
},
|
||||
{
|
||||
left: Number,
|
||||
"*"(a, b) {
|
||||
return mul_scalar(b, a);
|
||||
}
|
||||
},
|
||||
{
|
||||
right: Number,
|
||||
"*"(a, b) {
|
||||
return mul_scalar(a, b);
|
||||
}
|
||||
});
|
||||
|
||||
Vec2 = class Vec2 extends vec2_ops
|
||||
{
|
||||
constructor(x, y) {
|
||||
super();
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
toString() {
|
||||
return "Vec2(" + this.x + "," + this.y + ")";
|
||||
}
|
||||
}
|
||||
|
||||
var a = new Vec2(1, 2);
|
||||
var b = new Vec2(3, 4);
|
||||
var r;
|
||||
|
||||
r = a * 2 + 3 * b;
|
||||
assert(r.x === 11 && r.y === 16);
|
||||
assert(a == a, true);
|
||||
assert(a == b, false);
|
||||
assert(a != a, false);
|
||||
assert(a < b, true);
|
||||
assert(a <= b, true);
|
||||
assert(b < a, false);
|
||||
assert(b <= a, false);
|
||||
assert(a <= a, true);
|
||||
assert(a >= a, true);
|
||||
a++;
|
||||
assert(a.x === 2 && a.y === 3);
|
||||
r = ++a;
|
||||
assert(a.x === 3 && a.y === 4);
|
||||
assert(r === a);
|
||||
}
|
||||
|
||||
function test_default_op()
|
||||
{
|
||||
assert(Object(1) + 2, 3);
|
||||
assert(Object(1) + true, 2);
|
||||
assert(-Object(1), -1);
|
||||
}
|
||||
|
||||
test_operators_create();
|
||||
test_operators();
|
||||
test_default_op();
|
256
quickjs/tests/test_qjscalc.js
Normal file
|
@ -0,0 +1,256 @@
|
|||
"use math";
|
||||
"use strict";
|
||||
|
||||
function assert(actual, expected, message) {
|
||||
if (arguments.length == 1)
|
||||
expected = true;
|
||||
|
||||
if (actual === expected)
|
||||
return;
|
||||
|
||||
if (actual !== null && expected !== null
|
||||
&& typeof actual == 'object' && typeof expected == 'object'
|
||||
&& actual.toString() === expected.toString())
|
||||
return;
|
||||
|
||||
throw Error("assertion failed: got |" + actual + "|" +
|
||||
", expected |" + expected + "|" +
|
||||
(message ? " (" + message + ")" : ""));
|
||||
}
|
||||
|
||||
function assertThrows(err, func)
|
||||
{
|
||||
var ex;
|
||||
ex = false;
|
||||
try {
|
||||
func();
|
||||
} catch(e) {
|
||||
ex = true;
|
||||
assert(e instanceof err);
|
||||
}
|
||||
assert(ex, true, "exception expected");
|
||||
}
|
||||
|
||||
// load more elaborate version of assert if available
|
||||
try { __loadScript("test_assert.js"); } catch(e) {}
|
||||
|
||||
/*----------------*/
|
||||
|
||||
function pow(a, n)
|
||||
{
|
||||
var r, i;
|
||||
r = 1;
|
||||
for(i = 0; i < n; i++)
|
||||
r *= a;
|
||||
return r;
|
||||
}
|
||||
|
||||
function test_integer()
|
||||
{
|
||||
var a, r;
|
||||
a = pow(3, 100);
|
||||
assert((a - 1) != a);
|
||||
assert(a == 515377520732011331036461129765621272702107522001);
|
||||
assert(a == 0x5a4653ca673768565b41f775d6947d55cf3813d1);
|
||||
assert(Integer.isInteger(1) === true);
|
||||
assert(Integer.isInteger(1.0) === false);
|
||||
|
||||
assert(Integer.floorLog2(0) === -1);
|
||||
assert(Integer.floorLog2(7) === 2);
|
||||
|
||||
r = 1 << 31;
|
||||
assert(r, 2147483648, "1 << 31 === 2147483648");
|
||||
|
||||
r = 1 << 32;
|
||||
assert(r, 4294967296, "1 << 32 === 4294967296");
|
||||
|
||||
r = (1 << 31) < 0;
|
||||
assert(r, false, "(1 << 31) < 0 === false");
|
||||
|
||||
assert(typeof 1 === "number");
|
||||
assert(typeof 9007199254740991 === "number");
|
||||
assert(typeof 9007199254740992 === "bigint");
|
||||
}
|
||||
|
||||
function test_float()
|
||||
{
|
||||
assert(typeof 1.0 === "bigfloat");
|
||||
assert(1 == 1.0);
|
||||
assert(1 !== 1.0);
|
||||
}
|
||||
|
||||
/* jscalc tests */
|
||||
|
||||
function test_modulo()
|
||||
{
|
||||
var i, p, a, b;
|
||||
|
||||
/* Euclidian modulo operator */
|
||||
assert((-3) % 2 == 1);
|
||||
assert(3 % (-2) == 1);
|
||||
|
||||
p = 101;
|
||||
for(i = 1; i < p; i++) {
|
||||
a = Integer.invmod(i, p);
|
||||
assert(a >= 0 && a < p);
|
||||
assert((i * a) % p == 1);
|
||||
}
|
||||
|
||||
assert(Integer.isPrime(2^107-1));
|
||||
assert(!Integer.isPrime((2^107-1) * (2^89-1)));
|
||||
a = Integer.factor((2^89-1)*2^3*11*13^2*1009);
|
||||
assert(a == [ 2,2,2,11,13,13,1009,618970019642690137449562111 ]);
|
||||
}
|
||||
|
||||
function test_fraction()
|
||||
{
|
||||
assert((1/3 + 1).toString(), "4/3")
|
||||
assert((2/3)^30, 1073741824/205891132094649);
|
||||
assert(1/3 < 2/3);
|
||||
assert(1/3 < 1);
|
||||
assert(1/3 == 1.0/3);
|
||||
assert(1.0/3 < 2/3);
|
||||
}
|
||||
|
||||
function test_mod()
|
||||
{
|
||||
var a, b, p;
|
||||
|
||||
a = Mod(3, 101);
|
||||
b = Mod(-1, 101);
|
||||
assert((a + b) == Mod(2, 101));
|
||||
assert(a ^ 100 == Mod(1, 101));
|
||||
|
||||
p = 2 ^ 607 - 1; /* mersenne prime */
|
||||
a = Mod(3, p) ^ (p - 1);
|
||||
assert(a == Mod(1, p));
|
||||
}
|
||||
|
||||
function test_polynomial()
|
||||
{
|
||||
var a, b, q, r, t, i;
|
||||
a = (1 + X) ^ 4;
|
||||
assert(a == X^4+4*X^3+6*X^2+4*X+1);
|
||||
|
||||
r = (1 + X);
|
||||
q = (1+X+X^2);
|
||||
b = (1 - X^2);
|
||||
a = q * b + r;
|
||||
t = Polynomial.divrem(a, b);
|
||||
assert(t[0] == q);
|
||||
assert(t[1] == r);
|
||||
|
||||
a = 1 + 2*X + 3*X^2;
|
||||
assert(a.apply(0.1) == 1.23);
|
||||
|
||||
a = 1-2*X^2+2*X^3;
|
||||
assert(deriv(a) == (6*X^2-4*X));
|
||||
assert(deriv(integ(a)) == a);
|
||||
|
||||
a = (X-1)*(X-2)*(X-3)*(X-4)*(X-0.1);
|
||||
r = polroots(a);
|
||||
for(i = 0; i < r.length; i++) {
|
||||
b = abs(a.apply(r[i]));
|
||||
assert(b <= 1e-13);
|
||||
}
|
||||
}
|
||||
|
||||
function test_poly_mod()
|
||||
{
|
||||
var a, p;
|
||||
|
||||
/* modulo using polynomials */
|
||||
p = X^2 + X + 1;
|
||||
a = PolyMod(3+X, p) ^ 10;
|
||||
assert(a == PolyMod(-3725*X-18357, p));
|
||||
|
||||
a = PolyMod(1/X, 1+X^2);
|
||||
assert(a == PolyMod(-X, X^2+1));
|
||||
}
|
||||
|
||||
function test_rfunc()
|
||||
{
|
||||
var a;
|
||||
a = (X+1)/((X+1)*(X-1));
|
||||
assert(a == 1/(X-1));
|
||||
a = (X + 2) / (X - 2);
|
||||
assert(a.apply(1/3) == -7/5);
|
||||
|
||||
assert(deriv((X^2-X+1)/(X-1)) == (X^2-2*X)/(X^2-2*X+1));
|
||||
}
|
||||
|
||||
function test_series()
|
||||
{
|
||||
var a, b;
|
||||
a = 1+X+O(X^5);
|
||||
b = a.inverse();
|
||||
assert(b == 1-X+X^2-X^3+X^4+O(X^5));
|
||||
assert(deriv(b) == -1+2*X-3*X^2+4*X^3+O(X^4));
|
||||
assert(deriv(integ(b)) == b);
|
||||
|
||||
a = Series(1/(1-X), 5);
|
||||
assert(a == 1+X+X^2+X^3+X^4+O(X^5));
|
||||
b = a.apply(0.1);
|
||||
assert(b == 1.1111);
|
||||
|
||||
assert(exp(3*X^2+O(X^10)) == 1+3*X^2+9/2*X^4+9/2*X^6+27/8*X^8+O(X^10));
|
||||
assert(sin(X+O(X^6)) == X-1/6*X^3+1/120*X^5+O(X^6));
|
||||
assert(cos(X+O(X^6)) == 1-1/2*X^2+1/24*X^4+O(X^6));
|
||||
assert(tan(X+O(X^8)) == X+1/3*X^3+2/15*X^5+17/315*X^7+O(X^8));
|
||||
assert((1+X+O(X^6))^(2+X) == 1+2*X+2*X^2+3/2*X^3+5/6*X^4+5/12*X^5+O(X^6));
|
||||
}
|
||||
|
||||
function test_matrix()
|
||||
{
|
||||
var a, b, r;
|
||||
a = [[1, 2],[3, 4]];
|
||||
b = [3, 4];
|
||||
r = a * b;
|
||||
assert(r == [11, 25]);
|
||||
r = (a^-1) * 2;
|
||||
assert(r == [[-4, 2],[3, -1]]);
|
||||
|
||||
assert(norm2([1,2,3]) == 14);
|
||||
|
||||
assert(diag([1,2,3]) == [ [ 1, 0, 0 ], [ 0, 2, 0 ], [ 0, 0, 3 ] ]);
|
||||
assert(trans(a) == [ [ 1, 3 ], [ 2, 4 ] ]);
|
||||
assert(trans([1,2,3]) == [[1,2,3]]);
|
||||
assert(trace(a) == 5);
|
||||
|
||||
assert(charpoly(Matrix.hilbert(4)) == X^4-176/105*X^3+3341/12600*X^2-41/23625*X+1/6048000);
|
||||
assert(det(Matrix.hilbert(4)) == 1/6048000);
|
||||
|
||||
a = [[1,2,1],[-2,-3,1],[3,5,0]];
|
||||
assert(rank(a) == 2);
|
||||
assert(ker(a) == [ [ 5 ], [ -3 ], [ 1 ] ]);
|
||||
|
||||
assert(dp([1, 2, 3], [3, -4, -7]) === -26);
|
||||
assert(cp([1, 2, 3], [3, -4, -7]) == [ -2, 16, -10 ]);
|
||||
}
|
||||
|
||||
function assert_eq(a, ref)
|
||||
{
|
||||
assert(abs(a / ref - 1.0) <= 1e-15);
|
||||
}
|
||||
|
||||
function test_trig()
|
||||
{
|
||||
assert_eq(sin(1/2), 0.479425538604203);
|
||||
assert_eq(sin(2+3*I), 9.154499146911428-4.168906959966565*I);
|
||||
assert_eq(cos(2+3*I), -4.189625690968807-9.109227893755337*I);
|
||||
assert_eq((2+0.5*I)^(1.1-0.5*I), 2.494363021357619-0.23076804554558092*I);
|
||||
assert_eq(sqrt(2*I), 1 + I);
|
||||
}
|
||||
|
||||
test_integer();
|
||||
test_float();
|
||||
|
||||
test_modulo();
|
||||
test_fraction();
|
||||
test_mod();
|
||||
test_polynomial();
|
||||
test_poly_mod();
|
||||
test_rfunc();
|
||||
test_series();
|
||||
test_matrix();
|
||||
test_trig();
|
281
quickjs/tests/test_std.js
Normal file
|
@ -0,0 +1,281 @@
|
|||
import * as std from "std";
|
||||
import * as os from "os";
|
||||
|
||||
function assert(actual, expected, message) {
|
||||
if (arguments.length == 1)
|
||||
expected = true;
|
||||
|
||||
if (actual === expected)
|
||||
return;
|
||||
|
||||
if (actual !== null && expected !== null
|
||||
&& typeof actual == 'object' && typeof expected == 'object'
|
||||
&& actual.toString() === expected.toString())
|
||||
return;
|
||||
|
||||
throw Error("assertion failed: got |" + actual + "|" +
|
||||
", expected |" + expected + "|" +
|
||||
(message ? " (" + message + ")" : ""));
|
||||
}
|
||||
|
||||
// load more elaborate version of assert if available
|
||||
try { std.loadScript("test_assert.js"); } catch(e) {}
|
||||
|
||||
/*----------------*/
|
||||
|
||||
function test_printf()
|
||||
{
|
||||
assert(std.sprintf("a=%d s=%s", 123, "abc"), "a=123 s=abc");
|
||||
assert(std.sprintf("%010d", 123), "0000000123");
|
||||
assert(std.sprintf("%x", -2), "fffffffe");
|
||||
assert(std.sprintf("%lx", -2), "fffffffffffffffe");
|
||||
assert(std.sprintf("%10.1f", 2.1), " 2.1");
|
||||
assert(std.sprintf("%*.*f", 10, 2, -2.13), " -2.13");
|
||||
assert(std.sprintf("%#lx", 0x7fffffffffffffffn), "0x7fffffffffffffff");
|
||||
}
|
||||
|
||||
function test_file1()
|
||||
{
|
||||
var f, len, str, size, buf, ret, i, str1;
|
||||
|
||||
f = std.tmpfile();
|
||||
str = "hello world\n";
|
||||
f.puts(str);
|
||||
|
||||
f.seek(0, std.SEEK_SET);
|
||||
str1 = f.readAsString();
|
||||
assert(str1 === str);
|
||||
|
||||
f.seek(0, std.SEEK_END);
|
||||
size = f.tell();
|
||||
assert(size === str.length);
|
||||
|
||||
f.seek(0, std.SEEK_SET);
|
||||
|
||||
buf = new Uint8Array(size);
|
||||
ret = f.read(buf.buffer, 0, size);
|
||||
assert(ret === size);
|
||||
for(i = 0; i < size; i++)
|
||||
assert(buf[i] === str.charCodeAt(i));
|
||||
|
||||
f.close();
|
||||
}
|
||||
|
||||
function test_file2()
|
||||
{
|
||||
var f, str, i, size;
|
||||
f = std.tmpfile();
|
||||
str = "hello world\n";
|
||||
size = str.length;
|
||||
for(i = 0; i < size; i++)
|
||||
f.putByte(str.charCodeAt(i));
|
||||
f.seek(0, std.SEEK_SET);
|
||||
for(i = 0; i < size; i++) {
|
||||
assert(str.charCodeAt(i) === f.getByte());
|
||||
}
|
||||
assert(f.getByte() === -1);
|
||||
f.close();
|
||||
}
|
||||
|
||||
function test_getline()
|
||||
{
|
||||
var f, line, line_count, lines, i;
|
||||
|
||||
lines = ["hello world", "line 1", "line 2" ];
|
||||
f = std.tmpfile();
|
||||
for(i = 0; i < lines.length; i++) {
|
||||
f.puts(lines[i], "\n");
|
||||
}
|
||||
|
||||
f.seek(0, std.SEEK_SET);
|
||||
assert(!f.eof());
|
||||
line_count = 0;
|
||||
for(;;) {
|
||||
line = f.getline();
|
||||
if (line === null)
|
||||
break;
|
||||
assert(line == lines[line_count]);
|
||||
line_count++;
|
||||
}
|
||||
assert(f.eof());
|
||||
assert(line_count === lines.length);
|
||||
|
||||
f.close();
|
||||
}
|
||||
|
||||
function test_popen()
|
||||
{
|
||||
var str, f, fname = "tmp_file.txt";
|
||||
var content = "hello world";
|
||||
|
||||
f = std.open(fname, "w");
|
||||
f.puts(content);
|
||||
f.close();
|
||||
|
||||
/* test loadFile */
|
||||
assert(std.loadFile(fname), content);
|
||||
|
||||
/* execute the 'cat' shell command */
|
||||
f = std.popen("cat " + fname, "r");
|
||||
str = f.readAsString();
|
||||
f.close();
|
||||
|
||||
assert(str, content);
|
||||
|
||||
os.remove(fname);
|
||||
}
|
||||
|
||||
function test_ext_json()
|
||||
{
|
||||
var expected, input, obj;
|
||||
expected = '{"x":false,"y":true,"z2":null,"a":[1,8,160],"s":"str"}';
|
||||
input = `{ "x":false, /*comments are allowed */
|
||||
"y":true, // also a comment
|
||||
z2:null, // unquoted property names
|
||||
"a":[+1,0o10,0xa0,], // plus prefix, octal, hexadecimal
|
||||
"s":"str",} // trailing comma in objects and arrays
|
||||
`;
|
||||
obj = std.parseExtJSON(input);
|
||||
assert(JSON.stringify(obj), expected);
|
||||
}
|
||||
|
||||
function test_os()
|
||||
{
|
||||
var fd, fpath, fname, fdir, buf, buf2, i, files, err, fdate, st, link_path;
|
||||
|
||||
assert(os.isatty(0));
|
||||
|
||||
fdir = "test_tmp_dir";
|
||||
fname = "tmp_file.txt";
|
||||
fpath = fdir + "/" + fname;
|
||||
link_path = fdir + "/test_link";
|
||||
|
||||
os.remove(link_path);
|
||||
os.remove(fpath);
|
||||
os.remove(fdir);
|
||||
|
||||
err = os.mkdir(fdir, 0o755);
|
||||
assert(err === 0);
|
||||
|
||||
fd = os.open(fpath, os.O_RDWR | os.O_CREAT | os.O_TRUNC);
|
||||
assert(fd >= 0);
|
||||
|
||||
buf = new Uint8Array(10);
|
||||
for(i = 0; i < buf.length; i++)
|
||||
buf[i] = i;
|
||||
assert(os.write(fd, buf.buffer, 0, buf.length) === buf.length);
|
||||
|
||||
assert(os.seek(fd, 0, std.SEEK_SET) === 0);
|
||||
buf2 = new Uint8Array(buf.length);
|
||||
assert(os.read(fd, buf2.buffer, 0, buf2.length) === buf2.length);
|
||||
|
||||
for(i = 0; i < buf.length; i++)
|
||||
assert(buf[i] == buf2[i]);
|
||||
|
||||
if (typeof BigInt !== "undefined") {
|
||||
assert(os.seek(fd, BigInt(6), std.SEEK_SET), BigInt(6));
|
||||
assert(os.read(fd, buf2.buffer, 0, 1) === 1);
|
||||
assert(buf[6] == buf2[0]);
|
||||
}
|
||||
|
||||
assert(os.close(fd) === 0);
|
||||
|
||||
[files, err] = os.readdir(fdir);
|
||||
assert(err, 0);
|
||||
assert(files.indexOf(fname) >= 0);
|
||||
|
||||
fdate = 10000;
|
||||
|
||||
err = os.utimes(fpath, fdate, fdate);
|
||||
assert(err, 0);
|
||||
|
||||
[st, err] = os.stat(fpath);
|
||||
assert(err, 0);
|
||||
assert(st.mode & os.S_IFMT, os.S_IFREG);
|
||||
assert(st.mtime, fdate);
|
||||
|
||||
err = os.symlink(fname, link_path);
|
||||
assert(err === 0);
|
||||
|
||||
[st, err] = os.lstat(link_path);
|
||||
assert(err, 0);
|
||||
assert(st.mode & os.S_IFMT, os.S_IFLNK);
|
||||
|
||||
[buf, err] = os.readlink(link_path);
|
||||
assert(err, 0);
|
||||
assert(buf, fname);
|
||||
|
||||
assert(os.remove(link_path) === 0);
|
||||
|
||||
[buf, err] = os.getcwd();
|
||||
assert(err, 0);
|
||||
|
||||
[buf2, err] = os.realpath(".");
|
||||
assert(err, 0);
|
||||
|
||||
assert(buf, buf2);
|
||||
|
||||
assert(os.remove(fpath) === 0);
|
||||
|
||||
fd = os.open(fpath, os.O_RDONLY);
|
||||
assert(fd < 0);
|
||||
|
||||
assert(os.remove(fdir) === 0);
|
||||
}
|
||||
|
||||
function test_os_exec()
|
||||
{
|
||||
var ret, fds, pid, f, status;
|
||||
|
||||
ret = os.exec(["true"]);
|
||||
assert(ret, 0);
|
||||
|
||||
ret = os.exec(["/bin/sh", "-c", "exit 1"], { usePath: false });
|
||||
assert(ret, 1);
|
||||
|
||||
fds = os.pipe();
|
||||
pid = os.exec(["sh", "-c", "echo $FOO"], {
|
||||
stdout: fds[1],
|
||||
block: false,
|
||||
env: { FOO: "hello" },
|
||||
} );
|
||||
assert(pid >= 0);
|
||||
os.close(fds[1]); /* close the write end (as it is only in the child) */
|
||||
f = std.fdopen(fds[0], "r");
|
||||
assert(f.getline(), "hello");
|
||||
assert(f.getline(), null);
|
||||
f.close();
|
||||
[ret, status] = os.waitpid(pid, 0);
|
||||
assert(ret, pid);
|
||||
assert(status & 0x7f, 0); /* exited */
|
||||
assert(status >> 8, 0); /* exit code */
|
||||
|
||||
pid = os.exec(["cat"], { block: false } );
|
||||
assert(pid >= 0);
|
||||
os.kill(pid, os.SIGQUIT);
|
||||
[ret, status] = os.waitpid(pid, 0);
|
||||
assert(ret, pid);
|
||||
assert(status & 0x7f, os.SIGQUIT);
|
||||
}
|
||||
|
||||
function test_timer()
|
||||
{
|
||||
var th, i;
|
||||
|
||||
/* just test that a timer can be inserted and removed */
|
||||
th = [];
|
||||
for(i = 0; i < 3; i++)
|
||||
th[i] = os.setTimeout(function () { }, 1000);
|
||||
for(i = 0; i < 3; i++)
|
||||
os.clearTimeout(th[i]);
|
||||
}
|
||||
|
||||
test_printf();
|
||||
test_file1();
|
||||
test_file2();
|
||||
test_getline();
|
||||
test_popen();
|
||||
test_os();
|
||||
test_os_exec();
|
||||
test_timer();
|
||||
test_ext_json();
|
62
quickjs/tests/test_worker.js
Normal file
|
@ -0,0 +1,62 @@
|
|||
/* os.Worker API test */
|
||||
import * as std from "std";
|
||||
import * as os from "os";
|
||||
|
||||
function assert(actual, expected, message) {
|
||||
if (arguments.length == 1)
|
||||
expected = true;
|
||||
|
||||
if (actual === expected)
|
||||
return;
|
||||
|
||||
if (actual !== null && expected !== null
|
||||
&& typeof actual == 'object' && typeof expected == 'object'
|
||||
&& actual.toString() === expected.toString())
|
||||
return;
|
||||
|
||||
throw Error("assertion failed: got |" + actual + "|" +
|
||||
", expected |" + expected + "|" +
|
||||
(message ? " (" + message + ")" : ""));
|
||||
}
|
||||
|
||||
var worker;
|
||||
|
||||
function test_worker()
|
||||
{
|
||||
var counter;
|
||||
|
||||
worker = new os.Worker("./test_worker_module.js");
|
||||
|
||||
counter = 0;
|
||||
worker.onmessage = function (e) {
|
||||
var ev = e.data;
|
||||
// print("recv", JSON.stringify(ev));
|
||||
switch(ev.type) {
|
||||
case "num":
|
||||
assert(ev.num, counter);
|
||||
counter++;
|
||||
if (counter == 10) {
|
||||
/* test SharedArrayBuffer modification */
|
||||
let sab = new SharedArrayBuffer(10);
|
||||
let buf = new Uint8Array(sab);
|
||||
worker.postMessage({ type: "sab", buf: buf });
|
||||
}
|
||||
break;
|
||||
case "sab_done":
|
||||
{
|
||||
let buf = ev.buf;
|
||||
/* check that the SharedArrayBuffer was modified */
|
||||
assert(buf[2], 10);
|
||||
worker.postMessage({ type: "abort" });
|
||||
}
|
||||
break;
|
||||
case "done":
|
||||
/* terminate */
|
||||
worker.onmessage = null;
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
test_worker();
|
31
quickjs/tests/test_worker_module.js
Normal file
|
@ -0,0 +1,31 @@
|
|||
/* Worker code for test_worker.js */
|
||||
import * as std from "std";
|
||||
import * as os from "os";
|
||||
|
||||
var parent = os.Worker.parent;
|
||||
|
||||
function handle_msg(e) {
|
||||
var ev = e.data;
|
||||
// print("child_recv", JSON.stringify(ev));
|
||||
switch(ev.type) {
|
||||
case "abort":
|
||||
parent.postMessage({ type: "done" });
|
||||
break;
|
||||
case "sab":
|
||||
/* modify the SharedArrayBuffer */
|
||||
ev.buf[2] = 10;
|
||||
parent.postMessage({ type: "sab_done", buf: ev.buf });
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function worker_main() {
|
||||
var i;
|
||||
|
||||
parent.onmessage = handle_msg;
|
||||
for(i = 0; i < 10; i++) {
|
||||
parent.postMessage({ type: "num", num: i });
|
||||
}
|
||||
}
|
||||
|
||||
worker_main();
|
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
|
3057
quickjs/unicode_gen.c
Normal file
289
quickjs/unicode_gen_def.h
Normal file
|
@ -0,0 +1,289 @@
|
|||
#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(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(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
|
|
@ -1,100 +1,149 @@
|
|||
#ifndef TWODPHYSICS_H
|
||||
#define TWODPHYSICS_H
|
||||
|
||||
#include "script.h"
|
||||
#include <chipmunk/chipmunk.h>
|
||||
|
||||
#include "render.h"
|
||||
|
||||
struct gameobject;
|
||||
|
||||
extern cpBody *ballBody;
|
||||
extern float phys2d_gravity;
|
||||
extern int physOn;
|
||||
extern cpSpace *space;
|
||||
|
||||
|
||||
extern struct rgba color_white;
|
||||
extern struct rgba color_black;
|
||||
|
||||
extern struct rgba disabled_color;
|
||||
extern struct rgba dynamic_color;
|
||||
extern struct rgba kinematic_color;
|
||||
extern struct rgba static_color;
|
||||
extern struct rgba sleep_color;
|
||||
|
||||
|
||||
struct phys2d_shape {
|
||||
cpShape *shape;
|
||||
struct gameobject *go;
|
||||
cpShape *shape;
|
||||
int go;
|
||||
void *data;
|
||||
void (*debugdraw)(void *data);
|
||||
float (*moi)(void *data, float mass);
|
||||
};
|
||||
|
||||
/* Circles are the fastest collier type */
|
||||
struct phys2d_circle {
|
||||
float radius;
|
||||
float offset[2];
|
||||
struct phys2d_shape shape;
|
||||
float radius;
|
||||
cpVect offset;
|
||||
struct phys2d_shape shape;
|
||||
};
|
||||
|
||||
/* A single segment */
|
||||
struct phys2d_segment {
|
||||
float a[2];
|
||||
float b[2];
|
||||
float thickness;
|
||||
struct phys2d_shape shape;
|
||||
};
|
||||
|
||||
struct phys2d_box {
|
||||
float w;
|
||||
float h;
|
||||
float offset[2];
|
||||
float r;
|
||||
struct phys2d_shape shape;
|
||||
};
|
||||
|
||||
struct phys2d_edge {
|
||||
int n;
|
||||
float *points;
|
||||
float thickness;
|
||||
cpShape **shapes;
|
||||
struct phys2d_shape shape;
|
||||
float a[2];
|
||||
float b[2];
|
||||
float thickness;
|
||||
struct phys2d_shape shape;
|
||||
};
|
||||
|
||||
/* A convex polygon; defined as the convex hull around the given set of points */
|
||||
struct phys2d_poly {
|
||||
int n;
|
||||
float *points;
|
||||
float radius;
|
||||
struct phys2d_shape shape;
|
||||
cpVect *points;
|
||||
float radius;
|
||||
struct phys2d_shape shape;
|
||||
};
|
||||
|
||||
struct phys2d_circle *Make2DCircle(struct gameobject *go);
|
||||
void phys2d_circleinit(struct phys2d_circle *circle, struct gameobject *go);
|
||||
/* A box shape; a type of a polygon collider */
|
||||
struct phys2d_box {
|
||||
float w;
|
||||
float h;
|
||||
float offset[2];
|
||||
float rotation;
|
||||
float r;
|
||||
struct phys2d_shape shape;
|
||||
};
|
||||
|
||||
/* An edge with no volume. Cannot collide with each other. Join to make levels. Static only. */
|
||||
struct phys2d_edge {
|
||||
cpVect *points;
|
||||
float thickness;
|
||||
cpShape **shapes;
|
||||
int closed; /* True if the first and last points should be connected */
|
||||
struct phys2d_shape shape;
|
||||
int draws;
|
||||
};
|
||||
|
||||
struct phys2d_circle *Make2DCircle(int go);
|
||||
void phys2d_circledel(struct phys2d_circle *c);
|
||||
void phys2d_applycircle(struct phys2d_circle *circle);
|
||||
void phys2d_dbgdrawcircle(struct phys2d_circle *circle);
|
||||
void circle_gui(struct phys2d_circle *circle);
|
||||
float phys2d_circle_moi(struct phys2d_circle *c, float m);
|
||||
|
||||
struct phys2d_segment *Make2DSegment(struct gameobject *go);
|
||||
void phys2d_seginit(struct phys2d_segment *seg, struct gameobject *go);
|
||||
void phys2d_segdel(struct phys2d_segment *seg);
|
||||
void phys2d_applyseg(struct phys2d_segment *seg);
|
||||
void phys2d_dbgdrawseg(struct phys2d_segment *seg);
|
||||
void segment_gui(struct phys2d_segment *seg);
|
||||
|
||||
struct phys2d_box *Make2DBox(struct gameobject *go);
|
||||
void phys2d_boxinit(struct phys2d_box *box, struct gameobject *go);
|
||||
struct phys2d_box *Make2DBox(int go);
|
||||
void phys2d_boxdel(struct phys2d_box *box);
|
||||
void phys2d_applybox(struct phys2d_box *box);
|
||||
void phys2d_dbgdrawbox(struct phys2d_box *box);
|
||||
void box_gui(struct phys2d_box *box);
|
||||
float phys2d_box_moi(struct phys2d_box *box, float m);
|
||||
|
||||
struct phys2d_poly *Make2DPoly(struct gameobject *go);
|
||||
void phys2d_polyinit(struct phys2d_poly *poly, struct gameobject *go);
|
||||
struct phys2d_poly *Make2DPoly(int go);
|
||||
void phys2d_polydel(struct phys2d_poly *poly);
|
||||
void phys2d_applypoly(struct phys2d_poly *poly);
|
||||
void phys2d_dbgdrawpoly(struct phys2d_poly *poly);
|
||||
void phys2d_polyaddvert(struct phys2d_poly *poly);
|
||||
void poly_gui(struct phys2d_poly *poly);
|
||||
void phys2d_poly_setverts(struct phys2d_poly *poly, cpVect *verts);
|
||||
float phys2d_poly_moi(struct phys2d_poly *poly, float m);
|
||||
|
||||
struct phys2d_edge *Make2DEdge(struct gameobject *go);
|
||||
void phys2d_edgeinit(struct phys2d_edge *edge, struct gameobject *go);
|
||||
struct phys2d_edge *Make2DEdge(int go);
|
||||
void phys2d_edgedel(struct phys2d_edge *edge);
|
||||
void phys2d_applyedge(struct phys2d_edge *edge);
|
||||
void phys2d_edgeshapeapply(struct phys2d_shape *mshape, cpShape * shape);
|
||||
void phys2d_dbgdrawedge(struct phys2d_edge *edge);
|
||||
void phys2d_edgeaddvert(struct phys2d_edge *edge);
|
||||
void edge_gui(struct phys2d_edge *edge);
|
||||
void phys2d_edge_rmvert(struct phys2d_edge *edge, int index);
|
||||
float phys2d_edge_moi(struct phys2d_edge *edge, float m);
|
||||
|
||||
void phys2d_edge_setvert(struct phys2d_edge *edge, int index, cpVect val);
|
||||
void phys2d_edge_clearverts(struct phys2d_edge *edge);
|
||||
void phys2d_edge_addverts(struct phys2d_edge *edge, cpVect *verts);
|
||||
void phys2d_edge_set_sensor(struct phys2d_edge *edge, int sensor);
|
||||
void phys2d_edge_set_enabled(struct phys2d_edge *edge, int enabled);
|
||||
|
||||
void phys2d_init();
|
||||
void phys2d_update(float deltaT);
|
||||
void phys2d_apply();
|
||||
cpShape *phys2d_query_pos(cpVect pos);
|
||||
int *phys2d_query_box(cpVect pos, cpVect wh);
|
||||
|
||||
struct phys_cbs {
|
||||
struct callee begin;
|
||||
struct callee separate;
|
||||
};
|
||||
|
||||
struct shape_cb {
|
||||
struct phys2d_shape *shape;
|
||||
struct phys_cbs cbs;
|
||||
};
|
||||
|
||||
void fire_hits();
|
||||
|
||||
void phys2d_rm_go_handlers(int go);
|
||||
void phys2d_set_gravity(cpVect v);
|
||||
|
||||
void shape_enabled(struct phys2d_shape *shape, int enabled);
|
||||
int shape_is_enabled(struct phys2d_shape *shape);
|
||||
void shape_set_sensor(struct phys2d_shape *shape, int sensor);
|
||||
int shape_get_sensor(struct phys2d_shape *shape);
|
||||
|
||||
struct rgba shape_color_s(cpShape *shape);
|
||||
|
||||
void shape_gui(struct phys2d_shape *shape);
|
||||
void phys2d_setup_handlers(int go);
|
||||
int *phys2d_query_shape(struct phys2d_shape *shape);
|
||||
int *phys2d_query_box_points(cpVect pos, cpVect wh, cpVect *points, int n);
|
||||
|
||||
void flush_collide_cbs();
|
||||
|
||||
void phys2d_reindex_body(cpBody *body);
|
||||
cpVect world2go(struct gameobject *go, cpVect worldpos);
|
||||
cpVect go2world(struct gameobject *go, cpVect gopos);
|
||||
extern unsigned int category_masks[32];
|
||||
void set_cat_mask(int cat, unsigned int mask);
|
||||
int phys2d_in_air(cpBody *body);
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#ifndef THREEDPHYSICS_H
|
||||
#define THREEDPHYSICS_H
|
||||
|
||||
|
||||
#endif
|
|
@ -42,26 +42,26 @@ glm::vec3 ThirdPersonFollow::CalculatePosition()
|
|||
glm::vec3 p1 = CalculateCenter();
|
||||
|
||||
glm::vec3 p2 =
|
||||
XDirPosts ? GetPostsOffset(TFOR.Right(),
|
||||
FloatWidths.
|
||||
x) : GetExtentsOffset(TFOR.Right(),
|
||||
FloatWidths.x,
|
||||
TargetOffset.x,
|
||||
AnchorWidths.x);
|
||||
XDirPosts ? GetPostsOffset(TFOR.Right(),
|
||||
FloatWidths.
|
||||
x) : GetExtentsOffset(TFOR.Right(),
|
||||
FloatWidths.x,
|
||||
TargetOffset.x,
|
||||
AnchorWidths.x);
|
||||
glm::vec3 p3 =
|
||||
YDirPosts ? GetPostsOffset(TFOR.Up(),
|
||||
FloatWidths.
|
||||
y) : GetExtentsOffset(TFOR.Up(),
|
||||
FloatWidths.y,
|
||||
TargetOffset.y,
|
||||
AnchorWidths.y);
|
||||
YDirPosts ? GetPostsOffset(TFOR.Up(),
|
||||
FloatWidths.
|
||||
y) : GetExtentsOffset(TFOR.Up(),
|
||||
FloatWidths.y,
|
||||
TargetOffset.y,
|
||||
AnchorWidths.y);
|
||||
glm::vec3 p4 =
|
||||
ZDirPosts ? GetPostsOffset(TFOR.Back(),
|
||||
FloatWidths.
|
||||
z) : GetExtentsOffset(TFOR.Back(),
|
||||
FloatWidths.z,
|
||||
TargetOffset.z,
|
||||
AnchorWidths.z);
|
||||
ZDirPosts ? GetPostsOffset(TFOR.Back(),
|
||||
FloatWidths.
|
||||
z) : GetExtentsOffset(TFOR.Back(),
|
||||
FloatWidths.z,
|
||||
TargetOffset.z,
|
||||
AnchorWidths.z);
|
||||
|
||||
return p1 + p2 + p3 + p4;
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ glm::vec3 ThirdPersonFollow::CalculatePosition()
|
|||
glm::vec3 ThirdPersonFollow::CalculateCenter()
|
||||
{
|
||||
return Target->get_global_translation() +
|
||||
TFOR.TransformDirection(Offset) + (mytransform->Back() * Distance);
|
||||
TFOR.TransformDirection(Offset) + (mytransform->Back() * Distance);
|
||||
}
|
||||
|
||||
glm::vec3 ThirdPersonFollow::
|
||||
|
@ -82,37 +82,37 @@ GetPostsOffset(const glm::vec3 & DirectionVector, float AnchorWidth)
|
|||
|
||||
glm::vec3 ThirdPersonFollow::
|
||||
GetExtentsOffset(const glm::vec3 & DirectionVector, float AnchorWidth,
|
||||
float TOffset, float Width)
|
||||
float TOffset, float Width)
|
||||
{
|
||||
|
||||
float negated_offset_sign = ((0 <= TOffset) - (TOffset < 0)) * -1.f;
|
||||
float TotalWidth = AnchorWidth + Width;
|
||||
|
||||
if (glm::abs(TOffset) > TotalWidth
|
||||
&& !glm::epsilonEqual(glm::abs(TOffset), TotalWidth, 0.5f))
|
||||
return DirectionVector * TotalWidth * negated_offset_sign;
|
||||
&& !glm::epsilonEqual(glm::abs(TOffset), TotalWidth, 0.5f))
|
||||
return DirectionVector * TotalWidth * negated_offset_sign;
|
||||
else {
|
||||
if (glm::abs(TOffset) >= AnchorWidth)
|
||||
return DirectionVector * AnchorWidth * negated_offset_sign;
|
||||
else
|
||||
return DirectionVector * TOffset * -1.f;
|
||||
if (glm::abs(TOffset) >= AnchorWidth)
|
||||
return DirectionVector * AnchorWidth * negated_offset_sign;
|
||||
else
|
||||
return DirectionVector * TOffset * -1.f;
|
||||
}
|
||||
|
||||
return glm::vec3(0.f);
|
||||
}
|
||||
|
||||
glm::vec3 ThirdPersonFollow::FrameBasedVectorLerp(const glm::vec3 & From,
|
||||
const glm::vec3 & To,
|
||||
const glm::vec3 & Speeds,
|
||||
float Tick)
|
||||
const glm::vec3 & To,
|
||||
const glm::vec3 & Speeds,
|
||||
float Tick)
|
||||
{
|
||||
// Previously "FORTransform.TransformVector(Speeds)
|
||||
glm::vec3 TSpeed = glm::abs(TFOR.TransformDirection(Speeds));
|
||||
glm::vec3 TOffset = glm::abs(TFOR.TransformDirection(TargetOffset));
|
||||
glm::vec3 TAnchorWidths =
|
||||
glm::abs(TFOR.TransformDirection(AnchorWidths));
|
||||
glm::abs(TFOR.TransformDirection(AnchorWidths));
|
||||
glm::vec3 TFloatWidths =
|
||||
glm::abs(TFOR.TransformDirection(FloatWidths));
|
||||
glm::abs(TFOR.TransformDirection(FloatWidths));
|
||||
|
||||
|
||||
|
||||
|
@ -124,14 +124,14 @@ glm::vec3 ThirdPersonFollow::FrameBasedVectorLerp(const glm::vec3 & From,
|
|||
|
||||
|
||||
float xAlpha =
|
||||
glm::clamp((bUseX ? AnchorSpeed : TSpeed.x) * Tick, 0.f, 1.f);
|
||||
glm::clamp((bUseX ? AnchorSpeed : TSpeed.x) * Tick, 0.f, 1.f);
|
||||
float yAlpha =
|
||||
glm::clamp((bUseY ? AnchorSpeed : TSpeed.y) * Tick, 0.f, 1.f);
|
||||
glm::clamp((bUseY ? AnchorSpeed : TSpeed.y) * Tick, 0.f, 1.f);
|
||||
float zAlpha =
|
||||
glm::clamp((bUseZ ? AnchorSpeed : TSpeed.z) * Tick, 0.f, 1.f);
|
||||
glm::clamp((bUseZ ? AnchorSpeed : TSpeed.z) * Tick, 0.f, 1.f);
|
||||
|
||||
return VectorLerpPiecewise(From, To,
|
||||
glm::vec3(xAlpha, yAlpha, zAlpha));
|
||||
glm::vec3(xAlpha, yAlpha, zAlpha));
|
||||
}
|
||||
|
||||
int float_epsilon(mfloat_t a, mfloat_t b, mfloat_t e)
|
||||
|
@ -165,11 +165,11 @@ void ThirdPersonFollow::CalculateTargets()
|
|||
// For rotation
|
||||
// TODO: Check of this implementation is the same as UKismetMath FindLookAtRotation
|
||||
TargetRotation =
|
||||
RemoveLockedRotation(glm::quat
|
||||
(mytransform->
|
||||
get_global_transform()->get_origin() -
|
||||
Target->
|
||||
get_global_transform()->get_origin()));
|
||||
RemoveLockedRotation(glm::quat
|
||||
(mytransform->
|
||||
get_global_transform()->get_origin() -
|
||||
Target->
|
||||
get_global_transform()->get_origin()));
|
||||
}
|
||||
|
||||
follow_removelockedrot()
|
||||
|
@ -185,11 +185,11 @@ RemoveLockedRotation(const glm::quat & CurrentRotation)
|
|||
//
|
||||
|
||||
NewRotator.x =
|
||||
LockRoll ? mytransform->get_rotation().x : CurrentRotator.x;
|
||||
LockRoll ? mytransform->get_rotation().x : CurrentRotator.x;
|
||||
NewRotator.y =
|
||||
LockPitch ? mytransform->get_rotation().y : CurrentRotator.y;
|
||||
LockPitch ? mytransform->get_rotation().y : CurrentRotator.y;
|
||||
NewRotator.z =
|
||||
LockYaw ? mytransform->get_rotation().z : CurrentRotator.z;
|
||||
LockYaw ? mytransform->get_rotation().z : CurrentRotator.z;
|
||||
|
||||
return glm::quat(NewRotator);
|
||||
}
|
||||
|
@ -199,11 +199,11 @@ RemoveLockedRotation(const glm::quat & CurrentRotation)
|
|||
void ThirdPersonFollow::CalculateTargetOffset()
|
||||
{
|
||||
glm::vec3 p1 =
|
||||
(mytransform->Forward() * Distance) +
|
||||
TFOR.TransformDirection(Offset) +
|
||||
mytransform->get_global_translation();
|
||||
(mytransform->Forward() * Distance) +
|
||||
TFOR.TransformDirection(Offset) +
|
||||
mytransform->get_global_translation();
|
||||
glm::vec3 p2 =
|
||||
TFOR.InverseTransformDirection(Target->get_global_translation());
|
||||
TFOR.InverseTransformDirection(Target->get_global_translation());
|
||||
glm::vec3 p3 = TFOR.InverseTransformDirection(p1);
|
||||
|
||||
TargetOffset = p2 - p3;
|
|
@ -4,22 +4,23 @@
|
|||
#define THIRDPERSONFOLLOW_H
|
||||
|
||||
#include "transform.h"
|
||||
#include "HandmadeMath.h"
|
||||
|
||||
struct follow {
|
||||
float distance;
|
||||
mfloat_t target_rot[4];
|
||||
float distance;
|
||||
HMM_Quat target_rot;
|
||||
};
|
||||
|
||||
mfloat_t *follow_calccenter();
|
||||
mfloat_t *follow_postoffset();
|
||||
mfloat_t *extentsoffset();
|
||||
mfloat_t *framebasedveclerp();
|
||||
HMM_Vec3 follow_calccenter();
|
||||
HMM_Vec3 follow_postoffset();
|
||||
HMM_Vec3 extentsoffset();
|
||||
HMM_Vec3 framebasedveclerp();
|
||||
int lerpparam(float offset, float anchorwidth, float floatwidth);
|
||||
mfloat_t *vec3lerp(mfloat_t from[3], mfloat_t to[3], mfloat_t a[3]);
|
||||
HMM_Vec3 vec3lerp(HMM_Vec3 from, HMM_Vec3 to, HMM_Vec3 a);
|
||||
void follow_calctargets();
|
||||
mfloat_t *follow_removelockedrot();
|
||||
HMM_Vec3 follow_removelockedrot();
|
||||
void follow_targetoffset(struct follow *follow);
|
||||
int float_epsilon(mfloat_t a, mfloat_t b, mfloat_t e);
|
||||
int float_epsilon(float a, float b, float e);
|
||||
|
||||
/*
|
||||
|
||||
|
@ -31,45 +32,45 @@ class ThirdPersonFollow {
|
|||
|
||||
public:
|
||||
enum CameraType {
|
||||
STATIONARY,
|
||||
TRANSLATING,
|
||||
ROTATING,
|
||||
SPLINE
|
||||
STATIONARY,
|
||||
TRANSLATING,
|
||||
ROTATING,
|
||||
SPLINE
|
||||
};
|
||||
|
||||
enum CameraTransition {
|
||||
NONE,
|
||||
CROSSDISSOLVE,
|
||||
WIPE,
|
||||
DIP
|
||||
NONE,
|
||||
CROSSDISSOLVE,
|
||||
WIPE,
|
||||
DIP
|
||||
};
|
||||
|
||||
enum FrameOfReference {
|
||||
LOCAL,
|
||||
WORLD,
|
||||
EXTERNAL
|
||||
LOCAL,
|
||||
WORLD,
|
||||
EXTERNAL
|
||||
};
|
||||
|
||||
ThirdPersonFollow() {
|
||||
// Rotation
|
||||
RotationSpeed = 10.0f;
|
||||
LockPitch = LockYaw = LockRoll = true;
|
||||
// Rotation
|
||||
RotationSpeed = 10.0f;
|
||||
LockPitch = LockYaw = LockRoll = true;
|
||||
|
||||
XDirPosts = false;
|
||||
YDirPosts = false;
|
||||
ZDirPosts = false;
|
||||
XDirPosts = false;
|
||||
YDirPosts = false;
|
||||
ZDirPosts = false;
|
||||
|
||||
|
||||
// Translation
|
||||
//FloatWidths = AnchorWidths = CenterVector = glm::vec3(0, 0, 0);
|
||||
PositionSpeeds = glm::vec3(2.f, 2.f, 2.f);
|
||||
//TranslationScales = glm::vec3(1, 1, 1);
|
||||
// Translation
|
||||
//FloatWidths = AnchorWidths = CenterVector = glm::vec3(0, 0, 0);
|
||||
PositionSpeeds = glm::vec3(2.f, 2.f, 2.f);
|
||||
//TranslationScales = glm::vec3(1, 1, 1);
|
||||
|
||||
// Frame settings
|
||||
Offset = glm::vec3(0.f, 0.f, 0.f);
|
||||
Distance = 10;
|
||||
// Frame settings
|
||||
Offset = glm::vec3(0.f, 0.f, 0.f);
|
||||
Distance = 10;
|
||||
|
||||
AnchorSpeed = 80;
|
||||
AnchorSpeed = 80;
|
||||
} ~ThirdPersonFollow() {
|
||||
}
|
||||
|
||||
|
@ -81,14 +82,14 @@ class ThirdPersonFollow {
|
|||
|
||||
|
||||
void SetExternalFrame(Transform * val) {
|
||||
ExternalFrame = val;
|
||||
ExternalFrame = val;
|
||||
}
|
||||
|
||||
// The target the camera "looks" at, used for calculations
|
||||
Transform *Target = nullptr;
|
||||
|
||||
void SetTarget(Transform * val) {
|
||||
Target = val;
|
||||
Target = val;
|
||||
}
|
||||
|
||||
// Offset from the target
|
||||
|
@ -158,25 +159,25 @@ class ThirdPersonFollow {
|
|||
|
||||
/// Given a direction and width, find the offsets.
|
||||
glm::vec3 GetPostsOffset(const glm::vec3 & DirectionVector,
|
||||
float AnchorWidth);
|
||||
float AnchorWidth);
|
||||
|
||||
/// Given anchors, what's the anchor width?
|
||||
glm::vec3 GetExtentsOffset(const glm::vec3 & DirectionVector,
|
||||
float AnchorWidth, float TOffset,
|
||||
float Width);
|
||||
float AnchorWidth, float TOffset,
|
||||
float Width);
|
||||
|
||||
glm::quat RemoveLockedRotation(const glm::quat & CurrentRotation);
|
||||
|
||||
glm::vec3 FrameBasedVectorLerp(const glm::vec3 & From,
|
||||
const glm::vec3 & To,
|
||||
const glm::vec3 & Speeds, float Tick);
|
||||
const glm::vec3 & To,
|
||||
const glm::vec3 & Speeds, float Tick);
|
||||
|
||||
glm::vec3 VectorLerpPiecewise(const glm::vec3 & From,
|
||||
const glm::vec3 & To,
|
||||
const glm::vec3 & Alpha);
|
||||
const glm::vec3 & To,
|
||||
const glm::vec3 & Alpha);
|
||||
|
||||
bool GetLerpParam(const float Offst, const float AnchorWidth,
|
||||
const float FloatWidth);
|
||||
const float FloatWidth);
|
||||
|
||||
/// Set to a value that gives good clamping, smoothly. Activates when
|
||||
/// the target is out of range.
|
|
@ -1,7 +1,6 @@
|
|||
#include "light.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
|
||||
/*
|
||||
void Light::serialize(FILE * file)
|
||||
{
|
||||
|
@ -30,20 +29,20 @@ struct mDirectionalLight *dLight = NULL;
|
|||
struct mDirectionalLight *MakeDLight()
|
||||
{
|
||||
if (dLight != NULL) {
|
||||
dLight =
|
||||
(struct mDirectionalLight *)
|
||||
malloc(sizeof(struct mDirectionalLight));
|
||||
quat_from_euler(dLight->light.obj.transform.rotation,
|
||||
dlight_init_rot);
|
||||
dLight =
|
||||
(struct mDirectionalLight *)
|
||||
malloc(sizeof(struct mDirectionalLight));
|
||||
quat_from_euler(dLight->light.obj.transform.rotation,
|
||||
dlight_init_rot);
|
||||
|
||||
return dLight;
|
||||
return dLight;
|
||||
}
|
||||
|
||||
return dLight;
|
||||
}
|
||||
|
||||
void dlight_prepshader(struct mDirectionalLight *light,
|
||||
struct shader *shader)
|
||||
struct shader *shader)
|
||||
{
|
||||
mfloat_t fwd[3] = { 0.f };
|
||||
trans_forward(fwd, &light->light.obj.transform);
|
||||
|
@ -61,14 +60,14 @@ static int numLights = 0;
|
|||
struct mPointLight *MakePointlight()
|
||||
{
|
||||
if (numLights < 4) {
|
||||
struct mPointLight *light =
|
||||
(struct mPointLight *) malloc(sizeof(struct mPointLight));
|
||||
pointLights[numLights++] = light;
|
||||
light->light.strength = 0.2f;
|
||||
light->constant = 1.f;
|
||||
light->linear = 0.9f;
|
||||
light->quadratic = 0.032f;
|
||||
return light;
|
||||
struct mPointLight *light =
|
||||
(struct mPointLight *) malloc(sizeof(struct mPointLight));
|
||||
pointLights[numLights++] = light;
|
||||
light->light.strength = 0.2f;
|
||||
light->constant = 1.f;
|
||||
light->linear = 0.9f;
|
||||
light->quadratic = 0.032f;
|
||||
return light;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
@ -82,11 +81,11 @@ static void prepstring(char *buffer, char *prepend, const char *append)
|
|||
void pointlights_prepshader(struct shader *shader)
|
||||
{
|
||||
for (int i = 0; i < numLights; i++)
|
||||
pointlight_prepshader(pointLights[i], shader, i);
|
||||
pointlight_prepshader(pointLights[i], shader, i);
|
||||
}
|
||||
|
||||
void pointlight_prepshader(struct mPointLight *light,
|
||||
struct shader *shader, int num)
|
||||
struct shader *shader, int num)
|
||||
{
|
||||
shader_use(shader);
|
||||
char prepend[100] = { '\0' };
|
||||
|
@ -121,10 +120,10 @@ static int numSpots = 0;
|
|||
struct mSpotLight *MakeSpotlight()
|
||||
{
|
||||
if (numSpots < 4) {
|
||||
struct mSpotLight *light =
|
||||
(struct mSpotLight *) malloc(sizeof(struct mSpotLight));
|
||||
spotLights[numSpots++] = light;
|
||||
return light;
|
||||
struct mSpotLight *light =
|
||||
(struct mSpotLight *) malloc(sizeof(struct mSpotLight));
|
||||
spotLights[numSpots++] = light;
|
||||
return light;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
@ -135,17 +134,17 @@ struct mSpotLight *MakeSpotlight()
|
|||
void spotlights_prepshader(struct shader *shader)
|
||||
{
|
||||
for (int i = 0; i < numSpots; i++)
|
||||
spotlight_prepshader(spotLights[i], shader, i);
|
||||
spotlight_prepshader(spotLights[i], shader, i);
|
||||
}
|
||||
|
||||
void spotlight_prepshader(struct mSpotLight *light, struct shader *shader,
|
||||
int num)
|
||||
int num)
|
||||
{
|
||||
mfloat_t fwd[3] = { 0.f };
|
||||
trans_forward(fwd, &light->light.obj.transform);
|
||||
shader_use(shader);
|
||||
shader_setvec3(shader, "spotLight.position",
|
||||
light->light.obj.transform.position);
|
||||
light->light.obj.transform.position);
|
||||
shader_setvec3(shader, "spotLight.direction", fwd);
|
||||
shader_setvec3(shader, "spotLight.color", light->light.color);
|
||||
shader_setfloat(shader, "spotLight.strength", light->light.strength);
|
||||
|
@ -165,10 +164,10 @@ void light_gui(struct mLight *light)
|
|||
object_gui(&light->obj);
|
||||
|
||||
if (nk_tree_push(ctx, NK_TREE_NODE, "Light", NK_MINIMIZED)) {
|
||||
nk_property_float(ctx, "Strength", 0.f, &light->strength, 1.f, 0.01f, 0.001f);
|
||||
// ImGui::ColorEdit3("Color", &light->color[0]);
|
||||
nk_checkbox_label(ctx, "Dynamic", (bool *) &light->dynamic);
|
||||
nk_tree_pop(ctx);
|
||||
nk_property_float(ctx, "Strength", 0.f, &light->strength, 1.f, 0.01f, 0.001f);
|
||||
// ImGui::ColorEdit3("Color", &light->color[0]);
|
||||
nk_checkbox_label(ctx, "Dynamic", (bool *) &light->dynamic);
|
||||
nk_tree_pop(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -178,10 +177,10 @@ void pointlight_gui(struct mPointLight *light)
|
|||
light_gui(&light->light);
|
||||
|
||||
if (nk_tree_push(ctx, NK_TREE_NODE, "Point Light", NK_MINIMIZED)) {
|
||||
nk_property_float(ctx, "Constant", 0.f, &light->constant, 1.f, 0.01f, 0.001f);
|
||||
nk_property_float(ctx, "Linear", 0.f, &light->linear, 0.3f, 0.01f, 0.001f);
|
||||
nk_property_float(ctx, "Quadratic", 0.f, &light->quadratic, 0.3f, 0.01f, 0.001f);
|
||||
nk_tree_pop(ctx);
|
||||
nk_property_float(ctx, "Constant", 0.f, &light->constant, 1.f, 0.01f, 0.001f);
|
||||
nk_property_float(ctx, "Linear", 0.f, &light->linear, 0.3f, 0.01f, 0.001f);
|
||||
nk_property_float(ctx, "Quadratic", 0.f, &light->quadratic, 0.3f, 0.01f, 0.001f);
|
||||
nk_tree_pop(ctx);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -191,12 +190,12 @@ void spotlight_gui(struct mSpotLight *spot)
|
|||
light_gui(&spot->light);
|
||||
|
||||
if (nk_tree_push(ctx, NK_TREE_NODE, "Spotlight", NK_MINIMIZED)) {
|
||||
nk_property_float(ctx, "Linear", 0.f, &spot->linear, 1.f, 0.01f, 0.001f);
|
||||
nk_property_float(ctx, "Quadratic", 0.f, &spot->quadratic, 1.f, 0.01f, 0.001f);
|
||||
nk_property_float(ctx, "Distance", 0.f, &spot->distance, 200.f, 1.f, 0.1f, 200.f);
|
||||
nk_property_float(ctx, "Cutoff Degrees", 0.f, &spot->cutoff, 0.7f, 0.01f, 0.001f);
|
||||
nk_property_float(ctx, "Outer Cutoff Degrees", 0.f, &spot->outerCutoff, 0.7f, 0.01f, 0.001f);
|
||||
nk_tree_pop(ctx);
|
||||
nk_property_float(ctx, "Linear", 0.f, &spot->linear, 1.f, 0.01f, 0.001f);
|
||||
nk_property_float(ctx, "Quadratic", 0.f, &spot->quadratic, 1.f, 0.01f, 0.001f);
|
||||
nk_property_float(ctx, "Distance", 0.f, &spot->distance, 200.f, 1.f, 0.1f, 200.f);
|
||||
nk_property_float(ctx, "Cutoff Degrees", 0.f, &spot->cutoff, 0.7f, 0.01f, 0.001f);
|
||||
nk_property_float(ctx, "Outer Cutoff Degrees", 0.f, &spot->outerCutoff, 0.7f, 0.01f, 0.001f);
|
||||
nk_tree_pop(ctx);
|
||||
}
|
||||
}
|
||||
*/
|