├── VERSION
├── test262o_errors.txt
├── examples
├── hello.js
├── hello_module.js
├── test_fib.js
├── fib_module.js
├── test_point.js
├── pi_bigfloat.js
├── pi_bigdecimal.js
├── fib.c
├── pi_bigint.js
└── point.c
├── quickjs-version.h
├── doc
├── quickjs.pdf
├── jsbignum.pdf
└── jsx.md
├── readme.txt
├── tests
├── test-obj-call.js
├── test_worker_module.js
├── storage
│ ├── test-basic.js
│ ├── test-classes.js
│ ├── test-index.js
│ └── test-all.js
├── JSX
│ └── test-jsx.js
├── test_worker.js
├── test262.patch
├── bjson.c
├── test_closure.js
├── test_op_overloading.js
├── test_bjson.js
├── test_qjscalc.js
├── test_std.js
└── test_loop.js
├── win
├── premake-vs2019.bat
└── premake-vs2017.bat
├── storage
├── doc
│ ├── images
│ │ └── storage-schema.png
│ ├── README.md
│ ├── Storage.md
│ ├── Storage.Index.md
│ ├── architecture.md
│ └── introduction.md
├── quickjs-storage.h
└── dybase
│ ├── src
│ ├── buffer.h
│ ├── sync.h
│ ├── hashtab.h
│ ├── file.h
│ ├── pagepool.h
│ ├── stdtp.h
│ ├── btree.h
│ └── dybase.cpp
│ └── CHANGES
├── unicode_download.sh
├── LICENSE
├── README.md
├── libregexp-opcode.h
├── quickjs-libc.h
├── TODO
├── libregexp.h
├── list.h
├── release.sh
├── quickjs-bjson.c
├── premake5.lua
├── libunicode.h
├── Changelog
├── test262.conf
├── test262_errors.txt
├── .gitignore
├── unicode_gen_def.h
├── quickjs-atom.h
└── cutils.h
/VERSION:
--------------------------------------------------------------------------------
1 | 2021-03-27
2 |
--------------------------------------------------------------------------------
/test262o_errors.txt:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/examples/hello.js:
--------------------------------------------------------------------------------
1 | console.log("Hello World");
2 |
--------------------------------------------------------------------------------
/quickjs-version.h:
--------------------------------------------------------------------------------
1 | #define QUICKJS_VERSION "2021-03-27"
--------------------------------------------------------------------------------
/doc/quickjs.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/c-smile/quickjspp/HEAD/doc/quickjs.pdf
--------------------------------------------------------------------------------
/readme.txt:
--------------------------------------------------------------------------------
1 | The main documentation is in doc/quickjs.pdf or doc/quickjs.html.
2 |
--------------------------------------------------------------------------------
/doc/jsbignum.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/c-smile/quickjspp/HEAD/doc/jsbignum.pdf
--------------------------------------------------------------------------------
/tests/test-obj-call.js:
--------------------------------------------------------------------------------
1 | function foo(obj) {
2 | console.log(obj);
3 | }
4 |
5 | foo {bar:"bar"};
6 |
--------------------------------------------------------------------------------
/win/premake-vs2019.bat:
--------------------------------------------------------------------------------
1 | cd ..
2 | premake5 vs2019 --jsx --storage
3 | cd .build
4 | start vs2019\quickjs.sln
--------------------------------------------------------------------------------
/win/premake-vs2017.bat:
--------------------------------------------------------------------------------
1 | cd ..
2 | premake5 vs2017 --jsx --storage
3 | cd .build
4 | start vs2017\quickjs.sln
5 |
--------------------------------------------------------------------------------
/storage/doc/images/storage-schema.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/c-smile/quickjspp/HEAD/storage/doc/images/storage-schema.png
--------------------------------------------------------------------------------
/examples/hello_module.js:
--------------------------------------------------------------------------------
1 | /* example of JS module */
2 |
3 | import { fib } from "./fib_module.js";
4 |
5 | console.log("Hello World");
6 | console.log("fib(10)=", fib(10));
7 |
--------------------------------------------------------------------------------
/examples/test_fib.js:
--------------------------------------------------------------------------------
1 | /* example of JS module importing a C module */
2 |
3 | import { fib } from "./fib.so";
4 |
5 | console.log("Hello World");
6 | console.log("fib(10)=", fib(10));
7 |
--------------------------------------------------------------------------------
/examples/fib_module.js:
--------------------------------------------------------------------------------
1 | /* fib module */
2 | export function fib(n)
3 | {
4 | if (n <= 0)
5 | return 0;
6 | else if (n == 1)
7 | return 1;
8 | else
9 | return fib(n - 1) + fib(n - 2);
10 | }
11 |
--------------------------------------------------------------------------------
/storage/doc/README.md:
--------------------------------------------------------------------------------
1 | # module storage
2 |
3 | This module provides built-in data persistence - transparent data storage and retrieval using just JavaScript means.
4 |
5 | [Introduction](introduction.md) and usage manual.
6 |
7 | [Architecture](architecture.md) explained.
8 |
9 | Documentation:
10 |
11 | * class [Storage](Storage.md);
12 | * class [Storage.Index](Storage.Index.md);
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/unicode_download.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 |
4 | url="ftp://ftp.unicode.org/Public/13.0.0/ucd"
5 | emoji_url="${url}/emoji/emoji-data.txt"
6 |
7 | files="CaseFolding.txt DerivedNormalizationProps.txt PropList.txt \
8 | SpecialCasing.txt CompositionExclusions.txt ScriptExtensions.txt \
9 | UnicodeData.txt DerivedCoreProperties.txt NormalizationTest.txt Scripts.txt \
10 | PropertyValueAliases.txt"
11 |
12 | mkdir -p unicode
13 |
14 | #for f in $files; do
15 | # g="${url}/${f}"
16 | # wget $g -O unicode/$f
17 | #done
18 |
19 | wget $emoji_url -O unicode/emoji-data.txt
20 |
--------------------------------------------------------------------------------
/tests/test_worker_module.js:
--------------------------------------------------------------------------------
1 | /* Worker code for test_worker.js */
2 | import * as std from "std";
3 | import * as os from "os";
4 |
5 | var parent = os.Worker.parent;
6 |
7 | function handle_msg(e) {
8 | var ev = e.data;
9 | // print("child_recv", JSON.stringify(ev));
10 | switch(ev.type) {
11 | case "abort":
12 | parent.postMessage({ type: "done" });
13 | break;
14 | case "sab":
15 | /* modify the SharedArrayBuffer */
16 | ev.buf[2] = 10;
17 | parent.postMessage({ type: "sab_done", buf: ev.buf });
18 | break;
19 | }
20 | }
21 |
22 | function worker_main() {
23 | var i;
24 |
25 | parent.onmessage = handle_msg;
26 | for(i = 0; i < 10; i++) {
27 | parent.postMessage({ type: "num", num: i });
28 | }
29 | }
30 |
31 | worker_main();
32 |
--------------------------------------------------------------------------------
/examples/test_point.js:
--------------------------------------------------------------------------------
1 | /* example of JS module importing a C module */
2 | import { Point } from "./point.so";
3 |
4 | function assert(b, str)
5 | {
6 | if (b) {
7 | return;
8 | } else {
9 | throw Error("assertion failed: " + str);
10 | }
11 | }
12 |
13 | class ColorPoint extends Point {
14 | constructor(x, y, color) {
15 | super(x, y);
16 | this.color = color;
17 | }
18 | get_color() {
19 | return this.color;
20 | }
21 | };
22 |
23 | function main()
24 | {
25 | var pt, pt2;
26 |
27 | pt = new Point(2, 3);
28 | assert(pt.x === 2);
29 | assert(pt.y === 3);
30 | pt.x = 4;
31 | assert(pt.x === 4);
32 | assert(pt.norm() == 5);
33 |
34 | pt2 = new ColorPoint(2, 3, 0xffffff);
35 | assert(pt2.x === 2);
36 | assert(pt2.color === 0xffffff);
37 | assert(pt2.get_color() === 0xffffff);
38 | }
39 |
40 | main();
41 |
--------------------------------------------------------------------------------
/storage/doc/Storage.md:
--------------------------------------------------------------------------------
1 |
2 | # Storage class
3 |
4 | Represents persistent storage.
5 |
6 | ## Properties
7 |
8 | * ```root``` - object, root object in the storage. Read/write property.
9 |
10 | ## Methods
11 |
12 |
13 | * ```Storage.open(filename : string [,allowWrite: true] ) : storage | null```
14 |
15 | Static method. Opens the storage and returns an instance of Storage object. If *allowWrite* is *false* then storage is opened in read-only mode.
16 |
17 | * ```storage.close()```
18 |
19 | Closes underlying Storage object. Commits all data before cloasing. After closing the storage all persistent objects that are still in use are set to non-persistent state.
20 |
21 | * ```storage.commit()```
22 |
23 | Commits (writes) all persistent objects reachable from its root into storage.
24 |
25 | * ```storage.createIndex(type : string [, unique: bool]) returns: Index | null```
26 |
27 | Creates an index of given type and returns the index object. Index can have unique or duplicated keys depending on unique argument. Default value for *unique* is *true*. Supported types: "integer", "long", "float", "date" and "string".
28 |
--------------------------------------------------------------------------------
/tests/storage/test-basic.js:
--------------------------------------------------------------------------------
1 | import * as storage from "storage";
2 | import * as std from "std";
3 | import * as os from "os";
4 |
5 | function assert(actual, expected, message) {
6 | if (arguments.length == 1)
7 | expected = true;
8 |
9 | if (actual === expected)
10 | return;
11 |
12 | if (actual !== null && expected !== null
13 | && typeof actual == 'object' && typeof expected == 'object'
14 | && actual.toString() === expected.toString())
15 | return;
16 |
17 | throw Error("assertion failed: got |" + actual + "|" +
18 | ", expected |" + expected + "|" +
19 | (message ? " (" + message + ")" : ""));
20 | }
21 |
22 | const path = __DIR__ + "test.db";
23 | os.remove(path);
24 |
25 | function init() {
26 | let db = storage.open(path);
27 | db.root = { foo:"foofoo", bar:42, arr: [1,2,3] };
28 | db.close();
29 | }
30 |
31 | function test() {
32 | let db = storage.open(path);
33 | let r = db.root;
34 | let arr = db.root.arr;
35 | print(JSON.stringify(r));
36 | print(JSON.stringify(arr));
37 | assert(r.foo, "foofoo");
38 | db.close();
39 | }
40 |
41 | init();
42 | test();
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | QuickJS Javascript Engine
2 |
3 | Copyright (c) 2017-2021 Fabrice Bellard
4 | Copyright (c) 2017-2021 Charlie Gordon
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in
14 | all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/tests/storage/test-classes.js:
--------------------------------------------------------------------------------
1 | import * as storage from "storage";
2 | import * as std from "std";
3 | import * as os from "os";
4 |
5 | function assert(actual, expected, message) {
6 | if (arguments.length == 1)
7 | expected = true;
8 |
9 | if (actual === expected)
10 | return;
11 |
12 | if (actual !== null && expected !== null
13 | && typeof actual == 'object' && typeof expected == 'object'
14 | && actual.toString() === expected.toString())
15 | return;
16 |
17 | throw Error("assertion failed: got |" + actual + "|" +
18 | ", expected |" + expected + "|" +
19 | (message ? " (" + message + ")" : ""));
20 | }
21 |
22 | export class Account
23 | {
24 | constructor() {
25 | this.balance = 0n;
26 | this.name = "Foo";
27 | }
28 | show() {
29 | print("account:", this.name);
30 | print("balance:", this.balance);
31 | }
32 | }
33 |
34 | const path = __DIR__ + "test.db";
35 | os.remove(path);
36 |
37 | function init() {
38 |
39 | var inst = new Account();
40 | inst.show();
41 |
42 | let db = storage.open(path);
43 | db.root = {
44 | inst: inst
45 | };
46 | db.close();
47 | }
48 |
49 | function test() {
50 | let db = storage.open(path);
51 | let r = db.root;
52 | r.inst.show();
53 | db.close();
54 | print("PASSED");
55 | }
56 |
57 | init();
58 | test();
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/tests/storage/test-index.js:
--------------------------------------------------------------------------------
1 | import * as storage from "storage";
2 | import * as std from "std";
3 | import * as os from "os";
4 |
5 | function assert(actual, expected, message) {
6 | if (arguments.length == 1)
7 | expected = true;
8 |
9 | if (actual === expected)
10 | return;
11 |
12 | if (actual !== null && expected !== null
13 | && typeof actual == 'object' && typeof expected == 'object'
14 | && actual.toString() === expected.toString())
15 | return;
16 |
17 | throw Error("assertion failed: got |" + actual + "|" +
18 | ", expected |" + expected + "|" +
19 | (message ? " (" + message + ")" : ""));
20 | }
21 |
22 | const path = __DIR__ + "test.db";
23 | os.remove(path);
24 |
25 | function init() {
26 | let db = storage.open(path);
27 |
28 | let index = db.createIndex("string");
29 | db.root = {
30 | index: index
31 | };
32 | index.set("a", { key: "a" });
33 | index.set("b", { key: "b" });
34 | index.set("c", { key: "c" });
35 |
36 | assert(index.length, 3);
37 | db.close();
38 | }
39 |
40 | function test() {
41 | let db = storage.open(path);
42 |
43 | let index = db.root.index;
44 | assert(index.length, 3);
45 | for( let item of index )
46 | print(JSON.stringify(item));
47 | print("---- select() ----");
48 | for( let item of index.select("b","c") )
49 | print(JSON.stringify(item));
50 |
51 | db.close();
52 | }
53 |
54 | init();
55 | test();
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/tests/JSX/test-jsx.js:
--------------------------------------------------------------------------------
1 |
2 |
3 | // "driver" of JSX expressions
4 | JSX = function(tag,atts,kids) {
5 | return [tag,atts,kids]; // just produce "vnode" tuple
6 | }
7 |
8 | function isObject(object) {
9 | return object != null && typeof object === 'object';
10 | }
11 |
12 | function deepEqual(object1, object2) {
13 | const keys1 = Object.keys(object1);
14 | const keys2 = Object.keys(object2);
15 |
16 | if (keys1.length !== keys2.length) {
17 | return false;
18 | }
19 |
20 | for (const key of keys1) {
21 | const val1 = object1[key];
22 | const val2 = object2[key];
23 | const areObjects = isObject(val1) && isObject(val2);
24 | if (
25 | areObjects && !deepEqual(val1, val2) ||
26 | !areObjects && val1 !== val2
27 | ) {
28 | return false;
29 | }
30 | }
31 |
32 | return true;
33 | }
34 |
35 | function assert(v1,v2) {
36 | if(!deepEqual(v1,v2)) {
37 | //console.log(JSON.stringify(v1,v2));
38 | throw "problem in JSX construct"
39 | }
40 | }
41 |
42 |
43 | var t1 =
test
;
44 | var t1a = ["div",{},["test"]];
45 | assert(t1,t1a);
46 |
47 | var t2 = test
;
48 | var t2a = ["h1",{id:"foo"},["test"]];
49 |
50 | assert(t2,t2a);
51 |
52 | var t3 = ;
53 | var t3a = ["div",{},[["h1",{},[]]]];
54 |
55 | assert(t3,t3a);
56 |
57 |
58 | var t4 = header
;
59 | var t4a = ["div",{id:"foo",class:"bar"},[["h1",{},["header"]],["button",{},["clicks"]]]];
60 |
61 | assert(t4,t4a);
62 |
63 | console.log("JSX test passed!");
64 |
--------------------------------------------------------------------------------
/storage/quickjs-storage.h:
--------------------------------------------------------------------------------
1 | /*
2 | * QuickJS C library
3 | *
4 | * Copyright (c) 2017-2018 Fabrice Bellard
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 | #ifndef QUICKJS_STORAGE_H
25 | #define QUICKJS_STORAGE_H
26 |
27 | #include "../quickjs.h"
28 |
29 | #ifdef __cplusplus
30 | extern "C" {
31 | #endif
32 |
33 | JSModuleDef *js_init_module_storage(JSContext *ctx, const char *module_name);
34 |
35 |
36 | #ifdef __cplusplus
37 | } /* extern "C" { */
38 | #endif
39 |
40 | #endif /* QUICKJS_LIBC_H */
41 |
--------------------------------------------------------------------------------
/tests/test_worker.js:
--------------------------------------------------------------------------------
1 | /* os.Worker API test */
2 | import * as std from "std";
3 | import * as os from "os";
4 |
5 | function assert(actual, expected, message) {
6 | if (arguments.length == 1)
7 | expected = true;
8 |
9 | if (actual === expected)
10 | return;
11 |
12 | if (actual !== null && expected !== null
13 | && typeof actual == 'object' && typeof expected == 'object'
14 | && actual.toString() === expected.toString())
15 | return;
16 |
17 | throw Error("assertion failed: got |" + actual + "|" +
18 | ", expected |" + expected + "|" +
19 | (message ? " (" + message + ")" : ""));
20 | }
21 |
22 | var worker;
23 |
24 | function test_worker()
25 | {
26 | var counter;
27 |
28 | worker = new os.Worker("./test_worker_module.js");
29 |
30 | counter = 0;
31 | worker.onmessage = function (e) {
32 | var ev = e.data;
33 | // print("recv", JSON.stringify(ev));
34 | switch(ev.type) {
35 | case "num":
36 | assert(ev.num, counter);
37 | counter++;
38 | if (counter == 10) {
39 | /* test SharedArrayBuffer modification */
40 | let sab = new SharedArrayBuffer(10);
41 | let buf = new Uint8Array(sab);
42 | worker.postMessage({ type: "sab", buf: buf });
43 | }
44 | break;
45 | case "sab_done":
46 | {
47 | let buf = ev.buf;
48 | /* check that the SharedArrayBuffer was modified */
49 | assert(buf[2], 10);
50 | worker.postMessage({ type: "abort" });
51 | }
52 | break;
53 | case "done":
54 | /* terminate */
55 | worker.onmessage = null;
56 | break;
57 | }
58 | };
59 | }
60 |
61 |
62 | test_worker();
63 |
--------------------------------------------------------------------------------
/storage/dybase/src/buffer.h:
--------------------------------------------------------------------------------
1 |
2 | #ifndef __BUFFER_H__
3 | #define __BUFFER_H__
4 |
5 | template class dbSmallBuffer {
6 | private:
7 | T buf[initSize];
8 | length_t used;
9 | T * ptr;
10 | length_t allocated;
11 |
12 | public:
13 | dbSmallBuffer() {
14 | ptr = buf;
15 | used = 0;
16 | allocated = initSize;
17 | }
18 |
19 | ~dbSmallBuffer() {
20 | if (ptr != buf) { delete[] ptr; }
21 | }
22 |
23 | T *base() { return ptr; }
24 |
25 | length_t size() { return used; }
26 |
27 | T *append(int n) {
28 | if (n + used > allocated) {
29 | length_t newSize = n + used > allocated * 2 ? n + used : allocated * 2;
30 | T * newBuf = new T[newSize];
31 | for (int i = int(used); --i >= 0;) {
32 | newBuf[i] = ptr[i];
33 | }
34 | if (ptr != buf) { delete[] ptr; }
35 | ptr = newBuf;
36 | allocated = newSize;
37 | }
38 | T *p = ptr + used;
39 | used += n;
40 | return p;
41 | }
42 | };
43 |
44 | template class dbBuffer {
45 | private:
46 | length_t used;
47 | T * ptr;
48 | length_t allocated;
49 |
50 | public:
51 | dbBuffer() {
52 | ptr = NULL;
53 | used = 0;
54 | allocated = 0;
55 | }
56 |
57 | ~dbBuffer() { delete[] ptr; }
58 |
59 | T *base() { return ptr; }
60 |
61 | T *grab() {
62 | T *p = ptr;
63 | ptr = NULL;
64 | return p;
65 | }
66 |
67 | length_t size() { return used; }
68 |
69 | void add(T val) { *append(1) = val; }
70 |
71 | T *append(int n) {
72 | if (n + used > allocated) {
73 | length_t newSize = n + used > allocated * 2 ? n + used : allocated * 2;
74 | T * newBuf = new T[newSize];
75 | for (int i = int(used); --i >= 0;) {
76 | newBuf[i] = ptr[i];
77 | }
78 | delete[] ptr;
79 | ptr = newBuf;
80 | allocated = newSize;
81 | }
82 | T *p = ptr + used;
83 | used += n;
84 | return p;
85 | }
86 | };
87 |
88 | #endif
89 |
--------------------------------------------------------------------------------
/storage/dybase/src/sync.h:
--------------------------------------------------------------------------------
1 | //-< SYNC.H >--------------------------------------------------------*--------*
2 | // GigaBASE Version 1.0 (c) 1999 GARRET * ? *
3 | // (Post Relational Database Management System) * /\| *
4 | // * / \ *
5 | // Created: 20-Nov-98 K.A. Knizhnik * / [] \ *
6 | // Last update: 8-Feb-99 K.A. Knizhnik * GARRET *
7 | //-------------------------------------------------------------------*--------*
8 | // Intertask synchonization primitives
9 | //-------------------------------------------------------------------*--------*
10 |
11 | #ifndef __SYNC_H__
12 | #define __SYNC_H__
13 |
14 | #if defined(_WIN32)
15 | class dbMutex {
16 | CRITICAL_SECTION cs;
17 |
18 | public:
19 | dbMutex() { InitializeCriticalSection(&cs); }
20 | ~dbMutex() { DeleteCriticalSection(&cs); }
21 | void lock() { EnterCriticalSection(&cs); }
22 | void unlock() { LeaveCriticalSection(&cs); }
23 | };
24 |
25 | #else // Unix
26 |
27 | #ifndef NO_PTHREADS
28 |
29 | #include
30 | #include
31 | #include
32 |
33 | class dbMutex {
34 | friend class dbEvent;
35 | friend class dbSemaphore;
36 | pthread_mutex_t cs;
37 |
38 | public:
39 | dbMutex() { pthread_mutex_init(&cs, NULL); }
40 | ~dbMutex() { pthread_mutex_destroy(&cs); }
41 | void lock() { pthread_mutex_lock(&cs); }
42 | void unlock() { pthread_mutex_unlock(&cs); }
43 | };
44 |
45 | #else
46 |
47 | class dbMutex {
48 | public:
49 | void lock() {}
50 | void unlock() {}
51 | };
52 |
53 | #endif
54 |
55 | #endif
56 |
57 | class dbCriticalSection {
58 | private:
59 | dbMutex &mutex;
60 | dbCriticalSection(const dbCriticalSection &);
61 | dbCriticalSection &operator=(const dbCriticalSection &);
62 |
63 | public:
64 | dbCriticalSection(dbMutex &guard) : mutex(guard) { mutex.lock(); }
65 | ~dbCriticalSection() { mutex.unlock(); }
66 | };
67 |
68 | #endif
69 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # QuickJS Javascript Engine
4 |
5 | Authors: Fabrice Bellard and Charlie Gordon
6 |
7 | Ported from https://bellard.org/quickjs/ and its official GitHub mirror https://github.com/bellard/quickjs
8 |
9 | By Andrew Fedoniouk (a.k.a. c-smile)
10 |
11 | This version is
12 |
13 | * Microsoft Visual C++ compatible/compileable
14 | * Is used in Sciter.JS
15 | * It contains extras:
16 | * [JSX](doc/jsx.md) - built-in [facebook::JSX](https://facebook.github.io/jsx/) support with Sciter specific extras.
17 | * Built-in [Persistence](storage/doc/README.md) - you can think of it as local MongoDB (NoSQL) DB embedded into the language. Pretty small, adds just 70kb into binary.
18 | Persistence is based on [DyBASE of Konstantin Knizhnik](http://garret.ru/)
19 |
20 | The main documentation is in doc/quickjs.pdf or [doc/quickjs.html](doc/quickjs.html).
21 |
22 | # Build using Microsoft Visual Studio (2017 or 2019)
23 |
24 | Prerequisite: **premake5** - [download](https://premake.github.io/download.html) and install it.
25 |
26 | Then go to /win folder and run premake-vs2017.bat or premake-vs2019.bat .
27 |
28 | It will generate .build/vs2017/quickjs-msvc.sln and open it in Microsoft Visual Studio.
29 |
30 | Press F5 to compile it and run qjs - interactive JS command line application.
31 |
32 | # Premake5 and build on other platforms/compilers/ide
33 |
34 | Supported premake options:
35 |
36 | * ```--jsx``` - include JSX support;
37 | * ```--storage``` - include Persistent Storage support;
38 |
39 | Supported targets (these are built into [Premake](https://premake.github.io/) itself):
40 |
41 | * vs2017 - MS Visual Studio 2017
42 | * vs2019 - MS Visual Studio 2019
43 | * gmake2 - gmake files
44 | * etc...
45 |
46 | Few examples of other possible configurations:
47 | ```bat
48 | premake5 vs2019 --jsx --storage
49 | premake5 codeblocks --cc=gcc --jsx --storage
50 | premake5 gmake2 --cc=gcc --jsx --storage
51 | premake5 gmake2 --cc=clang --jsx --storage
52 | premake5 gmake2 --cc=clang --jsx --storage
53 | premake5 xcode4 --jsx --storage
54 | ```
55 |
56 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/storage/doc/Storage.Index.md:
--------------------------------------------------------------------------------
1 | # Index class
2 |
3 | Index object in persistent storage.
4 |
5 | ## Properties
6 |
7 | * ```index.length``` - integer, read-only, length of an index, number of objects associated represented by the index.
8 | * ```index.unique``` - boolean, read-only, true if the index was declared as unique.
9 | * ```index.type``` - string, read-only, key type as it was declared at creation time. Read-only property.
10 |
11 | ## Enumeration
12 |
13 | Indexes support ```for(of)``` enumeration style:
14 |
15 | ```JavaScript:
16 | // log all objects in the index
17 | for( var obj in index )
18 | console.log(obj);
19 | ```
20 |
21 |
22 | ## Methods
23 |
24 | * ```index.set( key, obj [, replace: true|false ] ) : true|false```
25 |
26 | Inserts *obj* object into the index and associates it with the *key* value. Optionally, in-case of non-unique index, replaces it with existing object if such key is already present in the index.
27 |
28 | * ```index.get( key ) returns: object | [objects...]```
29 |
30 | Returns object at the *key* position or null. *key* has to be of the same type as the type of the index object. If the index was created as non unique then the return value is an array - list of items under the key.
31 |
32 | * ```index.delete( key [,obj] ) returns: true | false```
33 |
34 | Method removes object *obj* by key from the index. Method returns true on success, otherwise false. If the index is unique, obj is optional.
35 |
36 | * ```index.select( minKey, maxKey [, ascending [, startInclusive [, endInclusive]]] ) returns: Iterator.```
37 |
38 | Returns selection in the Index based on criteria min-key, max-key, ascent or descent order, start-inclusive, end-inclusive. Default values: ```ascending:true```, ```startInclusive:true``` and ```endInclusive:true```.
39 |
40 | The method is intendeded to be used in ```for(of)``` enumerations:
41 |
42 | ```JavaScript:
43 | for( var obj in index.select(minVal, maxVal) ) { ... }
44 | ```
45 |
46 | Either minKey or maxKey can be *null* that means search from very first or very last key in the index.
47 |
48 | * ```index.clear()```
49 |
50 | Removes all items from the index object - makes it empty.
--------------------------------------------------------------------------------
/examples/pi_bigfloat.js:
--------------------------------------------------------------------------------
1 | /*
2 | * PI computation in Javascript using the QuickJS bigfloat type
3 | * (binary floating point)
4 | */
5 | "use strict";
6 |
7 | /* compute PI with a precision of 'prec' bits */
8 | function calc_pi() {
9 | const CHUD_A = 13591409n;
10 | const CHUD_B = 545140134n;
11 | const CHUD_C = 640320n;
12 | const CHUD_C3 = 10939058860032000n; /* C^3/24 */
13 | const CHUD_BITS_PER_TERM = 47.11041313821584202247; /* log2(C/12)*3 */
14 |
15 | /* return [P, Q, G] */
16 | function chud_bs(a, b, need_G) {
17 | var c, P, Q, G, P1, Q1, G1, P2, Q2, G2;
18 | if (a == (b - 1n)) {
19 | G = (2n * b - 1n) * (6n * b - 1n) * (6n * b - 5n);
20 | P = BigFloat(G * (CHUD_B * b + CHUD_A));
21 | if (b & 1n)
22 | P = -P;
23 | G = BigFloat(G);
24 | Q = BigFloat(b * b * b * CHUD_C3);
25 | } else {
26 | c = (a + b) >> 1n;
27 | [P1, Q1, G1] = chud_bs(a, c, true);
28 | [P2, Q2, G2] = chud_bs(c, b, need_G);
29 | P = P1 * Q2 + P2 * G1;
30 | Q = Q1 * Q2;
31 | if (need_G)
32 | G = G1 * G2;
33 | else
34 | G = 0l;
35 | }
36 | return [P, Q, G];
37 | }
38 |
39 | var n, P, Q, G;
40 | /* number of serie terms */
41 | n = BigInt(Math.ceil(BigFloatEnv.prec / CHUD_BITS_PER_TERM)) + 10n;
42 | [P, Q, G] = chud_bs(0n, n, false);
43 | Q = Q / (P + Q * BigFloat(CHUD_A));
44 | G = BigFloat((CHUD_C / 12n)) * BigFloat.sqrt(BigFloat(CHUD_C));
45 | return Q * G;
46 | }
47 |
48 | (function() {
49 | var r, n_digits, n_bits;
50 | if (typeof scriptArgs != "undefined") {
51 | if (scriptArgs.length < 2) {
52 | print("usage: pi n_digits");
53 | return;
54 | }
55 | n_digits = scriptArgs[1];
56 | } else {
57 | n_digits = 1000;
58 | }
59 | n_bits = Math.ceil(n_digits * Math.log2(10));
60 | /* we add more bits to reduce the probability of bad rounding for
61 | the last digits */
62 | BigFloatEnv.setPrec( () => {
63 | r = calc_pi();
64 | print(r.toFixed(n_digits, BigFloatEnv.RNDZ));
65 | }, n_bits + 32);
66 | })();
67 |
--------------------------------------------------------------------------------
/examples/pi_bigdecimal.js:
--------------------------------------------------------------------------------
1 | /*
2 | * PI computation in Javascript using the QuickJS bigdecimal type
3 | * (decimal floating point)
4 | */
5 | "use strict";
6 |
7 | /* compute PI with a precision of 'prec' digits */
8 | function calc_pi(prec) {
9 | const CHUD_A = 13591409m;
10 | const CHUD_B = 545140134m;
11 | const CHUD_C = 640320m;
12 | const CHUD_C3 = 10939058860032000m; /* C^3/24 */
13 | const CHUD_DIGITS_PER_TERM = 14.18164746272548; /* log10(C/12)*3 */
14 |
15 | /* return [P, Q, G] */
16 | function chud_bs(a, b, need_G) {
17 | var c, P, Q, G, P1, Q1, G1, P2, Q2, G2, b1;
18 | if (a == (b - 1n)) {
19 | b1 = BigDecimal(b);
20 | G = (2m * b1 - 1m) * (6m * b1 - 1m) * (6m * b1 - 5m);
21 | P = G * (CHUD_B * b1 + CHUD_A);
22 | if (b & 1n)
23 | P = -P;
24 | G = G;
25 | Q = b1 * b1 * b1 * CHUD_C3;
26 | } else {
27 | c = (a + b) >> 1n;
28 | [P1, Q1, G1] = chud_bs(a, c, true);
29 | [P2, Q2, G2] = chud_bs(c, b, need_G);
30 | P = P1 * Q2 + P2 * G1;
31 | Q = Q1 * Q2;
32 | if (need_G)
33 | G = G1 * G2;
34 | else
35 | G = 0m;
36 | }
37 | return [P, Q, G];
38 | }
39 |
40 | var n, P, Q, G;
41 | /* number of serie terms */
42 | n = BigInt(Math.ceil(prec / CHUD_DIGITS_PER_TERM)) + 10n;
43 | [P, Q, G] = chud_bs(0n, n, false);
44 | Q = BigDecimal.div(Q, (P + Q * CHUD_A),
45 | { roundingMode: "half-even",
46 | maximumSignificantDigits: prec });
47 | G = (CHUD_C / 12m) * BigDecimal.sqrt(CHUD_C,
48 | { roundingMode: "half-even",
49 | maximumSignificantDigits: prec });
50 | return Q * G;
51 | }
52 |
53 | (function() {
54 | var r, n_digits, n_bits;
55 | if (typeof scriptArgs != "undefined") {
56 | if (scriptArgs.length < 2) {
57 | print("usage: pi n_digits");
58 | return;
59 | }
60 | n_digits = scriptArgs[1] | 0;
61 | } else {
62 | n_digits = 1000;
63 | }
64 | /* we add more digits to reduce the probability of bad rounding for
65 | the last digits */
66 | r = calc_pi(n_digits + 20);
67 | print(r.toFixed(n_digits, "down"));
68 | })();
69 |
--------------------------------------------------------------------------------
/libregexp-opcode.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Regular Expression Engine
3 | *
4 | * Copyright (c) 2017-2018 Fabrice Bellard
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 |
25 | #ifdef DEF
26 |
27 | DEF(invalid, 1) /* never used */
28 | DEF(char, 3)
29 | DEF(char32, 5)
30 | DEF(dot, 1)
31 | DEF(any, 1) /* same as dot but match any character including line terminator */
32 | DEF(line_start, 1)
33 | DEF(line_end, 1)
34 | DEF(goto, 5)
35 | DEF(split_goto_first, 5)
36 | DEF(split_next_first, 5)
37 | DEF(match, 1)
38 | DEF(save_start, 2) /* save start position */
39 | DEF(save_end, 2) /* save end position, must come after saved_start */
40 | DEF(save_reset, 3) /* reset save positions */
41 | DEF(loop, 5) /* decrement the top the stack and goto if != 0 */
42 | DEF(push_i32, 5) /* push integer on the stack */
43 | DEF(drop, 1)
44 | DEF(word_boundary, 1)
45 | DEF(not_word_boundary, 1)
46 | DEF(back_reference, 2)
47 | DEF(backward_back_reference, 2) /* must come after back_reference */
48 | DEF(range, 3) /* variable length */
49 | DEF(range32, 3) /* variable length */
50 | DEF(lookahead, 5)
51 | DEF(negative_lookahead, 5)
52 | DEF(push_char_pos, 1) /* push the character position on the stack */
53 | DEF(bne_char_pos, 5) /* pop one stack element and jump if equal to the character
54 | position */
55 | DEF(prev, 1) /* go to the previous char */
56 | DEF(simple_greedy_quant, 17)
57 |
58 | #endif /* DEF */
59 |
--------------------------------------------------------------------------------
/tests/test262.patch:
--------------------------------------------------------------------------------
1 | diff --git a/harness/atomicsHelper.js b/harness/atomicsHelper.js
2 | index 9c1217351e..3c24755558 100644
3 | --- a/harness/atomicsHelper.js
4 | +++ b/harness/atomicsHelper.js
5 | @@ -227,10 +227,14 @@ $262.agent.waitUntil = function(typedArray, index, expected) {
6 | * }
7 | */
8 | $262.agent.timeouts = {
9 | - yield: 100,
10 | - small: 200,
11 | - long: 1000,
12 | - huge: 10000,
13 | +// yield: 100,
14 | +// small: 200,
15 | +// long: 1000,
16 | +// huge: 10000,
17 | + yield: 20,
18 | + small: 20,
19 | + long: 100,
20 | + huge: 1000,
21 | };
22 |
23 | /**
24 | diff --git a/harness/regExpUtils.js b/harness/regExpUtils.js
25 | index be7039fda0..7b38abf8df 100644
26 | --- a/harness/regExpUtils.js
27 | +++ b/harness/regExpUtils.js
28 | @@ -6,24 +6,27 @@ description: |
29 | defines: [buildString, testPropertyEscapes, matchValidator]
30 | ---*/
31 |
32 | +if ($262 && typeof $262.codePointRange === "function") {
33 | + /* use C function to build the codePointRange (much faster with
34 | + slow JS engines) */
35 | + codePointRange = $262.codePointRange;
36 | +} else {
37 | + codePointRange = function codePointRange(start, end) {
38 | + const codePoints = [];
39 | + let length = 0;
40 | + for (codePoint = start; codePoint < end; codePoint++) {
41 | + codePoints[length++] = codePoint;
42 | + }
43 | + return String.fromCodePoint.apply(null, codePoints);
44 | + }
45 | +}
46 | +
47 | function buildString({ loneCodePoints, ranges }) {
48 | - const CHUNK_SIZE = 10000;
49 | - let result = Reflect.apply(String.fromCodePoint, null, loneCodePoints);
50 | - for (let i = 0; i < ranges.length; i++) {
51 | - const range = ranges[i];
52 | - const start = range[0];
53 | - const end = range[1];
54 | - const codePoints = [];
55 | - for (let length = 0, codePoint = start; codePoint <= end; codePoint++) {
56 | - codePoints[length++] = codePoint;
57 | - if (length === CHUNK_SIZE) {
58 | - result += Reflect.apply(String.fromCodePoint, null, codePoints);
59 | - codePoints.length = length = 0;
60 | - }
61 | + let result = String.fromCodePoint.apply(null, loneCodePoints);
62 | + for (const [start, end] of ranges) {
63 | + result += codePointRange(start, end + 1);
64 | }
65 | - result += Reflect.apply(String.fromCodePoint, null, codePoints);
66 | - }
67 | - return result;
68 | + return result;
69 | }
70 |
71 | function testPropertyEscapes(regex, string, expression) {
72 |
--------------------------------------------------------------------------------
/examples/fib.c:
--------------------------------------------------------------------------------
1 | /*
2 | * QuickJS: Example of C module
3 | *
4 | * Copyright (c) 2017-2018 Fabrice Bellard
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 | #include "../quickjs.h"
25 |
26 | #define countof(x) (sizeof(x) / sizeof((x)[0]))
27 |
28 | static int fib(int n)
29 | {
30 | if (n <= 0)
31 | return 0;
32 | else if (n == 1)
33 | return 1;
34 | else
35 | return fib(n - 1) + fib(n - 2);
36 | }
37 |
38 | static JSValue js_fib(JSContext *ctx, JSValueConst this_val,
39 | int argc, JSValueConst *argv)
40 | {
41 | int n, res;
42 | if (JS_ToInt32(ctx, &n, argv[0]))
43 | return JS_EXCEPTION;
44 | res = fib(n);
45 | return JS_NewInt32(ctx, res);
46 | }
47 |
48 | static const JSCFunctionListEntry js_fib_funcs[] = {
49 | JS_CFUNC_DEF("fib", 1, js_fib ),
50 | };
51 |
52 | static int js_fib_init(JSContext *ctx, JSModuleDef *m)
53 | {
54 | return JS_SetModuleExportList(ctx, m, js_fib_funcs,
55 | countof(js_fib_funcs));
56 | }
57 |
58 | #ifdef JS_SHARED_LIBRARY
59 | #define JS_INIT_MODULE js_init_module
60 | #else
61 | #define JS_INIT_MODULE js_init_module_fib
62 | #endif
63 |
64 | JSModuleDef *JS_INIT_MODULE(JSContext *ctx, const char *module_name)
65 | {
66 | JSModuleDef *m;
67 | m = JS_NewCModule(ctx, module_name, js_fib_init);
68 | if (!m)
69 | return NULL;
70 | JS_AddModuleExportList(ctx, m, js_fib_funcs, countof(js_fib_funcs));
71 | return m;
72 | }
73 |
--------------------------------------------------------------------------------
/quickjs-libc.h:
--------------------------------------------------------------------------------
1 | /*
2 | * QuickJS C library
3 | *
4 | * Copyright (c) 2017-2018 Fabrice Bellard
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 | #ifndef QUICKJS_LIBC_H
25 | #define QUICKJS_LIBC_H
26 |
27 | #include
28 | #include
29 |
30 | #include "quickjs.h"
31 |
32 | #ifdef __cplusplus
33 | extern "C" {
34 | #endif
35 |
36 | JSModuleDef *js_init_module_std(JSContext *ctx, const char *module_name);
37 | JSModuleDef *js_init_module_os(JSContext *ctx, const char *module_name);
38 | void js_std_add_helpers(JSContext *ctx, int argc, char **argv);
39 | void js_std_loop(JSContext *ctx);
40 | void js_std_init_handlers(JSRuntime *rt);
41 | void js_std_free_handlers(JSRuntime *rt);
42 | void js_std_dump_error(JSContext *ctx);
43 | uint8_t *js_load_file(JSContext *ctx, size_t *pbuf_len, const char *filename);
44 | int js_module_set_import_meta(JSContext *ctx, JSValueConst func_val,
45 | JS_BOOL use_realpath, JS_BOOL is_main);
46 | JSModuleDef *js_module_loader(JSContext *ctx,
47 | const char *module_name, void *opaque);
48 | void js_std_eval_binary(JSContext *ctx, const uint8_t *buf, size_t buf_len,
49 | int flags);
50 | void js_std_promise_rejection_tracker(JSContext *ctx, JSValueConst promise,
51 | JSValueConst reason,
52 | JS_BOOL is_handled, void *opaque);
53 | void js_std_set_worker_new_context_func(JSContext *(*func)(JSRuntime *rt));
54 |
55 | #ifdef __cplusplus
56 | } /* extern "C" { */
57 | #endif
58 |
59 | #endif /* QUICKJS_LIBC_H */
60 |
--------------------------------------------------------------------------------
/doc/jsx.md:
--------------------------------------------------------------------------------
1 | # JSX - JavaScript XML/HTML language extensions
2 |
3 | Basic idea, this JS+X expression:
4 |
5 | ```javascript
6 | var data = Hello world!
;
7 | ```
8 | Gets parsed into code equivalent to this:
9 |
10 | ```javascript
11 | var data = JSX("div", {id:"foo"}, ["Hello world"]]);
12 | ```
13 | Where JSX is a global function, so called "JSX driver", defined elsewhere with the following signature:
14 |
15 | ```javascript
16 | function JSX(tag,atts,kids) {...}
17 | ```
18 | where:
19 |
20 | * `tag` - string, tag name: "div","p", ...;
21 | * `atts` - object, element attributes: `{id:"foo"}`
22 | * `kids` - array, child sub elements - strings or results of sub-calls of JSX.
23 |
24 | # Use cases
25 |
26 | JSX can be used with popular JS UI libraries as it is.
27 |
28 | ## [Mithril](https://mithril.js.org)
29 |
30 | This canonic Mithril sample:
31 | ```javascript
32 | var count = 0 // added a variable
33 |
34 | var Hello = {
35 | view: function() {
36 | return m("main", [
37 | m("h1", {class: "title"}, "My first app"),
38 | // changed the next line
39 | m("button", {onclick: function() {count++}}, count + " clicks"),
40 | ])
41 | }
42 | }
43 |
44 | m.mount(root, Hello)
45 | ```
46 |
47 | Can be rewritten using JS+X in more natural way as:
48 |
49 | ```javascript
50 |
51 | JSX = m; // using m() mithril function "as it is" as JSX driver!
52 |
53 | var count = 0 // added a variable
54 |
55 | var Hello = {
56 | view: function() {
57 | return
58 | My first app
59 |
60 |
61 | }
62 | }
63 |
64 | m.mount(root, Hello)
65 | ```
66 |
67 | ## [ReactJS](https://reactjs.org/)
68 |
69 | ReactJS shall also be able to use JSX as it is, it is just a matter of declaring
70 |
71 | ```javascript
72 |
73 | JSX = React.createElement; // using ReactJS VNode creator as JSX driver
74 | ```
75 |
76 | # JSX syntax details
77 |
78 | 1. Tags and attribute names shall follow JS/XML naming convention and may contain `-` (dashes) inside.
79 | 2. Attributes and element content may contain expressions enclosed into `{` and `}` brackets:
80 |
81 | ```javascript
82 | var className = "foo";
83 | var listItems = ["one","two", "three"];
84 |
85 | function renderList() {
86 | return
87 | { listItems.map( item => - {item}
) }
88 |
89 | }
90 | ```
91 | to generate list:
92 | ```html
93 |
94 | - one
95 | - two
96 | - three
97 |
98 | ```
99 |
100 | # To enable JSX support
101 |
102 | To enable JSX support on QuickJS from this repository define CONFIG_JSX option while compiling.
103 |
104 | [premake5.lua](https://github.com/c-smile/quickjspp/blob/master/premake5.lua#L23) script already defines CONFIG_JSX.
105 |
106 |
--------------------------------------------------------------------------------
/storage/dybase/src/hashtab.h:
--------------------------------------------------------------------------------
1 | #ifndef __HASHTAB_H__
2 | #define __HASHTAB_H__
3 |
4 | static const length_t dbHashtableSize = 1013;
5 |
6 | // if it returns non-zero - stops enumeration
7 | typedef int each_cb(void* key, unsigned int key_length, void* data, void* opaque);
8 |
9 | class dbHashtable {
10 | private:
11 | struct Entry {
12 | Entry * next;
13 | void * value;
14 | void * key;
15 | length_t keySize;
16 | unsigned hashCode;
17 | };
18 |
19 | Entry **table;
20 |
21 | static unsigned calculateHashCode(void *key, length_t keySize) {
22 | unsigned char *p = (unsigned char *)key;
23 | int n = int(keySize);
24 | unsigned h = 0;
25 | while (--n >= 0) {
26 | h = (h << 2) ^ *p++;
27 | }
28 | return h;
29 | }
30 |
31 | dbHashtable(const dbHashtable &);
32 | dbHashtable &operator=(const dbHashtable &);
33 |
34 | public:
35 | dbHashtable() {
36 | table = new Entry *[dbHashtableSize];
37 | memset(table, 0, sizeof(Entry *) * dbHashtableSize);
38 | }
39 |
40 | void put(void *key, length_t keySize, void *value) {
41 | unsigned hashCode = calculateHashCode(key, keySize);
42 | Entry * e = new Entry();
43 | e->hashCode = hashCode;
44 | e->key = key;
45 | e->keySize = keySize;
46 | e->value = value;
47 | unsigned h = hashCode % dbHashtableSize;
48 | e->next = table[h];
49 | table[h] = e;
50 | }
51 |
52 | void *get(void *key, length_t keySize) {
53 | unsigned hashCode = calculateHashCode(key, keySize);
54 | unsigned h = hashCode % dbHashtableSize;
55 | for (Entry *e = table[h]; e != NULL; e = e->next) {
56 | if (e->hashCode == hashCode && e->keySize == keySize &&
57 | memcmp(e->key, key, keySize) == 0) {
58 | return e->value;
59 | }
60 | }
61 | return NULL;
62 | }
63 |
64 | void *remove(void *key, length_t keySize) {
65 | Entry ** epp, *ep;
66 | unsigned hashCode = calculateHashCode(key, keySize);
67 | unsigned h = hashCode % dbHashtableSize;
68 | for (epp = &table[h]; (ep = *epp) != NULL; epp = &ep->next) {
69 | if (ep->hashCode == hashCode && memcmp(ep->key, key, keySize) == 0) {
70 | *epp = ep->next;
71 | return ep->value;
72 | }
73 | }
74 | return NULL;
75 | }
76 |
77 | void clear() {
78 | for (int i = dbHashtableSize; --i >= 0;) {
79 | Entry *e, *next;
80 | for (e = table[i]; e != NULL; e = next) {
81 | next = e->next;
82 | delete e;
83 | }
84 | table[i] = NULL;
85 | }
86 | }
87 |
88 | void each(each_cb* pcb, void* opaque) {
89 | for (int i = dbHashtableSize; --i >= 0;) {
90 | Entry *e, *next;
91 | for (e = table[i]; e != NULL; e = next) {
92 | next = e->next;
93 | if (pcb(e->key, e->keySize, e->value, opaque))
94 | break;
95 | }
96 | }
97 | }
98 |
99 |
100 | ~dbHashtable() {
101 | clear();
102 | delete[] table;
103 | }
104 | };
105 |
106 | #endif
107 |
--------------------------------------------------------------------------------
/TODO:
--------------------------------------------------------------------------------
1 | Bugs:
2 | - modules: better error handling with cyclic module references
3 |
4 | Misc ideas:
5 | - use custom printf to avoid compatibility issues with floating point numbers
6 | - consistent naming for preprocessor defines
7 | - unify coding style and naming conventions
8 | - use names from the ECMA spec in library implementation
9 | - use byte code emitters with typed arguments (for clarity)
10 | - use 2 bytecode DynBufs in JSFunctionDef, one for reading, one for writing
11 | and use the same wrappers in all phases
12 | - use more generic method for line numbers in resolve_variables and resolve_labels
13 | - use custom timezone support to avoid C library compatibility issues
14 |
15 | Memory:
16 | - use memory pools for objects, etc?
17 | - test border cases for max number of atoms, object properties, string length
18 | - add emergency malloc mode for out of memory exceptions.
19 | - test all DynBuf memory errors
20 | - test all js_realloc memory errors
21 | - improve JS_ComputeMemoryUsage() with more info
22 |
23 | Built-in standard library:
24 | - BSD sockets
25 | - modules: use realpath in module name normalizer and put it in quickjs-libc
26 | - modules: if no ".", use a well known module loading path ?
27 | - get rid of __loadScript, use more common name
28 |
29 | REPL:
30 | - debugger
31 | - readline: support MS Windows terminal
32 | - readline: handle dynamic terminal resizing
33 | - readline: handle double width unicode characters
34 | - multiline editing
35 | - runtime object and function inspectors
36 | - interactive object browser
37 | - use more generic approach to display evaluation results
38 | - improve directive handling: dispatch, colorize, completion...
39 | - save history
40 | - close all predefined methods in repl.js and jscalc.js
41 |
42 | Optimization ideas:
43 | - 64-bit atoms in 64-bit mode ?
44 | - 64-bit small bigint in 64-bit mode ?
45 | - reuse stack slots for disjoint scopes, if strip
46 | - add heuristic to avoid some cycles in closures
47 | - small String (0-2 charcodes) with immediate storage
48 | - perform static string concatenation at compile time
49 | - optimize string concatenation with ropes or miniropes?
50 | - add implicit numeric strings for Uint32 numbers?
51 | - optimize `s += a + b`, `s += a.b` and similar simple expressions
52 | - ensure string canonical representation and optimise comparisons and hashes?
53 | - remove JSObject.first_weak_ref, use bit+context based hashed array for weak references
54 | - property access optimization on the global object, functions,
55 | prototypes and special non extensible objects.
56 | - create object literals with the correct length by backpatching length argument
57 | - remove redundant set_loc_uninitialized/check_uninitialized opcodes
58 | - peephole optim: push_atom_value, to_propkey -> push_atom_value
59 | - peephole optim: put_loc x, get_loc_check x -> set_loc x
60 | - convert slow array to fast array when all properties != length are numeric
61 | - optimize destructuring assignments for global and local variables
62 | - implement some form of tail-call-optimization
63 | - optimize OP_apply
64 | - optimize f(...b)
65 |
66 | Test262o: 0/11262 errors, 463 excluded
67 | Test262o commit: 7da91bceb9ce7613f87db47ddd1292a2dda58b42 (es5-tests branch)
68 |
69 | Result: 35/75280 errors, 909 excluded, 585 skipped
70 | Test262 commit: 31126581e7290f9233c29cefd93f66c6ac78f1c9
71 |
--------------------------------------------------------------------------------
/examples/pi_bigint.js:
--------------------------------------------------------------------------------
1 | /*
2 | * PI computation in Javascript using the BigInt type
3 | */
4 | "use strict";
5 |
6 | /* return floor(log2(a)) for a > 0 and 0 for a = 0 */
7 | function floor_log2(a)
8 | {
9 | var k_max, a1, k, i;
10 | k_max = 0n;
11 | while ((a >> (2n ** k_max)) != 0n) {
12 | k_max++;
13 | }
14 | k = 0n;
15 | a1 = a;
16 | for(i = k_max - 1n; i >= 0n; i--) {
17 | a1 = a >> (2n ** i);
18 | if (a1 != 0n) {
19 | a = a1;
20 | k |= (1n << i);
21 | }
22 | }
23 | return k;
24 | }
25 |
26 | /* return ceil(log2(a)) for a > 0 */
27 | function ceil_log2(a)
28 | {
29 | return floor_log2(a - 1n) + 1n;
30 | }
31 |
32 | /* return floor(sqrt(a)) (not efficient but simple) */
33 | function int_sqrt(a)
34 | {
35 | var l, u, s;
36 | if (a == 0n)
37 | return a;
38 | l = ceil_log2(a);
39 | u = 1n << ((l + 1n) / 2n);
40 | /* u >= floor(sqrt(a)) */
41 | for(;;) {
42 | s = u;
43 | u = ((a / s) + s) / 2n;
44 | if (u >= s)
45 | break;
46 | }
47 | return s;
48 | }
49 |
50 | /* return pi * 2**prec */
51 | function calc_pi(prec) {
52 | const CHUD_A = 13591409n;
53 | const CHUD_B = 545140134n;
54 | const CHUD_C = 640320n;
55 | const CHUD_C3 = 10939058860032000n; /* C^3/24 */
56 | const CHUD_BITS_PER_TERM = 47.11041313821584202247; /* log2(C/12)*3 */
57 |
58 | /* return [P, Q, G] */
59 | function chud_bs(a, b, need_G) {
60 | var c, P, Q, G, P1, Q1, G1, P2, Q2, G2;
61 | if (a == (b - 1n)) {
62 | G = (2n * b - 1n) * (6n * b - 1n) * (6n * b - 5n);
63 | P = G * (CHUD_B * b + CHUD_A);
64 | if (b & 1n)
65 | P = -P;
66 | Q = b * b * b * CHUD_C3;
67 | } else {
68 | c = (a + b) >> 1n;
69 | [P1, Q1, G1] = chud_bs(a, c, true);
70 | [P2, Q2, G2] = chud_bs(c, b, need_G);
71 | P = P1 * Q2 + P2 * G1;
72 | Q = Q1 * Q2;
73 | if (need_G)
74 | G = G1 * G2;
75 | else
76 | G = 0n;
77 | }
78 | return [P, Q, G];
79 | }
80 |
81 | var n, P, Q, G;
82 | /* number of serie terms */
83 | n = BigInt(Math.ceil(Number(prec) / CHUD_BITS_PER_TERM)) + 10n;
84 | [P, Q, G] = chud_bs(0n, n, false);
85 | Q = (CHUD_C / 12n) * (Q << prec) / (P + Q * CHUD_A);
86 | G = int_sqrt(CHUD_C << (2n * prec));
87 | return (Q * G) >> prec;
88 | }
89 |
90 | function main(args) {
91 | var r, n_digits, n_bits, out;
92 | if (args.length < 1) {
93 | print("usage: pi n_digits");
94 | return;
95 | }
96 | n_digits = args[0] | 0;
97 |
98 | /* we add more bits to reduce the probability of bad rounding for
99 | the last digits */
100 | n_bits = BigInt(Math.ceil(n_digits * Math.log2(10))) + 32n;
101 | r = calc_pi(n_bits);
102 | r = ((10n ** BigInt(n_digits)) * r) >> n_bits;
103 | out = r.toString();
104 | print(out[0] + "." + out.slice(1));
105 | }
106 |
107 | var args;
108 | if (typeof scriptArgs != "undefined") {
109 | args = scriptArgs;
110 | args.shift();
111 | } else if (typeof arguments != "undefined") {
112 | args = arguments;
113 | } else {
114 | /* default: 1000 digits */
115 | args=[1000];
116 | }
117 |
118 | main(args);
119 |
--------------------------------------------------------------------------------
/tests/bjson.c:
--------------------------------------------------------------------------------
1 | /*
2 | * QuickJS: binary JSON module (test only)
3 | *
4 | * Copyright (c) 2017-2019 Fabrice Bellard
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 | #include "../quickjs-libc.h"
25 | #include "../cutils.h"
26 |
27 | static JSValue js_bjson_read(JSContext *ctx, JSValueConst this_val,
28 | int argc, JSValueConst *argv)
29 | {
30 | uint8_t *buf;
31 | uint64_t pos, len;
32 | JSValue obj;
33 | size_t size;
34 | int flags;
35 |
36 | if (JS_ToIndex(ctx, &pos, argv[1]))
37 | return JS_EXCEPTION;
38 | if (JS_ToIndex(ctx, &len, argv[2]))
39 | return JS_EXCEPTION;
40 | buf = JS_GetArrayBuffer(ctx, &size, argv[0]);
41 | if (!buf)
42 | return JS_EXCEPTION;
43 | if (pos + len > size)
44 | return JS_ThrowRangeError(ctx, "array buffer overflow");
45 | flags = 0;
46 | if (JS_ToBool(ctx, argv[3]))
47 | flags |= JS_READ_OBJ_REFERENCE;
48 | obj = JS_ReadObject(ctx, buf + pos, len, flags);
49 | return obj;
50 | }
51 |
52 | static JSValue js_bjson_write(JSContext *ctx, JSValueConst this_val,
53 | int argc, JSValueConst *argv)
54 | {
55 | size_t len;
56 | uint8_t *buf;
57 | JSValue array;
58 | int flags;
59 |
60 | flags = 0;
61 | if (JS_ToBool(ctx, argv[1]))
62 | flags |= JS_WRITE_OBJ_REFERENCE;
63 | buf = JS_WriteObject(ctx, &len, argv[0], flags);
64 | if (!buf)
65 | return JS_EXCEPTION;
66 | array = JS_NewArrayBufferCopy(ctx, buf, len);
67 | js_free(ctx, buf);
68 | return array;
69 | }
70 |
71 | static const JSCFunctionListEntry js_bjson_funcs[] = {
72 | JS_CFUNC_DEF("read", 4, js_bjson_read ),
73 | JS_CFUNC_DEF("write", 2, js_bjson_write ),
74 | };
75 |
76 | static int js_bjson_init(JSContext *ctx, JSModuleDef *m)
77 | {
78 | return JS_SetModuleExportList(ctx, m, js_bjson_funcs,
79 | countof(js_bjson_funcs));
80 | }
81 |
82 | #ifdef JS_SHARED_LIBRARY
83 | #define JS_INIT_MODULE js_init_module
84 | #else
85 | #define JS_INIT_MODULE js_init_module_bjson
86 | #endif
87 |
88 | JSModuleDef *JS_INIT_MODULE(JSContext *ctx, const char *module_name)
89 | {
90 | JSModuleDef *m;
91 | m = JS_NewCModule(ctx, module_name, js_bjson_init);
92 | if (!m)
93 | return NULL;
94 | JS_AddModuleExportList(ctx, m, js_bjson_funcs, countof(js_bjson_funcs));
95 | return m;
96 | }
97 |
--------------------------------------------------------------------------------
/libregexp.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Regular Expression Engine
3 | *
4 | * Copyright (c) 2017-2018 Fabrice Bellard
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 | #ifndef LIBREGEXP_H
25 | #define LIBREGEXP_H
26 |
27 | #include
28 |
29 | #include "libunicode.h"
30 |
31 | #define LRE_BOOL int /* for documentation purposes */
32 |
33 | #define LRE_FLAG_GLOBAL (1 << 0)
34 | #define LRE_FLAG_IGNORECASE (1 << 1)
35 | #define LRE_FLAG_MULTILINE (1 << 2)
36 | #define LRE_FLAG_DOTALL (1 << 3)
37 | #define LRE_FLAG_UTF16 (1 << 4)
38 | #define LRE_FLAG_STICKY (1 << 5)
39 |
40 | #define LRE_FLAG_NAMED_GROUPS (1 << 7) /* named groups are present in the regexp */
41 |
42 | uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size,
43 | const char *buf, size_t buf_len, int re_flags,
44 | void *opaque);
45 | int lre_get_capture_count(const uint8_t *bc_buf);
46 | int lre_get_flags(const uint8_t *bc_buf);
47 | const char *lre_get_groupnames(const uint8_t *bc_buf);
48 | int lre_exec(uint8_t **capture,
49 | const uint8_t *bc_buf, const uint8_t *cbuf, int cindex, int clen,
50 | int cbuf_type, void *opaque);
51 |
52 | int lre_parse_escape(const uint8_t **pp, int allow_utf16);
53 | LRE_BOOL lre_is_space(int c);
54 |
55 | /* must be provided by the user */
56 | LRE_BOOL lre_check_stack_overflow(void *opaque, size_t alloca_size);
57 | void *lre_realloc(void *opaque, void *ptr, size_t size);
58 |
59 | /* JS identifier test */
60 | extern uint32_t const lre_id_start_table_ascii[4];
61 | extern uint32_t const lre_id_continue_table_ascii[4];
62 |
63 | static inline int lre_js_is_ident_first(int c)
64 | {
65 | if ((uint32_t)c < 128) {
66 | return (lre_id_start_table_ascii[c >> 5] >> (c & 31)) & 1;
67 | } else {
68 | #ifdef CONFIG_ALL_UNICODE
69 | return lre_is_id_start(c);
70 | #else
71 | return !lre_is_space(c);
72 | #endif
73 | }
74 | }
75 |
76 | static inline int lre_js_is_ident_next(int c)
77 | {
78 | if ((uint32_t)c < 128) {
79 | return (lre_id_continue_table_ascii[c >> 5] >> (c & 31)) & 1;
80 | } else {
81 | /* ZWNJ and ZWJ are accepted in identifiers */
82 | #ifdef CONFIG_ALL_UNICODE
83 | return lre_is_id_continue(c) || c == 0x200C || c == 0x200D;
84 | #else
85 | return !lre_is_space(c) || c == 0x200C || c == 0x200D;
86 | #endif
87 | }
88 | }
89 |
90 | #undef LRE_BOOL
91 |
92 | #endif /* LIBREGEXP_H */
93 |
--------------------------------------------------------------------------------
/storage/dybase/src/file.h:
--------------------------------------------------------------------------------
1 | //-< FILE.CPP >------------------------------------------------------*--------*
2 | // GigaBASE Version 1.0 (c) 1999 GARRET * ? *
3 | // (Post Relational Database Management System) * /\| *
4 | // * / \ *
5 | // Created: 20-Nov-98 K.A. Knizhnik * / [] \ *
6 | // Last update: 30-Jan-99 K.A. Knizhnik * GARRET *
7 | //-------------------------------------------------------------------*--------*
8 | // System independent intrface to operating system file
9 | //-------------------------------------------------------------------*--------*
10 |
11 | #ifndef __FILE_H__
12 | #define __FILE_H__
13 |
14 | #include "sync.h"
15 |
16 | const length_t dbDefaultRaidBlockSize = 1024 * 1024;
17 |
18 | /**
19 | * Internal implementation of file
20 | */
21 | class dbFile {
22 | protected:
23 | #if defined(_WIN32)
24 | HANDLE fh;
25 | #else
26 | int fd;
27 | #endif
28 | dbMutex mutex;
29 |
30 | public:
31 | enum ReturnStatus {
32 | ok = 0,
33 | eof = -1 // number of read/written bytes is smaller than requested
34 | };
35 | enum OpenAttributes {
36 | read_only = 0x01,
37 | truncate = 0x02,
38 | sequential = 0x04,
39 | no_buffering = 0x08
40 | };
41 | int open(char const *fileName, int attr);
42 | int open(wchar_t const *fileName, int attr);
43 | int write(void const *ptr, length_t size);
44 | int read(void *ptr, length_t size);
45 |
46 | dbFile();
47 | virtual ~dbFile();
48 |
49 | virtual int flush();
50 | virtual int close();
51 |
52 | virtual int setSize(offs_t offs);
53 |
54 | virtual int write(offs_t pos, void const *ptr, length_t size);
55 | virtual int read(offs_t pos, void *ptr, length_t size);
56 |
57 | static void *allocateBuffer(length_t bufferSize);
58 | static void deallocateBuffer(void *buffer, length_t size = 0);
59 | static void protectBuffer(void *buf, length_t bufSize, bool readonly);
60 |
61 | static length_t ramSize();
62 |
63 | static char *errorText(int code, char *buf, length_t bufSize);
64 | };
65 |
66 | /**
67 | * File consisting of multiple segments
68 | */
69 | class dbMultiFile : public dbFile {
70 | public:
71 | struct dbSegment {
72 | char * name;
73 | offs_t size;
74 | offs_t offs;
75 | };
76 |
77 | int open(int nSegments, dbSegment *segments, int attr);
78 |
79 | virtual int setSize(offs_t offs);
80 |
81 | virtual int flush();
82 | virtual int close();
83 |
84 | virtual int write(offs_t pos, void const *ptr, length_t size);
85 | virtual int read(offs_t pos, void *ptr, length_t size);
86 |
87 | dbMultiFile() { segment = NULL; }
88 | ~dbMultiFile() {}
89 |
90 | protected:
91 | class dbFileSegment : public dbFile {
92 | public:
93 | offs_t size;
94 | offs_t offs;
95 | };
96 | int nSegments;
97 | dbFileSegment *segment;
98 | };
99 |
100 | /*
101 | * RAID-1 file. Scattern file blocks between several physical segments
102 | */
103 | class dbRaidFile : public dbMultiFile {
104 | length_t raidBlockSize;
105 |
106 | public:
107 | dbRaidFile(length_t blockSize) { raidBlockSize = blockSize; }
108 |
109 | virtual int setSize(offs_t offs);
110 |
111 | virtual int write(offs_t pos, void const *ptr, length_t size);
112 | virtual int read(offs_t pos, void *ptr, length_t size);
113 | };
114 |
115 | #endif
116 |
--------------------------------------------------------------------------------
/list.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Linux klist like system
3 | *
4 | * Copyright (c) 2016-2017 Fabrice Bellard
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 | #ifndef LIST_H
25 | #define LIST_H
26 |
27 | #ifndef NULL
28 | #include
29 | #endif
30 |
31 | struct list_head {
32 | struct list_head *prev;
33 | struct list_head *next;
34 | };
35 |
36 | #define LIST_HEAD_INIT(el) { &(el), &(el) }
37 |
38 | /* return the pointer of type 'type *' containing 'el' as field 'member' */
39 | #define list_entry(el, type, member) \
40 | ((type *)((uint8_t *)(el) - offsetof(type, member)))
41 |
42 | static inline void init_list_head(struct list_head *head)
43 | {
44 | head->prev = head;
45 | head->next = head;
46 | }
47 |
48 | /* insert 'el' between 'prev' and 'next' */
49 | static inline void __list_add(struct list_head *el,
50 | struct list_head *prev, struct list_head *next)
51 | {
52 | prev->next = el;
53 | el->prev = prev;
54 | el->next = next;
55 | next->prev = el;
56 | }
57 |
58 | /* add 'el' at the head of the list 'head' (= after element head) */
59 | static inline void list_add(struct list_head *el, struct list_head *head)
60 | {
61 | __list_add(el, head, head->next);
62 | }
63 |
64 | /* add 'el' at the end of the list 'head' (= before element head) */
65 | static inline void list_add_tail(struct list_head *el, struct list_head *head)
66 | {
67 | __list_add(el, head->prev, head);
68 | }
69 |
70 | static inline void list_del(struct list_head *el)
71 | {
72 | struct list_head *prev, *next;
73 | prev = el->prev;
74 | next = el->next;
75 | prev->next = next;
76 | next->prev = prev;
77 | el->prev = NULL; /* fail safe */
78 | el->next = NULL; /* fail safe */
79 | }
80 |
81 | static inline int list_empty(struct list_head *el)
82 | {
83 | return el->next == el;
84 | }
85 |
86 | #define list_for_each(el, head) \
87 | for(el = (head)->next; el != (head); el = el->next)
88 |
89 | #define list_for_each_safe(el, el1, head) \
90 | for(el = (head)->next, el1 = el->next; el != (head); \
91 | el = el1, el1 = el->next)
92 |
93 | #define list_for_each_prev(el, head) \
94 | for(el = (head)->prev; el != (head); el = el->prev)
95 |
96 | #define list_for_each_prev_safe(el, el1, head) \
97 | for(el = (head)->prev, el1 = el->prev; el != (head); \
98 | el = el1, el1 = el->prev)
99 |
100 | #endif /* LIST_H */
101 |
--------------------------------------------------------------------------------
/storage/dybase/CHANGES:
--------------------------------------------------------------------------------
1 | \--- Release version 0.01 20.03.2003 -------------------------------------
2 | Initial release
3 |
4 | --- Release version 0.02 24.03.2003 -------------------------------------
5 | 1. Add Index.set method which replace object in case of existed key
6 | 2. Fix memory leak in Ruby API
7 | 3. Add setup.py module to Python API
8 | 4. Fix bug in PHP API
9 |
10 | --- Release version 0.03 27.03.2003 -------------------------------------
11 | 1. Clear OID attribute in Persistent.deallcoate method (to make it possible to call
12 | deallocate method multiple times)
13 | 2. Fix bugs in PHP API
14 | 3. Correct declaration of storage_insertinindex function in Ruby API
15 |
16 | --- Release version 0.04 04.04.2003 -------------------------------------
17 | 1. Add optional garbage collection
18 | 2. Fix bug in class descriptors caching which cause creation of class descriptor for each instance of the object.
19 |
20 | --- Release version 0.05 08.04.2003 -------------------------------------
21 | 1. Add multithreaded support at language API level
22 | 2. Add methods for objects shared and exclusive locking
23 |
24 | --- Release version 0.06 18.04.2003 -------------------------------------
25 | 1. Add Persistent.modify method
26 | 2. Add index iterator
27 | 3. Fix bug with recursive mutex locking in B-Tree
28 |
29 | --- Release version 0.07 22.04.2003 -------------------------------------
30 | 1. Implement more sophisticated iterators for index search
31 |
32 | --- Release version 0.08 25.04.2003 -------------------------------------
33 | 1. Add makefile for MinGW environment
34 | 2. Fix the problem with LONG_LONG in python API
35 |
36 | --- Release version 0.09 28.05.2003 -------------------------------------
37 | 1. Use delegators in Ruby API
38 |
39 | --- Release version 0.10 29.05.2003 -------------------------------------
40 | 1. Use delegators in Python API
41 |
42 | --- Release version 0.11 15.07.2003 -------------------------------------
43 | 1. Fix bug with maintaining modifiedList in DyBASE and Ruby APIs.
44 |
45 | --- Release version 0.12 23.07.2003 -------------------------------------
46 | 1. Fix bug in B-Tree index iterator (handling case of empty tree)
47 |
48 | --- Release version 0.13 19.11.2003 -------------------------------------
49 | 1. Add support of map type. In PHP Api all arrays are now stored as maps,
50 | so new version will be incompatible with databases created by previous versions.
51 |
52 | --- Release version 0.14 14.12.2003 -------------------------------------
53 | 1. Fix critical bug in object index relocation algorithm
54 | 2. Fix bugs in index iterator
55 | 3. Beta version of Rebol API
56 |
57 | --- Release version 0.15 19.12.2003 -------------------------------------
58 | 1. Optimized version of Rebol API
59 |
60 | --- Release version 0.16 21.12.2003 -------------------------------------
61 | 1. New version of Rebol API
62 | 2. Fix bug in PHP API
63 | 3. Update comparison results
64 |
65 | --- Release version 0.17 21.12.2003 -------------------------------------
66 | 1. New implementation of object cache in Rebol API
67 | 2. Fix bug in storage close method in Rebol API
68 |
69 | --- Release version 0.18 28.12.2003 -------------------------------------
70 | 1. New implementation of fetching objects in Rebol API. Now it is not necessary to
71 | specify prototype object.
72 |
73 | --- Release version 0.19 26.03.2004 -------------------------------------
74 | 1. Fix bug in testlink.php
75 | 2. Change rule of creating object delegators in Python API to me able to automatically
76 | handle object modification in all cases.
77 | 3. Fix bug in B-Tree search method with open boundaries and remove from empty tree.
--------------------------------------------------------------------------------
/storage/dybase/src/pagepool.h:
--------------------------------------------------------------------------------
1 | //-< PAGEPOOL.H >----------------------------------------------------*--------*
2 | // GigaBASE Version 1.0 (c) 1999 GARRET * ? *
3 | // (Post Relational Database Management System) * /\| *
4 | // * / \ *
5 | // Created: 6-Feb-99 K.A. Knizhnik * / [] \ *
6 | // Last update: 6-Feb-99 K.A. Knizhnik * GARRET *
7 | //-------------------------------------------------------------------*--------*
8 | // Page pool interface
9 | //-------------------------------------------------------------------*--------*
10 |
11 | #include "file.h"
12 |
13 | class dbPageLruList {
14 | public:
15 | int next;
16 | int prev;
17 | };
18 |
19 | class dbPageHeader : public dbPageLruList {
20 | public:
21 | int collisionChain;
22 | int accessCount;
23 | offs_t offs;
24 | int writeQueueIndex;
25 | int state;
26 | enum PageState { // flag in accessCount field
27 | psDirty = 0x01, // page has been modified
28 | psRaw = 0x02, // page is loaded from the disk
29 | psWait = 0x04 // other thread(s) wait load operation completion
30 | };
31 | };
32 |
33 | class dbGetTie;
34 | class dbPutTie;
35 | class dbDatabase;
36 |
37 | class dbPagePool {
38 | friend class dbGetTie;
39 | friend class dbPutTie;
40 | friend class dbDatabase;
41 |
42 | protected:
43 | dbPageHeader *pages;
44 | int * hashTable;
45 | int freePages;
46 | int nPages;
47 |
48 | dbFile * file;
49 | dbDatabase *db;
50 | length_t hashBits;
51 | length_t poolSize;
52 | byte * buffer;
53 | length_t bufferSize;
54 | offs_t fileSize;
55 |
56 | int flushing;
57 |
58 | enum {
59 | initialWobArraySize = 8,
60 | minPoolSize = 256,
61 | minHashSize = 16 * 1024,
62 | maxUnusedMemory = 64 * 1024 * 1024
63 | };
64 |
65 | length_t nDirtyPages;
66 | dbPageHeader **dirtyPages;
67 |
68 | byte *find(offs_t addr, int state);
69 |
70 | public:
71 | byte *get(offs_t addr) { return find(addr, 0); }
72 | byte *put(offs_t addr) { return find(addr, dbPageHeader::psDirty); }
73 | void put(offs_t addr, byte *obj, length_t size);
74 | void copy(offs_t dst, offs_t src, length_t size);
75 | void unfix(void *ptr);
76 | void unfixLIFO(void *ptr);
77 | void fix(void *ptr);
78 | void modify(void *ptr);
79 | bool open(dbFile *file, offs_t fileSize);
80 | void close();
81 | void flush();
82 |
83 | bool destructed() { return pages == NULL; }
84 |
85 | dbPagePool(dbDatabase *dbs, length_t size) : db(dbs), poolSize(size) {}
86 | };
87 |
88 | class dbGetTie {
89 | friend class dbDatabase;
90 | friend class dbAnyCursor;
91 | dbPagePool *pool;
92 | byte * obj;
93 | byte * page;
94 |
95 | void set(dbPagePool &pool, offs_t pos);
96 | void reset();
97 |
98 | public:
99 | byte *get() { return obj; }
100 |
101 | dbGetTie() { obj = NULL; }
102 | ~dbGetTie() { reset(); }
103 | };
104 |
105 | class dbPutTie {
106 | friend class dbDatabase;
107 | friend class dbBtree;
108 |
109 | dbPagePool *pool;
110 | byte * obj;
111 | byte * page;
112 | length_t size;
113 | offs_t pos;
114 | oid_t oid;
115 |
116 | void set(dbPagePool &pool, oid_t oid, offs_t pos, length_t size);
117 | void reset();
118 | void unset() {
119 | if (obj != NULL) {
120 | if (page == NULL) { delete[] obj; }
121 | obj = NULL;
122 | }
123 | }
124 |
125 | public:
126 | byte *get() { return obj; }
127 |
128 | dbPutTie() {
129 | obj = NULL;
130 | oid = 0;
131 | }
132 | ~dbPutTie() { reset(); }
133 | };
134 |
--------------------------------------------------------------------------------
/storage/doc/architecture.md:
--------------------------------------------------------------------------------
1 | # Architecture of Storage Module
2 |
3 | The module uses modified [DyBase Engine of Konstantin Knizhnik](http://www.garret.ru/dybase.html) and
4 | minimal changes in QuickJS core to support persistence in JS.
5 |
6 | With enabled CONFIG_STORAGE flag existing ```struct JSObject``` gets additional pointer field:
7 |
8 | ```C
9 | struct JSObject {
10 | ...
11 | JSPersistentBlock* persistent;
12 | };
13 | ```
14 |
15 | Where JSPersistentBlock defines storage wireing fields. This makes any JS object to be persistable. For now only pure Objects and Arrays are persistable.
16 |
17 |
18 | Each persistent JS object and array can be in one of four states:
19 |
20 | * ```JS_NOT_PERSISTENT``` - not persistent at the moment
21 | * ```JS_PERSISTENT_DORMANT``` - object is persistent but is "dormant", it holds just a reference - item ID in terms of DyBase (dybase_oid_t). Object in this state has no properties or elements loaded into it - it is a {proxy-ref}erence.
22 | * ```JS_PERSISTENT_LOADED``` - the object has its properties and data loaded from DB;
23 | * ```JS_PERSISTENT_MODIFIED``` - the object is loaded from DB and is modified by script - ready to be commited to DB.
24 |
25 | ## Data life cycle – how persistent mechanism works
26 |
27 | Script runtime provides root object when we open existing storage:
28 |
29 | ```JavaScript
30 | var storage = Storage.open("path/to/data/file.db");
31 | var root = storage.root; // root data object
32 | ```
33 |
34 | Main idea is that the root object will be loaded in half-baked way – all sub-collections in that object will have just persistent proxies instead – things that represent references to corresponding data items in DB:
35 |
36 | 
37 |
38 | So immediately after loading root object will look as:
39 |
40 | ```
41 | storage.root -> {
42 | version: 1,
43 | parent: /*proxy-ref*/
44 | children: /*proxy-ref*/
45 | }
46 | ```
47 |
48 | Those special proxy-references are internal entities – not discoverable by the script.
49 |
50 | Instead, when we will need to access those sub-objects, script runtime will fetch them from DB transparently for script code. So when we will need to get some property of sub-object like this:
51 |
52 | ```JavaScript
53 | console.log(root.parent.name);
54 | ```
55 |
56 | the runtime will fetch needed object from the DB into VM’s heap (memory) and the root will look like this:
57 |
58 | ```
59 | storage.root -> {
60 | version: 1,
61 | parent: { name: "John the Magnificent", nickname: "Smith" },
62 | children: /*array-proxy-ref - not accessed yet*/
63 | }
64 | ```
65 |
66 | Therefore to get data from the DB we will just need to access elements of collections in DB by standard script means – using obj.prop property accessor or array[index] accessors.
67 |
68 | But what will happen with large DB and our code that may walk through all collections inside it? Will whole database be loaded into the heap as a result of visiting all persistent entities?
69 |
70 | The answer is “no”. At some point, when runtime will detect that heap is full, garbage collection will be triggered and all persistent entities will be replaced by their proxies. This will free heap from directly unreferenced persistent data. If any of such data contains changes they will be committed (saved) to the database before their removal from the heap.
71 |
72 | Therefore data commits (saving data to physical storage) are managed by script runtime automatically: at GC time and when storage gets closed. Script cannot prevent GC to happen nor it cannot force actual GC so data will be auto-commited. But if needed (e.g. after critical data changes), we can call synchronous ```storage.commit()``` method to force changed data to be saved at particular moment of time.
73 |
74 | Such mechanism allows script to handle potentially large data sets: maximum number of persistent entities is 2^32 and each persistent item can be a string or a byte array (a.k.a. blob, ArrayBuffer) of size 2^32 bytes.
75 |
76 |
--------------------------------------------------------------------------------
/release.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # Release the QuickJS source code
3 |
4 | set -e
5 |
6 | version=`cat VERSION`
7 |
8 | if [ "$1" = "-h" ] ; then
9 | echo "release.sh [release_list]"
10 | echo ""
11 | echo "release_list: extras binary win_binary quickjs"
12 |
13 | exit 1
14 | fi
15 |
16 | release_list="extras binary win_binary quickjs"
17 |
18 | if [ "$1" != "" ] ; then
19 | release_list="$1"
20 | fi
21 |
22 | #################################################"
23 | # extras
24 |
25 | if echo $release_list | grep -w -q extras ; then
26 |
27 | d="quickjs-${version}"
28 | name="quickjs-extras-${version}"
29 | outdir="/tmp/${d}"
30 |
31 | rm -rf $outdir
32 | mkdir -p $outdir $outdir/unicode $outdir/tests
33 |
34 | cp unicode/* $outdir/unicode
35 | cp -a tests/bench-v8 $outdir/tests
36 |
37 | ( cd /tmp && tar Jcvf /tmp/${name}.tar.xz ${d} )
38 |
39 | fi
40 |
41 | #################################################"
42 | # Windows binary release
43 |
44 | if echo $release_list | grep -w -q win_binary ; then
45 |
46 | # win64
47 |
48 | dlldir=/usr/x86_64-w64-mingw32/sys-root/mingw/bin
49 | cross_prefix="x86_64-w64-mingw32-"
50 | d="quickjs-win-x86_64-${version}"
51 | outdir="/tmp/${d}"
52 |
53 | rm -rf $outdir
54 | mkdir -p $outdir
55 |
56 | make CONFIG_WIN32=y qjs.exe
57 | cp qjs.exe $outdir
58 | ${cross_prefix}strip $outdir/qjs.exe
59 | cp $dlldir/libwinpthread-1.dll $outdir
60 |
61 | ( cd /tmp/$d && rm -f ../${d}.zip && zip -r ../${d}.zip . )
62 |
63 | make CONFIG_WIN32=y clean
64 |
65 | # win32
66 |
67 | dlldir=/usr/i686-w64-mingw32/sys-root/mingw/bin
68 | cross_prefix="i686-w64-mingw32-"
69 | d="quickjs-win-i686-${version}"
70 | outdir="/tmp/${d}"
71 |
72 | rm -rf $outdir
73 | mkdir -p $outdir
74 |
75 | make clean
76 | make CONFIG_WIN32=y clean
77 |
78 | make CONFIG_WIN32=y CONFIG_M32=y qjs.exe
79 | cp qjs.exe $outdir
80 | ${cross_prefix}strip $outdir/qjs.exe
81 | cp $dlldir/libwinpthread-1.dll $outdir
82 |
83 | ( cd /tmp/$d && rm -f ../${d}.zip && zip -r ../${d}.zip . )
84 |
85 | fi
86 |
87 | #################################################"
88 | # Linux binary release
89 |
90 | if echo $release_list | grep -w -q binary ; then
91 |
92 | make clean
93 | make CONFIG_WIN32=y clean
94 | make -j4 qjs run-test262
95 | make -j4 CONFIG_M32=y qjs32 run-test262-32
96 | strip qjs run-test262 qjs32 run-test262-32
97 |
98 | d="quickjs-linux-x86_64-${version}"
99 | outdir="/tmp/${d}"
100 |
101 | rm -rf $outdir
102 | mkdir -p $outdir
103 |
104 | cp qjs run-test262 $outdir
105 |
106 | ( cd /tmp/$d && rm -f ../${d}.zip && zip -r ../${d}.zip . )
107 |
108 | d="quickjs-linux-i686-${version}"
109 | outdir="/tmp/${d}"
110 |
111 | rm -rf $outdir
112 | mkdir -p $outdir
113 |
114 | cp qjs32 $outdir/qjs
115 | cp run-test262-32 $outdir/run-test262
116 |
117 | ( cd /tmp/$d && rm -f ../${d}.zip && zip -r ../${d}.zip . )
118 |
119 | fi
120 |
121 | #################################################"
122 | # quickjs
123 |
124 | if echo $release_list | grep -w -q quickjs ; then
125 |
126 | make build_doc
127 |
128 | d="quickjs-${version}"
129 | outdir="/tmp/${d}"
130 |
131 | rm -rf $outdir
132 | mkdir -p $outdir $outdir/doc $outdir/tests $outdir/examples
133 |
134 | cp Makefile VERSION TODO Changelog readme.txt LICENSE \
135 | release.sh unicode_download.sh \
136 | qjs.c qjsc.c qjscalc.js repl.js \
137 | quickjs.c quickjs.h quickjs-atom.h \
138 | quickjs-libc.c quickjs-libc.h quickjs-opcode.h \
139 | cutils.c cutils.h list.h \
140 | libregexp.c libregexp.h libregexp-opcode.h \
141 | libunicode.c libunicode.h libunicode-table.h \
142 | libbf.c libbf.h \
143 | unicode_gen.c unicode_gen_def.h \
144 | run-test262.c test262o.conf test262.conf \
145 | test262o_errors.txt test262_errors.txt \
146 | $outdir
147 |
148 | cp tests/*.js tests/*.patch tests/bjson.c $outdir/tests
149 |
150 | cp examples/*.js examples/*.c $outdir/examples
151 |
152 | cp doc/quickjs.texi doc/quickjs.pdf doc/quickjs.html \
153 | doc/jsbignum.texi doc/jsbignum.html doc/jsbignum.pdf \
154 | $outdir/doc
155 |
156 | ( cd /tmp && tar Jcvf /tmp/${d}.tar.xz ${d} )
157 |
158 | fi
159 |
--------------------------------------------------------------------------------
/quickjs-bjson.c:
--------------------------------------------------------------------------------
1 | /*
2 | * QuickJS: binary JSON module (test only)
3 | *
4 | * Copyright (c) 2017-2019 Fabrice Bellard
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 | #include "quickjs-libc.h"
25 | #include "cutils.h"
26 |
27 | static JSValue js_bjson_read(JSContext *ctx, JSValueConst this_val,
28 | int argc, JSValueConst *argv)
29 | {
30 | uint8_t *buf;
31 | uint64_t pos = 0, len = 0;
32 | JSValue obj;
33 | JSValue cb = JS_UNINITIALIZED;
34 | size_t size;
35 | int flags;
36 |
37 | if (argc > 1) {
38 | if (JS_IsFunction(ctx, argv[1]))
39 | cb = argv[1];
40 | else if (JS_ToIndex(ctx, &pos, argv[1]))
41 | return JS_EXCEPTION;
42 | if (argc > 2) {
43 | if (JS_ToIndex(ctx, &len, argv[2]))
44 | return JS_EXCEPTION;
45 | }
46 | }
47 | buf = JS_GetArrayBuffer(ctx, &size, argv[0]);
48 | if (!buf)
49 | return JS_EXCEPTION;
50 |
51 | if (len == 0)
52 | len = size - pos;
53 |
54 | if (pos + len > size)
55 | return JS_ThrowRangeError(ctx, "array buffer overflow");
56 | flags = 0;
57 | if (argc > 3 && JS_ToBool(ctx, argv[3]))
58 | flags |= JS_READ_OBJ_REFERENCE;
59 |
60 | if (cb != JS_UNINITIALIZED) {
61 | cb = JS_DupValue(ctx,cb);
62 | size_t rest = 0;
63 | uint8_t *sbuf = buf;
64 | uint64_t slen = len;
65 | uint8_t *send = buf + len;
66 | do {
67 | obj = JS_ReadObject2(ctx, sbuf, slen, flags, &rest);
68 | sbuf = send - rest;
69 | slen = rest;
70 | JSValue rv = JS_Call(ctx, cb, JS_UNDEFINED, 1, &obj);
71 | JS_FreeValue(ctx, obj);
72 | if (JS_IsException(rv)) {
73 | JS_FreeValue(ctx, cb);
74 | return rv;
75 | }
76 | if (rv == JS_FALSE)
77 | break;
78 | } while (rest);
79 | JS_FreeValue(ctx, cb);
80 | return JS_NewInt64(ctx, rest);
81 | }
82 | else
83 | obj = JS_ReadObject(ctx, buf + pos, len, flags);
84 | return obj;
85 | }
86 |
87 | static JSValue js_bjson_write(JSContext *ctx, JSValueConst this_val,
88 | int argc, JSValueConst *argv)
89 | {
90 | size_t len;
91 | uint8_t *buf;
92 | JSValue array;
93 | int flags;
94 |
95 | flags = 0;
96 | if (JS_ToBool(ctx, argv[1]))
97 | flags |= JS_WRITE_OBJ_REFERENCE;
98 | buf = JS_WriteObject(ctx, &len, argv[0], flags);
99 | if (!buf)
100 | return JS_EXCEPTION;
101 | array = JS_NewArrayBufferCopy(ctx, buf, len);
102 | js_free(ctx, buf);
103 | return array;
104 | }
105 |
106 | static const JSCFunctionListEntry js_bjson_funcs[] = {
107 | JS_CFUNC_DEF("read", 4, js_bjson_read),
108 | JS_CFUNC_DEF("write", 2, js_bjson_write),
109 | };
110 |
111 | static int js_bjson_init(JSContext *ctx, JSModuleDef *m)
112 | {
113 | return JS_SetModuleExportList(ctx, m, js_bjson_funcs,
114 | countof(js_bjson_funcs));
115 | }
116 |
117 | JSModuleDef *js_init_module_bjson(JSContext *ctx, const char *module_name)
118 | {
119 | JSModuleDef *m;
120 | m = JS_NewCModule(ctx, module_name, js_bjson_init);
121 | if (!m) return NULL;
122 | JS_AddModuleExportList(ctx, m, js_bjson_funcs, countof(js_bjson_funcs));
123 | return m;
124 | }
125 |
--------------------------------------------------------------------------------
/tests/storage/test-all.js:
--------------------------------------------------------------------------------
1 |
2 |
3 | import * as Storage from "storage";
4 | import * as std from "std";
5 | import * as os from "os";
6 |
7 | function assert(actual, expected, message) {
8 | if (arguments.length == 1)
9 | expected = true;
10 |
11 | if (actual === expected)
12 | return;
13 |
14 | if (actual !== null && expected !== null && typeof actual == 'object' && typeof expected == 'object'
15 | && actual.toString() === expected.toString()) return;
16 |
17 | throw Error("assertion failed: got |" + actual + "|" +
18 | ", expected |" + expected + "|" +
19 | (message ? " (" + message + ")" : ""));
20 | }
21 |
22 | function isObject(object) {
23 | return object != null && typeof object === 'object';
24 | }
25 |
26 | function deepEqual(object1, object2) {
27 | const keys1 = Object.keys(object1);
28 | const keys2 = Object.keys(object2);
29 |
30 | if (keys1.length !== keys2.length)
31 | return false;
32 |
33 | for (const key of keys1) {
34 | const val1 = object1[key];
35 | const val2 = object2[key];
36 | const areObjects = isObject(val1) && isObject(val2);
37 | if (areObjects && !deepEqual(val1, val2)
38 | || !areObjects && val1 !== val2)
39 | return false;
40 | }
41 |
42 | return true;
43 | }
44 |
45 | const path = __DIR__ + "test.db";
46 | os.remove(path);
47 |
48 | function init()
49 | {
50 | let storage = Storage.open(path);
51 |
52 | assert(storage.root, null, "fresh storage has null root");
53 |
54 | let index_int = storage.createIndex("integer"); index_int.set(1,{a:1}); index_int.set(2,{b:2}); index_int.set(3,{c:3});
55 | let index_date = storage.createIndex("date");
56 | let index_long = storage.createIndex("long");
57 | let index_float = storage.createIndex("float");
58 | let index_string = storage.createIndex("string"); index_string.set("a",{a:1}); index_string.set("b",{b:2}); index_string.set("c",{c:3});
59 |
60 | storage.root = {
61 | //basic types
62 | types:
63 | {
64 | tbool: true,
65 | tinteger: 42,
66 | tlong: 420n,
67 | tfloat: 3.1415926,
68 | tstring: "forty two",
69 | tarray: [1,2,3],
70 | tobject: { a:1, b:2, c:3},
71 | tdate: new Date(2021, 2, 28)
72 | },
73 | //indexes
74 | indexes: {
75 | iint: index_int,
76 | idate: index_date,
77 | ilong : index_long,
78 | ifloat: index_float,
79 | istring : index_string
80 | }
81 | };
82 | storage.close();
83 | }
84 |
85 | function test()
86 | {
87 | let storage = Storage.open(path);
88 |
89 | assert(!!storage);
90 |
91 | let dbTypes = storage.root.types;
92 |
93 | const types = {
94 | tbool: true,
95 | tinteger: 42,
96 | tlong: 420n,
97 | tfloat: 3.1415926,
98 | tstring: "forty two",
99 | tarray: [1,2,3],
100 | tobject: { a:1, b:2, c:3},
101 | tdate: new Date(2021, 2, 28)
102 | };
103 |
104 | assert(deepEqual(dbTypes,types));
105 |
106 | let indexes = storage.root.indexes;
107 |
108 | assert(indexes.iint.length,3);
109 |
110 | assert(deepEqual(indexes.iint.get(1),{a:1}));
111 | assert(deepEqual(indexes.iint.get(2),{b:2}));
112 | assert(deepEqual(indexes.iint.get(3),{c:3}));
113 |
114 | assert(indexes.istring.length,3);
115 |
116 | assert(deepEqual(indexes.istring.get("a"),{a:1}));
117 | assert(deepEqual(indexes.istring.get("b"),{b:2}));
118 | assert(deepEqual(indexes.istring.get("c"),{c:3}));
119 |
120 | var r = [];
121 | for(let obj of indexes.istring)
122 | r.push(obj);
123 |
124 | assert(deepEqual(r,[{a:1},{b:2},{c:3}]));
125 |
126 | r = [];
127 | for(let obj of indexes.istring.select("b","c")) // range inclusive
128 | r.push(obj);
129 | assert(deepEqual(r,[{b:2},{c:3}]));
130 |
131 | r = [];
132 | for(let obj of indexes.istring.select("b",null)) // range, open end
133 | r.push(obj);
134 | assert(deepEqual(r,[{b:2},{c:3}]));
135 |
136 | r = [];
137 | for(let obj of indexes.istring.select(null,"b")) // range, open start
138 | r.push(obj);
139 | assert(deepEqual(r,[{a:1},{b:2}]));
140 |
141 | storage.close();
142 |
143 | print("PASSED");
144 | }
145 |
146 | init();
147 | test();
--------------------------------------------------------------------------------
/premake5.lua:
--------------------------------------------------------------------------------
1 |
2 | (function()
3 | -- generate "quickjs-version.h" using VERSION file
4 | local file = io.open("VERSION", "r")
5 | local vers = file:read()
6 | file:close()
7 | vars = vers:gsub("%s+", "")
8 | file = io.open("quickjs-version.h", "w+")
9 | file:write("#define QUICKJS_VERSION \"" .. vers .. "\"")
10 | file:close()
11 | end)()
12 |
13 |
14 | newoption {
15 | trigger = "jsx",
16 | description = "Will add JSX support"
17 | }
18 |
19 | newoption {
20 | trigger = "storage",
21 | description = "Will add persistent storage support"
22 | }
23 |
24 | workspace "quickjs"
25 | -- Premake output folder
26 | location(path.join(".build", _ACTION))
27 |
28 | defines {
29 | "JS_STRICT_NAN_BOXING", -- this option enables x64 build on Windows/MSVC
30 | "CONFIG_BIGNUM"
31 | }
32 |
33 | if _OPTIONS["jsx"] then
34 | defines { "CONFIG_JSX" } -- native JSX support - enables JSX literals
35 | end
36 |
37 | if _OPTIONS["storage"] then
38 | defines { "CONFIG_STORAGE" } -- persistent storage support
39 | end
40 |
41 |
42 | platforms { "x86", "x64", "arm32", "arm64" }
43 |
44 | -- Configuration settings
45 | configurations { "Debug", "Release" }
46 |
47 | filter "platforms:x86"
48 | architecture "x86"
49 | filter "platforms:x64"
50 | architecture "x86_64"
51 | filter "platforms:arm32"
52 | architecture "ARM"
53 | filter "platforms:arm64"
54 | architecture "ARM64"
55 |
56 | filter "system:windows"
57 | removeplatforms { "arm32" }
58 |
59 | -- Debug configuration
60 | filter { "configurations:Debug" }
61 | defines { "DEBUG" }
62 | symbols "On"
63 | optimize "Off"
64 |
65 | -- Release configuration
66 | filter { "configurations:Release" }
67 | defines { "NDEBUG" }
68 | optimize "Speed"
69 | inlining "Auto"
70 |
71 | -- Should apply only for Visual C++
72 | filter { "language:not C#" and "toolset:msc" }
73 | defines { "_CRT_SECURE_NO_WARNINGS" }
74 | buildoptions { "/std:c++latest" }
75 | systemversion "latest"
76 |
77 | filter { }
78 | targetdir ".bin/%{cfg.buildcfg}/%{cfg.platform }"
79 | exceptionhandling "Off"
80 | rtti "Off"
81 | --vectorextensions "AVX2"
82 |
83 | -----------------------------------------------------------------------------------------------------------------------
84 |
85 | project "quickjs"
86 | language "C"
87 | kind "StaticLib"
88 | files {
89 | "cutils.h",
90 | "cutils.c",
91 | "libregexp.c",
92 | "libunicode.c",
93 | "quickjs.c",
94 | "quickjs-libc.c",
95 | "libbf.c",
96 | "libregexp.h",
97 | "libregexp-opcode.h",
98 | "libunicode.h",
99 | "libunicode-table.h",
100 | "list.h",
101 | "quickjs.h",
102 | "quickjs-atom.h",
103 | "quickjs-libc.h",
104 | "quickjs-opcode.h",
105 | "quickjs-jsx.h",
106 | }
107 |
108 |
109 | if _OPTIONS["storage"] then
110 | exceptionhandling "On"
111 | files {
112 | "storage/quickjs-storage.c",
113 | "storage/quickjs-storage.h",
114 | "storage/dybase/src/*.cpp",
115 | "storage/dybase/src/*.h",
116 | "storage/dybase/include/*.h"
117 | }
118 | includedirs {
119 | "storage/dybase/include"
120 | }
121 | end
122 |
123 | -----------------------------------------------------------------------------------------------------------------------
124 |
125 | project "qjsc"
126 | language "C"
127 | kind "ConsoleApp"
128 | links { "quickjs" }
129 | files {
130 | "qjsc.c"
131 | }
132 | filter { "action:gmake*", "toolset:gcc" }
133 | links { "dl", "pthread" }
134 |
135 | -----------------------------------------------------------------------------------------------------------------------
136 |
137 | project "qjs"
138 | language "C"
139 | kind "ConsoleApp"
140 | links { "quickjs" }
141 | dependson { "qjsc" }
142 | files {
143 | "qjs.c",
144 | "repl.js",
145 | "repl.c",
146 | "qjscalc.js",
147 | "qjscalc.c"
148 | }
149 | filter { "action:gmake*", "toolset:gcc" }
150 | links { "dl", "pthread" }
151 |
152 | -- Compile repl.js and save bytecode into repl.c
153 | prebuildcommands { "\"%{cfg.buildtarget.directory}/qjsc.exe\" -c -o \"../../repl.c\" -m \"../../repl.js\"" }
154 | prebuildcommands { "\"%{cfg.buildtarget.directory}/qjsc.exe\" -c -o \"../../qjscalc.c\" -m \"../../qjscalc.js\"" }
155 |
--------------------------------------------------------------------------------
/libunicode.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Unicode utilities
3 | *
4 | * Copyright (c) 2017-2018 Fabrice Bellard
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 | #ifndef LIBUNICODE_H
25 | #define LIBUNICODE_H
26 |
27 | #include
28 |
29 | #define LRE_BOOL int /* for documentation purposes */
30 |
31 | /* define it to include all the unicode tables (40KB larger) */
32 | #define CONFIG_ALL_UNICODE
33 |
34 | #define LRE_CC_RES_LEN_MAX 3
35 |
36 | typedef enum {
37 | UNICODE_NFC,
38 | UNICODE_NFD,
39 | UNICODE_NFKC,
40 | UNICODE_NFKD,
41 | } UnicodeNormalizationEnum;
42 |
43 | int lre_case_conv(uint32_t *res, uint32_t c, int conv_type);
44 | LRE_BOOL lre_is_cased(uint32_t c);
45 | LRE_BOOL lre_is_case_ignorable(uint32_t c);
46 |
47 | /* char ranges */
48 |
49 | typedef struct {
50 | int len; /* in points, always even */
51 | int size;
52 | uint32_t *points; /* points sorted by increasing value */
53 | void *mem_opaque;
54 | void *(*realloc_func)(void *opaque, void *ptr, size_t size);
55 | } CharRange;
56 |
57 | typedef enum {
58 | CR_OP_UNION,
59 | CR_OP_INTER,
60 | CR_OP_XOR,
61 | } CharRangeOpEnum;
62 |
63 | void cr_init(CharRange *cr, void *mem_opaque, void *(*realloc_func)(void *opaque, void *ptr, size_t size));
64 | void cr_free(CharRange *cr);
65 | int cr_realloc(CharRange *cr, int size);
66 | int cr_copy(CharRange *cr, const CharRange *cr1);
67 |
68 | static inline int cr_add_point(CharRange *cr, uint32_t v)
69 | {
70 | if (cr->len >= cr->size) {
71 | if (cr_realloc(cr, cr->len + 1))
72 | return -1;
73 | }
74 | cr->points[cr->len++] = v;
75 | return 0;
76 | }
77 |
78 | static inline int cr_add_interval(CharRange *cr, uint32_t c1, uint32_t c2)
79 | {
80 | if ((cr->len + 2) > cr->size) {
81 | if (cr_realloc(cr, cr->len + 2))
82 | return -1;
83 | }
84 | cr->points[cr->len++] = c1;
85 | cr->points[cr->len++] = c2;
86 | return 0;
87 | }
88 |
89 | int cr_union1(CharRange *cr, const uint32_t *b_pt, int b_len);
90 |
91 | static inline int cr_union_interval(CharRange *cr, uint32_t c1, uint32_t c2)
92 | {
93 | uint32_t b_pt[2];
94 | b_pt[0] = c1;
95 | b_pt[1] = c2 + 1;
96 | return cr_union1(cr, b_pt, 2);
97 | }
98 |
99 | int cr_op(CharRange *cr, const uint32_t *a_pt, int a_len,
100 | const uint32_t *b_pt, int b_len, int op);
101 |
102 | int cr_invert(CharRange *cr);
103 |
104 | #ifdef CONFIG_ALL_UNICODE
105 |
106 | LRE_BOOL lre_is_id_start(uint32_t c);
107 | LRE_BOOL lre_is_id_continue(uint32_t c);
108 |
109 | int unicode_normalize(uint32_t **pdst, const uint32_t *src, int src_len,
110 | UnicodeNormalizationEnum n_type,
111 | void *opaque, void *(*realloc_func)(void *opaque, void *ptr, size_t size));
112 |
113 | /* Unicode character range functions */
114 |
115 | int unicode_script(CharRange *cr,
116 | const char *script_name, LRE_BOOL is_ext);
117 | int unicode_general_category(CharRange *cr, const char *gc_name);
118 | int unicode_prop(CharRange *cr, const char *prop_name);
119 |
120 | #endif /* CONFIG_ALL_UNICODE */
121 |
122 | #undef LRE_BOOL
123 |
124 | #endif /* LIBUNICODE_H */
125 |
--------------------------------------------------------------------------------
/storage/dybase/src/stdtp.h:
--------------------------------------------------------------------------------
1 | //-< STDTP.H >-------------------------------------------------------*--------*
2 | // GigaBASE Version 1.0 (c) 1999 GARRET * ? *
3 | // (Post Relational Database Management System) * /\| *
4 | // * / \ *
5 | // Created: 20-Nov-98 K.A. Knizhnik * / [] \ *
6 | // Last update: 10-Dec-98 K.A. Knizhnik * GARRET *
7 | //-------------------------------------------------------------------*--------*
8 | // Standart type and macro definitions
9 | //-------------------------------------------------------------------*--------*
10 |
11 | #ifndef __STDTP_H__
12 | #define __STDTP_H__
13 |
14 | #if defined(_WIN32)
15 | #include
16 | #ifdef _MSC_VER
17 | #pragma warning(disable : 4800 4355 4146 4251)
18 | #pragma warning(disable : 4458 4456 4457 4459) // warning C4458 : declaration of
19 | // 'name' hides class member
20 | #endif
21 | #else
22 | #ifdef _AIX
23 | #define INT8_IS_DEFINED
24 | #endif
25 | #ifndef NO_PTHREADS
26 | #ifndef _REENTRANT
27 | #define _REENTRANT
28 | #endif
29 | #endif
30 | #endif
31 |
32 | #if defined(__VACPP_MULTI__) // IBM compiler produce a lot of stupid warnings
33 | #pragma report(disable, "CPPC1608")
34 | #pragma report(disable, "CPPC1281")
35 | #endif /* __VACPP_MULTI__ */
36 |
37 | #ifdef _WINCE
38 | #include
39 | #include
40 | #include
41 | #include
42 | #include
43 | #include
44 | #include "wince.h"
45 |
46 | #else
47 |
48 | #include
49 | #include
50 | #include
51 | #include
52 | #include
53 | #include
54 | #include
55 | #include
56 |
57 | #endif
58 |
59 | #if !defined(_WIN32)
60 | #define __cdecl
61 | #endif
62 |
63 | #define DEBUG_NONE 0
64 | #define DEBUG_CHECK 1
65 | #define DEBUG_TRACE 2
66 |
67 | #if GIGABASE_DEBUG == DEBUG_TRACE
68 | #define TRACE_MSG(x) dbTrace x
69 | #else
70 | #define TRACE_MSG(x)
71 | #endif
72 |
73 | extern void dbTrace(char *message, ...);
74 |
75 | // Align value 'x' to boundary 'b' which should be power of 2
76 | #define DOALIGN(x, b) (((x) + (b)-1) & ~((b)-1))
77 |
78 | typedef signed char db_int1;
79 | typedef unsigned char db_nat1;
80 |
81 | typedef signed short db_int2;
82 | typedef unsigned short db_nat2;
83 |
84 | typedef signed int db_int4;
85 | typedef unsigned int db_nat4;
86 |
87 | typedef float db_real4;
88 | typedef double db_real8;
89 |
90 | typedef unsigned char byte;
91 |
92 | #if defined(_WIN32) && !defined(__MINGW32__)
93 | typedef unsigned __int64 db_nat8;
94 | typedef __int64 db_int8;
95 | #if defined(__IBMCPP__)
96 | #define INT8_FORMAT "%lld"
97 | #define T_INT8_FORMAT _T("%lld")
98 | #else
99 | #define INT8_FORMAT "%I64d"
100 | #define T_INT8_FORMAT _T("%I64d")
101 | #endif
102 | #define CONST64(c) c
103 | #else
104 | #if SIZEOF_LONG == 8
105 | typedef unsigned long db_nat8;
106 | typedef signed long db_int8;
107 | #define INT8_FORMAT "%ld"
108 | #define T_INT8_FORMAT _T("%ld")
109 | #define CONST64(c) c##L
110 | #else
111 | typedef unsigned long long db_nat8;
112 | typedef signed long long db_int8;
113 | #define INT8_FORMAT "%lld"
114 | #define T_INT8_FORMAT _T("%lld")
115 | #define CONST64(c) c##LL
116 | #endif
117 | #endif
118 |
119 | #if !defined(bool) && (defined(__SUNPRO_CC) || defined(__IBMCPP__))
120 | #define bool char
121 | #define true(1)
122 | #define false(0)
123 | #endif
124 |
125 | #define nat8_low_part(x) ((db_nat4)(x))
126 | #define int8_low_part(x) ((db_int4)(x))
127 | #if defined(_MSC_VER) // bug in MVC 6.0
128 | #define nat8_high_part(x) (sizeof(x) < 8 ? 0 : ((db_nat4)((db_nat8)(x) >> 32)))
129 | #define int8_high_part(x) (sizeof(x) < 8 ? 0 : ((db_int4)((db_int8)(x) >> 32)))
130 | #else
131 | #define nat8_high_part(x) ((db_nat4)((db_nat8)(x) >> 32))
132 | #define int8_high_part(x) ((db_int4)((db_int8)(x) >> 32))
133 | #endif
134 |
135 | #define cons_nat8(hi, lo) ((((db_nat8)(hi)) << 32) | (db_nat4)(lo))
136 | #define cons_int8(hi, lo) ((((db_int8)(hi)) << 32) | (db_nat4)(lo))
137 |
138 | #define MAX_NAT8 db_nat8(-1)
139 |
140 | #define itemsof(array) (sizeof(array) / sizeof *(array))
141 |
142 | #endif
143 |
--------------------------------------------------------------------------------
/Changelog:
--------------------------------------------------------------------------------
1 | 2021-03-27:
2 |
3 | - faster Array.prototype.push and Array.prototype.unshift
4 | - added JS_UpdateStackTop()
5 | - fixed Windows console
6 | - misc bug fixes
7 |
8 | 2020-11-08:
9 |
10 | - improved function parameter initializers
11 | - added std.setenv(), std.unsetenv() and std.getenviron()
12 | - added JS_EvalThis()
13 | - misc bug fixes
14 |
15 | 2020-09-06:
16 |
17 | - added logical assignment operators
18 | - added IsHTMLDDA support
19 | - faster for-of loops
20 | - os.Worker now takes a module filename as parameter
21 | - qjsc: added -D option to compile dynamically loaded modules or workers
22 | - misc bug fixes
23 |
24 | 2020-07-05:
25 |
26 | - modified JS_GetPrototype() to return a live value
27 | - REPL: support unicode characters larger than 16 bits
28 | - added os.Worker
29 | - improved object serialization
30 | - added std.parseExtJSON
31 | - misc bug fixes
32 |
33 | 2020-04-12:
34 |
35 | - added cross realm support
36 | - added AggregateError and Promise.any
37 | - added env, uid and gid options in os.exec()
38 | - misc bug fixes
39 |
40 | 2020-03-16:
41 |
42 | - reworked error handling in std and os libraries: suppressed I/O
43 | exceptions in std FILE functions and return a positive errno value
44 | when it is explicit
45 | - output exception messages to stderr
46 | - added std.loadFile(), std.strerror(), std.FILE.prototype.tello()
47 | - added JS_GetRuntimeOpaque(), JS_SetRuntimeOpaque(), JS_NewUint32()
48 | - updated to Unicode 13.0.0
49 | - misc bug fixes
50 |
51 | 2020-01-19:
52 |
53 | - keep CONFIG_BIGNUM in the makefile
54 | - added os.chdir()
55 | - qjs: added -I option
56 | - more memory checks in the bignum operations
57 | - modified operator overloading semantics to be closer to the TC39
58 | proposal
59 | - suppressed "use bigint" mode. Simplified "use math" mode
60 | - BigDecimal: changed suffix from 'd' to 'm'
61 | - misc bug fixes
62 |
63 | 2020-01-05:
64 |
65 | - always compile the bignum code. Added '--bignum' option to qjs.
66 | - added BigDecimal
67 | - added String.prototype.replaceAll
68 | - misc bug fixes
69 |
70 | 2019-12-21:
71 |
72 | - added nullish coalescing operator (ES2020)
73 | - added optional chaining (ES2020)
74 | - removed recursions in garbage collector
75 | - test stack overflow in the parser
76 | - improved backtrace logic
77 | - added JS_SetHostPromiseRejectionTracker()
78 | - allow exotic constructors
79 | - improved c++ compatibility
80 | - misc bug fixes
81 |
82 | 2019-10-27:
83 |
84 | - added example of C class in a module (examples/test_point.js)
85 | - added JS_GetTypedArrayBuffer()
86 | - misc bug fixes
87 |
88 | 2019-09-18:
89 |
90 | - added os.exec and other system calls
91 | - exported JS_ValueToAtom()
92 | - qjsc: added 'qjsc_' prefix to the generated C identifiers
93 | - added cross-compilation support
94 | - misc bug fixes
95 |
96 | 2019-09-01:
97 |
98 | - added globalThis
99 | - documented JS_EVAL_FLAG_COMPILE_ONLY
100 | - added import.meta.url and import.meta.main
101 | - added 'debugger' statement
102 | - misc bug fixes
103 |
104 | 2019-08-18:
105 |
106 | - added os.realpath, os.getcwd, os.mkdir, os.stat, os.lstat,
107 | os.readlink, os.readdir, os.utimes, std.popen
108 | - module autodetection
109 | - added import.meta
110 | - misc bug fixes
111 |
112 | 2019-08-10:
113 |
114 | - added public class fields and private class fields, methods and
115 | accessors (TC39 proposal)
116 | - changed JS_ToCStringLen() prototype
117 | - qjsc: handle '-' in module names and modules with the same filename
118 | - added std.urlGet
119 | - exported JS_GetOwnPropertyNames() and JS_GetOwnProperty()
120 | - exported some bigint C functions
121 | - added support for eshost in run-test262
122 | - misc bug fixes
123 |
124 | 2019-07-28:
125 |
126 | - added dynamic import
127 | - added Promise.allSettled
128 | - added String.prototype.matchAll
129 | - added Object.fromEntries
130 | - reduced number of ticks in await
131 | - added BigInt support in Atomics
132 | - exported JS_NewPromiseCapability()
133 | - misc async function and async generator fixes
134 | - enabled hashbang support by default
135 |
136 | 2019-07-21:
137 |
138 | - updated test262 tests
139 | - updated to Unicode version 12.1.0
140 | - fixed missing Date object in qjsc
141 | - fixed multi-context creation
142 | - misc ES2020 related fixes
143 | - simplified power and division operators in bignum extension
144 | - fixed several crash conditions
145 |
146 | 2019-07-09:
147 |
148 | - first public release
149 |
--------------------------------------------------------------------------------
/test262.conf:
--------------------------------------------------------------------------------
1 | [config]
2 | # general settings for test262 ES6 version
3 |
4 | # framework style: old, new
5 | style=new
6 |
7 | # handle tests tagged as [noStrict]: yes, no, skip
8 | nostrict=yes
9 |
10 | # handle tests tagged as [strictOnly]: yes, no, skip
11 | strict=yes
12 |
13 | # test mode: default, default-nostrict, default-strict, strict, nostrict, both, all
14 | mode=default
15 |
16 | # handle tests flagged as [async]: yes, no, skip
17 | # for these, load 'harness/doneprintHandle.js' prior to test
18 | # and expect `print('Test262:AsyncTestComplete')` to be called for
19 | # successful termination
20 | async=yes
21 |
22 | # handle tests flagged as [module]: yes, no, skip
23 | module=yes
24 |
25 | # output error messages: yes, no
26 | verbose=yes
27 |
28 | # load harness files from this directory
29 | harnessdir=test262/harness
30 |
31 | # names of harness include files to skip
32 | #harnessexclude=
33 |
34 | # name of the error file for known errors
35 | errorfile=test262_errors.txt
36 |
37 | # exclude tests enumerated in this file (see also [exclude] section)
38 | #excludefile=test262_exclude.txt
39 |
40 | # report test results to this file
41 | reportfile=test262_report.txt
42 |
43 | # enumerate tests from this directory
44 | testdir=test262/test
45 |
46 | [features]
47 | # Standard language features and proposed extensions
48 | # list the features that are included
49 | # skipped features are tagged as such to avoid warnings
50 |
51 | AggregateError
52 | align-detached-buffer-semantics-with-web-reality
53 | arbitrary-module-namespace-names=skip
54 | Array.prototype.at=skip
55 | Array.prototype.flat
56 | Array.prototype.flatMap
57 | Array.prototype.flatten
58 | Array.prototype.values
59 | ArrayBuffer
60 | arrow-function
61 | async-functions
62 | async-iteration
63 | Atomics
64 | Atomics.waitAsync=skip
65 | BigInt
66 | caller
67 | class
68 | class-fields-private
69 | class-fields-public
70 | class-methods-private
71 | class-static-fields-public
72 | class-static-fields-private
73 | class-static-methods-private
74 | cleanupSome=skip
75 | coalesce-expression
76 | computed-property-names
77 | const
78 | cross-realm
79 | DataView
80 | DataView.prototype.getFloat32
81 | DataView.prototype.getFloat64
82 | DataView.prototype.getInt16
83 | DataView.prototype.getInt32
84 | DataView.prototype.getInt8
85 | DataView.prototype.getUint16
86 | DataView.prototype.getUint32
87 | DataView.prototype.setUint8
88 | default-parameters
89 | destructuring-assignment
90 | destructuring-binding
91 | dynamic-import
92 | export-star-as-namespace-from-module
93 | FinalizationGroup=skip
94 | FinalizationRegistry=skip
95 | FinalizationRegistry.prototype.cleanupSome=skip
96 | Float32Array
97 | Float64Array
98 | for-in-order
99 | for-of
100 | generators
101 | globalThis
102 | hashbang
103 | host-gc-required=skip
104 | import.meta
105 | Int16Array
106 | Int32Array
107 | Int8Array
108 | IsHTMLDDA
109 | json-superset
110 | legacy-regexp=skip
111 | let
112 | logical-assignment-operators
113 | Map
114 | new.target
115 | numeric-separator-literal
116 | object-rest
117 | object-spread
118 | Object.fromEntries
119 | Object.is
120 | optional-catch-binding
121 | optional-chaining
122 | Promise
123 | Promise.allSettled
124 | Promise.any
125 | Promise.prototype.finally
126 | Proxy
127 | proxy-missing-checks
128 | Reflect
129 | Reflect.construct
130 | Reflect.set
131 | Reflect.setPrototypeOf
132 | regexp-dotall
133 | regexp-lookbehind
134 | regexp-match-indices=skip
135 | regexp-named-groups
136 | regexp-unicode-property-escapes
137 | rest-parameters
138 | Set
139 | SharedArrayBuffer
140 | string-trimming
141 | String.fromCodePoint
142 | String.prototype.endsWith
143 | String.prototype.includes
144 | String.prototype.at=skip
145 | String.prototype.matchAll
146 | String.prototype.replaceAll
147 | String.prototype.trimEnd
148 | String.prototype.trimStart
149 | super
150 | Symbol
151 | Symbol.asyncIterator
152 | Symbol.hasInstance
153 | Symbol.isConcatSpreadable
154 | Symbol.iterator
155 | Symbol.match
156 | Symbol.matchAll
157 | Symbol.prototype.description
158 | Symbol.replace
159 | Symbol.search
160 | Symbol.species
161 | Symbol.split
162 | Symbol.toPrimitive
163 | Symbol.toStringTag
164 | Symbol.unscopables
165 | tail-call-optimization=skip
166 | template
167 | top-level-await=skip
168 | TypedArray
169 | TypedArray.prototype.at=skip
170 | u180e
171 | Uint16Array
172 | Uint32Array
173 | Uint8Array
174 | Uint8ClampedArray
175 | WeakMap
176 | WeakRef=skip
177 | WeakSet
178 | well-formed-json-stringify
179 | __getter__
180 | __proto__
181 | __setter__
182 |
183 | [exclude]
184 | # list excluded tests and directories here
185 |
186 | # intl not supported
187 | test262/test/intl402/
188 |
189 | # incompatible with the "caller" feature
190 | test262/test/built-ins/Function/prototype/restricted-property-caller.js
191 | test262/test/built-ins/Function/prototype/restricted-property-arguments.js
192 | test262/test/built-ins/ThrowTypeError/unique-per-realm-function-proto.js
193 |
194 | # slow tests
195 | #test262/test/built-ins/RegExp/CharacterClassEscapes/
196 | #test262/test/built-ins/RegExp/property-escapes/
197 |
198 | [tests]
199 | # list test files or use config.testdir
200 |
--------------------------------------------------------------------------------
/tests/test_closure.js:
--------------------------------------------------------------------------------
1 | function assert(actual, expected, message) {
2 | if (arguments.length == 1)
3 | expected = true;
4 |
5 | if (actual === expected)
6 | return;
7 |
8 | if (actual !== null && expected !== null
9 | && typeof actual == 'object' && typeof expected == 'object'
10 | && actual.toString() === expected.toString())
11 | return;
12 |
13 | throw Error("assertion failed: got |" + actual + "|" +
14 | ", expected |" + expected + "|" +
15 | (message ? " (" + message + ")" : ""));
16 | }
17 |
18 | // load more elaborate version of assert if available
19 | try { __loadScript("test_assert.js"); } catch(e) {}
20 |
21 | /*----------------*/
22 |
23 | var log_str = "";
24 |
25 | function log(str)
26 | {
27 | log_str += str + ",";
28 | }
29 |
30 | function f(a, b, c)
31 | {
32 | var x = 10;
33 | log("a="+a);
34 | function g(d) {
35 | function h() {
36 | log("d=" + d);
37 | log("x=" + x);
38 | }
39 | log("b=" + b);
40 | log("c=" + c);
41 | h();
42 | }
43 | g(4);
44 | return g;
45 | }
46 |
47 | var g1 = f(1, 2, 3);
48 | g1(5);
49 |
50 | assert(log_str, "a=1,b=2,c=3,d=4,x=10,b=2,c=3,d=5,x=10,", "closure1");
51 |
52 | function test_closure1()
53 | {
54 | function f2()
55 | {
56 | var val = 1;
57 |
58 | function set(a) {
59 | val = a;
60 | }
61 | function get(a) {
62 | return val;
63 | }
64 | return { "set": set, "get": get };
65 | }
66 |
67 | var obj = f2();
68 | obj.set(10);
69 | var r;
70 | r = obj.get();
71 | assert(r, 10, "closure2");
72 | }
73 |
74 | function test_closure2()
75 | {
76 | var expr_func = function myfunc1(n) {
77 | function myfunc2(n) {
78 | return myfunc1(n - 1);
79 | }
80 | if (n == 0)
81 | return 0;
82 | else
83 | return myfunc2(n);
84 | };
85 | var r;
86 | r = expr_func(1);
87 | assert(r, 0, "expr_func");
88 | }
89 |
90 | function test_closure3()
91 | {
92 | function fib(n)
93 | {
94 | if (n <= 0)
95 | return 0;
96 | else if (n == 1)
97 | return 1;
98 | else
99 | return fib(n - 1) + fib(n - 2);
100 | }
101 |
102 | var fib_func = function fib1(n)
103 | {
104 | if (n <= 0)
105 | return 0;
106 | else if (n == 1)
107 | return 1;
108 | else
109 | return fib1(n - 1) + fib1(n - 2);
110 | };
111 |
112 | assert(fib(6), 8, "fib");
113 | assert(fib_func(6), 8, "fib_func");
114 | }
115 |
116 | function test_arrow_function()
117 | {
118 | "use strict";
119 |
120 | function f1() {
121 | return (() => arguments)();
122 | }
123 | function f2() {
124 | return (() => this)();
125 | }
126 | function f3() {
127 | return (() => eval("this"))();
128 | }
129 | function f4() {
130 | return (() => eval("new.target"))();
131 | }
132 | var a;
133 |
134 | a = f1(1, 2);
135 | assert(a.length, 2);
136 | assert(a[0] === 1 && a[1] === 2);
137 |
138 | assert(f2.call("this_val") === "this_val");
139 | assert(f3.call("this_val") === "this_val");
140 | assert(new f4() === f4);
141 |
142 | var o1 = { f() { return this; } };
143 | var o2 = { f() {
144 | return (() => eval("super.f()"))();
145 | } };
146 | o2.__proto__ = o1;
147 |
148 | assert(o2.f() === o2);
149 | }
150 |
151 | function test_with()
152 | {
153 | var o1 = { x: "o1", y: "o1" };
154 | var x = "local";
155 | eval('var z="var_obj";');
156 | assert(z === "var_obj");
157 | with (o1) {
158 | assert(x === "o1");
159 | assert(eval("x") === "o1");
160 | var f = function () {
161 | o2 = { x: "o2" };
162 | with (o2) {
163 | assert(x === "o2");
164 | assert(y === "o1");
165 | assert(z === "var_obj");
166 | assert(eval("x") === "o2");
167 | assert(eval("y") === "o1");
168 | assert(eval("z") === "var_obj");
169 | assert(eval('eval("x")') === "o2");
170 | }
171 | };
172 | f();
173 | }
174 | }
175 |
176 | function test_eval_closure()
177 | {
178 | var tab;
179 |
180 | tab = [];
181 | for(let i = 0; i < 3; i++) {
182 | eval("tab.push(function g1() { return i; })");
183 | }
184 | for(let i = 0; i < 3; i++) {
185 | assert(tab[i]() === i);
186 | }
187 |
188 | tab = [];
189 | for(let i = 0; i < 3; i++) {
190 | let f = function f() {
191 | eval("tab.push(function g2() { return i; })");
192 | };
193 | f();
194 | }
195 | for(let i = 0; i < 3; i++) {
196 | assert(tab[i]() === i);
197 | }
198 | }
199 |
200 | function test_eval_const()
201 | {
202 | const a = 1;
203 | var success = false;
204 | var f = function () {
205 | eval("a = 1");
206 | };
207 | try {
208 | f();
209 | } catch(e) {
210 | success = (e instanceof TypeError);
211 | }
212 | assert(success);
213 | }
214 |
215 | test_closure1();
216 | test_closure2();
217 | test_closure3();
218 | test_arrow_function();
219 | test_with();
220 | test_eval_closure();
221 | test_eval_const();
222 |
--------------------------------------------------------------------------------
/examples/point.c:
--------------------------------------------------------------------------------
1 | /*
2 | * QuickJS: Example of C module with a class
3 | *
4 | * Copyright (c) 2019 Fabrice Bellard
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 | #include "../quickjs.h"
25 | #include
26 |
27 | #define countof(x) (sizeof(x) / sizeof((x)[0]))
28 |
29 | /* Point Class */
30 |
31 | typedef struct {
32 | int x;
33 | int y;
34 | } JSPointData;
35 |
36 | static JSClassID js_point_class_id;
37 |
38 | static void js_point_finalizer(JSRuntime *rt, JSValue val)
39 | {
40 | JSPointData *s = JS_GetOpaque(val, js_point_class_id);
41 | /* Note: 's' can be NULL in case JS_SetOpaque() was not called */
42 | js_free_rt(rt, s);
43 | }
44 |
45 | static JSValue js_point_ctor(JSContext *ctx,
46 | JSValueConst new_target,
47 | int argc, JSValueConst *argv)
48 | {
49 | JSPointData *s;
50 | JSValue obj = JS_UNDEFINED;
51 | JSValue proto;
52 |
53 | s = js_mallocz(ctx, sizeof(*s));
54 | if (!s)
55 | return JS_EXCEPTION;
56 | if (JS_ToInt32(ctx, &s->x, argv[0]))
57 | goto fail;
58 | if (JS_ToInt32(ctx, &s->y, argv[1]))
59 | goto fail;
60 | /* using new_target to get the prototype is necessary when the
61 | class is extended. */
62 | proto = JS_GetPropertyStr(ctx, new_target, "prototype");
63 | if (JS_IsException(proto))
64 | goto fail;
65 | obj = JS_NewObjectProtoClass(ctx, proto, js_point_class_id);
66 | JS_FreeValue(ctx, proto);
67 | if (JS_IsException(obj))
68 | goto fail;
69 | JS_SetOpaque(obj, s);
70 | return obj;
71 | fail:
72 | js_free(ctx, s);
73 | JS_FreeValue(ctx, obj);
74 | return JS_EXCEPTION;
75 | }
76 |
77 | static JSValue js_point_get_xy(JSContext *ctx, JSValueConst this_val, int magic)
78 | {
79 | JSPointData *s = JS_GetOpaque2(ctx, this_val, js_point_class_id);
80 | if (!s)
81 | return JS_EXCEPTION;
82 | if (magic == 0)
83 | return JS_NewInt32(ctx, s->x);
84 | else
85 | return JS_NewInt32(ctx, s->y);
86 | }
87 |
88 | static JSValue js_point_set_xy(JSContext *ctx, JSValueConst this_val, JSValue val, int magic)
89 | {
90 | JSPointData *s = JS_GetOpaque2(ctx, this_val, js_point_class_id);
91 | int v;
92 | if (!s)
93 | return JS_EXCEPTION;
94 | if (JS_ToInt32(ctx, &v, val))
95 | return JS_EXCEPTION;
96 | if (magic == 0)
97 | s->x = v;
98 | else
99 | s->y = v;
100 | return JS_UNDEFINED;
101 | }
102 |
103 | static JSValue js_point_norm(JSContext *ctx, JSValueConst this_val,
104 | int argc, JSValueConst *argv)
105 | {
106 | JSPointData *s = JS_GetOpaque2(ctx, this_val, js_point_class_id);
107 | if (!s)
108 | return JS_EXCEPTION;
109 | return JS_NewFloat64(ctx, sqrt((double)s->x * s->x + (double)s->y * s->y));
110 | }
111 |
112 | static JSClassDef js_point_class = {
113 | "Point",
114 | .finalizer = js_point_finalizer,
115 | };
116 |
117 | static const JSCFunctionListEntry js_point_proto_funcs[] = {
118 | JS_CGETSET_MAGIC_DEF("x", js_point_get_xy, js_point_set_xy, 0),
119 | JS_CGETSET_MAGIC_DEF("y", js_point_get_xy, js_point_set_xy, 1),
120 | JS_CFUNC_DEF("norm", 0, js_point_norm),
121 | };
122 |
123 | static int js_point_init(JSContext *ctx, JSModuleDef *m)
124 | {
125 | JSValue point_proto, point_class;
126 |
127 | /* create the Point class */
128 | JS_NewClassID(&js_point_class_id);
129 | JS_NewClass(JS_GetRuntime(ctx), js_point_class_id, &js_point_class);
130 |
131 | point_proto = JS_NewObject(ctx);
132 | JS_SetPropertyFunctionList(ctx, point_proto, js_point_proto_funcs, countof(js_point_proto_funcs));
133 |
134 | point_class = JS_NewCFunction2(ctx, js_point_ctor, "Point", 2, JS_CFUNC_constructor, 0);
135 | /* set proto.constructor and ctor.prototype */
136 | JS_SetConstructor(ctx, point_class, point_proto);
137 | JS_SetClassProto(ctx, js_point_class_id, point_proto);
138 |
139 | JS_SetModuleExport(ctx, m, "Point", point_class);
140 | return 0;
141 | }
142 |
143 | JSModuleDef *js_init_module(JSContext *ctx, const char *module_name)
144 | {
145 | JSModuleDef *m;
146 | m = JS_NewCModule(ctx, module_name, js_point_init);
147 | if (!m)
148 | return NULL;
149 | JS_AddModuleExport(ctx, m, "Point");
150 | return m;
151 | }
152 |
--------------------------------------------------------------------------------
/tests/test_op_overloading.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | function assert(actual, expected, message) {
4 | if (arguments.length == 1)
5 | expected = true;
6 |
7 | if (actual === expected)
8 | return;
9 |
10 | if (actual !== null && expected !== null
11 | && typeof actual == 'object' && typeof expected == 'object'
12 | && actual.toString() === expected.toString())
13 | return;
14 |
15 | throw Error("assertion failed: got |" + actual + "|" +
16 | ", expected |" + expected + "|" +
17 | (message ? " (" + message + ")" : ""));
18 | }
19 |
20 | /* operators overloading with Operators.create() */
21 | function test_operators_create() {
22 | class Vec2
23 | {
24 | constructor(x, y) {
25 | this.x = x;
26 | this.y = y;
27 | }
28 | static mul_scalar(p1, a) {
29 | var r = new Vec2();
30 | r.x = p1.x * a;
31 | r.y = p1.y * a;
32 | return r;
33 | }
34 | toString() {
35 | return "Vec2(" + this.x + "," + this.y + ")";
36 | }
37 | }
38 |
39 | Vec2.prototype[Symbol.operatorSet] = Operators.create(
40 | {
41 | "+"(p1, p2) {
42 | var r = new Vec2();
43 | r.x = p1.x + p2.x;
44 | r.y = p1.y + p2.y;
45 | return r;
46 | },
47 | "-"(p1, p2) {
48 | var r = new Vec2();
49 | r.x = p1.x - p2.x;
50 | r.y = p1.y - p2.y;
51 | return r;
52 | },
53 | "=="(a, b) {
54 | return a.x == b.x && a.y == b.y;
55 | },
56 | "<"(a, b) {
57 | var r;
58 | /* lexicographic order */
59 | if (a.x == b.x)
60 | r = (a.y < b.y);
61 | else
62 | r = (a.x < b.x);
63 | return r;
64 | },
65 | "++"(a) {
66 | var r = new Vec2();
67 | r.x = a.x + 1;
68 | r.y = a.y + 1;
69 | return r;
70 | }
71 | },
72 | {
73 | left: Number,
74 | "*"(a, b) {
75 | return Vec2.mul_scalar(b, a);
76 | }
77 | },
78 | {
79 | right: Number,
80 | "*"(a, b) {
81 | return Vec2.mul_scalar(a, b);
82 | }
83 | });
84 |
85 | var a = new Vec2(1, 2);
86 | var b = new Vec2(3, 4);
87 | var r;
88 |
89 | r = a * 2 + 3 * b;
90 | assert(r.x === 11 && r.y === 16);
91 | assert(a == a, true);
92 | assert(a == b, false);
93 | assert(a != a, false);
94 | assert(a < b, true);
95 | assert(a <= b, true);
96 | assert(b < a, false);
97 | assert(b <= a, false);
98 | assert(a <= a, true);
99 | assert(a >= a, true);
100 | a++;
101 | assert(a.x === 2 && a.y === 3);
102 | r = ++a;
103 | assert(a.x === 3 && a.y === 4);
104 | assert(r === a);
105 | }
106 |
107 | /* operators overloading thru inheritance */
108 | function test_operators()
109 | {
110 | var Vec2;
111 |
112 | function mul_scalar(p1, a) {
113 | var r = new Vec2();
114 | r.x = p1.x * a;
115 | r.y = p1.y * a;
116 | return r;
117 | }
118 |
119 | var vec2_ops = Operators({
120 | "+"(p1, p2) {
121 | var r = new Vec2();
122 | r.x = p1.x + p2.x;
123 | r.y = p1.y + p2.y;
124 | return r;
125 | },
126 | "-"(p1, p2) {
127 | var r = new Vec2();
128 | r.x = p1.x - p2.x;
129 | r.y = p1.y - p2.y;
130 | return r;
131 | },
132 | "=="(a, b) {
133 | return a.x == b.x && a.y == b.y;
134 | },
135 | "<"(a, b) {
136 | var r;
137 | /* lexicographic order */
138 | if (a.x == b.x)
139 | r = (a.y < b.y);
140 | else
141 | r = (a.x < b.x);
142 | return r;
143 | },
144 | "++"(a) {
145 | var r = new Vec2();
146 | r.x = a.x + 1;
147 | r.y = a.y + 1;
148 | return r;
149 | }
150 | },
151 | {
152 | left: Number,
153 | "*"(a, b) {
154 | return mul_scalar(b, a);
155 | }
156 | },
157 | {
158 | right: Number,
159 | "*"(a, b) {
160 | return mul_scalar(a, b);
161 | }
162 | });
163 |
164 | Vec2 = class Vec2 extends vec2_ops
165 | {
166 | constructor(x, y) {
167 | super();
168 | this.x = x;
169 | this.y = y;
170 | }
171 | toString() {
172 | return "Vec2(" + this.x + "," + this.y + ")";
173 | }
174 | }
175 |
176 | var a = new Vec2(1, 2);
177 | var b = new Vec2(3, 4);
178 | var r;
179 |
180 | r = a * 2 + 3 * b;
181 | assert(r.x === 11 && r.y === 16);
182 | assert(a == a, true);
183 | assert(a == b, false);
184 | assert(a != a, false);
185 | assert(a < b, true);
186 | assert(a <= b, true);
187 | assert(b < a, false);
188 | assert(b <= a, false);
189 | assert(a <= a, true);
190 | assert(a >= a, true);
191 | a++;
192 | assert(a.x === 2 && a.y === 3);
193 | r = ++a;
194 | assert(a.x === 3 && a.y === 4);
195 | assert(r === a);
196 | }
197 |
198 | function test_default_op()
199 | {
200 | assert(Object(1) + 2, 3);
201 | assert(Object(1) + true, 2);
202 | assert(-Object(1), -1);
203 | }
204 |
205 | test_operators_create();
206 | test_operators();
207 | test_default_op();
208 |
--------------------------------------------------------------------------------
/storage/dybase/src/btree.h:
--------------------------------------------------------------------------------
1 | //-< BTREE.CPP >-----------------------------------------------------*--------*
2 | // GigaBASE Version 1.0 (c) 1999 GARRET * ? *
3 | // (Post Relational Database Management System) * /\| *
4 | // * / \ *
5 | // Created: 1-Jan-99 K.A. Knizhnik * / [] \ *
6 | // Last update: 25-Oct-99 K.A. Knizhnik * GARRET *
7 | //-------------------------------------------------------------------*--------*
8 | // B-Tree interface
9 | //-------------------------------------------------------------------*--------*
10 |
11 | #ifndef __BTREE_H__
12 | #define __BTREE_H__
13 |
14 | #include "buffer.h"
15 |
16 | class dbSearchContext {
17 | public:
18 | void * low;
19 | length_t lowSize;
20 | int lowInclusive;
21 | void * high;
22 | length_t highSize;
23 | int highInclusive;
24 | int keyType;
25 | dbBuffer selection;
26 | };
27 |
28 | class dbBtreePage {
29 | public:
30 | db_nat4 nItems;
31 | db_nat4 size;
32 |
33 | struct str {
34 | oid_t oid;
35 | db_nat2 size;
36 | db_nat2 offs;
37 | };
38 |
39 | enum { dbMaxKeyLen = (dbPageSize - sizeof(str) * 2) / sizeof(char) / 2 };
40 |
41 | struct item {
42 | oid_t oid;
43 | int keyLen;
44 | union {
45 | db_int1 boolKey;
46 | db_int4 intKey;
47 | db_int8 longKey;
48 | oid_t refKey;
49 | db_real8 realKey;
50 | char charKey[dbMaxKeyLen];
51 | };
52 | };
53 | enum { maxItems = (dbPageSize - 8) / sizeof(oid_t) };
54 |
55 | union {
56 | oid_t record[maxItems];
57 | oid_t refKey[(dbPageSize - 8) / sizeof(oid_t)];
58 | db_int4 intKey[(dbPageSize - 8) / sizeof(db_int4)];
59 | db_int8 longKey[(dbPageSize - 8) / sizeof(db_int8)];
60 | db_real8 realKey[(dbPageSize - 8) / sizeof(db_real8)];
61 | db_int1 boolKey[dbPageSize - 8];
62 | char charKey[dbPageSize - 8];
63 | str strKey[1];
64 | };
65 |
66 | static oid_t allocate(dbDatabase *db, oid_t root, int type, item &ins);
67 |
68 | static int insert(dbDatabase *db, oid_t pageId, int type, item &ins,
69 | bool unique, bool replace, int height);
70 | static int remove(dbDatabase *db, oid_t pageId, int type, item &rem,
71 | int height);
72 |
73 | static void markPage(dbDatabase *db, oid_t pageId, int type, int height);
74 |
75 | static void purge(dbDatabase *db, oid_t pageId, int type, int height);
76 |
77 | int insertStrKey(dbDatabase *db, int r, item &ins, int height);
78 | int replaceStrKey(dbDatabase *db, int r, item &ins, int height);
79 | int removeStrKey(int r);
80 | void compactify(int m);
81 |
82 | int handlePageUnderflow(dbDatabase *db, int r, int type, item &rem,
83 | int height);
84 |
85 | bool find(dbDatabase *db, dbSearchContext &sc, int height);
86 | };
87 |
88 | class dbBtree : public dbObject {
89 | friend class dbDatabase;
90 | friend class dbBtreeIterator;
91 |
92 | protected:
93 | oid_t root;
94 | db_int4 height;
95 | db_int4 type;
96 | db_int4 flags;
97 | db_int4 unique;
98 |
99 | static bool packItem(dbDatabase *db, dbBtree *tree, dbBtreePage::item &it,
100 | void *key, int keyType, length_t keySize, oid_t oid);
101 |
102 | static void _drop(dbDatabase *db, oid_t treeId);
103 | static void _clear(dbDatabase *db, oid_t treeId);
104 |
105 | public:
106 | enum OperationEffect { done, overflow, underflow, duplicate, not_found };
107 |
108 | static oid_t allocate(dbDatabase *db, int type, bool unique);
109 | static void find(dbDatabase *db, oid_t treeId, dbSearchContext &sc);
110 | static bool insert(dbDatabase *db, oid_t treeId, void *key, int keyType,
111 | length_t keySize, oid_t oid, bool replace);
112 | static bool remove(dbDatabase *db, oid_t treeId, void *key, int keyType,
113 | length_t keySize, oid_t oid);
114 | static void drop(dbDatabase *db, oid_t treeId);
115 | static void clear(dbDatabase *db, oid_t treeId);
116 | static bool is_unique(dbDatabase *db, oid_t treeId);
117 | static int get_type(dbDatabase *db, oid_t treeId);
118 |
119 | void markTree(dbDatabase *db) {
120 | if (root != 0) { dbBtreePage::markPage(db, root, type, height); }
121 | }
122 | };
123 |
124 | class dbBtreeIterator {
125 | public:
126 | dbBtreeIterator(dbDatabase *db, oid_t treeId, int keyType, void *from,
127 | length_t fromLength, int fromInclusion, void *till,
128 | length_t tillLength, int tillInclusion, bool ascent);
129 | oid_t next();
130 |
131 | private:
132 | void gotoNextItem(dbBtreePage *pg, int pos);
133 | static int compare(void *key, int keyType, dbBtreePage *pg, int pos);
134 | static int compareStr(void *key, length_t keyLength, dbBtreePage *pg,
135 | int pos);
136 |
137 | enum { MaxTreeHeight = 8 };
138 |
139 | dbDatabase *db;
140 | int height;
141 | int type;
142 | int sp;
143 | int end;
144 | union {
145 | db_int1 boolKey;
146 | db_int4 intKey;
147 | db_int8 longKey;
148 | oid_t refKey;
149 | db_real8 realKey;
150 | } from_val, till_val;
151 | void * from;
152 | void * till;
153 | length_t fromLength;
154 | length_t tillLength;
155 | int fromInclusion;
156 | int tillInclusion;
157 | bool ascent;
158 | oid_t pageStack[MaxTreeHeight];
159 | int posStack[MaxTreeHeight];
160 | };
161 |
162 | #endif
163 |
--------------------------------------------------------------------------------
/tests/test_bjson.js:
--------------------------------------------------------------------------------
1 | import * as bjson from "./bjson.so";
2 |
3 | function assert(actual, expected, message) {
4 | if (arguments.length == 1)
5 | expected = true;
6 |
7 | if (actual === expected)
8 | return;
9 |
10 | if (actual !== null && expected !== null
11 | && typeof actual == 'object' && typeof expected == 'object'
12 | && actual.toString() === expected.toString())
13 | return;
14 |
15 | throw Error("assertion failed: got |" + actual + "|" +
16 | ", expected |" + expected + "|" +
17 | (message ? " (" + message + ")" : ""));
18 | }
19 |
20 | function toHex(a)
21 | {
22 | var i, s = "", tab, v;
23 | tab = new Uint8Array(a);
24 | for(i = 0; i < tab.length; i++) {
25 | v = tab[i].toString(16);
26 | if (v.length < 2)
27 | v = "0" + v;
28 | if (i !== 0)
29 | s += " ";
30 | s += v;
31 | }
32 | return s;
33 | }
34 |
35 | function isArrayLike(a)
36 | {
37 | return Array.isArray(a) ||
38 | (a instanceof Uint8ClampedArray) ||
39 | (a instanceof Uint8Array) ||
40 | (a instanceof Uint16Array) ||
41 | (a instanceof Uint32Array) ||
42 | (a instanceof Int8Array) ||
43 | (a instanceof Int16Array) ||
44 | (a instanceof Int32Array) ||
45 | (a instanceof Float32Array) ||
46 | (a instanceof Float64Array);
47 | }
48 |
49 | function toStr(a)
50 | {
51 | var s, i, props, prop;
52 |
53 | switch(typeof(a)) {
54 | case "object":
55 | if (a === null)
56 | return "null";
57 | if (a instanceof Date) {
58 | s = "Date(" + toStr(a.valueOf()) + ")";
59 | } else if (a instanceof Number) {
60 | s = "Number(" + toStr(a.valueOf()) + ")";
61 | } else if (a instanceof String) {
62 | s = "String(" + toStr(a.valueOf()) + ")";
63 | } else if (a instanceof Boolean) {
64 | s = "Boolean(" + toStr(a.valueOf()) + ")";
65 | } else if (isArrayLike(a)) {
66 | s = "[";
67 | for(i = 0; i < a.length; i++) {
68 | if (i != 0)
69 | s += ",";
70 | s += toStr(a[i]);
71 | }
72 | s += "]";
73 | } else {
74 | props = Object.keys(a);
75 | s = "{";
76 | for(i = 0; i < props.length; i++) {
77 | if (i != 0)
78 | s += ",";
79 | prop = props[i];
80 | s += prop + ":" + toStr(a[prop]);
81 | }
82 | s += "}";
83 | }
84 | return s;
85 | case "undefined":
86 | return "undefined";
87 | case "string":
88 | return a.__quote();
89 | case "number":
90 | case "bigfloat":
91 | if (a == 0 && 1 / a < 0)
92 | return "-0";
93 | else
94 | return a.toString();
95 | break;
96 | default:
97 | return a.toString();
98 | }
99 | }
100 |
101 | function bjson_test(a)
102 | {
103 | var buf, r, a_str, r_str;
104 | a_str = toStr(a);
105 | buf = bjson.write(a);
106 | if (0) {
107 | print(a_str, "->", toHex(buf));
108 | }
109 | r = bjson.read(buf, 0, buf.byteLength);
110 | r_str = toStr(r);
111 | if (a_str != r_str) {
112 | print(a_str);
113 | print(r_str);
114 | assert(false);
115 | }
116 | }
117 |
118 | /* test multiple references to an object including circular
119 | references */
120 | function bjson_test_reference()
121 | {
122 | var array, buf, i, n, array_buffer;
123 | n = 16;
124 | array = [];
125 | for(i = 0; i < n; i++)
126 | array[i] = {};
127 | array_buffer = new ArrayBuffer(n);
128 | for(i = 0; i < n; i++) {
129 | array[i].next = array[(i + 1) % n];
130 | array[i].idx = i;
131 | array[i].typed_array = new Uint8Array(array_buffer, i, 1);
132 | }
133 | buf = bjson.write(array, true);
134 |
135 | array = bjson.read(buf, 0, buf.byteLength, true);
136 |
137 | /* check the result */
138 | for(i = 0; i < n; i++) {
139 | assert(array[i].next, array[(i + 1) % n]);
140 | assert(array[i].idx, i);
141 | assert(array[i].typed_array.buffer, array_buffer);
142 | assert(array[i].typed_array.length, 1);
143 | assert(array[i].typed_array.byteOffset, i);
144 | }
145 | }
146 |
147 | function bjson_test_all()
148 | {
149 | var obj;
150 |
151 | bjson_test({x:1, y:2, if:3});
152 | bjson_test([1, 2, 3]);
153 | bjson_test([1.0, "aa", true, false, undefined, null, NaN, -Infinity, -0.0]);
154 | if (typeof BigInt !== "undefined") {
155 | bjson_test([BigInt("1"), -BigInt("0x123456789"),
156 | BigInt("0x123456789abcdef123456789abcdef")]);
157 | }
158 | if (typeof BigFloat !== "undefined") {
159 | BigFloatEnv.setPrec(function () {
160 | bjson_test([BigFloat("0.1"), BigFloat("-1e30"), BigFloat("0"),
161 | BigFloat("-0"), BigFloat("Infinity"), BigFloat("-Infinity"),
162 | 0.0 / BigFloat("0"), BigFloat.MAX_VALUE,
163 | BigFloat.MIN_VALUE]);
164 | }, 113, 15);
165 | }
166 | if (typeof BigDecimal !== "undefined") {
167 | bjson_test([BigDecimal("0"),
168 | BigDecimal("0.8"), BigDecimal("123321312321321e100"),
169 | BigDecimal("-1233213123213214332333223332e100"),
170 | BigDecimal("1.233e-1000")]);
171 | }
172 |
173 | bjson_test([new Date(1234), new String("abc"), new Number(-12.1), new Boolean(true)]);
174 |
175 | bjson_test(new Int32Array([123123, 222111, -32222]));
176 | bjson_test(new Float64Array([123123, 222111.5]));
177 |
178 | /* tested with a circular reference */
179 | obj = {};
180 | obj.x = obj;
181 | try {
182 | bjson.write(obj);
183 | assert(false);
184 | } catch(e) {
185 | assert(e instanceof TypeError);
186 | }
187 |
188 | bjson_test_reference();
189 | }
190 |
191 | bjson_test_all();
192 |
--------------------------------------------------------------------------------
/test262_errors.txt:
--------------------------------------------------------------------------------
1 | test262/test/built-ins/Function/internals/Construct/derived-this-uninitialized-realm.js:20: Test262Error: Expected a ReferenceError but got a ReferenceError
2 | test262/test/built-ins/Function/internals/Construct/derived-this-uninitialized-realm.js:20: strict mode: Test262Error: Expected a ReferenceError but got a ReferenceError
3 | test262/test/built-ins/RegExp/named-groups/non-unicode-property-names-valid.js:46: SyntaxError: invalid group name
4 | test262/test/built-ins/RegExp/named-groups/non-unicode-property-names-valid.js:46: strict mode: SyntaxError: invalid group name
5 | test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/BigInt/detached-buffer.js:46: Test262Error: (Testing with BigInt64Array.)
6 | test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/BigInt/detached-buffer.js:46: strict mode: Test262Error: (Testing with BigInt64Array.)
7 | test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/detached-buffer.js:47: Test262Error: (Testing with Float64Array.)
8 | test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/detached-buffer.js:47: strict mode: Test262Error: (Testing with Float64Array.)
9 | test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/detached-buffer-realm.js:37: strict mode: TypeError: out-of-bound numeric index (Testing with BigInt64Array.)
10 | test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/detached-buffer.js:34: TypeError: cannot convert bigint to number (Testing with BigInt64Array.)
11 | test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/detached-buffer.js:32: strict mode: TypeError: out-of-bound numeric index (Testing with BigInt64Array.)
12 | 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.)
13 | 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.)
14 | 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.)
15 | 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.)
16 | 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.)
17 | 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.)
18 | 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.)
19 | 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.)
20 | test262/test/built-ins/TypedArrayConstructors/internals/Set/detached-buffer-realm.js:37: strict mode: TypeError: out-of-bound numeric index (Testing with Float64Array.)
21 | test262/test/built-ins/TypedArrayConstructors/internals/Set/detached-buffer.js:32: strict mode: TypeError: out-of-bound numeric index (Testing with Float64Array.)
22 | 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.)
23 | 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.)
24 | 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.)
25 | 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.)
26 | 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.)
27 | 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.)
28 | test262/test/built-ins/TypedArrayConstructors/internals/Set/tonumber-value-detached-buffer.js:39: Test262Error: Expected SameValue(«false», «true») to be true (Testing with Float64Array.)
29 | 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.)
30 | test262/test/language/expressions/dynamic-import/usage-from-eval.js:26: TypeError: $DONE() not called
31 | test262/test/language/expressions/dynamic-import/usage-from-eval.js:26: strict mode: TypeError: $DONE() not called
32 | test262/test/language/expressions/optional-chaining/optional-call-preserves-this.js:21: TypeError: cannot read property 'c' of undefined
33 | test262/test/language/expressions/optional-chaining/optional-call-preserves-this.js:15: strict mode: TypeError: cannot read property '_b' of undefined
34 | test262/test/language/statements/for-of/head-lhs-async-invalid.js:14: unexpected error type: Test262: This statement should not be evaluated.
35 | test262/test/language/statements/for-of/head-lhs-async-invalid.js:14: strict mode: unexpected error type: Test262: This statement should not be evaluated.
36 |
--------------------------------------------------------------------------------
/tests/test_qjscalc.js:
--------------------------------------------------------------------------------
1 | "use math";
2 | "use strict";
3 |
4 | function assert(actual, expected, message) {
5 | if (arguments.length == 1)
6 | expected = true;
7 |
8 | if (actual === expected)
9 | return;
10 |
11 | if (actual !== null && expected !== null
12 | && typeof actual == 'object' && typeof expected == 'object'
13 | && actual.toString() === expected.toString())
14 | return;
15 |
16 | throw Error("assertion failed: got |" + actual + "|" +
17 | ", expected |" + expected + "|" +
18 | (message ? " (" + message + ")" : ""));
19 | }
20 |
21 | function assertThrows(err, func)
22 | {
23 | var ex;
24 | ex = false;
25 | try {
26 | func();
27 | } catch(e) {
28 | ex = true;
29 | assert(e instanceof err);
30 | }
31 | assert(ex, true, "exception expected");
32 | }
33 |
34 | // load more elaborate version of assert if available
35 | try { __loadScript("test_assert.js"); } catch(e) {}
36 |
37 | /*----------------*/
38 |
39 | function pow(a, n)
40 | {
41 | var r, i;
42 | r = 1;
43 | for(i = 0; i < n; i++)
44 | r *= a;
45 | return r;
46 | }
47 |
48 | function test_integer()
49 | {
50 | var a, r;
51 | a = pow(3, 100);
52 | assert((a - 1) != a);
53 | assert(a == 515377520732011331036461129765621272702107522001);
54 | assert(a == 0x5a4653ca673768565b41f775d6947d55cf3813d1);
55 | assert(Integer.isInteger(1) === true);
56 | assert(Integer.isInteger(1.0) === false);
57 |
58 | assert(Integer.floorLog2(0) === -1);
59 | assert(Integer.floorLog2(7) === 2);
60 |
61 | r = 1 << 31;
62 | assert(r, 2147483648, "1 << 31 === 2147483648");
63 |
64 | r = 1 << 32;
65 | assert(r, 4294967296, "1 << 32 === 4294967296");
66 |
67 | r = (1 << 31) < 0;
68 | assert(r, false, "(1 << 31) < 0 === false");
69 |
70 | assert(typeof 1 === "number");
71 | assert(typeof 9007199254740991 === "number");
72 | assert(typeof 9007199254740992 === "bigint");
73 | }
74 |
75 | function test_float()
76 | {
77 | assert(typeof 1.0 === "bigfloat");
78 | assert(1 == 1.0);
79 | assert(1 !== 1.0);
80 | }
81 |
82 | /* jscalc tests */
83 |
84 | function test_modulo()
85 | {
86 | var i, p, a, b;
87 |
88 | /* Euclidian modulo operator */
89 | assert((-3) % 2 == 1);
90 | assert(3 % (-2) == 1);
91 |
92 | p = 101;
93 | for(i = 1; i < p; i++) {
94 | a = Integer.invmod(i, p);
95 | assert(a >= 0 && a < p);
96 | assert((i * a) % p == 1);
97 | }
98 |
99 | assert(Integer.isPrime(2^107-1));
100 | assert(!Integer.isPrime((2^107-1) * (2^89-1)));
101 | a = Integer.factor((2^89-1)*2^3*11*13^2*1009);
102 | assert(a == [ 2,2,2,11,13,13,1009,618970019642690137449562111 ]);
103 | }
104 |
105 | function test_fraction()
106 | {
107 | assert((1/3 + 1).toString(), "4/3")
108 | assert((2/3)^30, 1073741824/205891132094649);
109 | assert(1/3 < 2/3);
110 | assert(1/3 < 1);
111 | assert(1/3 == 1.0/3);
112 | assert(1.0/3 < 2/3);
113 | }
114 |
115 | function test_mod()
116 | {
117 | var a, b, p;
118 |
119 | a = Mod(3, 101);
120 | b = Mod(-1, 101);
121 | assert((a + b) == Mod(2, 101));
122 | assert(a ^ 100 == Mod(1, 101));
123 |
124 | p = 2 ^ 607 - 1; /* mersenne prime */
125 | a = Mod(3, p) ^ (p - 1);
126 | assert(a == Mod(1, p));
127 | }
128 |
129 | function test_polynomial()
130 | {
131 | var a, b, q, r, t, i;
132 | a = (1 + X) ^ 4;
133 | assert(a == X^4+4*X^3+6*X^2+4*X+1);
134 |
135 | r = (1 + X);
136 | q = (1+X+X^2);
137 | b = (1 - X^2);
138 | a = q * b + r;
139 | t = Polynomial.divrem(a, b);
140 | assert(t[0] == q);
141 | assert(t[1] == r);
142 |
143 | a = 1 + 2*X + 3*X^2;
144 | assert(a.apply(0.1) == 1.23);
145 |
146 | a = 1-2*X^2+2*X^3;
147 | assert(deriv(a) == (6*X^2-4*X));
148 | assert(deriv(integ(a)) == a);
149 |
150 | a = (X-1)*(X-2)*(X-3)*(X-4)*(X-0.1);
151 | r = polroots(a);
152 | for(i = 0; i < r.length; i++) {
153 | b = abs(a.apply(r[i]));
154 | assert(b <= 1e-13);
155 | }
156 | }
157 |
158 | function test_poly_mod()
159 | {
160 | var a, p;
161 |
162 | /* modulo using polynomials */
163 | p = X^2 + X + 1;
164 | a = PolyMod(3+X, p) ^ 10;
165 | assert(a == PolyMod(-3725*X-18357, p));
166 |
167 | a = PolyMod(1/X, 1+X^2);
168 | assert(a == PolyMod(-X, X^2+1));
169 | }
170 |
171 | function test_rfunc()
172 | {
173 | var a;
174 | a = (X+1)/((X+1)*(X-1));
175 | assert(a == 1/(X-1));
176 | a = (X + 2) / (X - 2);
177 | assert(a.apply(1/3) == -7/5);
178 |
179 | assert(deriv((X^2-X+1)/(X-1)) == (X^2-2*X)/(X^2-2*X+1));
180 | }
181 |
182 | function test_series()
183 | {
184 | var a, b;
185 | a = 1+X+O(X^5);
186 | b = a.inverse();
187 | assert(b == 1-X+X^2-X^3+X^4+O(X^5));
188 | assert(deriv(b) == -1+2*X-3*X^2+4*X^3+O(X^4));
189 | assert(deriv(integ(b)) == b);
190 |
191 | a = Series(1/(1-X), 5);
192 | assert(a == 1+X+X^2+X^3+X^4+O(X^5));
193 | b = a.apply(0.1);
194 | assert(b == 1.1111);
195 |
196 | 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));
197 | assert(sin(X+O(X^6)) == X-1/6*X^3+1/120*X^5+O(X^6));
198 | assert(cos(X+O(X^6)) == 1-1/2*X^2+1/24*X^4+O(X^6));
199 | assert(tan(X+O(X^8)) == X+1/3*X^3+2/15*X^5+17/315*X^7+O(X^8));
200 | 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));
201 | }
202 |
203 | function test_matrix()
204 | {
205 | var a, b, r;
206 | a = [[1, 2],[3, 4]];
207 | b = [3, 4];
208 | r = a * b;
209 | assert(r == [11, 25]);
210 | r = (a^-1) * 2;
211 | assert(r == [[-4, 2],[3, -1]]);
212 |
213 | assert(norm2([1,2,3]) == 14);
214 |
215 | assert(diag([1,2,3]) == [ [ 1, 0, 0 ], [ 0, 2, 0 ], [ 0, 0, 3 ] ]);
216 | assert(trans(a) == [ [ 1, 3 ], [ 2, 4 ] ]);
217 | assert(trans([1,2,3]) == [[1,2,3]]);
218 | assert(trace(a) == 5);
219 |
220 | assert(charpoly(Matrix.hilbert(4)) == X^4-176/105*X^3+3341/12600*X^2-41/23625*X+1/6048000);
221 | assert(det(Matrix.hilbert(4)) == 1/6048000);
222 |
223 | a = [[1,2,1],[-2,-3,1],[3,5,0]];
224 | assert(rank(a) == 2);
225 | assert(ker(a) == [ [ 5 ], [ -3 ], [ 1 ] ]);
226 |
227 | assert(dp([1, 2, 3], [3, -4, -7]) === -26);
228 | assert(cp([1, 2, 3], [3, -4, -7]) == [ -2, 16, -10 ]);
229 | }
230 |
231 | function assert_eq(a, ref)
232 | {
233 | assert(abs(a / ref - 1.0) <= 1e-15);
234 | }
235 |
236 | function test_trig()
237 | {
238 | assert_eq(sin(1/2), 0.479425538604203);
239 | assert_eq(sin(2+3*I), 9.154499146911428-4.168906959966565*I);
240 | assert_eq(cos(2+3*I), -4.189625690968807-9.109227893755337*I);
241 | assert_eq((2+0.5*I)^(1.1-0.5*I), 2.494363021357619-0.23076804554558092*I);
242 | assert_eq(sqrt(2*I), 1 + I);
243 | }
244 |
245 | test_integer();
246 | test_float();
247 |
248 | test_modulo();
249 | test_fraction();
250 | test_mod();
251 | test_polynomial();
252 | test_poly_mod();
253 | test_rfunc();
254 | test_series();
255 | test_matrix();
256 | test_trig();
257 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # Premake files
7 | .bin/
8 | .build/
9 |
10 | # User-specific files
11 | *.suo
12 | *.user
13 | *.userosscache
14 | *.sln.docstates
15 |
16 | # User-specific files (MonoDevelop/Xamarin Studio)
17 | *.userprefs
18 |
19 | # Build results
20 | [Dd]ebug/
21 | [Dd]ebugPublic/
22 | [Rr]elease/
23 | [Rr]eleases/
24 | x64/
25 | x86/
26 | bld/
27 | [Bb]in/
28 | [Oo]bj/
29 | [Ll]og/
30 |
31 | # Visual Studio 2015/2017 cache/options directory
32 | .vs/
33 | # Uncomment if you have tasks that create the project's static files in wwwroot
34 | #wwwroot/
35 |
36 | # Visual Studio 2017 auto generated files
37 | Generated\ Files/
38 |
39 | # MSTest test Results
40 | [Tt]est[Rr]esult*/
41 | [Bb]uild[Ll]og.*
42 |
43 | # NUNIT
44 | *.VisualState.xml
45 | TestResult.xml
46 |
47 | # Build Results of an ATL Project
48 | [Dd]ebugPS/
49 | [Rr]eleasePS/
50 | dlldata.c
51 |
52 | # Benchmark Results
53 | BenchmarkDotNet.Artifacts/
54 |
55 | # .NET Core
56 | project.lock.json
57 | project.fragment.lock.json
58 | artifacts/
59 | **/Properties/launchSettings.json
60 |
61 | # StyleCop
62 | StyleCopReport.xml
63 |
64 | # Files built by Visual Studio
65 | *_i.c
66 | *_p.c
67 | *_i.h
68 | *.ilk
69 | *.meta
70 | *.obj
71 | *.iobj
72 | *.pch
73 | *.pdb
74 | *.ipdb
75 | *.pgc
76 | *.pgd
77 | *.rsp
78 | *.sbr
79 | *.tlb
80 | *.tli
81 | *.tlh
82 | *.tmp
83 | *.tmp_proj
84 | *.log
85 | *.vspscc
86 | *.vssscc
87 | .builds
88 | *.pidb
89 | *.svclog
90 | *.scc
91 |
92 | # Chutzpah Test files
93 | _Chutzpah*
94 |
95 | # Visual C++ cache files
96 | ipch/
97 | *.aps
98 | *.ncb
99 | *.opendb
100 | *.opensdf
101 | *.sdf
102 | *.cachefile
103 | *.VC.db
104 | *.VC.VC.opendb
105 |
106 | # Visual Studio profiler
107 | *.psess
108 | *.vsp
109 | *.vspx
110 | *.sap
111 |
112 | # Visual Studio Trace Files
113 | *.e2e
114 |
115 | # TFS 2012 Local Workspace
116 | $tf/
117 |
118 | # Guidance Automation Toolkit
119 | *.gpState
120 |
121 | # ReSharper is a .NET coding add-in
122 | _ReSharper*/
123 | *.[Rr]e[Ss]harper
124 | *.DotSettings.user
125 |
126 | # JustCode is a .NET coding add-in
127 | .JustCode
128 |
129 | # TeamCity is a build add-in
130 | _TeamCity*
131 |
132 | # DotCover is a Code Coverage Tool
133 | *.dotCover
134 |
135 | # AxoCover is a Code Coverage Tool
136 | .axoCover/*
137 | !.axoCover/settings.json
138 |
139 | # Visual Studio code coverage results
140 | *.coverage
141 | *.coveragexml
142 |
143 | # NCrunch
144 | _NCrunch_*
145 | .*crunch*.local.xml
146 | nCrunchTemp_*
147 |
148 | # MightyMoose
149 | *.mm.*
150 | AutoTest.Net/
151 |
152 | # Web workbench (sass)
153 | .sass-cache/
154 |
155 | # Installshield output folder
156 | [Ee]xpress/
157 |
158 | # DocProject is a documentation generator add-in
159 | DocProject/buildhelp/
160 | DocProject/Help/*.HxT
161 | DocProject/Help/*.HxC
162 | DocProject/Help/*.hhc
163 | DocProject/Help/*.hhk
164 | DocProject/Help/*.hhp
165 | DocProject/Help/Html2
166 | DocProject/Help/html
167 |
168 | # Click-Once directory
169 | publish/
170 |
171 | # Publish Web Output
172 | *.[Pp]ublish.xml
173 | *.azurePubxml
174 | # Note: Comment the next line if you want to checkin your web deploy settings,
175 | # but database connection strings (with potential passwords) will be unencrypted
176 | *.pubxml
177 | *.publishproj
178 |
179 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
180 | # checkin your Azure Web App publish settings, but sensitive information contained
181 | # in these scripts will be unencrypted
182 | PublishScripts/
183 |
184 | # NuGet Packages
185 | *.nupkg
186 | # The packages folder can be ignored because of Package Restore
187 | **/[Pp]ackages/*
188 | # except build/, which is used as an MSBuild target.
189 | !**/[Pp]ackages/build/
190 | # Uncomment if necessary however generally it will be regenerated when needed
191 | #!**/[Pp]ackages/repositories.config
192 | # NuGet v3's project.json files produces more ignorable files
193 | *.nuget.props
194 | *.nuget.targets
195 |
196 | # Microsoft Azure Build Output
197 | csx/
198 | *.build.csdef
199 |
200 | # Microsoft Azure Emulator
201 | ecf/
202 | rcf/
203 |
204 | # Windows Store app package directories and files
205 | AppPackages/
206 | BundleArtifacts/
207 | Package.StoreAssociation.xml
208 | _pkginfo.txt
209 | *.appx
210 |
211 | # Visual Studio cache files
212 | # files ending in .cache can be ignored
213 | *.[Cc]ache
214 | # but keep track of directories ending in .cache
215 | !*.[Cc]ache/
216 |
217 | # Others
218 | ClientBin/
219 | ~$*
220 | *~
221 | *.dbmdl
222 | *.dbproj.schemaview
223 | *.jfm
224 | *.pfx
225 | *.publishsettings
226 | orleans.codegen.cs
227 |
228 | # Including strong name files can present a security risk
229 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
230 | #*.snk
231 |
232 | # Since there are multiple workflows, uncomment next line to ignore bower_components
233 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
234 | #bower_components/
235 |
236 | # RIA/Silverlight projects
237 | Generated_Code/
238 |
239 | # Backup & report files from converting an old project file
240 | # to a newer Visual Studio version. Backup files are not needed,
241 | # because we have git ;-)
242 | _UpgradeReport_Files/
243 | Backup*/
244 | UpgradeLog*.XML
245 | UpgradeLog*.htm
246 | ServiceFabricBackup/
247 | *.rptproj.bak
248 |
249 | # SQL Server files
250 | *.mdf
251 | *.ldf
252 | *.ndf
253 |
254 | # Business Intelligence projects
255 | *.rdl.data
256 | *.bim.layout
257 | *.bim_*.settings
258 | *.rptproj.rsuser
259 |
260 | # Microsoft Fakes
261 | FakesAssemblies/
262 |
263 | # GhostDoc plugin setting file
264 | *.GhostDoc.xml
265 |
266 | # Node.js Tools for Visual Studio
267 | .ntvs_analysis.dat
268 | node_modules/
269 |
270 | # Visual Studio 6 build log
271 | *.plg
272 |
273 | # Visual Studio 6 workspace options file
274 | *.opt
275 |
276 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
277 | *.vbw
278 |
279 | # Visual Studio LightSwitch build output
280 | **/*.HTMLClient/GeneratedArtifacts
281 | **/*.DesktopClient/GeneratedArtifacts
282 | **/*.DesktopClient/ModelManifest.xml
283 | **/*.Server/GeneratedArtifacts
284 | **/*.Server/ModelManifest.xml
285 | _Pvt_Extensions
286 |
287 | # Paket dependency manager
288 | .paket/paket.exe
289 | paket-files/
290 |
291 | # FAKE - F# Make
292 | .fake/
293 |
294 | # JetBrains Rider
295 | .idea/
296 | *.sln.iml
297 |
298 | # CodeRush
299 | .cr/
300 |
301 | # Python Tools for Visual Studio (PTVS)
302 | __pycache__/
303 | *.pyc
304 |
305 | # Cake - Uncomment if you are using it
306 | # tools/**
307 | # !tools/packages.config
308 |
309 | # Tabs Studio
310 | *.tss
311 |
312 | # Telerik's JustMock configuration file
313 | *.jmconfig
314 |
315 | # BizTalk build output
316 | *.btp.cs
317 | *.btm.cs
318 | *.odx.cs
319 | *.xsd.cs
320 |
321 | # OpenCover UI analysis results
322 | OpenCover/
323 |
324 | # Azure Stream Analytics local run output
325 | ASALocalRun/
326 |
327 | # MSBuild Binary and Structured Log
328 | *.binlog
329 |
330 | # NVidia Nsight GPU debugger configuration file
331 | *.nvuser
332 |
333 | # MFractors (Xamarin productivity tool) working folder
334 | .mfractor/
335 |
336 |
--------------------------------------------------------------------------------
/tests/test_std.js:
--------------------------------------------------------------------------------
1 | import * as std from "std";
2 | import * as os from "os";
3 |
4 | function assert(actual, expected, message) {
5 | if (arguments.length == 1)
6 | expected = true;
7 |
8 | if (actual === expected)
9 | return;
10 |
11 | if (actual !== null && expected !== null
12 | && typeof actual == 'object' && typeof expected == 'object'
13 | && actual.toString() === expected.toString())
14 | return;
15 |
16 | throw Error("assertion failed: got |" + actual + "|" +
17 | ", expected |" + expected + "|" +
18 | (message ? " (" + message + ")" : ""));
19 | }
20 |
21 | // load more elaborate version of assert if available
22 | try { std.loadScript("test_assert.js"); } catch(e) {}
23 |
24 | /*----------------*/
25 |
26 | function test_printf()
27 | {
28 | assert(std.sprintf("a=%d s=%s", 123, "abc"), "a=123 s=abc");
29 | assert(std.sprintf("%010d", 123), "0000000123");
30 | assert(std.sprintf("%x", -2), "fffffffe");
31 | assert(std.sprintf("%lx", -2), "fffffffffffffffe");
32 | assert(std.sprintf("%10.1f", 2.1), " 2.1");
33 | assert(std.sprintf("%*.*f", 10, 2, -2.13), " -2.13");
34 | assert(std.sprintf("%#lx", 0x7fffffffffffffffn), "0x7fffffffffffffff");
35 | }
36 |
37 | function test_file1()
38 | {
39 | var f, len, str, size, buf, ret, i, str1;
40 |
41 | f = std.tmpfile();
42 | str = "hello world\n";
43 | f.puts(str);
44 |
45 | f.seek(0, std.SEEK_SET);
46 | str1 = f.readAsString();
47 | assert(str1 === str);
48 |
49 | f.seek(0, std.SEEK_END);
50 | size = f.tell();
51 | assert(size === str.length);
52 |
53 | f.seek(0, std.SEEK_SET);
54 |
55 | buf = new Uint8Array(size);
56 | ret = f.read(buf.buffer, 0, size);
57 | assert(ret === size);
58 | for(i = 0; i < size; i++)
59 | assert(buf[i] === str.charCodeAt(i));
60 |
61 | f.close();
62 | }
63 |
64 | function test_file2()
65 | {
66 | var f, str, i, size;
67 | f = std.tmpfile();
68 | str = "hello world\n";
69 | size = str.length;
70 | for(i = 0; i < size; i++)
71 | f.putByte(str.charCodeAt(i));
72 | f.seek(0, std.SEEK_SET);
73 | for(i = 0; i < size; i++) {
74 | assert(str.charCodeAt(i) === f.getByte());
75 | }
76 | assert(f.getByte() === -1);
77 | f.close();
78 | }
79 |
80 | function test_getline()
81 | {
82 | var f, line, line_count, lines, i;
83 |
84 | lines = ["hello world", "line 1", "line 2" ];
85 | f = std.tmpfile();
86 | for(i = 0; i < lines.length; i++) {
87 | f.puts(lines[i], "\n");
88 | }
89 |
90 | f.seek(0, std.SEEK_SET);
91 | assert(!f.eof());
92 | line_count = 0;
93 | for(;;) {
94 | line = f.getline();
95 | if (line === null)
96 | break;
97 | assert(line == lines[line_count]);
98 | line_count++;
99 | }
100 | assert(f.eof());
101 | assert(line_count === lines.length);
102 |
103 | f.close();
104 | }
105 |
106 | function test_popen()
107 | {
108 | var str, f, fname = "tmp_file.txt";
109 | var content = "hello world";
110 |
111 | f = std.open(fname, "w");
112 | f.puts(content);
113 | f.close();
114 |
115 | /* test loadFile */
116 | assert(std.loadFile(fname), content);
117 |
118 | /* execute the 'cat' shell command */
119 | f = std.popen("cat " + fname, "r");
120 | str = f.readAsString();
121 | f.close();
122 |
123 | assert(str, content);
124 |
125 | os.remove(fname);
126 | }
127 |
128 | function test_ext_json()
129 | {
130 | var expected, input, obj;
131 | expected = '{"x":false,"y":true,"z2":null,"a":[1,8,160],"s":"str"}';
132 | input = `{ "x":false, /*comments are allowed */
133 | "y":true, // also a comment
134 | z2:null, // unquoted property names
135 | "a":[+1,0o10,0xa0,], // plus prefix, octal, hexadecimal
136 | "s":"str",} // trailing comma in objects and arrays
137 | `;
138 | obj = std.parseExtJSON(input);
139 | assert(JSON.stringify(obj), expected);
140 | }
141 |
142 | function test_os()
143 | {
144 | var fd, fpath, fname, fdir, buf, buf2, i, files, err, fdate, st, link_path;
145 |
146 | assert(os.isatty(0));
147 |
148 | fdir = "test_tmp_dir";
149 | fname = "tmp_file.txt";
150 | fpath = fdir + "/" + fname;
151 | link_path = fdir + "/test_link";
152 |
153 | os.remove(link_path);
154 | os.remove(fpath);
155 | os.remove(fdir);
156 |
157 | err = os.mkdir(fdir, 0o755);
158 | assert(err === 0);
159 |
160 | fd = os.open(fpath, os.O_RDWR | os.O_CREAT | os.O_TRUNC);
161 | assert(fd >= 0);
162 |
163 | buf = new Uint8Array(10);
164 | for(i = 0; i < buf.length; i++)
165 | buf[i] = i;
166 | assert(os.write(fd, buf.buffer, 0, buf.length) === buf.length);
167 |
168 | assert(os.seek(fd, 0, std.SEEK_SET) === 0);
169 | buf2 = new Uint8Array(buf.length);
170 | assert(os.read(fd, buf2.buffer, 0, buf2.length) === buf2.length);
171 |
172 | for(i = 0; i < buf.length; i++)
173 | assert(buf[i] == buf2[i]);
174 |
175 | if (typeof BigInt !== "undefined") {
176 | assert(os.seek(fd, BigInt(6), std.SEEK_SET), BigInt(6));
177 | assert(os.read(fd, buf2.buffer, 0, 1) === 1);
178 | assert(buf[6] == buf2[0]);
179 | }
180 |
181 | assert(os.close(fd) === 0);
182 |
183 | [files, err] = os.readdir(fdir);
184 | assert(err, 0);
185 | assert(files.indexOf(fname) >= 0);
186 |
187 | fdate = 10000;
188 |
189 | err = os.utimes(fpath, fdate, fdate);
190 | assert(err, 0);
191 |
192 | [st, err] = os.stat(fpath);
193 | assert(err, 0);
194 | assert(st.mode & os.S_IFMT, os.S_IFREG);
195 | assert(st.mtime, fdate);
196 |
197 | err = os.symlink(fname, link_path);
198 | assert(err === 0);
199 |
200 | [st, err] = os.lstat(link_path);
201 | assert(err, 0);
202 | assert(st.mode & os.S_IFMT, os.S_IFLNK);
203 |
204 | [buf, err] = os.readlink(link_path);
205 | assert(err, 0);
206 | assert(buf, fname);
207 |
208 | assert(os.remove(link_path) === 0);
209 |
210 | [buf, err] = os.getcwd();
211 | assert(err, 0);
212 |
213 | [buf2, err] = os.realpath(".");
214 | assert(err, 0);
215 |
216 | assert(buf, buf2);
217 |
218 | assert(os.remove(fpath) === 0);
219 |
220 | fd = os.open(fpath, os.O_RDONLY);
221 | assert(fd < 0);
222 |
223 | assert(os.remove(fdir) === 0);
224 | }
225 |
226 | function test_os_exec()
227 | {
228 | var ret, fds, pid, f, status;
229 |
230 | ret = os.exec(["true"]);
231 | assert(ret, 0);
232 |
233 | ret = os.exec(["/bin/sh", "-c", "exit 1"], { usePath: false });
234 | assert(ret, 1);
235 |
236 | fds = os.pipe();
237 | pid = os.exec(["sh", "-c", "echo $FOO"], {
238 | stdout: fds[1],
239 | block: false,
240 | env: { FOO: "hello" },
241 | } );
242 | assert(pid >= 0);
243 | os.close(fds[1]); /* close the write end (as it is only in the child) */
244 | f = std.fdopen(fds[0], "r");
245 | assert(f.getline(), "hello");
246 | assert(f.getline(), null);
247 | f.close();
248 | [ret, status] = os.waitpid(pid, 0);
249 | assert(ret, pid);
250 | assert(status & 0x7f, 0); /* exited */
251 | assert(status >> 8, 0); /* exit code */
252 |
253 | pid = os.exec(["cat"], { block: false } );
254 | assert(pid >= 0);
255 | os.kill(pid, os.SIGQUIT);
256 | [ret, status] = os.waitpid(pid, 0);
257 | assert(ret, pid);
258 | assert(status & 0x7f, os.SIGQUIT);
259 | }
260 |
261 | function test_timer()
262 | {
263 | var th, i;
264 |
265 | /* just test that a timer can be inserted and removed */
266 | th = [];
267 | for(i = 0; i < 3; i++)
268 | th[i] = os.setTimeout(function () { }, 1000);
269 | for(i = 0; i < 3; i++)
270 | os.clearTimeout(th[i]);
271 | }
272 |
273 | test_printf();
274 | test_file1();
275 | test_file2();
276 | test_getline();
277 | test_popen();
278 | test_os();
279 | test_os_exec();
280 | test_timer();
281 | test_ext_json();
282 |
--------------------------------------------------------------------------------
/tests/test_loop.js:
--------------------------------------------------------------------------------
1 | function assert(actual, expected, message) {
2 | if (arguments.length == 1)
3 | expected = true;
4 |
5 | if (actual === expected)
6 | return;
7 |
8 | if (actual !== null && expected !== null
9 | && typeof actual == 'object' && typeof expected == 'object'
10 | && actual.toString() === expected.toString())
11 | return;
12 |
13 | throw Error("assertion failed: got |" + actual + "|" +
14 | ", expected |" + expected + "|" +
15 | (message ? " (" + message + ")" : ""));
16 | }
17 |
18 | // load more elaborate version of assert if available
19 | try { __loadScript("test_assert.js"); } catch(e) {}
20 |
21 | /*----------------*/
22 |
23 | function test_while()
24 | {
25 | var i, c;
26 | i = 0;
27 | c = 0;
28 | while (i < 3) {
29 | c++;
30 | i++;
31 | }
32 | assert(c === 3);
33 | }
34 |
35 | function test_while_break()
36 | {
37 | var i, c;
38 | i = 0;
39 | c = 0;
40 | while (i < 3) {
41 | c++;
42 | if (i == 1)
43 | break;
44 | i++;
45 | }
46 | assert(c === 2 && i === 1);
47 | }
48 |
49 | function test_do_while()
50 | {
51 | var i, c;
52 | i = 0;
53 | c = 0;
54 | do {
55 | c++;
56 | i++;
57 | } while (i < 3);
58 | assert(c === 3 && i === 3);
59 | }
60 |
61 | function test_for()
62 | {
63 | var i, c;
64 | c = 0;
65 | for(i = 0; i < 3; i++) {
66 | c++;
67 | }
68 | assert(c === 3 && i === 3);
69 |
70 | c = 0;
71 | for(var j = 0; j < 3; j++) {
72 | c++;
73 | }
74 | assert(c === 3 && j === 3);
75 | }
76 |
77 | function test_for_in()
78 | {
79 | var i, tab, a, b;
80 |
81 | tab = [];
82 | for(i in {x:1, y: 2}) {
83 | tab.push(i);
84 | }
85 | assert(tab.toString(), "x,y", "for_in");
86 |
87 | /* prototype chain test */
88 | a = {x:2, y: 2, "1": 3};
89 | b = {"4" : 3 };
90 | Object.setPrototypeOf(a, b);
91 | tab = [];
92 | for(i in a) {
93 | tab.push(i);
94 | }
95 | assert(tab.toString(), "1,x,y,4", "for_in");
96 |
97 | /* non enumerable properties hide enumerables ones in the
98 | prototype chain */
99 | a = {y: 2, "1": 3};
100 | Object.defineProperty(a, "x", { value: 1 });
101 | b = {"x" : 3 };
102 | Object.setPrototypeOf(a, b);
103 | tab = [];
104 | for(i in a) {
105 | tab.push(i);
106 | }
107 | assert(tab.toString(), "1,y", "for_in");
108 |
109 | /* array optimization */
110 | a = [];
111 | for(i = 0; i < 10; i++)
112 | a.push(i);
113 | tab = [];
114 | for(i in a) {
115 | tab.push(i);
116 | }
117 | assert(tab.toString(), "0,1,2,3,4,5,6,7,8,9", "for_in");
118 |
119 | /* iterate with a field */
120 | a={x:0};
121 | tab = [];
122 | for(a.x in {x:1, y: 2}) {
123 | tab.push(a.x);
124 | }
125 | assert(tab.toString(), "x,y", "for_in");
126 |
127 | /* iterate with a variable field */
128 | a=[0];
129 | tab = [];
130 | for(a[0] in {x:1, y: 2}) {
131 | tab.push(a[0]);
132 | }
133 | assert(tab.toString(), "x,y", "for_in");
134 |
135 | /* variable definition in the for in */
136 | tab = [];
137 | for(var j in {x:1, y: 2}) {
138 | tab.push(j);
139 | }
140 | assert(tab.toString(), "x,y", "for_in");
141 |
142 | /* variable assigment in the for in */
143 | tab = [];
144 | for(var k = 2 in {x:1, y: 2}) {
145 | tab.push(k);
146 | }
147 | assert(tab.toString(), "x,y", "for_in");
148 | }
149 |
150 | function test_for_in2()
151 | {
152 | var i;
153 | tab = [];
154 | for(i in {x:1, y: 2, z:3}) {
155 | if (i === "y")
156 | continue;
157 | tab.push(i);
158 | }
159 | assert(tab.toString() == "x,z");
160 |
161 | tab = [];
162 | for(i in {x:1, y: 2, z:3}) {
163 | if (i === "z")
164 | break;
165 | tab.push(i);
166 | }
167 | assert(tab.toString() == "x,y");
168 | }
169 |
170 | function test_for_break()
171 | {
172 | var i, c;
173 | c = 0;
174 | L1: for(i = 0; i < 3; i++) {
175 | c++;
176 | if (i == 0)
177 | continue;
178 | while (1) {
179 | break L1;
180 | }
181 | }
182 | assert(c === 2 && i === 1);
183 | }
184 |
185 | function test_switch1()
186 | {
187 | var i, a, s;
188 | s = "";
189 | for(i = 0; i < 3; i++) {
190 | a = "?";
191 | switch(i) {
192 | case 0:
193 | a = "a";
194 | break;
195 | case 1:
196 | a = "b";
197 | break;
198 | default:
199 | a = "c";
200 | break;
201 | }
202 | s += a;
203 | }
204 | assert(s === "abc" && i === 3);
205 | }
206 |
207 | function test_switch2()
208 | {
209 | var i, a, s;
210 | s = "";
211 | for(i = 0; i < 4; i++) {
212 | a = "?";
213 | switch(i) {
214 | case 0:
215 | a = "a";
216 | break;
217 | case 1:
218 | a = "b";
219 | break;
220 | case 2:
221 | continue;
222 | default:
223 | a = "" + i;
224 | break;
225 | }
226 | s += a;
227 | }
228 | assert(s === "ab3" && i === 4);
229 | }
230 |
231 | function test_try_catch1()
232 | {
233 | try {
234 | throw "hello";
235 | } catch (e) {
236 | assert(e, "hello", "catch");
237 | return;
238 | }
239 | assert(false, "catch");
240 | }
241 |
242 | function test_try_catch2()
243 | {
244 | var a;
245 | try {
246 | a = 1;
247 | } catch (e) {
248 | a = 2;
249 | }
250 | assert(a, 1, "catch");
251 | }
252 |
253 | function test_try_catch3()
254 | {
255 | var s;
256 | s = "";
257 | try {
258 | s += "t";
259 | } catch (e) {
260 | s += "c";
261 | } finally {
262 | s += "f";
263 | }
264 | assert(s, "tf", "catch");
265 | }
266 |
267 | function test_try_catch4()
268 | {
269 | var s;
270 | s = "";
271 | try {
272 | s += "t";
273 | throw "c";
274 | } catch (e) {
275 | s += e;
276 | } finally {
277 | s += "f";
278 | }
279 | assert(s, "tcf", "catch");
280 | }
281 |
282 | function test_try_catch5()
283 | {
284 | var s;
285 | s = "";
286 | for(;;) {
287 | try {
288 | s += "t";
289 | break;
290 | s += "b";
291 | } finally {
292 | s += "f";
293 | }
294 | }
295 | assert(s, "tf", "catch");
296 | }
297 |
298 | function test_try_catch6()
299 | {
300 | function f() {
301 | try {
302 | s += 't';
303 | return 1;
304 | } finally {
305 | s += "f";
306 | }
307 | }
308 | var s = "";
309 | assert(f() === 1);
310 | assert(s, "tf", "catch6");
311 | }
312 |
313 | function test_try_catch7()
314 | {
315 | var s;
316 | s = "";
317 |
318 | try {
319 | try {
320 | s += "t";
321 | throw "a";
322 | } finally {
323 | s += "f";
324 | }
325 | } catch(e) {
326 | s += e;
327 | } finally {
328 | s += "g";
329 | }
330 | assert(s, "tfag", "catch");
331 | }
332 |
333 | function test_try_catch8()
334 | {
335 | var i, s;
336 |
337 | s = "";
338 | for(var i in {x:1, y:2}) {
339 | try {
340 | s += i;
341 | throw "a";
342 | } catch (e) {
343 | s += e;
344 | } finally {
345 | s += "f";
346 | }
347 | }
348 | assert(s === "xafyaf");
349 | }
350 |
351 | test_while();
352 | test_while_break();
353 | test_do_while();
354 | test_for();
355 | test_for_break();
356 | test_switch1();
357 | test_switch2();
358 | test_for_in();
359 | test_for_in2();
360 |
361 | test_try_catch1();
362 | test_try_catch2();
363 | test_try_catch3();
364 | test_try_catch4();
365 | test_try_catch5();
366 | test_try_catch6();
367 | test_try_catch7();
368 | test_try_catch8();
369 |
--------------------------------------------------------------------------------
/unicode_gen_def.h:
--------------------------------------------------------------------------------
1 | #ifdef UNICODE_GENERAL_CATEGORY
2 | DEF(Cn, "Unassigned") /* must be zero */
3 | DEF(Lu, "Uppercase_Letter")
4 | DEF(Ll, "Lowercase_Letter")
5 | DEF(Lt, "Titlecase_Letter")
6 | DEF(Lm, "Modifier_Letter")
7 | DEF(Lo, "Other_Letter")
8 | DEF(Mn, "Nonspacing_Mark")
9 | DEF(Mc, "Spacing_Mark")
10 | DEF(Me, "Enclosing_Mark")
11 | DEF(Nd, "Decimal_Number,digit")
12 | DEF(Nl, "Letter_Number")
13 | DEF(No, "Other_Number")
14 | DEF(Sm, "Math_Symbol")
15 | DEF(Sc, "Currency_Symbol")
16 | DEF(Sk, "Modifier_Symbol")
17 | DEF(So, "Other_Symbol")
18 | DEF(Pc, "Connector_Punctuation")
19 | DEF(Pd, "Dash_Punctuation")
20 | DEF(Ps, "Open_Punctuation")
21 | DEF(Pe, "Close_Punctuation")
22 | DEF(Pi, "Initial_Punctuation")
23 | DEF(Pf, "Final_Punctuation")
24 | DEF(Po, "Other_Punctuation")
25 | DEF(Zs, "Space_Separator")
26 | DEF(Zl, "Line_Separator")
27 | DEF(Zp, "Paragraph_Separator")
28 | DEF(Cc, "Control,cntrl")
29 | DEF(Cf, "Format")
30 | DEF(Cs, "Surrogate")
31 | DEF(Co, "Private_Use")
32 | /* synthetic properties */
33 | DEF(LC, "Cased_Letter")
34 | DEF(L, "Letter")
35 | DEF(M, "Mark,Combining_Mark")
36 | DEF(N, "Number")
37 | DEF(S, "Symbol")
38 | DEF(P, "Punctuation,punct")
39 | DEF(Z, "Separator")
40 | DEF(C, "Other")
41 | #endif
42 |
43 | #ifdef UNICODE_SCRIPT
44 | /* scripts aliases names in PropertyValueAliases.txt */
45 | DEF(Unknown, "Zzzz")
46 | DEF(Adlam, "Adlm")
47 | DEF(Ahom, "Ahom")
48 | DEF(Anatolian_Hieroglyphs, "Hluw")
49 | DEF(Arabic, "Arab")
50 | DEF(Armenian, "Armn")
51 | DEF(Avestan, "Avst")
52 | DEF(Balinese, "Bali")
53 | DEF(Bamum, "Bamu")
54 | DEF(Bassa_Vah, "Bass")
55 | DEF(Batak, "Batk")
56 | DEF(Bengali, "Beng")
57 | DEF(Bhaiksuki, "Bhks")
58 | DEF(Bopomofo, "Bopo")
59 | DEF(Brahmi, "Brah")
60 | DEF(Braille, "Brai")
61 | DEF(Buginese, "Bugi")
62 | DEF(Buhid, "Buhd")
63 | DEF(Canadian_Aboriginal, "Cans")
64 | DEF(Carian, "Cari")
65 | DEF(Caucasian_Albanian, "Aghb")
66 | DEF(Chakma, "Cakm")
67 | DEF(Cham, "Cham")
68 | DEF(Cherokee, "Cher")
69 | DEF(Chorasmian, "Chrs")
70 | DEF(Common, "Zyyy")
71 | DEF(Coptic, "Copt,Qaac")
72 | DEF(Cuneiform, "Xsux")
73 | DEF(Cypriot, "Cprt")
74 | DEF(Cyrillic, "Cyrl")
75 | DEF(Deseret, "Dsrt")
76 | DEF(Devanagari, "Deva")
77 | DEF(Dives_Akuru, "Diak")
78 | DEF(Dogra, "Dogr")
79 | DEF(Duployan, "Dupl")
80 | DEF(Egyptian_Hieroglyphs, "Egyp")
81 | DEF(Elbasan, "Elba")
82 | DEF(Elymaic, "Elym")
83 | DEF(Ethiopic, "Ethi")
84 | DEF(Georgian, "Geor")
85 | DEF(Glagolitic, "Glag")
86 | DEF(Gothic, "Goth")
87 | DEF(Grantha, "Gran")
88 | DEF(Greek, "Grek")
89 | DEF(Gujarati, "Gujr")
90 | DEF(Gunjala_Gondi, "Gong")
91 | DEF(Gurmukhi, "Guru")
92 | DEF(Han, "Hani")
93 | DEF(Hangul, "Hang")
94 | DEF(Hanifi_Rohingya, "Rohg")
95 | DEF(Hanunoo, "Hano")
96 | DEF(Hatran, "Hatr")
97 | DEF(Hebrew, "Hebr")
98 | DEF(Hiragana, "Hira")
99 | DEF(Imperial_Aramaic, "Armi")
100 | DEF(Inherited, "Zinh,Qaai")
101 | DEF(Inscriptional_Pahlavi, "Phli")
102 | DEF(Inscriptional_Parthian, "Prti")
103 | DEF(Javanese, "Java")
104 | DEF(Kaithi, "Kthi")
105 | DEF(Kannada, "Knda")
106 | DEF(Katakana, "Kana")
107 | DEF(Kayah_Li, "Kali")
108 | DEF(Kharoshthi, "Khar")
109 | DEF(Khmer, "Khmr")
110 | DEF(Khojki, "Khoj")
111 | DEF(Khitan_Small_Script, "Kits")
112 | DEF(Khudawadi, "Sind")
113 | DEF(Lao, "Laoo")
114 | DEF(Latin, "Latn")
115 | DEF(Lepcha, "Lepc")
116 | DEF(Limbu, "Limb")
117 | DEF(Linear_A, "Lina")
118 | DEF(Linear_B, "Linb")
119 | DEF(Lisu, "Lisu")
120 | DEF(Lycian, "Lyci")
121 | DEF(Lydian, "Lydi")
122 | DEF(Makasar, "Maka")
123 | DEF(Mahajani, "Mahj")
124 | DEF(Malayalam, "Mlym")
125 | DEF(Mandaic, "Mand")
126 | DEF(Manichaean, "Mani")
127 | DEF(Marchen, "Marc")
128 | DEF(Masaram_Gondi, "Gonm")
129 | DEF(Medefaidrin, "Medf")
130 | DEF(Meetei_Mayek, "Mtei")
131 | DEF(Mende_Kikakui, "Mend")
132 | DEF(Meroitic_Cursive, "Merc")
133 | DEF(Meroitic_Hieroglyphs, "Mero")
134 | DEF(Miao, "Plrd")
135 | DEF(Modi, "Modi")
136 | DEF(Mongolian, "Mong")
137 | DEF(Mro, "Mroo")
138 | DEF(Multani, "Mult")
139 | DEF(Myanmar, "Mymr")
140 | DEF(Nabataean, "Nbat")
141 | DEF(Nandinagari, "Nand")
142 | DEF(New_Tai_Lue, "Talu")
143 | DEF(Newa, "Newa")
144 | DEF(Nko, "Nkoo")
145 | DEF(Nushu, "Nshu")
146 | DEF(Nyiakeng_Puachue_Hmong, "Hmnp")
147 | DEF(Ogham, "Ogam")
148 | DEF(Ol_Chiki, "Olck")
149 | DEF(Old_Hungarian, "Hung")
150 | DEF(Old_Italic, "Ital")
151 | DEF(Old_North_Arabian, "Narb")
152 | DEF(Old_Permic, "Perm")
153 | DEF(Old_Persian, "Xpeo")
154 | DEF(Old_Sogdian, "Sogo")
155 | DEF(Old_South_Arabian, "Sarb")
156 | DEF(Old_Turkic, "Orkh")
157 | DEF(Oriya, "Orya")
158 | DEF(Osage, "Osge")
159 | DEF(Osmanya, "Osma")
160 | DEF(Pahawh_Hmong, "Hmng")
161 | DEF(Palmyrene, "Palm")
162 | DEF(Pau_Cin_Hau, "Pauc")
163 | DEF(Phags_Pa, "Phag")
164 | DEF(Phoenician, "Phnx")
165 | DEF(Psalter_Pahlavi, "Phlp")
166 | DEF(Rejang, "Rjng")
167 | DEF(Runic, "Runr")
168 | DEF(Samaritan, "Samr")
169 | DEF(Saurashtra, "Saur")
170 | DEF(Sharada, "Shrd")
171 | DEF(Shavian, "Shaw")
172 | DEF(Siddham, "Sidd")
173 | DEF(SignWriting, "Sgnw")
174 | DEF(Sinhala, "Sinh")
175 | DEF(Sogdian, "Sogd")
176 | DEF(Sora_Sompeng, "Sora")
177 | DEF(Soyombo, "Soyo")
178 | DEF(Sundanese, "Sund")
179 | DEF(Syloti_Nagri, "Sylo")
180 | DEF(Syriac, "Syrc")
181 | DEF(Tagalog, "Tglg")
182 | DEF(Tagbanwa, "Tagb")
183 | DEF(Tai_Le, "Tale")
184 | DEF(Tai_Tham, "Lana")
185 | DEF(Tai_Viet, "Tavt")
186 | DEF(Takri, "Takr")
187 | DEF(Tamil, "Taml")
188 | DEF(Tangut, "Tang")
189 | DEF(Telugu, "Telu")
190 | DEF(Thaana, "Thaa")
191 | DEF(Thai, "Thai")
192 | DEF(Tibetan, "Tibt")
193 | DEF(Tifinagh, "Tfng")
194 | DEF(Tirhuta, "Tirh")
195 | DEF(Ugaritic, "Ugar")
196 | DEF(Vai, "Vaii")
197 | DEF(Wancho, "Wcho")
198 | DEF(Warang_Citi, "Wara")
199 | DEF(Yezidi, "Yezi")
200 | DEF(Yi, "Yiii")
201 | DEF(Zanabazar_Square, "Zanb")
202 | #endif
203 |
204 | #ifdef UNICODE_PROP_LIST
205 | /* Prop list not exported to regexp */
206 | DEF(Hyphen, "")
207 | DEF(Other_Math, "")
208 | DEF(Other_Alphabetic, "")
209 | DEF(Other_Lowercase, "")
210 | DEF(Other_Uppercase, "")
211 | DEF(Other_Grapheme_Extend, "")
212 | DEF(Other_Default_Ignorable_Code_Point, "")
213 | DEF(Other_ID_Start, "")
214 | DEF(Other_ID_Continue, "")
215 | DEF(Prepended_Concatenation_Mark, "")
216 | /* additional computed properties for smaller tables */
217 | DEF(ID_Continue1, "")
218 | DEF(XID_Start1, "")
219 | DEF(XID_Continue1, "")
220 | DEF(Changes_When_Titlecased1, "")
221 | DEF(Changes_When_Casefolded1, "")
222 | DEF(Changes_When_NFKC_Casefolded1, "")
223 |
224 | /* Prop list exported to JS */
225 | DEF(ASCII_Hex_Digit, "AHex")
226 | DEF(Bidi_Control, "Bidi_C")
227 | DEF(Dash, "")
228 | DEF(Deprecated, "Dep")
229 | DEF(Diacritic, "Dia")
230 | DEF(Extender, "Ext")
231 | DEF(Hex_Digit, "Hex")
232 | DEF(IDS_Binary_Operator, "IDSB")
233 | DEF(IDS_Trinary_Operator, "IDST")
234 | DEF(Ideographic, "Ideo")
235 | DEF(Join_Control, "Join_C")
236 | DEF(Logical_Order_Exception, "LOE")
237 | DEF(Noncharacter_Code_Point, "NChar")
238 | DEF(Pattern_Syntax, "Pat_Syn")
239 | DEF(Pattern_White_Space, "Pat_WS")
240 | DEF(Quotation_Mark, "QMark")
241 | DEF(Radical, "")
242 | DEF(Regional_Indicator, "RI")
243 | DEF(Sentence_Terminal, "STerm")
244 | DEF(Soft_Dotted, "SD")
245 | DEF(Terminal_Punctuation, "Term")
246 | DEF(Unified_Ideograph, "UIdeo")
247 | DEF(Variation_Selector, "VS")
248 | DEF(White_Space, "space")
249 | DEF(Bidi_Mirrored, "Bidi_M")
250 | DEF(Emoji, "")
251 | DEF(Emoji_Component, "EComp")
252 | DEF(Emoji_Modifier, "EMod")
253 | DEF(Emoji_Modifier_Base, "EBase")
254 | DEF(Emoji_Presentation, "EPres")
255 | DEF(Extended_Pictographic, "ExtPict")
256 | DEF(Default_Ignorable_Code_Point, "DI")
257 | DEF(ID_Start, "IDS")
258 | DEF(Case_Ignorable, "CI")
259 |
260 | /* other binary properties */
261 | DEF(ASCII,"")
262 | DEF(Alphabetic, "Alpha")
263 | DEF(Any, "")
264 | DEF(Assigned,"")
265 | DEF(Cased, "")
266 | DEF(Changes_When_Casefolded, "CWCF")
267 | DEF(Changes_When_Casemapped, "CWCM")
268 | DEF(Changes_When_Lowercased, "CWL")
269 | DEF(Changes_When_NFKC_Casefolded, "CWKCF")
270 | DEF(Changes_When_Titlecased, "CWT")
271 | DEF(Changes_When_Uppercased, "CWU")
272 | DEF(Grapheme_Base, "Gr_Base")
273 | DEF(Grapheme_Extend, "Gr_Ext")
274 | DEF(ID_Continue, "IDC")
275 | DEF(Lowercase, "Lower")
276 | DEF(Math, "")
277 | DEF(Uppercase, "Upper")
278 | DEF(XID_Continue, "XIDC")
279 | DEF(XID_Start, "XIDS")
280 |
281 | /* internal tables with index */
282 | DEF(Cased1, "")
283 |
284 | #endif
285 |
--------------------------------------------------------------------------------
/quickjs-atom.h:
--------------------------------------------------------------------------------
1 | /*
2 | * QuickJS atom definitions
3 | *
4 | * Copyright (c) 2017-2018 Fabrice Bellard
5 | * Copyright (c) 2017-2018 Charlie Gordon
6 | *
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * of this software and associated documentation files (the "Software"), to deal
9 | * in the Software without restriction, including without limitation the rights
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * copies of the Software, and to permit persons to whom the Software is
12 | * furnished to do so, subject to the following conditions:
13 | *
14 | * The above copyright notice and this permission notice shall be included in
15 | * all copies or substantial portions of the Software.
16 | *
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 | * THE SOFTWARE.
24 | */
25 |
26 | #ifdef DEF
27 |
28 | /* Note: first atoms are considered as keywords in the parser */
29 | DEF(null, "null") /* must be first */
30 | DEF(false, "false")
31 | DEF(true, "true")
32 | DEF(if, "if")
33 | DEF(else, "else")
34 | DEF(return, "return")
35 | DEF(var, "var")
36 | DEF(this, "this")
37 | DEF(delete, "delete")
38 | DEF(void, "void")
39 | DEF(typeof, "typeof")
40 | DEF(new, "new")
41 | DEF(in, "in")
42 | DEF(instanceof, "instanceof")
43 | DEF(do, "do")
44 | DEF(while, "while")
45 | DEF(for, "for")
46 | DEF(break, "break")
47 | DEF(continue, "continue")
48 | DEF(switch, "switch")
49 | DEF(case, "case")
50 | DEF(default, "default")
51 | DEF(throw, "throw")
52 | DEF(try, "try")
53 | DEF(catch, "catch")
54 | DEF(finally, "finally")
55 | DEF(function, "function")
56 | DEF(debugger, "debugger")
57 | DEF(with, "with")
58 | DEF(__file__, "__FILE__")
59 | DEF(__dir__, "__DIR__")
60 | /* FutureReservedWord */
61 | DEF(class, "class")
62 | DEF(const, "const")
63 | DEF(enum, "enum")
64 | DEF(export, "export")
65 | DEF(extends, "extends")
66 | DEF(import, "import")
67 | DEF(super, "super")
68 | /* FutureReservedWords when parsing strict mode code */
69 | DEF(implements, "implements")
70 | DEF(interface, "interface")
71 | DEF(let, "let")
72 | DEF(package, "package")
73 | DEF(private, "private")
74 | DEF(protected, "protected")
75 | DEF(public, "public")
76 | DEF(static, "static")
77 | DEF(yield, "yield")
78 | DEF(await, "await")
79 |
80 | /* empty string */
81 | DEF(empty_string, "")
82 | /* identifiers */
83 | DEF(length, "length")
84 | DEF(tag, "tag")
85 | DEF(fileName, "fileName")
86 | DEF(lineNumber, "lineNumber")
87 | DEF(message, "message")
88 | DEF(errors, "errors")
89 | DEF(stack, "stack")
90 | DEF(name, "name")
91 | DEF(toString, "toString")
92 | DEF(toLocaleString, "toLocaleString")
93 | DEF(valueOf, "valueOf")
94 | DEF(eval, "eval")
95 | DEF(prototype, "prototype")
96 | DEF(constructor, "constructor")
97 | DEF(configurable, "configurable")
98 | DEF(writable, "writable")
99 | DEF(enumerable, "enumerable")
100 | DEF(value, "value")
101 | DEF(get, "get")
102 | DEF(set, "set")
103 | DEF(of, "of")
104 | DEF(__proto__, "__proto__")
105 | DEF(undefined, "undefined")
106 | DEF(number, "number")
107 | DEF(boolean, "boolean")
108 | DEF(string, "string")
109 | DEF(object, "object")
110 | DEF(symbol, "symbol")
111 | DEF(integer, "integer")
112 | DEF(unknown, "unknown")
113 | DEF(arguments, "arguments")
114 | DEF(callee, "callee")
115 | DEF(caller, "caller")
116 | DEF(_eval_, "")
117 | DEF(_ret_, "")
118 | DEF(_var_, "")
119 | DEF(_arg_var_, "")
120 | DEF(_with_, "")
121 | DEF(lastIndex, "lastIndex")
122 | DEF(target, "target")
123 | DEF(index, "index")
124 | DEF(input, "input")
125 | DEF(defineProperties, "defineProperties")
126 | DEF(apply, "apply")
127 | DEF(join, "join")
128 | DEF(concat, "concat")
129 | DEF(split, "split")
130 | DEF(construct, "construct")
131 | DEF(getPrototypeOf, "getPrototypeOf")
132 | DEF(setPrototypeOf, "setPrototypeOf")
133 | DEF(isExtensible, "isExtensible")
134 | DEF(preventExtensions, "preventExtensions")
135 | DEF(has, "has")
136 | DEF(deleteProperty, "deleteProperty")
137 | DEF(defineProperty, "defineProperty")
138 | DEF(getOwnPropertyDescriptor, "getOwnPropertyDescriptor")
139 | DEF(ownKeys, "ownKeys")
140 | DEF(add, "add")
141 | DEF(done, "done")
142 | DEF(next, "next")
143 | DEF(values, "values")
144 | DEF(source, "source")
145 | DEF(flags, "flags")
146 | DEF(global, "global")
147 | DEF(unicode, "unicode")
148 | DEF(raw, "raw")
149 | DEF(new_target, "new.target")
150 | DEF(this_active_func, "this.active_func")
151 | DEF(home_object, "")
152 | DEF(computed_field, "")
153 | DEF(static_computed_field, "") /* must come after computed_fields */
154 | DEF(class_fields_init, "")
155 | DEF(brand, "")
156 | DEF(hash_constructor, "#constructor")
157 | DEF(as, "as")
158 | DEF(from, "from")
159 | DEF(meta, "meta")
160 | DEF(_default_, "*default*")
161 | DEF(_star_, "*")
162 | DEF(Module, "Module")
163 | DEF(then, "then")
164 | DEF(resolve, "resolve")
165 | DEF(reject, "reject")
166 | DEF(promise, "promise")
167 | DEF(proxy, "proxy")
168 | DEF(revoke, "revoke")
169 | DEF(async, "async")
170 | DEF(exec, "exec")
171 | DEF(groups, "groups")
172 | DEF(status, "status")
173 | DEF(reason, "reason")
174 | DEF(globalThis, "globalThis")
175 | #ifdef CONFIG_BIGNUM
176 | DEF(bigint, "bigint")
177 | DEF(bigfloat, "bigfloat")
178 | DEF(bigdecimal, "bigdecimal")
179 | DEF(roundingMode, "roundingMode")
180 | DEF(maximumSignificantDigits, "maximumSignificantDigits")
181 | DEF(maximumFractionDigits, "maximumFractionDigits")
182 | #endif
183 | #ifdef CONFIG_ATOMICS
184 | DEF(not_equal, "not-equal")
185 | DEF(timed_out, "timed-out")
186 | DEF(ok, "ok")
187 | #endif
188 | DEF(toJSON, "toJSON")
189 | /* class names */
190 | DEF(Object, "Object")
191 | DEF(Array, "Array")
192 | DEF(Error, "Error")
193 | DEF(Number, "Number")
194 | DEF(String, "String")
195 | DEF(Boolean, "Boolean")
196 | DEF(Symbol, "Symbol")
197 | DEF(Arguments, "Arguments")
198 | DEF(Math, "Math")
199 | DEF(JSON, "JSON")
200 | DEF(Date, "Date")
201 | DEF(Function, "Function")
202 | DEF(GeneratorFunction, "GeneratorFunction")
203 | DEF(ForInIterator, "ForInIterator")
204 | DEF(RegExp, "RegExp")
205 | DEF(ArrayBuffer, "ArrayBuffer")
206 | DEF(SharedArrayBuffer, "SharedArrayBuffer")
207 | /* must keep same order as class IDs for typed arrays */
208 | DEF(Uint8ClampedArray, "Uint8ClampedArray")
209 | DEF(Int8Array, "Int8Array")
210 | DEF(Uint8Array, "Uint8Array")
211 | DEF(Int16Array, "Int16Array")
212 | DEF(Uint16Array, "Uint16Array")
213 | DEF(Int32Array, "Int32Array")
214 | DEF(Uint32Array, "Uint32Array")
215 | #ifdef CONFIG_BIGNUM
216 | DEF(BigInt64Array, "BigInt64Array")
217 | DEF(BigUint64Array, "BigUint64Array")
218 | #endif
219 | DEF(Float32Array, "Float32Array")
220 | DEF(Float64Array, "Float64Array")
221 | DEF(DataView, "DataView")
222 | #ifdef CONFIG_BIGNUM
223 | DEF(BigInt, "BigInt")
224 | DEF(BigFloat, "BigFloat")
225 | DEF(BigFloatEnv, "BigFloatEnv")
226 | DEF(BigDecimal, "BigDecimal")
227 | DEF(OperatorSet, "OperatorSet")
228 | DEF(Operators, "Operators")
229 | #endif
230 | #ifdef CONFIG_JSX
231 | DEF(JSX, "JSX")
232 | #endif
233 | DEF(Map, "Map")
234 | DEF(Set, "Set") /* Map + 1 */
235 | DEF(WeakMap, "WeakMap") /* Map + 2 */
236 | DEF(WeakSet, "WeakSet") /* Map + 3 */
237 | DEF(Map_Iterator, "Map Iterator")
238 | DEF(Set_Iterator, "Set Iterator")
239 | DEF(Array_Iterator, "Array Iterator")
240 | DEF(String_Iterator, "String Iterator")
241 | DEF(RegExp_String_Iterator, "RegExp String Iterator")
242 | DEF(Generator, "Generator")
243 | DEF(Proxy, "Proxy")
244 | DEF(Promise, "Promise")
245 | DEF(PromiseResolveFunction, "PromiseResolveFunction")
246 | DEF(PromiseRejectFunction, "PromiseRejectFunction")
247 | DEF(AsyncFunction, "AsyncFunction")
248 | DEF(AsyncFunctionResolve, "AsyncFunctionResolve")
249 | DEF(AsyncFunctionReject, "AsyncFunctionReject")
250 | DEF(AsyncGeneratorFunction, "AsyncGeneratorFunction")
251 | DEF(AsyncGenerator, "AsyncGenerator")
252 | DEF(EvalError, "EvalError")
253 | DEF(RangeError, "RangeError")
254 | DEF(ReferenceError, "ReferenceError")
255 | DEF(SyntaxError, "SyntaxError")
256 | DEF(TypeError, "TypeError")
257 | DEF(URIError, "URIError")
258 | DEF(InternalError, "InternalError")
259 | /* private symbols */
260 | DEF(Private_brand, "")
261 | /* symbols */
262 | DEF(Symbol_toPrimitive, "Symbol.toPrimitive")
263 | DEF(Symbol_iterator, "Symbol.iterator")
264 | DEF(Symbol_match, "Symbol.match")
265 | DEF(Symbol_matchAll, "Symbol.matchAll")
266 | DEF(Symbol_replace, "Symbol.replace")
267 | DEF(Symbol_search, "Symbol.search")
268 | DEF(Symbol_split, "Symbol.split")
269 | DEF(Symbol_toStringTag, "Symbol.toStringTag")
270 | DEF(Symbol_isConcatSpreadable, "Symbol.isConcatSpreadable")
271 | DEF(Symbol_hasInstance, "Symbol.hasInstance")
272 | DEF(Symbol_species, "Symbol.species")
273 | DEF(Symbol_unscopables, "Symbol.unscopables")
274 | DEF(Symbol_asyncIterator, "Symbol.asyncIterator")
275 | #ifdef CONFIG_BIGNUM
276 | DEF(Symbol_operatorSet, "Symbol.operatorSet")
277 | #endif
278 |
279 | DEF(Symbol_tag, "Symbol.tag")
280 |
281 |
282 | #endif /* DEF */
283 |
--------------------------------------------------------------------------------
/storage/doc/introduction.md:
--------------------------------------------------------------------------------
1 | ## Introduction
2 |
3 | This module provides built-in data persistence - data storage and retrieval.
4 |
5 | “Built-in” here means that there is no special entity like Database Access Client or Database Driver in the language to access persistent data – it is rather that objects in storage (database file) are ordinary script entities: objects (key/value maps), arrays (lists of values), and primitive types (string, integer, long (a.k.a. BigInt), float, date, byte-vectors (ArrayBuffer), boolean and null).
6 |
7 | You can think of QuickJS+persistence as a script with built-in NoSQL database mechanism where access to data in DB is provided by standard language means: get/set properties of stored objects or get/set elements of stored arrays and indexes.
8 |
9 | To support persistence this module introduces two helper classes: Storage and Index.
10 |
11 | ## Storage
12 |
13 | Storage object represents database file in script. It is used as to create databases as to open existing databases to get access to data stored in them.
14 |
15 | To create or open existing database you will use ```Storage.open(path)``` method. On success this method returns instance of Storage class that has few properties and methods, the most interesting of them is ```storage.root``` property:
16 |
17 | ### ```storage.root```
18 |
19 | ```storage.root``` property is a reference to stored root object (or array).
20 |
21 | > **All objects accessible from (contained in) the ```storage.root``` object are automatically persistent – stored in the DB.**
22 |
23 | As simple as that. ```storage.root``` is ordinary script object that can be used by standard script means to access and/or modify data in storage.
24 |
25 | When you will make any change in any object or collection under that root object it will be stored to the database (a.k.a. persisted) without need to send that data anywhere or call any method explicitly.
26 |
27 | #### Example #1, storage opening and its structure initialization:
28 |
29 | Idiomatic code to open or create database looks like this:
30 |
31 | ```JavaScript
32 | import * as Storage from "storage"; // or "@storage" if Sciter.JS
33 |
34 | var storage = Storage.open("path/to/data/file.db");
35 | var root = storage.root || initDb(storage); // get root data object or initialize DB
36 | ```
37 |
38 | where ```initDb(storage)``` is called only when storage was just created and so is empty – its root is null in this case. That function may look like as:
39 |
40 | ```JavaScript
41 | function initDb(storage) {
42 | storage.root = {
43 | version: 1, // integer property ("integer field" in DB terms)
44 | meta: {}, // sub-object
45 | children: [] // sub-array, empty initially
46 | };
47 | return storage.root;
48 | }
49 | ```
50 |
51 |
52 | #### Example #2, accessing and populating persistent data:
53 |
54 | Having the ```root``` variable containing persistent root object, we can access and populate the data in it as we normally do – no other special mechanism is required:
55 |
56 | ```JavaScript
57 | // printout elements of root.children collection (array)
58 |
59 | let root = storage.root;
60 | for( let child of root.children )
61 | console.log(child.name, child.nickname);
62 | }
63 | ```
64 |
65 | In the same way, to populate the data in storage we use standard JavaScript means:
66 |
67 | ```JavaScript
68 | var collection = root.children; // plain JS array
69 | collection.push( { name: "Mikky", age: 7 } ); // calling Array's method push() to add
70 | collection.push( { name: "Olly", age: 6 } ); // objects to the collection
71 | collection.push( { name: "Linus", age: 5 } );
72 | }
73 | ```
74 |
75 | Nothing special as you see – the code is not anyhow different from ordinary script code accessing and populating any data in script heap.
76 |
77 | ## Index
78 |
79 | By default JavaScript supports collections of these built-in types:
80 |
81 | * objects – unordered name/value maps and
82 | * arrays – ordered lists of values with access by index (some integer).
83 | * auxiliary collections - [Weak]Map and [Weak]Set.
84 |
85 | These collections allow to organize data in various ways but sometimes these are not enough. We may need something in between of them – collections that are a) ordered but b) allow to access elements by keys at the same time. Example: we may need collection of objects that is ordered by their time of creation so we can present the collection to the user in data “freshness” order.
86 |
87 | To support such use cases the module introduces Index objects.
88 |
89 | > **Index is a keyed persistent collection that can be assigned to properties of other persistent objects or placed into arrays. Indexes provide effective access and ordering of potentially large data sets.**
90 |
91 | Indexes support string, integer, long (BigInt), float and date keys and contain objects as index elements (a.k.a. records).
92 |
93 | ### Defining and populating indexes
94 |
95 | Indexes are created by ```storage.createIndex(type[,unique]) : Index``` method, where
96 |
97 | * *type* defines type of keys in the index. It can be "string", "integer", "long", "float" or "date".
98 | * *unique* is either
99 | * *true* if the index support only unique keys, or
100 | * *false* if records with the same key values are allowed in the index.
101 |
102 | #### Example #3: creating indexes, simple storage of notes:
103 |
104 | To open storage database we can reuse code above, but storage initialization routine will look different this time:
105 |
106 | ```JavaScript
107 | function initNotesDb(storage) {
108 | storage.root = {
109 | version: 1,
110 | notesByDate: storage.createIndex("date",false), // list of notes indexed by date of creation
111 | notesById: storage.createIndex("string",true) // list of notes indexed by their UID
112 | }
113 | return storage.root;
114 | }
115 | ```
116 |
117 | As you see the storage contains two indexes: one will list notes by their date of creation and other will contain the same notes but ordered by unique ID.
118 |
119 | Having such setup, adding notes to DB is trivial:
120 |
121 | ```JavaScript
122 | function addNote(storage, noteText) {
123 | var note = {
124 | id : UUID.create(), // generate UID
125 | date : new Date(),
126 | text : noteText
127 | };
128 | storage.root.notesByDate.set(note.date, note); // adding the note
129 | storage.root.notesById.set(note.id, note); // to indexes
130 | return note; // returns constructed note object to the caller
131 | }
132 | ```
133 |
134 | We use here ```index.set(key,value)``` method to add items.
135 |
136 | ### Index selection – traversal and retrieval of index items
137 |
138 | Getting elements of unique indexes is trivial – we use ```index.get(key)``` method similar to methods of standard Map or Set collections:
139 |
140 | ```JavaScript
141 | function getNoteById(noteId) {
142 | return storage.root.notesById.get(noteId); // returns the note or undefined
143 | }
144 | ```
145 |
146 | To get items from non-unique indexes we need pair of keys to get items in range between keys by using ```index.select()``` method:
147 |
148 | ```JavaScript
149 | function getTodayNotes() {
150 | let now = new Date();
151 | let yesterday = new Date(now.year,now.month,now.day-1);
152 | var notes = [];
153 | for(let note of storage.root.select(yesterday,now)) // get range of notes from the index
154 | notes.push(note);
155 | return notes;
156 | }
157 | ```
158 |
159 | ## Persistence of objects of custom classes
160 |
161 | So far we were dealing with plain objects and arrays, but the Storage allows to store objects of custom classes too. This can be useful if your data objects have specific methods. Let’s refactor our notes storage to use it in OOP way:
162 |
163 |
164 | ```JavaScript
165 | // module NotesDB.js
166 |
167 | import * as Storage from "storage"; // or "@storage" if Sciter.JS
168 |
169 | const storage = ... open DB and optionally initialize the DB ...
170 |
171 | class Note {
172 |
173 | constructor(text, date = undefined, id = undefined) {
174 | this.id = id || UUID.create();
175 | this.date = date || new Date();
176 | this.text = text;
177 |
178 | // adding it to storage
179 | let root = storage.root;
180 | root.notesByDate.set(this.date, this);
181 | root.notesById.set(this.id, this);
182 | }
183 |
184 | remove() {
185 | let root = storage.root;
186 | root.notesByDate.delete(this.date, this); // need 'this' here as index is not unique
187 | root.notesById.delete(this.id);
188 | }
189 |
190 | static getById(id) {
191 | return storage.root.notesById.get(id); // will fetch object from DB and do
192 | // Object.setPrototypeOf(note,Note.prototype)
193 | }
194 | }
195 | ```
196 |
197 | Technical details: while storing objects of customs classes, the Storage will store just name of object’s class. Database cannot contain neither classes themselves nor any functions – just pure data. On loading objects of custom classes, the runtime will try to bind classes from current scopes with instances of objects by updating prototype field of such objects.
198 |
199 | ## As an afterword
200 |
201 | [Sciter Notes](https://notes.sciter.com/) application is a practical example of Storage use.
202 |
203 | That particular application uses Sciter/TIScript but principles are the same. You can see it’s [database handling routines on GitHub](https://github.com/c-smile/sciter-sdk/tree/master/notes/res/db), in particular its DB initialization may look in JS as:
204 |
205 | ```JavaScript
206 | //|
207 | //| open database and initialze it if needed
208 | //|
209 |
210 | function openDatabase(pathname)
211 | {
212 | //const DBNAME = "sciter-notes.db";
213 | //const pathname = dbPathFromArgs() || ...;
214 | var ndb = Storage.open(pathname);
215 | if(!ndb.root) {
216 | // new db, initialize structure
217 | ndb.root =
218 | {
219 | id2item :ndb.createIndex("string", true), // main index, item.id -> item, unique
220 | date2item :ndb.createIndex("date", false), // item by date of creation index, item.cdate -> item, not unique
221 | tags :{}, // map of tagid -> tag
222 | books :{}, // map of bookid -> book;
223 | version :1,
224 | };
225 | }
226 | ndb.path = pathname;
227 | return ndb;
228 | }
229 | ```
230 |
231 |
--------------------------------------------------------------------------------
/storage/dybase/src/dybase.cpp:
--------------------------------------------------------------------------------
1 |
2 | #include "stdtp.h"
3 | #include "database.h"
4 |
5 | #define INSIDE_DYBASE
6 |
7 | #include "btree.h"
8 | #include "dybase.h"
9 |
10 | dybase_storage_t dybase_open(const char *file_path, int page_pool_size,
11 | dybase_error_handler_t hnd, int read_write) {
12 | try {
13 | if (page_pool_size == 0) { page_pool_size = dbDefaultPagePoolSize; }
14 |
15 | dbDatabase::dbAccessType at =
16 | read_write ? dbDatabase::dbAllAccess : dbDatabase::dbReadOnly;
17 |
18 | dbDatabase *db = new dbDatabase(at, (dbDatabase::dbErrorHandler)hnd,
19 | page_pool_size / dbPageSize);
20 | if (db->open(file_path)) {
21 | return db;
22 | } else {
23 | delete db;
24 | return NULL;
25 | }
26 | } catch (dbException &) {
27 | return NULL;
28 | }
29 | }
30 |
31 | void dybase_close(dybase_storage_t storage) {
32 | dbDatabase *db = (dbDatabase *)storage;
33 | try {
34 | db->close();
35 | delete db;
36 | } catch (dbException &) { delete db; }
37 | }
38 |
39 | void dybase_commit(dybase_storage_t storage) {
40 | try {
41 | ((dbDatabase *)storage)->commit();
42 | } catch (dbException &) {}
43 | }
44 |
45 | void dybase_rollback(dybase_storage_t storage) {
46 | try {
47 | ((dbDatabase *)storage)->rollback();
48 | } catch (dbException &) {}
49 | }
50 |
51 | dybase_oid_t dybase_get_root_object(dybase_storage_t storage) {
52 | // try {
53 | return ((dbDatabase *)storage)->getRoot();
54 | //} catch (dbException&) {
55 | // return 0;
56 | //}
57 | }
58 |
59 | void dybase_set_root_object(dybase_storage_t storage, dybase_oid_t oid) {
60 | try {
61 | ((dbDatabase *)storage)->setRoot(oid);
62 | } catch (dbException &) {}
63 | }
64 |
65 | dybase_oid_t dybase_allocate_object(dybase_storage_t storage) {
66 | try {
67 | return ((dbDatabase *)storage)->allocate();
68 | } catch (dbException &) { return 0; }
69 | }
70 |
71 | void dybase_deallocate_object(dybase_storage_t storage, dybase_oid_t oid) {
72 | try {
73 | ((dbDatabase *)storage)->freeObject(oid);
74 | } catch (dbException &) {}
75 | }
76 |
77 | dybase_handle_t dybase_begin_store_object(dybase_storage_t storage,
78 | dybase_oid_t oid,
79 | char const * class_name) {
80 | try {
81 | return ((dbDatabase *)storage)->getStoreHandle(oid, class_name);
82 | } catch (dbException &) { return NULL; }
83 | }
84 |
85 | void dybase_store_object_field(dybase_handle_t handle, char const *field_name,
86 | int field_type, void *value_ptr,
87 | int value_length) {
88 | try {
89 | ((dbStoreHandle *)handle)
90 | ->setFieldValue(field_name, field_type, value_ptr, value_length);
91 | } catch (dbException &) {}
92 | }
93 |
94 | void dybase_store_array_element(dybase_handle_t handle, int elem_type,
95 | void *value_ptr, int value_length) {
96 | try {
97 | ((dbStoreHandle *)handle)->setElement(elem_type, value_ptr, value_length);
98 | } catch (dbException &) {}
99 | }
100 |
101 | void dybase_store_map_entry(dybase_handle_t handle, int key_type, void *key_ptr,
102 | int key_length, int value_type, void *value_ptr,
103 | int value_length) {
104 | try {
105 | ((dbStoreHandle *)handle)->setElement(key_type, key_ptr, key_length);
106 | ((dbStoreHandle *)handle)->setElement(value_type, value_ptr, value_length);
107 | } catch (dbException &) {}
108 | }
109 |
110 | void dybase_end_store_object(dybase_handle_t handle) {
111 | dbStoreHandle *hnd = (dbStoreHandle *)handle;
112 | try {
113 | hnd->db->storeObject(hnd);
114 | delete hnd;
115 | } catch (dbException &) { delete hnd; }
116 | }
117 |
118 | dybase_handle_t dybase_begin_load_object(dybase_storage_t storage,
119 | dybase_oid_t oid) {
120 | try {
121 | return ((dbDatabase *)storage)->getLoadHandle(oid);
122 | } catch (dbException &) { return NULL; }
123 | }
124 |
125 | void dybase_end_load_object(dybase_handle_t handle) {
126 | if (handle) {
127 | dbLoadHandle *hnd = (dbLoadHandle *)handle;
128 | assert(hnd);
129 | delete hnd;
130 | }
131 | }
132 |
133 | char *dybase_get_class_name(dybase_handle_t handle) {
134 | return ((dbLoadHandle *)handle)->getClassName();
135 | }
136 |
137 | char *dybase_next_field(dybase_handle_t handle) {
138 | dbLoadHandle *hnd = (dbLoadHandle *)handle;
139 | if (!hnd->hasNextField()) {
140 | delete hnd;
141 | return NULL;
142 | } else {
143 | return hnd->getFieldName();
144 | }
145 | }
146 |
147 | void dybase_next_element(dybase_handle_t handle) {
148 | bool hasNext = ((dbLoadHandle *)handle)->hasNext();
149 | assert(hasNext);
150 | hasNext = hasNext;
151 | }
152 |
153 | void dybase_get_value(dybase_handle_t handle, int *type, void **value_ptr,
154 | int *value_length) {
155 | dbLoadHandle *hnd = (dbLoadHandle *)handle;
156 | *type = hnd->getType();
157 | *value_ptr = hnd->getValue();
158 | *value_length = hnd->getLength();
159 | }
160 |
161 | dybase_oid_t dybase_create_index(dybase_storage_t storage, int key_type,
162 | int unique) {
163 | try {
164 | return dbBtree::allocate((dbDatabase *)storage, key_type, (bool)unique);
165 | } catch (dbException &) { return 0; }
166 | }
167 |
168 | int dybase_insert_in_index(dybase_storage_t storage, dybase_oid_t index,
169 | void *key, int key_type, int key_size,
170 | dybase_oid_t obj, int replace) {
171 | try {
172 | return dbBtree::insert((dbDatabase *)storage, (oid_t)index, key, key_type,
173 | key_size, (oid_t)obj, (bool)replace);
174 | } catch (dbException &) { return 0; }
175 | }
176 |
177 | int dybase_remove_from_index(dybase_storage_t storage, dybase_oid_t index,
178 | void *key, int key_type, int key_size,
179 | dybase_oid_t obj) {
180 | try {
181 | return dbBtree::remove((dbDatabase *)storage, (oid_t)index, key, key_type,
182 | key_size, (oid_t)obj);
183 | } catch (dbException &) { return 0; }
184 | }
185 |
186 | int dybase_is_index_unique(dybase_storage_t storage, dybase_oid_t index) {
187 | try {
188 | return dbBtree::is_unique((dbDatabase *)storage, (oid_t)index);
189 | } catch (dbException &) { return 0; }
190 | }
191 |
192 | int dybase_get_index_type(dybase_storage_t storage, dybase_oid_t index) {
193 | try {
194 | return dbBtree::get_type((dbDatabase *)storage, (oid_t)index);
195 | }
196 | catch (dbException &) { return 0; }
197 | }
198 |
199 | int dybase_index_search(dybase_storage_t storage, dybase_oid_t index,
200 | int key_type, void *min_key, int min_key_size,
201 | int min_key_inclusive, void *max_key, int max_key_size,
202 | int max_key_inclusive,
203 | dybase_oid_t **selected_objects) {
204 | try {
205 | dbSearchContext ctx;
206 | ctx.low = min_key;
207 | ctx.lowSize = min_key_size;
208 | ctx.lowInclusive = min_key_inclusive;
209 | ctx.high = max_key;
210 | ctx.highSize = max_key_size;
211 | ctx.highInclusive = max_key_inclusive;
212 | ctx.keyType = key_type;
213 | dbBtree::find((dbDatabase *)storage, (oid_t)index, ctx);
214 | *selected_objects = ctx.selection.grab();
215 | return ctx.selection.size();
216 | } catch (dbException &) { return 0; }
217 | }
218 |
219 | void dybase_free_selection(dybase_storage_t /*storage*/,
220 | dybase_oid_t *selected_objects, int /*n_selected*/) {
221 | try {
222 | delete[] selected_objects;
223 | } catch (dbException &) {}
224 | }
225 |
226 | void dybase_drop_index(dybase_storage_t storage, dybase_oid_t index) {
227 | try {
228 | dbBtree::drop((dbDatabase *)storage, (oid_t)index);
229 | } catch (dbException &) {}
230 | }
231 |
232 | void dybase_clear_index(dybase_storage_t storage, dybase_oid_t index) {
233 | try {
234 | dbBtree::clear((dbDatabase *)storage, (oid_t)index);
235 | } catch (dbException &) {}
236 | }
237 |
238 | dybase_iterator_t dybase_create_index_iterator(
239 | dybase_storage_t storage, dybase_oid_t index, int key_type, void *min_key,
240 | int min_key_size, int min_key_inclusive, void *max_key, int max_key_size,
241 | int max_key_inclusive, int ascent) {
242 | try {
243 | return (dybase_iterator_t) new dbBtreeIterator(
244 | (dbDatabase *)storage, (oid_t)index, key_type, min_key, min_key_size,
245 | min_key_inclusive, max_key, max_key_size, max_key_inclusive,
246 | (bool)ascent);
247 | } catch (dbException &) { return NULL; }
248 | }
249 |
250 | dybase_oid_t dybase_index_iterator_next(dybase_iterator_t iterator) {
251 | try {
252 | return ((dbBtreeIterator *)iterator)->next();
253 | } catch (dbException &) { return 0; }
254 | }
255 |
256 | void dybase_free_index_iterator(dybase_iterator_t iterator) {
257 | delete (dbBtreeIterator *)iterator;
258 | }
259 |
260 | void dybase_set_gc_threshold(dybase_storage_t storage, long allocated_delta) {
261 | ((dbDatabase *)storage)->setGcThreshold(allocated_delta);
262 | }
263 |
264 | void dybase_gc(dybase_storage_t storage) { ((dbDatabase *)storage)->gc(); }
265 |
266 |
267 | hashtable_t hashtable_create() {
268 | return new dbHashtable();
269 | }
270 | void hashtable_put(hashtable_t ht, void *key, int keySize, void *value)
271 | {
272 | dbHashtable* pht = (dbHashtable*)ht;
273 | pht->put(key, keySize, value);
274 | }
275 | void* hashtable_get(hashtable_t ht, void *key, int keySize)
276 | {
277 | dbHashtable* pht = (dbHashtable*)ht;
278 | return pht->get(key, keySize);
279 | }
280 | void hashtable_free(hashtable_t ht)
281 | {
282 | dbHashtable* pht = (dbHashtable*)ht;
283 | delete pht;
284 | }
285 |
286 | void* hashtable_remove(hashtable_t ht, void *key, int keySize)
287 | {
288 | dbHashtable* pht = (dbHashtable*)ht;
289 | return pht->remove(key, keySize);
290 | }
291 | void hashtable_clear(hashtable_t ht) {
292 | dbHashtable* pht = (dbHashtable*)ht;
293 | pht->clear();
294 | }
295 |
296 | typedef int each_cb_t(void* key, unsigned int key_length, void* data, void* opaque);
297 |
298 | void hashtable_each(hashtable_t ht, each_cb_t* pcb, void* opaque)
299 | {
300 | dbHashtable* pht = (dbHashtable*)ht;
301 | pht->each(pcb, opaque);
302 | }
303 |
304 |
305 |
--------------------------------------------------------------------------------
/cutils.h:
--------------------------------------------------------------------------------
1 | /*
2 | * C utilities
3 | *
4 | * Copyright (c) 2017 Fabrice Bellard
5 | * Copyright (c) 2018 Charlie Gordon
6 | *
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * of this software and associated documentation files (the "Software"), to deal
9 | * in the Software without restriction, including without limitation the rights
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * copies of the Software, and to permit persons to whom the Software is
12 | * furnished to do so, subject to the following conditions:
13 | *
14 | * The above copyright notice and this permission notice shall be included in
15 | * all copies or substantial portions of the Software.
16 | *
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 | * THE SOFTWARE.
24 | */
25 | #ifndef CUTILS_H
26 | #define CUTILS_H
27 |
28 | #include
29 | #include
30 | #include
31 |
32 | #ifdef _MSC_VER
33 | #include
34 | #include
35 | #ifndef alloca
36 | #define alloca(s) _alloca(s)
37 | #endif
38 | #else
39 | #include
40 | #endif
41 |
42 | /* set if CPU is big endian */
43 | #undef WORDS_BIGENDIAN
44 |
45 | #ifndef __has_attribute
46 | #define likely(x) (x)
47 | #define unlikely(x) (x)
48 | #define force_inline __forceinline
49 | #define no_inline __declspec(noinline)
50 | #define __maybe_unused
51 | #define __attribute__(x)
52 | #define __attribute(x)
53 | typedef intptr_t ssize_t;
54 | #define printf_like(A, B) /*__attribute__((format(printf, (A), (B))))*/
55 | #else
56 | #define likely(x) __builtin_expect(!!(x), 1)
57 | #define unlikely(x) __builtin_expect(!!(x), 0)
58 | #define force_inline inline __attribute__((always_inline))
59 | #define no_inline __attribute__((noinline))
60 | #define __maybe_unused __attribute__((unused))
61 | //#define printf_like(A, B) __attribute__((format(printf, (A), (B))))
62 | #define printf_like(A, B)
63 | #endif
64 |
65 | #define xglue(x, y) x ## y
66 | #define glue(x, y) xglue(x, y)
67 | #define stringify(s) tostring(s)
68 | #define tostring(s) #s
69 |
70 | #ifndef offsetof
71 | #define offsetof(type, field) ((size_t) &((type *)0)->field)
72 | #endif
73 | #ifndef countof
74 | #define countof(x) (sizeof(x) / sizeof((x)[0]))
75 | #endif
76 |
77 | typedef int BOOL;
78 |
79 | #ifndef FALSE
80 | enum {
81 | FALSE = 0,
82 | TRUE = 1,
83 | };
84 | #endif
85 |
86 | void pstrcpy(char *buf, int buf_size, const char *str);
87 | char *pstrcat(char *buf, int buf_size, const char *s);
88 | int strstart(const char *str, const char *val, const char **ptr);
89 | int has_suffix(const char *str, const char *suffix);
90 |
91 | static inline int max_int(int a, int b)
92 | {
93 | if (a > b)
94 | return a;
95 | else
96 | return b;
97 | }
98 |
99 | static inline int min_int(int a, int b)
100 | {
101 | if (a < b)
102 | return a;
103 | else
104 | return b;
105 | }
106 |
107 | static inline uint32_t max_uint32(uint32_t a, uint32_t b)
108 | {
109 | if (a > b)
110 | return a;
111 | else
112 | return b;
113 | }
114 |
115 | static inline uint32_t min_uint32(uint32_t a, uint32_t b)
116 | {
117 | if (a < b)
118 | return a;
119 | else
120 | return b;
121 | }
122 |
123 | static inline int64_t max_int64(int64_t a, int64_t b)
124 | {
125 | if (a > b)
126 | return a;
127 | else
128 | return b;
129 | }
130 |
131 | static inline int64_t min_int64(int64_t a, int64_t b)
132 | {
133 | if (a < b)
134 | return a;
135 | else
136 | return b;
137 | }
138 |
139 | /* WARNING: undefined if a = 0 */
140 | static inline int clz32(unsigned int a)
141 | {
142 | #ifdef _MSC_VER
143 | unsigned long idx;
144 | _BitScanReverse(&idx, a);
145 | return 31 ^ idx;
146 | #else
147 | return __builtin_clz(a);
148 | #endif
149 | }
150 |
151 | /* WARNING: undefined if a = 0 */
152 | static inline int clz64(uint64_t a)
153 | {
154 | #ifdef _MSC_VER
155 | unsigned long where;
156 | // BitScanReverse scans from MSB to LSB for first set bit.
157 | // Returns 0 if no set bit is found.
158 | #if INTPTR_MAX >= INT64_MAX // 64-bit
159 | if (_BitScanReverse64(&where, a))
160 | return (int)(63 - where);
161 | #else
162 | // Scan the high 32 bits.
163 | if (_BitScanReverse(&where, (uint32_t)(a >> 32)))
164 | return (int)(63 - (where + 32)); // Create a bit offset from the MSB.
165 | // Scan the low 32 bits.
166 | if (_BitScanReverse(&where, (uint32_t)(a)))
167 | return (int)(63 - where);
168 | #endif
169 | return 64; // Undefined Behavior.
170 | #else
171 | return __builtin_clzll(a);
172 | #endif
173 | }
174 |
175 | /* WARNING: undefined if a = 0 */
176 | static inline int ctz32(unsigned int a)
177 | {
178 | #ifdef _MSC_VER
179 | unsigned long idx;
180 | _BitScanForward(&idx, a);
181 | return 31 ^ idx;
182 | #else
183 | return __builtin_ctz(a);
184 | #endif
185 | }
186 |
187 | /* WARNING: undefined if a = 0 */
188 | static inline int ctz64(uint64_t a)
189 | {
190 | #ifdef _MSC_VER
191 | unsigned long where;
192 | // Search from LSB to MSB for first set bit.
193 | // Returns zero if no set bit is found.
194 | #if INTPTR_MAX >= INT64_MAX // 64-bit
195 | if (_BitScanForward64(&where, a))
196 | return (int)(where);
197 | #else
198 | // Win32 doesn't have _BitScanForward64 so emulate it with two 32 bit calls.
199 | // Scan the Low Word.
200 | if (_BitScanForward(&where, (uint32_t)(a)))
201 | return (int)(where);
202 | // Scan the High Word.
203 | if (_BitScanForward(&where, (uint32_t)(a >> 32)))
204 | return (int)(where + 32); // Create a bit offset from the LSB.
205 | #endif
206 | return 64;
207 | #else
208 | return __builtin_ctzll(a);
209 | #endif
210 | }
211 |
212 | #ifdef _MSC_VER
213 | #pragma pack(push, 1)
214 | struct packed_u64 {
215 | uint64_t v;
216 | };
217 |
218 | struct packed_u32 {
219 | uint32_t v;
220 | };
221 |
222 | struct packed_u16 {
223 | uint16_t v;
224 | };
225 | #pragma pack(pop)
226 | #else
227 | struct __attribute__((packed)) packed_u64 {
228 | uint64_t v;
229 | };
230 |
231 | struct __attribute__((packed)) packed_u32 {
232 | uint32_t v;
233 | };
234 |
235 | struct __attribute__((packed)) packed_u16 {
236 | uint16_t v;
237 | };
238 | #endif
239 |
240 | static inline uint64_t get_u64(const uint8_t *tab)
241 | {
242 | return ((const struct packed_u64 *)tab)->v;
243 | }
244 |
245 | static inline int64_t get_i64(const uint8_t *tab)
246 | {
247 | return (int64_t)((const struct packed_u64 *)tab)->v;
248 | }
249 |
250 | static inline void put_u64(uint8_t *tab, uint64_t val)
251 | {
252 | ((struct packed_u64 *)tab)->v = val;
253 | }
254 |
255 | static inline uint32_t get_u32(const uint8_t *tab)
256 | {
257 | return ((const struct packed_u32 *)tab)->v;
258 | }
259 |
260 | static inline int32_t get_i32(const uint8_t *tab)
261 | {
262 | return (int32_t)((const struct packed_u32 *)tab)->v;
263 | }
264 |
265 | static inline void put_u32(uint8_t *tab, uint32_t val)
266 | {
267 | ((struct packed_u32 *)tab)->v = val;
268 | }
269 |
270 | static inline uint32_t get_u16(const uint8_t *tab)
271 | {
272 | return ((const struct packed_u16 *)tab)->v;
273 | }
274 |
275 | static inline int32_t get_i16(const uint8_t *tab)
276 | {
277 | return (int16_t)((const struct packed_u16 *)tab)->v;
278 | }
279 |
280 | static inline void put_u16(uint8_t *tab, uint16_t val)
281 | {
282 | ((struct packed_u16 *)tab)->v = val;
283 | }
284 |
285 | static inline uint32_t get_u8(const uint8_t *tab)
286 | {
287 | return *tab;
288 | }
289 |
290 | static inline int32_t get_i8(const uint8_t *tab)
291 | {
292 | return (int8_t)*tab;
293 | }
294 |
295 | static inline void put_u8(uint8_t *tab, uint8_t val)
296 | {
297 | *tab = val;
298 | }
299 |
300 | static inline uint16_t bswap16(uint16_t x)
301 | {
302 | return (x >> 8) | (x << 8);
303 | }
304 |
305 | static inline uint32_t bswap32(uint32_t v)
306 | {
307 | return ((v & 0xff000000) >> 24) | ((v & 0x00ff0000) >> 8) |
308 | ((v & 0x0000ff00) << 8) | ((v & 0x000000ff) << 24);
309 | }
310 |
311 | static inline uint64_t bswap64(uint64_t v)
312 | {
313 | return ((v & ((uint64_t)0xff << (7 * 8))) >> (7 * 8)) |
314 | ((v & ((uint64_t)0xff << (6 * 8))) >> (5 * 8)) |
315 | ((v & ((uint64_t)0xff << (5 * 8))) >> (3 * 8)) |
316 | ((v & ((uint64_t)0xff << (4 * 8))) >> (1 * 8)) |
317 | ((v & ((uint64_t)0xff << (3 * 8))) << (1 * 8)) |
318 | ((v & ((uint64_t)0xff << (2 * 8))) << (3 * 8)) |
319 | ((v & ((uint64_t)0xff << (1 * 8))) << (5 * 8)) |
320 | ((v & ((uint64_t)0xff << (0 * 8))) << (7 * 8));
321 | }
322 |
323 | /* XXX: should take an extra argument to pass slack information to the caller */
324 | typedef void *DynBufReallocFunc(void *opaque, void *ptr, size_t size);
325 |
326 | typedef struct DynBuf {
327 | uint8_t *buf;
328 | size_t size;
329 | size_t allocated_size;
330 | BOOL error; /* true if a memory allocation error occurred */
331 | DynBufReallocFunc *realloc_func;
332 | void *opaque; /* for realloc_func */
333 | } DynBuf;
334 |
335 | void dbuf_init(DynBuf *s);
336 | void dbuf_init2(DynBuf *s, void *opaque, DynBufReallocFunc *realloc_func);
337 | int dbuf_realloc(DynBuf *s, size_t new_size);
338 | int dbuf_write(DynBuf *s, size_t offset, const uint8_t *data, size_t len);
339 | int dbuf_put(DynBuf *s, const uint8_t *data, size_t len);
340 | int dbuf_put_self(DynBuf *s, size_t offset, size_t len);
341 | int dbuf_putc(DynBuf *s, uint8_t c);
342 | int dbuf_putstr(DynBuf *s, const char *str);
343 | static inline int dbuf_put_u16(DynBuf *s, uint16_t val)
344 | {
345 | return dbuf_put(s, (uint8_t *)&val, 2);
346 | }
347 | static inline int dbuf_put_u32(DynBuf *s, uint32_t val)
348 | {
349 | return dbuf_put(s, (uint8_t *)&val, 4);
350 | }
351 | static inline int dbuf_put_u64(DynBuf *s, uint64_t val)
352 | {
353 | return dbuf_put(s, (uint8_t *)&val, 8);
354 | }
355 | int printf_like(2, 3) dbuf_printf(DynBuf *s, const char *fmt, ...);
356 | void dbuf_free(DynBuf *s);
357 | static inline BOOL dbuf_error(DynBuf *s) {
358 | return s->error;
359 | }
360 | static inline void dbuf_set_error(DynBuf *s)
361 | {
362 | s->error = TRUE;
363 | }
364 |
365 | #define UTF8_CHAR_LEN_MAX 6
366 |
367 | int unicode_to_utf8(uint8_t *buf, unsigned int c);
368 | int unicode_from_utf8(const uint8_t *p, int max_len, const uint8_t **pp);
369 |
370 | static inline int from_hex(int c)
371 | {
372 | if (c >= '0' && c <= '9')
373 | return c - '0';
374 | else if (c >= 'A' && c <= 'F')
375 | return c - 'A' + 10;
376 | else if (c >= 'a' && c <= 'f')
377 | return c - 'a' + 10;
378 | else
379 | return -1;
380 | }
381 |
382 | void rqsort(void *base, size_t nmemb, size_t size,
383 | int (*cmp)(const void *, const void *, void *),
384 | void *arg);
385 |
386 | #endif /* CUTILS_H */
387 |
--------------------------------------------------------------------------------