merge sokol

This commit is contained in:
John Alanbrook 2023-08-23 04:34:36 +00:00
commit 09765f5336
282 changed files with 667776 additions and 23600 deletions

217
.clang-format Normal file
View 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
View file

@ -1,4 +1,5 @@
.git/
.obj/
bin/
build/
*.o

145
Makefile
View file

@ -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

File diff suppressed because it is too large Load diff

Binary file not shown.

4
assets/fonts/dos.font Normal file
View file

@ -0,0 +1,4 @@
(font
:path "LessPerfectDOSVGA.ttf"
:size 16
)

Binary file not shown.

After

Width:  |  Height:  |  Size: 298 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 293 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 339 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 234 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 B

BIN
assets/icons/no_tex.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

View file

@ -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.

View file

@ -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.

View file

@ -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
View 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|

View file

@ -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.

View file

@ -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.

View file

@ -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
View file

@ -0,0 +1,2 @@
# Yugine Input Guide

View file

@ -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
View 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
View 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
View 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
View 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
View 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
View file

@ -0,0 +1 @@
2021-03-27

631
quickjs/cutils.c Normal file
View 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
View 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
View 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

File diff suppressed because it is too large Load diff

72
quickjs/examples/fib.c Normal file
View 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;
}

View 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);
}

View file

@ -0,0 +1 @@
console.log("Hello World");

View 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));

View 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"));
})();

View 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);
})();

View 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
View 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;
}

View 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));

View 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

File diff suppressed because it is too large Load diff

535
quickjs/libbf.h Normal file
View 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 */

View 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

File diff suppressed because it is too large Load diff

92
quickjs/libregexp.h Normal file
View 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

File diff suppressed because it is too large Load diff

1556
quickjs/libunicode.c Normal file

File diff suppressed because it is too large Load diff

124
quickjs/libunicode.h Normal file
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load diff

273
quickjs/quickjs-atom.h Normal file
View 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

File diff suppressed because it is too large Load diff

59
quickjs/quickjs-libc.h Normal file
View 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
View 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

File diff suppressed because it is too large Load diff

1049
quickjs/quickjs.h Normal file

File diff suppressed because it is too large Load diff

1
quickjs/readme.txt Normal file
View file

@ -0,0 +1 @@
The main documentation is in doc/quickjs.pdf or doc/quickjs.html.

158
quickjs/release.sh Executable file
View 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

File diff suppressed because it is too large Load diff

2107
quickjs/run-test262.c Normal file

File diff suppressed because it is too large Load diff

209
quickjs/test262.conf Normal file
View 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

View 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
View 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
View 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

File diff suppressed because it is too large Load diff

View 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) {

View 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
View 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();

View 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();

View 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();

View 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
View 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();

View 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();

View 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
View 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();

View 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();

View 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
View 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

File diff suppressed because it is too large Load diff

289
quickjs/unicode_gen_def.h Normal file
View 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

File diff suppressed because it is too large Load diff

View file

@ -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

View file

@ -1,5 +1,4 @@
#ifndef THREEDPHYSICS_H
#define THREEDPHYSICS_H
#endif

View file

@ -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;

View file

@ -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.

View file

@ -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);
}
}
*/

Some files were not shown because too many files have changed in this diff Show more