├── 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 | ![Storage schema](images/storage-schema.png) 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 | --------------------------------------------------------------------------------