Merge branch 'master' of https://github.com/h3rald/litestore
jump to
@@ -14,3 +14,8 @@ *.exe
nakefile LiteStore_UserGuide.htm jester_integration +js +*_backup +./config.json +*.db-shm +*.db-wal
@@ -6,5 +6,6 @@ "dialect": "SQLite",
"name": "data" } ], - "sqltools.useNodeRuntime": true + "sqltools.useNodeRuntime": true, + "git.ignoreLimitWarning": true }
@@ -7,6 +7,11 @@ md/architecture.md
md/getting-started.md md/usage.md md/auth.md + md/configuration-file.md + md/middleware.md + md/global-js-objects.md + md/system-documents.md + md/multiple-stores.md md/admin_app.md md/api.md md/api_info.md@@ -14,6 +19,7 @@ md/api_dir.md
md/api_docs.md md/api_tags.md md/api_indexes.md + md/api_stores.md md/nim-api.md md/nim-api_high.md md/nim-api_low.md@@ -24,7 +30,7 @@ for page in ${pages[@]}
do (cat "${page}"; printf "\n\n") >> LiteStore_UserGuide.md done -hastyscribe --field/version:1.7.0 LiteStore_UserGuide.md +hastyscribe --field/version:1.9.0 LiteStore_UserGuide.md rm LiteStore_UserGuide.md mv LiteStore_UserGuide.htm .. cd ../..
@@ -1,1 +0,0 @@
-CREATE INDEX json_document_field_test ON documents(json_extract(documents.data, '$.id') COLLATE NOCASE);
@@ -25,13 +25,13 @@ installExt = @["nim", "c", "h", "json", "ico"]
# Dependencies -requires "nim >= 1.0.0", "jwt" +requires "nim >= 1.0.0", "jwt", "nimgen", "duktape" # Build const parallel = "" #"--parallelBuild:1 --verbosity:3" - compile = "nim c -d:release --threads:on" & " " & parallel + compile = "nim c -d:release" & " " & parallel linux_x64 = "--cpu:amd64 --os:linux" windows_x64 = "--cpu:amd64 --os:windows" macosx_x64 = ""
@@ -16,15 +16,19 @@ return m("li", [m("span", title+": "), m("strong", content)]);
} }; var readonly = info.read_only ? m("span.label.label-success", "Yes") : m("span.label.label-danger", "No"); + var auth = info.auth ? m("span.label.label-success", "Yes") : m("span.label.label-danger", "No"); var mirror = info.mount ? m("span.label.label-success", "Yes") : m("span.label.label-danger", "No"); var infolist = m(".col-sm-6", [m("ul.list-unstyled", [ li("Version", info.version), li("Datastore Version", info.datastore_version), + li("API Version", info.api_version), li("Size", info.size), li("Serving Directory", info.directory, info.directory === null), li("Mirroring Changes", mirror), li("Log Level", info.log_level), li("Read-Only", readonly), + li("Auth", auth), + li("Additional Stores", info.additional_stores && info.additional_stores.join(", ") || "n/a"), li("Total Documents", m("span.badge", info.total_documents)), li("Total Tags", m("span.badge", info.total_tags)), ])]);@@ -42,4 +46,4 @@ return v;
}; u.layout(app.info); -}()) +}())
@@ -1,6 +1,6 @@
## Administration App -A simple but fully-functional administration app can be used to manage LiteStore data stores. This app can simply be imported into a data store file and then run via LiteStore. +A simple, *slightly* dated, but fully-functional administration app can be used to manage LiteStore data stores. This app can simply be imported into a data store file and then run via LiteStore. ### Obtaining and Running the Administration App@@ -64,4 +64,4 @@ * It is possible to upload local files instead of creating them by hand.
* Preview is available for images and HTML documents * Source code highlighting is available for Javascript, CSS, HTML, JSON and Markdown files. -![Document](images/app_document.png) +![Document](images/app_document.png)
@@ -24,12 +24,16 @@
Returns the following server statistics: * Version +* Datastore version +* API version * Size of the database on disk (in MB) * Whether the database is read-only or not * Log level (debug, info, warning, error, none) * Mounted directory (if any) +* Additional stores (if any) +* Whether authorization is enabled or not * Total documents -* Total Tags +* Total tags * Number of documents per tag ##### Example@@ -39,18 +43,21 @@ $ curl -i http://127.0.0.1:9500/info
HTTP/1.1 200 OK Content-Length: 965 Content-Type: application/json -Access-Control-Allow-Headers: Content-Type -Access-Control-Allow-Origin: * -Server: LiteStore/1.0.3 +Access-Control-Allow-Headers: Authorization, Content-Type +Access-Control-Allow-Origin: http://127.0.0.1:9500 +Server: LiteStore/1.9.0 { - "version": "LiteStore v1.1.0", - "datastore_version": 1, - "size": "5.76 MB", + "version": "LiteStore v1.9.0", + "datastore_version": 2, + "api_version": 7, + "size": "6.98 MB", "read_only": false, - "log_level": "info", + "log_level": "warn", "directory": "admin", "mount": true, + "additional_stores": [], + "auth": false, "total_documents": 68, "total_tags": 18, "tags": [@@ -71,4 +78,4 @@ "$subtype:html": 2
} ] } -``` +```
@@ -0,0 +1,253 @@
+### stores (LiteStore Stores) + +> %note% +> API v7 Required +> +> This resource has been introduced in version 7 of the LiteStore API. + +As of version 1.9.0, it is possible for a single LiteStore process to manage multiple data store files. These additional stores can be accessed but also added or removed at run time using this resource. + +#### OPTIONS stores + +Returns the allowed HTTP verbs for this resource. + +##### Example + +``` +$ curl -i -X OPTIONS http://127.0.0.1:9500/stores +HTTP/1.1 200 OK +server: LiteStore/1.9.0 +access-control-allow-origin: http://localhost:9500 +access-control-allow-headers: Content-Type +allow: GET,OPTIONS +access-control-allow-methods: GET,OPTIONS +content-length: 0 +``` + +#### OPTIONS stores/:id + +Returns the allowed HTTP verbs for this resource. + +##### Example + +``` +$ curl -i -X OPTIONS http://127.0.0.1:9500/stores/test1 +HTTP/1.1 200 OK +server: LiteStore/1.9.0 +access-control-allow-origin: http://localhost:9500 +access-control-allow-headers: Content-Type +allow: GET,OPTIONS,PUT,DELETE +access-control-allow-methods: GET,OPTIONS,PUT,DELETE +Content-Length: 0 +``` + +#### GET indexes + +Retrieves information on all available stores (file name and configuration). + +##### Example + +``` +$ curl -i http://localhost:9500/stores +HTTP/1.1 200 OK +content-type: application/json +access-control-allow-origin: http://127.0.0.1:9500 +access-control-allow-headers: Authorization, Content-Type +vary: Origin +server: LiteStore/1.9.0 +Content-Length: 2346 + +{ + "total": 4, + "execution_time": 0.0, + "results": [ + { + "id": "test1", + "file": "test1.db", + "config": null + }, + { + "id": "test2", + "file": "test2.db", + "config": null + }, + { + "id": "test3", + "file": "test3.db", + "config": null + }, + { + "id": "master", + "file": "data.db", + "config": { + "settings": { + "log": "debug", + "port": 9200 + }, + "stores": { + "test1": { + "file": "test1.db", + "config": null + }, + "test2": { + "file": "test2.db", + "config": null + }, + "test3": { + "file": "test3.db", + "config": null + } + }, + "resources": { + "/docs/vehicles/*": { + "GET": { + "middleware": [ + "validate", + "log" + ] + }, + "HEAD": { + "middleware": [ + "validate", + "log" + ] + }, + "POST": { + "allowed": false + }, + "PATCH": { + "auth": [ + "admin:vehicles" + ], + "middleware": [ + "validate", + "log" + ] + }, + "PUT": { + "auth": [ + "admin:vehicles" + ], + "middleware": [ + "validate", + "log" + ] + }, + "DELETE": { + "auth": [ + "admin:vehicles" + ], + "middleware": [ + "validate", + "log" + ] + } + }, + "/docs/logs/*": { + "GET": { + "auth": [ + "admin:server" + ] + }, + "POST": { + "allowed": false + }, + "PUT": { + "allowed": false + }, + "PATCH": { + "allowed": false + }, + "DELETE": { + "allowed": false + } + } + }, + "signature": "\n-----BEGIN CERTIFICATE-----\n<certificate text goes here>\n-----END CERTIFICATE-----\n" + } + } + ] +} +``` + +#### GET stores/:id + +Retrieves information on the specified store. + +##### Example + +``` +HTTP/1.1 200 OK +content-type: application/json +access-control-allow-origin: http://127.0.0.1:9500 +access-control-allow-headers: Authorization, Content-Type +vary: Origin +server: LiteStore/1.9.0 +Content-Length: 46 + +{"id":"test1","file":"test1.db","config":null} +``` + +#### PUT stores/:id + +Adds a new stores with the specified ID. If a file called **\<id\>.db** does not exist already, it will be created in the current working directory and initialized as a LiteStore store. + +Note that: +* Index IDs can only contain letters, numbers, and underscores. +* The body must be present and contain the store configuration (or **null**). + +> %warning% +> No updates +> +> It is not possible to update an existing store. Remove it and re-add it instead. + + +##### Example + +``` +curl -i -X PUT -d "null" "http://127.0.0.1:9500/stores/test3" --header "Content-Type:application/json" +HTTP/1.1 201 Created +content-type: application/json +access-control-allow-origin: http://127.0.0.1:9500 +access-control-allow-headers: Authorization, Content-Type +vary: Origin +server: LiteStore/1.9.0 +Content-Length: 46 + +{"id":"test3","file":"test3.db","config":null} +``` + +#### DELETE stores/:id + +Removes the specified store. Although it will no longer be accessible via LiteStore, the corresponding file will *not* be deleted from the filesystem. + +##### Example + +``` +$ curl -i -X DELETE "http://127.0.0.1:9200/stores/test3" +HTTP/1.1 204 No Content +vary: Origin +access-control-allow-origin: http://127.0.0.1:9200 +access-control-allow-headers: Authorization, Content-Type +content-length: 0 +server: LiteStore/1.9.0 +Content-Length: 0 +``` + +#### \* stores/:id/\* + +Forward the request to the specified store. Essentially, the path fragment after the store ID will be forwarded as a standard request to the specified store. + +##### Examples + +Retrieve all tags from store **vehicles**: +``` +$ curl -i http://localhost:9500/stores/vehicles/tags/ +``` + + +Delete the document with ID **AA457DB** from store **vehicles**: + +``` +$ curl -i -X DELETE "http://127.0.0.1:9200/stores/vehicles/docs/AA457DB" +```
@@ -35,17 +35,35 @@
The [documents](class:kwd) table is the most important table of the data store, as it contains all the documents stored in it. The following information is stored for each document: * **docid** – The internal unique document identifier. -* **id** – The public unique document identifier, used to access the document via the HTTP API. +* **id** – The public unique document identifier, used to access the document via the HTTP API or Nim API. * **data** – The contents of the document (or their base64-encoded representation in case of binary documents). * **binary** – Whether the document is binary (1) or textual (0). * **searchable** – Whether the document is searchable (1) or not (0). Currently, textual documents are searchable and binary documents are not. * **created** – When the document was created. * **modified** – When the document was last modified. +##### system_documents Table + +The [system_documents](class:kwd) table has a structure similar to the [documents](class:kwd) table, but it is used for well-known system documents that are used to provide additional functionalities, such as authorization or custom resources. + +Unlike ordinary documents, system documents: +* cannot be accessed via the HTTP or Nim API, they can only be imported, exported, or deleted with the corresponding commands. +* are not searchable. +* cannot be tagged. + +The following information is stored for each system document: + +* **docid** – The internal unique document identifier. +* **id** – The public unique document identifier. +* **data** – The contents of the document (or their base64-encoded representation in case of binary documents). +* **binary** – Whether the document is binary (1) or textual (0). +* **created** – When the document was created. +* **modified** – When the document was last modified. + ##### tags Table The [tags](class:kwd) table is used to store the associations between tags and documents. Tags can be added by users or add automatically by the system when a document is imported into the data store. ##### searchdata Table -This table is used as full-text index for searchable documents. +This table is used as full-text index for searchable documents.
@@ -2,6 +2,11 @@ ## Authorization
LiteStore can be configured to automatically validate [JWT](https://jwt.io/) tokens and authorize authenticated users on specific resources (and specific resource verbs even) based on their [OAuth2 scopes](https://oauth.net/2/scope/) specified in the token itself. +> %note% +> auth.json vs. config.json +> +> As of version 1.8.0, it is recommended to use the LiteStore configuration file to configure authorization. This specialized **auth.json** configuration file format will however be maintained for compatibility reasons. + To configure authorization, create an **auth.json** file like the following: ```
@@ -0,0 +1,104 @@
+## Configuration File + +As of version 1.8.0, you can specify a configuration file containing settings, middleware and authorization configuration using the **--config** or **-c** command line option: + +[litestore -c:config.json](class:cmd) + +A typical configuration file looks like this: + +``` +{ + "settings": { + "log": "debug", + "port": 9200 + }, + "stores": { + "logs": { + "file": "logs.db", + "config": { + "resources": { + "/docs/*": { + "GET": { + "auth": ["admin:server"] + }, + "POST": { + "allowed": false + }, + "PUT": { + "allowed": false + }, + "PATCH": { + "allowed": false + }, + "DELETE": { + "allowed": false + } + } + } + } + } + }, + "resources": { + "/docs/vehicles/*": { + "GET": { + "middleware": ["validate", "log"] + }, + "HEAD": { + "middleware": ["validate", "log"] + }, + "POST": { + "allowed": false + }, + "PATCH": { + "auth": ["admin:vehicles"], + "middleware": ["validate", "log"] + }, + "PUT": { + "auth": ["admin:vehicles"], + "middleware": ["validate", "log"] + }, + "DELETE": { + "auth": ["admin:vehicles"], + "middleware": ["validate", "log"] + } + } + } +} +``` + +At present, it contains a [settings](class:kwd), a [resources](class:kwd), and a [signature](class:kwd) section. + +### settings + +This section contains some of the most common command-line options, i.e.: + +* address +* port +* store +* directory +* mount +* readonly +* middleware +* log + +If a configuration file is specified and some of these settings are configured, they will be recognized as if they were specified via command line. However, if you also specify the same settings via command line, the command line settings will take precedence over the settings defined in the configuration file. + +### stores + +This section is used to defined additional stores to be managed by LiteStore by specifying the SQLite file to open and optionally the store configuration. + +In this case, the **logs** store is configured as an additional store. + +### resources + +This section can contain any number of resource paths, like [/docs/](class:kwd), [/info/](class:kwd), [/docs/vehicles/AA456CC](class:kwd) or [/docs/logs/*](class:kwd). If a wildcard is specified after a resource or folder path, the rules defined within that section will match any document within the specified path. So for examople [/docs/vehicles/*](class:kwd) will match both [/docs/vehicles/AB547QV](class:kwd) and [/docs/vehicles/BB326CZ](class:kwd), but *not* [/docs/vehicles/](class:kwd). + +Within each resource path, you can specify different HTTP methods (all uppercase) and within each method any of the following properties: + +* **auth** — A list of JWT scopes necessary to access the specified resource with the specified method. +* **middleware** — A list of middleware function definitions that will be executed in sequence when the resource is accessed with the specified method. +* **allowed** — If set to **false**, LiteStore will return a [405 - Method not allowed](class:kwd) error code when accessing the resource with the specified method. + +### signature + +This section must be set to a valid certificate used validate JWT tokens. Note that the certificate must follow a specific format and start with the appropriate begin/end blocks.
@@ -5,7 +5,7 @@ ### Downloading Pre-built Binaries
The easiest way to get LiteStore is by downloading one of the prebuilt binaries from the [Github Release Page][release]: - * [LiteStore for Mac OS X (x64)](https://github.com/h3rald/litestore/releases/download/{{$version}}litestore_{{$version}}_macosx_x64.zip) + * [LiteStore for Mac OS X (x64)](https://github.com/h3rald/litestore/releases/download/{{$version}}/litestore_{{$version}}_macosx_x64.zip) * [LiteStore for Windows (x64)](https://github.com/h3rald/litestore/releases/download/{{$version}}/litestore_{{$version}}_windows_x64.zip) * [LiteStore for Linux (x64)](https://github.com/h3rald/litestore/releases/download/{{$version}}/litestore_{{$version}}_linux_x64.zip)@@ -29,7 +29,7 @@ A simple but functional Administration App is available to manage LiteStore, create documents interactively, view and search content, etc.
To get the app up and running (assuming that you have the [litestore](class:cmd) executable in your path): -1. Download the default [data.db](https://github.com/h3rald/litestore/releases/download/{{$version}}/data.db) file. This file is a LiteStore data store file containing the sample app. +1. Extract the default **data.db** file included in the LiteStore release package. This file is a LiteStore data store file containing the sample app. 2. Go to the local directory in which you downloaded the [data.db](class:cmd) file. 3. Run [litestore -s:data.db](class:cmd) -4. Go to [localhost:9500/docs/admin/index.html](http://localhost:9500/docs/admin/index.html). +4. Go to [localhost:9500/docs/admin/index.html](http://localhost:9500/docs/admin/index.html).
@@ -0,0 +1,128 @@
+## Global JavaScript Objects + +When creating JavaScript handlers for middleware, you can use some special $-prefixed global objects to access the HTTP request to the resource, the HTTP response, and also access other LiteStore resources. + +### $ctx + +An empty object that can be used to temporarily store data to pass across different middleware handlers. + +### $req + +The current HTTP request sent to access the current resource. + +#### Properties + +<dl> +<dt>method: string</dt> +<dd>The HTTP method used by the request, all uppercase (GET, POST, DELETE, PUT, PATCH, OPTIOONS, or HEAD).</dd> +<dt>jwt: object</dt> +<dd>An object containing a parsed JWT token, if present. It exposes two properties: +<ul> +<li><strong>headers</strong>, an object typically containing the <strong>alg</strong> (algorithm) and <strong>typ</strong> (type) keys.</li> +<li><strong>claims</strong>, an object containing the claims included in the token (see the <a href="https://www.iana.org/assignments/jwt/jwt.xhtml#claims">IANA JSON Web Token Claims Registry</a> for a list of possible claims).</li> +</ul></dd> +<dt>headers: object</dt> +<dd>An object containing the request headers, as keys and values.</dd> +<dt>protocol: string</dt> +<dd>The request protocol and version.</dd> +<dt>hostname: string</dt> +<dd>The hostname target of the request.</dd> +<dt>port: number</dt> +<dd>The port used for the request.</dd> +<dt>path: string</dt> +<dd>The path to the resource requested.</dd> +<dt>query: string</dt> +<dd>The contents of the request query string.</dd> +<dt>content: string</dt> +<dd>When applicable, the content that was sent as body of the request.</dd> +</dl> + +### $res + +The HTTP response to return to the client. + +<dl> +<dt>code: number</dt> +<dd>The HTTP return code, by default set to `200`.</dd> +<dt>content: string</dt> +<dd>The response content, by default set to `""`.</dd> +<dt>headers: object</dt> +<dd>The response headers, by default set to: +<pre><code> +{ + "Access-Control-Allow-Origin": "*", + "Access-Control-Allow-Headers": "Authorization, Content-Type", + "Server": "LiteStore/<version>", + "Content-Type": "application/json", + "Content-Length": "<Automatically set to the length of the <b>content</b> property.>" +} +</code></pre></dd> +</dl> + +### $store + +Simple synchronous API to access LiteStore resources in a RESTful way, mimicking HTTP methods. + +All methods return a response object containing two String properties, **code** and **content**. + +<dl> +<dt>function get(resource: string, id: string, parameters: string): object</dt> +<dd>Retrieves the specified resource(s.). +<p> +Examples: +<ul> +<li><code>$store.get('docs', 'test-folder/test.json')</code></li> +<li><code>$store.get('docs', '', 'search=test&limit=20&offset=0')</code></li> +</ul> +</p> +</dd> +<dt>function post(resource: string, folder: string, body: string, contentType: string): object</dt> +<dd>Creates a new resource. +<p> +Examples: +<ul> +<li><code>$store.post('docs', 'test-folder', 'test!', 'text/plain')</code></li> +<li><code>$store.post('docs', '', '{"a": 1}', ?application/json')</code></li> +</ul> +</p> +</dd> +<dt>function put(resource: string, id: string, body: string, contentType: string): object</dt> +<dd>Creates or updates a specific resource. +<p> +Examples: +<ul> +<li><code>$store.put('docs', 'test-folder/test1.txt', 'Another Test.', 'text/plain')</code></li> +<li><code>$store.put('docs', 'test.json', '{"a": 2}', 'application/json')</code></li> +</ul> +</p> +</dd> +<dt>function patch(resource: string, id: string, body: string): object</dt> +<dd>Patches one or more fields of an existing resource. +<p> +Examples: +<ul> +<li><code>$store.patch('docs', 'test-folder/test1.txt', '{"op":"add", "path":"/tags/3", "value":"test1"}')</code></li> +</ul> +</p> +</dd> +<dt>function delete(resource: string, id: string): object</dt> +<dd>Deletes a specific resource. +<p> +Examples: +<ul> +<li><code>$store.delete('docs', 'test-folder/test1.txt')</code></li> +<li><code>$store.delete('docs', 'test.json')</code></li> +</ul> +</p> +</dd> +<dt>function head(resource: string, id: string): object</dt> +<dd>Retrieves the metadata of one or more resources, without retrieving their contents. +<p> +Examples: +<ul> +<li><code>$store.head('docs', 'test-folder/test1.txt')</code></li> +<li><code>$store.head('docs')</code></li> +</ul> +</p> +</dd> +</dl>
@@ -0,0 +1,108 @@
+## Middleware + +As of version 1.8.0, you can define your own custom middleware using JavaScript executed on the server side. + +LiteStore embeds the [duktape](https://duktape.org/) lightweight JavaScript engine and therefore you can use all functionalities exposed by duktape in your code, plus access some LiteStore-specific properties and method through some special global object. + +Although writing extremely complex logic in a JavaScript handler may not be appropriate, it can be useful for certain use cases, such as: +* validating data before it is saved +* manipulate data before it is saved +* aggregating different types of data not accessible via a single query +* perform additional operation when accessing data, such as logging who requested it + +### How middleware works + +Potentially, each resource could have one or more middleware functions associated to it. Association is done through the LiteStore configuration file in a similar way as authentication is configured: + +``` +{ + "settings": { + "middleware": "test/middleware" + }, + "resources": { + "/docs/vehicles/*": { + "GET": { + "middleware": ["validate", "log"] + }, + "PUT": { + "auth": ["admin:vehicles"], + "middleware": ["validate", "log"] + } + } + } +} +``` + +This simple configuration file shows how to configure middleware to be executed when a resources it requested via GET or PUT. In both cases, first the *validate* middleware function is executed, and then the *log*. These functions must reside in separate files named *validate.js* and *log.js* respectively, and placed into a folder (**test/middleware** in this case) referenced via the **middleware** setting (which is also exposed as a command line option, with **-w** as shorthand option). + +Middleware functions are executed sequentially until one of them explicitly stops the execution chain or the execution completes (by requesting the original resource). + +Considering the previous configuration example, if a PUT request is made to an item under **/docs/vehicles**: + +1. The *validate* middleware function is executed. +2. The *log* middleware function is executed. +3. The request is processed as normal. + +Note that, for example, the *validate* middleware function may cause the execution to stop before it reaches the *log* middleware, thereby effectively implementing server-side validation. + +### Creating a JavaScript Middleware Function + +Let's say you want to keep records of Italian vehicles identified by their number plate, which is in the following format: + +\[two-uppercase-letters\][three-digits\][two-uppercase-letters\] + +For example: AB467DX (OK, in reality there's a space between each set of digits/letters, but spaces in identifiers are ugly, so let's remove them!) + +Let's also say that Italian vehicle data will be managed within a folder called **vehicles**, therefore vehicles will be accessible at URLs similar to the following: + +* http://localhost:9500/docs/vehicles/AB467DX +* http://localhost:9500/docs/vehicles/CD569BW +* http://localhost:9500/docs/vehicles/EF981DE + +To make sure that valid IDs are used, we can create a file called **vehicles.js** and write the following code: + +``` +(function() { + var id = $req.path.replace(/^\/docs\//, ""); + var valid = /[A-Z]{2}[0-9]{3}[A-Z]{2}/; + if (!id.match(valid)) { + $res.content = { + error: "Invalid number plate" + }; + $res.code = 400; + return true; + } + $ctx.existing = !!($store.get("docs", id).code == 200); +})(); +``` + +Note that middleware must be coded in the form of an [IIFE](https://en.wikipedia.org/wiki/Immediately_invoked_function_expression). In this case, the function: +* retrieves the ID of the vehicle. +* checks if it's valid +* if it's invalid, prepares a 400 - Bad Request response and stops the execution of additional middleware (and ultimately the request itself) by returning **true**. +* otherwise, it checks whether the vehicle already exists and stores this information on a context, so that it will be accessible to other middleware functions down the execution chain. + +### Passing data to another middleware + +Although you can technically add additional properties to the **$req** and **$res** objects, you should use **$ctx** instead. **$ctx** is a global objects. + +In the *validate* middleware described in the previous section, the **$ctx.existing** property was set. This property can then be accessed and/or modified in additional middleware down the execution chain. + +Consider for example the following, very basic *log* middleware function: + +``` +(function(){ + var doc = { + user: $req.jwt.claims && $req.jwt.claims.sub || null, + agent: $req.headers['user-agent'], + language: $req.headers['accept-language'] && $req.headers['accept-language'].replace(/,.+$/, ''), + path: $req.path, + existing: !!$ctx.existing, + method: $req.method, + timestamp: Date.now() + } + $store.post('docs', 'logs', JSON.stringify(doc), 'application/json'); +}()) +``` + +This middleware function simply logs the current request to another folder within the data store, and gathers some stats and whether the request was performed on an existing object or not. In this case, **$ctx.existing** should be set by another middleware up the chain (*validate*).
@@ -0,0 +1,84 @@
+## Multiple Data Stores + +As of version 1.9.0, it is possible to configure LiteStore to manage several different SQLite database files, or *stores*. Essentially, besides the *master* store it is possible to create, delete or access additional stores at run time though the new **/stores** resource. + +Although folders already provide some partitioning for documents, in certain situations you may want to physically separate your data into multiple files, for example when: + +* Managing time-dependent content (store only records of a day or month in a single file) +* Storing accessory content that is unrelated to other data, like logging/diagnostic information +* Managing data belonging to different tenants + +Although all stores can be accessed by the same process using the **/stores** resource (which can essentially forward requests to be executed on a specific file), each store can have its own configuration file stored as a system document, its own authentication and its own middleware. + +### Configuring additional stores + +If you know the details of each store at development/configuration time, you can configure them in the **stores** section of the LiteStore configuration file, like this: + +``` +{ + "settings": { + "log": "debug", + "port": 9200 + }, + "stores": { + "test1": { + "file": "test1.db", + "config": null + }, + "test2": { + "file": "test2.db", + "config": null + }, + "test3": { + "file": "test3.db", + "config": null + } + }, + "resources": { + "/docs/vehicles/*": { + "GET": { + "middleware": ["validate", "log"] + }, + "HEAD": { + "middleware": ["validate", "log"] + }, + "POST": { + "allowed": false + }, + "PATCH": { + "auth": ["admin:vehicles"], + "middleware": ["validate", "log"] + }, + "PUT": { + "auth": ["admin:vehicles"], + "middleware": ["validate", "log"] + }, + "DELETE": { + "auth": ["admin:vehicles"], + "middleware": ["validate", "log"] + } + }, + "/docs/logs/*": { + "GET": { + "auth": ["admin:server"] + }, + "POST": { + "allowed": false + }, + "PUT": { + "allowed": false + }, + "PATCH": { + "allowed": false + }, + "DELETE": { + "allowed": false + } + } + } +} +``` + + When LiteStore is executed, the three additional stores will be created and initialized, their configuration (if any) will be saved as a system document and they will be immediately accessible. + + Alternatively, you can add or remove stores dynamically at run time by executing POST and DELETE requests to the **/stores** resource, optionally specifying configuration settings as the request body.
@@ -27,9 +27,9 @@ #### Document Tagging
You can add custom tags to documents to easily categorize them and retrieve them. Some system tags are also added automatically to identify the document content type, format and collection. -#### Enhanced Querying and Indexing of JSON documents +#### Enhanced Querying of JSON documents -By leveraging the [SQLite JSON1 extension](https://www.sqlite.org/json1.html) and implementing custom query string parsing, LiteStore provides enhanced filtering, ordering, and custom field selection of JSON documents. +By leveraging the [SQLite JSON1 extension](https://www.sqlite.org/json1.html) and implementing custom query string parsing, LiteStore provides enhanced filtering, ordering, and custom field selection of JSON documents. Additionally, you can also configure custom indexes specifying JSON fields for extra speed! #### Full-text Search@@ -39,9 +39,17 @@ #### RESTful HTTP API
Every operation can be performed on the data store using a simple but powerful RESTful HTTP API, perfect for client-side, single-page applications. -#### Authorization +#### JWT-based Authorization -Optionally, you can configure per-resource authorization by validating [JWT](https://jwt.io/) tokens and checking [Oauth2 Scopes](https://oauth.net/2/scope/) +LiteStore can be configure validate [JWT](https://jwt.io/) tokens and configure access to specific resources based on specific [OAuth2 scopes](https://oauth.net/2/scope/). + +#### Middleware + +By leveraging the [duktape](https://duktape.org/) library, you can create your own middleware functions in JavaScript to perform additional tasks (validation, logging, data aggregation...) before accessing data. + +#### Multiple Data Stores + +LiteStore can be configured to manage more than one SQLite file through the same process. At run time, it will be possible to access data stored in each store but also add and remove stores. #### Nim API
@@ -0,0 +1,43 @@
+## System Documents + +As of version 1.8.0, it is possible to import, export, or delete *system documents* besides ordinary documents. Such documents are different from ordinary documents, because: + +* they are only intended to be used internally by LiteStore. +* they cannot be accessed via any of the public APIs except for the [import](class:kwd), [export](class:kwd) and [delete](class:kwd) commands. +* they must have a well-known name and/or folder structure. + +At present, only the following system documents are recognized by LiteStore: + +* **auth.json** — The LiteStore authorization configuration file. +* **config.json** — The main LiteStore configuration file. +* **middleware/\*.js** — Any [.js](class:ext) file containing the definition of a middleware function, placed within a [middleware](class:dir) folder. + +### Importing, exporting and deleting System Documents + +You can import, export, and delete system documents with the respective commands, but you must specify the [--system](class:kwd) command line flag. + +For example, suppose you have a [sysdocs](class:dir) folder containing the following file hierarchy: + +* sysdocs/ + * auth.jsom + * config.json + * middleware/ + * log.js + * req.js + * validate.js + +To import all the documents stored within the [sysdocs](class:dir) folder, you must run the following command: + +[litestore -d:sysdocs --system import](class:kwd) + +Similarly, the [export](class:kwd) and [delete](class:kwd) commands can be used to export and delete system documents respectively, always specifying the [--system](class:kwd) flag. + +### How LiteStore uses System Documents + +While at development time you may want to be able to edit your system documents and therefore keep them outside your data store as ordinary text files (and load them using the **--auth**, **--config** and **--middleware** options), in production you may want to ship them within the data store along with your application data. + +At run time, LiteStore will attempt to retrieve settings/middleware/authorization configuration using the following order of precedence (first listed have higher precedence): + +1. Command line options +2. Configuration files specified via command line options +3. Configuration files loaded as system documents
@@ -19,6 +19,7 @@
* **-a**, **-\-address** — Specify server address (default: 127.0.0.1). * **--auth** — Specify an authorization configuration file. * **-b**, **--body** — Specify a string containing input data for an operation to be executed. +* **-c**, **--config** — Specify a configuration file. * **-d**, **-\-directory** — Specify a directory to serve, import, export, delete, or mount. * **-f**, **--file** — Specify a file containing input data for an operation to be executed. * **-h**, **-\-help** — Display program usage.@@ -28,9 +29,11 @@ * **-o**, **--operation** — Specify an operation to execute via the execute command: get, put, delete, patch, post, head, options.
* **-p**, **-\-port** —Specify server port number (default: 9500). * **-r**, **-\-readonly** — Allow only data retrieval operations. * **-s**, **-\-store** — Specify a datastore file (default: data.db) +* **--system** — Set the system flag for import, export, and delete operations * **-t**, **--type** — Specify a content type for the body an operation to be executed via the execute command. * **-u**, **--uri** — Specify an uri to execute an operation through the execute command. * **-v**, **-\-version** — Display the program version. +* **-w**, **--middleware** — Specify a path to a folder containing middleware definitions ### Examples@@ -39,6 +42,15 @@
* with default settings: [litestore](class:cmd) + +* loading configuration from a configuration file called **config.json**: + + [litestore -c:config.json](class:cmd) + +* loading middleware definition files stored in a directory called **myMiddleware**: + + [litestore -w:myMiddleware](class:cmd) + * with custom port (**9700**) and address (**0.0.0.0**): [litestore -p:9700 -a:0.0.0.0](class:cmd)@@ -60,6 +72,12 @@
Import a directory called **admin**: [litestore import -d:admin](class:cmd) + +#### Importing system documents from a directory + +Import all documents stored in a directory called **system** as system documents: + +[litestore import -d:system --system](class:cmd) #### Exporting a directory
@@ -9,7 +9,7 @@
As a document store, LiteStore provides the following features * You can save and retrieve data as arbitrary JSON documents but also as arbitrary documents of virtually any content type. -* You can query data using user-specified and system tags and/or via the native full-text search functionality (available only for textual documents). +* You can query data using user-specified and system tags, via the native full-text search functionality (available only for textual documents) or writing SQL-like queries on JSON documents. * You can access data by the means of a RESTful API. #### SPA Prototyping Backend and Lightweight File Server@@ -42,4 +42,4 @@ Your app could then be served on any desktop system able to run LiteStore (e.g. OSX, Windows, Linux, ...even on a [Raspberry Pi](https://www.raspberrypi.org)).
#### Static Site Backend -LiteStore can be configured to run in read-only mode, so that only GET, HEAD, or OPTIONS request are accepted by the server. This makes it ideal as a backend for static web site generated with something like [nanoc](http://nanoc.ws) or [Jekyll](http://jekyllrb.com). +LiteStore can be configured to run in read-only mode, so that only GET, HEAD, or OPTIONS request are accepted by the server. This makes it ideal as a backend for static web site generated with something like [nanoc](http://nanoc.ws) or [Jekyll](http://jekyllrb.com).
@@ -1,15 +1,16 @@
import strutils, - os, uri, - httpcore + httpcore, + json, + tables import litestorepkg/lib/types, litestorepkg/lib/logger, litestorepkg/lib/utils, litestorepkg/lib/core, - litestorepkg/lib/cli, - litestorepkg/lib/server + litestorepkg/lib/server, + litestorepkg/lib/cli export types,@@ -58,58 +59,62 @@ req.headers["Content-Type"] = ctype
req.hostname = "<cli>" req.url = parseUri("$1://$2:$3/$4" % @["http", "localhost", "9500", uri]) let resp = req.process(LS) - echo resp.content if resp.code.int < 300 and resp.code.int >= 200: quit(0) else: quit(resp.code.int) -proc setup*(open = true) = - if not LS.file.fileExists: - try: - LOG.debug("Creating datastore: ", LS.file) - LS.file.createDatastore() - except: - eWarn() - fail(200, "Unable to create datastore '$1'" % [LS.file]) - if (open): - try: - LS.store = LS.file.openDatastore() - if LS.mount: - try: - LS.store.mountDir(LS.directory) - except: - eWarn() - fail(202, "Unable to mount directory '$1'" % [LS.directory]) - except: - fail(201, "Unable to open datastore '$1'" % [LS.file]) +# stores: { +# test: { +# file: 'path/to/test.db', +# config: { +# resources: {}, +# signature: '' +# } +# } +# } +proc initStores*() = + if LS.config.kind == JObject and LS.config.hasKey("stores"): + for k, v in LS.config["stores"].pairs: + if not v.hasKey("file"): + fail(120, "File not specified for store '$1'" % k) + let file = v["file"].getStr + var config = newJNull() + if v.hasKey("config"): + config = v["config"] + LSDICT[k] = LS.addStore(k, file, config) + LOG.info("Initializing master store") + LS.setup(true) + LS.initStore() + LSDICT["master"] = LS when isMainModule: + run() + # Manage vacuum operation separately if LS.operation == opVacuum: - setup(false) + LS.setup(false) vacuum LS.file else: # Open Datastore - setup(true) - - case LS.operation: - of opRun: - LS.serve - runForever() - of opImport: - LS.store.importDir(LS.directory) - of opExport: - LS.store.exportDir(LS.directory) - of opDelete: - LS.store.deleteDir(LS.directory) - of opOptimize: - LS.store.optimize - of opExecute: - executeOperation() - else: - discard + initStores() + case LS.operation: + of opRun: + LS.serve + runForever() + of opImport: + LS.store.importDir(LS.directory, LS.manageSystemData) + of opExport: + LS.store.exportDir(LS.directory, LS.manageSystemData) + of opDelete: + LS.store.deleteDir(LS.directory, LS.manageSystemData) + of opOptimize: + LS.store.optimize + of opExecute: + executeOperation() + else: + discard else:
@@ -0,0 +1,54 @@
+import strutils +const sourcePath = currentSourcePath().split({'\\', '/'})[0..^2].join("/") +{.passC: "-I\"" & sourcePath & "/src\"".} +const headerduk_config = sourcePath & "/src/duk_config.h" +type + duk_uint8_t* = uint8_t + duk_int8_t* = int8_t + duk_uint16_t* = uint16_t + duk_int16_t* = int16_t + duk_uint32_t* = uint32_t + duk_int32_t* = int32_t + duk_uint64_t* = uint64_t + duk_int64_t* = int64_t + duk_uint_least8_t* = uint_least8_t + duk_int_least8_t* = int_least8_t + duk_uint_least16_t* = uint_least16_t + duk_int_least16_t* = int_least16_t + duk_uint_least32_t* = uint_least32_t + duk_int_least32_t* = int_least32_t + duk_uint_least64_t* = uint_least64_t + duk_int_least64_t* = int_least64_t + duk_uint_fast8_t* = uint_fast8_t + duk_int_fast8_t* = int_fast8_t + duk_uint_fast16_t* = uint_fast16_t + duk_int_fast16_t* = int_fast16_t + duk_uint_fast32_t* = uint_fast32_t + duk_int_fast32_t* = int_fast32_t + duk_uint_fast64_t* = uint_fast64_t + duk_int_fast64_t* = int_fast64_t + duk_uintptr_t* = uintptr_t + duk_intptr_t* = intptr_t + duk_uintmax_t* = uintmax_t + duk_intmax_t* = intmax_t + duk_size_t* = csize + duk_ptrdiff_t* = ptrdiff_t + duk_int_t* = cint + duk_uint_t* = cuint + duk_int_fast_t* = duk_int_fast32_t + duk_uint_fast_t* = duk_uint_fast32_t + duk_small_int_t* = cint + duk_small_uint_t* = cuint + duk_small_int_fast_t* = duk_int_fast16_t + duk_small_uint_fast_t* = duk_uint_fast16_t + duk_bool_t* = duk_small_uint_t + duk_idx_t* = duk_int_t + duk_uidx_t* = duk_uint_t + duk_uarridx_t* = duk_uint_t + duk_ret_t* = duk_small_int_t + duk_errcode_t* = duk_int_t + duk_codepoint_t* = duk_int_t + duk_ucodepoint_t* = duk_uint_t + duk_float_t* = cfloat + duk_double_t* = cdouble + duk_context* = duk_hthread
@@ -1,24 +0,0 @@
-{ - "settings": { - "mount": true, - "directory": "admin" - }, - "resources": { - "/info": { - "GET": { "auth": ["admin:server"] } - }, - "/docs/*": { - "POST": { "auth": ["admin:server"] }, - "PATCH": { "auth": ["admin:server"] }, - "PUT": { "auth": ["admin:server"] }, - "DELETE": { "auth": ["admin:server"] } - }, - "/docs/wiki/*": { - "POST": { "auth": ["admin:wiki"] }, - "PUT": { "auth": ["admin:wiki"] }, - "PATCH": { "auth": ["admin:wiki"] }, - "DELETE": { "auth": ["admin:wiki"] } - } - }, - "signature": "\n-----BEGIN CERTIFICATE-----\n<certificate text goes here>\n-----END CERTIFICATE-----\n" -}
@@ -0,0 +1,86 @@
+{ + "settings": { + "log": "debug", + "port": 9200 + }, + "stores": { + "test1": { + "file": "test1.db", + "config": null + }, + "test2": { + "file": "test2.db", + "config": null + }, + "test3": { + "file": "test3.db", + "config": null + } + }, + "resources": { + "/docs/vehicles/*": { + "GET": { + "middleware": [ + "validate", + "log" + ] + }, + "HEAD": { + "middleware": [ + "validate", + "log" + ] + }, + "POST": { + "allowed": false + }, + "PATCH": { + "auth": [ + "admin:vehicles" + ], + "middleware": [ + "validate", + "log" + ] + }, + "PUT": { + "auth": [ + "admin:vehicles" + ], + "middleware": [ + "validate", + "log" + ] + }, + "DELETE": { + "auth": [ + "admin:vehicles" + ], + "middleware": [ + "validate", + "log" + ] + } + }, + "/docs/logs/*": { + "GET": { + "auth": [ + "admin:server" + ] + }, + "POST": { + "allowed": false + }, + "PUT": { + "allowed": false + }, + "PATCH": { + "allowed": false + }, + "DELETE": { + "allowed": false + } + } + }, + "signature": "\n-----BEGIN CERTIFICATE-----\n<certificate text goes here>\n-----END CERTIFICATE-----\n" +}
@@ -0,0 +1,12 @@
+(function(){ + var doc = { + user: $req.jwt.claims && $req.jwt.claims.sub || null, + agent: $req.headers['user-agent'], + language: $req.headers['accept-language'] && $req.headers['accept-language'].replace(/,.+$/, ''), + path: $req.path, + existing: !!$ctx.existing, + method: $req.method, + timestamp: Date.now() + } + $store.post('docs', 'logs', JSON.stringify(doc), 'application/json'); +}())
@@ -0,0 +1,4 @@
+(function(){ + $res.content = $req; + return true; +}())
@@ -0,0 +1,12 @@
+(function() { + var id = $req.path.replace(/^\/docs\//, ""); + var valid = /[A-Z]{2}[0-9]{3}[A-Z]{2}/; + if (!id.match(valid)) { + $res.content = { + error: "Invalid number plate" + }; + $res.code = 400; + return true; + } + $ctx.existing = !!($store.get("docs", id).code == 200); +})();
@@ -477,7 +477,6 @@ if not folder.isFolder:
return resError(Http400, "Invalid folder specified when creating document: $1" % folder) try: var doc = LS.store.createDocument(folder, body, ct) - echo doc if doc != "": result.headers = ctJsonHeader() setOrigin(LS, req, result.headers)
@@ -823,7 +823,6 @@ if id != "":
if resource == "indexes": var field = "" try: - echo req.body field = parseJson(req.body.strip)["field"].getStr except: return resError(Http400, "Bad Request - Invalid JSON body - $1" % getCurrentExceptionMsg())
@@ -0,0 +1,1131 @@
+import + asynchttpserver, + strutils, + sequtils, + cgi, + strtabs, + pegs, + json, + os, + uri, + times +import + types, + contenttypes, + core, + utils, + logger, + duktape + +# Helper procs + +proc sqlOp(op: string): string = + let table = newStringTable() + table["not eq"] = "<>" + table["eq"] = "==" + table["gt"] = ">" + table["gte"] = ">=" + table["lt"] = "<" + table["lte"] = "<=" + table["contains"] = "contains" + table["like"] = "like" + return table[op] + +proc orderByClauses*(str: string): string = + var clauses = newSeq[string]() + var fragments = str.split(",") + let clause = peg""" + clause <- {[-+]} {field} + field <- ('id' / 'created' / 'modified' / path) + path <- '$' (objField)+ + ident <- [a-zA-Z0-9_]+ + objField <- '.' ident + """ + for f in fragments: + var matches = @["", ""] + if f.find(clause, matches) != -1: + var field = matches[1] + if field[0] == '$': + field = "json_extract(documents.data, '$1')" % matches[1] + if matches[0] == "-": + clauses.add("$1 COLLATE NOCASE DESC" % field) + else: + clauses.add("$1 COLLATE NOCASE ASC" % field) + return clauses.join(", ") + +proc selectClause*(str: string, options: var QueryOptions) = + let tokens = """ + path <- '$' (objItem / objField)+ + ident <- [a-zA-Z0-9_]+ + objIndex <- '[' \d+ ']' + objField <- '.' ident + objItem <- objField objIndex + """ + let fields = peg(""" + fields <- ^{field} (\s* ',' \s* {field})*$ + field <- path \s+ ('as' / 'AS') \s+ ident + """ & tokens) + let field = peg(""" + field <- ^{path} \s+ ('as' / 'AS') \s+ {ident}$ + """ & tokens) + var fieldMatches = newSeq[string](10) + if str.strip.match(fields, fieldMatches): + for m in fieldMatches: + if m.len > 0: + var rawTuple = newSeq[string](2) + if m.match(field, rawTuple): + options.jsonSelect.add((path: rawTuple[0], alias: rawTuple[1])) + +proc filterClauses*(str: string, options: var QueryOptions) = + let tokens = """ + operator <- 'not eq' / 'eq' / 'gte' / 'gt' / 'lte' / 'lt' / 'contains' / 'like' + value <- string / number / 'null' / 'true' / 'false' + string <- '"' ('\\"' . / [^"])* '"' + number <- '-'? '0' / [1-9] [0-9]* ('.' [0-9]+)? (( 'e' / 'E' ) ( '+' / '-' )? [0-9]+)? + path <- '$' (objItem / objField)+ + ident <- [a-zA-Z0-9_]+ + objIndex <- '[' \d+ ']' + objField <- '.' ident + objItem <- objField objIndex + """ + let clause = peg(""" + clause <- {path} \s+ {operator} \s+ {value} + """ & tokens) + let andClauses = peg(""" + andClauses <- ^{clause} (\s+ 'and' \s+ {clause})*$ + clause <- path \s+ operator \s+ value + """ & tokens) + let orClauses = peg(""" + orClauses <- ^{andClauses} (\s+ 'or' \s+ {andClauses})*$ + andClauses <- clause (\s+ 'and' \s+ clause)* + clause <- path \s+ operator \s+ value + """ & tokens) + var orClausesMatches = newSeq[string](10) + discard str.strip.match(orClauses, orClausesMatches) + var parsedClauses = newSeq[seq[seq[string]]]() + for orClause in orClausesMatches: + if orClause.len > 0: + var andClausesMatches = newSeq[string](10) + discard orClause.strip.match(andClauses, andClausesMatches) + var parsedAndClauses = newSeq[seq[string]]() + for andClause in andClausesMatches: + if andClause.len > 0: + var clauses = newSeq[string](3) + discard andClause.strip.match(clause, clauses) + clauses[1] = sqlOp(clauses[1]) + if clauses[2] == "true": + clauses[2] = "1" + elif clauses[2] == "false": + clauses[2] = "0" + parsedAndClauses.add clauses + if parsedAndClauses.len > 0: + parsedClauses.add parsedAndClauses + if parsedClauses.len == 0: + return + var currentArr = 0 + var tables = newSeq[string]() + let resOrClauses = parsedClauses.map do (it: seq[seq[string]]) -> string: + let resAndClauses = it.map do (x: seq[string]) -> string: + if x[1] == "contains": + currentArr = currentArr + 1 + tables.add "json_each(documents.data, '$1') AS arr$2" % [x[0], $currentArr] + return "arr$1.value == $2" % [$currentArr, x[2]] + else: + var arr = @[x[0], x[1], x[2]] + if x[1] == "like": + arr[2] = x[2].replace('*', '%') + return "json_extract(documents.data, '$1') $2 $3 " % arr + return resAndClauses.join(" AND ") + options.tables = options.tables & tables + options.jsonFilter = resOrClauses.join(" OR ") + +proc parseQueryOption*(fragment: string, options: var QueryOptions) = + if fragment == "": + return + var pair = fragment.split('=') + if pair.len < 2 or pair[1] == "": + raise newException(EInvalidRequest, "Invalid query string fragment '$1'" % fragment) + try: + pair[1] = pair[1].replace("+", "%2B").decodeURL + except: + raise newException(EInvalidRequest, "Unable to decode query string fragment '$1'" % fragment) + case pair[0]: + of "filter": + filterClauses(pair[1], options) + if options.jsonFilter == "": + raise newException(EInvalidRequest, "Invalid filter clause: $1" % pair[1].replace("\"", "\\\"")) + of "select": + selectClause(pair[1], options) + if options.jsonSelect.len == 0: + raise newException(EInvalidRequest, "Invalid select clause: $1" % pair[1].replace("\"", "\\\"")) + of "like": + options.like = pair[1] + of "search": + options.search = pair[1] + of "tags": + options.tags = pair[1] + of "created-after": + try: + options.createdAfter = pair[1].parseInt.fromUnix.utc.format("yyyy-MM-dd'T'HH:mm:ss'Z'") + except: + raise newException(EInvalidRequest, "Invalid created-after value: $1" % getCurrentExceptionMsg()) + of "created-before": + try: + options.createdBefore = pair[1].parseInt.fromUnix.utc.format("yyyy-MM-dd'T'HH:mm:ss'Z'") + except: + raise newException(EInvalidRequest, "Invalid created-before value: $1" % getCurrentExceptionMsg()) + of "modified-after": + try: + options.modifiedAfter = pair[1].parseInt.fromUnix.utc.format("yyyy-MM-dd'T'HH:mm:ss'Z'") + except: + raise newException(EInvalidRequest, "Invalid modified.after value: $1" % getCurrentExceptionMsg()) + of "modified-before": + try: + options.modifiedBefore = pair[1].parseInt.fromUnix.utc.format("yyyy-MM-dd'T'HH:mm:ss'Z'") + except: + raise newException(EInvalidRequest, "Invalid modified-before value: $1" % getCurrentExceptionMsg()) + of "limit": + try: + options.limit = pair[1].parseInt + except: + raise newException(EInvalidRequest, "Invalid limit value: $1" % getCurrentExceptionMsg()) + of "offset": + try: + options.offset = pair[1].parseInt + except: + raise newException(EInvalidRequest, "Invalid offset value: $1" % getCurrentExceptionMsg()) + of "sort": + let orderby = pair[1].orderByClauses() + if orderby != "": + options.orderby = orderby + else: + raise newException(EInvalidRequest, "Invalid sort value: $1" % pair[1]) + of "contents", "raw": + discard + else: + discard + +proc parseQueryOptions*(querystring: string, options: var QueryOptions) = + var fragments = querystring.split('&') + for f in fragments: + f.parseQueryOption(options) + +proc validate*(req: LSRequest, LS: LiteStore, resource: string, id: string, cb: proc(req: LSRequest, LS: LiteStore, resource: string, id: string):LSResponse): LSResponse = + if req.reqMethod == HttpPost or req.reqMethod == HttpPut or req.reqMethod == HttpPatch: + var ct = "" + let body = req.body.strip + if body == "": + return resError(Http400, "Bad request: No content specified for document.") + if req.headers.hasKey("Content-Type"): + ct = req.headers["Content-Type"] + case ct: + of "application/json": + try: + discard body.parseJson() + except: + return resError(Http400, "Invalid JSON content - $1" % getCurrentExceptionMsg()) + else: + discard + return cb(req, LS, resource, id) + +proc patchTag(tags: var seq[string], index: int, op, path, value: string): bool = + LOG.debug("- PATCH -> $1 tag['$2'] = \"$3\" - Total tags: $4." % [op, $index, $value, $tags.len]) + case op: + of "remove": + let tag = tags[index] + if not tag.startsWith("$"): + tags[index] = "" # Not removing element, otherwise subsequent indexes won't work! + else: + raise newException(EInvalidRequest, "cannot remove system tag: $1" % tag) + of "add": + if value.match(PEG_USER_TAG): + tags.insert(value, index) + else: + if value.strip == "": + raise newException(EInvalidRequest, "tag not specified." % value) + else: + raise newException(EInvalidRequest, "invalid tag: $1" % value) + of "replace": + if value.match(PEG_USER_TAG): + if tags[index].startsWith("$"): + raise newException(EInvalidRequest, "cannot replace system tag: $1" % tags[index]) + else: + tags[index] = value + else: + if value.strip == "": + raise newException(EInvalidRequest, "tag not specified." % value) + else: + raise newException(EInvalidRequest, "invalid tag: $1" % value) + of "test": + if tags[index] != value: + return false + else: + raise newException(EInvalidRequest, "invalid patch operation: $1" % op) + return true + +proc patchData*(data: var JsonNode, origData: JsonNode, op: string, path: string, value: JsonNode): bool = + LOG.debug("- PATCH -> $1 path $2 with $3" % [op, path, $value]) + var keys = path.replace(peg"^\/data\/", "").split("/") + if keys.len == 0: + raise newException(EInvalidRequest, "no valid path specified: $1" % path) + var d = data + var dorig = origData + var c = 1 + for key in keys: + if d.kind == JArray: + try: + var index = key.parseInt + if c >= keys.len: + d.elems[index] = value + case op: + of "remove": + d.elems.del(index) + of "add": + d.elems.insert(value, index) + of "replace": + d.elems[index] = value + of "test": + if d.elems[index] != value: + return false + else: + raise newException(EInvalidRequest, "invalid patch operation: $1" % op) + else: + d = d[index] + dorig = dorig[index] + except: + raise newException(EInvalidRequest, "invalid index key '$1' in path '$2'" % [key, path]) + else: + if c >= keys.len: + case op: + of "remove": + if d.hasKey(key): + d.delete(key) + else: + raise newException(EInvalidRequest, "key '$1' not found in path '$2'" % [key, path]) + of "add": + d[key] = value + of "replace": + if d.hasKey(key): + d[key] = value + else: + raise newException(EInvalidRequest, "key '$1' not found in path '$2'" % [key, path]) + of "test": + if dorig.hasKey(key): + if dorig[key] != value: + return false + else: + raise newException(EInvalidRequest, "key '$1' not found in path '$2'" % [key, path]) + else: + raise newException(EInvalidRequest, "invalid patch operation: $1" % op) + else: + d = d[key] + dorig = dorig[key] + c += 1 + return true + + +proc applyPatchOperation*(data: var JsonNode, origData: JsonNode, tags: var seq[string], op: string, path: string, value: JsonNode): bool = + var matches = @[""] + let p = peg""" + path <- ^tagPath / fieldPath$ + tagPath <- '\/tags\/' {\d+} + fieldPath <- '\/data\/' ident ('\/' ident)* + ident <- [a-zA-Z0-9_]+ / '-' + """ + if path.find(p, matches) == -1: + raise newException(EInvalidRequest, "cannot patch path '$1'" % path) + if path.match(peg"^\/tags\/"): + let index = matches[0].parseInt + if value.kind != JString: + raise newException(EInvalidRequest, "tag '$1' is not a string." % $value) + let tag = value.getStr + return patchTag(tags, index, op, path, tag) + elif tags.contains("$subtype:json"): + return patchData(data, origData, op, path, value) + else: + raise newException(EInvalidRequest, "cannot patch data of a non-JSON document.") + +# Low level procs + +proc getTag*(LS: LiteStore, id: string, options = newQueryOptions(), req: LSRequest): LSResponse = + let doc = LS.store.retrieveTag(id, options) + result.headers = ctJsonHeader() + setOrigin(LS, req, result.headers) + if doc == newJNull(): + result = resTagNotFound(id) + else: + result.content = $doc + result.code = Http200 + +proc getIndex*(LS: LiteStore, id: string, options = newQueryOptions(), req: LSRequest): LSResponse = + let doc = LS.store.retrieveIndex(id, options) + result.headers = ctJsonHeader() + setOrigin(LS, req, result.headers) + if doc == newJNull(): + result = resIndexNotFound(id) + else: + result.content = $doc + result.code = Http200 + +proc getRawDocument*(LS: LiteStore, id: string, options = newQueryOptions(), req: LSRequest): LSResponse = + let doc = LS.store.retrieveRawDocument(id, options) + result.headers = ctJsonHeader() + setOrigin(LS, req, result.headers) + if doc == "": + result = resDocumentNotFound(id) + else: + result.content = doc + result.code = Http200 + +proc getDocument*(LS: LiteStore, id: string, options = newQueryOptions(), req: LSRequest): LSResponse = + let doc = LS.store.retrieveDocument(id, options) + if doc.data == "": + result = resDocumentNotFound(id) + else: + result.headers = doc.contenttype.ctHeader + setOrigin(LS, req, result.headers) + result.content = doc.data + result.code = Http200 + +proc deleteDocument*(LS: LiteStore, id: string, req: LSRequest): LSResponse = + let doc = LS.store.retrieveDocument(id) + if doc.data == "": + result = resDocumentNotFound(id) + else: + try: + let res = LS.store.destroyDocument(id) + if res == 0: + result = resError(Http500, "Unable to delete document '$1'" % id) + else: + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + result.headers["Content-Length"] = "0" + result.content = "" + result.code = Http204 + except: + result = resError(Http500, "Unable to delete document '$1'" % id) + +proc getTags*(LS: LiteStore, options: QueryOptions = newQueryOptions(), req: LSRequest): LSResponse = + var options = options + let t0 = cpuTime() + let docs = LS.store.retrieveTags(options) + let orig_limit = options.limit + let orig_offset = options.offset + options.limit = 0 + options.offset = 0 + options.select = @["COUNT(tag_id)"] + let total = LS.store.countTags(prepareSelectTagsQuery(options), options.like.replace("*", "%")) + var content = newJObject() + if options.like != "": + content["like"] = %(options.like.decodeURL) + if orig_limit > 0: + content["limit"] = %orig_limit + if orig_offset > 0: + content["offset"] = %orig_offset + content["total"] = %total + content["execution_time"] = %(cputime()-t0) + content["results"] = docs + result.headers = ctJsonHeader() + setOrigin(LS, req, result.headers) + result.content = content.pretty + result.code = Http200 + +proc getIndexes*(LS: LiteStore, options: QueryOptions = newQueryOptions(), req: LSRequest): LSResponse = + var options = options + let t0 = cpuTime() + let docs = LS.store.retrieveIndexes(options) + let orig_limit = options.limit + let orig_offset = options.offset + options.limit = 0 + options.offset = 0 + options.select = @["COUNT(name)"] + let total = LS.store.countIndexes(prepareSelectIndexesQuery(options), options.like.replace("*", "%")) + var content = newJObject() + if options.like != "": + content["like"] = %(options.like.decodeURL) + if orig_limit > 0: + content["limit"] = %orig_limit + if orig_offset > 0: + content["offset"] = %orig_offset + content["total"] = %total + content["execution_time"] = %(cputime()-t0) + content["results"] = docs + result.headers = ctJsonHeader() + setOrigin(LS, req, result.headers) + result.content = content.pretty + result.code = Http200 + +proc getRawDocuments*(LS: LiteStore, options: QueryOptions = newQueryOptions(), req: LSRequest): LSResponse = + var options = options + let t0 = cpuTime() + let docs = LS.store.retrieveRawDocuments(options) + let orig_limit = options.limit + let orig_offset = options.offset + options.limit = 0 + options.offset = 0 + options.select = @["COUNT(docid)"] + let total = LS.store.retrieveRawDocuments(options)[0].num + var content = newJObject() + if options.folder != "": + content["folder"] = %(options.folder) + if options.search != "": + content["search"] = %(options.search.decodeURL) + if options.tags != "": + content["tags"] = newJArray() + for tag in options.tags.replace("+", "%2B").decodeURL.split(","): + content["tags"].add(%tag) + if orig_limit > 0: + content["limit"] = %orig_limit + if orig_offset > 0: + content["offset"] = %orig_offset + if options.orderby != "": + content["sort"] = %options.orderby + content["total"] = %total + content["execution_time"] = %(cputime()-t0) + content["results"] = docs + result.headers = ctJsonHeader() + setOrigin(LS, req, result.headers) + result.content = content.pretty + result.code = Http200 + +proc getInfo*(LS: LiteStore, req: LSRequest): LSResponse = + let info = LS.store.retrieveInfo() + let version = info[0] + let total_documents = info[1] + let total_tags = LS.store.countTags() + let tags = LS.store.retrieveTagsWithTotals() + var content = newJObject() + content["version"] = %(LS.appname & " v" & LS.appversion) + content["datastore_version"] = %version + content["size"] = %($((LS.file.getFileSize().float/(1024*1024)).formatFloat(ffDecimal, 2)) & " MB") + content["read_only"] = %LS.readonly + content["log_level"] = %LS.loglevel + if LS.directory.len == 0: + content["directory"] = newJNull() + else: + content["directory"] = %LS.directory + content["mount"] = %LS.mount + content["total_documents"] = %total_documents + content["total_tags"] = %total_tags + content["tags"] = tags + result.headers = ctJsonHeader() + setOrigin(LS, req, result.headers) + result.content = content.pretty + result.code = Http200 + +proc putIndex*(LS: LiteStore, id, field: string, req: LSRequest): LSResponse = + try: + if (not id.match(PEG_INDEX)): + return resError(Http400, "invalid index ID: $1" % id) + if (not field.match(PEG_JSON_FIELD)): + return resError(Http400, "invalid field path: $1" % field) + if (LS.store.retrieveIndex(id) != newJNull()): + return resError(Http409, "Index already exists: $1" % id) + LS.store.createIndex(id, field) + result.headers = ctJsonHeader() + setOrigin(LS, req, result.headers) + result.content = "{\"id\": \"$1\", \"field\": \"$2\"}" % [id, field] + result.code = Http200 + except: + eWarn() + result = resError(Http500, "Unable to create index.") + +proc deleteIndex*(LS: LiteStore, id: string, req: LSRequest): LSResponse = + if (not id.match(PEG_INDEX)): + return resError(Http400, "invalid index ID: $1" % id) + if (LS.store.retrieveIndex(id) == newJNull()): + return resError(Http404, "Index not found: $1" % id) + try: + LS.store.dropIndex(id) + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + result.headers["Content-Length"] = "0" + result.content = "" + result.code = Http204 + except: + eWarn() + result = resError(Http500, "Unable to delete index.") + +proc postDocument*(LS: LiteStore, body: string, ct: string, folder="", req: LSRequest): LSResponse = + if not folder.isFolder: + return resError(Http400, "Invalid folder specified when creating document: $1" % folder) + try: + var doc = LS.store.createDocument(folder, body, ct) + if doc != "": + result.headers = ctJsonHeader() + setOrigin(LS, req, result.headers) + result.content = doc + result.code = Http201 + else: + result = resError(Http500, "Unable to create document.") + except: + eWarn() + result = resError(Http500, "Unable to create document.") + +proc putDocument*(LS: LiteStore, id: string, body: string, ct: string, req: LSRequest): LSResponse = + if id.isFolder: + return resError(Http400, "Invalid ID '$1' (Document IDs cannot end with '/')." % id) + let doc = LS.store.retrieveDocument(id) + if doc.data == "": + # Create a new document + var doc = LS.store.createDocument(id, body, ct) + if doc != "": + result.headers = ctJsonHeader() + setOrigin(LS, req, result.headers) + result.content = doc + result.code = Http201 + else: + result = resError(Http500, "Unable to create document.") + else: + # Update existing document + try: + var doc = LS.store.updateDocument(id, body, ct) + if doc != "": + result.headers = ctJsonHeader() + setOrigin(LS, req, result.headers) + result.content = doc + result.code = Http200 + else: + result = resError(Http500, "Unable to update document '$1'." % id) + except: + result = resError(Http500, "Unable to update document '$1'." % id) + +proc patchDocument*(LS: LiteStore, id: string, body: string, req: LSRequest): LSResponse = + var apply = true + let jbody = body.parseJson + if jbody.kind != JArray: + return resError(Http400, "Bad request: PATCH request body is not an array.") + var options = newQueryOptions() + options.select = @["documents.id AS id", "created", "modified", "data"] + let doc = LS.store.retrieveRawDocument(id, options) + if doc == "": + return resDocumentNotFound(id) + let jdoc = doc.parseJson + var tags = newSeq[string]() + var origTags = newSeq[string]() + for tag in jdoc["tags"].items: + tags.add(tag.str) + origTags.add(tag.str) + var data: JsonNode + var origData: JsonNode + if tags.contains("$subtype:json"): + try: + origData = jdoc["data"].getStr.parseJson + data = origData.copy + except: + discard + var c = 1 + for item in jbody.items: + if item.hasKey("op") and item.hasKey("path"): + if not item.hasKey("value"): + item["value"] = %"" + try: + apply = applyPatchOperation(data, origData, tags, item["op"].str, item["path"].str, item["value"]) + if not apply: + break + except: + return resError(Http400, "Bad request - $1" % getCurrentExceptionMsg()) + else: + return resError(Http400, "Bad request: patch operation #$1 is malformed." % $c) + c.inc + if apply: + if origData.len > 0 and origData != data: + try: + var doc = LS.store.updateDocument(id, data.pretty, "application/json") + if doc == "": + return resError(Http500, "Unable to patch document '$1'." % id) + except: + return resError(Http500, "Unable to patch document '$1' - $2" % id, getCurrentExceptionMsg()) + if origTags != tags: + try: + for t1 in jdoc["tags"].items: + discard LS.store.destroyTag(t1.str, id, true) + for t2 in tags: + if t2 != "": + LS.store.createTag(t2, id, true) + except: + return resError(Http500, "Unable to patch document '$1' - $2" % [id, getCurrentExceptionMsg()]) + return LS.getRawDocument(id, newQueryOptions(), req) + +# Main routing + +proc options*(req: LSRequest, LS: LiteStore, resource: string, id = ""): LSResponse = + case resource: + of "info": + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + result.headers["Allow"] = "GET, OPTIONS" + result.headers["Access-Control-Allow-Methods"] = "GET, OPTIONS" + if id != "": + return resError(Http404, "Info '$1' not found." % id) + else: + result.code = Http204 + result.content = "" + of "dir": + result.code = Http204 + result.content = "" + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + result.headers["Allow"] = "GET, OPTIONS" + result.headers["Access-Control-Allow-Methods"] = "GET, OPTIONS" + of "tags": + result.code = Http204 + result.content = "" + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + result.headers["Allow"] = "GET, OPTIONS" + result.headers["Access-Control-Allow-Methods"] = "GET, OPTIONS" + of "indexes": + result.code = Http204 + result.content = "" + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + if id != "": + result.code = Http204 + result.content = "" + if LS.readonly: + result.headers["Allow"] = "GET, OPTIONS" + result.headers["Access-Control-Allow-Methods"] = "GET, OPTIONS" + else: + result.headers["Allow"] = "GET, OPTIONS, PUT, DELETE" + result.headers["Access-Control-Allow-Methods"] = "GET, OPTIONS, PUT, DELETE" + else: + result.code = Http204 + result.content = "" + if LS.readonly: + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + result.headers["Allow"] = "GET, OPTIONS" + result.headers["Access-Control-Allow-Methods"] = "GET, OPTIONS" + else: + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + result.headers["Allow"] = "GET, OPTIONS" + result.headers["Access-Control-Allow-Methods"] = "GET, OPTIONS" + of "docs": + var folder: string + if id.isFolder: + folder = id + if folder.len > 0: + result.code = Http204 + result.content = "" + if LS.readonly: + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + result.headers["Allow"] = "HEAD, GET, OPTIONS" + result.headers["Access-Control-Allow-Methods"] = "HEAD, GET, OPTIONS" + else: + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + result.headers["Allow"] = "HEAD, GET, OPTIONS, POST, PUT" + result.headers["Access-Control-Allow-Methods"] = "HEAD, GET, OPTIONS, POST, PUT" + elif id != "": + result.code = Http204 + result.content = "" + if LS.readonly: + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + result.headers["Allow"] = "HEAD, GET, OPTIONS" + result.headers["Access-Control-Allow-Methods"] = "HEAD, GET, OPTIONS" + else: + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + result.headers["Allow"] = "HEAD, GET, OPTIONS, PUT, PATCH, DELETE" + result.headers["Allow-Patch"] = "application/json-patch+json" + result.headers["Access-Control-Allow-Methods"] = "HEAD, GET, OPTIONS, PUT, PATCH, DELETE" + else: + result.code = Http204 + result.content = "" + if LS.readonly: + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + result.headers["Allow"] = "HEAD, GET, OPTIONS" + result.headers["Access-Control-Allow-Methods"] = "HEAD, GET, OPTIONS" + else: + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + result.headers["Allow"] = "HEAD, GET, OPTIONS, POST" + result.headers["Access-Control-Allow-Methods"] = "HEAD, GET, OPTIONS, POST" + else: + discard # never happens really. + +proc head*(req: LSRequest, LS: LiteStore, resource: string, id = ""): LSResponse = + var options = newQueryOptions() + options.select = @["documents.id AS id", "created", "modified"] + if id.isFolder: + options.folder = id + try: + parseQueryOptions(req.url.query, options); + if id != "" and options.folder == "": + result = LS.getRawDocument(id, options, req) + result.content = "" + else: + result = LS.getRawDocuments(options, req) + result.content = "" + except: + return resError(Http400, "Bad request - $1" % getCurrentExceptionMsg()) + +proc get*(req: LSRequest, LS: LiteStore, resource: string, id = ""): LSResponse = + case resource: + of "docs": + var options = newQueryOptions() + if id.isFolder: + options.folder = id + if req.url.query.contains("contents=false"): + options.select = @["documents.id AS id", "created", "modified"] + try: + parseQueryOptions(req.url.query, options); + if id != "" and options.folder == "": + if req.url.query.contains("raw=true") or req.headers.hasKey("Accept") and req.headers["Accept"] == "application/json": + return LS.getRawDocument(id, options, req) + else: + return LS.getDocument(id, options, req) + else: + return LS.getRawDocuments(options, req) + except: + let e = getCurrentException() + let trace = e.getStackTrace() + echo trace + return resError(Http400, "Bad Request - $1" % getCurrentExceptionMsg()) + of "tags": + var options = newQueryOptions() + try: + parseQueryOptions(req.url.query, options); + if id != "": + return LS.getTag(id, options, req) + else: + return LS.getTags(options, req) + except: + return resError(Http400, "Bad Request - $1" % getCurrentExceptionMsg()) + of "indexes": + var options = newQueryOptions() + try: + parseQueryOptions(req.url.query, options); + if id != "": + return LS.getIndex(id, options, req) + else: + return LS.getIndexes(options, req) + except: + return resError(Http400, "Bad Request - $1" % getCurrentExceptionMsg()) + of "info": + if id != "": + return resError(Http404, "Info '$1' not found." % id) + return LS.getInfo(req) + else: + discard # never happens really. + +proc post*(req: LSRequest, LS: LiteStore, resource: string, id = ""): LSResponse = + var ct = "text/plain" + if req.headers.hasKey("Content-Type"): + ct = req.headers["Content-Type"] + return LS.postDocument(req.body.strip, ct, id, req) + +proc put*(req: LSRequest, LS: LiteStore, resource: string, id = ""): LSResponse = + if id != "": + if resource == "indexes": + var field = "" + try: + field = parseJson(req.body.strip)["field"].getStr + except: + return resError(Http400, "Bad Request - Invalid JSON body - $1" % getCurrentExceptionMsg()) + return LS.putIndex(id, field, req) + else: # Assume docs + var ct = "text/plain" + if req.headers.hasKey("Content-Type"): + ct = req.headers["Content-Type"] + return LS.putDocument(id, req.body.strip, ct, req) + else: + return resError(Http400, "Bad request: document ID must be specified in PUT requests.") + +proc delete*(req: LSRequest, LS: LiteStore, resource: string, id = ""): LSResponse = + if id != "": + if resource == "indexes": + return LS.deleteIndex(id, req) + else: # Assume docs + return LS.deleteDocument(id, req) + else: + return resError(Http400, "Bad request: document ID must be specified in DELETE requests.") + +proc patch*(req: LSRequest, LS: LiteStore, resource: string, id = ""): LSResponse = + if id != "": + return LS.patchDocument(id, req.body, req) + else: + return resError(Http400, "Bad request: document ID must be specified in PATCH requests.") + +proc serveFile*(req: LSRequest, LS: LiteStore, id: string): LSResponse = + let path = LS.directory / id + var reqMethod = $req.reqMethod + if req.headers.hasKey("X-HTTP-Method-Override"): + reqMethod = req.headers["X-HTTP-Method-Override"] + case reqMethod.toUpperAscii: + of "OPTIONS": + return validate(req, LS, "dir", id, options) + of "GET": + if path.fileExists: + try: + let contents = path.readFile + let parts = path.splitFile + if CONTENT_TYPES.hasKey(parts.ext): + result.headers = CONTENT_TYPES[parts.ext].ctHeader + else: + result.headers = ctHeader("text/plain") + setOrigin(LS, req, result.headers) + result.content = contents + result.code = Http200 + except: + return resError(Http500, "Unable to read file '$1'." % path) + else: + return resError(Http404, "File '$1' not found." % path) + else: + return resError(Http405, "Method not allowed: $1" % $req.reqMethod) + +proc route*(req: LSRequest, LS: LiteStore, resource = "docs", id = ""): LSResponse = + var reqMethod = $req.reqMethod + if req.headers.hasKey("X-HTTP-Method-Override"): + reqMethod = req.headers["X-HTTP-Method-Override"] + case reqMethod.toUpperAscii: + of "POST": + if LS.readonly: + return resError(Http405, "Method not allowed: $1" % $req.reqMethod) + return validate(req, LS, resource, id, post) + of "PUT": + if LS.readonly: + return resError(Http405, "Method not allowed: $1" % $req.reqMethod) + return validate(req, LS, resource, id, put) + of "DELETE": + if LS.readonly: + return resError(Http405, "Method not allowed: $1" % $req.reqMethod) + return validate(req, LS, resource, id, delete) + of "HEAD": + return validate(req, LS, resource, id, head) + of "OPTIONS": + return validate(req, LS, resource, id, options) + of "GET": + return validate(req, LS, resource, id, get) + of "PATCH": + if LS.readonly: + return resError(Http405, "Method not allowed: $1" % $req.reqMethod) + return validate(req, LS, resource, id, patch) + else: + return resError(Http405, "Method not allowed: $1" % $req.reqMethod) + +proc newSimpleLSRequest(meth: HttpMethod, resource, id, body = "", params = "", headers = newHttpHeaders()): LSRequest = + result.reqMethod = meth + result.body = body + result.headers = headers + result.url = parseUri("$1://$2:$3/$4/$5?$6" % @["http", "localhost", "9500", resource, id, params]) + +proc get(resource, id: string, params = ""): LSResponse = + return newSimpleLSRequest(HttpGet, resource, id, "", params).get(LS, resource, id) + +proc post(resource, folder, body: string, ct = ""): LSResponse = + var headers = newHttpHeaders() + if ct != "": + headers["Content-Type"] = ct + return newSimpleLSRequest(HttpPost, resource, "", body, "", headers).post(LS, resource, folder & "/") + +proc put(resource, id, body: string, ct = ""): LSResponse = + var headers = newHttpHeaders() + if ct != "": + headers["Content-Type"] = ct + return newSimpleLSRequest(HttpPut, resource, id, body, "", headers).put(LS, resource, id) + +proc patch(resource, id, body: string): LSResponse = + var headers = newHttpHeaders() + headers["Content-Type"] = "application/json" + return newSimpleLSRequest(HttpPatch, resource, id, body, "", headers).patch(LS, resource, id) + +proc delete(resource, id: string): LSResponse = + return newSimpleLSRequest(HttpPatch, resource, id).delete(LS, resource, id) + +proc head(resource, id: string): LSResponse = + return newSimpleLSRequest(HttpHead, resource, id).head(LS, resource, id) + +proc registerStoreApi(LS: LiteStore, ctx: DTContext, origResource, origId: string) = + var api_idx = ctx.duk_push_object() + # GET + var get: DTCFunction = (proc (ctx: DTContext): cint{.stdcall.} = + let resource = duk_get_string(ctx, 0) + let id = duk_get_string(ctx, 1) + let params = duk_get_string(ctx, 2) + let resp = get($resource, $id, $params) + var res_idx = ctx.duk_push_object() + ctx.duk_push_int(cast[cint](resp.code)) + discard ctx.duk_put_prop_string(res_idx, "code") + discard ctx.duk_push_string(resp.content) + discard ctx.duk_put_prop_string(res_idx, "content") + return 1 + ) + discard duk_push_c_function(ctx, get, 3) + discard ctx.duk_put_prop_string(api_idx, "get") + # POST + var post: DTCFunction = (proc (ctx: DTContext): cint{.stdcall.} = + let resource = duk_get_string(ctx, 0) + let folder = duk_get_string(ctx, 1) + let body = duk_get_string(ctx, 2) + let ct = duk_get_string(ctx, 3) + let resp = post($resource, $folder, $body, $ct) + var res_idx = ctx.duk_push_object() + ctx.duk_push_int(cast[cint](resp.code)) + discard ctx.duk_put_prop_string(res_idx, "code") + discard ctx.duk_push_string(resp.content) + discard ctx.duk_put_prop_string(res_idx, "content") + return 1 + ) + discard duk_push_c_function(ctx, post, 4) + discard ctx.duk_put_prop_string(api_idx, "post") + # PUT + var put: DTCFunction = (proc (ctx: DTContext): cint{.stdcall.} = + let resource = duk_get_string(ctx, 0) + let id = duk_get_string(ctx, 1) + let body = duk_get_string(ctx, 2) + let ct = duk_get_string(ctx, 3) + let resp = put($resource, $id, $body, $ct) + var res_idx = ctx.duk_push_object() + ctx.duk_push_int(cast[cint](resp.code)) + discard ctx.duk_put_prop_string(res_idx, "code") + discard ctx.duk_push_string(resp.content) + discard ctx.duk_put_prop_string(res_idx, "content") + return 1 + ) + discard duk_push_c_function(ctx, put, 4) + discard ctx.duk_put_prop_string(api_idx, "put") + # PATCH + var patch: DTCFunction = (proc (ctx: DTContext): cint{.stdcall.} = + let resource = duk_get_string(ctx, 0) + let id = duk_get_string(ctx, 1) + let body = duk_get_string(ctx, 2) + let resp = patch($resource, $id, $body) + var res_idx = ctx.duk_push_object() + ctx.duk_push_int(cast[cint](resp.code)) + discard ctx.duk_put_prop_string(res_idx, "code") + discard ctx.duk_push_string(resp.content) + discard ctx.duk_put_prop_string(res_idx, "content") + return 1 + ) + discard duk_push_c_function(ctx, patch, 3) + discard ctx.duk_put_prop_string(api_idx, "patch") + # DELETE + var delete: DTCFunction = (proc (ctx: DTContext): cint{.stdcall.} = + let resource = duk_get_string(ctx, 0) + let id = duk_get_string(ctx, 1) + let resp = delete($resource, $id) + var res_idx = ctx.duk_push_object() + ctx.duk_push_int(cast[cint](resp.code)) + discard ctx.duk_put_prop_string(res_idx, "code") + discard ctx.duk_push_string(resp.content) + discard ctx.duk_put_prop_string(res_idx, "content") + return 1 + ) + discard duk_push_c_function(ctx, delete, 2) + discard ctx.duk_put_prop_string(api_idx, "delete") + # HEAD + var head: DTCFunction = (proc (ctx: DTContext): cint{.stdcall.} = + let resource = duk_get_string(ctx, 0) + let id = duk_get_string(ctx, 1) + let resp = head($resource, $id) + var res_idx = ctx.duk_push_object() + ctx.duk_push_int(cast[cint](resp.code)) + discard ctx.duk_put_prop_string(res_idx, "code") + discard ctx.duk_push_string(resp.content) + discard ctx.duk_put_prop_string(res_idx, "content") + return 1 + ) + discard duk_push_c_function(ctx, head, 2) + discard ctx.duk_put_prop_string(api_idx, "head") + discard ctx.duk_put_global_string("$store") + +proc jError(ctx: DTContext): LSResponse = + return resError(Http500, "Middleware Error: " & $ctx.duk_safe_to_string(-1)) + +proc getMiddleware*(LS: LiteStore, id: string): string = + if not LS.middleware.hasKey(id): + # Attempt to retrieve resource from system documents + let options = newQueryOptions(true) + let doc = LS.store.retrieveDocument("middleware/" & id & ".js", options) + result = doc.data + if result == "": + LOG.warn("Middleware '$1' not found" % id) + else: + result = LS.middleware[id] + +proc getMiddlewareSeq(resource, id, meth: string): seq[string] = + result = newSeq[string]() + if LS.config.kind != JObject or not LS.config.hasKey("resources"): + return + var reqUri = "/" & resource & "/" & id + if reqUri[^1] == '/': + reqUri.removeSuffix({'/'}) + let parts = reqUri.split("/") + let ancestors = parts[1..parts.len-2] + var currentPath = "" + var currentPaths = "" + for p in ancestors: + currentPath &= "/" & p + currentPaths = currentPath & "/*" + if LS.config["resources"].hasKey(currentPaths) and LS.config["resources"][currentPaths].hasKey(meth) and LS.config["resources"][currentPaths][meth].hasKey("middleware"): + let mw = LS.config["resources"][currentPaths][meth]["middleware"] + if (mw.kind == JArray): + for m in mw: + result.add m.getStr + if LS.config["resources"].hasKey(reqUri) and LS.config["resources"][reqUri].hasKey(meth) and LS.config["resources"][reqUri][meth].hasKey("middleware"): + let mw = LS.config["resources"][reqUri][meth]["middleware"] + if (mw.kind == JArray): + for m in mw: + result.add m.getStr + +proc execute*(req: var LSRequest, LS: LiteStore, resource, id: string): LSResponse = + let middleware = getMiddlewareSeq(resource, id, $req.reqMethod) + LOG.debug("Middleware: " & middleware.join(" -> ")); + if middleware.len == 0: + return route(req, LS, resource, id) + var jReq = $(%* req) + LOG.debug("Request: " & jReq) + var jRes = """{ + "code": 200, + "content": {}, + "final": false, + "headers": { + "Access-Control-Allow-Origin": "*", + "Access-Control-Allow-Headers": "Authorization, Content-Type", + "Server": "$1", + "Content-Type": "application/json" + } + }""" % [LS.appname & "/" & LS.appversion] + var context = "{}" + # Create execution context + var ctx = duk_create_heap_default() + duk_console_init(ctx) + duk_print_alert_init(ctx) + LS.registerStoreApi(ctx, resource, id) + if ctx.duk_peval_string("($1)" % $jReq) != 0: + return jError(ctx) + discard ctx.duk_put_global_string("$req") + if ctx.duk_peval_string("($1)" % $jRes) != 0: + return jError(ctx) + discard ctx.duk_put_global_string("$res") + if ctx.duk_peval_string("($1)" % $context) != 0: + return jError(ctx) + discard ctx.duk_put_global_string("$ctx") + # Middleware-specific functions + var i = 0 + var abort = 0 + while abort != 1 and i < middleware.len: + let code = LS.getMiddleware(middleware[i]) + LOG.debug("Evaluating middleware '$1'" % middleware[i]) + if ctx.duk_peval_string(code) != 0: + return jError(ctx) + abort = ctx.duk_get_boolean(-1) + i.inc + # Retrieve response, and request + if ctx.duk_peval_string("JSON.stringify($res);") != 0: + return jError(ctx) + let fRes = parseJson($(ctx.duk_get_string(-1))).newLSResponse + if ctx.duk_peval_string("JSON.stringify($req);") != 0: + return jError(ctx) + let fReq = parseJson($(ctx.duk_get_string(-1))).newLSRequest() + ctx.duk_destroy_heap(); + LOG.debug("abort: $1", [$abort]) + if abort == 1: + return fRes + return route(fReq, LS, resource, id)
@@ -0,0 +1,1263 @@
+import + asynchttpserver, + strutils, + sequtils, + cgi, + strtabs, + pegs, + json, + os, + uri, + tables, + times +import + types, + contenttypes, + core, + utils, + logger, + duktape + +# Helper procs + +proc sqlOp(op: string): string = + let table = newStringTable() + table["not eq"] = "<>" + table["eq"] = "==" + table["gt"] = ">" + table["gte"] = ">=" + table["lt"] = "<" + table["lte"] = "<=" + table["contains"] = "contains" + table["like"] = "like" + return table[op] + +proc orderByClauses*(str: string): string = + var clauses = newSeq[string]() + var fragments = str.split(",") + let clause = peg""" + clause <- {[-+]} {field} + field <- ('id' / 'created' / 'modified' / path) + path <- '$' (objField)+ + ident <- [a-zA-Z0-9_]+ + objField <- '.' ident + """ + for f in fragments: + var matches = @["", ""] + if f.find(clause, matches) != -1: + var field = matches[1] + if field[0] == '$': + field = "json_extract(documents.data, '$1')" % matches[1] + if matches[0] == "-": + clauses.add("$1 COLLATE NOCASE DESC" % field) + else: + clauses.add("$1 COLLATE NOCASE ASC" % field) + return clauses.join(", ") + +proc selectClause*(str: string, options: var QueryOptions) = + let tokens = """ + path <- '$' (objItem / objField)+ + ident <- [a-zA-Z0-9_]+ + objIndex <- '[' \d+ ']' + objField <- '.' ident + objItem <- objField objIndex + """ + let fields = peg(""" + fields <- ^{field} (\s* ',' \s* {field})*$ + field <- path \s+ ('as' / 'AS') \s+ ident + """ & tokens) + let field = peg(""" + field <- ^{path} \s+ ('as' / 'AS') \s+ {ident}$ + """ & tokens) + var fieldMatches = newSeq[string](10) + if str.strip.match(fields, fieldMatches): + for m in fieldMatches: + if m.len > 0: + var rawTuple = newSeq[string](2) + if m.match(field, rawTuple): + options.jsonSelect.add((path: rawTuple[0], alias: rawTuple[1])) + +proc filterClauses*(str: string, options: var QueryOptions) = + let tokens = """ + operator <- 'not eq' / 'eq' / 'gte' / 'gt' / 'lte' / 'lt' / 'contains' / 'like' + value <- string / number / 'null' / 'true' / 'false' + string <- '"' ('\\"' . / [^"])* '"' + number <- '-'? '0' / [1-9] [0-9]* ('.' [0-9]+)? (( 'e' / 'E' ) ( '+' / '-' )? [0-9]+)? + path <- '$' (objItem / objField)+ + ident <- [a-zA-Z0-9_]+ + objIndex <- '[' \d+ ']' + objField <- '.' ident + objItem <- objField objIndex + """ + let clause = peg(""" + clause <- {path} \s+ {operator} \s+ {value} + """ & tokens) + let andClauses = peg(""" + andClauses <- ^{clause} (\s+ 'and' \s+ {clause})*$ + clause <- path \s+ operator \s+ value + """ & tokens) + let orClauses = peg(""" + orClauses <- ^{andClauses} (\s+ 'or' \s+ {andClauses})*$ + andClauses <- clause (\s+ 'and' \s+ clause)* + clause <- path \s+ operator \s+ value + """ & tokens) + var orClausesMatches = newSeq[string](10) + discard str.strip.match(orClauses, orClausesMatches) + var parsedClauses = newSeq[seq[seq[string]]]() + for orClause in orClausesMatches: + if orClause.len > 0: + var andClausesMatches = newSeq[string](10) + discard orClause.strip.match(andClauses, andClausesMatches) + var parsedAndClauses = newSeq[seq[string]]() + for andClause in andClausesMatches: + if andClause.len > 0: + var clauses = newSeq[string](3) + discard andClause.strip.match(clause, clauses) + clauses[1] = sqlOp(clauses[1]) + if clauses[2] == "true": + clauses[2] = "1" + elif clauses[2] == "false": + clauses[2] = "0" + parsedAndClauses.add clauses + if parsedAndClauses.len > 0: + parsedClauses.add parsedAndClauses + if parsedClauses.len == 0: + return + var currentArr = 0 + var tables = newSeq[string]() + let resOrClauses = parsedClauses.map do (it: seq[seq[string]]) -> string: + let resAndClauses = it.map do (x: seq[string]) -> string: + if x[1] == "contains": + currentArr = currentArr + 1 + tables.add "json_each(documents.data, '$1') AS arr$2" % [x[0], $currentArr] + return "arr$1.value == $2" % [$currentArr, x[2]] + else: + var arr = @[x[0], x[1], x[2]] + if x[1] == "like": + arr[2] = x[2].replace('*', '%') + return "json_extract(documents.data, '$1') $2 $3 " % arr + return resAndClauses.join(" AND ") + options.tables = options.tables & tables + options.jsonFilter = resOrClauses.join(" OR ") + +proc parseQueryOption*(fragment: string, options: var QueryOptions) = + if fragment == "": + return + var pair = fragment.split('=') + if pair.len < 2 or pair[1] == "": + raise newException(EInvalidRequest, "Invalid query string fragment '$1'" % fragment) + try: + pair[1] = pair[1].replace("+", "%2B").decodeURL + except: + raise newException(EInvalidRequest, "Unable to decode query string fragment '$1'" % fragment) + case pair[0]: + of "filter": + filterClauses(pair[1], options) + if options.jsonFilter == "": + raise newException(EInvalidRequest, "Invalid filter clause: $1" % pair[1].replace("\"", "\\\"")) + of "select": + selectClause(pair[1], options) + if options.jsonSelect.len == 0: + raise newException(EInvalidRequest, "Invalid select clause: $1" % pair[1].replace("\"", "\\\"")) + of "like": + options.like = pair[1] + of "search": + options.search = pair[1] + of "tags": + options.tags = pair[1] + of "created-after": + try: + options.createdAfter = pair[1].parseInt.fromUnix.utc.format("yyyy-MM-dd'T'HH:mm:ss'Z'") + except: + raise newException(EInvalidRequest, "Invalid created-after value: $1" % getCurrentExceptionMsg()) + of "created-before": + try: + options.createdBefore = pair[1].parseInt.fromUnix.utc.format("yyyy-MM-dd'T'HH:mm:ss'Z'") + except: + raise newException(EInvalidRequest, "Invalid created-before value: $1" % getCurrentExceptionMsg()) + of "modified-after": + try: + options.modifiedAfter = pair[1].parseInt.fromUnix.utc.format("yyyy-MM-dd'T'HH:mm:ss'Z'") + except: + raise newException(EInvalidRequest, "Invalid modified.after value: $1" % getCurrentExceptionMsg()) + of "modified-before": + try: + options.modifiedBefore = pair[1].parseInt.fromUnix.utc.format("yyyy-MM-dd'T'HH:mm:ss'Z'") + except: + raise newException(EInvalidRequest, "Invalid modified-before value: $1" % getCurrentExceptionMsg()) + of "limit": + try: + options.limit = pair[1].parseInt + except: + raise newException(EInvalidRequest, "Invalid limit value: $1" % getCurrentExceptionMsg()) + of "offset": + try: + options.offset = pair[1].parseInt + except: + raise newException(EInvalidRequest, "Invalid offset value: $1" % getCurrentExceptionMsg()) + of "sort": + let orderby = pair[1].orderByClauses() + if orderby != "": + options.orderby = orderby + else: + raise newException(EInvalidRequest, "Invalid sort value: $1" % pair[1]) + of "contents", "raw": + discard + else: + discard + +proc parseQueryOptions*(querystring: string, options: var QueryOptions) = + var fragments = querystring.split('&') + for f in fragments: + f.parseQueryOption(options) + +proc validate*(req: LSRequest, LS: LiteStore, resource: string, id: string, cb: proc(req: LSRequest, LS: LiteStore, resource: string, id: string):LSResponse): LSResponse = + if req.reqMethod == HttpPost or req.reqMethod == HttpPut or req.reqMethod == HttpPatch: + var ct = "" + let body = req.body.strip + if body == "": + return resError(Http400, "Bad request: No content specified for document.") + if req.headers.hasKey("Content-Type"): + ct = req.headers["Content-Type"] + case ct: + of "application/json": + try: + discard body.parseJson() + except: + return resError(Http400, "Invalid JSON content - $1" % getCurrentExceptionMsg()) + else: + discard + return cb(req, LS, resource, id) + +proc patchTag(tags: var seq[string], index: int, op, path, value: string): bool = + LOG.debug("- PATCH -> $1 tag['$2'] = \"$3\" - Total tags: $4." % [op, $index, $value, $tags.len]) + case op: + of "remove": + let tag = tags[index] + if not tag.startsWith("$"): + tags[index] = "" # Not removing element, otherwise subsequent indexes won't work! + else: + raise newException(EInvalidRequest, "cannot remove system tag: $1" % tag) + of "add": + if value.match(PEG_USER_TAG): + tags.insert(value, index) + else: + if value.strip == "": + raise newException(EInvalidRequest, "tag not specified." % value) + else: + raise newException(EInvalidRequest, "invalid tag: $1" % value) + of "replace": + if value.match(PEG_USER_TAG): + if tags[index].startsWith("$"): + raise newException(EInvalidRequest, "cannot replace system tag: $1" % tags[index]) + else: + tags[index] = value + else: + if value.strip == "": + raise newException(EInvalidRequest, "tag not specified." % value) + else: + raise newException(EInvalidRequest, "invalid tag: $1" % value) + of "test": + if tags[index] != value: + return false + else: + raise newException(EInvalidRequest, "invalid patch operation: $1" % op) + return true + +proc patchData*(data: var JsonNode, origData: JsonNode, op: string, path: string, value: JsonNode): bool = + LOG.debug("- PATCH -> $1 path $2 with $3" % [op, path, $value]) + var keys = path.replace(peg"^\/data\/", "").split("/") + if keys.len == 0: + raise newException(EInvalidRequest, "no valid path specified: $1" % path) + var d = data + var dorig = origData + var c = 1 + for key in keys: + if d.kind == JArray: + try: + var index = key.parseInt + if c >= keys.len: + d.elems[index] = value + case op: + of "remove": + d.elems.del(index) + of "add": + d.elems.insert(value, index) + of "replace": + d.elems[index] = value + of "test": + if d.elems[index] != value: + return false + else: + raise newException(EInvalidRequest, "invalid patch operation: $1" % op) + else: + d = d[index] + dorig = dorig[index] + except: + raise newException(EInvalidRequest, "invalid index key '$1' in path '$2'" % [key, path]) + else: + if c >= keys.len: + case op: + of "remove": + if d.hasKey(key): + d.delete(key) + else: + raise newException(EInvalidRequest, "key '$1' not found in path '$2'" % [key, path]) + of "add": + d[key] = value + of "replace": + if d.hasKey(key): + d[key] = value + else: + raise newException(EInvalidRequest, "key '$1' not found in path '$2'" % [key, path]) + of "test": + if dorig.hasKey(key): + if dorig[key] != value: + return false + else: + raise newException(EInvalidRequest, "key '$1' not found in path '$2'" % [key, path]) + else: + raise newException(EInvalidRequest, "invalid patch operation: $1" % op) + else: + d = d[key] + dorig = dorig[key] + c += 1 + return true + + +proc applyPatchOperation*(data: var JsonNode, origData: JsonNode, tags: var seq[string], op: string, path: string, value: JsonNode): bool = + var matches = @[""] + let p = peg""" + path <- ^tagPath / fieldPath$ + tagPath <- '\/tags\/' {\d+} + fieldPath <- '\/data\/' ident ('\/' ident)* + ident <- [a-zA-Z0-9_]+ / '-' + """ + if path.find(p, matches) == -1: + raise newException(EInvalidRequest, "cannot patch path '$1'" % path) + if path.match(peg"^\/tags\/"): + let index = matches[0].parseInt + if value.kind != JString: + raise newException(EInvalidRequest, "tag '$1' is not a string." % $value) + let tag = value.getStr + return patchTag(tags, index, op, path, tag) + elif tags.contains("$subtype:json"): + return patchData(data, origData, op, path, value) + else: + raise newException(EInvalidRequest, "cannot patch data of a non-JSON document.") + +# Low level procs + +proc getTag*(LS: LiteStore, id: string, options = newQueryOptions(), req: LSRequest): LSResponse = + let doc = LS.store.retrieveTag(id, options) + result.headers = ctJsonHeader() + setOrigin(LS, req, result.headers) + if doc == newJNull(): + result = resTagNotFound(id) + else: + result.content = $doc + result.code = Http200 + +proc getStore*(LS: LiteStore, id: string, options = newQueryOptions(), req: LSRequest): LSResponse = + if (not LSDICT.hasKey(id)): + return resStoreNotFound(id) + let store = LSDICT[id] + var doc = newJObject() + doc["id"] = %id + doc["file"] = %store.file + doc["config"] = store.config + result.headers = ctJsonHeader() + setOrigin(LS, req, result.headers) + result.content = $doc + result.code = Http200 + +proc getIndex*(LS: LiteStore, id: string, options = newQueryOptions(), req: LSRequest): LSResponse = + let doc = LS.store.retrieveIndex(id, options) + result.headers = ctJsonHeader() + setOrigin(LS, req, result.headers) + if doc == newJNull(): + result = resIndexNotFound(id) + else: + result.content = $doc + result.code = Http200 + +proc getRawDocument*(LS: LiteStore, id: string, options = newQueryOptions(), req: LSRequest): LSResponse = + let doc = LS.store.retrieveRawDocument(id, options) + result.headers = ctJsonHeader() + setOrigin(LS, req, result.headers) + if doc == "": + result = resDocumentNotFound(id) + else: + result.content = doc + result.code = Http200 + +proc getDocument*(LS: LiteStore, id: string, options = newQueryOptions(), req: LSRequest): LSResponse = + let doc = LS.store.retrieveDocument(id, options) + if doc.data == "": + result = resDocumentNotFound(id) + else: + result.headers = doc.contenttype.ctHeader + setOrigin(LS, req, result.headers) + result.content = doc.data + result.code = Http200 + +proc deleteDocument*(LS: LiteStore, id: string, req: LSRequest): LSResponse = + let doc = LS.store.retrieveDocument(id) + if doc.data == "": + result = resDocumentNotFound(id) + else: + try: + let res = LS.store.destroyDocument(id) + if res == 0: + result = resError(Http500, "Unable to delete document '$1'" % id) + else: + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + result.headers["Content-Length"] = "0" + result.content = "" + result.code = Http204 + except: + result = resError(Http500, "Unable to delete document '$1'" % id) + +proc getTags*(LS: LiteStore, options: QueryOptions = newQueryOptions(), req: LSRequest): LSResponse = + var options = options + let t0 = cpuTime() + let docs = LS.store.retrieveTags(options) + let orig_limit = options.limit + let orig_offset = options.offset + options.limit = 0 + options.offset = 0 + options.select = @["COUNT(tag_id)"] + let total = LS.store.countTags(prepareSelectTagsQuery(options), options.like.replace("*", "%")) + var content = newJObject() + if options.like != "": + content["like"] = %(options.like.decodeURL) + if orig_limit > 0: + content["limit"] = %orig_limit + if orig_offset > 0: + content["offset"] = %orig_offset + content["total"] = %total + content["execution_time"] = %(cputime()-t0) + content["results"] = docs + result.headers = ctJsonHeader() + setOrigin(LS, req, result.headers) + result.content = content.pretty + result.code = Http200 + +proc getStores(LS: LiteStore, options: QueryOptions = newQueryOptions(), req: LSRequest): LSResponse = + let t0 = cpuTime() + var docs = newJArray() + for k, v in LSDICT.pairs: + var store = newJObject() + store["id"] = %k + store["file"] = %v.file + store["config"] = v.config + docs.add(store) + var content = newJObject() + content["total"] = %LSDICT.len + content["execution_time"] = %(cputime()-t0) + content["results"] = docs + result.headers = ctJsonHeader() + setOrigin(LS, req, result.headers) + result.content = content.pretty + result.code = Http200 + +proc getIndexes*(LS: LiteStore, options: QueryOptions = newQueryOptions(), req: LSRequest): LSResponse = + var options = options + let t0 = cpuTime() + let docs = LS.store.retrieveIndexes(options) + let orig_limit = options.limit + let orig_offset = options.offset + options.limit = 0 + options.offset = 0 + options.select = @["COUNT(name)"] + let total = LS.store.countIndexes(prepareSelectIndexesQuery(options), options.like.replace("*", "%")) + var content = newJObject() + if options.like != "": + content["like"] = %(options.like.decodeURL) + if orig_limit > 0: + content["limit"] = %orig_limit + if orig_offset > 0: + content["offset"] = %orig_offset + content["total"] = %total + content["execution_time"] = %(cputime()-t0) + content["results"] = docs + result.headers = ctJsonHeader() + setOrigin(LS, req, result.headers) + result.content = content.pretty + result.code = Http200 + +proc getRawDocuments*(LS: LiteStore, options: QueryOptions = newQueryOptions(), req: LSRequest): LSResponse = + var options = options + let t0 = cpuTime() + let docs = LS.store.retrieveRawDocuments(options) + let orig_limit = options.limit + let orig_offset = options.offset + options.limit = 0 + options.offset = 0 + options.select = @["COUNT(docid)"] + let total = LS.store.retrieveRawDocuments(options)[0].num + var content = newJObject() + if options.folder != "": + content["folder"] = %(options.folder) + if options.search != "": + content["search"] = %(options.search.decodeURL) + if options.tags != "": + content["tags"] = newJArray() + for tag in options.tags.replace("+", "%2B").decodeURL.split(","): + content["tags"].add(%tag) + if orig_limit > 0: + content["limit"] = %orig_limit + if orig_offset > 0: + content["offset"] = %orig_offset + if options.orderby != "": + content["sort"] = %options.orderby + content["total"] = %total + content["execution_time"] = %(cputime()-t0) + content["results"] = docs + result.headers = ctJsonHeader() + setOrigin(LS, req, result.headers) + result.content = content.pretty + result.code = Http200 + +proc getInfo*(LS: LiteStore, req: LSRequest): LSResponse = + let info = LS.store.retrieveInfo() + let version = info[0] + let total_documents = info[1] + let total_tags = LS.store.countTags() + let tags = LS.store.retrieveTagsWithTotals() + var content = newJObject() + content["version"] = %(LS.appname & " v" & LS.appversion) + content["datastore_version"] = %version + content["api_version"] = %7 + content["size"] = %($((LS.file.getFileSize().float/(1024*1024)).formatFloat(ffDecimal, 2)) & " MB") + content["read_only"] = %LS.readonly + content["log_level"] = %LS.loglevel + if LS.directory.len == 0: + content["directory"] = newJNull() + else: + content["directory"] = %LS.directory + content["mount"] = %LS.mount + if LS.config != newJNull() and LS.config.hasKey("stores") and LS.config["stores"].len > 0: + content["additional_stores"] = %toSeq(LS.config["stores"].keys) + else: + content["additional_stores"] = newJArray() + if LS.auth != newJNull(): + content["auth"] = %true + else: + content["auth"] = %false + content["total_documents"] = %total_documents + content["total_tags"] = %total_tags + content["tags"] = tags + result.headers = ctJsonHeader() + setOrigin(LS, req, result.headers) + result.content = content.pretty + result.code = Http200 + +proc putIndex*(LS: LiteStore, id, field: string, req: LSRequest): LSResponse = + try: + if (not id.match(PEG_INDEX)): + return resError(Http400, "invalid index ID: $1" % id) + if (not field.match(PEG_JSON_FIELD)): + return resError(Http400, "invalid field path: $1" % field) + if (LS.store.retrieveIndex(id) != newJNull()): + return resError(Http409, "Index already exists: $1" % id) + LS.store.createIndex(id, field) + result.headers = ctJsonHeader() + setOrigin(LS, req, result.headers) + result.content = "{\"id\": \"$1\", \"field\": \"$2\"}" % [id, field] + result.code = Http201 + except: + eWarn() + result = resError(Http500, "Unable to create index.") + +proc putStore*(LS: LiteStore, id: string, config: JsonNode, req: LSRequest): LSResponse = + try: + if (not id.match(PEG_STORE) or id == "master"): + return resError(Http400, "invalid store ID: $1" % id) + if (LSDICT.hasKey(id)): + return resError(Http409, "Store already exists: $1" % id) + let store = LS.addStore(id, id & ".db", config) + LS.updateConfig() + LSDICT[id] = store + result = getStore(LS, id, newQueryOptions(), req) + result.code = Http201 + except: + eWarn() + result = resError(Http500, "Unable to create store.") + +proc deleteIndex*(LS: LiteStore, id: string, req: LSRequest): LSResponse = + if (not id.match(PEG_INDEX)): + return resError(Http400, "invalid index ID: $1" % id) + if (LS.store.retrieveIndex(id) == newJNull()): + return resError(Http404, "Index not found: $1" % id) + try: + LS.store.dropIndex(id) + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + result.headers["Content-Length"] = "0" + result.content = "" + result.code = Http204 + except: + eWarn() + result = resError(Http500, "Unable to delete index.") + +proc deleteStore*(LS: LiteStore, id: string, req: LSRequest): LSResponse = + if (not id.match(PEG_STORE)): + return resError(Http400, "invalid store ID: $1" % id) + if (not LSDICT.hasKey(id)): + return resError(Http404, "Store not found: $1" % id) + try: + LSDICT.del(id) + if LS.config.hasKey("stores") and LS.config["stores"].hasKey(id): + LS.config["stores"].delete(id) + LS.updateConfig() + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + result.headers["Content-Length"] = "0" + result.content = "" + result.code = Http204 + except: + eWarn() + result = resError(Http500, "Unable to delete index.") + +proc postDocument*(LS: LiteStore, body: string, ct: string, folder="", req: LSRequest): LSResponse = + if not folder.isFolder: + return resError(Http400, "Invalid folder specified when creating document: $1" % folder) + try: + var doc = LS.store.createDocument(folder, body, ct) + if doc != "": + result.headers = ctJsonHeader() + setOrigin(LS, req, result.headers) + result.content = doc + result.code = Http201 + else: + result = resError(Http500, "Unable to create document.") + except: + eWarn() + result = resError(Http500, "Unable to create document.") + +proc putDocument*(LS: LiteStore, id: string, body: string, ct: string, req: LSRequest): LSResponse = + if id.isFolder: + return resError(Http400, "Invalid ID '$1' (Document IDs cannot end with '/')." % id) + let doc = LS.store.retrieveDocument(id) + if doc.data == "": + # Create a new document + var doc = LS.store.createDocument(id, body, ct) + if doc != "": + result.headers = ctJsonHeader() + setOrigin(LS, req, result.headers) + result.content = doc + result.code = Http201 + else: + result = resError(Http500, "Unable to create document.") + else: + # Update existing document + try: + var doc = LS.store.updateDocument(id, body, ct) + if doc != "": + result.headers = ctJsonHeader() + setOrigin(LS, req, result.headers) + result.content = doc + result.code = Http200 + else: + result = resError(Http500, "Unable to update document '$1'." % id) + except: + result = resError(Http500, "Unable to update document '$1'." % id) + +proc patchDocument*(LS: LiteStore, id: string, body: string, req: LSRequest): LSResponse = + var apply = true + let jbody = body.parseJson + if jbody.kind != JArray: + return resError(Http400, "Bad request: PATCH request body is not an array.") + var options = newQueryOptions() + options.select = @["documents.id AS id", "created", "modified", "data"] + let doc = LS.store.retrieveRawDocument(id, options) + if doc == "": + return resDocumentNotFound(id) + let jdoc = doc.parseJson + var tags = newSeq[string]() + var origTags = newSeq[string]() + for tag in jdoc["tags"].items: + tags.add(tag.str) + origTags.add(tag.str) + var data: JsonNode + var origData: JsonNode + if tags.contains("$subtype:json"): + try: + origData = jdoc["data"].getStr.parseJson + data = origData.copy + except: + discard + var c = 1 + for item in jbody.items: + if item.hasKey("op") and item.hasKey("path"): + if not item.hasKey("value"): + item["value"] = %"" + try: + apply = applyPatchOperation(data, origData, tags, item["op"].str, item["path"].str, item["value"]) + if not apply: + break + except: + return resError(Http400, "Bad request - $1" % getCurrentExceptionMsg()) + else: + return resError(Http400, "Bad request: patch operation #$1 is malformed." % $c) + c.inc + if apply: + if origData.len > 0 and origData != data: + try: + var doc = LS.store.updateDocument(id, data.pretty, "application/json") + if doc == "": + return resError(Http500, "Unable to patch document '$1'." % id) + except: + return resError(Http500, "Unable to patch document '$1' - $2" % id, getCurrentExceptionMsg()) + if origTags != tags: + try: + for t1 in jdoc["tags"].items: + discard LS.store.destroyTag(t1.str, id, true) + for t2 in tags: + if t2 != "": + LS.store.createTag(t2, id, true) + except: + return resError(Http500, "Unable to patch document '$1' - $2" % [id, getCurrentExceptionMsg()]) + return LS.getRawDocument(id, newQueryOptions(), req) + +# Main routing + +proc options*(req: LSRequest, LS: LiteStore, resource: string, id = ""): LSResponse = + case resource: + of "info": + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + result.headers["Allow"] = "GET, OPTIONS" + result.headers["Access-Control-Allow-Methods"] = "GET, OPTIONS" + if id != "": + return resError(Http404, "Info '$1' not found." % id) + else: + result.code = Http204 + result.content = "" + of "dir": + result.code = Http204 + result.content = "" + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + result.headers["Allow"] = "GET, OPTIONS" + result.headers["Access-Control-Allow-Methods"] = "GET, OPTIONS" + of "tags": + result.code = Http204 + result.content = "" + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + result.headers["Allow"] = "GET, OPTIONS" + result.headers["Access-Control-Allow-Methods"] = "GET, OPTIONS" + of "indexes": + result.code = Http204 + result.content = "" + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + if id != "": + result.code = Http204 + result.content = "" + if LS.readonly: + result.headers["Allow"] = "GET, OPTIONS" + result.headers["Access-Control-Allow-Methods"] = "GET, OPTIONS" + else: + result.headers["Allow"] = "GET, OPTIONS, PUT, DELETE" + result.headers["Access-Control-Allow-Methods"] = "GET, OPTIONS, PUT, DELETE" + else: + result.code = Http204 + result.content = "" + if LS.readonly: + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + result.headers["Allow"] = "GET, OPTIONS" + result.headers["Access-Control-Allow-Methods"] = "GET, OPTIONS" + else: + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + result.headers["Allow"] = "GET, OPTIONS" + result.headers["Access-Control-Allow-Methods"] = "GET, OPTIONS" + of "docs": + var folder: string + if id.isFolder: + folder = id + if folder.len > 0: + result.code = Http204 + result.content = "" + if LS.readonly: + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + result.headers["Allow"] = "HEAD, GET, OPTIONS" + result.headers["Access-Control-Allow-Methods"] = "HEAD, GET, OPTIONS" + else: + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + result.headers["Allow"] = "HEAD, GET, OPTIONS, POST, PUT" + result.headers["Access-Control-Allow-Methods"] = "HEAD, GET, OPTIONS, POST, PUT" + elif id != "": + result.code = Http204 + result.content = "" + if LS.readonly: + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + result.headers["Allow"] = "HEAD, GET, OPTIONS" + result.headers["Access-Control-Allow-Methods"] = "HEAD, GET, OPTIONS" + else: + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + result.headers["Allow"] = "HEAD, GET, OPTIONS, PUT, PATCH, DELETE" + result.headers["Allow-Patch"] = "application/json-patch+json" + result.headers["Access-Control-Allow-Methods"] = "HEAD, GET, OPTIONS, PUT, PATCH, DELETE" + else: + result.code = Http204 + result.content = "" + if LS.readonly: + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + result.headers["Allow"] = "HEAD, GET, OPTIONS" + result.headers["Access-Control-Allow-Methods"] = "HEAD, GET, OPTIONS" + else: + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + result.headers["Allow"] = "HEAD, GET, OPTIONS, POST" + result.headers["Access-Control-Allow-Methods"] = "HEAD, GET, OPTIONS, POST" + of "stores": + result.code = Http204 + result.content = "" + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + if id != "": + result.code = Http204 + result.content = "" + if LS.readonly: + result.headers["Allow"] = "GET, OPTIONS" + result.headers["Access-Control-Allow-Methods"] = "GET, OPTIONS" + else: + result.headers["Allow"] = "GET, OPTIONS, PUT, DELETE" + result.headers["Access-Control-Allow-Methods"] = "GET, OPTIONS, PUT, DELETE" + else: + result.code = Http204 + result.content = "" + if LS.readonly: + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + result.headers["Allow"] = "GET, OPTIONS" + result.headers["Access-Control-Allow-Methods"] = "GET, OPTIONS" + else: + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + result.headers["Allow"] = "GET, OPTIONS" + result.headers["Access-Control-Allow-Methods"] = "GET, OPTIONS" + else: + discard # never happens really. + +proc head*(req: LSRequest, LS: LiteStore, resource: string, id = ""): LSResponse = + var options = newQueryOptions() + options.select = @["documents.id AS id", "created", "modified"] + if id.isFolder: + options.folder = id + try: + parseQueryOptions(req.url.query, options); + if id != "" and options.folder == "": + result = LS.getRawDocument(id, options, req) + result.content = "" + else: + result = LS.getRawDocuments(options, req) + result.content = "" + except: + return resError(Http400, "Bad request - $1" % getCurrentExceptionMsg()) + +proc get*(req: LSRequest, LS: LiteStore, resource: string, id = ""): LSResponse = + case resource: + of "docs": + var options = newQueryOptions() + if id.isFolder: + options.folder = id + if req.url.query.contains("contents=false"): + options.select = @["documents.id AS id", "created", "modified"] + try: + parseQueryOptions(req.url.query, options); + if id != "" and options.folder == "": + if req.url.query.contains("raw=true") or req.headers.hasKey("Accept") and req.headers["Accept"] == "application/json": + return LS.getRawDocument(id, options, req) + else: + return LS.getDocument(id, options, req) + else: + return LS.getRawDocuments(options, req) + except: + let e = getCurrentException() + let trace = e.getStackTrace() + echo trace + return resError(Http400, "Bad Request - $1" % getCurrentExceptionMsg()) + of "tags": + var options = newQueryOptions() + try: + parseQueryOptions(req.url.query, options); + if id != "": + return LS.getTag(id, options, req) + else: + return LS.getTags(options, req) + except: + return resError(Http400, "Bad Request - $1" % getCurrentExceptionMsg()) + of "indexes": + var options = newQueryOptions() + try: + parseQueryOptions(req.url.query, options); + if id != "": + return LS.getIndex(id, options, req) + else: + return LS.getIndexes(options, req) + except: + return resError(Http400, "Bad Request - $1" % getCurrentExceptionMsg()) + of "stores": + var options = newQueryOptions() + try: + parseQueryOptions(req.url.query, options); + if id != "": + return LS.getStore(id, options, req) + else: + return LS.getStores(options, req) + except: + return resError(Http400, "Bad Request - $1" % getCurrentExceptionMsg()) + of "info": + if id != "": + return resError(Http404, "Info '$1' not found." % id) + return LS.getInfo(req) + else: + discard # never happens really. + +proc post*(req: LSRequest, LS: LiteStore, resource: string, id = ""): LSResponse = + var ct = "text/plain" + if req.headers.hasKey("Content-Type"): + ct = req.headers["Content-Type"] + return LS.postDocument(req.body.strip, ct, id, req) + +proc put*(req: LSRequest, LS: LiteStore, resource: string, id = ""): LSResponse = + if id != "": + if resource == "indexes": + var field = "" + try: + field = parseJson(req.body.strip)["field"].getStr + except: + return resError(Http400, "Bad Request - Invalid JSON body - $1" % getCurrentExceptionMsg()) + return LS.putIndex(id, field, req) + elif resource == "stores": + var config = newJNull() + try: + config = parseJson(req.body) + except: + return resError(Http400, "Bad Request - Invalid JSON body - $1" % getCurrentExceptionMsg()) + return LS.putStore(id, config, req) + else: # Assume docs + var ct = "text/plain" + if req.headers.hasKey("Content-Type"): + ct = req.headers["Content-Type"] + return LS.putDocument(id, req.body.strip, ct, req) + else: + return resError(Http400, "Bad request: document ID must be specified in PUT requests.") + +proc delete*(req: LSRequest, LS: LiteStore, resource: string, id = ""): LSResponse = + if id != "": + if resource == "indexes": + return LS.deleteIndex(id, req) + elif resource == "stores": + return LS.deleteStore(id, req) + else: # Assume docs + return LS.deleteDocument(id, req) + else: + return resError(Http400, "Bad request: document ID must be specified in DELETE requests.") + +proc patch*(req: LSRequest, LS: LiteStore, resource: string, id = ""): LSResponse = + if id != "": + return LS.patchDocument(id, req.body, req) + else: + return resError(Http400, "Bad request: document ID must be specified in PATCH requests.") + +proc serveFile*(req: LSRequest, LS: LiteStore, id: string): LSResponse = + let path = LS.directory / id + var reqMethod = $req.reqMethod + if req.headers.hasKey("X-HTTP-Method-Override"): + reqMethod = req.headers["X-HTTP-Method-Override"] + case reqMethod.toUpperAscii: + of "OPTIONS": + return validate(req, LS, "dir", id, options) + of "GET": + if path.fileExists: + try: + let contents = path.readFile + let parts = path.splitFile + if CONTENT_TYPES.hasKey(parts.ext): + result.headers = CONTENT_TYPES[parts.ext].ctHeader + else: + result.headers = ctHeader("text/plain") + setOrigin(LS, req, result.headers) + result.content = contents + result.code = Http200 + except: + return resError(Http500, "Unable to read file '$1'." % path) + else: + return resError(Http404, "File '$1' not found." % path) + else: + return resError(Http405, "Method not allowed: $1" % $req.reqMethod) + +proc route*(req: LSRequest, LS: LiteStore, resource = "docs", id = ""): LSResponse = + var reqMethod = $req.reqMethod + if req.headers.hasKey("X-HTTP-Method-Override"): + reqMethod = req.headers["X-HTTP-Method-Override"] + case reqMethod.toUpperAscii: + of "POST": + if LS.readonly: + return resError(Http405, "Method not allowed: $1" % $req.reqMethod) + return validate(req, LS, resource, id, post) + of "PUT": + if LS.readonly: + return resError(Http405, "Method not allowed: $1" % $req.reqMethod) + return validate(req, LS, resource, id, put) + of "DELETE": + if LS.readonly: + return resError(Http405, "Method not allowed: $1" % $req.reqMethod) + return validate(req, LS, resource, id, delete) + of "HEAD": + return validate(req, LS, resource, id, head) + of "OPTIONS": + return validate(req, LS, resource, id, options) + of "GET": + return validate(req, LS, resource, id, get) + of "PATCH": + if LS.readonly: + return resError(Http405, "Method not allowed: $1" % $req.reqMethod) + return validate(req, LS, resource, id, patch) + else: + return resError(Http405, "Method not allowed: $1" % $req.reqMethod) + +proc multiRoute(req: LSRequest, resource, id: string): LSResponse = + var matches = @["", "", ""] + if req.url.path.find(PEG_STORE_URL, matches) != -1: + let id = matches[0] + let path = matches[1] + matches = @["", "", ""] + discard path.find(PEG_URL) + return req.route(LSDICT[id], matches[1], matches[2]) + return req.route(LS, resource, id) + +proc newSimpleLSRequest(meth: HttpMethod, resource, id, body = "", params = "", headers = newHttpHeaders()): LSRequest = + result.reqMethod = meth + result.body = body + result.headers = headers + result.url = parseUri("$1://$2:$3/$4/$5?$6" % @["http", "localhost", "9500", resource, id, params]) + +proc get(resource, id: string, params = ""): LSResponse = + return newSimpleLSRequest(HttpGet, resource, id, "", params).multiRoute(resource, id) + +proc post(resource, folder, body: string, ct = ""): LSResponse = + var headers = newHttpHeaders() + if ct != "": + headers["Content-Type"] = ct + return newSimpleLSRequest(HttpPost, resource, folder, body, "", headers).multiRoute(resource, folder & "/") + +proc put(resource, id, body: string, ct = ""): LSResponse = + var headers = newHttpHeaders() + if ct != "": + headers["Content-Type"] = ct + return newSimpleLSRequest(HttpPut, resource, id, body, "", headers).multiRoute(resource, id) + +proc patch(resource, id, body: string): LSResponse = + var headers = newHttpHeaders() + headers["Content-Type"] = "application/json" + return newSimpleLSRequest(HttpPatch, resource, id, body, "", headers).multiRoute(resource, id) + +proc delete(resource, id: string): LSResponse = + return newSimpleLSRequest(HttpPatch, resource, id).multiRoute(resource, id) + +proc head(resource, id: string): LSResponse = + return newSimpleLSRequest(HttpHead, resource, id).multiRoute(resource, id) + +proc registerStoreApi(LS: LiteStore, ctx: DTContext, origResource, origId: string) = + var api_idx = ctx.duk_push_object() + # GET + var get: DTCFunction = (proc (ctx: DTContext): cint{.stdcall.} = + let resource = duk_get_string(ctx, 0) + let id = duk_get_string(ctx, 1) + let params = duk_get_string(ctx, 2) + let resp = get($resource, $id, $params) + var res_idx = ctx.duk_push_object() + ctx.duk_push_int(cast[cint](resp.code)) + discard ctx.duk_put_prop_string(res_idx, "code") + discard ctx.duk_push_string(resp.content) + discard ctx.duk_put_prop_string(res_idx, "content") + return 1 + ) + discard duk_push_c_function(ctx, get, 3) + discard ctx.duk_put_prop_string(api_idx, "get") + # POST + var post: DTCFunction = (proc (ctx: DTContext): cint{.stdcall.} = + let resource = duk_get_string(ctx, 0) + let folder = duk_get_string(ctx, 1) + let body = duk_get_string(ctx, 2) + let ct = duk_get_string(ctx, 3) + let resp = post($resource, $folder, $body, $ct) + var res_idx = ctx.duk_push_object() + ctx.duk_push_int(cast[cint](resp.code)) + discard ctx.duk_put_prop_string(res_idx, "code") + discard ctx.duk_push_string(resp.content) + discard ctx.duk_put_prop_string(res_idx, "content") + return 1 + ) + discard duk_push_c_function(ctx, post, 4) + discard ctx.duk_put_prop_string(api_idx, "post") + # PUT + var put: DTCFunction = (proc (ctx: DTContext): cint{.stdcall.} = + let resource = duk_get_string(ctx, 0) + let id = duk_get_string(ctx, 1) + let body = duk_get_string(ctx, 2) + let ct = duk_get_string(ctx, 3) + let resp = put($resource, $id, $body, $ct) + var res_idx = ctx.duk_push_object() + ctx.duk_push_int(cast[cint](resp.code)) + discard ctx.duk_put_prop_string(res_idx, "code") + discard ctx.duk_push_string(resp.content) + discard ctx.duk_put_prop_string(res_idx, "content") + return 1 + ) + discard duk_push_c_function(ctx, put, 4) + discard ctx.duk_put_prop_string(api_idx, "put") + # PATCH + var patch: DTCFunction = (proc (ctx: DTContext): cint{.stdcall.} = + let resource = duk_get_string(ctx, 0) + let id = duk_get_string(ctx, 1) + let body = duk_get_string(ctx, 2) + let resp = patch($resource, $id, $body) + var res_idx = ctx.duk_push_object() + ctx.duk_push_int(cast[cint](resp.code)) + discard ctx.duk_put_prop_string(res_idx, "code") + discard ctx.duk_push_string(resp.content) + discard ctx.duk_put_prop_string(res_idx, "content") + return 1 + ) + discard duk_push_c_function(ctx, patch, 3) + discard ctx.duk_put_prop_string(api_idx, "patch") + # DELETE + var delete: DTCFunction = (proc (ctx: DTContext): cint{.stdcall.} = + let resource = duk_get_string(ctx, 0) + let id = duk_get_string(ctx, 1) + let resp = delete($resource, $id) + var res_idx = ctx.duk_push_object() + ctx.duk_push_int(cast[cint](resp.code)) + discard ctx.duk_put_prop_string(res_idx, "code") + discard ctx.duk_push_string(resp.content) + discard ctx.duk_put_prop_string(res_idx, "content") + return 1 + ) + discard duk_push_c_function(ctx, delete, 2) + discard ctx.duk_put_prop_string(api_idx, "delete") + # HEAD + var head: DTCFunction = (proc (ctx: DTContext): cint{.stdcall.} = + let resource = duk_get_string(ctx, 0) + let id = duk_get_string(ctx, 1) + let resp = head($resource, $id) + var res_idx = ctx.duk_push_object() + ctx.duk_push_int(cast[cint](resp.code)) + discard ctx.duk_put_prop_string(res_idx, "code") + discard ctx.duk_push_string(resp.content) + discard ctx.duk_put_prop_string(res_idx, "content") + return 1 + ) + discard duk_push_c_function(ctx, head, 2) + discard ctx.duk_put_prop_string(api_idx, "head") + discard ctx.duk_put_global_string("$store") + +proc jError(ctx: DTContext): LSResponse = + return resError(Http500, "Middleware Error: " & $ctx.duk_safe_to_string(-1)) + +proc getMiddleware*(LS: LiteStore, id: string): string = + if not LS.middleware.hasKey(id): + # Attempt to retrieve resource from system documents + let options = newQueryOptions(true) + let doc = LS.store.retrieveDocument("middleware/" & id & ".js", options) + result = doc.data + if result == "": + LOG.warn("Middleware '$1' not found" % id) + else: + result = LS.middleware[id] + +proc getMiddlewareSeq(LS: LiteStore, resource, id, meth: string): seq[string] = + result = newSeq[string]() + if LS.config.kind != JObject or not LS.config.hasKey("resources"): + return + var reqUri = "/" & resource & "/" & id + if reqUri[^1] == '/': + reqUri.removeSuffix({'/'}) + let parts = reqUri.split("/") + let ancestors = parts[1..parts.len-2] + var currentPath = "" + var currentPaths = "" + for p in ancestors: + currentPath &= "/" & p + currentPaths = currentPath & "/*" + if LS.config["resources"].hasKey(currentPaths) and LS.config["resources"][currentPaths].hasKey(meth) and LS.config["resources"][currentPaths][meth].hasKey("middleware"): + let mw = LS.config["resources"][currentPaths][meth]["middleware"] + if (mw.kind == JArray): + for m in mw: + result.add m.getStr + if LS.config["resources"].hasKey(reqUri) and LS.config["resources"][reqUri].hasKey(meth) and LS.config["resources"][reqUri][meth].hasKey("middleware"): + let mw = LS.config["resources"][reqUri][meth]["middleware"] + if (mw.kind == JArray): + for m in mw: + result.add m.getStr + +proc execute*(req: var LSRequest, LS: LiteStore, resource, id: string): LSResponse = + echo LS.file + let middleware = getMiddlewareSeq(LS, resource, id, $req.reqMethod) + LOG.debug("Middleware: " & middleware.join(" -> ")); + if middleware.len == 0: + return route(req, LS, resource, id) + var jReq = $(%* req) + LOG.debug("Request: " & jReq) + var jRes = """{ + "code": 200, + "content": {}, + "final": false, + "headers": { + "Access-Control-Allow-Origin": "*", + "Access-Control-Allow-Headers": "Authorization, Content-Type", + "Server": "$1", + "Content-Type": "application/json" + } + }""" % [LS.appname & "/" & LS.appversion] + var context = "{}" + # Create execution context + var ctx = duk_create_heap_default() + duk_console_init(ctx) + duk_print_alert_init(ctx) + LS.registerStoreApi(ctx, resource, id) + if ctx.duk_peval_string("($1)" % $jReq) != 0: + return jError(ctx) + discard ctx.duk_put_global_string("$req") + if ctx.duk_peval_string("($1)" % $jRes) != 0: + return jError(ctx) + discard ctx.duk_put_global_string("$res") + if ctx.duk_peval_string("($1)" % $context) != 0: + return jError(ctx) + discard ctx.duk_put_global_string("$ctx") + # Middleware-specific functions + var i = 0 + var abort = 0 + while abort != 1 and i < middleware.len: + let code = LS.getMiddleware(middleware[i]) + LOG.debug("Evaluating middleware '$1'" % middleware[i]) + if ctx.duk_peval_string(code) != 0: + return jError(ctx) + abort = ctx.duk_get_boolean(-1) + i.inc + # Retrieve response, and request + if ctx.duk_peval_string("JSON.stringify($res);") != 0: + return jError(ctx) + let fRes = parseJson($(ctx.duk_get_string(-1))).newLSResponse + if ctx.duk_peval_string("JSON.stringify($req);") != 0: + return jError(ctx) + let fReq = parseJson($(ctx.duk_get_string(-1))).newLSRequest() + ctx.duk_destroy_heap(); + LOG.debug("abort: $1", [$abort]) + if abort == 1: + return fRes + return route(fReq, LS, resource, id)
@@ -1,9 +1,11 @@
import parseopt, strutils, - json + json, + os, + strtabs import - logger, + core, config, types, utils@@ -15,8 +17,10 @@ operation = opRun
directory:string = "" readonly = false logLevel = "warn" + system = false mount = false auth = newJNull() + middleware = newStringTable() configuration = newJNull() authFile = "" configFile = ""@@ -57,173 +61,135 @@ -o, --operation Specify an operation to execute via the execute command: get, put, delete, patch, post, head, options.
-p, --port Specify server port number (default: 9500). -r, --readonly Allow only data retrieval operations. -s, --store Specify a datastore file (default: data.db) + --system Set the system flag for import, export, and delete operations -t, --type Specify a content type for the body an operation to be executed via the execute command. -u, --uri Specify an uri to execute an operation through the execute command. -v, --version Display the program version. + -w, --middleware Specify a path to a folder containing middleware definitions. """ -for kind, key, val in getOpt(): - case kind: - of cmdArgument: - case key: - of "run": - operation = opRun - of "import": - operation = opImport - of "execute": - operation = opExecute - of "export": - operation = opExport - of "delete": - operation = opDelete - of "optimize": - operation = opOptimize - of "vacuum": - operation = opVacuum - else: - discard - of cmdLongOption, cmdShortOption: - case key: - of "address", "a": - if val == "": - fail(100, "Address not specified.") - address = val - cliSettings["address"] = %address - of "port", "p": - if val == "": - fail(101, "Port not specified.") - port = val.parseInt - cliSettings["port"] = %port - of "store", "s": - file = val - cliSettings["store"] = %file - of "log", "l": - if val == "": - fail(102, "Log level not specified.") - case val: - of "info": - LOG.level = lvInfo - of "warn": - LOG.level = lvWarn - of "debug": - LOG.level = lvDebug - of "error": - LOG.level = lvError - of "none": - LOG.level = lvNone - else: - fail(103, "Invalid log level '$1'" % val) - loglevel = val - cliSettings["log"] = %logLevel - of "directory", "d": - if val == "": - fail(104, "Directory not specified.") - directory = val - cliSettings["directory"] = %directory - of "operation", "o": - if val == "": - fail(106, "Operation not specified.") - exOperation = val - of "file", "f": - if val == "": - fail(107, "File not specified.") - exFile = val - of "uri", "u": - if val == "": - fail(108, "URI not specified.") - exUri = val - of "body", "b": - if val == "": - fail(112, "Body not specified.") - exBody = val - of "type", "t": - if val == "": - fail(113, "Content type not specified.") - exType = val - of "auth": - if val == "": - fail(114, "Authentication/Authorization configuration file not specified.") - authFile = val - of "config", "c": - if val == "": - fail(115, "Configuration file not specified.") - configuration = val.parseFile - configFile = val - of "mount", "m": - mount = true - cliSettings["mounnt"] = %mount - of "version", "v": - echo pkgVersion - quit(0) - of "help", "h": - echo usage - quit(0) - of "readonly", "r": - readonly = true - cliSettings["readonly"] = %readonly - else: - discard - else: - discard - -# Process auth configuration if present - -if auth == newJNull() and configuration != newJNull() and configuration.hasKey("signature"): - auth = newJObject(); - auth["access"] = newJObject(); - auth["signature"] = configuration["signature"] - for k, v in configuration["resources"].pairs: - if v.hasKey("auth"): - auth["access"][k] = v["auth"] - -# Process config settings if present and if no cli settings are set - -if configuration != newJNull() and configuration.hasKey("settings"): - let settings = configuration["settings"] - if not cliSettings.hasKey("address") and settings.hasKey("address"): - address = settings["address"].getStr - if not cliSettings.hasKey("port") and settings.hasKey("port"): - port = settings["port"].getInt - if not cliSettings.hasKey("store") and settings.hasKey("store"): - file = settings["store"].getStr - if not cliSettings.hasKey("directory") and settings.hasKey("directory"): - directory = settings["directory"].getStr - if not cliSettings.hasKey("mount") and settings.hasKey("mount"): - mount = settings["mount"].getBool - if not cliSettings.hasKey("readonly") and settings.hasKey("readonly"): - readonly = settings["readonly"].getBool - -# Validation - -if directory == "" and (operation in [opDelete, opImport, opExport] or mount): - fail(105, "--directory option not specified.") - -if exFile == "" and (exOperation in ["put", "post", "patch"]): - fail(109, "--file option not specified") - -if exUri == "" and operation == opExecute: - fail(110, "--uri option not specified") - -if exOperation == "" and operation == opExecute: - fail(111, "--operation option not specified") - - +proc run*() = + for kind, key, val in getOpt(): + case kind: + of cmdArgument: + case key: + of "run": + operation = opRun + of "import": + operation = opImport + of "execute": + operation = opExecute + of "export": + operation = opExport + of "delete": + operation = opDelete + of "optimize": + operation = opOptimize + of "vacuum": + operation = opVacuum + else: + discard + of cmdLongOption, cmdShortOption: + case key: + of "address", "a": + if val == "": + fail(100, "Address not specified.") + address = val + cliSettings["address"] = %address + of "port", "p": + if val == "": + fail(101, "Port not specified.") + port = val.parseInt + cliSettings["port"] = %port + of "store", "s": + file = val + cliSettings["store"] = %file + of "system": + system = true + of "log", "l": + if val == "": + fail(102, "Log level not specified.") + setLogLevel(val) + logLevel = val + cliSettings["log"] = %logLevel + of "directory", "d": + if val == "": + fail(104, "Directory not specified.") + directory = val + cliSettings["directory"] = %directory + of "middleware", "w": + if val == "": + fail(115, "Middleware path not specified.") + if not val.existsDir(): + fail(116, "Middleware directory does not exist.") + for file in val.walkDir(): + if file.kind == pcFile or file.kind == pcLinkToFile: + middleware[file.path.splitFile[1]] = file.path.readFile() + cliSettings["middleware"] = %val + of "operation", "o": + if val == "": + fail(106, "Operation not specified.") + exOperation = val + of "file", "f": + if val == "": + fail(107, "File not specified.") + exFile = val + of "uri", "u": + if val == "": + fail(108, "URI not specified.") + exUri = val + of "body", "b": + if val == "": + fail(112, "Body not specified.") + exBody = val + of "type", "t": + if val == "": + fail(113, "Content type not specified.") + exType = val + of "auth": + if val == "": + fail(114, "Authentication/Authorization configuration file not specified.") + authFile = val + of "config", "c": + if val == "": + fail(115, "Configuration file not specified.") + configuration = val.parseFile + configFile = val + of "mount", "m": + mount = true + cliSettings["mount"] = %mount + of "version", "v": + echo pkgVersion + quit(0) + of "help", "h": + echo usage + quit(0) + of "readonly", "r": + readonly = true + cliSettings["readonly"] = %readonly + else: + discard + else: + discard -LS.operation = operation -LS.address = address -LS.port = port -LS.file = file -LS.directory = directory -LS.readonly = readonly -LS.favicon = favicon -LS.loglevel = loglevel -LS.auth = auth -LS.authFile = authFile -LS.config = configuration -LS.configFile = configFile -LS.mount = mount -LS.execution.file = exFile -LS.execution.body = exBody -LS.execution.ctype = exType -LS.execution.uri = exUri -LS.execution.operation = exOperation + LS.operation = operation + LS.address = address + LS.port = port + LS.file = file + LS.directory = directory + LS.readonly = readonly + LS.favicon = favicon + LS.logLevel = logLevel + LS.cliSettings = cliSettings + LS.auth = auth + LS.manageSystemData = system + LS.middleware = middleware + LS.authFile = authFile + LS.config = configuration + LS.configFile = configFile + LS.mount = mount + LS.execution.file = exFile + LS.execution.body = exBody + LS.execution.ctype = exType + LS.execution.uri = exUri + LS.execution.operation = exOperation
@@ -1,6 +1,6 @@
const pkgName* = "litestore" - pkgVersion* = "1.7.0" + pkgVersion* = "1.9.0" pkgAuthor* = "Fabio Cevasco" pkgDescription* = "Self-contained, lightweight, RESTful document store." pkgLicense* = "MIT"
@@ -41,9 +41,10 @@ let data = db.open(file, "", "", "")
LOG.debug("Creating tables") data.exec(SQL_CREATE_DOCUMENTS_TABLE) data.exec(SQL_CREATE_SEARCHDATA_TABLE) + data.exec(SQL_CREATE_SYSTEM_DOCUMENTS_TABLE) data.exec(SQL_CREATE_TAGS_TABLE) data.exec(SQL_CREATE_INFO_TABLE) - data.exec(SQL_INSERT_INFO, 1, 0, 0) + data.exec(SQL_INSERT_INFO, 2, 0) LOG.debug("Creating indexes") data.createIndexes() LOG.debug("Database created")@@ -64,7 +65,30 @@ except:
raise newException(EDatastoreUnavailable, "Datastore '$1' cannot destroyed." % store.path) -proc openDatastore*(file: string): Datastore = +proc retrieveInfo*(store: Datastore): array[0..1, int] = + var data = store.db.getRow(SQL_SELECT_INFO) + return [data[0].parseInt, data[1].parseInt] + +proc upgradeDatastore*(store: Datastore) = + let info = store.retrieveInfo() + if info[0] == 1: + LOG.debug("Upgrading datastore to version 2...") + let bkp_path = store.path & "__v1_backup" + copyFile(store.path, bkp_path) + try: + store.db.exec(SQL_CREATE_SYSTEM_DOCUMENTS_TABLE) + store.db.exec(SQL_UPDATE_VERSION, 2) + LOG.debug("Done.") + except: + store.closeDatastore() + store.path.removeFile() + copyFile(bkp_path, store.path) + let e = getCurrentException() + LOG.error(getCurrentExceptionMsg()) + LOG.debug(e.getStackTrace()) + LOG.error("Unable to upgrade datastore '$1'." % store.path) + +proc openDatastore*(file: string): Datastore {.gcsafe.} = if not file.fileExists: raise newException(EDatastoreDoesNotExist, "Datastore '$1' does not exists." % file)@@ -75,7 +99,7 @@ LOG.debug("Registering custom functions...")
discard create_function(cast[PSqlite3](result.db), "rank", -1, SQLITE_ANY, cast[pointer](SQLITE_DETERMINISTIC), okapi_bm25f_kb, nil, nil) LOG.debug("Executing PRAGMAs...") - discard result.db.tryExec("PRAGMA locking_mode = exclusive".sql) + discard result.db.tryExec("PRAGMA journal_mode = WAL".sql) discard result.db.tryExec("PRAGMA page_size = 4096".sql) discard result.db.tryExec("PRAGMA cache_size = 10000".sql) discard result.db.tryExec("PRAGMA foreign_keys = ON".sql)@@ -85,10 +109,6 @@ result.mount = ""
except: raise newException(EDatastoreUnavailable, "Datastore '$1' cannot be opened." % file) - -proc retrieveInfo*(store: Datastore): array[0..1, int] = - var data = store.db.getRow(SQL_SELECT_INFO) - return [data[0].parseInt, data[1].parseInt] proc hasMirror(store: Datastore): bool = return store.mount.len > 0@@ -143,7 +163,6 @@ proc retrieveIndexes*(store: Datastore, options: QueryOptions = newQueryOptions()): JsonNode =
var query = prepareSelectIndexesQuery(options) var raw_indexes: seq[Row] if (options.like.len > 0): - echo options.like if (options.like[options.like.len-1] == '*' and options.like[0] != '*'): let str = "json_index_" & options.like.substr(0, options.like.len-2) raw_indexes = store.db.getAllRows(query.sql, str, str & "{")@@ -303,6 +322,67 @@ store.rollback()
eWarn() raise +proc createSystemDocument*(store: Datastore, id = "", rawdata = "", + contenttype = "text/plain", binary = -1): string = + let singleOp = not LS_TRANSACTION + var id = id + var contenttype = contenttype.replace(peg"""\;(.+)$""", "") # Strip charset for now + var binary = checkIfBinary(binary, contenttype) + var data = rawdata + if contenttype == "application/json": + # Validate JSON data + try: + discard data.parseJson + except: + raise newException(JsonParsingError, "Invalid JSON content - " & + getCurrentExceptionMsg()) + if id == "": + id = $genOid() + elif id.isFolder: + id = id & $genOid() + # Store document + try: + LOG.debug("Creating system document '$1'" % id) + store.begin() + discard store.db.insertID(SQL_INSERT_SYSTEM_DOCUMENT, id, data, contenttype, + binary, currentTime()) + if singleOp: + store.commit() + return $store.retrieveRawDocument(id) + except: + store.rollback() + eWarn() + raise + +proc updateSystemDocument*(store: Datastore, id: string, rawdata: string, + contenttype = "text/plain", binary = -1): string = + let singleOp = not LS_TRANSACTION + var contenttype = contenttype.replace(peg"""\;(.+)$""", "") # Strip charset for now + var binary = checkIfBinary(binary, contenttype) + var data = rawdata + if contenttype == "application/json": + # Validate JSON data + try: + discard data.parseJson + except: + raise newException(JsonParsingError, "Invalid JSON content - " & + getCurrentExceptionMsg()) + try: + LOG.debug("Updating system document '$1'" % id) + store.begin() + var res = store.db.execAffectedRows(SQL_UPDATE_SYSTEM_DOCUMENT, data, contenttype, + binary, currentTime(), id) + if res > 0: + result = $store.retrieveRawDocument(id) + else: + result = "" + if singleOp: + store.commit() + except: + eWarn() + store.rollback() + raise + proc updateDocument*(store: Datastore, id: string, rawdata: string, contenttype = "text/plain", binary = -1, searchable = 1): string = let singleOp = not LS_TRANSACTION@@ -404,11 +484,16 @@
proc countDocuments*(store: Datastore): int64 = return store.db.getRow(SQL_COUNT_DOCUMENTS)[0].parseInt -proc importFile*(store: Datastore, f: string, dir = "") = +proc importFile*(store: Datastore, f: string, dir = "/", system = false) = if not f.fileExists: raise newException(EFileNotFound, "File '$1' not found." % f) let ext = f.splitFile.ext - var d_id = f.replace("\\", "/") + var d_id: string + if system: + # Do not save original directory name + d_id = f.replace("\\", "/")[dir.len+1..f.len-1]; + else: + d_id = f.replace("\\", "/"); var d_contents = f.readFile var d_ct = "application/octet-stream" if CONTENT_TYPES.hasKey(ext):@@ -422,8 +507,11 @@ d_contents = d_contents.encode(d_contents.len*2) # Encode in Base64.
let singleOp = not LS_TRANSACTION store.begin() try: - discard store.createDocument(d_id, d_contents, d_ct, d_binary, d_searchable) - if dir != "": + if system: + discard store.createSystemDocument(d_id, d_contents, d_ct, d_binary) + else: + discard store.createDocument(d_id, d_contents, d_ct, d_binary, d_searchable) + if dir != "/" and not system: store.db.exec(SQL_INSERT_TAG, "$dir:"&dir, d_id) except: store.rollback()@@ -456,7 +544,7 @@ eWarn()
quit(203) quit(0) -proc importDir*(store: Datastore, dir: string) = +proc importDir*(store: Datastore, dir: string, system = false) = var files = newSeq[string]() if not dir.dirExists: raise newException(EDirectoryNotFound, "Directory '$1' not found." % dir)@@ -478,7 +566,7 @@ LOG.debug("Dropping column indexes...")
store.db.dropIndexes() for f in files: try: - store.importFile(f, dir) + store.importFile(f, dir, system) cFiles.inc if (cFiles-1) mod batchSize == 0: cBatches.inc@@ -494,8 +582,12 @@ store.db.createIndexes()
store.commit() LOG.info("Imported $1/$2 files", cFiles, files.len) -proc exportDir*(store: Datastore, dir: string) = - let docs = store.db.getAllRows(SQL_SELECT_DOCUMENTS_BY_TAG, "$dir:"&dir) +proc exportDir*(store: Datastore, dir: string, system = false) = + var docs: seq[Row] + if system: + docs = store.db.getAllRows(SQL_SELECT_SYSTEM_DOCUMENTS) + else: + docs = store.db.getAllRows(SQL_SELECT_DOCUMENTS_BY_TAG, "$dir:"&dir) LOG.info("Exporting $1 files...", docs.len) for doc in docs: LOG.debug("Exporting: $1", doc[1])@@ -509,12 +601,15 @@ file.parentDir.createDir
file.writeFile(data) LOG.info("Done."); -proc deleteDir*(store: Datastore, dir: string) = - store.db.exec(SQL_DELETE_SEARCHDATA_BY_TAG, "$dir:"&dir) - store.db.exec(SQL_DELETE_DOCUMENTS_BY_TAG, "$dir:"&dir) - store.db.exec(SQL_DELETE_TAGS_BY_TAG, "$dir:"&dir) - let total = store.db.getRow(SQL_COUNT_DOCUMENTS)[0].parseInt - store.db.exec(SQL_SET_TOTAL_DOCS, total) +proc deleteDir*(store: Datastore, dir: string, system = false) = + if system: + store.db.exec(SQL_DELETE_SYSTEM_DOCUMENTS) + else: + store.db.exec(SQL_DELETE_SEARCHDATA_BY_TAG, "$dir:"&dir) + store.db.exec(SQL_DELETE_DOCUMENTS_BY_TAG, "$dir:"&dir) + store.db.exec(SQL_DELETE_TAGS_BY_TAG, "$dir:"&dir) + let total = store.db.getRow(SQL_COUNT_DOCUMENTS)[0].parseInt + store.db.exec(SQL_SET_TOTAL_DOCS, total) proc mountDir*(store: var Datastore, dir: string) = if not dir.dirExists:@@ -526,3 +621,143 @@ result = 0
var ids = store.db.getAllRows(SQL_SELECT_DOCUMENT_IDS_BY_TAG, tag) for id in ids: result.inc(store.destroyDocument(id[0]).int) + +proc setLogLevel*(val: string) = + case val: + of "info": + LOG.level = lvInfo + of "warn": + LOG.level = lvWarn + of "debug": + LOG.level = lvDebug + of "error": + LOG.level = lvError + of "none": + LOG.level = lvNone + else: + fail(103, "Invalid log level '$1'" % val) + +proc processAuthConfig(configuration: JsonNode, auth: var JsonNode) = + if auth == newJNull() and configuration != newJNull() and configuration.hasKey("signature"): + auth = newJObject(); + auth["access"] = newJObject(); + auth["signature"] = configuration["signature"] + for k, v in configuration["resources"].pairs: + auth["access"][k] = newJObject() + for meth, content in v.pairs: + if content.hasKey("auth"): + auth["access"][k][meth] = content["auth"] + +proc processConfigSettings(LS: var LiteStore) = + # Process config settings if present and if no cli settings are set + if LS.config != newJNull() and LS.config.hasKey("settings"): + let settings = LS.config["settings"] + let cliSettings = LS.cliSettings + if not cliSettings.hasKey("address") and settings.hasKey("address"): + LS.address = settings["address"].getStr + if not cliSettings.hasKey("port") and settings.hasKey("port"): + LS.port = settings["port"].getInt + if not cliSettings.hasKey("store") and settings.hasKey("store"): + LS.file = settings["store"].getStr + if not cliSettings.hasKey("directory") and settings.hasKey("directory"): + LS.directory = settings["directory"].getStr + if not cliSettings.hasKey("middleware") and settings.hasKey("middleware"): + let val = settings["middleware"].getStr + for file in val.walkDir(): + if file.kind == pcFile or file.kind == pcLinkToFile: + LS.middleware[file.path.splitFile[1]] = file.path.readFile() + if not cliSettings.hasKey("log") and settings.hasKey("log"): + LS.logLevel = settings["log"].getStr + setLogLevel(LS.logLevel) + if not cliSettings.hasKey("mount") and settings.hasKey("mount"): + LS.mount = settings["mount"].getBool + if not cliSettings.hasKey("readonly") and settings.hasKey("readonly"): + LS.readonly = settings["readonly"].getBool + +proc setup*(LS: var LiteStore, open = true) {.gcsafe.} = + if not LS.file.fileExists: + try: + LS.file.createDatastore() + except: + eWarn() + fail(200, "Unable to create datastore '$1'" % [LS.file]) + if (open): + try: + LS.store = LS.file.openDatastore() + try: + LS.store.upgradeDatastore() + except: + fail(203, "Unable to upgrade datastore '$1'" % [LS.file]) + if LS.mount: + try: + LS.store.mountDir(LS.directory) + except: + eWarn() + fail(202, "Unable to mount directory '$1'" % [LS.directory]) + except: + fail(201, "Unable to open datastore '$1'" % [LS.file]) + +proc initStore*(LS: var LiteStore) = + if LS.configFile == "": + # Attempt to retrieve config.json from system documents + let options = newQueryOptions(true) + let rawDoc = LS.store.retrieveRawDocument("config.json", options) + if rawDoc != "": + LS.config = rawDoc.parseJson()["data"] + + if LS.config != newJNull(): + # Process config settings + LS.processConfigSettings() + # Process auth from config settings + processAuthConfig(LS.config, LS.auth) + + if LS.auth == newJNull(): + # Attempt to retrieve auth.json from system documents + let options = newQueryOptions(true) + let rawDoc = LS.store.retrieveRawDocument("auth.json", options) + if rawDoc != "": + LS.auth = rawDoc.parseJson()["data"] + + # Validation + if LS.directory == "" and (LS.operation in [opDelete, opImport, opExport] or LS.mount): + fail(105, "--directory option not specified.") + + if LS.execution.file == "" and (LS.execution.operation in ["put", "post", "patch"]): + fail(109, "--file option not specified") + + if LS.execution.uri == "" and LS.operation == opExecute: + fail(110, "--uri option not specified") + + if LS.execution.operation == "" and LS.operation == opExecute: + fail(111, "--operation option not specified") + + +proc updateConfig*(LS: LiteStore) = + let rawConfig = LS.config.pretty + if LS.configFile != "": + LS.configFile.writeFile(rawConfig) + else: + let options = newQueryOptions(true) + let configDoc = LS.store.retrieveRawDocument("config.json", options) + if configDoc != "": + discard LS.store.updateSystemDocument("config.json", rawConfig, "application/json") + +proc addStore*(LS: LiteStore, id, file: string, config = newJNull()): LiteStore = + result = initLiteStore() + result.address = LS.address + result.port = LS.port + result.appname = LS.appname + result.appversion = LS.appversion + result.favicon = LS.favicon + result.file = file + result.middleware = newStringTable() + if config != newJNull(): + result.config = config + LOG.info("Initializing store '$1'" % id) + result.setup(true) + result.initStore() + if not LS.config.hasKey("stores"): + LS.config["stores"] = newJObject() + LS.config["stores"][id] = newJObject() + LS.config["stores"][id]["file"] = %file + LS.config["stores"][id]["config"] = config
@@ -0,0 +1,721 @@
+type + DTContext* = pointer +type + duk_int_t* = cint + duk_uint_t* = cuint + duk_uint8_t* = uint8 + duk_int8_t* = int8 + duk_uint16_t* = uint16 + duk_int16_t* = int16 + duk_uint32_t* = uint32 + duk_int32_t* = int32 + duk_uint64_t* = uint64 + duk_int64_t* = int64 + duk_small_int_t* = cint + duk_small_uint_t* = cuint + duk_bool_t* = cint + duk_idx_t* = duk_int_t + duk_uidx_t* = duk_uint_t + duk_uarridx_t* = duk_uint_t + duk_errcode_t* = duk_int_t + duk_codepoint_t* = duk_int_t + duk_ucodepoint_t* = duk_uint_t + duk_float_t* = cfloat + duk_double_t* = cdouble + duk_size_t* = cint + duk_ret_t* = cint + +import strutils +const sourcePath = currentSourcePath().split({'\\', '/'})[0..^2].join("/") +{.passC: "-I\"" & sourcePath & "/../vendor/duktape\"".} +const headerduktape = sourcePath & "/../vendor/duktape/duktape.h" +const headerconsole = sourcePath & "/../vendor/duktape/extras/console/duk_console.h" +const headerprintalert = sourcePath & "/../vendor/duktape/extras/print-alert/duk_print_alert.h" +{.compile: "../vendor/duktape/duktape.c".} +{.compile: "../vendor/duktape/extras/console/duk_console.c".} +{.compile: "../vendor/duktape/extras/print-alert/duk_print_alert.c".} +const + DUK_VERSION* = 20201 + DUK_DEBUG_PROTOCOL_VERSION* = 2 + DUK_API_ENTRY_STACK* = 64 + DUK_TYPE_MIN* = 0 + DUK_TYPE_NONE* = 0 + DUK_TYPE_UNDEFINED* = 1 + DUK_TYPE_NULL* = 2 + DUK_TYPE_BOOLEAN* = 3 + DUK_TYPE_NUMBER* = 4 + DUK_TYPE_STRING* = 5 + DUK_TYPE_OBJECT* = 6 + DUK_TYPE_BUFFER* = 7 + DUK_TYPE_POINTER* = 8 + DUK_TYPE_LIGHTFUNC* = 9 + DUK_TYPE_MAX* = 9 + DUK_HINT_NONE* = 0 + DUK_HINT_STRING* = 1 + DUK_HINT_NUMBER* = 2 + DUK_ERR_NONE* = 0 + DUK_ERR_ERROR* = 1 + DUK_ERR_EVAL_ERROR* = 2 + DUK_ERR_RANGE_ERROR* = 3 + DUK_ERR_REFERENCE_ERROR* = 4 + DUK_ERR_SYNTAX_ERROR* = 5 + DUK_ERR_TYPE_ERROR* = 6 + DUK_ERR_URI_ERROR* = 7 + DUK_EXEC_SUCCESS* = 0 + DUK_EXEC_ERROR* = 1 + DUK_LEVEL_DEBUG* = 0 + DUK_LEVEL_DDEBUG* = 1 + DUK_LEVEL_DDDEBUG* = 2 + DUK_BUFOBJ_ARRAYBUFFER* = 0 + DUK_BUFOBJ_NODEJS_BUFFER* = 1 + DUK_BUFOBJ_DATAVIEW* = 2 + DUK_BUFOBJ_INT8ARRAY* = 3 + DUK_BUFOBJ_UINT8ARRAY* = 4 + DUK_BUFOBJ_UINT8CLAMPEDARRAY* = 5 + DUK_BUFOBJ_INT16ARRAY* = 6 + DUK_BUFOBJ_UINT16ARRAY* = 7 + DUK_BUFOBJ_INT32ARRAY* = 8 + DUK_BUFOBJ_UINT32ARRAY* = 9 + DUK_BUFOBJ_FLOAT32ARRAY* = 10 + DUK_BUFOBJ_FLOAT64ARRAY* = 11 + DUK_BUF_MODE_FIXED* = 0 + DUK_BUF_MODE_DYNAMIC* = 1 + DUK_BUF_MODE_DONTCARE* = 2 + DUK_DATE_MSEC_SECOND* = 1000 + DUK_DATE_MAX_ECMA_YEAR* = 275760 + DUK_DATE_IDX_YEAR* = 0 + DUK_DATE_IDX_MONTH* = 1 + DUK_DATE_IDX_DAY* = 2 + DUK_DATE_IDX_HOUR* = 3 + DUK_DATE_IDX_MINUTE* = 4 + DUK_DATE_IDX_SECOND* = 5 + DUK_DATE_IDX_MILLISECOND* = 6 + DUK_DATE_IDX_WEEKDAY* = 7 + DUK_DATE_IDX_NUM_PARTS* = 8 + DUK_DATE_FLAG_VALUE_SHIFT* = 12 + +type + duk_thread_state* {.importc: "duk_thread_state", header: headerduktape, bycopy.} = object + + duk_memory_functions* {.importc: "duk_memory_functions", header: headerduktape, + bycopy.} = object + + duk_function_list_entry* {.importc: "duk_function_list_entry", + header: headerduktape, bycopy.} = object + + duk_number_list_entry* {.importc: "duk_number_list_entry", header: headerduktape, + bycopy.} = object + + duk_time_components* {.importc: "duk_time_components", header: headerduktape, + bycopy.} = object + + duk_c_function* = proc (ctx: DTContext): duk_ret_t {.stdcall.} + duk_alloc_function* = proc (udata: pointer; size: duk_size_t): pointer {.stdcall.} + duk_realloc_function* = proc (udata: pointer; `ptr`: pointer; size: duk_size_t): pointer {. + stdcall.} + duk_free_function* = proc (udata: pointer; `ptr`: pointer) {.stdcall.} + duk_fatal_function* = proc (udata: pointer; msg: cstring) {.stdcall.} + duk_decode_char_function* = proc (udata: pointer; codepoint: duk_codepoint_t) {. + stdcall.} + duk_map_char_function* = proc (udata: pointer; codepoint: duk_codepoint_t): duk_codepoint_t {. + stdcall.} + duk_safe_call_function* = proc (ctx: DTContext; udata: pointer): duk_ret_t {. + stdcall.} + duk_debug_read_function* = proc (udata: pointer; buffer: cstring; length: duk_size_t): duk_size_t {. + stdcall.} + duk_debug_write_function* = proc (udata: pointer; buffer: cstring; length: duk_size_t): duk_size_t {. + stdcall.} + duk_debug_peek_function* = proc (udata: pointer): duk_size_t {.stdcall.} + duk_debug_read_flush_function* = proc (udata: pointer) {.stdcall.} + duk_debug_write_flush_function* = proc (udata: pointer) {.stdcall.} + duk_debug_request_function* = proc (ctx: DTContext; udata: pointer; + nvalues: duk_idx_t): duk_idx_t {.stdcall.} + duk_debug_detached_function* = proc (ctx: DTContext; udata: pointer) {.stdcall.} + +proc duk_create_heap*(alloc_func: duk_alloc_function; + realloc_func: duk_realloc_function; + free_func: duk_free_function; heap_udata: pointer; + fatal_handler: duk_fatal_function): DTContext {.stdcall, + importc: "duk_create_heap", header: headerduktape.} +proc duk_destroy_heap*(ctx: DTContext) {.stdcall, importc: "duk_destroy_heap", + header: headerduktape.} +proc duk_suspend*(ctx: DTContext; state: ptr duk_thread_state) {.stdcall, + importc: "duk_suspend", header: headerduktape.} +proc duk_resume*(ctx: DTContext; state: ptr duk_thread_state) {.stdcall, + importc: "duk_resume", header: headerduktape.} +proc duk_alloc_raw*(ctx: DTContext; size: duk_size_t): pointer {.stdcall, + importc: "duk_alloc_raw", header: headerduktape.} +proc duk_free_raw*(ctx: DTContext; `ptr`: pointer) {.stdcall, + importc: "duk_free_raw", header: headerduktape.} +proc duk_realloc_raw*(ctx: DTContext; `ptr`: pointer; size: duk_size_t): pointer {. + stdcall, importc: "duk_realloc_raw", header: headerduktape.} +proc duk_alloc*(ctx: DTContext; size: duk_size_t): pointer {.stdcall, + importc: "duk_alloc", header: headerduktape.} +proc duk_free*(ctx: DTContext; `ptr`: pointer) {.stdcall, importc: "duk_free", + header: headerduktape.} +proc duk_realloc*(ctx: DTContext; `ptr`: pointer; size: duk_size_t): pointer {. + stdcall, importc: "duk_realloc", header: headerduktape.} +proc duk_get_memory_functions*(ctx: DTContext; + out_funcs: ptr duk_memory_functions) {.stdcall, + importc: "duk_get_memory_functions", header: headerduktape.} +proc duk_gc*(ctx: DTContext; flags: duk_uint_t) {.stdcall, importc: "duk_gc", + header: headerduktape.} +proc duk_throw_raw*(ctx: DTContext) {.stdcall, importc: "duk_throw_raw", + header: headerduktape.} +proc duk_fatal_raw*(ctx: DTContext; err_msg: cstring) {.stdcall, + importc: "duk_fatal_raw", header: headerduktape.} +proc duk_error_raw*(ctx: DTContext; err_code: duk_errcode_t; filename: cstring; + line: duk_int_t; fmt: cstring) {.varargs, stdcall, + importc: "duk_error_raw", header: headerduktape.} +proc duk_is_strict_call*(ctx: DTContext): duk_bool_t {.stdcall, + importc: "duk_is_strict_call", header: headerduktape.} +proc duk_is_constructor_call*(ctx: DTContext): duk_bool_t {.stdcall, + importc: "duk_is_constructor_call", header: headerduktape.} +proc duk_normalize_index*(ctx: DTContext; idx: duk_idx_t): duk_idx_t {.stdcall, + importc: "duk_normalize_index", header: headerduktape.} +proc duk_require_normalize_index*(ctx: DTContext; idx: duk_idx_t): duk_idx_t {. + stdcall, importc: "duk_require_normalize_index", header: headerduktape.} +proc duk_is_valid_index*(ctx: DTContext; idx: duk_idx_t): duk_bool_t {.stdcall, + importc: "duk_is_valid_index", header: headerduktape.} +proc duk_require_valid_index*(ctx: DTContext; idx: duk_idx_t) {.stdcall, + importc: "duk_require_valid_index", header: headerduktape.} +proc duk_get_top*(ctx: DTContext): duk_idx_t {.stdcall, importc: "duk_get_top", + header: headerduktape.} +proc duk_set_top*(ctx: DTContext; idx: duk_idx_t) {.stdcall, + importc: "duk_set_top", header: headerduktape.} +proc duk_get_top_index*(ctx: DTContext): duk_idx_t {.stdcall, + importc: "duk_get_top_index", header: headerduktape.} +proc duk_require_top_index*(ctx: DTContext): duk_idx_t {.stdcall, + importc: "duk_require_top_index", header: headerduktape.} +proc duk_check_stack*(ctx: DTContext; extra: duk_idx_t): duk_bool_t {.stdcall, + importc: "duk_check_stack", header: headerduktape.} +proc duk_require_stack*(ctx: DTContext; extra: duk_idx_t) {.stdcall, + importc: "duk_require_stack", header: headerduktape.} +proc duk_check_stack_top*(ctx: DTContext; top: duk_idx_t): duk_bool_t {.stdcall, + importc: "duk_check_stack_top", header: headerduktape.} +proc duk_require_stack_top*(ctx: DTContext; top: duk_idx_t) {.stdcall, + importc: "duk_require_stack_top", header: headerduktape.} +proc duk_swap*(ctx: DTContext; idx1: duk_idx_t; idx2: duk_idx_t) {.stdcall, + importc: "duk_swap", header: headerduktape.} +proc duk_swap_top*(ctx: DTContext; idx: duk_idx_t) {.stdcall, + importc: "duk_swap_top", header: headerduktape.} +proc duk_dup*(ctx: DTContext; from_idx: duk_idx_t) {.stdcall, importc: "duk_dup", + header: headerduktape.} +proc duk_dup_top*(ctx: DTContext) {.stdcall, importc: "duk_dup_top", + header: headerduktape.} +proc duk_insert*(ctx: DTContext; to_idx: duk_idx_t) {.stdcall, + importc: "duk_insert", header: headerduktape.} +proc duk_replace*(ctx: DTContext; to_idx: duk_idx_t) {.stdcall, + importc: "duk_replace", header: headerduktape.} +proc duk_copy*(ctx: DTContext; from_idx: duk_idx_t; to_idx: duk_idx_t) {.stdcall, + importc: "duk_copy", header: headerduktape.} +proc duk_remove*(ctx: DTContext; idx: duk_idx_t) {.stdcall, + importc: "duk_remove", header: headerduktape.} +proc duk_xcopymove_raw*(to_ctx: DTContext; from_ctx: DTContext; + count: duk_idx_t; is_copy: duk_bool_t) {.stdcall, + importc: "duk_xcopymove_raw", header: headerduktape.} +proc duk_push_undefined*(ctx: DTContext) {.stdcall, + importc: "duk_push_undefined", header: headerduktape.} +proc duk_push_null*(ctx: DTContext) {.stdcall, importc: "duk_push_null", + header: headerduktape.} +proc duk_push_boolean*(ctx: DTContext; val: duk_bool_t) {.stdcall, + importc: "duk_push_boolean", header: headerduktape.} +proc duk_push_true*(ctx: DTContext) {.stdcall, importc: "duk_push_true", + header: headerduktape.} +proc duk_push_false*(ctx: DTContext) {.stdcall, importc: "duk_push_false", + header: headerduktape.} +proc duk_push_number*(ctx: DTContext; val: duk_double_t) {.stdcall, + importc: "duk_push_number", header: headerduktape.} +proc duk_push_nan*(ctx: DTContext) {.stdcall, importc: "duk_push_nan", + header: headerduktape.} +proc duk_push_int*(ctx: DTContext; val: duk_int_t) {.stdcall, + importc: "duk_push_int", header: headerduktape.} +proc duk_push_uint*(ctx: DTContext; val: duk_uint_t) {.stdcall, + importc: "duk_push_uint", header: headerduktape.} +proc duk_push_string*(ctx: DTContext; str: cstring): cstring {.stdcall, + importc: "duk_push_string", header: headerduktape.} +proc duk_push_lstring*(ctx: DTContext; str: cstring; len: duk_size_t): cstring {. + stdcall, importc: "duk_push_lstring", header: headerduktape.} +proc duk_push_pointer*(ctx: DTContext; p: pointer) {.stdcall, + importc: "duk_push_pointer", header: headerduktape.} +proc duk_push_sprintf*(ctx: DTContext; fmt: cstring): cstring {.varargs, stdcall, + importc: "duk_push_sprintf", header: headerduktape.} +proc duk_push_this*(ctx: DTContext) {.stdcall, importc: "duk_push_this", + header: headerduktape.} +proc duk_push_current_function*(ctx: DTContext) {.stdcall, + importc: "duk_push_current_function", header: headerduktape.} +proc duk_push_current_thread*(ctx: DTContext) {.stdcall, + importc: "duk_push_current_thread", header: headerduktape.} +proc duk_push_global_object*(ctx: DTContext) {.stdcall, + importc: "duk_push_global_object", header: headerduktape.} +proc duk_push_heap_stash*(ctx: DTContext) {.stdcall, + importc: "duk_push_heap_stash", header: headerduktape.} +proc duk_push_global_stash*(ctx: DTContext) {.stdcall, + importc: "duk_push_global_stash", header: headerduktape.} +proc duk_push_thread_stash*(ctx: DTContext; target_ctx: DTContext) {. + stdcall, importc: "duk_push_thread_stash", header: headerduktape.} +proc duk_push_object*(ctx: DTContext): duk_idx_t {.stdcall, + importc: "duk_push_object", header: headerduktape.} +proc duk_push_bare_object*(ctx: DTContext): duk_idx_t {.stdcall, + importc: "duk_push_bare_object", header: headerduktape.} +proc duk_push_array*(ctx: DTContext): duk_idx_t {.stdcall, + importc: "duk_push_array", header: headerduktape.} +proc duk_push_c_function*(ctx: DTContext; `func`: duk_c_function; + nargs: duk_idx_t): duk_idx_t {.stdcall, + importc: "duk_push_c_function", header: headerduktape.} +proc duk_push_c_lightfunc*(ctx: DTContext; `func`: duk_c_function; + nargs: duk_idx_t; length: duk_idx_t; magic: duk_int_t): duk_idx_t {. + stdcall, importc: "duk_push_c_lightfunc", header: headerduktape.} +proc duk_push_thread_raw*(ctx: DTContext; flags: duk_uint_t): duk_idx_t {. + stdcall, importc: "duk_push_thread_raw", header: headerduktape.} +proc duk_push_proxy*(ctx: DTContext; proxy_flags: duk_uint_t): duk_idx_t {. + stdcall, importc: "duk_push_proxy", header: headerduktape.} +proc duk_push_error_object_raw*(ctx: DTContext; err_code: duk_errcode_t; + filename: cstring; line: duk_int_t; fmt: cstring): duk_idx_t {. + varargs, stdcall, importc: "duk_push_error_object_raw", header: headerduktape.} +proc duk_push_buffer_raw*(ctx: DTContext; size: duk_size_t; + flags: duk_small_uint_t): pointer {.stdcall, + importc: "duk_push_buffer_raw", header: headerduktape.} +proc duk_push_buffer_object*(ctx: DTContext; idx_buffer: duk_idx_t; + byte_offset: duk_size_t; byte_length: duk_size_t; + flags: duk_uint_t) {.stdcall, + importc: "duk_push_buffer_object", header: headerduktape.} +proc duk_push_heapptr*(ctx: DTContext; `ptr`: pointer): duk_idx_t {.stdcall, + importc: "duk_push_heapptr", header: headerduktape.} +proc duk_pop*(ctx: DTContext) {.stdcall, importc: "duk_pop", + header: headerduktape.} +proc duk_pop_n*(ctx: DTContext; count: duk_idx_t) {.stdcall, + importc: "duk_pop_n", header: headerduktape.} +proc duk_pop_2*(ctx: DTContext) {.stdcall, importc: "duk_pop_2", + header: headerduktape.} +proc duk_pop_3*(ctx: DTContext) {.stdcall, importc: "duk_pop_3", + header: headerduktape.} +proc duk_get_type*(ctx: DTContext; idx: duk_idx_t): duk_int_t {.stdcall, + importc: "duk_get_type", header: headerduktape.} +proc duk_check_type*(ctx: DTContext; idx: duk_idx_t; `type`: duk_int_t): duk_bool_t {. + stdcall, importc: "duk_check_type", header: headerduktape.} +proc duk_get_type_mask*(ctx: DTContext; idx: duk_idx_t): duk_uint_t {.stdcall, + importc: "duk_get_type_mask", header: headerduktape.} +proc duk_check_type_mask*(ctx: DTContext; idx: duk_idx_t; mask: duk_uint_t): duk_bool_t {. + stdcall, importc: "duk_check_type_mask", header: headerduktape.} +proc duk_is_undefined*(ctx: DTContext; idx: duk_idx_t): duk_bool_t {.stdcall, + importc: "duk_is_undefined", header: headerduktape.} +proc duk_is_null*(ctx: DTContext; idx: duk_idx_t): duk_bool_t {.stdcall, + importc: "duk_is_null", header: headerduktape.} +proc duk_is_boolean*(ctx: DTContext; idx: duk_idx_t): duk_bool_t {.stdcall, + importc: "duk_is_boolean", header: headerduktape.} +proc duk_is_number*(ctx: DTContext; idx: duk_idx_t): duk_bool_t {.stdcall, + importc: "duk_is_number", header: headerduktape.} +proc duk_is_nan*(ctx: DTContext; idx: duk_idx_t): duk_bool_t {.stdcall, + importc: "duk_is_nan", header: headerduktape.} +proc duk_is_string*(ctx: DTContext; idx: duk_idx_t): duk_bool_t {.stdcall, + importc: "duk_is_string", header: headerduktape.} +proc duk_is_object*(ctx: DTContext; idx: duk_idx_t): duk_bool_t {.stdcall, + importc: "duk_is_object", header: headerduktape.} +proc duk_is_buffer*(ctx: DTContext; idx: duk_idx_t): duk_bool_t {.stdcall, + importc: "duk_is_buffer", header: headerduktape.} +proc duk_is_buffer_data*(ctx: DTContext; idx: duk_idx_t): duk_bool_t {.stdcall, + importc: "duk_is_buffer_data", header: headerduktape.} +proc duk_is_pointer*(ctx: DTContext; idx: duk_idx_t): duk_bool_t {.stdcall, + importc: "duk_is_pointer", header: headerduktape.} +proc duk_is_lightfunc*(ctx: DTContext; idx: duk_idx_t): duk_bool_t {.stdcall, + importc: "duk_is_lightfunc", header: headerduktape.} +proc duk_is_symbol*(ctx: DTContext; idx: duk_idx_t): duk_bool_t {.stdcall, + importc: "duk_is_symbol", header: headerduktape.} +proc duk_is_array*(ctx: DTContext; idx: duk_idx_t): duk_bool_t {.stdcall, + importc: "duk_is_array", header: headerduktape.} +proc duk_is_function*(ctx: DTContext; idx: duk_idx_t): duk_bool_t {.stdcall, + importc: "duk_is_function", header: headerduktape.} +proc duk_is_c_function*(ctx: DTContext; idx: duk_idx_t): duk_bool_t {.stdcall, + importc: "duk_is_c_function", header: headerduktape.} +proc duk_is_ecmascript_function*(ctx: DTContext; idx: duk_idx_t): duk_bool_t {. + stdcall, importc: "duk_is_ecmascript_function", header: headerduktape.} +proc duk_is_bound_function*(ctx: DTContext; idx: duk_idx_t): duk_bool_t {. + stdcall, importc: "duk_is_bound_function", header: headerduktape.} +proc duk_is_thread*(ctx: DTContext; idx: duk_idx_t): duk_bool_t {.stdcall, + importc: "duk_is_thread", header: headerduktape.} +proc duk_is_constructable*(ctx: DTContext; idx: duk_idx_t): duk_bool_t {.stdcall, + importc: "duk_is_constructable", header: headerduktape.} +proc duk_is_dynamic_buffer*(ctx: DTContext; idx: duk_idx_t): duk_bool_t {. + stdcall, importc: "duk_is_dynamic_buffer", header: headerduktape.} +proc duk_is_fixed_buffer*(ctx: DTContext; idx: duk_idx_t): duk_bool_t {.stdcall, + importc: "duk_is_fixed_buffer", header: headerduktape.} +proc duk_is_external_buffer*(ctx: DTContext; idx: duk_idx_t): duk_bool_t {. + stdcall, importc: "duk_is_external_buffer", header: headerduktape.} +proc duk_get_error_code*(ctx: DTContext; idx: duk_idx_t): duk_errcode_t {. + stdcall, importc: "duk_get_error_code", header: headerduktape.} +proc duk_get_boolean*(ctx: DTContext; idx: duk_idx_t): duk_bool_t {.stdcall, + importc: "duk_get_boolean", header: headerduktape.} +proc duk_get_number*(ctx: DTContext; idx: duk_idx_t): duk_double_t {.stdcall, + importc: "duk_get_number", header: headerduktape.} +proc duk_get_int*(ctx: DTContext; idx: duk_idx_t): duk_int_t {.stdcall, + importc: "duk_get_int", header: headerduktape.} +proc duk_get_uint*(ctx: DTContext; idx: duk_idx_t): duk_uint_t {.stdcall, + importc: "duk_get_uint", header: headerduktape.} +proc duk_get_string*(ctx: DTContext; idx: duk_idx_t): cstring {.stdcall, + importc: "duk_get_string", header: headerduktape.} +proc duk_get_lstring*(ctx: DTContext; idx: duk_idx_t; out_len: ptr duk_size_t): cstring {. + stdcall, importc: "duk_get_lstring", header: headerduktape.} +proc duk_get_buffer*(ctx: DTContext; idx: duk_idx_t; out_size: ptr duk_size_t): pointer {. + stdcall, importc: "duk_get_buffer", header: headerduktape.} +proc duk_get_buffer_data*(ctx: DTContext; idx: duk_idx_t; + out_size: ptr duk_size_t): pointer {.stdcall, + importc: "duk_get_buffer_data", header: headerduktape.} +proc duk_get_pointer*(ctx: DTContext; idx: duk_idx_t): pointer {.stdcall, + importc: "duk_get_pointer", header: headerduktape.} +proc duk_get_c_function*(ctx: DTContext; idx: duk_idx_t): duk_c_function {. + stdcall, importc: "duk_get_c_function", header: headerduktape.} +proc duk_get_context*(ctx: DTContext; idx: duk_idx_t): DTContext {.stdcall, + importc: "duk_get_context", header: headerduktape.} +proc duk_get_heapptr*(ctx: DTContext; idx: duk_idx_t): pointer {.stdcall, + importc: "duk_get_heapptr", header: headerduktape.} +proc duk_get_boolean_default*(ctx: DTContext; idx: duk_idx_t; + def_value: duk_bool_t): duk_bool_t {.stdcall, + importc: "duk_get_boolean_default", header: headerduktape.} +proc duk_get_number_default*(ctx: DTContext; idx: duk_idx_t; + def_value: duk_double_t): duk_double_t {.stdcall, + importc: "duk_get_number_default", header: headerduktape.} +proc duk_get_int_default*(ctx: DTContext; idx: duk_idx_t; def_value: duk_int_t): duk_int_t {. + stdcall, importc: "duk_get_int_default", header: headerduktape.} +proc duk_get_uint_default*(ctx: DTContext; idx: duk_idx_t; def_value: duk_uint_t): duk_uint_t {. + stdcall, importc: "duk_get_uint_default", header: headerduktape.} +proc duk_get_string_default*(ctx: DTContext; idx: duk_idx_t; def_value: cstring): cstring {. + stdcall, importc: "duk_get_string_default", header: headerduktape.} +proc duk_get_lstring_default*(ctx: DTContext; idx: duk_idx_t; + out_len: ptr duk_size_t; def_ptr: cstring; + def_len: duk_size_t): cstring {.stdcall, + importc: "duk_get_lstring_default", header: headerduktape.} +proc duk_get_buffer_default*(ctx: DTContext; idx: duk_idx_t; + out_size: ptr duk_size_t; def_ptr: pointer; + def_len: duk_size_t): pointer {.stdcall, + importc: "duk_get_buffer_default", header: headerduktape.} +proc duk_get_buffer_data_default*(ctx: DTContext; idx: duk_idx_t; + out_size: ptr duk_size_t; def_ptr: pointer; + def_len: duk_size_t): pointer {.stdcall, + importc: "duk_get_buffer_data_default", header: headerduktape.} +proc duk_get_pointer_default*(ctx: DTContext; idx: duk_idx_t; def_value: pointer): pointer {. + stdcall, importc: "duk_get_pointer_default", header: headerduktape.} +proc duk_get_c_function_default*(ctx: DTContext; idx: duk_idx_t; + def_value: duk_c_function): duk_c_function {. + stdcall, importc: "duk_get_c_function_default", header: headerduktape.} +proc duk_get_context_default*(ctx: DTContext; idx: duk_idx_t; + def_value: DTContext): DTContext {.stdcall, + importc: "duk_get_context_default", header: headerduktape.} +proc duk_get_heapptr_default*(ctx: DTContext; idx: duk_idx_t; def_value: pointer): pointer {. + stdcall, importc: "duk_get_heapptr_default", header: headerduktape.} +proc duk_opt_boolean*(ctx: DTContext; idx: duk_idx_t; def_value: duk_bool_t): duk_bool_t {. + stdcall, importc: "duk_opt_boolean", header: headerduktape.} +proc duk_opt_number*(ctx: DTContext; idx: duk_idx_t; def_value: duk_double_t): duk_double_t {. + stdcall, importc: "duk_opt_number", header: headerduktape.} +proc duk_opt_int*(ctx: DTContext; idx: duk_idx_t; def_value: duk_int_t): duk_int_t {. + stdcall, importc: "duk_opt_int", header: headerduktape.} +proc duk_opt_uint*(ctx: DTContext; idx: duk_idx_t; def_value: duk_uint_t): duk_uint_t {. + stdcall, importc: "duk_opt_uint", header: headerduktape.} +proc duk_opt_string*(ctx: DTContext; idx: duk_idx_t; def_ptr: cstring): cstring {. + stdcall, importc: "duk_opt_string", header: headerduktape.} +proc duk_opt_lstring*(ctx: DTContext; idx: duk_idx_t; out_len: ptr duk_size_t; + def_ptr: cstring; def_len: duk_size_t): cstring {.stdcall, + importc: "duk_opt_lstring", header: headerduktape.} +proc duk_opt_buffer*(ctx: DTContext; idx: duk_idx_t; out_size: ptr duk_size_t; + def_ptr: pointer; def_size: duk_size_t): pointer {.stdcall, + importc: "duk_opt_buffer", header: headerduktape.} +proc duk_opt_buffer_data*(ctx: DTContext; idx: duk_idx_t; + out_size: ptr duk_size_t; def_ptr: pointer; + def_size: duk_size_t): pointer {.stdcall, + importc: "duk_opt_buffer_data", header: headerduktape.} +proc duk_opt_pointer*(ctx: DTContext; idx: duk_idx_t; def_value: pointer): pointer {. + stdcall, importc: "duk_opt_pointer", header: headerduktape.} +proc duk_opt_c_function*(ctx: DTContext; idx: duk_idx_t; + def_value: duk_c_function): duk_c_function {.stdcall, + importc: "duk_opt_c_function", header: headerduktape.} +proc duk_opt_context*(ctx: DTContext; idx: duk_idx_t; def_value: DTContext): DTContext {. + stdcall, importc: "duk_opt_context", header: headerduktape.} +proc duk_opt_heapptr*(ctx: DTContext; idx: duk_idx_t; def_value: pointer): pointer {. + stdcall, importc: "duk_opt_heapptr", header: headerduktape.} +proc duk_require_undefined*(ctx: DTContext; idx: duk_idx_t) {.stdcall, + importc: "duk_require_undefined", header: headerduktape.} +proc duk_require_null*(ctx: DTContext; idx: duk_idx_t) {.stdcall, + importc: "duk_require_null", header: headerduktape.} +proc duk_require_boolean*(ctx: DTContext; idx: duk_idx_t): duk_bool_t {.stdcall, + importc: "duk_require_boolean", header: headerduktape.} +proc duk_require_number*(ctx: DTContext; idx: duk_idx_t): duk_double_t {.stdcall, + importc: "duk_require_number", header: headerduktape.} +proc duk_require_int*(ctx: DTContext; idx: duk_idx_t): duk_int_t {.stdcall, + importc: "duk_require_int", header: headerduktape.} +proc duk_require_uint*(ctx: DTContext; idx: duk_idx_t): duk_uint_t {.stdcall, + importc: "duk_require_uint", header: headerduktape.} +proc duk_require_string*(ctx: DTContext; idx: duk_idx_t): cstring {.stdcall, + importc: "duk_require_string", header: headerduktape.} +proc duk_require_lstring*(ctx: DTContext; idx: duk_idx_t; + out_len: ptr duk_size_t): cstring {.stdcall, + importc: "duk_require_lstring", header: headerduktape.} +proc duk_require_object*(ctx: DTContext; idx: duk_idx_t) {.stdcall, + importc: "duk_require_object", header: headerduktape.} +proc duk_require_buffer*(ctx: DTContext; idx: duk_idx_t; + out_size: ptr duk_size_t): pointer {.stdcall, + importc: "duk_require_buffer", header: headerduktape.} +proc duk_require_buffer_data*(ctx: DTContext; idx: duk_idx_t; + out_size: ptr duk_size_t): pointer {.stdcall, + importc: "duk_require_buffer_data", header: headerduktape.} +proc duk_require_pointer*(ctx: DTContext; idx: duk_idx_t): pointer {.stdcall, + importc: "duk_require_pointer", header: headerduktape.} +proc duk_require_c_function*(ctx: DTContext; idx: duk_idx_t): duk_c_function {. + stdcall, importc: "duk_require_c_function", header: headerduktape.} +proc duk_require_context*(ctx: DTContext; idx: duk_idx_t): DTContext {. + stdcall, importc: "duk_require_context", header: headerduktape.} +proc duk_require_function*(ctx: DTContext; idx: duk_idx_t) {.stdcall, + importc: "duk_require_function", header: headerduktape.} +proc duk_require_heapptr*(ctx: DTContext; idx: duk_idx_t): pointer {.stdcall, + importc: "duk_require_heapptr", header: headerduktape.} +proc duk_to_undefined*(ctx: DTContext; idx: duk_idx_t) {.stdcall, + importc: "duk_to_undefined", header: headerduktape.} +proc duk_to_null*(ctx: DTContext; idx: duk_idx_t) {.stdcall, + importc: "duk_to_null", header: headerduktape.} +proc duk_to_boolean*(ctx: DTContext; idx: duk_idx_t): duk_bool_t {.stdcall, + importc: "duk_to_boolean", header: headerduktape.} +proc duk_to_number*(ctx: DTContext; idx: duk_idx_t): duk_double_t {.stdcall, + importc: "duk_to_number", header: headerduktape.} +proc duk_to_int*(ctx: DTContext; idx: duk_idx_t): duk_int_t {.stdcall, + importc: "duk_to_int", header: headerduktape.} +proc duk_to_uint*(ctx: DTContext; idx: duk_idx_t): duk_uint_t {.stdcall, + importc: "duk_to_uint", header: headerduktape.} +proc duk_to_int32*(ctx: DTContext; idx: duk_idx_t): duk_int32_t {.stdcall, + importc: "duk_to_int32", header: headerduktape.} +proc duk_to_uint32*(ctx: DTContext; idx: duk_idx_t): duk_uint32_t {.stdcall, + importc: "duk_to_uint32", header: headerduktape.} +proc duk_to_uint16*(ctx: DTContext; idx: duk_idx_t): duk_uint16_t {.stdcall, + importc: "duk_to_uint16", header: headerduktape.} +proc duk_to_string*(ctx: DTContext; idx: duk_idx_t): cstring {.stdcall, + importc: "duk_to_string", header: headerduktape.} +proc duk_to_lstring*(ctx: DTContext; idx: duk_idx_t; out_len: ptr duk_size_t): cstring {. + stdcall, importc: "duk_to_lstring", header: headerduktape.} +proc duk_to_buffer_raw*(ctx: DTContext; idx: duk_idx_t; + out_size: ptr duk_size_t; flags: duk_uint_t): pointer {. + stdcall, importc: "duk_to_buffer_raw", header: headerduktape.} +proc duk_to_pointer*(ctx: DTContext; idx: duk_idx_t): pointer {.stdcall, + importc: "duk_to_pointer", header: headerduktape.} +proc duk_to_object*(ctx: DTContext; idx: duk_idx_t) {.stdcall, + importc: "duk_to_object", header: headerduktape.} +proc duk_to_primitive*(ctx: DTContext; idx: duk_idx_t; hint: duk_int_t) {.stdcall, + importc: "duk_to_primitive", header: headerduktape.} +proc duk_safe_to_lstring*(ctx: DTContext; idx: duk_idx_t; + out_len: ptr duk_size_t): cstring {.stdcall, + importc: "duk_safe_to_lstring", header: headerduktape.} +proc duk_get_length*(ctx: DTContext; idx: duk_idx_t): duk_size_t {.stdcall, + importc: "duk_get_length", header: headerduktape.} +proc duk_set_length*(ctx: DTContext; idx: duk_idx_t; len: duk_size_t) {.stdcall, + importc: "duk_set_length", header: headerduktape.} +proc duk_base64_encode*(ctx: DTContext; idx: duk_idx_t): cstring {.stdcall, + importc: "duk_base64_encode", header: headerduktape.} +proc duk_base64_decode*(ctx: DTContext; idx: duk_idx_t) {.stdcall, + importc: "duk_base64_decode", header: headerduktape.} +proc duk_hex_encode*(ctx: DTContext; idx: duk_idx_t): cstring {.stdcall, + importc: "duk_hex_encode", header: headerduktape.} +proc duk_hex_decode*(ctx: DTContext; idx: duk_idx_t) {.stdcall, + importc: "duk_hex_decode", header: headerduktape.} +proc duk_json_encode*(ctx: DTContext; idx: duk_idx_t): cstring {.stdcall, + importc: "duk_json_encode", header: headerduktape.} +proc duk_json_decode*(ctx: DTContext; idx: duk_idx_t) {.stdcall, + importc: "duk_json_decode", header: headerduktape.} +proc duk_buffer_to_string*(ctx: DTContext; idx: duk_idx_t): cstring {.stdcall, + importc: "duk_buffer_to_string", header: headerduktape.} +proc duk_resize_buffer*(ctx: DTContext; idx: duk_idx_t; new_size: duk_size_t): pointer {. + stdcall, importc: "duk_resize_buffer", header: headerduktape.} +proc duk_steal_buffer*(ctx: DTContext; idx: duk_idx_t; out_size: ptr duk_size_t): pointer {. + stdcall, importc: "duk_steal_buffer", header: headerduktape.} +proc duk_config_buffer*(ctx: DTContext; idx: duk_idx_t; `ptr`: pointer; + len: duk_size_t) {.stdcall, importc: "duk_config_buffer", + header: headerduktape.} +proc duk_get_prop*(ctx: DTContext; obj_idx: duk_idx_t): duk_bool_t {.stdcall, + importc: "duk_get_prop", header: headerduktape.} +proc duk_get_prop_string*(ctx: DTContext; obj_idx: duk_idx_t; key: cstring): duk_bool_t {. + stdcall, importc: "duk_get_prop_string", header: headerduktape.} +proc duk_get_prop_lstring*(ctx: DTContext; obj_idx: duk_idx_t; key: cstring; + key_len: duk_size_t): duk_bool_t {.stdcall, + importc: "duk_get_prop_lstring", header: headerduktape.} +proc duk_get_prop_index*(ctx: DTContext; obj_idx: duk_idx_t; + arr_idx: duk_uarridx_t): duk_bool_t {.stdcall, + importc: "duk_get_prop_index", header: headerduktape.} +proc duk_get_prop_heapptr*(ctx: DTContext; obj_idx: duk_idx_t; `ptr`: pointer): duk_bool_t {. + stdcall, importc: "duk_get_prop_heapptr", header: headerduktape.} +proc duk_put_prop*(ctx: DTContext; obj_idx: duk_idx_t): duk_bool_t {.stdcall, + importc: "duk_put_prop", header: headerduktape.} +proc duk_put_prop_string*(ctx: DTContext; obj_idx: duk_idx_t; key: cstring): duk_bool_t {. + stdcall, importc: "duk_put_prop_string", header: headerduktape.} +proc duk_put_prop_lstring*(ctx: DTContext; obj_idx: duk_idx_t; key: cstring; + key_len: duk_size_t): duk_bool_t {.stdcall, + importc: "duk_put_prop_lstring", header: headerduktape.} +proc duk_put_prop_index*(ctx: DTContext; obj_idx: duk_idx_t; + arr_idx: duk_uarridx_t): duk_bool_t {.stdcall, + importc: "duk_put_prop_index", header: headerduktape.} +proc duk_put_prop_heapptr*(ctx: DTContext; obj_idx: duk_idx_t; `ptr`: pointer): duk_bool_t {. + stdcall, importc: "duk_put_prop_heapptr", header: headerduktape.} +proc duk_del_prop*(ctx: DTContext; obj_idx: duk_idx_t): duk_bool_t {.stdcall, + importc: "duk_del_prop", header: headerduktape.} +proc duk_del_prop_string*(ctx: DTContext; obj_idx: duk_idx_t; key: cstring): duk_bool_t {. + stdcall, importc: "duk_del_prop_string", header: headerduktape.} +proc duk_del_prop_lstring*(ctx: DTContext; obj_idx: duk_idx_t; key: cstring; + key_len: duk_size_t): duk_bool_t {.stdcall, + importc: "duk_del_prop_lstring", header: headerduktape.} +proc duk_del_prop_index*(ctx: DTContext; obj_idx: duk_idx_t; + arr_idx: duk_uarridx_t): duk_bool_t {.stdcall, + importc: "duk_del_prop_index", header: headerduktape.} +proc duk_del_prop_heapptr*(ctx: DTContext; obj_idx: duk_idx_t; `ptr`: pointer): duk_bool_t {. + stdcall, importc: "duk_del_prop_heapptr", header: headerduktape.} +proc duk_has_prop*(ctx: DTContext; obj_idx: duk_idx_t): duk_bool_t {.stdcall, + importc: "duk_has_prop", header: headerduktape.} +proc duk_has_prop_string*(ctx: DTContext; obj_idx: duk_idx_t; key: cstring): duk_bool_t {. + stdcall, importc: "duk_has_prop_string", header: headerduktape.} +proc duk_has_prop_lstring*(ctx: DTContext; obj_idx: duk_idx_t; key: cstring; + key_len: duk_size_t): duk_bool_t {.stdcall, + importc: "duk_has_prop_lstring", header: headerduktape.} +proc duk_has_prop_index*(ctx: DTContext; obj_idx: duk_idx_t; + arr_idx: duk_uarridx_t): duk_bool_t {.stdcall, + importc: "duk_has_prop_index", header: headerduktape.} +proc duk_has_prop_heapptr*(ctx: DTContext; obj_idx: duk_idx_t; `ptr`: pointer): duk_bool_t {. + stdcall, importc: "duk_has_prop_heapptr", header: headerduktape.} +proc duk_get_prop_desc*(ctx: DTContext; obj_idx: duk_idx_t; flags: duk_uint_t) {. + stdcall, importc: "duk_get_prop_desc", header: headerduktape.} +proc duk_def_prop*(ctx: DTContext; obj_idx: duk_idx_t; flags: duk_uint_t) {. + stdcall, importc: "duk_def_prop", header: headerduktape.} +proc duk_get_global_string*(ctx: DTContext; key: cstring): duk_bool_t {.stdcall, + importc: "duk_get_global_string", header: headerduktape.} +proc duk_get_global_lstring*(ctx: DTContext; key: cstring; key_len: duk_size_t): duk_bool_t {. + stdcall, importc: "duk_get_global_lstring", header: headerduktape.} +proc duk_put_global_string*(ctx: DTContext; key: cstring): duk_bool_t {.stdcall, + importc: "duk_put_global_string", header: headerduktape.} +proc duk_put_global_lstring*(ctx: DTContext; key: cstring; key_len: duk_size_t): duk_bool_t {. + stdcall, importc: "duk_put_global_lstring", header: headerduktape.} +proc duk_inspect_value*(ctx: DTContext; idx: duk_idx_t) {.stdcall, + importc: "duk_inspect_value", header: headerduktape.} +proc duk_inspect_callstack_entry*(ctx: DTContext; level: duk_int_t) {.stdcall, + importc: "duk_inspect_callstack_entry", header: headerduktape.} +proc duk_get_prototype*(ctx: DTContext; idx: duk_idx_t) {.stdcall, + importc: "duk_get_prototype", header: headerduktape.} +proc duk_set_prototype*(ctx: DTContext; idx: duk_idx_t) {.stdcall, + importc: "duk_set_prototype", header: headerduktape.} +proc duk_get_finalizer*(ctx: DTContext; idx: duk_idx_t) {.stdcall, + importc: "duk_get_finalizer", header: headerduktape.} +proc duk_set_finalizer*(ctx: DTContext; idx: duk_idx_t) {.stdcall, + importc: "duk_set_finalizer", header: headerduktape.} +proc duk_set_global_object*(ctx: DTContext) {.stdcall, + importc: "duk_set_global_object", header: headerduktape.} +proc duk_get_magic*(ctx: DTContext; idx: duk_idx_t): duk_int_t {.stdcall, + importc: "duk_get_magic", header: headerduktape.} +proc duk_set_magic*(ctx: DTContext; idx: duk_idx_t; magic: duk_int_t) {.stdcall, + importc: "duk_set_magic", header: headerduktape.} +proc duk_get_current_magic*(ctx: DTContext): duk_int_t {.stdcall, + importc: "duk_get_current_magic", header: headerduktape.} +proc duk_put_function_list*(ctx: DTContext; obj_idx: duk_idx_t; + funcs: ptr duk_function_list_entry) {.stdcall, + importc: "duk_put_function_list", header: headerduktape.} +proc duk_put_number_list*(ctx: DTContext; obj_idx: duk_idx_t; + numbers: ptr duk_number_list_entry) {.stdcall, + importc: "duk_put_number_list", header: headerduktape.} +proc duk_compact*(ctx: DTContext; obj_idx: duk_idx_t) {.stdcall, + importc: "duk_compact", header: headerduktape.} +proc duk_enum*(ctx: DTContext; obj_idx: duk_idx_t; enum_flags: duk_uint_t) {. + stdcall, importc: "duk_enum", header: headerduktape.} +proc duk_next*(ctx: DTContext; enum_idx: duk_idx_t; get_value: duk_bool_t): duk_bool_t {. + stdcall, importc: "duk_next", header: headerduktape.} +proc duk_seal*(ctx: DTContext; obj_idx: duk_idx_t) {.stdcall, + importc: "duk_seal", header: headerduktape.} +proc duk_freeze*(ctx: DTContext; obj_idx: duk_idx_t) {.stdcall, + importc: "duk_freeze", header: headerduktape.} +proc duk_concat*(ctx: DTContext; count: duk_idx_t) {.stdcall, + importc: "duk_concat", header: headerduktape.} +proc duk_join*(ctx: DTContext; count: duk_idx_t) {.stdcall, importc: "duk_join", + header: headerduktape.} +proc duk_decode_string*(ctx: DTContext; idx: duk_idx_t; + callback: duk_decode_char_function; udata: pointer) {. + stdcall, importc: "duk_decode_string", header: headerduktape.} +proc duk_map_string*(ctx: DTContext; idx: duk_idx_t; + callback: duk_map_char_function; udata: pointer) {.stdcall, + importc: "duk_map_string", header: headerduktape.} +proc duk_substring*(ctx: DTContext; idx: duk_idx_t; + start_char_offset: duk_size_t; end_char_offset: duk_size_t) {. + stdcall, importc: "duk_substring", header: headerduktape.} +proc duk_trim*(ctx: DTContext; idx: duk_idx_t) {.stdcall, importc: "duk_trim", + header: headerduktape.} +proc duk_char_code_at*(ctx: DTContext; idx: duk_idx_t; char_offset: duk_size_t): duk_codepoint_t {. + stdcall, importc: "duk_char_code_at", header: headerduktape.} +proc duk_equals*(ctx: DTContext; idx1: duk_idx_t; idx2: duk_idx_t): duk_bool_t {. + stdcall, importc: "duk_equals", header: headerduktape.} +proc duk_strict_equals*(ctx: DTContext; idx1: duk_idx_t; idx2: duk_idx_t): duk_bool_t {. + stdcall, importc: "duk_strict_equals", header: headerduktape.} +proc duk_samevalue*(ctx: DTContext; idx1: duk_idx_t; idx2: duk_idx_t): duk_bool_t {. + stdcall, importc: "duk_samevalue", header: headerduktape.} +proc duk_instanceof*(ctx: DTContext; idx1: duk_idx_t; idx2: duk_idx_t): duk_bool_t {. + stdcall, importc: "duk_instanceof", header: headerduktape.} +proc duk_call*(ctx: DTContext; nargs: duk_idx_t) {.stdcall, importc: "duk_call", + header: headerduktape.} +proc duk_call_method*(ctx: DTContext; nargs: duk_idx_t) {.stdcall, + importc: "duk_call_method", header: headerduktape.} +proc duk_call_prop*(ctx: DTContext; obj_idx: duk_idx_t; nargs: duk_idx_t) {. + stdcall, importc: "duk_call_prop", header: headerduktape.} +proc duk_pcall*(ctx: DTContext; nargs: duk_idx_t): duk_int_t {.stdcall, + importc: "duk_pcall", header: headerduktape.} +proc duk_pcall_method*(ctx: DTContext; nargs: duk_idx_t): duk_int_t {.stdcall, + importc: "duk_pcall_method", header: headerduktape.} +proc duk_pcall_prop*(ctx: DTContext; obj_idx: duk_idx_t; nargs: duk_idx_t): duk_int_t {. + stdcall, importc: "duk_pcall_prop", header: headerduktape.} +proc duk_new*(ctx: DTContext; nargs: duk_idx_t) {.stdcall, importc: "duk_new", + header: headerduktape.} +proc duk_pnew*(ctx: DTContext; nargs: duk_idx_t): duk_int_t {.stdcall, + importc: "duk_pnew", header: headerduktape.} +proc duk_safe_call*(ctx: DTContext; `func`: duk_safe_call_function; + udata: pointer; nargs: duk_idx_t; nrets: duk_idx_t): duk_int_t {. + stdcall, importc: "duk_safe_call", header: headerduktape.} +proc duk_eval_raw*(ctx: DTContext; src_buffer: cstring; src_length: duk_size_t; + flags: duk_uint_t): duk_int_t {.stdcall, importc: "duk_eval_raw", + header: headerduktape.} +proc duk_compile_raw*(ctx: DTContext; src_buffer: cstring; + src_length: duk_size_t; flags: duk_uint_t): duk_int_t {.stdcall, + importc: "duk_compile_raw", header: headerduktape.} +proc duk_dump_function*(ctx: DTContext) {.stdcall, + importc: "duk_dump_function", header: headerduktape.} +proc duk_load_function*(ctx: DTContext) {.stdcall, + importc: "duk_load_function", header: headerduktape.} +proc duk_push_context_dump*(ctx: DTContext) {.stdcall, + importc: "duk_push_context_dump", header: headerduktape.} +proc duk_debugger_attach*(ctx: DTContext; read_cb: duk_debug_read_function; + write_cb: duk_debug_write_function; + peek_cb: duk_debug_peek_function; + read_flush_cb: duk_debug_read_flush_function; + write_flush_cb: duk_debug_write_flush_function; + request_cb: duk_debug_request_function; + detached_cb: duk_debug_detached_function; udata: pointer) {. + stdcall, importc: "duk_debugger_attach", header: headerduktape.} +proc duk_debugger_detach*(ctx: DTContext) {.stdcall, + importc: "duk_debugger_detach", header: headerduktape.} +proc duk_debugger_cooperate*(ctx: DTContext) {.stdcall, + importc: "duk_debugger_cooperate", header: headerduktape.} +proc duk_debugger_notify*(ctx: DTContext; nvalues: duk_idx_t): duk_bool_t {. + stdcall, importc: "duk_debugger_notify", header: headerduktape.} +proc duk_debugger_pause*(ctx: DTContext) {.stdcall, + importc: "duk_debugger_pause", header: headerduktape.} +proc duk_get_now*(ctx: DTContext): duk_double_t {.stdcall, + importc: "duk_get_now", header: headerduktape.} +proc duk_time_to_components*(ctx: DTContext; timeval: duk_double_t; + comp: ptr duk_time_components) {.stdcall, + importc: "duk_time_to_components", header: headerduktape.} +proc duk_components_to_time*(ctx: DTContext; comp: ptr duk_time_components): duk_double_t {. + stdcall, importc: "duk_components_to_time", header: headerduktape.} +proc duk_create_heap_default*(): DTContext {.header: headerduktape.} +proc duk_eval_string*(ctx: DTContext, s: cstring) {.header: headerduktape.} +proc duk_pcompile_string*(ctx: DTContext, flags: duk_uint_t, s: cstring): duk_int_t {.header: headerduktape.} +proc duk_safe_to_string*(ctx: DTContext, idx: duk_idx_t): cstring {.header: headerduktape.} +# proc duk_to_string*(ctx: DTContext, index: cint): cstring {.header: headerduktape.} + +proc duk_peval_string*(ctx: DTContext, s: cstring): duk_int_t {.header: headerduktape.} + +## Extras + +proc duk_console_init*(ctx: DTContext, flags: duk_uint_t = 0) {.stdcall, +importc: "duk_console_init", header: headerconsole.} +proc duk_print_alert_init*(ctx: DTContext, flags: duk_uint_t = 0) {.stdcall, +importc: "duk_print_alert_init", header: headerprintalert.} + +type + DTCFunction* = duk_c_function +
@@ -3,25 +3,18 @@
# SQL QUERIES -const SQL_CREATE_DOCUMENTS_TABLE* = sql""" -CREATE TABLE documents ( -docid INTEGER PRIMARY KEY, -id TEXT UNIQUE NOT NULL, -data TEXT, -content_type TEXT, -binary INTEGER, -searchable INTEGER, -created TEXT, -modified TEXT) -""" const SQL_CREATE_INDEX_DOCUMENTS_DOCID* = sql"CREATE INDEX IF NOT EXISTS documents_docid ON documents(docid)" SQL_CREATE_INDEX_DOCUMENTS_ID* = sql"CREATE INDEX IF NOT EXISTS documents_id ON documents(id)" + SQL_CREATE_INDEX_SYSTEM_DOCUMENTS_DOCID* = sql"CREATE INDEX IF NOT EXISTS system_documents_docid ON documents(docid)" + SQL_CREATE_INDEX_SYSTEM_DOCUMENTS_ID* = sql"CREATE INDEX IF NOT EXISTS system_documents_id ON documents(id)" SQL_CREATE_INDEX_TAGS_DOCUMENT_ID* = sql"CREATE INDEX IF NOT EXISTS tags_document_id ON tags(document_id)" SQL_CREATE_INDEX_TAGS_TAG_ID* = sql"CREATE INDEX IF NOT EXISTS tags_tag_id ON tags(tag_id)" SQL_DROP_INDEX_DOCUMENTS_DOCID* = sql"DROP INDEX IF EXISTS documents_docid" SQL_DROP_INDEX_DOCUMENTS_ID* = sql"DROP INDEX IF EXISTS documents_id" + SQL_DROP_INDEX_SYSTEM_DOCUMENTS_DOCID* = sql"DROP INDEX IF EXISTS system_documents_docid" + SQL_DROP_INDEX_SYSTEM_DOCUMENTS_ID* = sql"DROP INDEX IF EXISTS system_documents_id" SQL_DROP_INDEX_TAGS_DOCUMENT_ID* = sql"DROP INDEX IF EXISTS tags_document_id" SQL_DROP_INDEX_TAGS_TAG_ID* = sql"DROP INDEX IF EXISTS tags_tag_id"@@ -31,6 +24,30 @@ SQL_REBUILD* = sql"INSERT INTO searchdata(searchdata) VALUES('rebuild')"
SQL_VACUUM* = sql"VACUUM" +const SQL_CREATE_DOCUMENTS_TABLE* = sql""" +CREATE TABLE documents ( +docid INTEGER PRIMARY KEY, +id TEXT UNIQUE NOT NULL, +data TEXT, +content_type TEXT, +binary INTEGER, +searchable INTEGER, +created TEXT, +modified TEXT) +""" + +const SQL_CREATE_SYSTEM_DOCUMENTS_TABLE* = sql""" +CREATE TABLE system_documents ( + docid INTEGER PRIMARY KEY, + id TEXT UNIQUE NOT NULL, + data TEXT, + content_type TEXT, + binary INTEGER, + created TEXT, + modified TEXT +) +""" + const SQL_CREATE_SEARCHDATA_TABLE* = sql""" CREATE VIRTUAL TABLE searchdata USING fts4( id TEXT UNIQUE NOT NULL,@@ -58,10 +75,14 @@ (version, total_documents)
VALUES (?, ?) """ +const SQL_UPDATE_VERSION* = sql""" +UPDATE info +SET version = ? +""" + const SQL_SELECT_INFO* = sql""" SELECT * FROM info """ - const SQL_SET_TOTAL_DOCS* = sql""" UPDATE info@@ -82,6 +103,12 @@ const SQL_INSERT_DOCUMENT* = sql"""
INSERT INTO documents (id, data, content_type, binary, searchable, created) VALUES (?, ?, ?, ?, ?, ?) +""" + +const SQL_INSERT_SYSTEM_DOCUMENT* = sql""" +INSERT INTO system_documents +(id, data, content_type, binary, created) +VALUES (?, ?, ?, ?, ?) """ const SQL_UPDATE_DOCUMENT* = sql"""@@ -94,6 +121,15 @@ modified = ?
WHERE id = ? """ +const SQL_UPDATE_SYSTEM_DOCUMENT* = sql""" +UPDATE system_documents +SET data = ?, +content_type = ?, +binary = ?, +modified = ? +WHERE id = ? +""" + const SQL_SET_DOCUMENT_MODIFIED* = sql""" UPDATE documents SET modified = ?@@ -154,6 +190,10 @@ WHERE documents.id = tags.document_id AND
tag_id = ? """ +const SQL_SELECT_SYSTEM_DOCUMENTS* = sql""" +SELECT * FROM system_documents +""" + const SQL_SELECT_DOCUMENT_IDS_BY_TAG* = sql""" SELECT id FROM documents, tags WHERE documents.id = tags.document_id AND@@ -181,6 +221,10 @@ const SQL_DELETE_DOCUMENTS_BY_TAG* = sql"""
DELETE FROM documents WHERE documents.id IN (SELECT document_id FROM tags WHERE tag_id = ?) +""" + +const SQL_DELETE_SYSTEM_DOCUMENTS* = sql""" +DELETE FROM system_documents """ const SQL_DELETE_SEARCHDATA_BY_TAG* = sql"""
@@ -9,8 +9,11 @@ cgi,
os, json, tables, + strtabs, base64, - jwt + asyncnet, + jwt, + sequtils import types, utils,@@ -18,7 +21,9 @@ api_v1,
api_v2, api_v3, api_v4, - api_v5 + api_v5, + api_v6, + api_v7 export api_v5@@ -45,8 +50,8 @@ proc handleCtrlC() {.noconv.} =
echo "" LOG.info("Exiting...") quit() - -template auth(uri: string): void = + +template auth(uri: string, jwt: JWT): void = let cfg = access[uri] if cfg.hasKey(reqMethod): LOG.debug("Authenticating: " & reqMethod & " " & uri)@@ -55,7 +60,7 @@ return resError(Http401, "Unauthorized - No token")
let token = req.headers["Authorization"].replace(peg"^ 'Bearer '", "") # Validate token try: - let jwt = token.toJwt() + jwt = token.toJwt() let parts = token.split(".") var sig = LS.auth["signature"].getStr discard verifySignature(parts[0] & "." & parts[1], decodeUrlSafe(parts[2]), sig)@@ -79,11 +84,37 @@ echo getCurrentExceptionMsg()
writeStackTrace() return resError(Http401, "Unauthorized - Invalid token") +proc isAllowed(resource, id, meth: string): bool = + if LS.config.kind != JObject or not LS.config.hasKey("resources"): + return true + var reqUri = "/" & resource & "/" & id + if reqUri[^1] == '/': + reqUri.removeSuffix({'/'}) + let parts = reqUri.split("/") + let ancestors = parts[1..parts.len-2] + var currentPath = "" + var currentPaths = "" + for p in ancestors: + currentPath &= "/" & p + currentPaths = currentPath & "/*" + if LS.config["resources"].hasKey(currentPaths) and LS.config["resources"][currentPaths].hasKey(meth) and LS.config["resources"][currentPaths][meth].hasKey("allowed"): + let allowed = LS.config["resources"][currentPaths][meth]["allowed"] + if (allowed == %false): + return false; + if LS.config["resources"].hasKey(reqUri) and LS.config["resources"][reqUri].hasKey(meth) and LS.config["resources"][reqUri][meth].hasKey("allowed"): + let allowed = LS.config["resources"][reqUri][meth]["allowed"] + if (allowed == %false): + return false + return true + proc processApiUrl(req: LSRequest, LS: LiteStore, info: ResourceInfo): LSResponse = var reqUri = "/" & info.resource & "/" & info.id if reqUri[^1] == '/': reqUri.removeSuffix({'/'}) let reqMethod = $req.reqMethod + var jwt: JWT + if not isAllowed(info.resource, info.id, reqMethod): + return resError(Http405, "Method not allowed: $1" % reqMethod) # Authentication/Authorization if LS.auth != newJNull(): var uri = reqUri@@ -91,12 +122,12 @@ let access = LS.auth["access"]
while true: # Match exact url if access.hasKey(uri): - auth(uri) + auth(uri, jwt) break # Match exact url adding /* (e.g. /docs would match also /docs/* in auth.json) elif uri[^1] != '*' and uri[^1] != '/': if access.hasKey(uri & "/*"): - auth(uri & "/*") + auth(uri & "/*", jwt) break var parts = uri.split("/") if parts[^1] == "*":@@ -109,9 +140,35 @@ else:
# If at the end of the URL, check generic URL uri = "/*" if access.hasKey(uri): - auth(uri) + auth(uri, jwt) break - if info.version == "v5": + if info.version == "v7": + if info.resource.match(peg"^docs / info / tags / indexes / stores$"): + var nReq = req + if jwt.signature.len != 0: + nReq.jwt = jwt + return api_v7.execute(nReq, LS, info.resource, info.id) + elif info.resource.match(peg"^dir$"): + if LS.directory.len > 0: + return api_v7.serveFile(req, LS, info.id) + else: + return resError(Http400, "Bad Request - Not serving any directory." % info.version) + else: + return resError(Http404, "Resource Not Found: $1" % info.resource) + if info.version == "v6": + if info.resource.match(peg"^docs / info / tags / indexes$"): + var nReq = req + if jwt.signature.len != 0: + nReq.jwt = jwt + return api_v6.execute(nReq, LS, info.resource, info.id) + elif info.resource.match(peg"^dir$"): + if LS.directory.len > 0: + return api_v6.serveFile(req, LS, info.id) + else: + return resError(Http400, "Bad Request - Not serving any directory." % info.version) + else: + return resError(Http404, "Resource Not Found: $1" % info.resource) + elif info.version == "v5": if info.resource.match(peg"^docs / info / tags / indexes$"): return api_v5.route(req, LS, info.resource, info.id) elif info.resource.match(peg"^dir$"):@@ -178,7 +235,7 @@ op
try: var info: ResourceInfo req.route peg"^\/?$": - info.version = "v5" + info.version = "v7" info.resource = "info" return req.processApiUrl(LS, info) req.route peg"^\/favicon.ico$":@@ -187,7 +244,7 @@ result.content = LS.favicon
result.headers = ctHeader("image/x-icon") return result req.route PEG_DEFAULT_URL: - info.version = "v5" + info.version = "v7" info.resource = matches[0] info.id = matches[1] return req.processApiUrl(LS, info)@@ -206,26 +263,58 @@ let e = getCurrentException()
let trace = e.getStackTrace() return resError(Http500, "Internal Server Error: $1" % getCurrentExceptionMsg(), trace) + +proc process*(req: LSRequest, LSDICT: OrderedTable[string, LiteStore]): LSResponse {.gcsafe.}= + var matches = @["", ""] + if req.url.path.find(PEG_STORE_URL, matches) != -1: + let id = matches[0] + let path = matches[1] + if path == "": + var info: ResourceInfo + info.version = "v7" + info.resource = "stores" + info.id = id + return req.processApiUrl(LS, info) + else: + var newReq = req + newReq.url.path = "/$1" % path + return newReq.process(LSDICT[id]) + else: + return req.process(LS) + setControlCHook(handleCtrlC) proc serve*(LS: LiteStore) = var server = newAsyncHttpServer() - proc handleHttpRequest(req: LSRequest): Future[void] {.async, gcsafe, closure.} = + proc handleHttpRequest(origReq: Request): Future[void] {.async, gcsafe, closure.} = + var client = origReq.client + var req = newLSRequest(origReq) + let address = client.getLocalAddr() + req.url.hostname = address[0] + req.url.port = $int(address[1]) LOG.info(getReqInfo(req).replace("$", "$$")) - let res = req.process(LS) - let areq = asynchttpserver.Request(req) - await areq.respond(res.code, res.content, res.headers) + let res = req.process(LSDICT) + var newReq = newRequest(req, client) + await newReq.respond(res.code, res.content, res.headers) echo(LS.appname & " v" & LS.appversion & " started on " & LS.address & ":" & $LS.port & ".") if LS.configFile != "": - echo "- Configuration File: " & LS.configFile + echo "- Configuration file: " & LS.configFile if LS.authFile != "": - echo "- Auth File: " & LS.authFile + echo "- Auth file: " & LS.authFile if LS.mount: echo "- Mirroring datastore changes to: " & LS.directory + elif LS.directory != "": + echo "- Serving directory: " & LS.directory if LS.readonly: echo "- Read-only mode" - echo "- Log Level: " & LS.loglevel - echo "- Store: " & LS.file + echo "- Log level: " & LS.loglevel + echo "- Stores:" + let storeIds = toSeq(LSDICT.keys) + for i in countdown(storeIds.len-1, 0): + let file = LSDICT[storeIds[i]].file + echo " - $1: $2" % [storeIds[i], file] + if LS.middleware.len > 0: + echo "- Middleware configured" if LS.auth != newJNull(): echo "- Authorization configured" asyncCheck server.serve(LS.port.Port, handleHttpRequest, LS.address)
@@ -1,8 +1,17 @@
import x_db_sqlite, asynchttpserver, + asyncnet, + uri, pegs, - json + json, + strtabs, + strutils, + sequtils, + nativesockets, + jwt, + uri, + tables import config@@ -34,6 +43,7 @@ jsonFilter*: string
jsonSelect*: seq[tuple[path: string, alias: string]] select*: seq[string] single*:bool + system*:bool limit*: int offset*: int orderby*: string@@ -74,45 +84,174 @@ port*: int
operation*: Operation config*: JsonNode configFile*: string + cliSettings*: JsonNode directory*: string + manageSystemData*: bool file*: string mount*: bool readonly*: bool appname*: string + middleware*: StringTableRef appversion*: string auth*: JsonNode authFile*: string favicon*:string loglevel*:string - LSRequest* = asynchttpserver.Request - LSResponse* = tuple[ - code: HttpCode, - content: string, - headers: HttpHeaders] + LSRequest* = object + reqMethod*: HttpMethod + headers*: HttpHeaders + protocol*: tuple[orig: string, major, minor: int] + url*: Uri + jwt*: JWT + hostname*: string + body*: string + LSResponse* = object + code*: HttpCode + content*: string + headers*: HttpHeaders ResourceInfo* = tuple[ resource: string, id: string, version: string ] +proc initLiteStore*(): LiteStore = + result.config = newJNull() + result.configFile = "" + result.cliSettings = newJObject() + result.directory = "" + result.manageSystemData = false + result.file = "" + result.mount = false + result.readonly = false + result.loglevel = "warn" + result.auth = newJNull() + result.authFile = "" + +proc httpMethod*(meth: string): HttpMethod = + case meth: + of "GET": + return HttpGet + of "POST": + return HttpPost + of "PUT": + return HttpPut + of "HEAD": + return HttpHead + of "PATCH": + return HttpPatch + of "OPTIONS": + return HttpOptions + of "DELETE": + return HttpDelete + else: + return HttpGet + + +proc `%`*(protocol: tuple[orig: string, major: int, minor: int]): JsonNode = + result = newJObject() + result["orig"] = %protocol.orig + result["major"] = %protocol.major + result["minor"] = %protocol.minor + +proc `%`*(code: HttpCode): JsonNode = + return %(int(code)) + +proc `%`*(table: Table[string, seq[string]]): JsonNode = + result = newJObject() + for k, v in table: + result[k] = %v + +proc `%`*(req: LSRequest): JsonNode = + result = newJObject() + result["method"] = %($req.reqMethod) + result["jwt"] = newJObject(); + if req.jwt.signature.len > 0: + result["jwt"]["header"] = %req.jwt.header + result["jwt"]["claims"] = %req.jwt.claims + result["headers"] = newJObject() + let headers = %req.headers + result["headers"] = newJObject() + for k, v in headers["table"].pairs: + result["headers"][k] = %join(v.mapIt(it.getStr), ", ") + result["protocol"] = %req.protocol.orig + result["hostname"] = %req.url.hostname + result["port"] = %req.url.port.parseInt + result["path"] = %req.url.path + result["query"] = %req.url.query + result["content"] = %req.body + +proc `%`*(res: LSResponse): JsonNode = + result = newJObject() + result["code"] = %($res.code) + result["headers"] = %res.headers + result["content"] = %res.content + +proc newLSResponse*(res: JsonNode): LSResponse = + result.code = HttpCode(res["code"].getInt) + result.content = $res["content"] + result.headers = newHttpHeaders() + for k, v in res["headers"].pairs: + result.headers[k] = v.getStr + +proc newLSRequest*(req: JsonNode): LSRequest = + result.reqMethod = httpMethod(req["method"].getStr) + result.headers = newHttpHeaders() + for k, v in req["headers"].pairs: + result.headers[k] = v.getStr + let protocol = req["protocol"].getStr + let parts = protocol.split("/") + let version = parts[1].split(".") + result.protocol = (orig: parts[0], major: version[0].parseInt, minor: version[1].parseInt) + result.url = initUri() + result.url.hostname = req["hostname"].getStr + result.url.port = req["port"].getStr + result.url.path = req["path"].getStr + result.url.query = req["query"].getStr + result.hostname = req["hostname"].getStr + result.body = req["content"].getStr + +proc newLSRequest*(req: Request): LSRequest = + result.reqMethod = req.reqMethod + result.headers = req.headers + result.protocol = req.protocol + result.url = req.url + result.hostname = req.hostname + result.body = req.body + +proc newRequest*(req: LSRequest, client: AsyncSocket): Request = + result.client = client + result.reqMethod = req.reqMethod + result.headers = req.headers + result.protocol = req.protocol + result.url = req.url + result.hostname = req.hostname + result.body = req.body + var PEG_TAG* {.threadvar.}: Peg PEG_USER_TAG* {.threadvar.}: Peg PEG_INDEX* {.threadvar}: Peg + PEG_STORE* {.threadvar}: Peg PEG_JSON_FIELD* {.threadvar.}: Peg PEG_DEFAULT_URL* {.threadvar.}: Peg + PEG_STORE_URL* {.threadvar.}: Peg PEG_URL* {.threadvar.}: Peg PEG_TAG = peg"""^\$? [a-zA-Z0-9_\-?~:.@#^!+]+$""" PEG_USER_TAG = peg"""^[a-zA-Z0-9_\-?~:.@#^!+]+$""" PEG_INDEX = peg"""^[a-zA-Z0-9_]+$""" +PEG_STORE = peg"""^[a-zA-Z0-9_]+$""" PEG_JSON_FIELD = peg"""'$' ('.' [a-z-A-Z0-9_]+)+""" -PEG_DEFAULT_URL = peg"""^\/{(docs / info / dir / tags / indexes)} (\/ {(.+)} / \/?)$""" +PEG_DEFAULT_URL = peg"""^\/{(docs / info / dir / tags / indexes / stores)} (\/ {(.+)} / \/?)$""" +PEG_STORE_URL = peg"""^\/stores \/ {([a-z0-9_]+)} (\/ {(.+)} / \/?)$""" PEG_URL = peg"""^\/({(v\d+)} \/) {([^\/]+)} (\/ {(.+)} / \/?)$""" # Initialize LiteStore var LS* {.threadvar.}: LiteStore +var LSDICT* {.threadvar.}: OrderedTable[string, LiteStore] var TAB_HEADERS* {.threadvar.}: array[0..2, (string, string)] +LSDICT = initOrderedTable[string, LiteStore]() LS.appversion = pkgVersion LS.appname = appname@@ -123,7 +262,10 @@ "Access-Control-Allow-Headers": "Authorization, Content-Type",
"Server": LS.appname & "/" & LS.appversion } -proc newQueryOptions*(): QueryOptions = - return QueryOptions(select: @["documents.id AS id", "documents.data AS data", "content_type", "binary", "searchable", "created", "modified"], - single: false, limit: 0, offset: 0, orderby: "", tags: "", search: "", folder: "", like: "", +proc newQueryOptions*(system = false): QueryOptions = + var select = @["documents.id AS id", "documents.data AS data", "content_type", "binary", "searchable", "created", "modified"] + if system: + select = @["system_documents.id AS id", "system_documents.data AS data", "content_type", "binary", "created", "modified"] + return QueryOptions(select: select, + single: false, limit: 0, offset: 0, orderby: "", tags: "", search: "", folder: "", like: "", system: system, createdAfter: "", createdBefore: "", modifiedAfter: "", modifiedBefore: "", jsonFilter: "", jsonSelect: newSeq[tuple[path: string, alias: string]](), tables: newSeq[string]())
@@ -60,6 +60,9 @@ raise newException(EInvalidTag, "Invalid Tag '$1'" % tag)
result = result & "AND " & doc_id_col & " IN (" & select_tagged & tag & "') " proc prepareSelectDocumentsQuery*(options: var QueryOptions): string = + var documents_table = "documents" + if options.system: + documents_table = "system_documents" var tables = options.tables result = "SELECT " if options.jsonFilter.len > 0 or options.jsonSelect.len > 0:@@ -84,23 +87,23 @@ if options.limit > 0:
innerSelect = innerSelect & "LIMIT " & $options.limit if options.offset > 0: innerSelect = innerSelect & " OFFSET " & $options.offset - tables = options.tables & @["documents"] + tables = options.tables & @[documents_table] result = result & options.select.join(", ") result = result & " FROM " & tables.join(", ") & " JOIN (" & innerSelect & ") as ranktable USING(docid) JOIN searchdata USING(docid) " result = result & "WHERE 1=1 " else: tables = options.tables & @["searchdata"] if options.jsonFilter != "": - options.select[0] = "COUNT(documents.docid)" - tables = tables & @["documents"] + options.select[0] = "COUNT($1.docid)" % documents_table + tables = tables & @[documents_table] result = result & options.select.join(", ") result = result & " FROM "&tables.join(", ")&" " result = result & "WHERE 1=1 " if options.jsonFilter != "": - result = result & "AND documents.id = searchdata.id " + result = result & "AND $1.id = searchdata.id " % documents_table options.orderby = "" else: - tables = options.tables & @["documents"] + tables = options.tables & @[documents_table] result = result & options.select.join(", ") result = result & " FROM "&tables.join(", ")&" WHERE 1=1 " if options.single:@@ -108,7 +111,7 @@ result = result & "AND id = ?"
var doc_id_col: string if options.tags.len > 0 or options.folder.len > 0: if options.jsonFilter.len > 0 or (options.search.len > 0 and options.select[0] != "COUNT(docid)"): - doc_id_col = "documents.id" + doc_id_col = "$1.id" % documents_table else: doc_id_col = "id" if options.createdAfter != "":@@ -306,12 +309,15 @@
proc resIndexNotFound*(id: string): LSResponse = resError(Http404, "Index '$1' not found." % id) +proc resStoreNotFound*(id: string): LSResponse = + resError(Http404, "Store '$1' not found." % id) + proc eWarn*() = var e = getCurrentException() LOG.warn(e.msg) LOG.debug(getStackTrace(e)) -proc validate*(req: Request, LS: LiteStore, resource: string, id: string, cb: proc(req: Request, LS: LiteStore, resource: string, id: string):LSResponse): LSResponse = +proc validate*(req: LSRequest, LS: LiteStore, resource: string, id: string, cb: proc(req: LSRequest, LS: LiteStore, resource: string, id: string):LSResponse): LSResponse = if req.reqMethod == HttpPost or req.reqMethod == HttpPut or req.reqMethod == HttpPatch: var ct = "" let body = req.body.strip
@@ -0,0 +1,3779 @@
+/* + * duk_config.h configuration header generated by genconfig.py. + * + * Git commit: 6001888049cb42656f8649db020e804bcdeca6a7 + * Git describe: v2.5.0 + * Git branch: master + * + * Supported platforms: + * - Mac OSX, iPhone, Darwin + * - Orbis + * - OpenBSD + * - Generic BSD + * - Atari ST TOS + * - AmigaOS + * - Durango (XboxOne) + * - Windows + * - Flashplayer (Crossbridge) + * - QNX + * - TI-Nspire + * - Emscripten + * - Android + * - Linux + * - Solaris + * - AIX + * - HPUX + * - Generic POSIX + * - Cygwin + * - Generic UNIX + * - Generic fallback + * + * Supported architectures: + * - x86 + * - x64 + * - x32 + * - ARM 32-bit + * - ARM 64-bit + * - MIPS 32-bit + * - MIPS 64-bit + * - PowerPC 32-bit + * - PowerPC 64-bit + * - SPARC 32-bit + * - SPARC 64-bit + * - RISC-V 32-bit + * - RISC-V 64-bit + * - SuperH + * - Motorola 68k + * - Emscripten + * - Generic + * + * Supported compilers: + * - Clang + * - GCC + * - MSVC + * - Emscripten + * - TinyC + * - VBCC + * - Bruce's C compiler + * - Generic + * + */ + +#if !defined(DUK_CONFIG_H_INCLUDED) +#define DUK_CONFIG_H_INCLUDED + +/* + * Intermediate helper defines + */ + +/* DLL build detection */ +/* not configured for DLL build */ +#undef DUK_F_DLL_BUILD + +/* Apple OSX, iOS */ +#if defined(__APPLE__) +#define DUK_F_APPLE +#endif + +/* FreeBSD */ +#if defined(__FreeBSD__) || defined(__FreeBSD) +#define DUK_F_FREEBSD +#endif + +/* Orbis (PS4) variant */ +#if defined(DUK_F_FREEBSD) && defined(__ORBIS__) +#define DUK_F_ORBIS +#endif + +/* OpenBSD */ +#if defined(__OpenBSD__) || defined(__OpenBSD) +#define DUK_F_OPENBSD +#endif + +/* NetBSD */ +#if defined(__NetBSD__) || defined(__NetBSD) +#define DUK_F_NETBSD +#endif + +/* BSD variant */ +#if defined(DUK_F_FREEBSD) || defined(DUK_F_NETBSD) || defined(DUK_F_OPENBSD) || \ + defined(__bsdi__) || defined(__DragonFly__) +#define DUK_F_BSD +#endif + +/* Atari ST TOS. __TOS__ defined by PureC. No platform define in VBCC + * apparently, so to use with VBCC user must define __TOS__ manually. + */ +#if defined(__TOS__) +#define DUK_F_TOS +#endif + +/* Motorola 68K. Not defined by VBCC, so user must define one of these + * manually when using VBCC. + */ +#if defined(__m68k__) || defined(M68000) || defined(__MC68K__) +#define DUK_F_M68K +#endif + +/* AmigaOS. Neither AMIGA nor __amigaos__ is defined on VBCC, so user must + * define 'AMIGA' manually when using VBCC. + */ +#if defined(AMIGA) || defined(__amigaos__) +#define DUK_F_AMIGAOS +#endif + +/* PowerPC */ +#if defined(__powerpc) || defined(__powerpc__) || defined(__PPC__) +#define DUK_F_PPC +#if defined(__PPC64__) || defined(__LP64__) || defined(_LP64) +#define DUK_F_PPC64 +#else +#define DUK_F_PPC32 +#endif +#endif + +/* Durango (Xbox One) */ +#if defined(_DURANGO) || defined(_XBOX_ONE) +#define DUK_F_DURANGO +#endif + +/* Windows, both 32-bit and 64-bit */ +#if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64) || \ + defined(__WIN32__) || defined(__TOS_WIN__) || defined(__WINDOWS__) +#define DUK_F_WINDOWS +#if defined(_WIN64) || defined(WIN64) +#define DUK_F_WIN64 +#else +#define DUK_F_WIN32 +#endif +#endif + +/* Flash player (e.g. Crossbridge) */ +#if defined(__FLASHPLAYER__) +#define DUK_F_FLASHPLAYER +#endif + +/* QNX */ +#if defined(__QNX__) +#define DUK_F_QNX +#endif + +/* TI-Nspire (using Ndless) */ +#if defined(_TINSPIRE) +#define DUK_F_TINSPIRE +#endif + +/* Emscripten (provided explicitly by user), improve if possible */ +#if defined(EMSCRIPTEN) +#define DUK_F_EMSCRIPTEN +#endif + +/* BCC (Bruce's C compiler): this is a "torture target" for compilation */ +#if defined(__BCC__) || defined(__BCC_VERSION__) +#define DUK_F_BCC +#endif + +#if defined(ANDROID) || defined(__ANDROID__) +#define DUK_F_ANDROID +#endif + +/* Linux */ +#if defined(__linux) || defined(__linux__) || defined(linux) +#define DUK_F_LINUX +#endif + +/* illumos / Solaris */ +#if defined(__sun) && defined(__SVR4) +#define DUK_F_SUN +#if defined(__SUNPRO_C) && (__SUNPRO_C < 0x550) +#define DUK_F_OLD_SOLARIS +/* Defines _ILP32 / _LP64 required by DUK_F_X86/DUK_F_X64. Platforms + * are processed before architectures, so this happens before the + * DUK_F_X86/DUK_F_X64 detection is emitted. + */ +#include <sys/isa_defs.h> +#endif +#endif + +/* AIX */ +#if defined(_AIX) +/* defined(__xlc__) || defined(__IBMC__): works but too wide */ +#define DUK_F_AIX +#endif + +/* HPUX */ +#if defined(__hpux) +#define DUK_F_HPUX +#if defined(__ia64) +#define DUK_F_HPUX_ITANIUM +#endif +#endif + +/* POSIX */ +#if defined(__posix) +#define DUK_F_POSIX +#endif + +/* Cygwin */ +#if defined(__CYGWIN__) +#define DUK_F_CYGWIN +#endif + +/* Generic Unix (includes Cygwin) */ +#if defined(__unix) || defined(__unix__) || defined(unix) || \ + defined(DUK_F_LINUX) || defined(DUK_F_BSD) +#define DUK_F_UNIX +#endif + +/* Intel x86 (32-bit), x64 (64-bit) or x32 (64-bit but 32-bit pointers), + * define only one of DUK_F_X86, DUK_F_X64, DUK_F_X32. + * https://sites.google.com/site/x32abi/ + * + * With DUK_F_OLD_SOLARIS the <sys/isa_defs.h> header must be included + * before this. + */ +#if defined(__amd64__) || defined(__amd64) || \ + defined(__x86_64__) || defined(__x86_64) || \ + defined(_M_X64) || defined(_M_AMD64) +#if defined(__ILP32__) || defined(_ILP32) +#define DUK_F_X32 +#else +#define DUK_F_X64 +#endif +#elif defined(i386) || defined(__i386) || defined(__i386__) || \ + defined(__i486__) || defined(__i586__) || defined(__i686__) || \ + defined(__IA32__) || defined(_M_IX86) || defined(__X86__) || \ + defined(_X86_) || defined(__THW_INTEL__) || defined(__I86__) +#if defined(__LP64__) || defined(_LP64) +/* This should not really happen, but would indicate x64. */ +#define DUK_F_X64 +#else +#define DUK_F_X86 +#endif +#endif + +/* ARM */ +#if defined(__arm__) || defined(__thumb__) || defined(_ARM) || defined(_M_ARM) || defined(_M_ARM64) || defined(__aarch64__) +#define DUK_F_ARM +#if defined(__LP64__) || defined(_LP64) || defined(__arm64) || defined(__arm64__) || defined(_M_ARM64) || defined(__aarch64__) +#define DUK_F_ARM64 +#else +#define DUK_F_ARM32 +#endif +#endif + +/* MIPS. Related defines: __MIPSEB__, __MIPSEL__, __mips_isa_rev, __LP64__ */ +#if defined(__mips__) || defined(mips) || defined(_MIPS_ISA) || \ + defined(_R3000) || defined(_R4000) || defined(_R5900) || \ + defined(_MIPS_ISA_MIPS1) || defined(_MIPS_ISA_MIPS2) || \ + defined(_MIPS_ISA_MIPS3) || defined(_MIPS_ISA_MIPS4) || \ + defined(__mips) || defined(__MIPS__) +#define DUK_F_MIPS +#if defined(__LP64__) || defined(_LP64) || defined(__mips64) || \ + defined(__mips64__) || defined(__mips_n64) +#define DUK_F_MIPS64 +#else +#define DUK_F_MIPS32 +#endif +#endif + +/* SPARC */ +#if defined(sparc) || defined(__sparc) || defined(__sparc__) +#define DUK_F_SPARC +#if defined(__LP64__) || defined(_LP64) +#define DUK_F_SPARC64 +#else +#define DUK_F_SPARC32 +#endif +#endif + +/* RISC-V, https://github.com/riscv/riscv-toolchain-conventions#cc-preprocessor-definitions */ +#if defined(__riscv) +#define DUK_F_RISCV +#if defined(__riscv_xlen) +#if (__riscv_xlen == 32) +#define DUK_F_RISCV32 +#elif (__riscv_xlen == 64) +#define DUK_F_RISCV64 +#else +#error __riscv_xlen has unsupported value (not 32 or 64) +#endif +#else +#error __riscv defined without __riscv_xlen +#endif +#endif /* __riscv */ + +/* SuperH */ +#if defined(__sh__) || \ + defined(__sh1__) || defined(__SH1__) || \ + defined(__sh2__) || defined(__SH2__) || \ + defined(__sh3__) || defined(__SH3__) || \ + defined(__sh4__) || defined(__SH4__) || \ + defined(__sh5__) || defined(__SH5__) +#define DUK_F_SUPERH +#endif + +/* Clang */ +#if defined(__clang__) +#define DUK_F_CLANG +#endif + +/* C++ */ +#undef DUK_F_CPP +#if defined(__cplusplus) +#define DUK_F_CPP +#endif + +/* C99 or above */ +#undef DUK_F_C99 +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +#define DUK_F_C99 +#endif + +/* C++11 or above */ +#undef DUK_F_CPP11 +#if defined(__cplusplus) && (__cplusplus >= 201103L) +#define DUK_F_CPP11 +#endif + +/* GCC. Clang also defines __GNUC__ so don't detect GCC if using Clang. */ +#if defined(__GNUC__) && !defined(__clang__) && !defined(DUK_F_CLANG) +#define DUK_F_GCC +#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) +/* Convenience, e.g. gcc 4.5.1 == 40501; http://stackoverflow.com/questions/6031819/emulating-gccs-builtin-unreachable */ +#define DUK_F_GCC_VERSION (__GNUC__ * 10000L + __GNUC_MINOR__ * 100L + __GNUC_PATCHLEVEL__) +#else +#error cannot figure out gcc version +#endif +#endif + +/* MinGW. Also GCC flags (DUK_F_GCC) are enabled now. */ +#if defined(__MINGW32__) || defined(__MINGW64__) +#define DUK_F_MINGW +#endif + +/* MSVC */ +#if defined(_MSC_VER) +/* MSVC preprocessor defines: http://msdn.microsoft.com/en-us/library/b0084kay.aspx + * _MSC_FULL_VER includes the build number, but it has at least two formats, see e.g. + * BOOST_MSVC_FULL_VER in http://www.boost.org/doc/libs/1_52_0/boost/config/compiler/visualc.hpp + */ +#define DUK_F_MSVC +#if defined(_MSC_FULL_VER) +#if (_MSC_FULL_VER > 100000000) +#define DUK_F_MSVC_FULL_VER _MSC_FULL_VER +#else +#define DUK_F_MSCV_FULL_VER (_MSC_FULL_VER * 10) +#endif +#endif +#endif /* _MSC_VER */ + +/* TinyC */ +#if defined(__TINYC__) +/* http://bellard.org/tcc/tcc-doc.html#SEC9 */ +#define DUK_F_TINYC +#endif + +/* VBCC */ +#if defined(__VBCC__) +#define DUK_F_VBCC +#endif + +/* Atari Mint */ +#if defined(__MINT__) +#define DUK_F_MINT +#endif + +/* + * Platform autodetection + */ + +/* Workaround for older C++ compilers before including <inttypes.h>, + * see e.g.: https://sourceware.org/bugzilla/show_bug.cgi?id=15366 + */ +#if defined(__cplusplus) && !defined(__STDC_LIMIT_MACROS) +#define __STDC_LIMIT_MACROS +#endif +#if defined(__cplusplus) && !defined(__STDC_CONSTANT_MACROS) +#define __STDC_CONSTANT_MACROS +#endif + +#if defined(DUK_F_APPLE) +/* --- Mac OSX, iPhone, Darwin --- */ +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME +#include <TargetConditionals.h> +#include <architecture/byte_order.h> +#include <sys/param.h> +#include <sys/time.h> +#include <time.h> + +/* http://stackoverflow.com/questions/5919996/how-to-detect-reliably-mac-os-x-ios-linux-windows-in-c-preprocessor */ +#if TARGET_IPHONE_SIMULATOR +#define DUK_USE_OS_STRING "iphone-sim" +#elif TARGET_OS_IPHONE +#define DUK_USE_OS_STRING "iphone" +#elif TARGET_OS_MAC +#define DUK_USE_OS_STRING "osx" +#else +#define DUK_USE_OS_STRING "osx-unknown" +#endif + +/* Use _setjmp() on Apple by default, see GH-55. */ +#define DUK_JMPBUF_TYPE jmp_buf +#define DUK_SETJMP(jb) _setjmp((jb)) +#define DUK_LONGJMP(jb) _longjmp((jb), 1) +#elif defined(DUK_F_ORBIS) +/* --- Orbis --- */ +/* Orbis = PS4 */ +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_S +/* no parsing (not an error) */ +#define DUK_USE_DATE_FMT_STRFTIME +#include <sys/types.h> +#include <machine/endian.h> +#include <sys/param.h> +#include <sys/time.h> +#include <time.h> + +#define DUK_USE_OS_STRING "orbis" +#elif defined(DUK_F_OPENBSD) +/* --- OpenBSD --- */ +/* http://www.monkey.org/openbsd/archive/ports/0401/msg00089.html */ +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME +#include <sys/types.h> +#include <sys/endian.h> +#include <sys/param.h> +#include <sys/time.h> +#include <time.h> + +#define DUK_USE_OS_STRING "openbsd" +#elif defined(DUK_F_BSD) +/* --- Generic BSD --- */ +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME +#include <sys/types.h> +#include <sys/endian.h> +#include <sys/param.h> +#include <sys/time.h> +#include <time.h> + +#define DUK_USE_OS_STRING "bsd" +#elif defined(DUK_F_TOS) +/* --- Atari ST TOS --- */ +#define DUK_USE_DATE_NOW_TIME +#define DUK_USE_DATE_TZO_GMTIME +/* no parsing (not an error) */ +#define DUK_USE_DATE_FMT_STRFTIME +#include <time.h> + +#define DUK_USE_OS_STRING "tos" + +/* TOS on M68K is always big endian. */ +#if !defined(DUK_USE_BYTEORDER) && defined(DUK_F_M68K) +#define DUK_USE_BYTEORDER 3 +#endif +#elif defined(DUK_F_AMIGAOS) +/* --- AmigaOS --- */ +#if defined(DUK_F_M68K) +/* AmigaOS on M68k */ +#define DUK_USE_DATE_NOW_TIME +#define DUK_USE_DATE_TZO_GMTIME +/* no parsing (not an error) */ +#define DUK_USE_DATE_FMT_STRFTIME +#include <time.h> +#elif defined(DUK_F_PPC) +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME +#include <time.h> +#if !defined(UINTPTR_MAX) +#define UINTPTR_MAX UINT_MAX +#endif +#else +#error AmigaOS but not M68K/PPC, not supported now +#endif + +#define DUK_USE_OS_STRING "amigaos" + +/* AmigaOS on M68K or PPC is always big endian. */ +#if !defined(DUK_USE_BYTEORDER) && (defined(DUK_F_M68K) || defined(DUK_F_PPC)) +#define DUK_USE_BYTEORDER 3 +#endif +#elif defined(DUK_F_DURANGO) +/* --- Durango (XboxOne) --- */ +/* Durango = XboxOne + * Configuration is nearly identical to Windows, except for + * DUK_USE_DATE_TZO_WINDOWS. + */ + +/* Initial fix: disable secure CRT related warnings when compiling Duktape + * itself (must be defined before including Windows headers). Don't define + * for user code including duktape.h. + */ +#if defined(DUK_COMPILING_DUKTAPE) && !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +/* MSVC does not have sys/param.h */ +#define DUK_USE_DATE_NOW_WINDOWS +#define DUK_USE_DATE_TZO_WINDOWS_NO_DST +/* Note: PRS and FMT are intentionally left undefined for now. This means + * there is no platform specific date parsing/formatting but there is still + * the ISO 8601 standard format. + */ +#if defined(DUK_COMPILING_DUKTAPE) +/* Only include when compiling Duktape to avoid polluting application build + * with a lot of unnecessary defines. + */ +#include <windows.h> +#endif + +#define DUK_USE_OS_STRING "durango" + +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 1 +#endif +#elif defined(DUK_F_WINDOWS) +/* --- Windows --- */ +/* Windows version can't obviously be determined at compile time, + * but _WIN32_WINNT indicates the minimum version targeted: + * - https://msdn.microsoft.com/en-us/library/6sehtctf.aspx + */ + +/* Initial fix: disable secure CRT related warnings when compiling Duktape + * itself (must be defined before including Windows headers). Don't define + * for user code including duktape.h. + */ +#if defined(DUK_COMPILING_DUKTAPE) && !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +/* Windows 32-bit and 64-bit are currently the same. */ +/* MSVC does not have sys/param.h */ + +#if defined(DUK_COMPILING_DUKTAPE) +/* Only include when compiling Duktape to avoid polluting application build + * with a lot of unnecessary defines. + */ +#include <windows.h> +#endif + +/* GetSystemTimePreciseAsFileTime() available from Windows 8: + * https://msdn.microsoft.com/en-us/library/windows/desktop/hh706895(v=vs.85).aspx + */ +#if defined(DUK_USE_DATE_NOW_WINDOWS_SUBMS) || defined(DUK_USE_DATE_NOW_WINDOWS) +/* User forced provider. */ +#else +#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0602) +#define DUK_USE_DATE_NOW_WINDOWS_SUBMS +#else +#define DUK_USE_DATE_NOW_WINDOWS +#endif +#endif + +#define DUK_USE_DATE_TZO_WINDOWS + +/* Note: PRS and FMT are intentionally left undefined for now. This means + * there is no platform specific date parsing/formatting but there is still + * the ISO 8601 standard format. + */ + +/* QueryPerformanceCounter() may go backwards in Windows XP, so enable for + * Vista and later: https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).aspx#qpc_support_in_windows_versions + */ +#if !defined(DUK_USE_GET_MONOTONIC_TIME_WINDOWS_QPC) && \ + defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600) +#define DUK_USE_GET_MONOTONIC_TIME_WINDOWS_QPC +#endif + +#define DUK_USE_OS_STRING "windows" + +/* On Windows, assume we're little endian. Even Itanium which has a + * configurable endianness runs little endian in Windows. + */ +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 1 +#endif +#elif defined(DUK_F_FLASHPLAYER) +/* --- Flashplayer (Crossbridge) --- */ +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME +#include <endian.h> +#include <sys/param.h> +#include <sys/time.h> +#include <time.h> + +#define DUK_USE_OS_STRING "flashplayer" + +#if !defined(DUK_USE_BYTEORDER) && defined(DUK_F_FLASHPLAYER) +#define DUK_USE_BYTEORDER 1 +#endif +#elif defined(DUK_F_QNX) +/* --- QNX --- */ +#if defined(DUK_F_QNX) && defined(DUK_COMPILING_DUKTAPE) +/* See: /opt/qnx650/target/qnx6/usr/include/sys/platform.h */ +#define _XOPEN_SOURCE 600 +#define _POSIX_C_SOURCE 200112L +#endif + +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME +#include <sys/types.h> +#include <sys/param.h> +#include <sys/time.h> +#include <time.h> + +#define DUK_USE_OS_STRING "qnx" +#elif defined(DUK_F_TINSPIRE) +/* --- TI-Nspire --- */ +#if defined(DUK_COMPILING_DUKTAPE) && !defined(_XOPEN_SOURCE) +#define _XOPEN_SOURCE /* e.g. strptime */ +#endif + +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME +#include <sys/types.h> +#include <sys/param.h> +#include <sys/time.h> +#include <time.h> + +#define DUK_USE_OS_STRING "tinspire" +#elif defined(DUK_F_EMSCRIPTEN) +/* --- Emscripten --- */ +#if defined(DUK_COMPILING_DUKTAPE) +#if !defined(_POSIX_C_SOURCE) +#define _POSIX_C_SOURCE 200809L +#endif +#if !defined(_GNU_SOURCE) +#define _GNU_SOURCE /* e.g. getdate_r */ +#endif +#if !defined(_XOPEN_SOURCE) +#define _XOPEN_SOURCE /* e.g. strptime */ +#endif +#endif /* DUK_COMPILING_DUKTAPE */ + +#include <sys/types.h> +#if defined(DUK_F_BCC) +/* no endian.h */ +#else +#include <endian.h> +#endif /* DUK_F_BCC */ +#include <sys/param.h> +#include <sys/time.h> +#include <time.h> +#include <stdint.h> + +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME + +#define DUK_USE_OS_STRING "emscripten" +#elif defined(DUK_F_ANDROID) +/* --- Android --- */ +#if defined(DUK_COMPILING_DUKTAPE) +#if !defined(_POSIX_C_SOURCE) +#define _POSIX_C_SOURCE 200809L +#endif +#if !defined(_GNU_SOURCE) +#define _GNU_SOURCE /* e.g. getdate_r */ +#endif +#if !defined(_XOPEN_SOURCE) +#define _XOPEN_SOURCE /* e.g. strptime */ +#endif +#endif /* DUK_COMPILING_DUKTAPE */ + +#include <sys/types.h> +#if defined(DUK_F_BCC) +/* no endian.h or stdint.h */ +#else +#include <endian.h> +#include <stdint.h> +#endif /* DUK_F_BCC */ +#include <sys/param.h> +#include <sys/time.h> +#include <time.h> + +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME + +#if 0 /* XXX: safe condition? */ +#define DUK_USE_GET_MONOTONIC_TIME_CLOCK_GETTIME +#endif + +#define DUK_USE_OS_STRING "android" +#elif defined(DUK_F_LINUX) +/* --- Linux --- */ +#if defined(DUK_COMPILING_DUKTAPE) +#if !defined(_POSIX_C_SOURCE) +#define _POSIX_C_SOURCE 200809L +#endif +#if !defined(_GNU_SOURCE) +#define _GNU_SOURCE /* e.g. getdate_r */ +#endif +#if !defined(_XOPEN_SOURCE) +#define _XOPEN_SOURCE /* e.g. strptime */ +#endif +#endif /* DUK_COMPILING_DUKTAPE */ + +#include <sys/types.h> +#if defined(DUK_F_BCC) +/* no endian.h or stdint.h */ +#else +#include <endian.h> +#include <stdint.h> +#endif /* DUK_F_BCC */ +#include <sys/param.h> +#include <sys/time.h> +#include <time.h> + +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME + +#if 0 /* XXX: safe condition? */ +#define DUK_USE_GET_MONOTONIC_TIME_CLOCK_GETTIME +#endif + +#define DUK_USE_OS_STRING "linux" +#elif defined(DUK_F_SUN) +/* --- Solaris --- */ +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME + +#include <sys/types.h> +#if defined(DUK_F_OLD_SOLARIS) +/* Old Solaris with no endian.h, stdint.h */ +#define DUK_F_NO_STDINT_H +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 3 +#endif +#else /* DUK_F_OLD_SOLARIS */ +#include <sys/param.h> +#endif /* DUK_F_OLD_SOLARIS */ + +#include <sys/param.h> +#include <sys/time.h> +#include <time.h> + +#define DUK_USE_OS_STRING "solaris" +#elif defined(DUK_F_AIX) +/* --- AIX --- */ +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 3 +#endif +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME +#include <sys/param.h> +#include <sys/time.h> +#include <time.h> + +#define DUK_USE_OS_STRING "aix" +#elif defined(DUK_F_HPUX) +/* --- HPUX --- */ +#define DUK_F_NO_STDINT_H +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 3 +#endif +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME +#include <sys/param.h> +#include <sys/time.h> +#include <time.h> + +#define DUK_USE_OS_STRING "hpux" +#elif defined(DUK_F_POSIX) +/* --- Generic POSIX --- */ +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME +#include <sys/types.h> +#include <endian.h> +#include <sys/param.h> +#include <sys/time.h> +#include <time.h> + +#define DUK_USE_OS_STRING "posix" +#elif defined(DUK_F_CYGWIN) +/* --- Cygwin --- */ +/* don't use strptime() for now */ +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_FMT_STRFTIME +#include <sys/types.h> +#include <endian.h> +#include <sys/param.h> +#include <sys/time.h> +#include <time.h> + +#define DUK_JMPBUF_TYPE jmp_buf +#define DUK_SETJMP(jb) _setjmp((jb)) +#define DUK_LONGJMP(jb) _longjmp((jb), 1) + +#define DUK_USE_OS_STRING "windows" +#elif defined(DUK_F_UNIX) +/* --- Generic UNIX --- */ +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME +#include <time.h> +#include <sys/time.h> +#define DUK_USE_OS_STRING "unknown" +#else +/* --- Generic fallback --- */ +/* The most portable current time provider is time(), but it only has a + * one second resolution. + */ +#define DUK_USE_DATE_NOW_TIME + +/* The most portable way to figure out local time offset is gmtime(), + * but it's not thread safe so use with caution. + */ +#define DUK_USE_DATE_TZO_GMTIME + +/* Avoid custom date parsing and formatting for portability. */ +#undef DUK_USE_DATE_PRS_STRPTIME +#undef DUK_USE_DATE_FMT_STRFTIME + +/* Rely on C89 headers only; time.h must be here. */ +#include <time.h> + +#define DUK_USE_OS_STRING "unknown" +#endif /* autodetect platform */ + +/* Shared includes: C89 */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> /* varargs */ +#include <setjmp.h> +#include <stddef.h> /* e.g. ptrdiff_t */ +#include <math.h> +#include <limits.h> + +/* date.h is omitted, and included per platform */ + +/* Shared includes: stdint.h is C99 */ +#if defined(DUK_F_NO_STDINT_H) +/* stdint.h not available */ +#else +/* Technically C99 (C++11) but found in many systems. On some systems + * __STDC_LIMIT_MACROS and __STDC_CONSTANT_MACROS must be defined before + * including stdint.h (see above). + */ +#include <stdint.h> +#endif + +/* <exception> is only included if needed, based on DUK_USE_xxx flags. */ + +/* + * Architecture autodetection + */ + +#if defined(DUK_F_X86) +/* --- x86 --- */ +#define DUK_USE_ARCH_STRING "x86" +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 1 +#endif + +#define DUK_USE_PACKED_TVAL + +/* FreeBSD, -m32, and clang prior to 5.0 has union aliasing issues which + * break duk_tval copying. Disable packed duk_tval automatically. + */ +#if defined(DUK_F_FREEBSD) && defined(DUK_F_X86) && \ + defined(__clang__) && defined(__clang_major__) && (__clang_major__ < 5) +#undef DUK_USE_PACKED_TVAL +#endif +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_X64) +/* --- x64 --- */ +#define DUK_USE_ARCH_STRING "x64" +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 1 +#endif +#undef DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_X32) +/* --- x32 --- */ +#define DUK_USE_ARCH_STRING "x32" +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 1 +#endif +#define DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_ARM32) +/* --- ARM 32-bit --- */ +#define DUK_USE_ARCH_STRING "arm32" +/* Byte order varies, so rely on autodetect. */ +#define DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_ARM64) +/* --- ARM 64-bit --- */ +#define DUK_USE_ARCH_STRING "arm64" +/* Byte order varies, so rely on autodetect. */ +#undef DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_MIPS32) +/* --- MIPS 32-bit --- */ +#define DUK_USE_ARCH_STRING "mips32" +/* MIPS byte order varies so rely on autodetection. */ +#define DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_MIPS64) +/* --- MIPS 64-bit --- */ +#define DUK_USE_ARCH_STRING "mips64" +/* MIPS byte order varies so rely on autodetection. */ +#undef DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_PPC32) +/* --- PowerPC 32-bit --- */ +#define DUK_USE_ARCH_STRING "ppc32" +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 3 +#endif +#define DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_PPC64) +/* --- PowerPC 64-bit --- */ +#define DUK_USE_ARCH_STRING "ppc64" +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 3 +#endif +#undef DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_SPARC32) +/* --- SPARC 32-bit --- */ +#define DUK_USE_ARCH_STRING "sparc32" +/* SPARC byte order varies so rely on autodetection. */ +#define DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_SPARC64) +/* --- SPARC 64-bit --- */ +#define DUK_USE_ARCH_STRING "sparc64" +/* SPARC byte order varies so rely on autodetection. */ +#undef DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_RISCV32) +/* --- RISC-V 32-bit --- */ +#define DUK_USE_ARCH_STRING "riscv32" +#define DUK_USE_BYTEORDER 1 +#define DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_RISCV64) +/* --- RISC-V 64-bit --- */ +#define DUK_USE_ARCH_STRING "riscv64" +#define DUK_USE_BYTEORDER 1 +#undef DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_SUPERH) +/* --- SuperH --- */ +#define DUK_USE_ARCH_STRING "sh" +/* Byte order varies, rely on autodetection. */ +#define DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_M68K) +/* --- Motorola 68k --- */ +#define DUK_USE_ARCH_STRING "m68k" +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 3 +#endif +#define DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_EMSCRIPTEN) +/* --- Emscripten --- */ +#define DUK_USE_ARCH_STRING "emscripten" +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 1 +#endif +#undef DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#else +/* --- Generic --- */ +/* These are necessary wild guesses. */ +#define DUK_USE_ARCH_STRING "generic" +/* Rely on autodetection for byte order, alignment, and packed tval. */ +#endif /* autodetect architecture */ + +/* + * Compiler autodetection + */ + +#if defined(DUK_F_CLANG) +/* --- Clang --- */ +#if defined(DUK_F_C99) || defined(DUK_F_CPP11) +/* C99 / C++11 and above: rely on va_copy() which is required. */ +#define DUK_VA_COPY(dest,src) va_copy(dest,src) +#else +/* Clang: assume we have __va_copy() in non-C99 mode. */ +#define DUK_VA_COPY(dest,src) __va_copy(dest,src) +#endif + +#define DUK_NORETURN(decl) decl __attribute__((noreturn)) + +#if defined(__clang__) && defined(__has_builtin) +#if __has_builtin(__builtin_unreachable) +#define DUK_UNREACHABLE() do { __builtin_unreachable(); } while (0) +#endif +#endif + +#define DUK_USE_BRANCH_HINTS +#define DUK_LIKELY(x) __builtin_expect((x), 1) +#define DUK_UNLIKELY(x) __builtin_expect((x), 0) +#if defined(__clang__) && defined(__has_builtin) +#if __has_builtin(__builtin_unpredictable) +#define DUK_UNPREDICTABLE(x) __builtin_unpredictable((x)) +#endif +#endif + +#if defined(DUK_F_C99) || defined(DUK_F_CPP11) +#define DUK_NOINLINE __attribute__((noinline)) +#define DUK_INLINE inline +#define DUK_ALWAYS_INLINE inline __attribute__((always_inline)) +#endif + +/* DUK_HOT */ +/* DUK_COLD */ + +#if defined(DUK_F_DLL_BUILD) && defined(DUK_F_WINDOWS) +/* MSVC dllexport/dllimport: appropriate __declspec depends on whether we're + * compiling Duktape or the application. + */ +#if defined(DUK_COMPILING_DUKTAPE) +#define DUK_EXTERNAL_DECL extern __declspec(dllexport) +#define DUK_EXTERNAL __declspec(dllexport) +#else +#define DUK_EXTERNAL_DECL extern __declspec(dllimport) +#define DUK_EXTERNAL should_not_happen +#endif +#if defined(DUK_SINGLE_FILE) +#define DUK_INTERNAL_DECL static +#define DUK_INTERNAL static +#else +#define DUK_INTERNAL_DECL extern +#define DUK_INTERNAL /*empty*/ +#endif +#define DUK_LOCAL_DECL static +#define DUK_LOCAL static +#else +#define DUK_EXTERNAL_DECL __attribute__ ((visibility("default"))) extern +#define DUK_EXTERNAL __attribute__ ((visibility("default"))) +#if defined(DUK_SINGLE_FILE) +#if (defined(DUK_F_GCC_VERSION) && DUK_F_GCC_VERSION >= 30101) || defined(DUK_F_CLANG) +/* Minimize warnings for unused internal functions with GCC >= 3.1.1 and + * Clang. Based on documentation it should suffice to have the attribute + * in the declaration only, but in practice some warnings are generated unless + * the attribute is also applied to the definition. + */ +#define DUK_INTERNAL_DECL static __attribute__ ((unused)) +#define DUK_INTERNAL static __attribute__ ((unused)) +#else +#define DUK_INTERNAL_DECL static +#define DUK_INTERNAL static +#endif +#else +#if (defined(DUK_F_GCC_VERSION) && DUK_F_GCC_VERSION >= 30101) || defined(DUK_F_CLANG) +#define DUK_INTERNAL_DECL __attribute__ ((visibility("hidden"))) __attribute__ ((unused)) extern +#define DUK_INTERNAL __attribute__ ((visibility("hidden"))) __attribute__ ((unused)) +#else +#define DUK_INTERNAL_DECL __attribute__ ((visibility("hidden"))) extern +#define DUK_INTERNAL __attribute__ ((visibility("hidden"))) +#endif +#endif +#define DUK_LOCAL_DECL static +#define DUK_LOCAL static +#endif + +#if defined(DUK_F_CPP) +#define DUK_USE_COMPILER_STRING "clang" +#else +#define DUK_USE_COMPILER_STRING "clang" +#endif + +#undef DUK_USE_VARIADIC_MACROS +#if defined(DUK_F_C99) || defined(DUK_F_CPP11) +#define DUK_USE_VARIADIC_MACROS +#endif + +#define DUK_USE_UNION_INITIALIZERS + +#undef DUK_USE_FLEX_C99 +#undef DUK_USE_FLEX_ZEROSIZE +#undef DUK_USE_FLEX_ONESIZE +#if defined(DUK_F_C99) +#define DUK_USE_FLEX_C99 +#else +#define DUK_USE_FLEX_ZEROSIZE +#endif + +#define DUK_USE_CLANG_PRAGMAS +#define DUK_USE_PACK_CLANG_ATTR + +#if defined(__clang__) && defined(__has_builtin) +#if __has_builtin(__builtin_bswap64) +#define DUK_BSWAP64(x) ((duk_uint64_t) __builtin_bswap64((duk_uint64_t) (x))) +#endif +#if __has_builtin(__builtin_bswap32) +#define DUK_BSWAP32(x) ((duk_uint32_t) __builtin_bswap32((duk_uint32_t) (x))) +#endif +#if __has_builtin(__builtin_bswap16) +#define DUK_BSWAP16(x) ((duk_uint16_t) __builtin_bswap16((duk_uint16_t) (x))) +#endif +#endif +#elif defined(DUK_F_GCC) +/* --- GCC --- */ +#if defined(DUK_F_C99) || defined(DUK_F_CPP11) +/* C99 / C++11 and above: rely on va_copy() which is required. */ +#define DUK_VA_COPY(dest,src) va_copy(dest,src) +#else +/* GCC: assume we have __va_copy() in non-C99 mode. */ +#define DUK_VA_COPY(dest,src) __va_copy(dest,src) +#endif + +#if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 20500L) && (DUK_F_GCC_VERSION < 50000L) +/* Since gcc-2.5. + * + * Disabled temporarily in GCC 5+ because of an unresolved noreturn-related + * issue: https://github.com/svaarala/duktape/issues/2155. + */ +#define DUK_NORETURN(decl) decl __attribute__((noreturn)) +#endif + +#if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 40500L) +/* Since gcc-4.5. */ +#define DUK_UNREACHABLE() do { __builtin_unreachable(); } while (0) +#endif + +#define DUK_USE_BRANCH_HINTS +#if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 40500L) +/* GCC: test not very accurate; enable only in relatively recent builds + * because of bugs in gcc-4.4 (http://lists.debian.org/debian-gcc/2010/04/msg00000.html) + */ +#define DUK_LIKELY(x) __builtin_expect((x), 1) +#define DUK_UNLIKELY(x) __builtin_expect((x), 0) +#endif +/* XXX: equivalent of clang __builtin_unpredictable? */ + +#if (defined(DUK_F_C99) || defined(DUK_F_CPP11)) && \ + defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 30101) +#define DUK_NOINLINE __attribute__((noinline)) +#define DUK_INLINE inline +#define DUK_ALWAYS_INLINE inline __attribute__((always_inline)) +#endif + +#if (defined(DUK_F_C99) || defined(DUK_F_CPP11)) && \ + defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 40300) +#define DUK_HOT __attribute__((hot)) +#define DUK_COLD __attribute__((cold)) +#endif + +#if defined(DUK_F_DLL_BUILD) && defined(DUK_F_WINDOWS) +/* MSVC dllexport/dllimport: appropriate __declspec depends on whether we're + * compiling Duktape or the application. + */ +#if defined(DUK_COMPILING_DUKTAPE) +#define DUK_EXTERNAL_DECL extern __declspec(dllexport) +#define DUK_EXTERNAL __declspec(dllexport) +#else +#define DUK_EXTERNAL_DECL extern __declspec(dllimport) +#define DUK_EXTERNAL should_not_happen +#endif +#if defined(DUK_SINGLE_FILE) +#define DUK_INTERNAL_DECL static +#define DUK_INTERNAL static +#else +#define DUK_INTERNAL_DECL extern +#define DUK_INTERNAL /*empty*/ +#endif +#define DUK_LOCAL_DECL static +#define DUK_LOCAL static +#elif defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 40000) +#define DUK_EXTERNAL_DECL __attribute__ ((visibility("default"))) extern +#define DUK_EXTERNAL __attribute__ ((visibility("default"))) +#if defined(DUK_SINGLE_FILE) +#if (defined(DUK_F_GCC_VERSION) && DUK_F_GCC_VERSION >= 30101) || defined(DUK_F_CLANG) +/* Minimize warnings for unused internal functions with GCC >= 3.1.1 and + * Clang. Based on documentation it should suffice to have the attribute + * in the declaration only, but in practice some warnings are generated unless + * the attribute is also applied to the definition. + */ +#define DUK_INTERNAL_DECL static __attribute__ ((unused)) +#define DUK_INTERNAL static __attribute__ ((unused)) +#else +#define DUK_INTERNAL_DECL static +#define DUK_INTERNAL static +#endif +#else +#if (defined(DUK_F_GCC_VERSION) && DUK_F_GCC_VERSION >= 30101) || defined(DUK_F_CLANG) +#define DUK_INTERNAL_DECL __attribute__ ((visibility("hidden"))) __attribute__ ((unused)) extern +#define DUK_INTERNAL __attribute__ ((visibility("hidden"))) __attribute__ ((unused)) +#else +#define DUK_INTERNAL_DECL __attribute__ ((visibility("hidden"))) extern +#define DUK_INTERNAL __attribute__ ((visibility("hidden"))) +#endif +#endif +#define DUK_LOCAL_DECL static +#define DUK_LOCAL static +#endif + +#if defined(DUK_F_MINGW) +#if defined(DUK_F_CPP) +#define DUK_USE_COMPILER_STRING "mingw++" +#else +#define DUK_USE_COMPILER_STRING "mingw" +#endif +#else +#if defined(DUK_F_CPP) +#define DUK_USE_COMPILER_STRING "g++" +#else +#define DUK_USE_COMPILER_STRING "gcc" +#endif +#endif + +#undef DUK_USE_VARIADIC_MACROS +#if defined(DUK_F_C99) || (defined(DUK_F_CPP11) && defined(__GNUC__)) +#define DUK_USE_VARIADIC_MACROS +#endif + +#define DUK_USE_UNION_INITIALIZERS + +#undef DUK_USE_FLEX_C99 +#undef DUK_USE_FLEX_ZEROSIZE +#undef DUK_USE_FLEX_ONESIZE +#if defined(DUK_F_C99) +#define DUK_USE_FLEX_C99 +#else +#define DUK_USE_FLEX_ZEROSIZE +#endif + +/* Since 4.6 one can '#pragma GCC diagnostic push/pop'. */ +#if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 40600) +#define DUK_USE_GCC_PRAGMAS +#else +#undef DUK_USE_GCC_PRAGMAS +#endif + +#define DUK_USE_PACK_GCC_ATTR + +/* Availability varies based on platform (between GCC 4.4 and 4.8), and there + * are apparently some bugs in GCC 4.x. Check for GCC 5.0 before enabling + * these to be safe. + */ +#if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 50000L) +#define DUK_BSWAP64(x) ((duk_uint64_t) __builtin_bswap64((duk_uint64_t) (x))) +#define DUK_BSWAP32(x) ((duk_uint32_t) __builtin_bswap32((duk_uint32_t) (x))) +#define DUK_BSWAP16(x) ((duk_uint16_t) __builtin_bswap16((duk_uint16_t) (x))) +#endif +#elif defined(DUK_F_MSVC) +/* --- MSVC --- */ +/* http://msdn.microsoft.com/en-us/library/aa235362(VS.60).aspx */ +#define DUK_NORETURN(decl) __declspec(noreturn) decl + +/* XXX: DUK_UNREACHABLE for msvc? */ + +#undef DUK_USE_BRANCH_HINTS + +/* XXX: DUK_LIKELY, DUK_UNLIKELY for msvc? */ +/* XXX: DUK_NOINLINE, DUK_INLINE, DUK_ALWAYS_INLINE for msvc? */ + +#if defined(DUK_F_DLL_BUILD) && defined(DUK_F_WINDOWS) +/* MSVC dllexport/dllimport: appropriate __declspec depends on whether we're + * compiling Duktape or the application. + */ +#if defined(DUK_COMPILING_DUKTAPE) +#define DUK_EXTERNAL_DECL extern __declspec(dllexport) +#define DUK_EXTERNAL __declspec(dllexport) +#else +#define DUK_EXTERNAL_DECL extern __declspec(dllimport) +#define DUK_EXTERNAL should_not_happen +#endif +#if defined(DUK_SINGLE_FILE) +#define DUK_INTERNAL_DECL static +#define DUK_INTERNAL static +#else +#define DUK_INTERNAL_DECL extern +#define DUK_INTERNAL /*empty*/ +#endif +#define DUK_LOCAL_DECL static +#define DUK_LOCAL static +#endif + +#if defined(DUK_F_CPP) +#define DUK_USE_COMPILER_STRING "msvc++" +#else +#define DUK_USE_COMPILER_STRING "msvc" +#endif + +#undef DUK_USE_VARIADIC_MACROS +#if defined(DUK_F_C99) +#define DUK_USE_VARIADIC_MACROS +#elif defined(_MSC_VER) && (_MSC_VER >= 1400) +/* VS2005+ should have variadic macros even when they're not C99. */ +#define DUK_USE_VARIADIC_MACROS +#endif + +#undef DUK_USE_UNION_INITIALIZERS +#if defined(_MSC_VER) && (_MSC_VER >= 1800) +/* VS2013+ supports union initializers but there's a bug involving union-inside-struct: + * https://connect.microsoft.com/VisualStudio/feedback/details/805981 + * The bug was fixed (at least) in VS2015 so check for VS2015 for now: + * https://blogs.msdn.microsoft.com/vcblog/2015/07/01/c-compiler-front-end-fixes-in-vs2015/ + * Manually tested using VS2013, CL reports 18.00.31101, so enable for VS2013 too. + */ +#define DUK_USE_UNION_INITIALIZERS +#endif + +#undef DUK_USE_FLEX_C99 +#undef DUK_USE_FLEX_ZEROSIZE +#undef DUK_USE_FLEX_ONESIZE +#if defined(DUK_F_C99) +#define DUK_USE_FLEX_C99 +#else +#define DUK_USE_FLEX_ZEROSIZE +#endif + +#undef DUK_USE_GCC_PRAGMAS + +#define DUK_USE_PACK_MSVC_PRAGMA + +/* These have been tested from VS2008 onwards; may work in older VS versions + * too but not enabled by default. + */ +#if defined(_MSC_VER) && (_MSC_VER >= 1500) +#define DUK_NOINLINE __declspec(noinline) +#define DUK_INLINE __inline +#define DUK_ALWAYS_INLINE __forceinline +#endif + +#if defined(_MSC_VER) && (_MSC_VER >= 1900) +#define DUK_SNPRINTF snprintf +#define DUK_VSNPRINTF vsnprintf +#else +/* (v)snprintf() is missing before MSVC 2015. Note that _(v)snprintf() does + * NOT NUL terminate on truncation, but Duktape code never assumes that. + * http://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010 + */ +#define DUK_SNPRINTF _snprintf +#define DUK_VSNPRINTF _vsnprintf +#endif + +/* Avoid warning when doing DUK_UNREF(some_function). */ +#if defined(_MSC_VER) && (_MSC_VER < 1500) +#pragma warning(disable: 4100 4101 4550 4551) +#define DUK_UNREF(x) +#else +#define DUK_UNREF(x) do { __pragma(warning(suppress:4100 4101 4550 4551)) (x); } while (0) +#endif + +/* Older versions of MSVC don't support the LL/ULL suffix. */ +#define DUK_U64_CONSTANT(x) x##ui64 +#define DUK_I64_CONSTANT(x) x##i64 +#elif defined(DUK_F_EMSCRIPTEN) +/* --- Emscripten --- */ +#define DUK_NORETURN(decl) decl __attribute__((noreturn)) + +#if defined(__clang__) && defined(__has_builtin) +#if __has_builtin(__builtin_unreachable) +#define DUK_UNREACHABLE() do { __builtin_unreachable(); } while (0) +#endif +#endif + +#define DUK_USE_BRANCH_HINTS +#define DUK_LIKELY(x) __builtin_expect((x), 1) +#define DUK_UNLIKELY(x) __builtin_expect((x), 0) +#if defined(__clang__) && defined(__has_builtin) +#if __has_builtin(__builtin_unpredictable) +#define DUK_UNPREDICTABLE(x) __builtin_unpredictable((x)) +#endif +#endif + +#if defined(DUK_F_C99) || defined(DUK_F_CPP11) +#define DUK_NOINLINE __attribute__((noinline)) +#define DUK_INLINE inline +#define DUK_ALWAYS_INLINE inline __attribute__((always_inline)) +#endif + +#define DUK_EXTERNAL_DECL __attribute__ ((visibility("default"))) extern +#define DUK_EXTERNAL __attribute__ ((visibility("default"))) +#if defined(DUK_SINGLE_FILE) +#if (defined(DUK_F_GCC_VERSION) && DUK_F_GCC_VERSION >= 30101) || defined(DUK_F_CLANG) +/* Minimize warnings for unused internal functions with GCC >= 3.1.1 and + * Clang. Based on documentation it should suffice to have the attribute + * in the declaration only, but in practice some warnings are generated unless + * the attribute is also applied to the definition. + */ +#define DUK_INTERNAL_DECL static __attribute__ ((unused)) +#define DUK_INTERNAL static __attribute__ ((unused)) +#else +#define DUK_INTERNAL_DECL static +#define DUK_INTERNAL static +#endif +#else +#if (defined(DUK_F_GCC_VERSION) && DUK_F_GCC_VERSION >= 30101) || defined(DUK_F_CLANG) +#define DUK_INTERNAL_DECL __attribute__ ((visibility("hidden"))) __attribute__ ((unused)) extern +#define DUK_INTERNAL __attribute__ ((visibility("hidden"))) __attribute__ ((unused)) +#else +#define DUK_INTERNAL_DECL __attribute__ ((visibility("hidden"))) extern +#define DUK_INTERNAL __attribute__ ((visibility("hidden"))) +#endif +#endif +#define DUK_LOCAL_DECL static +#define DUK_LOCAL static + +#define DUK_USE_COMPILER_STRING "emscripten" + +#undef DUK_USE_VARIADIC_MACROS +#if defined(DUK_F_C99) || defined(DUK_F_CPP11) +#define DUK_USE_VARIADIC_MACROS +#endif + +#define DUK_USE_UNION_INITIALIZERS + +#undef DUK_USE_FLEX_C99 +#undef DUK_USE_FLEX_ZEROSIZE +#undef DUK_USE_FLEX_ONESIZE +#if defined(DUK_F_C99) +#define DUK_USE_FLEX_C99 +#else +#define DUK_USE_FLEX_ZEROSIZE +#endif + +#undef DUK_USE_GCC_PRAGMAS +#define DUK_USE_PACK_CLANG_ATTR +#elif defined(DUK_F_TINYC) +/* --- TinyC --- */ +#undef DUK_USE_BRANCH_HINTS + +#if defined(DUK_F_CPP) +#define DUK_USE_COMPILER_STRING "tinyc++" +#else +#define DUK_USE_COMPILER_STRING "tinyc" +#endif + +/* http://bellard.org/tcc/tcc-doc.html#SEC7 */ +#define DUK_USE_VARIADIC_MACROS + +#define DUK_USE_UNION_INITIALIZERS + +/* Most portable, wastes space */ +#define DUK_USE_FLEX_ONESIZE + +/* Most portable, potentially wastes space */ +#define DUK_USE_PACK_DUMMY_MEMBER +#elif defined(DUK_F_VBCC) +/* --- VBCC --- */ +#undef DUK_USE_BRANCH_HINTS + +#if defined(DUK_F_CPP) +#define DUK_USE_COMPILER_STRING "vbcc-c++" +#else +#define DUK_USE_COMPILER_STRING "vbcc" +#endif + +#undef DUK_USE_VARIADIC_MACROS +#if defined(DUK_F_C99) || defined(DUK_F_CPP11) +#define DUK_USE_VARIADIC_MACROS +#endif + +/* VBCC supports C99 so check only for C99 for union initializer support. + * Designated union initializers would possibly work even without a C99 check. + */ +#undef DUK_USE_UNION_INITIALIZERS +#if defined(DUK_F_C99) +#define DUK_USE_UNION_INITIALIZERS +#endif + +#define DUK_USE_FLEX_ZEROSIZE +#define DUK_USE_PACK_DUMMY_MEMBER +#elif defined(DUK_F_BCC) +/* --- Bruce's C compiler --- */ +#undef DUK_USE_BRANCH_HINTS + +#if defined(DUK_F_CPP) +#define DUK_USE_COMPILER_STRING "bcc++" +#else +#define DUK_USE_COMPILER_STRING "bcc" +#endif + +/* Most portable */ +#undef DUK_USE_VARIADIC_MACROS + +/* Most portable, wastes space */ +#undef DUK_USE_UNION_INITIALIZERS + +/* Most portable, wastes space */ +#define DUK_USE_FLEX_ONESIZE + +/* Most portable, potentially wastes space */ +#define DUK_USE_PACK_DUMMY_MEMBER + +/* BCC, assume we're on x86. */ +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 1 +#endif +#else +/* --- Generic --- */ +#undef DUK_USE_BRANCH_HINTS + +#if defined(DUK_F_CPP) +#define DUK_USE_COMPILER_STRING "generic-c++" +#else +#define DUK_USE_COMPILER_STRING "generic" +#endif + +#undef DUK_USE_VARIADIC_MACROS +#if defined(DUK_F_C99) || defined(DUK_F_CPP11) +#define DUK_USE_VARIADIC_MACROS +#endif + +/* C++ doesn't have standard designated union initializers ({ .foo = 1 }). */ +#undef DUK_USE_UNION_INITIALIZERS +#if defined(DUK_F_C99) +#define DUK_USE_UNION_INITIALIZERS +#endif + +/* Most portable, wastes space */ +#define DUK_USE_FLEX_ONESIZE + +/* Most portable, potentially wastes space */ +#define DUK_USE_PACK_DUMMY_MEMBER +#endif /* autodetect compiler */ + +/* uclibc */ +#if defined(__UCLIBC__) +#define DUK_F_UCLIBC +#endif + +/* + * Wrapper typedefs and constants for integer types, also sanity check types. + * + * C99 typedefs are quite good but not always available, and we want to avoid + * forcibly redefining the C99 typedefs. So, there are Duktape wrappers for + * all C99 typedefs and Duktape code should only use these typedefs. Type + * detection when C99 is not supported is best effort and may end up detecting + * some types incorrectly. + * + * Pointer sizes are a portability problem: pointers to different types may + * have a different size and function pointers are very difficult to manage + * portably. + * + * http://en.wikipedia.org/wiki/C_data_types#Fixed-width_integer_types + * + * Note: there's an interesting corner case when trying to define minimum + * signed integer value constants which leads to the current workaround of + * defining e.g. -0x80000000 as (-0x7fffffffL - 1L). See doc/code-issues.txt + * for a longer discussion. + * + * Note: avoid typecasts and computations in macro integer constants as they + * can then no longer be used in macro relational expressions (such as + * #if DUK_SIZE_MAX < 0xffffffffUL). There is internal code which relies on + * being able to compare DUK_SIZE_MAX against a limit. + */ + +/* XXX: add feature options to force basic types from outside? */ + +#if !defined(INT_MAX) +#error INT_MAX not defined +#endif + +/* Check that architecture is two's complement, standard C allows e.g. + * INT_MIN to be -2**31+1 (instead of -2**31). + */ +#if defined(INT_MAX) && defined(INT_MIN) +#if INT_MAX != -(INT_MIN + 1) +#error platform does not seem complement of two +#endif +#else +#error cannot check complement of two +#endif + +/* Pointer size determination based on __WORDSIZE or architecture when + * that's not available. + */ +#if defined(DUK_F_X86) || defined(DUK_F_X32) || \ + defined(DUK_F_M68K) || defined(DUK_F_PPC32) || \ + defined(DUK_F_BCC) || \ + (defined(__WORDSIZE) && (__WORDSIZE == 32)) || \ + ((defined(DUK_F_OLD_SOLARIS) || defined(DUK_F_AIX) || \ + defined(DUK_F_HPUX)) && defined(_ILP32)) || \ + defined(DUK_F_ARM32) +#define DUK_F_32BIT_PTRS +#elif defined(DUK_F_X64) || \ + (defined(__WORDSIZE) && (__WORDSIZE == 64)) || \ + ((defined(DUK_F_OLD_SOLARIS) || defined(DUK_F_AIX) || \ + defined(DUK_F_HPUX)) && defined(_LP64)) || \ + defined(DUK_F_ARM64) +#define DUK_F_64BIT_PTRS +#else +/* not sure, not needed with C99 anyway */ +#endif + +/* Intermediate define for 'have inttypes.h' */ +#undef DUK_F_HAVE_INTTYPES +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ + !(defined(DUK_F_AMIGAOS) && defined(DUK_F_VBCC)) +/* vbcc + AmigaOS has C99 but no inttypes.h */ +#define DUK_F_HAVE_INTTYPES +#elif defined(__cplusplus) && (__cplusplus >= 201103L) +/* C++11 apparently ratified stdint.h */ +#define DUK_F_HAVE_INTTYPES +#endif + +/* Basic integer typedefs and limits, preferably from inttypes.h, otherwise + * through automatic detection. + */ +#if defined(DUK_F_HAVE_INTTYPES) +/* C99 or compatible */ + +#define DUK_F_HAVE_64BIT +#include <inttypes.h> + +typedef uint8_t duk_uint8_t; +typedef int8_t duk_int8_t; +typedef uint16_t duk_uint16_t; +typedef int16_t duk_int16_t; +typedef uint32_t duk_uint32_t; +typedef int32_t duk_int32_t; +typedef uint64_t duk_uint64_t; +typedef int64_t duk_int64_t; +typedef uint_least8_t duk_uint_least8_t; +typedef int_least8_t duk_int_least8_t; +typedef uint_least16_t duk_uint_least16_t; +typedef int_least16_t duk_int_least16_t; +typedef uint_least32_t duk_uint_least32_t; +typedef int_least32_t duk_int_least32_t; +typedef uint_least64_t duk_uint_least64_t; +typedef int_least64_t duk_int_least64_t; +typedef uint_fast8_t duk_uint_fast8_t; +typedef int_fast8_t duk_int_fast8_t; +typedef uint_fast16_t duk_uint_fast16_t; +typedef int_fast16_t duk_int_fast16_t; +typedef uint_fast32_t duk_uint_fast32_t; +typedef int_fast32_t duk_int_fast32_t; +typedef uint_fast64_t duk_uint_fast64_t; +typedef int_fast64_t duk_int_fast64_t; +typedef uintptr_t duk_uintptr_t; +typedef intptr_t duk_intptr_t; +typedef uintmax_t duk_uintmax_t; +typedef intmax_t duk_intmax_t; + +#define DUK_UINT8_MIN 0 +#define DUK_UINT8_MAX UINT8_MAX +#define DUK_INT8_MIN INT8_MIN +#define DUK_INT8_MAX INT8_MAX +#define DUK_UINT_LEAST8_MIN 0 +#define DUK_UINT_LEAST8_MAX UINT_LEAST8_MAX +#define DUK_INT_LEAST8_MIN INT_LEAST8_MIN +#define DUK_INT_LEAST8_MAX INT_LEAST8_MAX +#define DUK_UINT_FAST8_MIN 0 +#define DUK_UINT_FAST8_MAX UINT_FAST8_MAX +#define DUK_INT_FAST8_MIN INT_FAST8_MIN +#define DUK_INT_FAST8_MAX INT_FAST8_MAX +#define DUK_UINT16_MIN 0 +#define DUK_UINT16_MAX UINT16_MAX +#define DUK_INT16_MIN INT16_MIN +#define DUK_INT16_MAX INT16_MAX +#define DUK_UINT_LEAST16_MIN 0 +#define DUK_UINT_LEAST16_MAX UINT_LEAST16_MAX +#define DUK_INT_LEAST16_MIN INT_LEAST16_MIN +#define DUK_INT_LEAST16_MAX INT_LEAST16_MAX +#define DUK_UINT_FAST16_MIN 0 +#define DUK_UINT_FAST16_MAX UINT_FAST16_MAX +#define DUK_INT_FAST16_MIN INT_FAST16_MIN +#define DUK_INT_FAST16_MAX INT_FAST16_MAX +#define DUK_UINT32_MIN 0 +#define DUK_UINT32_MAX UINT32_MAX +#define DUK_INT32_MIN INT32_MIN +#define DUK_INT32_MAX INT32_MAX +#define DUK_UINT_LEAST32_MIN 0 +#define DUK_UINT_LEAST32_MAX UINT_LEAST32_MAX +#define DUK_INT_LEAST32_MIN INT_LEAST32_MIN +#define DUK_INT_LEAST32_MAX INT_LEAST32_MAX +#define DUK_UINT_FAST32_MIN 0 +#define DUK_UINT_FAST32_MAX UINT_FAST32_MAX +#define DUK_INT_FAST32_MIN INT_FAST32_MIN +#define DUK_INT_FAST32_MAX INT_FAST32_MAX +#define DUK_UINT64_MIN 0 +#define DUK_UINT64_MAX UINT64_MAX +#define DUK_INT64_MIN INT64_MIN +#define DUK_INT64_MAX INT64_MAX +#define DUK_UINT_LEAST64_MIN 0 +#define DUK_UINT_LEAST64_MAX UINT_LEAST64_MAX +#define DUK_INT_LEAST64_MIN INT_LEAST64_MIN +#define DUK_INT_LEAST64_MAX INT_LEAST64_MAX +#define DUK_UINT_FAST64_MIN 0 +#define DUK_UINT_FAST64_MAX UINT_FAST64_MAX +#define DUK_INT_FAST64_MIN INT_FAST64_MIN +#define DUK_INT_FAST64_MAX INT_FAST64_MAX + +#define DUK_UINTPTR_MIN 0 +#define DUK_UINTPTR_MAX UINTPTR_MAX +#define DUK_INTPTR_MIN INTPTR_MIN +#define DUK_INTPTR_MAX INTPTR_MAX + +#define DUK_UINTMAX_MIN 0 +#define DUK_UINTMAX_MAX UINTMAX_MAX +#define DUK_INTMAX_MIN INTMAX_MIN +#define DUK_INTMAX_MAX INTMAX_MAX + +#define DUK_SIZE_MIN 0 +#define DUK_SIZE_MAX SIZE_MAX +#undef DUK_SIZE_MAX_COMPUTED + +#else /* C99 types */ + +/* When C99 types are not available, we use heuristic detection to get + * the basic 8, 16, 32, and (possibly) 64 bit types. The fast/least + * types are then assumed to be exactly the same for now: these could + * be improved per platform but C99 types are very often now available. + * 64-bit types are not available on all platforms; this is OK at least + * on 32-bit platforms. + * + * This detection code is necessarily a bit hacky and can provide typedefs + * and defines that won't work correctly on some exotic platform. + */ + +#if (defined(CHAR_BIT) && (CHAR_BIT == 8)) || \ + (defined(UCHAR_MAX) && (UCHAR_MAX == 255)) +typedef unsigned char duk_uint8_t; +typedef signed char duk_int8_t; +#else +#error cannot detect 8-bit type +#endif + +#if defined(USHRT_MAX) && (USHRT_MAX == 65535UL) +typedef unsigned short duk_uint16_t; +typedef signed short duk_int16_t; +#elif defined(UINT_MAX) && (UINT_MAX == 65535UL) +/* On some platforms int is 16-bit but long is 32-bit (e.g. PureC) */ +typedef unsigned int duk_uint16_t; +typedef signed int duk_int16_t; +#else +#error cannot detect 16-bit type +#endif + +#if defined(UINT_MAX) && (UINT_MAX == 4294967295UL) +typedef unsigned int duk_uint32_t; +typedef signed int duk_int32_t; +#elif defined(ULONG_MAX) && (ULONG_MAX == 4294967295UL) +/* On some platforms int is 16-bit but long is 32-bit (e.g. PureC) */ +typedef unsigned long duk_uint32_t; +typedef signed long duk_int32_t; +#else +#error cannot detect 32-bit type +#endif + +/* 64-bit type detection is a bit tricky. + * + * ULLONG_MAX is a standard define. __LONG_LONG_MAX__ and __ULONG_LONG_MAX__ + * are used by at least GCC (even if system headers don't provide ULLONG_MAX). + * Some GCC variants may provide __LONG_LONG_MAX__ but not __ULONG_LONG_MAX__. + * + * ULL / LL constants are rejected / warned about by some compilers, even if + * the compiler has a 64-bit type and the compiler/system headers provide an + * unsupported constant (ULL/LL)! Try to avoid using ULL / LL constants. + * As a side effect we can only check that e.g. ULONG_MAX is larger than 32 + * bits but can't be sure it is exactly 64 bits. Self tests will catch such + * cases. + */ +#undef DUK_F_HAVE_64BIT +#if !defined(DUK_F_HAVE_64BIT) && defined(ULONG_MAX) +#if (ULONG_MAX > 4294967295UL) +#define DUK_F_HAVE_64BIT +typedef unsigned long duk_uint64_t; +typedef signed long duk_int64_t; +#endif +#endif +#if !defined(DUK_F_HAVE_64BIT) && defined(ULLONG_MAX) +#if (ULLONG_MAX > 4294967295UL) +#define DUK_F_HAVE_64BIT +typedef unsigned long long duk_uint64_t; +typedef signed long long duk_int64_t; +#endif +#endif +#if !defined(DUK_F_HAVE_64BIT) && defined(__ULONG_LONG_MAX__) +#if (__ULONG_LONG_MAX__ > 4294967295UL) +#define DUK_F_HAVE_64BIT +typedef unsigned long long duk_uint64_t; +typedef signed long long duk_int64_t; +#endif +#endif +#if !defined(DUK_F_HAVE_64BIT) && defined(__LONG_LONG_MAX__) +#if (__LONG_LONG_MAX__ > 2147483647L) +#define DUK_F_HAVE_64BIT +typedef unsigned long long duk_uint64_t; +typedef signed long long duk_int64_t; +#endif +#endif +#if !defined(DUK_F_HAVE_64BIT) && defined(DUK_F_MINGW) +#define DUK_F_HAVE_64BIT +typedef unsigned long duk_uint64_t; +typedef signed long duk_int64_t; +#endif +#if !defined(DUK_F_HAVE_64BIT) && defined(DUK_F_MSVC) +#define DUK_F_HAVE_64BIT +typedef unsigned __int64 duk_uint64_t; +typedef signed __int64 duk_int64_t; +#endif +#if !defined(DUK_F_HAVE_64BIT) +/* cannot detect 64-bit type, not always needed so don't error */ +#endif + +typedef duk_uint8_t duk_uint_least8_t; +typedef duk_int8_t duk_int_least8_t; +typedef duk_uint16_t duk_uint_least16_t; +typedef duk_int16_t duk_int_least16_t; +typedef duk_uint32_t duk_uint_least32_t; +typedef duk_int32_t duk_int_least32_t; +typedef duk_uint8_t duk_uint_fast8_t; +typedef duk_int8_t duk_int_fast8_t; +typedef duk_uint16_t duk_uint_fast16_t; +typedef duk_int16_t duk_int_fast16_t; +typedef duk_uint32_t duk_uint_fast32_t; +typedef duk_int32_t duk_int_fast32_t; +#if defined(DUK_F_HAVE_64BIT) +typedef duk_uint64_t duk_uint_least64_t; +typedef duk_int64_t duk_int_least64_t; +typedef duk_uint64_t duk_uint_fast64_t; +typedef duk_int64_t duk_int_fast64_t; +#endif +#if defined(DUK_F_HAVE_64BIT) +typedef duk_uint64_t duk_uintmax_t; +typedef duk_int64_t duk_intmax_t; +#else +typedef duk_uint32_t duk_uintmax_t; +typedef duk_int32_t duk_intmax_t; +#endif + +/* Note: the funny looking computations for signed minimum 16-bit, 32-bit, and + * 64-bit values are intentional as the obvious forms (e.g. -0x80000000L) are + * -not- portable. See code-issues.txt for a detailed discussion. + */ +#define DUK_UINT8_MIN 0UL +#define DUK_UINT8_MAX 0xffUL +#define DUK_INT8_MIN (-0x80L) +#define DUK_INT8_MAX 0x7fL +#define DUK_UINT_LEAST8_MIN 0UL +#define DUK_UINT_LEAST8_MAX 0xffUL +#define DUK_INT_LEAST8_MIN (-0x80L) +#define DUK_INT_LEAST8_MAX 0x7fL +#define DUK_UINT_FAST8_MIN 0UL +#define DUK_UINT_FAST8_MAX 0xffUL +#define DUK_INT_FAST8_MIN (-0x80L) +#define DUK_INT_FAST8_MAX 0x7fL +#define DUK_UINT16_MIN 0UL +#define DUK_UINT16_MAX 0xffffUL +#define DUK_INT16_MIN (-0x7fffL - 1L) +#define DUK_INT16_MAX 0x7fffL +#define DUK_UINT_LEAST16_MIN 0UL +#define DUK_UINT_LEAST16_MAX 0xffffUL +#define DUK_INT_LEAST16_MIN (-0x7fffL - 1L) +#define DUK_INT_LEAST16_MAX 0x7fffL +#define DUK_UINT_FAST16_MIN 0UL +#define DUK_UINT_FAST16_MAX 0xffffUL +#define DUK_INT_FAST16_MIN (-0x7fffL - 1L) +#define DUK_INT_FAST16_MAX 0x7fffL +#define DUK_UINT32_MIN 0UL +#define DUK_UINT32_MAX 0xffffffffUL +#define DUK_INT32_MIN (-0x7fffffffL - 1L) +#define DUK_INT32_MAX 0x7fffffffL +#define DUK_UINT_LEAST32_MIN 0UL +#define DUK_UINT_LEAST32_MAX 0xffffffffUL +#define DUK_INT_LEAST32_MIN (-0x7fffffffL - 1L) +#define DUK_INT_LEAST32_MAX 0x7fffffffL +#define DUK_UINT_FAST32_MIN 0UL +#define DUK_UINT_FAST32_MAX 0xffffffffUL +#define DUK_INT_FAST32_MIN (-0x7fffffffL - 1L) +#define DUK_INT_FAST32_MAX 0x7fffffffL + +/* 64-bit constants. Since LL / ULL constants are not always available, + * use computed values. These values can't be used in preprocessor + * comparisons; flag them as such. + */ +#if defined(DUK_F_HAVE_64BIT) +#define DUK_UINT64_MIN ((duk_uint64_t) 0) +#define DUK_UINT64_MAX ((duk_uint64_t) -1) +#define DUK_INT64_MIN ((duk_int64_t) (~(DUK_UINT64_MAX >> 1))) +#define DUK_INT64_MAX ((duk_int64_t) (DUK_UINT64_MAX >> 1)) +#define DUK_UINT_LEAST64_MIN DUK_UINT64_MIN +#define DUK_UINT_LEAST64_MAX DUK_UINT64_MAX +#define DUK_INT_LEAST64_MIN DUK_INT64_MIN +#define DUK_INT_LEAST64_MAX DUK_INT64_MAX +#define DUK_UINT_FAST64_MIN DUK_UINT64_MIN +#define DUK_UINT_FAST64_MAX DUK_UINT64_MAX +#define DUK_INT_FAST64_MIN DUK_INT64_MIN +#define DUK_INT_FAST64_MAX DUK_INT64_MAX +#define DUK_UINT64_MIN_COMPUTED +#define DUK_UINT64_MAX_COMPUTED +#define DUK_INT64_MIN_COMPUTED +#define DUK_INT64_MAX_COMPUTED +#define DUK_UINT_LEAST64_MIN_COMPUTED +#define DUK_UINT_LEAST64_MAX_COMPUTED +#define DUK_INT_LEAST64_MIN_COMPUTED +#define DUK_INT_LEAST64_MAX_COMPUTED +#define DUK_UINT_FAST64_MIN_COMPUTED +#define DUK_UINT_FAST64_MAX_COMPUTED +#define DUK_INT_FAST64_MIN_COMPUTED +#define DUK_INT_FAST64_MAX_COMPUTED +#endif + +#if defined(DUK_F_HAVE_64BIT) +#define DUK_UINTMAX_MIN DUK_UINT64_MIN +#define DUK_UINTMAX_MAX DUK_UINT64_MAX +#define DUK_INTMAX_MIN DUK_INT64_MIN +#define DUK_INTMAX_MAX DUK_INT64_MAX +#define DUK_UINTMAX_MIN_COMPUTED +#define DUK_UINTMAX_MAX_COMPUTED +#define DUK_INTMAX_MIN_COMPUTED +#define DUK_INTMAX_MAX_COMPUTED +#else +#define DUK_UINTMAX_MIN 0UL +#define DUK_UINTMAX_MAX 0xffffffffUL +#define DUK_INTMAX_MIN (-0x7fffffffL - 1L) +#define DUK_INTMAX_MAX 0x7fffffffL +#endif + +/* This detection is not very reliable. */ +#if defined(DUK_F_32BIT_PTRS) +typedef duk_int32_t duk_intptr_t; +typedef duk_uint32_t duk_uintptr_t; +#define DUK_UINTPTR_MIN DUK_UINT32_MIN +#define DUK_UINTPTR_MAX DUK_UINT32_MAX +#define DUK_INTPTR_MIN DUK_INT32_MIN +#define DUK_INTPTR_MAX DUK_INT32_MAX +#elif defined(DUK_F_64BIT_PTRS) && defined(DUK_F_HAVE_64BIT) +typedef duk_int64_t duk_intptr_t; +typedef duk_uint64_t duk_uintptr_t; +#define DUK_UINTPTR_MIN DUK_UINT64_MIN +#define DUK_UINTPTR_MAX DUK_UINT64_MAX +#define DUK_INTPTR_MIN DUK_INT64_MIN +#define DUK_INTPTR_MAX DUK_INT64_MAX +#define DUK_UINTPTR_MIN_COMPUTED +#define DUK_UINTPTR_MAX_COMPUTED +#define DUK_INTPTR_MIN_COMPUTED +#define DUK_INTPTR_MAX_COMPUTED +#else +#error cannot determine intptr type +#endif + +/* SIZE_MAX may be missing so use an approximate value for it. */ +#undef DUK_SIZE_MAX_COMPUTED +#if !defined(SIZE_MAX) +#define DUK_SIZE_MAX_COMPUTED +#define SIZE_MAX ((size_t) (-1)) +#endif +#define DUK_SIZE_MIN 0 +#define DUK_SIZE_MAX SIZE_MAX + +#endif /* C99 types */ + +/* A few types are assumed to always exist. */ +typedef size_t duk_size_t; +typedef ptrdiff_t duk_ptrdiff_t; + +/* The best type for an "all around int" in Duktape internals is "at least + * 32 bit signed integer" which is most convenient. Same for unsigned type. + * Prefer 'int' when large enough, as it is almost always a convenient type. + */ +#if defined(UINT_MAX) && (UINT_MAX >= 0xffffffffUL) +typedef int duk_int_t; +typedef unsigned int duk_uint_t; +#define DUK_INT_MIN INT_MIN +#define DUK_INT_MAX INT_MAX +#define DUK_UINT_MIN 0 +#define DUK_UINT_MAX UINT_MAX +#else +typedef duk_int_fast32_t duk_int_t; +typedef duk_uint_fast32_t duk_uint_t; +#define DUK_INT_MIN DUK_INT_FAST32_MIN +#define DUK_INT_MAX DUK_INT_FAST32_MAX +#define DUK_UINT_MIN DUK_UINT_FAST32_MIN +#define DUK_UINT_MAX DUK_UINT_FAST32_MAX +#endif + +/* Same as 'duk_int_t' but guaranteed to be a 'fast' variant if this + * distinction matters for the CPU. These types are used mainly in the + * executor where it might really matter. + */ +typedef duk_int_fast32_t duk_int_fast_t; +typedef duk_uint_fast32_t duk_uint_fast_t; +#define DUK_INT_FAST_MIN DUK_INT_FAST32_MIN +#define DUK_INT_FAST_MAX DUK_INT_FAST32_MAX +#define DUK_UINT_FAST_MIN DUK_UINT_FAST32_MIN +#define DUK_UINT_FAST_MAX DUK_UINT_FAST32_MAX + +/* Small integers (16 bits or more) can fall back to the 'int' type, but + * have a typedef so they are marked "small" explicitly. + */ +typedef int duk_small_int_t; +typedef unsigned int duk_small_uint_t; +#define DUK_SMALL_INT_MIN INT_MIN +#define DUK_SMALL_INT_MAX INT_MAX +#define DUK_SMALL_UINT_MIN 0 +#define DUK_SMALL_UINT_MAX UINT_MAX + +/* Fast variants of small integers, again for really fast paths like the + * executor. + */ +typedef duk_int_fast16_t duk_small_int_fast_t; +typedef duk_uint_fast16_t duk_small_uint_fast_t; +#define DUK_SMALL_INT_FAST_MIN DUK_INT_FAST16_MIN +#define DUK_SMALL_INT_FAST_MAX DUK_INT_FAST16_MAX +#define DUK_SMALL_UINT_FAST_MIN DUK_UINT_FAST16_MIN +#define DUK_SMALL_UINT_FAST_MAX DUK_UINT_FAST16_MAX + +/* Boolean values are represented with the platform 'unsigned int'. */ +typedef duk_small_uint_t duk_bool_t; +#define DUK_BOOL_MIN DUK_SMALL_UINT_MIN +#define DUK_BOOL_MAX DUK_SMALL_UINT_MAX + +/* Index values must have at least 32-bit signed range. */ +typedef duk_int_t duk_idx_t; +#define DUK_IDX_MIN DUK_INT_MIN +#define DUK_IDX_MAX DUK_INT_MAX + +/* Unsigned index variant. */ +typedef duk_uint_t duk_uidx_t; +#define DUK_UIDX_MIN DUK_UINT_MIN +#define DUK_UIDX_MAX DUK_UINT_MAX + +/* Array index values, could be exact 32 bits. + * Currently no need for signed duk_arridx_t. + */ +typedef duk_uint_t duk_uarridx_t; +#define DUK_UARRIDX_MIN DUK_UINT_MIN +#define DUK_UARRIDX_MAX DUK_UINT_MAX + +/* Duktape/C function return value, platform int is enough for now to + * represent 0, 1, or negative error code. Must be compatible with + * assigning truth values (e.g. duk_ret_t rc = (foo == bar);). + */ +typedef duk_small_int_t duk_ret_t; +#define DUK_RET_MIN DUK_SMALL_INT_MIN +#define DUK_RET_MAX DUK_SMALL_INT_MAX + +/* Error codes are represented with platform int. High bits are used + * for flags and such, so 32 bits are needed. + */ +typedef duk_int_t duk_errcode_t; +#define DUK_ERRCODE_MIN DUK_INT_MIN +#define DUK_ERRCODE_MAX DUK_INT_MAX + +/* Codepoint type. Must be 32 bits or more because it is used also for + * internal codepoints. The type is signed because negative codepoints + * are used as internal markers (e.g. to mark EOF or missing argument). + * (X)UTF-8/CESU-8 encode/decode take and return an unsigned variant to + * ensure duk_uint32_t casts back and forth nicely. Almost everything + * else uses the signed one. + */ +typedef duk_int_t duk_codepoint_t; +typedef duk_uint_t duk_ucodepoint_t; +#define DUK_CODEPOINT_MIN DUK_INT_MIN +#define DUK_CODEPOINT_MAX DUK_INT_MAX +#define DUK_UCODEPOINT_MIN DUK_UINT_MIN +#define DUK_UCODEPOINT_MAX DUK_UINT_MAX + +/* IEEE float/double typedef. */ +typedef float duk_float_t; +typedef double duk_double_t; + +/* We're generally assuming that we're working on a platform with a 32-bit + * address space. If DUK_SIZE_MAX is a typecast value (which is necessary + * if SIZE_MAX is missing), the check must be avoided because the + * preprocessor can't do a comparison. + */ +#if !defined(DUK_SIZE_MAX) +#error DUK_SIZE_MAX is undefined, probably missing SIZE_MAX +#elif !defined(DUK_SIZE_MAX_COMPUTED) +#if DUK_SIZE_MAX < 0xffffffffUL +/* On some systems SIZE_MAX can be smaller than max unsigned 32-bit value + * which seems incorrect if size_t is (at least) an unsigned 32-bit type. + * However, it doesn't seem useful to error out compilation if this is the + * case. + */ +#endif +#endif + +/* Type used in public API declarations and user code. Typedef maps to + * 'struct duk_hthread' like the 'duk_hthread' typedef which is used + * exclusively in internals. + */ +typedef struct duk_hthread duk_context; + +/* Check whether we should use 64-bit integers or not. + * + * Quite incomplete now. Use 64-bit types if detected (C99 or other detection) + * unless they are known to be unreliable. For instance, 64-bit types are + * available on VBCC but seem to misbehave. + */ +#if defined(DUK_F_HAVE_64BIT) && !defined(DUK_F_VBCC) +#define DUK_USE_64BIT_OPS +#else +#undef DUK_USE_64BIT_OPS +#endif + +/* + * Fill-ins for platform, architecture, and compiler + */ + +/* An abort()-like primitive is needed by the default fatal error handler. */ +#if !defined(DUK_ABORT) +#define DUK_ABORT abort +#endif + +#if !defined(DUK_SETJMP) +#define DUK_JMPBUF_TYPE jmp_buf +#define DUK_SETJMP(jb) setjmp((jb)) +#define DUK_LONGJMP(jb) longjmp((jb), 1) +#endif + +#if 0 +/* sigsetjmp() alternative */ +#define DUK_JMPBUF_TYPE sigjmp_buf +#define DUK_SETJMP(jb) sigsetjmp((jb)) +#define DUK_LONGJMP(jb) siglongjmp((jb), 1) +#endif + +/* Special naming to avoid conflict with e.g. DUK_FREE() in duk_heap.h + * (which is unfortunately named). May sometimes need replacement, e.g. + * some compilers don't handle zero length or NULL correctly in realloc(). + */ +#if !defined(DUK_ANSI_MALLOC) +#define DUK_ANSI_MALLOC malloc +#endif +#if !defined(DUK_ANSI_REALLOC) +#define DUK_ANSI_REALLOC realloc +#endif +#if !defined(DUK_ANSI_CALLOC) +#define DUK_ANSI_CALLOC calloc +#endif +#if !defined(DUK_ANSI_FREE) +#define DUK_ANSI_FREE free +#endif + +/* ANSI C (various versions) and some implementations require that the + * pointer arguments to memset(), memcpy(), and memmove() be valid values + * even when byte size is 0 (even a NULL pointer is considered invalid in + * this context). Zero-size operations as such are allowed, as long as their + * pointer arguments point to a valid memory area. The DUK_MEMSET(), + * DUK_MEMCPY(), and DUK_MEMMOVE() macros require this same behavior, i.e.: + * (1) pointers must be valid and non-NULL, (2) zero size must otherwise be + * allowed. If these are not fulfilled, a macro wrapper is needed. + * + * http://stackoverflow.com/questions/5243012/is-it-guaranteed-to-be-safe-to-perform-memcpy0-0-0 + * http://lists.cs.uiuc.edu/pipermail/llvmdev/2007-October/011065.html + * + * Not sure what's the required behavior when a pointer points just past the + * end of a buffer, which often happens in practice (e.g. zero size memmoves). + * For example, if allocation size is 3, the following pointer would not + * technically point to a valid memory byte: + * + * <-- alloc --> + * | 0 | 1 | 2 | ..... + * ^-- p=3, points after last valid byte (2) + */ +#if !defined(DUK_MEMCPY) +#if defined(DUK_F_UCLIBC) +/* Old uclibcs have a broken memcpy so use memmove instead (this is overly wide + * now on purpose): http://lists.uclibc.org/pipermail/uclibc-cvs/2008-October/025511.html + */ +#define DUK_MEMCPY memmove +#else +#define DUK_MEMCPY memcpy +#endif +#endif +#if !defined(DUK_MEMMOVE) +#define DUK_MEMMOVE memmove +#endif +#if !defined(DUK_MEMCMP) +#define DUK_MEMCMP memcmp +#endif +#if !defined(DUK_MEMSET) +#define DUK_MEMSET memset +#endif +#if !defined(DUK_STRLEN) +#define DUK_STRLEN strlen +#endif +#if !defined(DUK_STRCMP) +#define DUK_STRCMP strcmp +#endif +#if !defined(DUK_STRNCMP) +#define DUK_STRNCMP strncmp +#endif +#if !defined(DUK_SPRINTF) +#define DUK_SPRINTF sprintf +#endif +#if !defined(DUK_SNPRINTF) +/* snprintf() is technically not part of C89 but usually available. */ +#define DUK_SNPRINTF snprintf +#endif +#if !defined(DUK_VSPRINTF) +#define DUK_VSPRINTF vsprintf +#endif +#if !defined(DUK_VSNPRINTF) +/* vsnprintf() is technically not part of C89 but usually available. */ +#define DUK_VSNPRINTF vsnprintf +#endif +#if !defined(DUK_SSCANF) +#define DUK_SSCANF sscanf +#endif +#if !defined(DUK_VSSCANF) +#define DUK_VSSCANF vsscanf +#endif +#if !defined(DUK_MEMZERO) +#define DUK_MEMZERO(p,n) DUK_MEMSET((p), 0, (n)) +#endif + +#if !defined(DUK_DOUBLE_INFINITY) +#undef DUK_USE_COMPUTED_INFINITY +#if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION < 40600) +/* GCC older than 4.6: avoid overflow warnings related to using INFINITY */ +#define DUK_DOUBLE_INFINITY (__builtin_inf()) +#elif defined(INFINITY) +#define DUK_DOUBLE_INFINITY ((double) INFINITY) +#elif !defined(DUK_F_VBCC) && !defined(DUK_F_MSVC) && !defined(DUK_F_BCC) && \ + !defined(DUK_F_OLD_SOLARIS) && !defined(DUK_F_AIX) +#define DUK_DOUBLE_INFINITY (1.0 / 0.0) +#else +/* In VBCC (1.0 / 0.0) results in a warning and 0.0 instead of infinity. + * Use a computed infinity (initialized when a heap is created at the + * latest). + */ +#define DUK_USE_COMPUTED_INFINITY +#define DUK_DOUBLE_INFINITY duk_computed_infinity +#endif +#endif + +#if !defined(DUK_DOUBLE_NAN) +#undef DUK_USE_COMPUTED_NAN +#if defined(NAN) +#define DUK_DOUBLE_NAN NAN +#elif !defined(DUK_F_VBCC) && !defined(DUK_F_MSVC) && !defined(DUK_F_BCC) && \ + !defined(DUK_F_OLD_SOLARIS) && !defined(DUK_F_AIX) +#define DUK_DOUBLE_NAN (0.0 / 0.0) +#else +/* In VBCC (0.0 / 0.0) results in a warning and 0.0 instead of NaN. + * In MSVC (VS2010 Express) (0.0 / 0.0) results in a compile error. + * Use a computed NaN (initialized when a heap is created at the + * latest). + */ +#define DUK_USE_COMPUTED_NAN +#define DUK_DOUBLE_NAN duk_computed_nan +#endif +#endif + +/* Many platforms are missing fpclassify() and friends, so use replacements + * if necessary. The replacement constants (FP_NAN etc) can be anything but + * match Linux constants now. + */ +#undef DUK_USE_REPL_FPCLASSIFY +#undef DUK_USE_REPL_SIGNBIT +#undef DUK_USE_REPL_ISFINITE +#undef DUK_USE_REPL_ISNAN +#undef DUK_USE_REPL_ISINF + +/* Complex condition broken into separate parts. */ +#undef DUK_F_USE_REPL_ALL +#if !(defined(FP_NAN) && defined(FP_INFINITE) && defined(FP_ZERO) && \ + defined(FP_SUBNORMAL) && defined(FP_NORMAL)) +/* Missing some obvious constants. */ +#define DUK_F_USE_REPL_ALL +#elif defined(DUK_F_AMIGAOS) && defined(DUK_F_VBCC) +/* VBCC is missing the built-ins even in C99 mode (perhaps a header issue). */ +#define DUK_F_USE_REPL_ALL +#elif defined(DUK_F_AMIGAOS) && defined(DUK_F_M68K) +/* AmigaOS + M68K seems to have math issues even when using GCC cross + * compilation. Use replacements for all AmigaOS versions on M68K + * regardless of compiler. + */ +#define DUK_F_USE_REPL_ALL +#elif defined(DUK_F_FREEBSD) && defined(DUK_F_CLANG) +/* Placeholder fix for (detection is wider than necessary): + * http://llvm.org/bugs/show_bug.cgi?id=17788 + */ +#define DUK_F_USE_REPL_ALL +#elif defined(DUK_F_UCLIBC) +/* At least some uclibc versions have broken floating point math. For + * example, fpclassify() can incorrectly classify certain NaN formats. + * To be safe, use replacements. + */ +#define DUK_F_USE_REPL_ALL +#elif defined(DUK_F_AIX) +/* Older versions may be missing isnan(), etc. */ +#define DUK_F_USE_REPL_ALL +#endif + +#if defined(DUK_F_USE_REPL_ALL) +#define DUK_USE_REPL_FPCLASSIFY +#define DUK_USE_REPL_SIGNBIT +#define DUK_USE_REPL_ISFINITE +#define DUK_USE_REPL_ISNAN +#define DUK_USE_REPL_ISINF +#define DUK_FPCLASSIFY duk_repl_fpclassify +#define DUK_SIGNBIT duk_repl_signbit +#define DUK_ISFINITE duk_repl_isfinite +#define DUK_ISNAN duk_repl_isnan +#define DUK_ISINF duk_repl_isinf +#define DUK_FP_NAN 0 +#define DUK_FP_INFINITE 1 +#define DUK_FP_ZERO 2 +#define DUK_FP_SUBNORMAL 3 +#define DUK_FP_NORMAL 4 +#else +#define DUK_FPCLASSIFY fpclassify +#define DUK_SIGNBIT signbit +#define DUK_ISFINITE isfinite +#define DUK_ISNAN isnan +#define DUK_ISINF isinf +#define DUK_FP_NAN FP_NAN +#define DUK_FP_INFINITE FP_INFINITE +#define DUK_FP_ZERO FP_ZERO +#define DUK_FP_SUBNORMAL FP_SUBNORMAL +#define DUK_FP_NORMAL FP_NORMAL +#endif + +#if defined(DUK_F_USE_REPL_ALL) +#undef DUK_F_USE_REPL_ALL +#endif + +/* These functions don't currently need replacement but are wrapped for + * completeness. Because these are used as function pointers, they need + * to be defined as concrete C functions (not macros). + */ +#if !defined(DUK_FABS) +#define DUK_FABS fabs +#endif +#if !defined(DUK_FLOOR) +#define DUK_FLOOR floor +#endif +#if !defined(DUK_CEIL) +#define DUK_CEIL ceil +#endif +#if !defined(DUK_FMOD) +#define DUK_FMOD fmod +#endif +#if !defined(DUK_POW) +#define DUK_POW pow +#endif +#if !defined(DUK_ACOS) +#define DUK_ACOS acos +#endif +#if !defined(DUK_ASIN) +#define DUK_ASIN asin +#endif +#if !defined(DUK_ATAN) +#define DUK_ATAN atan +#endif +#if !defined(DUK_ATAN2) +#define DUK_ATAN2 atan2 +#endif +#if !defined(DUK_SIN) +#define DUK_SIN sin +#endif +#if !defined(DUK_COS) +#define DUK_COS cos +#endif +#if !defined(DUK_TAN) +#define DUK_TAN tan +#endif +#if !defined(DUK_EXP) +#define DUK_EXP exp +#endif +#if !defined(DUK_LOG) +#define DUK_LOG log +#endif +#if !defined(DUK_SQRT) +#define DUK_SQRT sqrt +#endif + +/* The functions below exist only in C99/C++11 or later and need a workaround + * for platforms that don't include them. MSVC isn't detected as C99, but + * these functions also exist in MSVC 2013 and later so include a clause for + * that too. Android doesn't have log2; disable all of these for Android. + */ +#if (defined(DUK_F_C99) || defined(DUK_F_CPP11) || (defined(_MSC_VER) && (_MSC_VER >= 1800))) && \ + !defined(DUK_F_ANDROID) && !defined(DUK_F_MINT) +#if !defined(DUK_CBRT) +#define DUK_CBRT cbrt +#endif +#if !defined(DUK_LOG2) +#define DUK_LOG2 log2 +#endif +#if !defined(DUK_LOG10) +#define DUK_LOG10 log10 +#endif +#if !defined(DUK_TRUNC) +#define DUK_TRUNC trunc +#endif +#endif /* DUK_F_C99 etc */ + +/* NetBSD 6.0 x86 (at least) has a few problems with pow() semantics, + * see test-bug-netbsd-math-pow.js. MinGW has similar (but different) + * issues, see test-bug-mingw-math-issues.js. Enable pow() workarounds + * for these targets. + */ +#undef DUK_USE_POW_WORKAROUNDS +#if defined(DUK_F_NETBSD) || defined(DUK_F_MINGW) +#define DUK_USE_POW_WORKAROUNDS +#endif + +/* Similar workarounds for atan2() semantics issues. MinGW issues are + * documented in test-bug-mingw-math-issues.js. + */ +#undef DUK_USE_ATAN2_WORKAROUNDS +#if defined(DUK_F_MINGW) +#define DUK_USE_ATAN2_WORKAROUNDS +#endif + +/* Rely as little as possible on compiler behavior for NaN comparison, + * signed zero handling, etc. Currently never activated but may be needed + * for broken compilers. + */ +#undef DUK_USE_PARANOID_MATH + +/* There was a curious bug where test-bi-date-canceling.js would fail e.g. + * on 64-bit Ubuntu, gcc-4.8.1, -m32, and no -std=c99. Some date computations + * using doubles would be optimized which then broke some corner case tests. + * The problem goes away by adding 'volatile' to the datetime computations. + * Not sure what the actual triggering conditions are, but using this on + * non-C99 systems solves the known issues and has relatively little cost + * on other platforms. + */ +#undef DUK_USE_PARANOID_DATE_COMPUTATION +#if !defined(DUK_F_C99) +#define DUK_USE_PARANOID_DATE_COMPUTATION +#endif + +/* + * Byte order and double memory layout detection + * + * Endianness detection is a major portability hassle because the macros + * and headers are not standardized. There's even variance across UNIX + * platforms. Even with "standard" headers, details like underscore count + * varies between platforms, e.g. both __BYTE_ORDER and _BYTE_ORDER are used + * (Crossbridge has a single underscore, for instance). + * + * The checks below are structured with this in mind: several approaches are + * used, and at the end we check if any of them worked. This allows generic + * approaches to be tried first, and platform/compiler specific hacks tried + * last. As a last resort, the user can force a specific endianness, as it's + * not likely that automatic detection will work on the most exotic platforms. + * + * Duktape supports little and big endian machines. There's also support + * for a hybrid used by some ARM machines where integers are little endian + * but IEEE double values use a mixed order (12345678 -> 43218765). This + * byte order for doubles is referred to as "mixed endian". + */ + +/* GCC and Clang provide endianness defines as built-in predefines, with + * leading and trailing double underscores (e.g. __BYTE_ORDER__). See + * output of "make gccpredefs" and "make clangpredefs". Clang doesn't + * seem to provide __FLOAT_WORD_ORDER__; assume not mixed endian for clang. + * http://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html + */ +#if !defined(DUK_USE_BYTEORDER) && defined(__BYTE_ORDER__) +#if defined(__ORDER_LITTLE_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) +#if defined(__FLOAT_WORD_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && (__FLOAT_WORD_ORDER__ == __ORDER_LITTLE_ENDIAN__) +#define DUK_USE_BYTEORDER 1 +#elif defined(__FLOAT_WORD_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && (__FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__) +#define DUK_USE_BYTEORDER 2 +#elif !defined(__FLOAT_WORD_ORDER__) +/* Float word order not known, assume not a hybrid. */ +#define DUK_USE_BYTEORDER 1 +#else +/* Byte order is little endian but cannot determine IEEE double word order. */ +#endif /* float word order */ +#elif defined(__ORDER_BIG_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) +#if defined(__FLOAT_WORD_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && (__FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__) +#define DUK_USE_BYTEORDER 3 +#elif !defined(__FLOAT_WORD_ORDER__) +/* Float word order not known, assume not a hybrid. */ +#define DUK_USE_BYTEORDER 3 +#else +/* Byte order is big endian but cannot determine IEEE double word order. */ +#endif /* float word order */ +#else +/* Cannot determine byte order; __ORDER_PDP_ENDIAN__ is related to 32-bit + * integer ordering and is not relevant. + */ +#endif /* integer byte order */ +#endif /* !defined(DUK_USE_BYTEORDER) && defined(__BYTE_ORDER__) */ + +/* More or less standard endianness predefines provided by header files. + * The ARM hybrid case is detected by assuming that __FLOAT_WORD_ORDER + * will be big endian, see: http://lists.mysql.com/internals/443. + * On some platforms some defines may be present with an empty value which + * causes comparisons to fail: https://github.com/svaarala/duktape/issues/453. + */ +#if !defined(DUK_USE_BYTEORDER) +#if defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && (__BYTE_ORDER == __LITTLE_ENDIAN) || \ + defined(_BYTE_ORDER) && defined(_LITTLE_ENDIAN) && (_BYTE_ORDER == _LITTLE_ENDIAN) || \ + defined(__LITTLE_ENDIAN__) +#if defined(__FLOAT_WORD_ORDER) && defined(__LITTLE_ENDIAN) && (__FLOAT_WORD_ORDER == __LITTLE_ENDIAN) || \ + defined(_FLOAT_WORD_ORDER) && defined(_LITTLE_ENDIAN) && (_FLOAT_WORD_ORDER == _LITTLE_ENDIAN) +#define DUK_USE_BYTEORDER 1 +#elif defined(__FLOAT_WORD_ORDER) && defined(__BIG_ENDIAN) && (__FLOAT_WORD_ORDER == __BIG_ENDIAN) || \ + defined(_FLOAT_WORD_ORDER) && defined(_BIG_ENDIAN) && (_FLOAT_WORD_ORDER == _BIG_ENDIAN) +#define DUK_USE_BYTEORDER 2 +#elif !defined(__FLOAT_WORD_ORDER) && !defined(_FLOAT_WORD_ORDER) +/* Float word order not known, assume not a hybrid. */ +#define DUK_USE_BYTEORDER 1 +#else +/* Byte order is little endian but cannot determine IEEE double word order. */ +#endif /* float word order */ +#elif defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && (__BYTE_ORDER == __BIG_ENDIAN) || \ + defined(_BYTE_ORDER) && defined(_BIG_ENDIAN) && (_BYTE_ORDER == _BIG_ENDIAN) || \ + defined(__BIG_ENDIAN__) +#if defined(__FLOAT_WORD_ORDER) && defined(__BIG_ENDIAN) && (__FLOAT_WORD_ORDER == __BIG_ENDIAN) || \ + defined(_FLOAT_WORD_ORDER) && defined(_BIG_ENDIAN) && (_FLOAT_WORD_ORDER == _BIG_ENDIAN) +#define DUK_USE_BYTEORDER 3 +#elif !defined(__FLOAT_WORD_ORDER) && !defined(_FLOAT_WORD_ORDER) +/* Float word order not known, assume not a hybrid. */ +#define DUK_USE_BYTEORDER 3 +#else +/* Byte order is big endian but cannot determine IEEE double word order. */ +#endif /* float word order */ +#else +/* Cannot determine byte order. */ +#endif /* integer byte order */ +#endif /* !defined(DUK_USE_BYTEORDER) */ + +/* QNX gcc cross compiler seems to define e.g. __LITTLEENDIAN__ or __BIGENDIAN__: + * $ /opt/qnx650/host/linux/x86/usr/bin/i486-pc-nto-qnx6.5.0-gcc -dM -E - </dev/null | grep -ni endian + * 67:#define __LITTLEENDIAN__ 1 + * $ /opt/qnx650/host/linux/x86/usr/bin/mips-unknown-nto-qnx6.5.0-gcc -dM -E - </dev/null | grep -ni endian + * 81:#define __BIGENDIAN__ 1 + * $ /opt/qnx650/host/linux/x86/usr/bin/arm-unknown-nto-qnx6.5.0-gcc -dM -E - </dev/null | grep -ni endian + * 70:#define __LITTLEENDIAN__ 1 + */ +#if !defined(DUK_USE_BYTEORDER) +#if defined(__LITTLEENDIAN__) +#define DUK_USE_BYTEORDER 1 +#elif defined(__BIGENDIAN__) +#define DUK_USE_BYTEORDER 3 +#endif +#endif + +/* + * Alignment requirement and support for unaligned accesses + * + * Assume unaligned accesses are not supported unless specifically allowed + * in the target platform. Some platforms may support unaligned accesses + * but alignment to 4 or 8 may still be desirable. Note that unaligned + * accesses (and even pointers) relative to natural alignment (regardless + * of target alignment) are technically undefined behavior and thus + * compiler/architecture specific. + */ + +/* If not forced, use safe default for alignment. */ +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 8 +#endif + +/* Compiler specific hackery needed to force struct size to match alignment, + * see e.g. duk_hbuffer.h. + * + * http://stackoverflow.com/questions/11130109/c-struct-size-alignment + * http://stackoverflow.com/questions/10951039/specifying-64-bit-alignment + */ +#if !(defined(DUK_USE_PACK_MSVC_PRAGMA) || defined(DUK_USE_PACK_GCC_ATTR) || \ + defined(DUK_USE_PACK_CLANG_ATTR) || defined(DUK_USE_PACK_DUMMY_MEMBER)) +#define DUK_USE_PACK_DUMMY_MEMBER +#endif + +#if !defined(DUK_U64_CONSTANT) +#define DUK_U64_CONSTANT(x) x##ULL +#endif +#if !defined(DUK_I64_CONSTANT) +#define DUK_I64_CONSTANT(x) x##LL +#endif + +#if !defined(DUK_VA_COPY) +/* We need va_copy() which is defined in C99 / C++11, so an awkward + * replacement is needed for pre-C99 / pre-C++11 environments. This + * will quite likely need portability hacks for some non-C99 + * environments. + */ +#if defined(DUK_F_C99) || defined(DUK_F_CPP11) +/* C99 / C++11 and above: rely on va_copy() which is required. + * Omit parenthesis on macro right side on purpose to minimize differences + * to direct use. + */ +#define DUK_VA_COPY(dest,src) va_copy(dest,src) +#else +/* Pre-C99: va_list type is implementation dependent. This replacement + * assumes it is a plain value so that a simple assignment will work. + * This is not the case on all platforms (it may be a single-array element, + * for instance). + */ +#define DUK_VA_COPY(dest,src) do { (dest) = (src); } while (0) +#endif +#endif + +#if !defined(DUK_MACRO_STRINGIFY) +/* Macro hackery to convert e.g. __LINE__ to a string without formatting, + * see: http://stackoverflow.com/questions/240353/convert-a-preprocessor-token-to-a-string + */ +#define DUK_MACRO_STRINGIFY_HELPER(x) #x +#define DUK_MACRO_STRINGIFY(x) DUK_MACRO_STRINGIFY_HELPER(x) +#endif + +#if !defined(DUK_CAUSE_SEGFAULT) +/* This can be used for testing; valgrind will then indicate the C call stack + * leading to the call site. + */ +#define DUK_CAUSE_SEGFAULT() do { *((volatile duk_uint32_t *) NULL) = (duk_uint32_t) 0xdeadbeefUL; } while (0) +#endif + +#if !defined(DUK_UNREF) +/* Macro for suppressing warnings for potentially unreferenced variables. + * The variables can be actually unreferenced or unreferenced in some + * specific cases only; for instance, if a variable is only debug printed, + * it is unreferenced when debug printing is disabled. May cause warnings + * for volatile arguments. + */ +#define DUK_UNREF(x) do { (void) (x); } while (0) +#endif + +/* Fillin for DUK_NORETURN; DUK_WO_NORETURN() is used to insert dummy + * dummy statements after noreturn calls to silence harmless compiler + * warnings, e.g.: + * + * DUK_ERROR_TYPE(thr, "aiee"); + * DUK_WO_NORETURN(return 0;); + * + * Statements inside DUK_WO_NORETURN() must NEVER be actually reachable, + * and they're only included to satisfy the compiler. + */ +#if defined(DUK_NORETURN) +#define DUK_WO_NORETURN(stmt) do { } while (0) +#else +#define DUK_NORETURN(decl) decl +#define DUK_WO_NORETURN(stmt) do { stmt } while (0) +#endif + +#if defined(DUK_UNREACHABLE) +#define DUK_WO_UNREACHABLE(stmt) do { } while (0) +#else +/* Don't know how to declare unreachable point, so don't do it; this + * may cause some spurious compilation warnings (e.g. "variable used + * uninitialized"). + */ +#define DUK_UNREACHABLE() do { } while (0) +#define DUK_WO_UNREACHABLE(stmt) do { stmt } while (0) +#endif + +#if !defined(DUK_LOSE_CONST) +/* Convert any input pointer into a "void *", losing a const qualifier. + * This is not fully portable because casting through duk_uintptr_t may + * not work on all architectures (e.g. those with long, segmented pointers). + */ +#define DUK_LOSE_CONST(src) ((void *) (duk_uintptr_t) (src)) +#endif + +#if !defined(DUK_LIKELY) +#define DUK_LIKELY(x) (x) +#endif +#if !defined(DUK_UNLIKELY) +#define DUK_UNLIKELY(x) (x) +#endif +#if !defined(DUK_UNPREDICTABLE) +#define DUK_UNPREDICTABLE(x) (x) +#endif + +#if !defined(DUK_NOINLINE) +#define DUK_NOINLINE /*nop*/ +#endif +#if !defined(DUK_INLINE) +#define DUK_INLINE /*nop*/ +#endif +#if !defined(DUK_ALWAYS_INLINE) +#define DUK_ALWAYS_INLINE /*nop*/ +#endif + +#if !defined(DUK_HOT) +#define DUK_HOT /*nop*/ +#endif +#if !defined(DUK_COLD) +#define DUK_COLD /*nop*/ +#endif + +#if !defined(DUK_EXTERNAL_DECL) +#define DUK_EXTERNAL_DECL extern +#endif +#if !defined(DUK_EXTERNAL) +#define DUK_EXTERNAL /*empty*/ +#endif +#if !defined(DUK_INTERNAL_DECL) +#if defined(DUK_SINGLE_FILE) +#define DUK_INTERNAL_DECL static +#else +#define DUK_INTERNAL_DECL extern +#endif +#endif +#if !defined(DUK_INTERNAL) +#if defined(DUK_SINGLE_FILE) +#define DUK_INTERNAL static +#else +#define DUK_INTERNAL /*empty*/ +#endif +#endif +#if !defined(DUK_LOCAL_DECL) +#define DUK_LOCAL_DECL static +#endif +#if !defined(DUK_LOCAL) +#define DUK_LOCAL static +#endif + +#if !defined(DUK_FILE_MACRO) +#define DUK_FILE_MACRO __FILE__ +#endif +#if !defined(DUK_LINE_MACRO) +#define DUK_LINE_MACRO __LINE__ +#endif +#if !defined(DUK_FUNC_MACRO) +#if defined(DUK_F_C99) || defined(DUK_F_CPP11) +#define DUK_FUNC_MACRO __func__ +#elif defined(__FUNCTION__) +#define DUK_FUNC_MACRO __FUNCTION__ +#else +#define DUK_FUNC_MACRO "unknown" +#endif +#endif + +#if defined(DUK_F_HAVE_64BIT) +#if !defined(DUK_BSWAP64) +#define DUK_BSWAP64(x) \ + ((((duk_uint64_t) (x)) >> 56U) | \ + ((((duk_uint64_t) (x)) >> 40U) & DUK_U64_CONSTANT(0xff00)) | \ + ((((duk_uint64_t) (x)) >> 24U) & DUK_U64_CONSTANT(0xff0000)) | \ + ((((duk_uint64_t) (x)) >> 8U) & DUK_U64_CONSTANT(0xff000000)) | \ + ((((duk_uint64_t) (x)) << 8U) & DUK_U64_CONSTANT(0xff00000000)) | \ + ((((duk_uint64_t) (x)) << 24U) & DUK_U64_CONSTANT(0xff0000000000)) | \ + ((((duk_uint64_t) (x)) << 40U) & DUK_U64_CONSTANT(0xff000000000000)) | \ + (((duk_uint64_t) (x)) << 56U)) +#endif +#endif +#if !defined(DUK_BSWAP32) +#define DUK_BSWAP32(x) \ + ((((duk_uint32_t) (x)) >> 24U) | \ + ((((duk_uint32_t) (x)) >> 8U) & 0xff00UL) | \ + ((((duk_uint32_t) (x)) << 8U) & 0xff0000UL) | \ + (((duk_uint32_t) (x)) << 24U)) +#endif +#if !defined(DUK_BSWAP16) +#define DUK_BSWAP16(x) \ + ((duk_uint16_t) (x) >> 8U) | \ + ((duk_uint16_t) (x) << 8U) +#endif + +/* DUK_USE_VARIADIC_MACROS: required from compilers, so no fill-in. */ +/* DUK_USE_UNION_INITIALIZERS: required from compilers, so no fill-in. */ + +#if !(defined(DUK_USE_FLEX_C99) || defined(DUK_USE_FLEX_ZEROSIZE) || defined(DUK_USE_FLEX_ONESIZE)) +#if defined(DUK_F_C99) +#define DUK_USE_FLEX_C99 +#else +#define DUK_USE_FLEX_ZEROSIZE /* Not standard but common enough */ +#endif +#endif + +#if !(defined(DUK_USE_PACK_GCC_ATTR) || defined(DUK_USE_PACK_CLANG_ATTR) || \ + defined(DUK_USE_PACK_MSVC_PRAGMA) || defined(DUK_USE_PACK_DUMMY_MEMBER)) +#define DUK_USE_PACK_DUMMY_MEMBER +#endif + +#if 0 /* not defined by default */ +#undef DUK_USE_GCC_PRAGMAS +#endif + +/* Workaround for GH-323: avoid inlining control when compiling from + * multiple sources, as it causes compiler portability trouble. + */ +#if !defined(DUK_SINGLE_FILE) +#undef DUK_NOINLINE +#undef DUK_INLINE +#undef DUK_ALWAYS_INLINE +#define DUK_NOINLINE /*nop*/ +#define DUK_INLINE /*nop*/ +#define DUK_ALWAYS_INLINE /*nop*/ +#endif + +/* + * Check whether or not a packed duk_tval representation is possible. + * What's basically required is that pointers are 32-bit values + * (sizeof(void *) == 4). Best effort check, not always accurate. + * If guess goes wrong, crashes may result; self tests also verify + * the guess. + */ + +/* Explicit marker needed; may be 'defined', 'undefined, 'or 'not provided'. */ +#if !defined(DUK_F_PACKED_TVAL_PROVIDED) +#undef DUK_F_PACKED_TVAL_POSSIBLE + +/* Strict C99 case: DUK_UINTPTR_MAX (= UINTPTR_MAX) should be very reliable */ +#if !defined(DUK_F_PACKED_TVAL_POSSIBLE) && defined(DUK_UINTPTR_MAX) +#if (DUK_UINTPTR_MAX <= 0xffffffffUL) +#define DUK_F_PACKED_TVAL_POSSIBLE +#endif +#endif + +/* Non-C99 case, still relying on DUK_UINTPTR_MAX, as long as it is not a computed value */ +#if !defined(DUK_F_PACKED_TVAL_POSSIBLE) && defined(DUK_UINTPTR_MAX) && !defined(DUK_UINTPTR_MAX_COMPUTED) +#if (DUK_UINTPTR_MAX <= 0xffffffffUL) +#define DUK_F_PACKED_TVAL_POSSIBLE +#endif +#endif + +/* DUK_SIZE_MAX (= SIZE_MAX) is often reliable */ +#if !defined(DUK_F_PACKED_TVAL_POSSIBLE) && defined(DUK_SIZE_MAX) && !defined(DUK_SIZE_MAX_COMPUTED) +#if (DUK_SIZE_MAX <= 0xffffffffUL) +#define DUK_F_PACKED_TVAL_POSSIBLE +#endif +#endif + +#undef DUK_USE_PACKED_TVAL +#if defined(DUK_F_PACKED_TVAL_POSSIBLE) +#define DUK_USE_PACKED_TVAL +#endif +#undef DUK_F_PACKED_TVAL_POSSIBLE + +#endif /* DUK_F_PACKED_TVAL_PROVIDED */ +/* Object property allocation layout has implications for memory and code + * footprint and generated code size/speed. The best layout also depends + * on whether the platform has alignment requirements or benefits from + * having mostly aligned accesses. + */ +#undef DUK_USE_HOBJECT_LAYOUT_1 +#undef DUK_USE_HOBJECT_LAYOUT_2 +#undef DUK_USE_HOBJECT_LAYOUT_3 +#if (DUK_USE_ALIGN_BY == 1) +/* On platforms without any alignment issues, layout 1 is preferable + * because it compiles to slightly less code and provides direct access + * to property keys. + */ +#define DUK_USE_HOBJECT_LAYOUT_1 +#else +/* On other platforms use layout 2, which requires some padding but + * is a bit more natural than layout 3 in ordering the entries. Layout + * 3 is currently not used. + */ +#define DUK_USE_HOBJECT_LAYOUT_2 +#endif + +/* GCC/clang inaccurate math would break compliance and probably duk_tval, + * so refuse to compile. Relax this if -ffast-math is tested to work. + */ +#if defined(__FAST_MATH__) +#error __FAST_MATH__ defined, refusing to compile +#endif + +/* + * Autogenerated defaults + */ + +#undef DUK_USE_ALLOW_UNDEFINED_BEHAVIOR +#define DUK_USE_ARRAY_BUILTIN +#define DUK_USE_ARRAY_FASTPATH +#define DUK_USE_ARRAY_PROP_FASTPATH +#undef DUK_USE_ASSERTIONS +#define DUK_USE_AUGMENT_ERROR_CREATE +#define DUK_USE_AUGMENT_ERROR_THROW +#define DUK_USE_AVOID_PLATFORM_FUNCPTRS +#define DUK_USE_BASE64_FASTPATH +#define DUK_USE_BASE64_SUPPORT +#define DUK_USE_BOOLEAN_BUILTIN +#define DUK_USE_BUFFEROBJECT_SUPPORT +#undef DUK_USE_BUFLEN16 +#define DUK_USE_BYTECODE_DUMP_SUPPORT +#define DUK_USE_CACHE_ACTIVATION +#define DUK_USE_CACHE_CATCHER +#define DUK_USE_CALLSTACK_LIMIT 10000 +#define DUK_USE_CBOR_BUILTIN +#define DUK_USE_CBOR_SUPPORT +#define DUK_USE_COMPILER_RECLIMIT 2500 +#define DUK_USE_COROUTINE_SUPPORT +#undef DUK_USE_CPP_EXCEPTIONS +#undef DUK_USE_DATAPTR16 +#undef DUK_USE_DATAPTR_DEC16 +#undef DUK_USE_DATAPTR_ENC16 +#define DUK_USE_DATE_BUILTIN +#undef DUK_USE_DATE_FORMAT_STRING +#undef DUK_USE_DATE_GET_LOCAL_TZOFFSET +#undef DUK_USE_DATE_GET_NOW +#undef DUK_USE_DATE_PARSE_STRING +#undef DUK_USE_DATE_PRS_GETDATE +#undef DUK_USE_DEBUG +#undef DUK_USE_DEBUGGER_DUMPHEAP +#undef DUK_USE_DEBUGGER_INSPECT +#undef DUK_USE_DEBUGGER_PAUSE_UNCAUGHT +#undef DUK_USE_DEBUGGER_SUPPORT +#define DUK_USE_DEBUGGER_THROW_NOTIFY +#undef DUK_USE_DEBUGGER_TRANSPORT_TORTURE +#define DUK_USE_DEBUG_BUFSIZE 65536L +#define DUK_USE_DEBUG_LEVEL 0 +#undef DUK_USE_DEBUG_WRITE +#define DUK_USE_DOUBLE_LINKED_HEAP +#define DUK_USE_DUKTAPE_BUILTIN +#define DUK_USE_ENCODING_BUILTINS +#define DUK_USE_ERRCREATE +#define DUK_USE_ERRTHROW +#define DUK_USE_ES6 +#define DUK_USE_ES6_OBJECT_PROTO_PROPERTY +#define DUK_USE_ES6_OBJECT_SETPROTOTYPEOF +#define DUK_USE_ES6_PROXY +#define DUK_USE_ES6_REGEXP_SYNTAX +#define DUK_USE_ES6_UNICODE_ESCAPE +#define DUK_USE_ES7 +#define DUK_USE_ES7_EXP_OPERATOR +#define DUK_USE_ES8 +#define DUK_USE_ES9 +#define DUK_USE_ESBC_LIMITS +#define DUK_USE_ESBC_MAX_BYTES 2147418112L +#define DUK_USE_ESBC_MAX_LINENUMBER 2147418112L +#undef DUK_USE_EXEC_FUN_LOCAL +#undef DUK_USE_EXEC_INDIRECT_BOUND_CHECK +#undef DUK_USE_EXEC_PREFER_SIZE +#define DUK_USE_EXEC_REGCONST_OPTIMIZE +#undef DUK_USE_EXEC_TIMEOUT_CHECK +#undef DUK_USE_EXPLICIT_NULL_INIT +#undef DUK_USE_EXTSTR_FREE +#undef DUK_USE_EXTSTR_INTERN_CHECK +#undef DUK_USE_FASTINT +#define DUK_USE_FAST_REFCOUNT_DEFAULT +#undef DUK_USE_FATAL_HANDLER +#define DUK_USE_FATAL_MAXLEN 128 +#define DUK_USE_FINALIZER_SUPPORT +#undef DUK_USE_FINALIZER_TORTURE +#undef DUK_USE_FUNCPTR16 +#undef DUK_USE_FUNCPTR_DEC16 +#undef DUK_USE_FUNCPTR_ENC16 +#define DUK_USE_FUNCTION_BUILTIN +#define DUK_USE_FUNC_FILENAME_PROPERTY +#define DUK_USE_FUNC_NAME_PROPERTY +#undef DUK_USE_GC_TORTURE +#undef DUK_USE_GET_MONOTONIC_TIME +#undef DUK_USE_GET_RANDOM_DOUBLE +#define DUK_USE_GLOBAL_BINDING +#define DUK_USE_GLOBAL_BUILTIN +#undef DUK_USE_HEAPPTR16 +#undef DUK_USE_HEAPPTR_DEC16 +#undef DUK_USE_HEAPPTR_ENC16 +#define DUK_USE_HEX_FASTPATH +#define DUK_USE_HEX_SUPPORT +#define DUK_USE_HOBJECT_ARRAY_ABANDON_LIMIT 2 +#define DUK_USE_HOBJECT_ARRAY_ABANDON_MINSIZE 257 +#define DUK_USE_HOBJECT_ARRAY_FAST_RESIZE_LIMIT 9 +#define DUK_USE_HOBJECT_ARRAY_MINGROW_ADD 16 +#define DUK_USE_HOBJECT_ARRAY_MINGROW_DIVISOR 8 +#define DUK_USE_HOBJECT_ENTRY_MINGROW_ADD 16 +#define DUK_USE_HOBJECT_ENTRY_MINGROW_DIVISOR 8 +#define DUK_USE_HOBJECT_HASH_PART +#define DUK_USE_HOBJECT_HASH_PROP_LIMIT 8 +#define DUK_USE_HSTRING_ARRIDX +#define DUK_USE_HSTRING_CLEN +#undef DUK_USE_HSTRING_EXTDATA +#define DUK_USE_HSTRING_LAZY_CLEN +#define DUK_USE_HTML_COMMENTS +#define DUK_USE_IDCHAR_FASTPATH +#undef DUK_USE_INJECT_HEAP_ALLOC_ERROR +#undef DUK_USE_INTERRUPT_COUNTER +#undef DUK_USE_INTERRUPT_DEBUG_FIXUP +#define DUK_USE_JC +#define DUK_USE_JSON_BUILTIN +#define DUK_USE_JSON_DECNUMBER_FASTPATH +#define DUK_USE_JSON_DECSTRING_FASTPATH +#define DUK_USE_JSON_DEC_RECLIMIT 1000 +#define DUK_USE_JSON_EATWHITE_FASTPATH +#define DUK_USE_JSON_ENC_RECLIMIT 1000 +#define DUK_USE_JSON_QUOTESTRING_FASTPATH +#undef DUK_USE_JSON_STRINGIFY_FASTPATH +#define DUK_USE_JSON_SUPPORT +#define DUK_USE_JX +#define DUK_USE_LEXER_SLIDING_WINDOW +#undef DUK_USE_LIGHTFUNC_BUILTINS +#define DUK_USE_LITCACHE_SIZE 256 +#define DUK_USE_MARK_AND_SWEEP_RECLIMIT 256 +#define DUK_USE_MATH_BUILTIN +#define DUK_USE_NATIVE_CALL_RECLIMIT 1000 +#undef DUK_USE_NATIVE_STACK_CHECK +#define DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT +#undef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY +#undef DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY +#define DUK_USE_NONSTD_FUNC_STMT +#define DUK_USE_NONSTD_GETTER_KEY_ARGUMENT +#define DUK_USE_NONSTD_JSON_ESC_U2028_U2029 +#define DUK_USE_NONSTD_SETTER_KEY_ARGUMENT +#define DUK_USE_NONSTD_STRING_FROMCHARCODE_32BIT +#define DUK_USE_NUMBER_BUILTIN +#define DUK_USE_OBJECT_BUILTIN +#undef DUK_USE_OBJSIZES16 +#undef DUK_USE_PARANOID_ERRORS +#define DUK_USE_PC2LINE +#define DUK_USE_PERFORMANCE_BUILTIN +#undef DUK_USE_PREFER_SIZE +#undef DUK_USE_PROMISE_BUILTIN +#define DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS +#undef DUK_USE_REFCOUNT16 +#define DUK_USE_REFCOUNT32 +#define DUK_USE_REFERENCE_COUNTING +#define DUK_USE_REFLECT_BUILTIN +#define DUK_USE_REGEXP_CANON_BITMAP +#undef DUK_USE_REGEXP_CANON_WORKAROUND +#define DUK_USE_REGEXP_COMPILER_RECLIMIT 10000 +#define DUK_USE_REGEXP_EXECUTOR_RECLIMIT 10000 +#define DUK_USE_REGEXP_SUPPORT +#undef DUK_USE_ROM_GLOBAL_CLONE +#undef DUK_USE_ROM_GLOBAL_INHERIT +#undef DUK_USE_ROM_OBJECTS +#define DUK_USE_ROM_PTRCOMP_FIRST 63488L +#undef DUK_USE_ROM_STRINGS +#define DUK_USE_SECTION_B +#undef DUK_USE_SELF_TESTS +#define DUK_USE_SHEBANG_COMMENTS +#undef DUK_USE_SHUFFLE_TORTURE +#define DUK_USE_SOURCE_NONBMP +#undef DUK_USE_STRHASH16 +#undef DUK_USE_STRHASH_DENSE +#define DUK_USE_STRHASH_SKIP_SHIFT 5 +#define DUK_USE_STRICT_DECL +#undef DUK_USE_STRICT_UTF8_SOURCE +#define DUK_USE_STRING_BUILTIN +#undef DUK_USE_STRLEN16 +#define DUK_USE_STRTAB_GROW_LIMIT 17 +#define DUK_USE_STRTAB_MAXSIZE 268435456L +#define DUK_USE_STRTAB_MINSIZE 1024 +#undef DUK_USE_STRTAB_PTRCOMP +#define DUK_USE_STRTAB_RESIZE_CHECK_MASK 255 +#define DUK_USE_STRTAB_SHRINK_LIMIT 6 +#undef DUK_USE_STRTAB_TORTURE +#define DUK_USE_SYMBOL_BUILTIN +#define DUK_USE_TAILCALL +#define DUK_USE_TARGET_INFO "unknown" +#define DUK_USE_TRACEBACKS +#define DUK_USE_TRACEBACK_DEPTH 10 +#define DUK_USE_VALSTACK_GROW_SHIFT 2 +#define DUK_USE_VALSTACK_LIMIT 1000000L +#define DUK_USE_VALSTACK_SHRINK_CHECK_SHIFT 2 +#define DUK_USE_VALSTACK_SHRINK_SLACK_SHIFT 4 +#undef DUK_USE_VALSTACK_UNSAFE +#define DUK_USE_VERBOSE_ERRORS +#define DUK_USE_VERBOSE_EXECUTOR_ERRORS +#define DUK_USE_VOLUNTARY_GC +#define DUK_USE_ZERO_BUFFER_DATA + +/* + * You may add overriding #define/#undef directives below for + * customization. You of course cannot un-#include or un-typedef + * anything; these require direct changes above. + */ + +/* __OVERRIDE_DEFINES__ */ + +/* + * Conditional includes + */ + +#if defined(DUK_F_CPP) && defined(DUK_USE_CPP_EXCEPTIONS) +#include <exception> /* std::exception */ +#include <stdexcept> /* std::runtime_error */ +#endif + +/* + * Date provider selection + * + * User may define DUK_USE_DATE_GET_NOW() etc directly, in which case we'll + * rely on an external provider. If this is not done, revert to previous + * behavior and use Unix/Windows built-in provider. + */ + +#if defined(DUK_COMPILING_DUKTAPE) + +#if defined(DUK_USE_DATE_GET_NOW) +/* External provider already defined. */ +#elif defined(DUK_USE_DATE_NOW_GETTIMEOFDAY) +#define DUK_USE_DATE_GET_NOW(ctx) duk_bi_date_get_now_gettimeofday() +#elif defined(DUK_USE_DATE_NOW_TIME) +#define DUK_USE_DATE_GET_NOW(ctx) duk_bi_date_get_now_time() +#elif defined(DUK_USE_DATE_NOW_WINDOWS) +#define DUK_USE_DATE_GET_NOW(ctx) duk_bi_date_get_now_windows() +#elif defined(DUK_USE_DATE_NOW_WINDOWS_SUBMS) +#define DUK_USE_DATE_GET_NOW(ctx) duk_bi_date_get_now_windows_subms() +#else +#error no provider for DUK_USE_DATE_GET_NOW() +#endif + +#if defined(DUK_USE_DATE_GET_LOCAL_TZOFFSET) +/* External provider already defined. */ +#elif defined(DUK_USE_DATE_TZO_GMTIME_R) || defined(DUK_USE_DATE_TZO_GMTIME_S) || defined(DUK_USE_DATE_TZO_GMTIME) +#define DUK_USE_DATE_GET_LOCAL_TZOFFSET(d) duk_bi_date_get_local_tzoffset_gmtime((d)) +#elif defined(DUK_USE_DATE_TZO_WINDOWS) +#define DUK_USE_DATE_GET_LOCAL_TZOFFSET(d) duk_bi_date_get_local_tzoffset_windows((d)) +#elif defined(DUK_USE_DATE_TZO_WINDOWS_NO_DST) +#define DUK_USE_DATE_GET_LOCAL_TZOFFSET(d) duk_bi_date_get_local_tzoffset_windows_no_dst((d)) +#else +#error no provider for DUK_USE_DATE_GET_LOCAL_TZOFFSET() +#endif + +#if defined(DUK_USE_DATE_PARSE_STRING) +/* External provider already defined. */ +#elif defined(DUK_USE_DATE_PRS_STRPTIME) +#define DUK_USE_DATE_PARSE_STRING(ctx,str) duk_bi_date_parse_string_strptime((ctx), (str)) +#elif defined(DUK_USE_DATE_PRS_GETDATE) +#define DUK_USE_DATE_PARSE_STRING(ctx,str) duk_bi_date_parse_string_getdate((ctx), (str)) +#else +/* No provider for DUK_USE_DATE_PARSE_STRING(), fall back to ISO 8601 only. */ +#endif + +#if defined(DUK_USE_DATE_FORMAT_STRING) +/* External provider already defined. */ +#elif defined(DUK_USE_DATE_FMT_STRFTIME) +#define DUK_USE_DATE_FORMAT_STRING(ctx,parts,tzoffset,flags) \ + duk_bi_date_format_parts_strftime((ctx), (parts), (tzoffset), (flags)) +#else +/* No provider for DUK_USE_DATE_FORMAT_STRING(), fall back to ISO 8601 only. */ +#endif + +#if defined(DUK_USE_GET_MONOTONIC_TIME) +/* External provider already defined. */ +#elif defined(DUK_USE_GET_MONOTONIC_TIME_CLOCK_GETTIME) +#define DUK_USE_GET_MONOTONIC_TIME(ctx) duk_bi_date_get_monotonic_time_clock_gettime() +#elif defined(DUK_USE_GET_MONOTONIC_TIME_WINDOWS_QPC) +#define DUK_USE_GET_MONOTONIC_TIME(ctx) duk_bi_date_get_monotonic_time_windows_qpc() +#else +/* No provider for DUK_USE_GET_MONOTONIC_TIME(), fall back to DUK_USE_DATE_GET_NOW(). */ +#endif + +#endif /* DUK_COMPILING_DUKTAPE */ + +/* + * Checks for legacy feature options (DUK_OPT_xxx) + */ + +#if defined(DUK_OPT_ASSERTIONS) +#error unsupported legacy feature option DUK_OPT_ASSERTIONS used +#endif +#if defined(DUK_OPT_BUFFEROBJECT_SUPPORT) +#error unsupported legacy feature option DUK_OPT_BUFFEROBJECT_SUPPORT used +#endif +#if defined(DUK_OPT_BUFLEN16) +#error unsupported legacy feature option DUK_OPT_BUFLEN16 used +#endif +#if defined(DUK_OPT_DATAPTR16) +#error unsupported legacy feature option DUK_OPT_DATAPTR16 used +#endif +#if defined(DUK_OPT_DATAPTR_DEC16) +#error unsupported legacy feature option DUK_OPT_DATAPTR_DEC16 used +#endif +#if defined(DUK_OPT_DATAPTR_ENC16) +#error unsupported legacy feature option DUK_OPT_DATAPTR_ENC16 used +#endif +#if defined(DUK_OPT_DDDPRINT) +#error unsupported legacy feature option DUK_OPT_DDDPRINT used +#endif +#if defined(DUK_OPT_DDPRINT) +#error unsupported legacy feature option DUK_OPT_DDPRINT used +#endif +#if defined(DUK_OPT_DEBUG) +#error unsupported legacy feature option DUK_OPT_DEBUG used +#endif +#if defined(DUK_OPT_DEBUGGER_DUMPHEAP) +#error unsupported legacy feature option DUK_OPT_DEBUGGER_DUMPHEAP used +#endif +#if defined(DUK_OPT_DEBUGGER_FWD_LOGGING) +#error unsupported legacy feature option DUK_OPT_DEBUGGER_FWD_LOGGING used +#endif +#if defined(DUK_OPT_DEBUGGER_FWD_PRINTALERT) +#error unsupported legacy feature option DUK_OPT_DEBUGGER_FWD_PRINTALERT used +#endif +#if defined(DUK_OPT_DEBUGGER_SUPPORT) +#error unsupported legacy feature option DUK_OPT_DEBUGGER_SUPPORT used +#endif +#if defined(DUK_OPT_DEBUGGER_TRANSPORT_TORTURE) +#error unsupported legacy feature option DUK_OPT_DEBUGGER_TRANSPORT_TORTURE used +#endif +#if defined(DUK_OPT_DEBUG_BUFSIZE) +#error unsupported legacy feature option DUK_OPT_DEBUG_BUFSIZE used +#endif +#if defined(DUK_OPT_DECLARE) +#error unsupported legacy feature option DUK_OPT_DECLARE used +#endif +#if defined(DUK_OPT_DEEP_C_STACK) +#error unsupported legacy feature option DUK_OPT_DEEP_C_STACK used +#endif +#if defined(DUK_OPT_DLL_BUILD) +#error unsupported legacy feature option DUK_OPT_DLL_BUILD used +#endif +#if defined(DUK_OPT_DPRINT) +#error unsupported legacy feature option DUK_OPT_DPRINT used +#endif +#if defined(DUK_OPT_DPRINT_COLORS) +#error unsupported legacy feature option DUK_OPT_DPRINT_COLORS used +#endif +#if defined(DUK_OPT_DPRINT_RDTSC) +#error unsupported legacy feature option DUK_OPT_DPRINT_RDTSC used +#endif +#if defined(DUK_OPT_EXEC_TIMEOUT_CHECK) +#error unsupported legacy feature option DUK_OPT_EXEC_TIMEOUT_CHECK used +#endif +#if defined(DUK_OPT_EXTERNAL_STRINGS) +#error unsupported legacy feature option DUK_OPT_EXTERNAL_STRINGS used +#endif +#if defined(DUK_OPT_EXTSTR_FREE) +#error unsupported legacy feature option DUK_OPT_EXTSTR_FREE used +#endif +#if defined(DUK_OPT_EXTSTR_INTERN_CHECK) +#error unsupported legacy feature option DUK_OPT_EXTSTR_INTERN_CHECK used +#endif +#if defined(DUK_OPT_FASTINT) +#error unsupported legacy feature option DUK_OPT_FASTINT used +#endif +#if defined(DUK_OPT_FORCE_ALIGN) +#error unsupported legacy feature option DUK_OPT_FORCE_ALIGN used +#endif +#if defined(DUK_OPT_FORCE_BYTEORDER) +#error unsupported legacy feature option DUK_OPT_FORCE_BYTEORDER used +#endif +#if defined(DUK_OPT_FUNCPTR16) +#error unsupported legacy feature option DUK_OPT_FUNCPTR16 used +#endif +#if defined(DUK_OPT_FUNCPTR_DEC16) +#error unsupported legacy feature option DUK_OPT_FUNCPTR_DEC16 used +#endif +#if defined(DUK_OPT_FUNCPTR_ENC16) +#error unsupported legacy feature option DUK_OPT_FUNCPTR_ENC16 used +#endif +#if defined(DUK_OPT_FUNC_NONSTD_CALLER_PROPERTY) +#error unsupported legacy feature option DUK_OPT_FUNC_NONSTD_CALLER_PROPERTY used +#endif +#if defined(DUK_OPT_FUNC_NONSTD_SOURCE_PROPERTY) +#error unsupported legacy feature option DUK_OPT_FUNC_NONSTD_SOURCE_PROPERTY used +#endif +#if defined(DUK_OPT_GC_TORTURE) +#error unsupported legacy feature option DUK_OPT_GC_TORTURE used +#endif +#if defined(DUK_OPT_HAVE_CUSTOM_H) +#error unsupported legacy feature option DUK_OPT_HAVE_CUSTOM_H used +#endif +#if defined(DUK_OPT_HEAPPTR16) +#error unsupported legacy feature option DUK_OPT_HEAPPTR16 used +#endif +#if defined(DUK_OPT_HEAPPTR_DEC16) +#error unsupported legacy feature option DUK_OPT_HEAPPTR_DEC16 used +#endif +#if defined(DUK_OPT_HEAPPTR_ENC16) +#error unsupported legacy feature option DUK_OPT_HEAPPTR_ENC16 used +#endif +#if defined(DUK_OPT_INTERRUPT_COUNTER) +#error unsupported legacy feature option DUK_OPT_INTERRUPT_COUNTER used +#endif +#if defined(DUK_OPT_JSON_STRINGIFY_FASTPATH) +#error unsupported legacy feature option DUK_OPT_JSON_STRINGIFY_FASTPATH used +#endif +#if defined(DUK_OPT_LIGHTFUNC_BUILTINS) +#error unsupported legacy feature option DUK_OPT_LIGHTFUNC_BUILTINS used +#endif +#if defined(DUK_OPT_NONSTD_FUNC_CALLER_PROPERTY) +#error unsupported legacy feature option DUK_OPT_NONSTD_FUNC_CALLER_PROPERTY used +#endif +#if defined(DUK_OPT_NONSTD_FUNC_SOURCE_PROPERTY) +#error unsupported legacy feature option DUK_OPT_NONSTD_FUNC_SOURCE_PROPERTY used +#endif +#if defined(DUK_OPT_NO_ARRAY_SPLICE_NONSTD_DELCOUNT) +#error unsupported legacy feature option DUK_OPT_NO_ARRAY_SPLICE_NONSTD_DELCOUNT used +#endif +#if defined(DUK_OPT_NO_AUGMENT_ERRORS) +#error unsupported legacy feature option DUK_OPT_NO_AUGMENT_ERRORS used +#endif +#if defined(DUK_OPT_NO_BROWSER_LIKE) +#error unsupported legacy feature option DUK_OPT_NO_BROWSER_LIKE used +#endif +#if defined(DUK_OPT_NO_BUFFEROBJECT_SUPPORT) +#error unsupported legacy feature option DUK_OPT_NO_BUFFEROBJECT_SUPPORT used +#endif +#if defined(DUK_OPT_NO_BYTECODE_DUMP_SUPPORT) +#error unsupported legacy feature option DUK_OPT_NO_BYTECODE_DUMP_SUPPORT used +#endif +#if defined(DUK_OPT_NO_COMMONJS_MODULES) +#error unsupported legacy feature option DUK_OPT_NO_COMMONJS_MODULES used +#endif +#if defined(DUK_OPT_NO_ES6_OBJECT_PROTO_PROPERTY) +#error unsupported legacy feature option DUK_OPT_NO_ES6_OBJECT_PROTO_PROPERTY used +#endif +#if defined(DUK_OPT_NO_ES6_OBJECT_SETPROTOTYPEOF) +#error unsupported legacy feature option DUK_OPT_NO_ES6_OBJECT_SETPROTOTYPEOF used +#endif +#if defined(DUK_OPT_NO_ES6_PROXY) +#error unsupported legacy feature option DUK_OPT_NO_ES6_PROXY used +#endif +#if defined(DUK_OPT_NO_FILE_IO) +#error unsupported legacy feature option DUK_OPT_NO_FILE_IO used +#endif +#if defined(DUK_OPT_NO_FUNC_STMT) +#error unsupported legacy feature option DUK_OPT_NO_FUNC_STMT used +#endif +#if defined(DUK_OPT_NO_JC) +#error unsupported legacy feature option DUK_OPT_NO_JC used +#endif +#if defined(DUK_OPT_NO_JSONC) +#error unsupported legacy feature option DUK_OPT_NO_JSONC used +#endif +#if defined(DUK_OPT_NO_JSONX) +#error unsupported legacy feature option DUK_OPT_NO_JSONX used +#endif +#if defined(DUK_OPT_NO_JX) +#error unsupported legacy feature option DUK_OPT_NO_JX used +#endif +#if defined(DUK_OPT_NO_MARK_AND_SWEEP) +#error unsupported legacy feature option DUK_OPT_NO_MARK_AND_SWEEP used +#endif +#if defined(DUK_OPT_NO_MS_STRINGTABLE_RESIZE) +#error unsupported legacy feature option DUK_OPT_NO_MS_STRINGTABLE_RESIZE used +#endif +#if defined(DUK_OPT_NO_NONSTD_ACCESSOR_KEY_ARGUMENT) +#error unsupported legacy feature option DUK_OPT_NO_NONSTD_ACCESSOR_KEY_ARGUMENT used +#endif +#if defined(DUK_OPT_NO_NONSTD_ARRAY_CONCAT_TRAILER) +#error unsupported legacy feature option DUK_OPT_NO_NONSTD_ARRAY_CONCAT_TRAILER used +#endif +#if defined(DUK_OPT_NO_NONSTD_ARRAY_MAP_TRAILER) +#error unsupported legacy feature option DUK_OPT_NO_NONSTD_ARRAY_MAP_TRAILER used +#endif +#if defined(DUK_OPT_NO_NONSTD_ARRAY_SPLICE_DELCOUNT) +#error unsupported legacy feature option DUK_OPT_NO_NONSTD_ARRAY_SPLICE_DELCOUNT used +#endif +#if defined(DUK_OPT_NO_NONSTD_FUNC_STMT) +#error unsupported legacy feature option DUK_OPT_NO_NONSTD_FUNC_STMT used +#endif +#if defined(DUK_OPT_NO_NONSTD_JSON_ESC_U2028_U2029) +#error unsupported legacy feature option DUK_OPT_NO_NONSTD_JSON_ESC_U2028_U2029 used +#endif +#if defined(DUK_OPT_NO_NONSTD_STRING_FROMCHARCODE_32BIT) +#error unsupported legacy feature option DUK_OPT_NO_NONSTD_STRING_FROMCHARCODE_32BIT used +#endif +#if defined(DUK_OPT_NO_OBJECT_ES6_PROTO_PROPERTY) +#error unsupported legacy feature option DUK_OPT_NO_OBJECT_ES6_PROTO_PROPERTY used +#endif +#if defined(DUK_OPT_NO_OBJECT_ES6_SETPROTOTYPEOF) +#error unsupported legacy feature option DUK_OPT_NO_OBJECT_ES6_SETPROTOTYPEOF used +#endif +#if defined(DUK_OPT_NO_OCTAL_SUPPORT) +#error unsupported legacy feature option DUK_OPT_NO_OCTAL_SUPPORT used +#endif +#if defined(DUK_OPT_NO_PACKED_TVAL) +#error unsupported legacy feature option DUK_OPT_NO_PACKED_TVAL used +#endif +#if defined(DUK_OPT_NO_PC2LINE) +#error unsupported legacy feature option DUK_OPT_NO_PC2LINE used +#endif +#if defined(DUK_OPT_NO_REFERENCE_COUNTING) +#error unsupported legacy feature option DUK_OPT_NO_REFERENCE_COUNTING used +#endif +#if defined(DUK_OPT_NO_REGEXP_SUPPORT) +#error unsupported legacy feature option DUK_OPT_NO_REGEXP_SUPPORT used +#endif +#if defined(DUK_OPT_NO_SECTION_B) +#error unsupported legacy feature option DUK_OPT_NO_SECTION_B used +#endif +#if defined(DUK_OPT_NO_SOURCE_NONBMP) +#error unsupported legacy feature option DUK_OPT_NO_SOURCE_NONBMP used +#endif +#if defined(DUK_OPT_NO_STRICT_DECL) +#error unsupported legacy feature option DUK_OPT_NO_STRICT_DECL used +#endif +#if defined(DUK_OPT_NO_TRACEBACKS) +#error unsupported legacy feature option DUK_OPT_NO_TRACEBACKS used +#endif +#if defined(DUK_OPT_NO_VERBOSE_ERRORS) +#error unsupported legacy feature option DUK_OPT_NO_VERBOSE_ERRORS used +#endif +#if defined(DUK_OPT_NO_VOLUNTARY_GC) +#error unsupported legacy feature option DUK_OPT_NO_VOLUNTARY_GC used +#endif +#if defined(DUK_OPT_NO_ZERO_BUFFER_DATA) +#error unsupported legacy feature option DUK_OPT_NO_ZERO_BUFFER_DATA used +#endif +#if defined(DUK_OPT_OBJSIZES16) +#error unsupported legacy feature option DUK_OPT_OBJSIZES16 used +#endif +#if defined(DUK_OPT_PANIC_HANDLER) +#error unsupported legacy feature option DUK_OPT_PANIC_HANDLER used +#endif +#if defined(DUK_OPT_REFCOUNT16) +#error unsupported legacy feature option DUK_OPT_REFCOUNT16 used +#endif +#if defined(DUK_OPT_SEGFAULT_ON_PANIC) +#error unsupported legacy feature option DUK_OPT_SEGFAULT_ON_PANIC used +#endif +#if defined(DUK_OPT_SELF_TESTS) +#error unsupported legacy feature option DUK_OPT_SELF_TESTS used +#endif +#if defined(DUK_OPT_SETJMP) +#error unsupported legacy feature option DUK_OPT_SETJMP used +#endif +#if defined(DUK_OPT_SHUFFLE_TORTURE) +#error unsupported legacy feature option DUK_OPT_SHUFFLE_TORTURE used +#endif +#if defined(DUK_OPT_SIGSETJMP) +#error unsupported legacy feature option DUK_OPT_SIGSETJMP used +#endif +#if defined(DUK_OPT_STRHASH16) +#error unsupported legacy feature option DUK_OPT_STRHASH16 used +#endif +#if defined(DUK_OPT_STRICT_UTF8_SOURCE) +#error unsupported legacy feature option DUK_OPT_STRICT_UTF8_SOURCE used +#endif +#if defined(DUK_OPT_STRLEN16) +#error unsupported legacy feature option DUK_OPT_STRLEN16 used +#endif +#if defined(DUK_OPT_STRTAB_CHAIN) +#error unsupported legacy feature option DUK_OPT_STRTAB_CHAIN used +#endif +#if defined(DUK_OPT_STRTAB_CHAIN_SIZE) +#error unsupported legacy feature option DUK_OPT_STRTAB_CHAIN_SIZE used +#endif +#if defined(DUK_OPT_TARGET_INFO) +#error unsupported legacy feature option DUK_OPT_TARGET_INFO used +#endif +#if defined(DUK_OPT_TRACEBACK_DEPTH) +#error unsupported legacy feature option DUK_OPT_TRACEBACK_DEPTH used +#endif +#if defined(DUK_OPT_UNDERSCORE_SETJMP) +#error unsupported legacy feature option DUK_OPT_UNDERSCORE_SETJMP used +#endif +#if defined(DUK_OPT_USER_INITJS) +#error unsupported legacy feature option DUK_OPT_USER_INITJS used +#endif + +/* + * Checks for config option consistency (DUK_USE_xxx) + */ + +#if defined(DUK_USE_32BIT_PTRS) +#error unsupported config option used (option has been removed): DUK_USE_32BIT_PTRS +#endif +#if defined(DUK_USE_ALIGN_4) +#error unsupported config option used (option has been removed): DUK_USE_ALIGN_4 +#endif +#if defined(DUK_USE_ALIGN_8) +#error unsupported config option used (option has been removed): DUK_USE_ALIGN_8 +#endif +#if defined(DUK_USE_BROWSER_LIKE) +#error unsupported config option used (option has been removed): DUK_USE_BROWSER_LIKE +#endif +#if defined(DUK_USE_BUILTIN_INITJS) +#error unsupported config option used (option has been removed): DUK_USE_BUILTIN_INITJS +#endif +#if defined(DUK_USE_BYTEORDER_FORCED) +#error unsupported config option used (option has been removed): DUK_USE_BYTEORDER_FORCED +#endif +#if defined(DUK_USE_COMMONJS_MODULES) +#error unsupported config option used (option has been removed): DUK_USE_COMMONJS_MODULES +#endif +#if defined(DUK_USE_DATAPTR_DEC16) && !defined(DUK_USE_DATAPTR16) +#error config option DUK_USE_DATAPTR_DEC16 requires option DUK_USE_DATAPTR16 (which is missing) +#endif +#if defined(DUK_USE_DATAPTR_ENC16) && !defined(DUK_USE_DATAPTR16) +#error config option DUK_USE_DATAPTR_ENC16 requires option DUK_USE_DATAPTR16 (which is missing) +#endif +#if defined(DUK_USE_DDDPRINT) +#error unsupported config option used (option has been removed): DUK_USE_DDDPRINT +#endif +#if defined(DUK_USE_DDPRINT) +#error unsupported config option used (option has been removed): DUK_USE_DDPRINT +#endif +#if defined(DUK_USE_DEBUGGER_FWD_LOGGING) +#error unsupported config option used (option has been removed): DUK_USE_DEBUGGER_FWD_LOGGING +#endif +#if defined(DUK_USE_DEBUGGER_FWD_PRINTALERT) +#error unsupported config option used (option has been removed): DUK_USE_DEBUGGER_FWD_PRINTALERT +#endif +#if defined(DUK_USE_DEBUGGER_SUPPORT) && !defined(DUK_USE_INTERRUPT_COUNTER) +#error config option DUK_USE_DEBUGGER_SUPPORT requires option DUK_USE_INTERRUPT_COUNTER (which is missing) +#endif +#if defined(DUK_USE_DEEP_C_STACK) +#error unsupported config option used (option has been removed): DUK_USE_DEEP_C_STACK +#endif +#if defined(DUK_USE_DOUBLE_BE) +#error unsupported config option used (option has been removed): DUK_USE_DOUBLE_BE +#endif +#if defined(DUK_USE_DOUBLE_BE) && defined(DUK_USE_DOUBLE_LE) +#error config option DUK_USE_DOUBLE_BE conflicts with option DUK_USE_DOUBLE_LE (which is also defined) +#endif +#if defined(DUK_USE_DOUBLE_BE) && defined(DUK_USE_DOUBLE_ME) +#error config option DUK_USE_DOUBLE_BE conflicts with option DUK_USE_DOUBLE_ME (which is also defined) +#endif +#if defined(DUK_USE_DOUBLE_LE) +#error unsupported config option used (option has been removed): DUK_USE_DOUBLE_LE +#endif +#if defined(DUK_USE_DOUBLE_LE) && defined(DUK_USE_DOUBLE_BE) +#error config option DUK_USE_DOUBLE_LE conflicts with option DUK_USE_DOUBLE_BE (which is also defined) +#endif +#if defined(DUK_USE_DOUBLE_LE) && defined(DUK_USE_DOUBLE_ME) +#error config option DUK_USE_DOUBLE_LE conflicts with option DUK_USE_DOUBLE_ME (which is also defined) +#endif +#if defined(DUK_USE_DOUBLE_ME) +#error unsupported config option used (option has been removed): DUK_USE_DOUBLE_ME +#endif +#if defined(DUK_USE_DOUBLE_ME) && defined(DUK_USE_DOUBLE_LE) +#error config option DUK_USE_DOUBLE_ME conflicts with option DUK_USE_DOUBLE_LE (which is also defined) +#endif +#if defined(DUK_USE_DOUBLE_ME) && defined(DUK_USE_DOUBLE_BE) +#error config option DUK_USE_DOUBLE_ME conflicts with option DUK_USE_DOUBLE_BE (which is also defined) +#endif +#if defined(DUK_USE_DPRINT) +#error unsupported config option used (option has been removed): DUK_USE_DPRINT +#endif +#if defined(DUK_USE_DPRINT) && !defined(DUK_USE_DEBUG) +#error config option DUK_USE_DPRINT requires option DUK_USE_DEBUG (which is missing) +#endif +#if defined(DUK_USE_DPRINT_COLORS) +#error unsupported config option used (option has been removed): DUK_USE_DPRINT_COLORS +#endif +#if defined(DUK_USE_DPRINT_RDTSC) +#error unsupported config option used (option has been removed): DUK_USE_DPRINT_RDTSC +#endif +#if defined(DUK_USE_ES6_REGEXP_BRACES) +#error unsupported config option used (option has been removed): DUK_USE_ES6_REGEXP_BRACES +#endif +#if defined(DUK_USE_ESBC_MAX_BYTES) && !defined(DUK_USE_ESBC_LIMITS) +#error config option DUK_USE_ESBC_MAX_BYTES requires option DUK_USE_ESBC_LIMITS (which is missing) +#endif +#if defined(DUK_USE_ESBC_MAX_LINENUMBER) && !defined(DUK_USE_ESBC_LIMITS) +#error config option DUK_USE_ESBC_MAX_LINENUMBER requires option DUK_USE_ESBC_LIMITS (which is missing) +#endif +#if defined(DUK_USE_EXEC_TIMEOUT_CHECK) && !defined(DUK_USE_INTERRUPT_COUNTER) +#error config option DUK_USE_EXEC_TIMEOUT_CHECK requires option DUK_USE_INTERRUPT_COUNTER (which is missing) +#endif +#if defined(DUK_USE_EXTSTR_FREE) && !defined(DUK_USE_HSTRING_EXTDATA) +#error config option DUK_USE_EXTSTR_FREE requires option DUK_USE_HSTRING_EXTDATA (which is missing) +#endif +#if defined(DUK_USE_EXTSTR_INTERN_CHECK) && !defined(DUK_USE_HSTRING_EXTDATA) +#error config option DUK_USE_EXTSTR_INTERN_CHECK requires option DUK_USE_HSTRING_EXTDATA (which is missing) +#endif +#if defined(DUK_USE_FASTINT) && !defined(DUK_USE_64BIT_OPS) +#error config option DUK_USE_FASTINT requires option DUK_USE_64BIT_OPS (which is missing) +#endif +#if defined(DUK_USE_FILE_IO) +#error unsupported config option used (option has been removed): DUK_USE_FILE_IO +#endif +#if defined(DUK_USE_FULL_TVAL) +#error unsupported config option used (option has been removed): DUK_USE_FULL_TVAL +#endif +#if defined(DUK_USE_FUNCPTR_DEC16) && !defined(DUK_USE_FUNCPTR16) +#error config option DUK_USE_FUNCPTR_DEC16 requires option DUK_USE_FUNCPTR16 (which is missing) +#endif +#if defined(DUK_USE_FUNCPTR_ENC16) && !defined(DUK_USE_FUNCPTR16) +#error config option DUK_USE_FUNCPTR_ENC16 requires option DUK_USE_FUNCPTR16 (which is missing) +#endif +#if defined(DUK_USE_HASHBYTES_UNALIGNED_U32_ACCESS) +#error unsupported config option used (option has been removed): DUK_USE_HASHBYTES_UNALIGNED_U32_ACCESS +#endif +#if defined(DUK_USE_HEAPPTR16) && defined(DUK_USE_DEBUG) +#error config option DUK_USE_HEAPPTR16 conflicts with option DUK_USE_DEBUG (which is also defined) +#endif +#if defined(DUK_USE_HEAPPTR_DEC16) && !defined(DUK_USE_HEAPPTR16) +#error config option DUK_USE_HEAPPTR_DEC16 requires option DUK_USE_HEAPPTR16 (which is missing) +#endif +#if defined(DUK_USE_HEAPPTR_ENC16) && !defined(DUK_USE_HEAPPTR16) +#error config option DUK_USE_HEAPPTR_ENC16 requires option DUK_USE_HEAPPTR16 (which is missing) +#endif +#if defined(DUK_USE_INTEGER_BE) +#error unsupported config option used (option has been removed): DUK_USE_INTEGER_BE +#endif +#if defined(DUK_USE_INTEGER_BE) && defined(DUK_USE_INTEGER_LE) +#error config option DUK_USE_INTEGER_BE conflicts with option DUK_USE_INTEGER_LE (which is also defined) +#endif +#if defined(DUK_USE_INTEGER_BE) && defined(DUK_USE_INTEGER_ME) +#error config option DUK_USE_INTEGER_BE conflicts with option DUK_USE_INTEGER_ME (which is also defined) +#endif +#if defined(DUK_USE_INTEGER_LE) +#error unsupported config option used (option has been removed): DUK_USE_INTEGER_LE +#endif +#if defined(DUK_USE_INTEGER_LE) && defined(DUK_USE_INTEGER_BE) +#error config option DUK_USE_INTEGER_LE conflicts with option DUK_USE_INTEGER_BE (which is also defined) +#endif +#if defined(DUK_USE_INTEGER_LE) && defined(DUK_USE_INTEGER_ME) +#error config option DUK_USE_INTEGER_LE conflicts with option DUK_USE_INTEGER_ME (which is also defined) +#endif +#if defined(DUK_USE_INTEGER_ME) +#error unsupported config option used (option has been removed): DUK_USE_INTEGER_ME +#endif +#if defined(DUK_USE_INTEGER_ME) && defined(DUK_USE_INTEGER_LE) +#error config option DUK_USE_INTEGER_ME conflicts with option DUK_USE_INTEGER_LE (which is also defined) +#endif +#if defined(DUK_USE_INTEGER_ME) && defined(DUK_USE_INTEGER_BE) +#error config option DUK_USE_INTEGER_ME conflicts with option DUK_USE_INTEGER_BE (which is also defined) +#endif +#if defined(DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE) +#error unsupported config option used (option has been removed): DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE +#endif +#if defined(DUK_USE_MARK_AND_SWEEP) +#error unsupported config option used (option has been removed): DUK_USE_MARK_AND_SWEEP +#endif +#if defined(DUK_USE_MATH_FMAX) +#error unsupported config option used (option has been removed): DUK_USE_MATH_FMAX +#endif +#if defined(DUK_USE_MATH_FMIN) +#error unsupported config option used (option has been removed): DUK_USE_MATH_FMIN +#endif +#if defined(DUK_USE_MATH_ROUND) +#error unsupported config option used (option has been removed): DUK_USE_MATH_ROUND +#endif +#if defined(DUK_USE_MS_STRINGTABLE_RESIZE) +#error unsupported config option used (option has been removed): DUK_USE_MS_STRINGTABLE_RESIZE +#endif +#if defined(DUK_USE_NONSTD_ARRAY_CONCAT_TRAILER) +#error unsupported config option used (option has been removed): DUK_USE_NONSTD_ARRAY_CONCAT_TRAILER +#endif +#if defined(DUK_USE_NONSTD_ARRAY_MAP_TRAILER) +#error unsupported config option used (option has been removed): DUK_USE_NONSTD_ARRAY_MAP_TRAILER +#endif +#if defined(DUK_USE_NONSTD_REGEXP_DOLLAR_ESCAPE) +#error unsupported config option used (option has been removed): DUK_USE_NONSTD_REGEXP_DOLLAR_ESCAPE +#endif +#if defined(DUK_USE_NO_DOUBLE_ALIASING_SELFTEST) +#error unsupported config option used (option has been removed): DUK_USE_NO_DOUBLE_ALIASING_SELFTEST +#endif +#if defined(DUK_USE_OCTAL_SUPPORT) +#error unsupported config option used (option has been removed): DUK_USE_OCTAL_SUPPORT +#endif +#if defined(DUK_USE_PACKED_TVAL_POSSIBLE) +#error unsupported config option used (option has been removed): DUK_USE_PACKED_TVAL_POSSIBLE +#endif +#if defined(DUK_USE_PANIC_ABORT) +#error unsupported config option used (option has been removed): DUK_USE_PANIC_ABORT +#endif +#if defined(DUK_USE_PANIC_EXIT) +#error unsupported config option used (option has been removed): DUK_USE_PANIC_EXIT +#endif +#if defined(DUK_USE_PANIC_HANDLER) +#error unsupported config option used (option has been removed): DUK_USE_PANIC_HANDLER +#endif +#if defined(DUK_USE_PANIC_SEGFAULT) +#error unsupported config option used (option has been removed): DUK_USE_PANIC_SEGFAULT +#endif +#if defined(DUK_USE_POW_NETBSD_WORKAROUND) +#error unsupported config option used (option has been removed): DUK_USE_POW_NETBSD_WORKAROUND +#endif +#if defined(DUK_USE_RDTSC) +#error unsupported config option used (option has been removed): DUK_USE_RDTSC +#endif +#if defined(DUK_USE_REFZERO_FINALIZER_TORTURE) +#error unsupported config option used (option has been removed): DUK_USE_REFZERO_FINALIZER_TORTURE +#endif +#if defined(DUK_USE_ROM_GLOBAL_CLONE) && !defined(DUK_USE_ROM_STRINGS) +#error config option DUK_USE_ROM_GLOBAL_CLONE requires option DUK_USE_ROM_STRINGS (which is missing) +#endif +#if defined(DUK_USE_ROM_GLOBAL_CLONE) && !defined(DUK_USE_ROM_OBJECTS) +#error config option DUK_USE_ROM_GLOBAL_CLONE requires option DUK_USE_ROM_OBJECTS (which is missing) +#endif +#if defined(DUK_USE_ROM_GLOBAL_CLONE) && defined(DUK_USE_ROM_GLOBAL_INHERIT) +#error config option DUK_USE_ROM_GLOBAL_CLONE conflicts with option DUK_USE_ROM_GLOBAL_INHERIT (which is also defined) +#endif +#if defined(DUK_USE_ROM_GLOBAL_INHERIT) && !defined(DUK_USE_ROM_STRINGS) +#error config option DUK_USE_ROM_GLOBAL_INHERIT requires option DUK_USE_ROM_STRINGS (which is missing) +#endif +#if defined(DUK_USE_ROM_GLOBAL_INHERIT) && !defined(DUK_USE_ROM_OBJECTS) +#error config option DUK_USE_ROM_GLOBAL_INHERIT requires option DUK_USE_ROM_OBJECTS (which is missing) +#endif +#if defined(DUK_USE_ROM_GLOBAL_INHERIT) && defined(DUK_USE_ROM_GLOBAL_CLONE) +#error config option DUK_USE_ROM_GLOBAL_INHERIT conflicts with option DUK_USE_ROM_GLOBAL_CLONE (which is also defined) +#endif +#if defined(DUK_USE_ROM_OBJECTS) && !defined(DUK_USE_ROM_STRINGS) +#error config option DUK_USE_ROM_OBJECTS requires option DUK_USE_ROM_STRINGS (which is missing) +#endif +#if defined(DUK_USE_ROM_STRINGS) && !defined(DUK_USE_ROM_OBJECTS) +#error config option DUK_USE_ROM_STRINGS requires option DUK_USE_ROM_OBJECTS (which is missing) +#endif +#if defined(DUK_USE_SETJMP) +#error unsupported config option used (option has been removed): DUK_USE_SETJMP +#endif +#if defined(DUK_USE_SIGSETJMP) +#error unsupported config option used (option has been removed): DUK_USE_SIGSETJMP +#endif +#if defined(DUK_USE_STRTAB_CHAIN) +#error unsupported config option used (option has been removed): DUK_USE_STRTAB_CHAIN +#endif +#if defined(DUK_USE_STRTAB_CHAIN_SIZE) +#error unsupported config option used (option has been removed): DUK_USE_STRTAB_CHAIN_SIZE +#endif +#if defined(DUK_USE_STRTAB_CHAIN_SIZE) && !defined(DUK_USE_STRTAB_CHAIN) +#error config option DUK_USE_STRTAB_CHAIN_SIZE requires option DUK_USE_STRTAB_CHAIN (which is missing) +#endif +#if defined(DUK_USE_STRTAB_PROBE) +#error unsupported config option used (option has been removed): DUK_USE_STRTAB_PROBE +#endif +#if defined(DUK_USE_STRTAB_PTRCOMP) && !defined(DUK_USE_HEAPPTR16) +#error config option DUK_USE_STRTAB_PTRCOMP requires option DUK_USE_HEAPPTR16 (which is missing) +#endif +#if defined(DUK_USE_TAILCALL) && defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY) +#error config option DUK_USE_TAILCALL conflicts with option DUK_USE_NONSTD_FUNC_CALLER_PROPERTY (which is also defined) +#endif +#if defined(DUK_USE_UNALIGNED_ACCESSES_POSSIBLE) +#error unsupported config option used (option has been removed): DUK_USE_UNALIGNED_ACCESSES_POSSIBLE +#endif +#if defined(DUK_USE_UNDERSCORE_SETJMP) +#error unsupported config option used (option has been removed): DUK_USE_UNDERSCORE_SETJMP +#endif +#if defined(DUK_USE_USER_DECLARE) +#error unsupported config option used (option has been removed): DUK_USE_USER_DECLARE +#endif +#if defined(DUK_USE_USER_INITJS) +#error unsupported config option used (option has been removed): DUK_USE_USER_INITJS +#endif + +#if defined(DUK_USE_CPP_EXCEPTIONS) && !defined(__cplusplus) +#error DUK_USE_CPP_EXCEPTIONS enabled but not compiling with a C++ compiler +#endif + +/* + * Convert DUK_USE_BYTEORDER, from whatever source, into currently used + * internal defines. If detection failed, #error out. + */ + +#if defined(DUK_USE_BYTEORDER) +#if (DUK_USE_BYTEORDER == 1) +#define DUK_USE_INTEGER_LE +#define DUK_USE_DOUBLE_LE +#elif (DUK_USE_BYTEORDER == 2) +#define DUK_USE_INTEGER_LE /* integer endianness is little on purpose */ +#define DUK_USE_DOUBLE_ME +#elif (DUK_USE_BYTEORDER == 3) +#define DUK_USE_INTEGER_BE +#define DUK_USE_DOUBLE_BE +#else +#error unsupported: byte order invalid +#endif /* byte order */ +#else +#error unsupported: byte order detection failed +#endif /* defined(DUK_USE_BYTEORDER) */ + +#endif /* DUK_CONFIG_H_INCLUDED */
@@ -0,0 +1,1911 @@
+{ + "comment": "Metadata for Duktape sources", + "duk_version_string": "2.5.0", + "type": "duk_source_meta", + "line_map": [ + { + "original_line": 1, + "combined_line": 156, + "original_file": "duk_replacements.c" + }, + { + "original_line": 1, + "combined_line": 166, + "original_file": "duk_internal.h" + }, + { + "original_line": 1, + "combined_line": 204, + "original_file": "duk_dblunion.h" + }, + { + "original_line": 1, + "combined_line": 630, + "original_file": "duk_fltunion.h" + }, + { + "original_line": 1, + "combined_line": 671, + "original_file": "duk_replacements.h" + }, + { + "original_line": 1, + "combined_line": 702, + "original_file": "duk_jmpbuf.h" + }, + { + "original_line": 1, + "combined_line": 728, + "original_file": "duk_exception.h" + }, + { + "original_line": 1, + "combined_line": 760, + "original_file": "duk_forwdecl.h" + }, + { + "original_line": 1, + "combined_line": 896, + "original_file": "duk_tval.h" + }, + { + "original_line": 1, + "combined_line": 1537, + "original_file": "duk_builtins.h" + }, + { + "original_line": 45, + "combined_line": 2329, + "original_file": "duk_internal.h" + }, + { + "original_line": 1, + "combined_line": 2332, + "original_file": "duk_util.h" + }, + { + "original_line": 1, + "combined_line": 3065, + "original_file": "duk_strings.h" + }, + { + "original_line": 1, + "combined_line": 3234, + "original_file": "duk_js_bytecode.h" + }, + { + "original_line": 1, + "combined_line": 3718, + "original_file": "duk_lexer.h" + }, + { + "original_line": 1, + "combined_line": 4158, + "original_file": "duk_js_compiler.h" + }, + { + "original_line": 1, + "combined_line": 4387, + "original_file": "duk_regexp.h" + }, + { + "original_line": 1, + "combined_line": 4473, + "original_file": "duk_heaphdr.h" + }, + { + "original_line": 1, + "combined_line": 4772, + "original_file": "duk_refcount.h" + }, + { + "original_line": 1, + "combined_line": 5499, + "original_file": "duk_api_internal.h" + }, + { + "original_line": 1, + "combined_line": 5887, + "original_file": "duk_hstring.h" + }, + { + "original_line": 1, + "combined_line": 6142, + "original_file": "duk_hobject.h" + }, + { + "original_line": 1, + "combined_line": 7125, + "original_file": "duk_hcompfunc.h" + }, + { + "original_line": 1, + "combined_line": 7400, + "original_file": "duk_hnatfunc.h" + }, + { + "original_line": 1, + "combined_line": 7441, + "original_file": "duk_hboundfunc.h" + }, + { + "original_line": 1, + "combined_line": 7480, + "original_file": "duk_hbufobj.h" + }, + { + "original_line": 1, + "combined_line": 7609, + "original_file": "duk_hthread.h" + }, + { + "original_line": 1, + "combined_line": 8019, + "original_file": "duk_harray.h" + }, + { + "original_line": 1, + "combined_line": 8069, + "original_file": "duk_henv.h" + }, + { + "original_line": 1, + "combined_line": 8116, + "original_file": "duk_hbuffer.h" + }, + { + "original_line": 1, + "combined_line": 8454, + "original_file": "duk_hproxy.h" + }, + { + "original_line": 1, + "combined_line": 8482, + "original_file": "duk_heap.h" + }, + { + "original_line": 1, + "combined_line": 9207, + "original_file": "duk_debugger.h" + }, + { + "original_line": 1, + "combined_line": 9360, + "original_file": "duk_debug.h" + }, + { + "original_line": 1, + "combined_line": 9546, + "original_file": "duk_error.h" + }, + { + "original_line": 1, + "combined_line": 10073, + "original_file": "duk_unicode.h" + }, + { + "original_line": 1, + "combined_line": 10365, + "original_file": "duk_json.h" + }, + { + "original_line": 1, + "combined_line": 10435, + "original_file": "duk_js.h" + }, + { + "original_line": 1, + "combined_line": 10553, + "original_file": "duk_numconv.h" + }, + { + "original_line": 1, + "combined_line": 10659, + "original_file": "duk_bi_protos.h" + }, + { + "original_line": 1, + "combined_line": 10742, + "original_file": "duk_selftest.h" + }, + { + "original_line": 76, + "combined_line": 10758, + "original_file": "duk_internal.h" + }, + { + "original_line": 10, + "combined_line": 10761, + "original_file": "duk_replacements.c" + }, + { + "original_line": 1, + "combined_line": 10835, + "original_file": "duk_debug_macros.c" + }, + { + "original_line": 1, + "combined_line": 10927, + "original_file": "duk_builtins.c" + }, + { + "original_line": 1, + "combined_line": 11792, + "original_file": "duk_error_macros.c" + }, + { + "original_line": 1, + "combined_line": 11948, + "original_file": "duk_unicode_support.c" + }, + { + "original_line": 1, + "combined_line": 13214, + "original_file": "duk_util_memrw.c" + }, + { + "original_line": 1, + "combined_line": 13363, + "original_file": "duk_util_misc.c" + }, + { + "original_line": 1, + "combined_line": 13547, + "original_file": "duk_hobject_class.c" + }, + { + "original_line": 1, + "combined_line": 13677, + "original_file": "duk_alloc_default.c" + }, + { + "original_line": 1, + "combined_line": 13712, + "original_file": "duk_api_buffer.c" + }, + { + "original_line": 1, + "combined_line": 13786, + "original_file": "duk_api_bytecode.c" + }, + { + "original_line": 1, + "combined_line": 14555, + "original_file": "duk_api_call.c" + }, + { + "original_line": 1, + "combined_line": 15072, + "original_file": "duk_api_codec.c" + }, + { + "original_line": 1, + "combined_line": 15999, + "original_file": "duk_api_compile.c" + }, + { + "original_line": 1, + "combined_line": 16172, + "original_file": "duk_api_debug.c" + }, + { + "original_line": 1, + "combined_line": 16434, + "original_file": "duk_api_heap.c" + }, + { + "original_line": 1, + "combined_line": 16640, + "original_file": "duk_api_inspect.c" + }, + { + "original_line": 1, + "combined_line": 16886, + "original_file": "duk_api_memory.c" + }, + { + "original_line": 1, + "combined_line": 16967, + "original_file": "duk_api_object.c" + }, + { + "original_line": 1, + "combined_line": 18018, + "original_file": "duk_api_random.c" + }, + { + "original_line": 1, + "combined_line": 18028, + "original_file": "duk_api_stack.c" + }, + { + "original_line": 1, + "combined_line": 24907, + "original_file": "duk_api_string.c" + }, + { + "original_line": 1, + "combined_line": 25286, + "original_file": "duk_api_time.c" + }, + { + "original_line": 1, + "combined_line": 25397, + "original_file": "duk_bi_array.c" + }, + { + "original_line": 1, + "combined_line": 27053, + "original_file": "duk_bi_boolean.c" + }, + { + "original_line": 1, + "combined_line": 27123, + "original_file": "duk_bi_buffer.c" + }, + { + "original_line": 1, + "combined_line": 30060, + "original_file": "duk_bi_cbor.c" + }, + { + "original_line": 1, + "combined_line": 31726, + "original_file": "duk_bi_date.c" + }, + { + "original_line": 1, + "combined_line": 33545, + "original_file": "duk_bi_date_unix.c" + }, + { + "original_line": 1, + "combined_line": 33875, + "original_file": "duk_bi_date_windows.c" + }, + { + "original_line": 1, + "combined_line": 34069, + "original_file": "duk_bi_duktape.c" + }, + { + "original_line": 1, + "combined_line": 34228, + "original_file": "duk_bi_encoding.c" + }, + { + "original_line": 1, + "combined_line": 34767, + "original_file": "duk_bi_error.c" + }, + { + "original_line": 1, + "combined_line": 35160, + "original_file": "duk_bi_function.c" + }, + { + "original_line": 1, + "combined_line": 35614, + "original_file": "duk_bi_global.c" + }, + { + "original_line": 1, + "combined_line": 36346, + "original_file": "duk_bi_json.c" + }, + { + "original_line": 1, + "combined_line": 39616, + "original_file": "duk_bi_math.c" + }, + { + "original_line": 1, + "combined_line": 40136, + "original_file": "duk_bi_number.c" + }, + { + "original_line": 1, + "combined_line": 40417, + "original_file": "duk_bi_object.c" + }, + { + "original_line": 1, + "combined_line": 41221, + "original_file": "duk_bi_performance.c" + }, + { + "original_line": 1, + "combined_line": 41253, + "original_file": "duk_bi_pointer.c" + }, + { + "original_line": 1, + "combined_line": 41329, + "original_file": "duk_bi_promise.c" + }, + { + "original_line": 1, + "combined_line": 41374, + "original_file": "duk_bi_proxy.c" + }, + { + "original_line": 1, + "combined_line": 41471, + "original_file": "duk_bi_reflect.c" + }, + { + "original_line": 1, + "combined_line": 41571, + "original_file": "duk_bi_regexp.c" + }, + { + "original_line": 1, + "combined_line": 41798, + "original_file": "duk_bi_string.c" + }, + { + "original_line": 1, + "combined_line": 43379, + "original_file": "duk_bi_symbol.c" + }, + { + "original_line": 1, + "combined_line": 43550, + "original_file": "duk_bi_thread.c" + }, + { + "original_line": 1, + "combined_line": 43877, + "original_file": "duk_bi_thrower.c" + }, + { + "original_line": 1, + "combined_line": 43887, + "original_file": "duk_debug_fixedbuffer.c" + }, + { + "original_line": 1, + "combined_line": 43957, + "original_file": "duk_debug_vsnprintf.c" + }, + { + "original_line": 1, + "combined_line": 45058, + "original_file": "duk_debugger.c" + }, + { + "original_line": 1, + "combined_line": 47973, + "original_file": "duk_error_augment.c" + }, + { + "original_line": 1, + "combined_line": 48562, + "original_file": "duk_error_longjmp.c" + }, + { + "original_line": 1, + "combined_line": 48666, + "original_file": "duk_error_misc.c" + }, + { + "original_line": 1, + "combined_line": 48841, + "original_file": "duk_error_throw.c" + }, + { + "original_line": 1, + "combined_line": 49004, + "original_file": "duk_hbuffer_alloc.c" + }, + { + "original_line": 1, + "combined_line": 49137, + "original_file": "duk_hbuffer_assert.c" + }, + { + "original_line": 1, + "combined_line": 49151, + "original_file": "duk_hbuffer_ops.c" + }, + { + "original_line": 2, + "combined_line": 49231, + "original_file": "duk_hbufobj_misc.c" + }, + { + "original_line": 1, + "combined_line": 49251, + "original_file": "duk_heap_alloc.c" + }, + { + "original_line": 1, + "combined_line": 50477, + "original_file": "duk_heap_finalize.c" + }, + { + "original_line": 1, + "combined_line": 50923, + "original_file": "duk_heap_hashstring.c" + }, + { + "original_line": 1, + "combined_line": 51045, + "original_file": "duk_heap_markandsweep.c" + }, + { + "original_line": 1, + "combined_line": 52528, + "original_file": "duk_heap_memory.c" + }, + { + "original_line": 1, + "combined_line": 52941, + "original_file": "duk_heap_misc.c" + }, + { + "original_line": 1, + "combined_line": 53129, + "original_file": "duk_heap_refcount.c" + }, + { + "original_line": 1, + "combined_line": 53976, + "original_file": "duk_heap_stringcache.c" + }, + { + "original_line": 1, + "combined_line": 54286, + "original_file": "duk_heap_stringtable.c" + }, + { + "original_line": 1, + "combined_line": 55336, + "original_file": "duk_heaphdr_assert.c" + }, + { + "original_line": 1, + "combined_line": 55415, + "original_file": "duk_hobject_alloc.c" + }, + { + "original_line": 1, + "combined_line": 55687, + "original_file": "duk_hobject_assert.c" + }, + { + "original_line": 1, + "combined_line": 55815, + "original_file": "duk_hobject_enum.c" + }, + { + "original_line": 1, + "combined_line": 56525, + "original_file": "duk_hobject_misc.c" + }, + { + "original_line": 1, + "combined_line": 56579, + "original_file": "duk_hobject_pc2line.c" + }, + { + "original_line": 1, + "combined_line": 56824, + "original_file": "duk_hobject_props.c" + }, + { + "original_line": 1, + "combined_line": 63040, + "original_file": "duk_hstring_assert.c" + }, + { + "original_line": 1, + "combined_line": 63054, + "original_file": "duk_hstring_misc.c" + }, + { + "original_line": 1, + "combined_line": 63251, + "original_file": "duk_hthread_alloc.c" + }, + { + "original_line": 1, + "combined_line": 63311, + "original_file": "duk_hthread_builtins.c" + }, + { + "original_line": 1, + "combined_line": 64198, + "original_file": "duk_hthread_misc.c" + }, + { + "original_line": 1, + "combined_line": 64296, + "original_file": "duk_hthread_stacks.c" + }, + { + "original_line": 1, + "combined_line": 64704, + "original_file": "duk_js_arith.c" + }, + { + "original_line": 1, + "combined_line": 64842, + "original_file": "duk_js_call.c" + }, + { + "original_line": 1, + "combined_line": 67780, + "original_file": "duk_js_compiler.c" + }, + { + "original_line": 1, + "combined_line": 75888, + "original_file": "duk_js_executor.c" + }, + { + "original_line": 1, + "combined_line": 81150, + "original_file": "duk_js_ops.c" + }, + { + "original_line": 1, + "combined_line": 82629, + "original_file": "duk_js_var.c" + }, + { + "original_line": 1, + "combined_line": 84423, + "original_file": "duk_lexer.c" + }, + { + "original_line": 1, + "combined_line": 86885, + "original_file": "duk_numconv.c" + }, + { + "original_line": 1, + "combined_line": 89179, + "original_file": "duk_regexp_compiler.c" + }, + { + "original_line": 1, + "combined_line": 90471, + "original_file": "duk_regexp_executor.c" + }, + { + "original_line": 1, + "combined_line": 91499, + "original_file": "duk_selftest.c" + }, + { + "original_line": 2, + "combined_line": 92187, + "original_file": "duk_tval.c" + }, + { + "original_line": 1, + "combined_line": 92339, + "original_file": "duk_unicode_tables.c" + }, + { + "original_line": 1, + "combined_line": 98515, + "original_file": "duk_util_bitdecoder.c" + }, + { + "original_line": 1, + "combined_line": 98682, + "original_file": "duk_util_bitencoder.c" + }, + { + "original_line": 1, + "combined_line": 98726, + "original_file": "duk_util_bufwriter.c" + }, + { + "original_line": 1, + "combined_line": 99013, + "original_file": "duk_util_cast.c" + }, + { + "original_line": 1, + "combined_line": 99182, + "original_file": "duk_util_double.c" + }, + { + "original_line": 1, + "combined_line": 99526, + "original_file": "duk_util_hashbytes.c" + }, + { + "original_line": 1, + "combined_line": 99588, + "original_file": "duk_util_memory.c" + }, + { + "original_line": 1, + "combined_line": 99625, + "original_file": "duk_util_tinyrandom.c" + } + ], + "duk_version": 20500, + "git_branch": "master", + "git_commit": "6001888049cb42656f8649db020e804bcdeca6a7", + "builtin_strings_info": [ + { + "plain": "Undefined", + "base64": "VW5kZWZpbmVk", + "define": "DUK_STRIDX_UC_UNDEFINED" + }, + { + "plain": "Null", + "base64": "TnVsbA==", + "define": "DUK_STRIDX_UC_NULL" + }, + { + "plain": "Symbol", + "base64": "U3ltYm9s", + "define": "DUK_STRIDX_UC_SYMBOL" + }, + { + "plain": "Arguments", + "base64": "QXJndW1lbnRz", + "define": "DUK_STRIDX_UC_ARGUMENTS" + }, + { + "plain": "Object", + "base64": "T2JqZWN0", + "define": "DUK_STRIDX_UC_OBJECT" + }, + { + "plain": "Function", + "base64": "RnVuY3Rpb24=", + "define": "DUK_STRIDX_UC_FUNCTION" + }, + { + "plain": "Array", + "base64": "QXJyYXk=", + "define": "DUK_STRIDX_UC_ARRAY" + }, + { + "plain": "String", + "base64": "U3RyaW5n", + "define": "DUK_STRIDX_UC_STRING" + }, + { + "plain": "Boolean", + "base64": "Qm9vbGVhbg==", + "define": "DUK_STRIDX_UC_BOOLEAN" + }, + { + "plain": "Number", + "base64": "TnVtYmVy", + "define": "DUK_STRIDX_UC_NUMBER" + }, + { + "plain": "Date", + "base64": "RGF0ZQ==", + "define": "DUK_STRIDX_UC_DATE" + }, + { + "plain": "RegExp", + "base64": "UmVnRXhw", + "define": "DUK_STRIDX_REG_EXP" + }, + { + "plain": "Error", + "base64": "RXJyb3I=", + "define": "DUK_STRIDX_UC_ERROR" + }, + { + "plain": "Math", + "base64": "TWF0aA==", + "define": "DUK_STRIDX_MATH" + }, + { + "plain": "JSON", + "base64": "SlNPTg==", + "define": "DUK_STRIDX_JSON" + }, + { + "plain": "", + "base64": "", + "define": "DUK_STRIDX_EMPTY_STRING" + }, + { + "plain": "ArrayBuffer", + "base64": "QXJyYXlCdWZmZXI=", + "define": "DUK_STRIDX_ARRAY_BUFFER" + }, + { + "plain": "DataView", + "base64": "RGF0YVZpZXc=", + "define": "DUK_STRIDX_DATA_VIEW" + }, + { + "plain": "Int8Array", + "base64": "SW50OEFycmF5", + "define": "DUK_STRIDX_INT8_ARRAY" + }, + { + "plain": "Uint8Array", + "base64": "VWludDhBcnJheQ==", + "define": "DUK_STRIDX_UINT8_ARRAY" + }, + { + "plain": "Uint8ClampedArray", + "base64": "VWludDhDbGFtcGVkQXJyYXk=", + "define": "DUK_STRIDX_UINT8_CLAMPED_ARRAY" + }, + { + "plain": "Int16Array", + "base64": "SW50MTZBcnJheQ==", + "define": "DUK_STRIDX_INT16_ARRAY" + }, + { + "plain": "Uint16Array", + "base64": "VWludDE2QXJyYXk=", + "define": "DUK_STRIDX_UINT16_ARRAY" + }, + { + "plain": "Int32Array", + "base64": "SW50MzJBcnJheQ==", + "define": "DUK_STRIDX_INT32_ARRAY" + }, + { + "plain": "Uint32Array", + "base64": "VWludDMyQXJyYXk=", + "define": "DUK_STRIDX_UINT32_ARRAY" + }, + { + "plain": "Float32Array", + "base64": "RmxvYXQzMkFycmF5", + "define": "DUK_STRIDX_FLOAT32_ARRAY" + }, + { + "plain": "Float64Array", + "base64": "RmxvYXQ2NEFycmF5", + "define": "DUK_STRIDX_FLOAT64_ARRAY" + }, + { + "plain": "global", + "base64": "Z2xvYmFs", + "define": "DUK_STRIDX_GLOBAL" + }, + { + "plain": "ObjEnv", + "base64": "T2JqRW52", + "define": "DUK_STRIDX_OBJ_ENV" + }, + { + "plain": "DecEnv", + "base64": "RGVjRW52", + "define": "DUK_STRIDX_DEC_ENV" + }, + { + "plain": "Buffer", + "base64": "QnVmZmVy", + "define": "DUK_STRIDX_UC_BUFFER" + }, + { + "plain": "Pointer", + "base64": "UG9pbnRlcg==", + "define": "DUK_STRIDX_UC_POINTER" + }, + { + "plain": "Thread", + "base64": "VGhyZWFk", + "define": "DUK_STRIDX_UC_THREAD" + }, + { + "plain": "eval", + "base64": "ZXZhbA==", + "define": "DUK_STRIDX_EVAL" + }, + { + "plain": "value", + "base64": "dmFsdWU=", + "define": "DUK_STRIDX_VALUE" + }, + { + "plain": "writable", + "base64": "d3JpdGFibGU=", + "define": "DUK_STRIDX_WRITABLE" + }, + { + "plain": "configurable", + "base64": "Y29uZmlndXJhYmxl", + "define": "DUK_STRIDX_CONFIGURABLE" + }, + { + "plain": "enumerable", + "base64": "ZW51bWVyYWJsZQ==", + "define": "DUK_STRIDX_ENUMERABLE" + }, + { + "plain": "join", + "base64": "am9pbg==", + "define": "DUK_STRIDX_JOIN" + }, + { + "plain": "toLocaleString", + "base64": "dG9Mb2NhbGVTdHJpbmc=", + "define": "DUK_STRIDX_TO_LOCALE_STRING" + }, + { + "plain": "valueOf", + "base64": "dmFsdWVPZg==", + "define": "DUK_STRIDX_VALUE_OF" + }, + { + "plain": "toUTCString", + "base64": "dG9VVENTdHJpbmc=", + "define": "DUK_STRIDX_TO_UTC_STRING" + }, + { + "plain": "toISOString", + "base64": "dG9JU09TdHJpbmc=", + "define": "DUK_STRIDX_TO_ISO_STRING" + }, + { + "plain": "toGMTString", + "base64": "dG9HTVRTdHJpbmc=", + "define": "DUK_STRIDX_TO_GMT_STRING" + }, + { + "plain": "source", + "base64": "c291cmNl", + "define": "DUK_STRIDX_SOURCE" + }, + { + "plain": "ignoreCase", + "base64": "aWdub3JlQ2FzZQ==", + "define": "DUK_STRIDX_IGNORE_CASE" + }, + { + "plain": "multiline", + "base64": "bXVsdGlsaW5l", + "define": "DUK_STRIDX_MULTILINE" + }, + { + "plain": "lastIndex", + "base64": "bGFzdEluZGV4", + "define": "DUK_STRIDX_LAST_INDEX" + }, + { + "plain": "flags", + "base64": "ZmxhZ3M=", + "define": "DUK_STRIDX_FLAGS" + }, + { + "plain": "index", + "base64": "aW5kZXg=", + "define": "DUK_STRIDX_INDEX" + }, + { + "plain": "prototype", + "base64": "cHJvdG90eXBl", + "define": "DUK_STRIDX_PROTOTYPE" + }, + { + "plain": "constructor", + "base64": "Y29uc3RydWN0b3I=", + "define": "DUK_STRIDX_CONSTRUCTOR" + }, + { + "plain": "message", + "base64": "bWVzc2FnZQ==", + "define": "DUK_STRIDX_MESSAGE" + }, + { + "plain": "boolean", + "base64": "Ym9vbGVhbg==", + "define": "DUK_STRIDX_LC_BOOLEAN" + }, + { + "plain": "number", + "base64": "bnVtYmVy", + "define": "DUK_STRIDX_LC_NUMBER" + }, + { + "plain": "string", + "base64": "c3RyaW5n", + "define": "DUK_STRIDX_LC_STRING" + }, + { + "plain": "symbol", + "base64": "c3ltYm9s", + "define": "DUK_STRIDX_LC_SYMBOL" + }, + { + "plain": "object", + "base64": "b2JqZWN0", + "define": "DUK_STRIDX_LC_OBJECT" + }, + { + "plain": "undefined", + "base64": "dW5kZWZpbmVk", + "define": "DUK_STRIDX_LC_UNDEFINED" + }, + { + "plain": "NaN", + "base64": "TmFO", + "define": "DUK_STRIDX_NAN" + }, + { + "plain": "Infinity", + "base64": "SW5maW5pdHk=", + "define": "DUK_STRIDX_INFINITY" + }, + { + "plain": "-Infinity", + "base64": "LUluZmluaXR5", + "define": "DUK_STRIDX_MINUS_INFINITY" + }, + { + "plain": "-0", + "base64": "LTA=", + "define": "DUK_STRIDX_MINUS_ZERO" + }, + { + "plain": ",", + "base64": "LA==", + "define": "DUK_STRIDX_COMMA" + }, + { + "plain": "\n ", + "base64": "CiAgICA=", + "define": "DUK_STRIDX_NEWLINE_4SPACE" + }, + { + "plain": "[...]", + "base64": "Wy4uLl0=", + "define": "DUK_STRIDX_BRACKETED_ELLIPSIS" + }, + { + "plain": "Invalid Date", + "base64": "SW52YWxpZCBEYXRl", + "define": "DUK_STRIDX_INVALID_DATE" + }, + { + "plain": "arguments", + "base64": "YXJndW1lbnRz", + "define": "DUK_STRIDX_LC_ARGUMENTS" + }, + { + "plain": "callee", + "base64": "Y2FsbGVl", + "define": "DUK_STRIDX_CALLEE" + }, + { + "plain": "caller", + "base64": "Y2FsbGVy", + "define": "DUK_STRIDX_CALLER" + }, + { + "plain": "apply", + "base64": "YXBwbHk=", + "define": "DUK_STRIDX_APPLY" + }, + { + "plain": "construct", + "base64": "Y29uc3RydWN0", + "define": "DUK_STRIDX_CONSTRUCT" + }, + { + "plain": "deleteProperty", + "base64": "ZGVsZXRlUHJvcGVydHk=", + "define": "DUK_STRIDX_DELETE_PROPERTY" + }, + { + "plain": "get", + "base64": "Z2V0", + "define": "DUK_STRIDX_GET" + }, + { + "plain": "has", + "base64": "aGFz", + "define": "DUK_STRIDX_HAS" + }, + { + "plain": "ownKeys", + "base64": "b3duS2V5cw==", + "define": "DUK_STRIDX_OWN_KEYS" + }, + { + "plain": "\u0081Symbol.toPrimitive\u00ff", + "base64": "gVN5bWJvbC50b1ByaW1pdGl2Zf8=", + "define": "DUK_STRIDX_WELLKNOWN_SYMBOL_TO_PRIMITIVE" + }, + { + "plain": "\u0081Symbol.hasInstance\u00ff", + "base64": "gVN5bWJvbC5oYXNJbnN0YW5jZf8=", + "define": "DUK_STRIDX_WELLKNOWN_SYMBOL_HAS_INSTANCE" + }, + { + "plain": "\u0081Symbol.toStringTag\u00ff", + "base64": "gVN5bWJvbC50b1N0cmluZ1RhZ/8=", + "define": "DUK_STRIDX_WELLKNOWN_SYMBOL_TO_STRING_TAG" + }, + { + "plain": "\u0081Symbol.isConcatSpreadable\u00ff", + "base64": "gVN5bWJvbC5pc0NvbmNhdFNwcmVhZGFibGX/", + "define": "DUK_STRIDX_WELLKNOWN_SYMBOL_IS_CONCAT_SPREADABLE" + }, + { + "plain": "setPrototypeOf", + "base64": "c2V0UHJvdG90eXBlT2Y=", + "define": "DUK_STRIDX_SET_PROTOTYPE_OF" + }, + { + "plain": "__proto__", + "base64": "X19wcm90b19f", + "define": "DUK_STRIDX___PROTO__" + }, + { + "plain": "toString", + "base64": "dG9TdHJpbmc=", + "define": "DUK_STRIDX_TO_STRING" + }, + { + "plain": "toJSON", + "base64": "dG9KU09O", + "define": "DUK_STRIDX_TO_JSON" + }, + { + "plain": "type", + "base64": "dHlwZQ==", + "define": "DUK_STRIDX_TYPE" + }, + { + "plain": "data", + "base64": "ZGF0YQ==", + "define": "DUK_STRIDX_DATA" + }, + { + "plain": "buffer", + "base64": "YnVmZmVy", + "define": "DUK_STRIDX_LC_BUFFER" + }, + { + "plain": "length", + "base64": "bGVuZ3Ro", + "define": "DUK_STRIDX_LENGTH" + }, + { + "plain": "set", + "base64": "c2V0", + "define": "DUK_STRIDX_SET" + }, + { + "plain": "stack", + "base64": "c3RhY2s=", + "define": "DUK_STRIDX_STACK" + }, + { + "plain": "pc", + "base64": "cGM=", + "define": "DUK_STRIDX_PC" + }, + { + "plain": "lineNumber", + "base64": "bGluZU51bWJlcg==", + "define": "DUK_STRIDX_LINE_NUMBER" + }, + { + "plain": "\u0082Tracedata", + "base64": "glRyYWNlZGF0YQ==", + "define": "DUK_STRIDX_INT_TRACEDATA" + }, + { + "plain": "name", + "base64": "bmFtZQ==", + "define": "DUK_STRIDX_NAME" + }, + { + "plain": "fileName", + "base64": "ZmlsZU5hbWU=", + "define": "DUK_STRIDX_FILE_NAME" + }, + { + "plain": "pointer", + "base64": "cG9pbnRlcg==", + "define": "DUK_STRIDX_LC_POINTER" + }, + { + "plain": "\u0082Target", + "base64": "glRhcmdldA==", + "define": "DUK_STRIDX_INT_TARGET" + }, + { + "plain": "\u0082Next", + "base64": "gk5leHQ=", + "define": "DUK_STRIDX_INT_NEXT" + }, + { + "plain": "\u0082Bytecode", + "base64": "gkJ5dGVjb2Rl", + "define": "DUK_STRIDX_INT_BYTECODE" + }, + { + "plain": "\u0082Formals", + "base64": "gkZvcm1hbHM=", + "define": "DUK_STRIDX_INT_FORMALS" + }, + { + "plain": "\u0082Varmap", + "base64": "glZhcm1hcA==", + "define": "DUK_STRIDX_INT_VARMAP" + }, + { + "plain": "\u0082Source", + "base64": "glNvdXJjZQ==", + "define": "DUK_STRIDX_INT_SOURCE" + }, + { + "plain": "\u0082Pc2line", + "base64": "glBjMmxpbmU=", + "define": "DUK_STRIDX_INT_PC2LINE" + }, + { + "plain": "\u0082Map", + "base64": "gk1hcA==", + "define": "DUK_STRIDX_INT_MAP" + }, + { + "plain": "\u0082Varenv", + "base64": "glZhcmVudg==", + "define": "DUK_STRIDX_INT_VARENV" + }, + { + "plain": "\u0082Finalizer", + "base64": "gkZpbmFsaXplcg==", + "define": "DUK_STRIDX_INT_FINALIZER" + }, + { + "plain": "\u0082Value", + "base64": "glZhbHVl", + "define": "DUK_STRIDX_INT_VALUE" + }, + { + "plain": "compile", + "base64": "Y29tcGlsZQ==", + "define": "DUK_STRIDX_COMPILE" + }, + { + "plain": "input", + "base64": "aW5wdXQ=", + "define": "DUK_STRIDX_INPUT" + }, + { + "plain": "errCreate", + "base64": "ZXJyQ3JlYXRl", + "define": "DUK_STRIDX_ERR_CREATE" + }, + { + "plain": "errThrow", + "base64": "ZXJyVGhyb3c=", + "define": "DUK_STRIDX_ERR_THROW" + }, + { + "plain": "env", + "base64": "ZW52", + "define": "DUK_STRIDX_ENV" + }, + { + "plain": "hex", + "base64": "aGV4", + "define": "DUK_STRIDX_HEX" + }, + { + "plain": "base64", + "base64": "YmFzZTY0", + "define": "DUK_STRIDX_BASE64" + }, + { + "plain": "jx", + "base64": "ang=", + "define": "DUK_STRIDX_JX" + }, + { + "plain": "jc", + "base64": "amM=", + "define": "DUK_STRIDX_JC" + }, + { + "plain": "{\"_undef\":true}", + "base64": "eyJfdW5kZWYiOnRydWV9", + "define": "DUK_STRIDX_JSON_EXT_UNDEFINED" + }, + { + "plain": "{\"_nan\":true}", + "base64": "eyJfbmFuIjp0cnVlfQ==", + "define": "DUK_STRIDX_JSON_EXT_NAN" + }, + { + "plain": "{\"_inf\":true}", + "base64": "eyJfaW5mIjp0cnVlfQ==", + "define": "DUK_STRIDX_JSON_EXT_POSINF" + }, + { + "plain": "{\"_ninf\":true}", + "base64": "eyJfbmluZiI6dHJ1ZX0=", + "define": "DUK_STRIDX_JSON_EXT_NEGINF" + }, + { + "plain": "{\"_func\":true}", + "base64": "eyJfZnVuYyI6dHJ1ZX0=", + "define": "DUK_STRIDX_JSON_EXT_FUNCTION1" + }, + { + "plain": "{_func:true}", + "base64": "e19mdW5jOnRydWV9", + "define": "DUK_STRIDX_JSON_EXT_FUNCTION2" + }, + { + "plain": "break", + "base64": "YnJlYWs=", + "define": "DUK_STRIDX_BREAK" + }, + { + "plain": "case", + "base64": "Y2FzZQ==", + "define": "DUK_STRIDX_CASE" + }, + { + "plain": "catch", + "base64": "Y2F0Y2g=", + "define": "DUK_STRIDX_CATCH" + }, + { + "plain": "continue", + "base64": "Y29udGludWU=", + "define": "DUK_STRIDX_CONTINUE" + }, + { + "plain": "debugger", + "base64": "ZGVidWdnZXI=", + "define": "DUK_STRIDX_DEBUGGER" + }, + { + "plain": "default", + "base64": "ZGVmYXVsdA==", + "define": "DUK_STRIDX_DEFAULT" + }, + { + "plain": "delete", + "base64": "ZGVsZXRl", + "define": "DUK_STRIDX_DELETE" + }, + { + "plain": "do", + "base64": "ZG8=", + "define": "DUK_STRIDX_DO" + }, + { + "plain": "else", + "base64": "ZWxzZQ==", + "define": "DUK_STRIDX_ELSE" + }, + { + "plain": "finally", + "base64": "ZmluYWxseQ==", + "define": "DUK_STRIDX_FINALLY" + }, + { + "plain": "for", + "base64": "Zm9y", + "define": "DUK_STRIDX_FOR" + }, + { + "plain": "function", + "base64": "ZnVuY3Rpb24=", + "define": "DUK_STRIDX_LC_FUNCTION" + }, + { + "plain": "if", + "base64": "aWY=", + "define": "DUK_STRIDX_IF" + }, + { + "plain": "in", + "base64": "aW4=", + "define": "DUK_STRIDX_IN" + }, + { + "plain": "instanceof", + "base64": "aW5zdGFuY2VvZg==", + "define": "DUK_STRIDX_INSTANCEOF" + }, + { + "plain": "new", + "base64": "bmV3", + "define": "DUK_STRIDX_NEW" + }, + { + "plain": "return", + "base64": "cmV0dXJu", + "define": "DUK_STRIDX_RETURN" + }, + { + "plain": "switch", + "base64": "c3dpdGNo", + "define": "DUK_STRIDX_SWITCH" + }, + { + "plain": "this", + "base64": "dGhpcw==", + "define": "DUK_STRIDX_THIS" + }, + { + "plain": "throw", + "base64": "dGhyb3c=", + "define": "DUK_STRIDX_THROW" + }, + { + "plain": "try", + "base64": "dHJ5", + "define": "DUK_STRIDX_TRY" + }, + { + "plain": "typeof", + "base64": "dHlwZW9m", + "define": "DUK_STRIDX_TYPEOF" + }, + { + "plain": "var", + "base64": "dmFy", + "define": "DUK_STRIDX_VAR" + }, + { + "plain": "const", + "base64": "Y29uc3Q=", + "define": "DUK_STRIDX_CONST" + }, + { + "plain": "void", + "base64": "dm9pZA==", + "define": "DUK_STRIDX_VOID" + }, + { + "plain": "while", + "base64": "d2hpbGU=", + "define": "DUK_STRIDX_WHILE" + }, + { + "plain": "with", + "base64": "d2l0aA==", + "define": "DUK_STRIDX_WITH" + }, + { + "plain": "class", + "base64": "Y2xhc3M=", + "define": "DUK_STRIDX_CLASS" + }, + { + "plain": "enum", + "base64": "ZW51bQ==", + "define": "DUK_STRIDX_ENUM" + }, + { + "plain": "export", + "base64": "ZXhwb3J0", + "define": "DUK_STRIDX_EXPORT" + }, + { + "plain": "extends", + "base64": "ZXh0ZW5kcw==", + "define": "DUK_STRIDX_EXTENDS" + }, + { + "plain": "import", + "base64": "aW1wb3J0", + "define": "DUK_STRIDX_IMPORT" + }, + { + "plain": "super", + "base64": "c3VwZXI=", + "define": "DUK_STRIDX_SUPER" + }, + { + "plain": "null", + "base64": "bnVsbA==", + "define": "DUK_STRIDX_LC_NULL" + }, + { + "plain": "true", + "base64": "dHJ1ZQ==", + "define": "DUK_STRIDX_TRUE" + }, + { + "plain": "false", + "base64": "ZmFsc2U=", + "define": "DUK_STRIDX_FALSE" + }, + { + "plain": "implements", + "base64": "aW1wbGVtZW50cw==", + "define": "DUK_STRIDX_IMPLEMENTS" + }, + { + "plain": "interface", + "base64": "aW50ZXJmYWNl", + "define": "DUK_STRIDX_INTERFACE" + }, + { + "plain": "let", + "base64": "bGV0", + "define": "DUK_STRIDX_LET" + }, + { + "plain": "package", + "base64": "cGFja2FnZQ==", + "define": "DUK_STRIDX_PACKAGE" + }, + { + "plain": "private", + "base64": "cHJpdmF0ZQ==", + "define": "DUK_STRIDX_PRIVATE" + }, + { + "plain": "protected", + "base64": "cHJvdGVjdGVk", + "define": "DUK_STRIDX_PROTECTED" + }, + { + "plain": "public", + "base64": "cHVibGlj", + "define": "DUK_STRIDX_PUBLIC" + }, + { + "plain": "static", + "base64": "c3RhdGlj", + "define": "DUK_STRIDX_STATIC" + }, + { + "plain": "yield", + "base64": "eWllbGQ=", + "define": "DUK_STRIDX_YIELD" + } + ], + "builtin_strings_base64": [ + "VW5kZWZpbmVk", + "TnVsbA==", + "U3ltYm9s", + "QXJndW1lbnRz", + "T2JqZWN0", + "RnVuY3Rpb24=", + "QXJyYXk=", + "U3RyaW5n", + "Qm9vbGVhbg==", + "TnVtYmVy", + "RGF0ZQ==", + "UmVnRXhw", + "RXJyb3I=", + "TWF0aA==", + "SlNPTg==", + "", + "QXJyYXlCdWZmZXI=", + "RGF0YVZpZXc=", + "SW50OEFycmF5", + "VWludDhBcnJheQ==", + "VWludDhDbGFtcGVkQXJyYXk=", + "SW50MTZBcnJheQ==", + "VWludDE2QXJyYXk=", + "SW50MzJBcnJheQ==", + "VWludDMyQXJyYXk=", + "RmxvYXQzMkFycmF5", + "RmxvYXQ2NEFycmF5", + "Z2xvYmFs", + "T2JqRW52", + "RGVjRW52", + "QnVmZmVy", + "UG9pbnRlcg==", + "VGhyZWFk", + "ZXZhbA==", + "dmFsdWU=", + "d3JpdGFibGU=", + "Y29uZmlndXJhYmxl", + "ZW51bWVyYWJsZQ==", + "am9pbg==", + "dG9Mb2NhbGVTdHJpbmc=", + "dmFsdWVPZg==", + "dG9VVENTdHJpbmc=", + "dG9JU09TdHJpbmc=", + "dG9HTVRTdHJpbmc=", + "c291cmNl", + "aWdub3JlQ2FzZQ==", + "bXVsdGlsaW5l", + "bGFzdEluZGV4", + "ZmxhZ3M=", + "aW5kZXg=", + "cHJvdG90eXBl", + "Y29uc3RydWN0b3I=", + "bWVzc2FnZQ==", + "Ym9vbGVhbg==", + "bnVtYmVy", + "c3RyaW5n", + "c3ltYm9s", + "b2JqZWN0", + "dW5kZWZpbmVk", + "TmFO", + "SW5maW5pdHk=", + "LUluZmluaXR5", + "LTA=", + "LA==", + "CiAgICA=", + "Wy4uLl0=", + "SW52YWxpZCBEYXRl", + "YXJndW1lbnRz", + "Y2FsbGVl", + "Y2FsbGVy", + "YXBwbHk=", + "Y29uc3RydWN0", + "ZGVsZXRlUHJvcGVydHk=", + "Z2V0", + "aGFz", + "b3duS2V5cw==", + "gVN5bWJvbC50b1ByaW1pdGl2Zf8=", + "gVN5bWJvbC5oYXNJbnN0YW5jZf8=", + "gVN5bWJvbC50b1N0cmluZ1RhZ/8=", + "gVN5bWJvbC5pc0NvbmNhdFNwcmVhZGFibGX/", + "c2V0UHJvdG90eXBlT2Y=", + "X19wcm90b19f", + "dG9TdHJpbmc=", + "dG9KU09O", + "dHlwZQ==", + "ZGF0YQ==", + "YnVmZmVy", + "bGVuZ3Ro", + "c2V0", + "c3RhY2s=", + "cGM=", + "bGluZU51bWJlcg==", + "glRyYWNlZGF0YQ==", + "bmFtZQ==", + "ZmlsZU5hbWU=", + "cG9pbnRlcg==", + "glRhcmdldA==", + "gk5leHQ=", + "gkJ5dGVjb2Rl", + "gkZvcm1hbHM=", + "glZhcm1hcA==", + "glNvdXJjZQ==", + "glBjMmxpbmU=", + "gk1hcA==", + "glZhcmVudg==", + "gkZpbmFsaXplcg==", + "glZhbHVl", + "Y29tcGlsZQ==", + "aW5wdXQ=", + "ZXJyQ3JlYXRl", + "ZXJyVGhyb3c=", + "ZW52", + "aGV4", + "YmFzZTY0", + "ang=", + "amM=", + "eyJfdW5kZWYiOnRydWV9", + "eyJfbmFuIjp0cnVlfQ==", + "eyJfaW5mIjp0cnVlfQ==", + "eyJfbmluZiI6dHJ1ZX0=", + "eyJfZnVuYyI6dHJ1ZX0=", + "e19mdW5jOnRydWV9", + "YnJlYWs=", + "Y2FzZQ==", + "Y2F0Y2g=", + "Y29udGludWU=", + "ZGVidWdnZXI=", + "ZGVmYXVsdA==", + "ZGVsZXRl", + "ZG8=", + "ZWxzZQ==", + "ZmluYWxseQ==", + "Zm9y", + "ZnVuY3Rpb24=", + "aWY=", + "aW4=", + "aW5zdGFuY2VvZg==", + "bmV3", + "cmV0dXJu", + "c3dpdGNo", + "dGhpcw==", + "dGhyb3c=", + "dHJ5", + "dHlwZW9m", + "dmFy", + "Y29uc3Q=", + "dm9pZA==", + "d2hpbGU=", + "d2l0aA==", + "Y2xhc3M=", + "ZW51bQ==", + "ZXhwb3J0", + "ZXh0ZW5kcw==", + "aW1wb3J0", + "c3VwZXI=", + "bnVsbA==", + "dHJ1ZQ==", + "ZmFsc2U=", + "aW1wbGVtZW50cw==", + "aW50ZXJmYWNl", + "bGV0", + "cGFja2FnZQ==", + "cHJpdmF0ZQ==", + "cHJvdGVjdGVk", + "cHVibGlj", + "c3RhdGlj", + "eWllbGQ=" + ], + "git_describe": "v2.5.0", + "builtin_strings": [ + "Undefined", + "Null", + "Symbol", + "Arguments", + "Object", + "Function", + "Array", + "String", + "Boolean", + "Number", + "Date", + "RegExp", + "Error", + "Math", + "JSON", + "", + "ArrayBuffer", + "DataView", + "Int8Array", + "Uint8Array", + "Uint8ClampedArray", + "Int16Array", + "Uint16Array", + "Int32Array", + "Uint32Array", + "Float32Array", + "Float64Array", + "global", + "ObjEnv", + "DecEnv", + "Buffer", + "Pointer", + "Thread", + "eval", + "value", + "writable", + "configurable", + "enumerable", + "join", + "toLocaleString", + "valueOf", + "toUTCString", + "toISOString", + "toGMTString", + "source", + "ignoreCase", + "multiline", + "lastIndex", + "flags", + "index", + "prototype", + "constructor", + "message", + "boolean", + "number", + "string", + "symbol", + "object", + "undefined", + "NaN", + "Infinity", + "-Infinity", + "-0", + ",", + "\n ", + "[...]", + "Invalid Date", + "arguments", + "callee", + "caller", + "apply", + "construct", + "deleteProperty", + "get", + "has", + "ownKeys", + "\u0081Symbol.toPrimitive\u00ff", + "\u0081Symbol.hasInstance\u00ff", + "\u0081Symbol.toStringTag\u00ff", + "\u0081Symbol.isConcatSpreadable\u00ff", + "setPrototypeOf", + "__proto__", + "toString", + "toJSON", + "type", + "data", + "buffer", + "length", + "set", + "stack", + "pc", + "lineNumber", + "\u0082Tracedata", + "name", + "fileName", + "pointer", + "\u0082Target", + "\u0082Next", + "\u0082Bytecode", + "\u0082Formals", + "\u0082Varmap", + "\u0082Source", + "\u0082Pc2line", + "\u0082Map", + "\u0082Varenv", + "\u0082Finalizer", + "\u0082Value", + "compile", + "input", + "errCreate", + "errThrow", + "env", + "hex", + "base64", + "jx", + "jc", + "{\"_undef\":true}", + "{\"_nan\":true}", + "{\"_inf\":true}", + "{\"_ninf\":true}", + "{\"_func\":true}", + "{_func:true}", + "break", + "case", + "catch", + "continue", + "debugger", + "default", + "delete", + "do", + "else", + "finally", + "for", + "function", + "if", + "in", + "instanceof", + "new", + "return", + "switch", + "this", + "throw", + "try", + "typeof", + "var", + "const", + "void", + "while", + "with", + "class", + "enum", + "export", + "extends", + "import", + "super", + "null", + "true", + "false", + "implements", + "interface", + "let", + "package", + "private", + "protected", + "public", + "static", + "yield" + ] +}
@@ -0,0 +1,99755 @@
+/* + * Single source autogenerated distributable for Duktape 2.5.0. + * + * Git commit 6001888049cb42656f8649db020e804bcdeca6a7 (v2.5.0). + * Git branch master. + * + * See Duktape AUTHORS.rst and LICENSE.txt for copyright and + * licensing information. + */ + +/* LICENSE.txt */ +/* +* =============== +* Duktape license +* =============== +* +* (http://opensource.org/licenses/MIT) +* +* Copyright (c) 2013-2019 by Duktape authors (see AUTHORS.rst) +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +* THE SOFTWARE. +*/ + +/* AUTHORS.rst */ +/* +* =============== +* Duktape authors +* =============== +* +* Copyright +* ========= +* +* Duktape copyrights are held by its authors. Each author has a copyright +* to their contribution, and agrees to irrevocably license the contribution +* under the Duktape ``LICENSE.txt``. +* +* Authors +* ======= +* +* Please include an e-mail address, a link to your GitHub profile, or something +* similar to allow your contribution to be identified accurately. +* +* The following people have contributed code, website contents, or Wiki contents, +* and agreed to irrevocably license their contributions under the Duktape +* ``LICENSE.txt`` (in order of appearance): +* +* * Sami Vaarala <sami.vaarala@iki.fi> +* * Niki Dobrev +* * Andreas \u00d6man <andreas@lonelycoder.com> +* * L\u00e1szl\u00f3 Lang\u00f3 <llango.u-szeged@partner.samsung.com> +* * Legimet <legimet.calc@gmail.com> +* * Karl Skomski <karl@skomski.com> +* * Bruce Pascoe <fatcerberus1@gmail.com> +* * Ren\u00e9 Hollander <rene@rene8888.at> +* * Julien Hamaide (https://github.com/crazyjul) +* * Sebastian G\u00f6tte (https://github.com/jaseg) +* * Tomasz Magulski (https://github.com/magul) +* * \D. Bohdan (https://github.com/dbohdan) +* * Ond\u0159ej Jirman (https://github.com/megous) +* * Sa\u00fal Ibarra Corretg\u00e9 <saghul@gmail.com> +* * Jeremy HU <huxingyi@msn.com> +* * Ole Andr\u00e9 Vadla Ravn\u00e5s (https://github.com/oleavr) +* * Harold Brenes (https://github.com/harold-b) +* * Oliver Crow (https://github.com/ocrow) +* * Jakub Ch\u0142api\u0144ski (https://github.com/jchlapinski) +* * Brett Vickers (https://github.com/beevik) +* * Dominik Okwieka (https://github.com/okitec) +* * Remko Tron\u00e7on (https://el-tramo.be) +* * Romero Malaquias (rbsm@ic.ufal.br) +* * Michael Drake <michael.drake@codethink.co.uk> +* * Steven Don (https://github.com/shdon) +* * Simon Stone (https://github.com/sstone1) +* * \J. McC. (https://github.com/jmhmccr) +* * Jakub Nowakowski (https://github.com/jimvonmoon) +* * Tommy Nguyen (https://github.com/tn0502) +* * Fabrice Fontaine (https://github.com/ffontaine) +* * Christopher Hiller (https://github.com/boneskull) +* * Gonzalo Diethelm (https://github.com/gonzus) +* * Michal Kasperek (https://github.com/michalkas) +* * Andrew Janke (https://github.com/apjanke) +* * Steve Fan (https://github.com/stevefan1999) +* * Edward Betts (https://github.com/edwardbetts) +* * Ozhan Duz (https://github.com/webfolderio) +* * Akos Kiss (https://github.com/akosthekiss) +* * TheBrokenRail (https://github.com/TheBrokenRail) +* * Jesse Doyle (https://github.com/jessedoyle) +* * Gero Kuehn (https://github.com/dc6jgk) +* * James Swift (https://github.com/phraemer) +* * Luis de Bethencourt (https://github.com/luisbg) +* * Ian Whyman (https://github.com/v00d00) +* * Rick Sayre (https://github.com/whorfin) +* +* Other contributions +* =================== +* +* The following people have contributed something other than code (e.g. reported +* bugs, provided ideas, etc; roughly in order of appearance): +* +* * Greg Burns +* * Anthony Rabine +* * Carlos Costa +* * Aur\u00e9lien Bouilland +* * Preet Desai (Pris Matic) +* * judofyr (http://www.reddit.com/user/judofyr) +* * Jason Woofenden +* * Micha\u0142 Przyby\u015b +* * Anthony Howe +* * Conrad Pankoff +* * Jim Schimpf +* * Rajaran Gaunker (https://github.com/zimbabao) +* * Andreas \u00d6man +* * Doug Sanden +* * Josh Engebretson (https://github.com/JoshEngebretson) +* * Remo Eichenberger (https://github.com/remoe) +* * Mamod Mehyar (https://github.com/mamod) +* * David Demelier (https://github.com/markand) +* * Tim Caswell (https://github.com/creationix) +* * Mitchell Blank Jr (https://github.com/mitchblank) +* * https://github.com/yushli +* * Seo Sanghyeon (https://github.com/sanxiyn) +* * Han ChoongWoo (https://github.com/tunz) +* * Joshua Peek (https://github.com/josh) +* * Bruce E. Pascoe (https://github.com/fatcerberus) +* * https://github.com/Kelledin +* * https://github.com/sstruchtrup +* * Michael Drake (https://github.com/tlsa) +* * https://github.com/chris-y +* * Laurent Zubiaur (https://github.com/lzubiaur) +* * Neil Kolban (https://github.com/nkolban) +* * Wilhelm Wanecek (https://github.com/wanecek) +* * Andrew Janke (https://github.com/apjanke) +* * Unamer (https://github.com/unamer) +* * Karl Dahlke (eklhad@gmail.com) +* +* If you are accidentally missing from this list, send me an e-mail +* (``sami.vaarala@iki.fi``) and I'll fix the omission. +*/ + +#line 1 "duk_replacements.c" +/* + * Replacements for missing platform functions. + * + * Unlike the originals, fpclassify() and signbit() replacements don't + * work on any floating point types, only doubles. The C typing here + * mimics the standard prototypes. + */ + +/* #include duk_internal.h */ +#line 1 "duk_internal.h" +/* + * Top-level include file to be used for all (internal) source files. + * + * Source files should not include individual header files, as they + * have not been designed to be individually included. + */ + +#if !defined(DUK_INTERNAL_H_INCLUDED) +#define DUK_INTERNAL_H_INCLUDED + +/* + * The 'duktape.h' header provides the public API, but also handles all + * compiler and platform specific feature detection, Duktape feature + * resolution, inclusion of system headers, etc. These have been merged + * because the public API is also dependent on e.g. detecting appropriate + * C types which is quite platform/compiler specific especially for a non-C99 + * build. The public API is also dependent on the resolved feature set. + * + * Some actions taken by the merged header (such as including system headers) + * are not appropriate for building a user application. The define + * DUK_COMPILING_DUKTAPE allows the merged header to skip/include some + * sections depending on what is being built. + */ + +#define DUK_COMPILING_DUKTAPE +#include "duktape.h" + +/* + * Duktape includes (other than duk_features.h) + * + * The header files expect to be included in an order which satisfies header + * dependencies correctly (the headers themselves don't include any other + * includes). Forward declarations are used to break circular struct/typedef + * dependencies. + */ + +/* #include duk_dblunion.h */ +#line 1 "duk_dblunion.h" +/* + * Union to access IEEE double memory representation, indexes for double + * memory representation, and some macros for double manipulation. + * + * Also used by packed duk_tval. Use a union for bit manipulation to + * minimize aliasing issues in practice. The C99 standard does not + * guarantee that this should work, but it's a very widely supported + * practice for low level manipulation. + * + * IEEE double format summary: + * + * seeeeeee eeeeffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff + * A B C D E F G H + * + * s sign bit + * eee... exponent field + * fff... fraction + * + * See http://en.wikipedia.org/wiki/Double_precision_floating-point_format. + * + * NaNs are represented as exponent 0x7ff and mantissa != 0. The NaN is a + * signaling NaN when the highest bit of the mantissa is zero, and a quiet + * NaN when the highest bit is set. + * + * At least three memory layouts are relevant here: + * + * A B C D E F G H Big endian (e.g. 68k) DUK_USE_DOUBLE_BE + * H G F E D C B A Little endian (e.g. x86) DUK_USE_DOUBLE_LE + * D C B A H G F E Mixed endian (e.g. ARM FPA) DUK_USE_DOUBLE_ME + * + * Legacy ARM (FPA) is a special case: ARM double values are in mixed + * endian format while ARM duk_uint64_t values are in standard little endian + * format (H G F E D C B A). When a double is read as a duk_uint64_t + * from memory, the register will contain the (logical) value + * E F G H A B C D. This requires some special handling below. + * See http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0056d/Bcfhgcgd.html. + * + * Indexes of various types (8-bit, 16-bit, 32-bit) in memory relative to + * the logical (big endian) order: + * + * byte order duk_uint8_t duk_uint16_t duk_uint32_t + * BE 01234567 0123 01 + * LE 76543210 3210 10 + * ME (ARM) 32107654 1032 01 + * + * Some processors may alter NaN values in a floating point load+store. + * For instance, on X86 a FLD + FSTP may convert a signaling NaN to a + * quiet one. This is catastrophic when NaN space is used in packed + * duk_tval values. See: misc/clang_aliasing.c. + */ + +#if !defined(DUK_DBLUNION_H_INCLUDED) +#define DUK_DBLUNION_H_INCLUDED + +/* + * Union for accessing double parts, also serves as packed duk_tval + */ + +union duk_double_union { + double d; + float f[2]; +#if defined(DUK_USE_64BIT_OPS) + duk_uint64_t ull[1]; +#endif + duk_uint32_t ui[2]; + duk_uint16_t us[4]; + duk_uint8_t uc[8]; +#if defined(DUK_USE_PACKED_TVAL) + void *vp[2]; /* used by packed duk_tval, assumes sizeof(void *) == 4 */ +#endif +}; + +typedef union duk_double_union duk_double_union; + +/* + * Indexes of various types with respect to big endian (logical) layout + */ + +#if defined(DUK_USE_DOUBLE_LE) +#if defined(DUK_USE_64BIT_OPS) +#define DUK_DBL_IDX_ULL0 0 +#endif +#define DUK_DBL_IDX_UI0 1 +#define DUK_DBL_IDX_UI1 0 +#define DUK_DBL_IDX_US0 3 +#define DUK_DBL_IDX_US1 2 +#define DUK_DBL_IDX_US2 1 +#define DUK_DBL_IDX_US3 0 +#define DUK_DBL_IDX_UC0 7 +#define DUK_DBL_IDX_UC1 6 +#define DUK_DBL_IDX_UC2 5 +#define DUK_DBL_IDX_UC3 4 +#define DUK_DBL_IDX_UC4 3 +#define DUK_DBL_IDX_UC5 2 +#define DUK_DBL_IDX_UC6 1 +#define DUK_DBL_IDX_UC7 0 +#define DUK_DBL_IDX_VP0 DUK_DBL_IDX_UI0 /* packed tval */ +#define DUK_DBL_IDX_VP1 DUK_DBL_IDX_UI1 /* packed tval */ +#elif defined(DUK_USE_DOUBLE_BE) +#if defined(DUK_USE_64BIT_OPS) +#define DUK_DBL_IDX_ULL0 0 +#endif +#define DUK_DBL_IDX_UI0 0 +#define DUK_DBL_IDX_UI1 1 +#define DUK_DBL_IDX_US0 0 +#define DUK_DBL_IDX_US1 1 +#define DUK_DBL_IDX_US2 2 +#define DUK_DBL_IDX_US3 3 +#define DUK_DBL_IDX_UC0 0 +#define DUK_DBL_IDX_UC1 1 +#define DUK_DBL_IDX_UC2 2 +#define DUK_DBL_IDX_UC3 3 +#define DUK_DBL_IDX_UC4 4 +#define DUK_DBL_IDX_UC5 5 +#define DUK_DBL_IDX_UC6 6 +#define DUK_DBL_IDX_UC7 7 +#define DUK_DBL_IDX_VP0 DUK_DBL_IDX_UI0 /* packed tval */ +#define DUK_DBL_IDX_VP1 DUK_DBL_IDX_UI1 /* packed tval */ +#elif defined(DUK_USE_DOUBLE_ME) +#if defined(DUK_USE_64BIT_OPS) +#define DUK_DBL_IDX_ULL0 0 /* not directly applicable, byte order differs from a double */ +#endif +#define DUK_DBL_IDX_UI0 0 +#define DUK_DBL_IDX_UI1 1 +#define DUK_DBL_IDX_US0 1 +#define DUK_DBL_IDX_US1 0 +#define DUK_DBL_IDX_US2 3 +#define DUK_DBL_IDX_US3 2 +#define DUK_DBL_IDX_UC0 3 +#define DUK_DBL_IDX_UC1 2 +#define DUK_DBL_IDX_UC2 1 +#define DUK_DBL_IDX_UC3 0 +#define DUK_DBL_IDX_UC4 7 +#define DUK_DBL_IDX_UC5 6 +#define DUK_DBL_IDX_UC6 5 +#define DUK_DBL_IDX_UC7 4 +#define DUK_DBL_IDX_VP0 DUK_DBL_IDX_UI0 /* packed tval */ +#define DUK_DBL_IDX_VP1 DUK_DBL_IDX_UI1 /* packed tval */ +#else +#error internal error +#endif + +/* + * Helper macros for reading/writing memory representation parts, used + * by duk_numconv.c and duk_tval.h. + */ + +#define DUK_DBLUNION_SET_DOUBLE(u,v) do { \ + (u)->d = (v); \ + } while (0) + +#define DUK_DBLUNION_SET_HIGH32(u,v) do { \ + (u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) (v); \ + } while (0) + +#if defined(DUK_USE_64BIT_OPS) +#if defined(DUK_USE_DOUBLE_ME) +#define DUK_DBLUNION_SET_HIGH32_ZERO_LOW32(u,v) do { \ + (u)->ull[DUK_DBL_IDX_ULL0] = (duk_uint64_t) (v); \ + } while (0) +#else +#define DUK_DBLUNION_SET_HIGH32_ZERO_LOW32(u,v) do { \ + (u)->ull[DUK_DBL_IDX_ULL0] = ((duk_uint64_t) (v)) << 32; \ + } while (0) +#endif +#else /* DUK_USE_64BIT_OPS */ +#define DUK_DBLUNION_SET_HIGH32_ZERO_LOW32(u,v) do { \ + (u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) (v); \ + (u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) 0; \ + } while (0) +#endif /* DUK_USE_64BIT_OPS */ + +#define DUK_DBLUNION_SET_LOW32(u,v) do { \ + (u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (v); \ + } while (0) + +#define DUK_DBLUNION_GET_DOUBLE(u) ((u)->d) +#define DUK_DBLUNION_GET_HIGH32(u) ((u)->ui[DUK_DBL_IDX_UI0]) +#define DUK_DBLUNION_GET_LOW32(u) ((u)->ui[DUK_DBL_IDX_UI1]) + +#if defined(DUK_USE_64BIT_OPS) +#if defined(DUK_USE_DOUBLE_ME) +#define DUK_DBLUNION_SET_UINT64(u,v) do { \ + (u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) ((v) >> 32); \ + (u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (v); \ + } while (0) +#define DUK_DBLUNION_GET_UINT64(u) \ + ((((duk_uint64_t) (u)->ui[DUK_DBL_IDX_UI0]) << 32) | \ + ((duk_uint64_t) (u)->ui[DUK_DBL_IDX_UI1])) +#else +#define DUK_DBLUNION_SET_UINT64(u,v) do { \ + (u)->ull[DUK_DBL_IDX_ULL0] = (duk_uint64_t) (v); \ + } while (0) +#define DUK_DBLUNION_GET_UINT64(u) ((u)->ull[DUK_DBL_IDX_ULL0]) +#endif +#define DUK_DBLUNION_SET_INT64(u,v) DUK_DBLUNION_SET_UINT64((u), (duk_uint64_t) (v)) +#define DUK_DBLUNION_GET_INT64(u) ((duk_int64_t) DUK_DBLUNION_GET_UINT64((u))) +#endif /* DUK_USE_64BIT_OPS */ + +/* + * Double NaN manipulation macros related to NaN normalization needed when + * using the packed duk_tval representation. NaN normalization is necessary + * to keep double values compatible with the duk_tval format. + * + * When packed duk_tval is used, the NaN space is used to store pointers + * and other tagged values in addition to NaNs. Actual NaNs are normalized + * to a specific quiet NaN. The macros below are used by the implementation + * to check and normalize NaN values when they might be created. The macros + * are essentially NOPs when the non-packed duk_tval representation is used. + * + * A FULL check is exact and checks all bits. A NOTFULL check is used by + * the packed duk_tval and works correctly for all NaNs except those that + * begin with 0x7ff0. Since the 'normalized NaN' values used with packed + * duk_tval begin with 0x7ff8, the partial check is reliable when packed + * duk_tval is used. The 0x7ff8 prefix means the normalized NaN will be a + * quiet NaN regardless of its remaining lower bits. + * + * The ME variant below is specifically for ARM byte order, which has the + * feature that while doubles have a mixed byte order (32107654), unsigned + * long long values has a little endian byte order (76543210). When writing + * a logical double value through a ULL pointer, the 32-bit words need to be + * swapped; hence the #if defined()s below for ULL writes with DUK_USE_DOUBLE_ME. + * This is not full ARM support but suffices for some environments. + */ + +#if defined(DUK_USE_64BIT_OPS) +#if defined(DUK_USE_DOUBLE_ME) +/* Macros for 64-bit ops + mixed endian doubles. */ +#define DUK__DBLUNION_SET_NAN_FULL(u) do { \ + (u)->ull[DUK_DBL_IDX_ULL0] = DUK_U64_CONSTANT(0x000000007ff80000); \ + } while (0) +#define DUK__DBLUNION_IS_NAN_FULL(u) \ + ((((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x000000007ff00000)) == DUK_U64_CONSTANT(0x000000007ff00000)) && \ + ((((u)->ull[DUK_DBL_IDX_ULL0]) & DUK_U64_CONSTANT(0xffffffff000fffff)) != 0)) +#define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \ + ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x000000007ff80000)) +#define DUK__DBLUNION_IS_ANYINF(u) \ + (((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0xffffffff7fffffff)) == DUK_U64_CONSTANT(0x000000007ff00000)) +#define DUK__DBLUNION_IS_POSINF(u) \ + ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x000000007ff00000)) +#define DUK__DBLUNION_IS_NEGINF(u) \ + ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x00000000fff00000)) +#define DUK__DBLUNION_IS_ANYZERO(u) \ + (((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0xffffffff7fffffff)) == DUK_U64_CONSTANT(0x0000000000000000)) +#define DUK__DBLUNION_IS_POSZERO(u) \ + ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x0000000000000000)) +#define DUK__DBLUNION_IS_NEGZERO(u) \ + ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x0000000080000000)) +#else +/* Macros for 64-bit ops + big/little endian doubles. */ +#define DUK__DBLUNION_SET_NAN_FULL(u) do { \ + (u)->ull[DUK_DBL_IDX_ULL0] = DUK_U64_CONSTANT(0x7ff8000000000000); \ + } while (0) +#define DUK__DBLUNION_IS_NAN_FULL(u) \ + ((((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7ff0000000000000)) == DUK_U64_CONSTANT(0x7ff0000000000000)) && \ + ((((u)->ull[DUK_DBL_IDX_ULL0]) & DUK_U64_CONSTANT(0x000fffffffffffff)) != 0)) +#define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \ + ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x7ff8000000000000)) +#define DUK__DBLUNION_IS_ANYINF(u) \ + (((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7fffffffffffffff)) == DUK_U64_CONSTANT(0x7ff0000000000000)) +#define DUK__DBLUNION_IS_POSINF(u) \ + ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x7ff0000000000000)) +#define DUK__DBLUNION_IS_NEGINF(u) \ + ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0xfff0000000000000)) +#define DUK__DBLUNION_IS_ANYZERO(u) \ + (((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7fffffffffffffff)) == DUK_U64_CONSTANT(0x0000000000000000)) +#define DUK__DBLUNION_IS_POSZERO(u) \ + ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x0000000000000000)) +#define DUK__DBLUNION_IS_NEGZERO(u) \ + ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x8000000000000000)) +#endif +#else /* DUK_USE_64BIT_OPS */ +/* Macros for no 64-bit ops, any endianness. */ +#define DUK__DBLUNION_SET_NAN_FULL(u) do { \ + (u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) 0x7ff80000UL; \ + (u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) 0x00000000UL; \ + } while (0) +#define DUK__DBLUNION_IS_NAN_FULL(u) \ + ((((u)->ui[DUK_DBL_IDX_UI0] & 0x7ff00000UL) == 0x7ff00000UL) && \ + (((u)->ui[DUK_DBL_IDX_UI0] & 0x000fffffUL) != 0 || \ + (u)->ui[DUK_DBL_IDX_UI1] != 0)) +#define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \ + (((u)->ui[DUK_DBL_IDX_UI0] == 0x7ff80000UL) && \ + ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL)) +#define DUK__DBLUNION_IS_ANYINF(u) \ + ((((u)->ui[DUK_DBL_IDX_UI0] & 0x7fffffffUL) == 0x7ff00000UL) && \ + ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL)) +#define DUK__DBLUNION_IS_POSINF(u) \ + (((u)->ui[DUK_DBL_IDX_UI0] == 0x7ff00000UL) && \ + ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL)) +#define DUK__DBLUNION_IS_NEGINF(u) \ + (((u)->ui[DUK_DBL_IDX_UI0] == 0xfff00000UL) && \ + ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL)) +#define DUK__DBLUNION_IS_ANYZERO(u) \ + ((((u)->ui[DUK_DBL_IDX_UI0] & 0x7fffffffUL) == 0x00000000UL) && \ + ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL)) +#define DUK__DBLUNION_IS_POSZERO(u) \ + (((u)->ui[DUK_DBL_IDX_UI0] == 0x00000000UL) && \ + ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL)) +#define DUK__DBLUNION_IS_NEGZERO(u) \ + (((u)->ui[DUK_DBL_IDX_UI0] == 0x80000000UL) && \ + ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL)) +#endif /* DUK_USE_64BIT_OPS */ + +#define DUK__DBLUNION_SET_NAN_NOTFULL(u) do { \ + (u)->us[DUK_DBL_IDX_US0] = 0x7ff8UL; \ + } while (0) + +#define DUK__DBLUNION_IS_NAN_NOTFULL(u) \ + /* E == 0x7ff, topmost four bits of F != 0 => assume NaN */ \ + ((((u)->us[DUK_DBL_IDX_US0] & 0x7ff0UL) == 0x7ff0UL) && \ + (((u)->us[DUK_DBL_IDX_US0] & 0x000fUL) != 0x0000UL)) + +#define DUK__DBLUNION_IS_NORMALIZED_NAN_NOTFULL(u) \ + /* E == 0x7ff, F == 8 => normalized NaN */ \ + ((u)->us[DUK_DBL_IDX_US0] == 0x7ff8UL) + +#define DUK__DBLUNION_NORMALIZE_NAN_CHECK_FULL(u) do { \ + if (DUK__DBLUNION_IS_NAN_FULL((u))) { \ + DUK__DBLUNION_SET_NAN_FULL((u)); \ + } \ + } while (0) + +#define DUK__DBLUNION_NORMALIZE_NAN_CHECK_NOTFULL(u) do { \ + if (DUK__DBLUNION_IS_NAN_NOTFULL((u))) { \ + DUK__DBLUNION_SET_NAN_NOTFULL((u)); \ + } \ + } while (0) + +/* Concrete macros for NaN handling used by the implementation internals. + * Chosen so that they match the duk_tval representation: with a packed + * duk_tval, ensure NaNs are properly normalized; with a non-packed duk_tval + * these are essentially NOPs. + */ + +#if defined(DUK_USE_PACKED_TVAL) +#if defined(DUK_USE_FULL_TVAL) +#define DUK_DBLUNION_NORMALIZE_NAN_CHECK(u) DUK__DBLUNION_NORMALIZE_NAN_CHECK_FULL((u)) +#define DUK_DBLUNION_IS_NAN(u) DUK__DBLUNION_IS_NAN_FULL((u)) +#define DUK_DBLUNION_IS_NORMALIZED_NAN(u) DUK__DBLUNION_IS_NORMALIZED_NAN_FULL((u)) +#define DUK_DBLUNION_SET_NAN(d) DUK__DBLUNION_SET_NAN_FULL((d)) +#else +#define DUK_DBLUNION_NORMALIZE_NAN_CHECK(u) DUK__DBLUNION_NORMALIZE_NAN_CHECK_NOTFULL((u)) +#define DUK_DBLUNION_IS_NAN(u) DUK__DBLUNION_IS_NAN_NOTFULL((u)) +#define DUK_DBLUNION_IS_NORMALIZED_NAN(u) DUK__DBLUNION_IS_NORMALIZED_NAN_NOTFULL((u)) +#define DUK_DBLUNION_SET_NAN(d) DUK__DBLUNION_SET_NAN_NOTFULL((d)) +#endif +#define DUK_DBLUNION_IS_NORMALIZED(u) \ + (!DUK_DBLUNION_IS_NAN((u)) || /* either not a NaN */ \ + DUK_DBLUNION_IS_NORMALIZED_NAN((u))) /* or is a normalized NaN */ +#else /* DUK_USE_PACKED_TVAL */ +#define DUK_DBLUNION_NORMALIZE_NAN_CHECK(u) /* nop: no need to normalize */ +#define DUK_DBLUNION_IS_NAN(u) DUK__DBLUNION_IS_NAN_FULL((u)) /* (DUK_ISNAN((u)->d)) */ +#define DUK_DBLUNION_IS_NORMALIZED_NAN(u) DUK__DBLUNION_IS_NAN_FULL((u)) /* (DUK_ISNAN((u)->d)) */ +#define DUK_DBLUNION_IS_NORMALIZED(u) 1 /* all doubles are considered normalized */ +#define DUK_DBLUNION_SET_NAN(u) do { \ + /* in non-packed representation we don't care about which NaN is used */ \ + (u)->d = DUK_DOUBLE_NAN; \ + } while (0) +#endif /* DUK_USE_PACKED_TVAL */ + +#define DUK_DBLUNION_IS_ANYINF(u) DUK__DBLUNION_IS_ANYINF((u)) +#define DUK_DBLUNION_IS_POSINF(u) DUK__DBLUNION_IS_POSINF((u)) +#define DUK_DBLUNION_IS_NEGINF(u) DUK__DBLUNION_IS_NEGINF((u)) + +#define DUK_DBLUNION_IS_ANYZERO(u) DUK__DBLUNION_IS_ANYZERO((u)) +#define DUK_DBLUNION_IS_POSZERO(u) DUK__DBLUNION_IS_POSZERO((u)) +#define DUK_DBLUNION_IS_NEGZERO(u) DUK__DBLUNION_IS_NEGZERO((u)) + +/* XXX: native 64-bit byteswaps when available */ + +/* 64-bit byteswap, same operation independent of target endianness. */ +#define DUK_DBLUNION_BSWAP64(u) do { \ + duk_uint32_t duk__bswaptmp1, duk__bswaptmp2; \ + duk__bswaptmp1 = (u)->ui[0]; \ + duk__bswaptmp2 = (u)->ui[1]; \ + duk__bswaptmp1 = DUK_BSWAP32(duk__bswaptmp1); \ + duk__bswaptmp2 = DUK_BSWAP32(duk__bswaptmp2); \ + (u)->ui[0] = duk__bswaptmp2; \ + (u)->ui[1] = duk__bswaptmp1; \ + } while (0) + +/* Byteswap an IEEE double in the duk_double_union from host to network + * order. For a big endian target this is a no-op. + */ +#if defined(DUK_USE_DOUBLE_LE) +#define DUK_DBLUNION_DOUBLE_HTON(u) do { \ + duk_uint32_t duk__bswaptmp1, duk__bswaptmp2; \ + duk__bswaptmp1 = (u)->ui[0]; \ + duk__bswaptmp2 = (u)->ui[1]; \ + duk__bswaptmp1 = DUK_BSWAP32(duk__bswaptmp1); \ + duk__bswaptmp2 = DUK_BSWAP32(duk__bswaptmp2); \ + (u)->ui[0] = duk__bswaptmp2; \ + (u)->ui[1] = duk__bswaptmp1; \ + } while (0) +#elif defined(DUK_USE_DOUBLE_ME) +#define DUK_DBLUNION_DOUBLE_HTON(u) do { \ + duk_uint32_t duk__bswaptmp1, duk__bswaptmp2; \ + duk__bswaptmp1 = (u)->ui[0]; \ + duk__bswaptmp2 = (u)->ui[1]; \ + duk__bswaptmp1 = DUK_BSWAP32(duk__bswaptmp1); \ + duk__bswaptmp2 = DUK_BSWAP32(duk__bswaptmp2); \ + (u)->ui[0] = duk__bswaptmp1; \ + (u)->ui[1] = duk__bswaptmp2; \ + } while (0) +#elif defined(DUK_USE_DOUBLE_BE) +#define DUK_DBLUNION_DOUBLE_HTON(u) do { } while (0) +#else +#error internal error, double endianness insane +#endif + +/* Reverse operation is the same. */ +#define DUK_DBLUNION_DOUBLE_NTOH(u) DUK_DBLUNION_DOUBLE_HTON((u)) + +/* Some sign bit helpers. */ +#if defined(DUK_USE_64BIT_OPS) +#define DUK_DBLUNION_HAS_SIGNBIT(u) (((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x8000000000000000)) != 0) +#define DUK_DBLUNION_GET_SIGNBIT(u) (((u)->ull[DUK_DBL_IDX_ULL0] >> 63U)) +#else +#define DUK_DBLUNION_HAS_SIGNBIT(u) (((u)->ui[DUK_DBL_IDX_UI0] & 0x80000000UL) != 0) +#define DUK_DBLUNION_GET_SIGNBIT(u) (((u)->ui[DUK_DBL_IDX_UI0] >> 31U)) +#endif + +#endif /* DUK_DBLUNION_H_INCLUDED */ +/* #include duk_fltunion.h */ +#line 1 "duk_fltunion.h" +/* + * Union to access IEEE float memory representation. + */ + +#if !defined(DUK_FLTUNION_H_INCLUDED) +#define DUK_FLTUNION_H_INCLUDED + +/* #include duk_internal.h -> already included */ + +union duk_float_union { + float f; + duk_uint32_t ui[1]; + duk_uint16_t us[2]; + duk_uint8_t uc[4]; +}; + +typedef union duk_float_union duk_float_union; + +#if defined(DUK_USE_DOUBLE_LE) || defined(DUK_USE_DOUBLE_ME) +#define DUK_FLT_IDX_UI0 0 +#define DUK_FLT_IDX_US0 1 +#define DUK_FLT_IDX_US1 0 +#define DUK_FLT_IDX_UC0 3 +#define DUK_FLT_IDX_UC1 2 +#define DUK_FLT_IDX_UC2 1 +#define DUK_FLT_IDX_UC3 0 +#elif defined(DUK_USE_DOUBLE_BE) +#define DUK_FLT_IDX_UI0 0 +#define DUK_FLT_IDX_US0 0 +#define DUK_FLT_IDX_US1 1 +#define DUK_FLT_IDX_UC0 0 +#define DUK_FLT_IDX_UC1 1 +#define DUK_FLT_IDX_UC2 2 +#define DUK_FLT_IDX_UC3 3 +#else +#error internal error +#endif + +#endif /* DUK_FLTUNION_H_INCLUDED */ +/* #include duk_replacements.h */ +#line 1 "duk_replacements.h" +#if !defined(DUK_REPLACEMENTS_H_INCLUDED) +#define DUK_REPLACEMENTS_H_INCLUDED + +#if !defined(DUK_SINGLE_FILE) +#if defined(DUK_USE_COMPUTED_INFINITY) +DUK_INTERNAL_DECL double duk_computed_infinity; +#endif +#if defined(DUK_USE_COMPUTED_NAN) +DUK_INTERNAL_DECL double duk_computed_nan; +#endif +#endif /* !DUK_SINGLE_FILE */ + +#if defined(DUK_USE_REPL_FPCLASSIFY) +DUK_INTERNAL_DECL int duk_repl_fpclassify(double x); +#endif +#if defined(DUK_USE_REPL_SIGNBIT) +DUK_INTERNAL_DECL int duk_repl_signbit(double x); +#endif +#if defined(DUK_USE_REPL_ISFINITE) +DUK_INTERNAL_DECL int duk_repl_isfinite(double x); +#endif +#if defined(DUK_USE_REPL_ISNAN) +DUK_INTERNAL_DECL int duk_repl_isnan(double x); +#endif +#if defined(DUK_USE_REPL_ISINF) +DUK_INTERNAL_DECL int duk_repl_isinf(double x); +#endif + +#endif /* DUK_REPLACEMENTS_H_INCLUDED */ +/* #include duk_jmpbuf.h */ +#line 1 "duk_jmpbuf.h" +/* + * Wrapper for jmp_buf. + * + * This is used because jmp_buf is an array type for backward compatibility. + * Wrapping jmp_buf in a struct makes pointer references, sizeof, etc, + * behave more intuitively. + * + * http://en.wikipedia.org/wiki/Setjmp.h#Member_types + */ + +#if !defined(DUK_JMPBUF_H_INCLUDED) +#define DUK_JMPBUF_H_INCLUDED + +#if defined(DUK_USE_CPP_EXCEPTIONS) +struct duk_jmpbuf { + duk_small_int_t dummy; /* unused */ +}; +#else +struct duk_jmpbuf { + DUK_JMPBUF_TYPE jb; +}; +#endif + +#endif /* DUK_JMPBUF_H_INCLUDED */ +/* #include duk_exception.h */ +#line 1 "duk_exception.h" +/* + * Exceptions for Duktape internal throws when C++ exceptions are used + * for long control transfers. + */ + +#if !defined(DUK_EXCEPTION_H_INCLUDED) +#define DUK_EXCEPTION_H_INCLUDED + +#if defined(DUK_USE_CPP_EXCEPTIONS) +/* Internal exception used as a setjmp-longjmp replacement. User code should + * NEVER see or catch this exception, so it doesn't inherit from any base + * class which should minimize the chance of user code accidentally catching + * the exception. + */ +class duk_internal_exception { + /* intentionally empty */ +}; + +/* Fatal error, thrown as a specific C++ exception with C++ exceptions + * enabled. It is unsafe to continue; doing so may cause crashes or memory + * leaks. This is intended to be either uncaught, or caught by user code + * aware of the "unsafe to continue" semantics. + */ +class duk_fatal_exception : public virtual std::runtime_error { + public: + duk_fatal_exception(const char *message) : std::runtime_error(message) {} +}; +#endif + +#endif /* DUK_EXCEPTION_H_INCLUDED */ +/* #include duk_forwdecl.h */ +#line 1 "duk_forwdecl.h" +/* + * Forward declarations for all Duktape structures. + */ + +#if !defined(DUK_FORWDECL_H_INCLUDED) +#define DUK_FORWDECL_H_INCLUDED + +/* + * Forward declarations + */ + +#if defined(DUK_USE_CPP_EXCEPTIONS) +class duk_internal_exception; +#else +struct duk_jmpbuf; +#endif + +/* duk_tval intentionally skipped */ +struct duk_heaphdr; +struct duk_heaphdr_string; +struct duk_harray; +struct duk_hstring; +struct duk_hstring_external; +struct duk_hobject; +struct duk_hcompfunc; +struct duk_hnatfunc; +struct duk_hboundfunc; +struct duk_hthread; +struct duk_hbufobj; +struct duk_hdecenv; +struct duk_hobjenv; +struct duk_hproxy; +struct duk_hbuffer; +struct duk_hbuffer_fixed; +struct duk_hbuffer_dynamic; +struct duk_hbuffer_external; + +struct duk_propaccessor; +union duk_propvalue; +struct duk_propdesc; + +struct duk_heap; +struct duk_breakpoint; + +struct duk_activation; +struct duk_catcher; +struct duk_ljstate; +struct duk_strcache_entry; +struct duk_litcache_entry; +struct duk_strtab_entry; + +#if defined(DUK_USE_DEBUG) +struct duk_fixedbuffer; +#endif + +struct duk_bitdecoder_ctx; +struct duk_bitencoder_ctx; +struct duk_bufwriter_ctx; + +struct duk_token; +struct duk_re_token; +struct duk_lexer_point; +struct duk_lexer_ctx; +struct duk_lexer_codepoint; + +struct duk_compiler_instr; +struct duk_compiler_func; +struct duk_compiler_ctx; + +struct duk_re_matcher_ctx; +struct duk_re_compiler_ctx; + +#if defined(DUK_USE_CPP_EXCEPTIONS) +/* no typedef */ +#else +typedef struct duk_jmpbuf duk_jmpbuf; +#endif + +/* duk_tval intentionally skipped */ +typedef struct duk_heaphdr duk_heaphdr; +typedef struct duk_heaphdr_string duk_heaphdr_string; +typedef struct duk_harray duk_harray; +typedef struct duk_hstring duk_hstring; +typedef struct duk_hstring_external duk_hstring_external; +typedef struct duk_hobject duk_hobject; +typedef struct duk_hcompfunc duk_hcompfunc; +typedef struct duk_hnatfunc duk_hnatfunc; +typedef struct duk_hboundfunc duk_hboundfunc; +typedef struct duk_hthread duk_hthread; +typedef struct duk_hbufobj duk_hbufobj; +typedef struct duk_hdecenv duk_hdecenv; +typedef struct duk_hobjenv duk_hobjenv; +typedef struct duk_hproxy duk_hproxy; +typedef struct duk_hbuffer duk_hbuffer; +typedef struct duk_hbuffer_fixed duk_hbuffer_fixed; +typedef struct duk_hbuffer_dynamic duk_hbuffer_dynamic; +typedef struct duk_hbuffer_external duk_hbuffer_external; + +typedef struct duk_propaccessor duk_propaccessor; +typedef union duk_propvalue duk_propvalue; +typedef struct duk_propdesc duk_propdesc; + +typedef struct duk_heap duk_heap; +typedef struct duk_breakpoint duk_breakpoint; + +typedef struct duk_activation duk_activation; +typedef struct duk_catcher duk_catcher; +typedef struct duk_ljstate duk_ljstate; +typedef struct duk_strcache_entry duk_strcache_entry; +typedef struct duk_litcache_entry duk_litcache_entry; +typedef struct duk_strtab_entry duk_strtab_entry; + +#if defined(DUK_USE_DEBUG) +typedef struct duk_fixedbuffer duk_fixedbuffer; +#endif + +typedef struct duk_bitdecoder_ctx duk_bitdecoder_ctx; +typedef struct duk_bitencoder_ctx duk_bitencoder_ctx; +typedef struct duk_bufwriter_ctx duk_bufwriter_ctx; + +typedef struct duk_token duk_token; +typedef struct duk_re_token duk_re_token; +typedef struct duk_lexer_point duk_lexer_point; +typedef struct duk_lexer_ctx duk_lexer_ctx; +typedef struct duk_lexer_codepoint duk_lexer_codepoint; + +typedef struct duk_compiler_instr duk_compiler_instr; +typedef struct duk_compiler_func duk_compiler_func; +typedef struct duk_compiler_ctx duk_compiler_ctx; + +typedef struct duk_re_matcher_ctx duk_re_matcher_ctx; +typedef struct duk_re_compiler_ctx duk_re_compiler_ctx; + +#endif /* DUK_FORWDECL_H_INCLUDED */ +/* #include duk_tval.h */ +#line 1 "duk_tval.h" +/* + * Tagged type definition (duk_tval) and accessor macros. + * + * Access all fields through the accessor macros, as the representation + * is quite tricky. + * + * There are two packed type alternatives: an 8-byte representation + * based on an IEEE double (preferred for compactness), and a 12-byte + * representation (portability). The latter is needed also in e.g. + * 64-bit environments (it usually pads to 16 bytes per value). + * + * Selecting the tagged type format involves many trade-offs (memory + * use, size and performance of generated code, portability, etc). + * + * NB: because macro arguments are often expressions, macros should + * avoid evaluating their argument more than once. + */ + +#if !defined(DUK_TVAL_H_INCLUDED) +#define DUK_TVAL_H_INCLUDED + +/* sanity */ +#if !defined(DUK_USE_DOUBLE_LE) && !defined(DUK_USE_DOUBLE_ME) && !defined(DUK_USE_DOUBLE_BE) +#error unsupported: cannot determine byte order variant +#endif + +#if defined(DUK_USE_PACKED_TVAL) +/* ======================================================================== */ + +/* + * Packed 8-byte representation + */ + +/* use duk_double_union as duk_tval directly */ +typedef union duk_double_union duk_tval; +typedef struct { + duk_uint16_t a; + duk_uint16_t b; + duk_uint16_t c; + duk_uint16_t d; +} duk_tval_unused; + +/* tags */ +#define DUK_TAG_NORMALIZED_NAN 0x7ff8UL /* the NaN variant we use */ +/* avoid tag 0xfff0, no risk of confusion with negative infinity */ +#define DUK_TAG_MIN 0xfff1UL +#if defined(DUK_USE_FASTINT) +#define DUK_TAG_FASTINT 0xfff1UL /* embed: integer value */ +#endif +#define DUK_TAG_UNUSED 0xfff2UL /* marker; not actual tagged value */ +#define DUK_TAG_UNDEFINED 0xfff3UL /* embed: nothing */ +#define DUK_TAG_NULL 0xfff4UL /* embed: nothing */ +#define DUK_TAG_BOOLEAN 0xfff5UL /* embed: 0 or 1 (false or true) */ +/* DUK_TAG_NUMBER would logically go here, but it has multiple 'tags' */ +#define DUK_TAG_POINTER 0xfff6UL /* embed: void ptr */ +#define DUK_TAG_LIGHTFUNC 0xfff7UL /* embed: func ptr */ +#define DUK_TAG_STRING 0xfff8UL /* embed: duk_hstring ptr */ +#define DUK_TAG_OBJECT 0xfff9UL /* embed: duk_hobject ptr */ +#define DUK_TAG_BUFFER 0xfffaUL /* embed: duk_hbuffer ptr */ +#define DUK_TAG_MAX 0xfffaUL + +/* for convenience */ +#define DUK_XTAG_BOOLEAN_FALSE 0xfff50000UL +#define DUK_XTAG_BOOLEAN_TRUE 0xfff50001UL + +#define DUK_TVAL_IS_VALID_TAG(tv) \ + (DUK_TVAL_GET_TAG((tv)) - DUK_TAG_MIN <= DUK_TAG_MAX - DUK_TAG_MIN) + +/* DUK_TVAL_UNUSED initializer for duk_tval_unused, works for any endianness. */ +#define DUK_TVAL_UNUSED_INITIALIZER() \ + { DUK_TAG_UNUSED, DUK_TAG_UNUSED, DUK_TAG_UNUSED, DUK_TAG_UNUSED } + +/* two casts to avoid gcc warning: "warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]" */ +#if defined(DUK_USE_64BIT_OPS) +#if defined(DUK_USE_DOUBLE_ME) +#define DUK__TVAL_SET_TAGGEDPOINTER(tv,h,tag) do { \ + (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) (tag)) << 16) | (((duk_uint64_t) (duk_uint32_t) (h)) << 32); \ + } while (0) +#else +#define DUK__TVAL_SET_TAGGEDPOINTER(tv,h,tag) do { \ + (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) (tag)) << 48) | ((duk_uint64_t) (duk_uint32_t) (h)); \ + } while (0) +#endif +#else /* DUK_USE_64BIT_OPS */ +#define DUK__TVAL_SET_TAGGEDPOINTER(tv,h,tag) do { \ + duk_tval *duk__tv; \ + duk__tv = (tv); \ + duk__tv->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) (tag)) << 16; \ + duk__tv->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (h); \ + } while (0) +#endif /* DUK_USE_64BIT_OPS */ + +#if defined(DUK_USE_64BIT_OPS) +/* Double casting for pointer to avoid gcc warning (cast from pointer to integer of different size) */ +#if defined(DUK_USE_DOUBLE_ME) +#define DUK__TVAL_SET_LIGHTFUNC(tv,fp,flags) do { \ + (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_LIGHTFUNC) << 16) | \ + ((duk_uint64_t) (flags)) | \ + (((duk_uint64_t) (duk_uint32_t) (fp)) << 32); \ + } while (0) +#else +#define DUK__TVAL_SET_LIGHTFUNC(tv,fp,flags) do { \ + (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_LIGHTFUNC) << 48) | \ + (((duk_uint64_t) (flags)) << 32) | \ + ((duk_uint64_t) (duk_uint32_t) (fp)); \ + } while (0) +#endif +#else /* DUK_USE_64BIT_OPS */ +#define DUK__TVAL_SET_LIGHTFUNC(tv,fp,flags) do { \ + duk_tval *duk__tv; \ + duk__tv = (tv); \ + duk__tv->ui[DUK_DBL_IDX_UI0] = (((duk_uint32_t) DUK_TAG_LIGHTFUNC) << 16) | ((duk_uint32_t) (flags)); \ + duk__tv->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (fp); \ + } while (0) +#endif /* DUK_USE_64BIT_OPS */ + +#if defined(DUK_USE_FASTINT) +/* Note: masking is done for 'i' to deal with negative numbers correctly */ +#if defined(DUK_USE_DOUBLE_ME) +#define DUK__TVAL_SET_I48(tv,i) do { \ + duk_tval *duk__tv; \ + duk__tv = (tv); \ + duk__tv->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) DUK_TAG_FASTINT) << 16 | (((duk_uint32_t) ((i) >> 32)) & 0x0000ffffUL); \ + duk__tv->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (i); \ + } while (0) +#define DUK__TVAL_SET_U32(tv,i) do { \ + duk_tval *duk__tv; \ + duk__tv = (tv); \ + duk__tv->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) DUK_TAG_FASTINT) << 16; \ + duk__tv->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (i); \ + } while (0) +#else +#define DUK__TVAL_SET_I48(tv,i) do { \ + (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_FASTINT) << 48) | (((duk_uint64_t) (i)) & DUK_U64_CONSTANT(0x0000ffffffffffff)); \ + } while (0) +#define DUK__TVAL_SET_U32(tv,i) do { \ + (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_FASTINT) << 48) | (duk_uint64_t) (i); \ + } while (0) +#endif + +/* This needs to go through a cast because sign extension is needed. */ +#define DUK__TVAL_SET_I32(tv,i) do { \ + duk_int64_t duk__tmp = (duk_int64_t) (i); \ + DUK_TVAL_SET_I48((tv), duk__tmp); \ + } while (0) + +/* XXX: Clumsy sign extend and masking of 16 topmost bits. */ +#if defined(DUK_USE_DOUBLE_ME) +#define DUK__TVAL_GET_FASTINT(tv) (((duk_int64_t) ((((duk_uint64_t) (tv)->ui[DUK_DBL_IDX_UI0]) << 32) | ((duk_uint64_t) (tv)->ui[DUK_DBL_IDX_UI1]))) << 16 >> 16) +#else +#define DUK__TVAL_GET_FASTINT(tv) ((((duk_int64_t) (tv)->ull[DUK_DBL_IDX_ULL0]) << 16) >> 16) +#endif +#define DUK__TVAL_GET_FASTINT_U32(tv) ((tv)->ui[DUK_DBL_IDX_UI1]) +#define DUK__TVAL_GET_FASTINT_I32(tv) ((duk_int32_t) (tv)->ui[DUK_DBL_IDX_UI1]) +#endif /* DUK_USE_FASTINT */ + +#define DUK_TVAL_SET_UNDEFINED(tv) do { \ + (tv)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_UNDEFINED; \ + } while (0) +#define DUK_TVAL_SET_UNUSED(tv) do { \ + (tv)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_UNUSED; \ + } while (0) +#define DUK_TVAL_SET_NULL(tv) do { \ + (tv)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_NULL; \ + } while (0) + +#define DUK_TVAL_SET_BOOLEAN(tv,val) DUK_DBLUNION_SET_HIGH32((tv), (((duk_uint32_t) DUK_TAG_BOOLEAN) << 16) | ((duk_uint32_t) (val))) + +#define DUK_TVAL_SET_NAN(tv) DUK_DBLUNION_SET_NAN_FULL((tv)) + +/* Assumes that caller has normalized NaNs, otherwise trouble ahead. */ +#if defined(DUK_USE_FASTINT) +#define DUK_TVAL_SET_DOUBLE(tv,d) do { \ + duk_double_t duk__dblval; \ + duk__dblval = (d); \ + DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); \ + DUK_DBLUNION_SET_DOUBLE((tv), duk__dblval); \ + } while (0) +#define DUK_TVAL_SET_I48(tv,i) DUK__TVAL_SET_I48((tv), (i)) +#define DUK_TVAL_SET_I32(tv,i) DUK__TVAL_SET_I32((tv), (i)) +#define DUK_TVAL_SET_U32(tv,i) DUK__TVAL_SET_U32((tv), (i)) +#define DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv,d) duk_tval_set_number_chkfast_fast((tv), (d)) +#define DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv,d) duk_tval_set_number_chkfast_slow((tv), (d)) +#define DUK_TVAL_SET_NUMBER(tv,d) DUK_TVAL_SET_DOUBLE((tv), (d)) +#define DUK_TVAL_CHKFAST_INPLACE_FAST(tv) do { \ + duk_tval *duk__tv; \ + duk_double_t duk__d; \ + duk__tv = (tv); \ + if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \ + duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \ + DUK_TVAL_SET_NUMBER_CHKFAST_FAST(duk__tv, duk__d); \ + } \ + } while (0) +#define DUK_TVAL_CHKFAST_INPLACE_SLOW(tv) do { \ + duk_tval *duk__tv; \ + duk_double_t duk__d; \ + duk__tv = (tv); \ + if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \ + duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \ + DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(duk__tv, duk__d); \ + } \ + } while (0) +#else /* DUK_USE_FASTINT */ +#define DUK_TVAL_SET_DOUBLE(tv,d) do { \ + duk_double_t duk__dblval; \ + duk__dblval = (d); \ + DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); \ + DUK_DBLUNION_SET_DOUBLE((tv), duk__dblval); \ + } while (0) +#define DUK_TVAL_SET_I48(tv,i) DUK_TVAL_SET_DOUBLE((tv), (duk_double_t) (i)) /* XXX: fast int-to-double */ +#define DUK_TVAL_SET_I32(tv,i) DUK_TVAL_SET_DOUBLE((tv), (duk_double_t) (i)) +#define DUK_TVAL_SET_U32(tv,i) DUK_TVAL_SET_DOUBLE((tv), (duk_double_t) (i)) +#define DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv,d) DUK_TVAL_SET_DOUBLE((tv), (d)) +#define DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv,d) DUK_TVAL_SET_DOUBLE((tv), (d)) +#define DUK_TVAL_SET_NUMBER(tv,d) DUK_TVAL_SET_DOUBLE((tv), (d)) +#define DUK_TVAL_CHKFAST_INPLACE_FAST(tv) do { } while (0) +#define DUK_TVAL_CHKFAST_INPLACE_SLOW(tv) do { } while (0) +#endif /* DUK_USE_FASTINT */ + +#define DUK_TVAL_SET_FASTINT(tv,i) DUK_TVAL_SET_I48((tv), (i)) /* alias */ + +#define DUK_TVAL_SET_LIGHTFUNC(tv,fp,flags) DUK__TVAL_SET_LIGHTFUNC((tv), (fp), (flags)) +#define DUK_TVAL_SET_STRING(tv,h) DUK__TVAL_SET_TAGGEDPOINTER((tv), (h), DUK_TAG_STRING) +#define DUK_TVAL_SET_OBJECT(tv,h) DUK__TVAL_SET_TAGGEDPOINTER((tv), (h), DUK_TAG_OBJECT) +#define DUK_TVAL_SET_BUFFER(tv,h) DUK__TVAL_SET_TAGGEDPOINTER((tv), (h), DUK_TAG_BUFFER) +#define DUK_TVAL_SET_POINTER(tv,p) DUK__TVAL_SET_TAGGEDPOINTER((tv), (p), DUK_TAG_POINTER) + +#define DUK_TVAL_SET_TVAL(tv,x) do { *(tv) = *(x); } while (0) + +/* getters */ +#define DUK_TVAL_GET_BOOLEAN(tv) ((duk_small_uint_t) (tv)->us[DUK_DBL_IDX_US1]) +#if defined(DUK_USE_FASTINT) +#define DUK_TVAL_GET_DOUBLE(tv) ((tv)->d) +#define DUK_TVAL_GET_FASTINT(tv) DUK__TVAL_GET_FASTINT((tv)) +#define DUK_TVAL_GET_FASTINT_U32(tv) DUK__TVAL_GET_FASTINT_U32((tv)) +#define DUK_TVAL_GET_FASTINT_I32(tv) DUK__TVAL_GET_FASTINT_I32((tv)) +#define DUK_TVAL_GET_NUMBER(tv) duk_tval_get_number_packed((tv)) +#else +#define DUK_TVAL_GET_NUMBER(tv) ((tv)->d) +#define DUK_TVAL_GET_DOUBLE(tv) ((tv)->d) +#endif +#define DUK_TVAL_GET_LIGHTFUNC(tv,out_fp,out_flags) do { \ + (out_flags) = (tv)->ui[DUK_DBL_IDX_UI0] & 0xffffUL; \ + (out_fp) = (duk_c_function) (tv)->ui[DUK_DBL_IDX_UI1]; \ + } while (0) +#define DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv) ((duk_c_function) ((tv)->ui[DUK_DBL_IDX_UI1])) +#define DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv) (((duk_small_uint_t) (tv)->ui[DUK_DBL_IDX_UI0]) & 0xffffUL) +#define DUK_TVAL_GET_STRING(tv) ((duk_hstring *) (tv)->vp[DUK_DBL_IDX_VP1]) +#define DUK_TVAL_GET_OBJECT(tv) ((duk_hobject *) (tv)->vp[DUK_DBL_IDX_VP1]) +#define DUK_TVAL_GET_BUFFER(tv) ((duk_hbuffer *) (tv)->vp[DUK_DBL_IDX_VP1]) +#define DUK_TVAL_GET_POINTER(tv) ((void *) (tv)->vp[DUK_DBL_IDX_VP1]) +#define DUK_TVAL_GET_HEAPHDR(tv) ((duk_heaphdr *) (tv)->vp[DUK_DBL_IDX_VP1]) + +/* decoding */ +#define DUK_TVAL_GET_TAG(tv) ((duk_small_uint_t) (tv)->us[DUK_DBL_IDX_US0]) + +#define DUK_TVAL_IS_UNDEFINED(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_UNDEFINED) +#define DUK_TVAL_IS_UNUSED(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_UNUSED) +#define DUK_TVAL_IS_NULL(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_NULL) +#define DUK_TVAL_IS_BOOLEAN(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_BOOLEAN) +#define DUK_TVAL_IS_BOOLEAN_TRUE(tv) ((tv)->ui[DUK_DBL_IDX_UI0] == DUK_XTAG_BOOLEAN_TRUE) +#define DUK_TVAL_IS_BOOLEAN_FALSE(tv) ((tv)->ui[DUK_DBL_IDX_UI0] == DUK_XTAG_BOOLEAN_FALSE) +#define DUK_TVAL_IS_LIGHTFUNC(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_LIGHTFUNC) +#define DUK_TVAL_IS_STRING(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_STRING) +#define DUK_TVAL_IS_OBJECT(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_OBJECT) +#define DUK_TVAL_IS_BUFFER(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_BUFFER) +#define DUK_TVAL_IS_POINTER(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_POINTER) +#if defined(DUK_USE_FASTINT) +/* 0xfff0 is -Infinity */ +#define DUK_TVAL_IS_DOUBLE(tv) (DUK_TVAL_GET_TAG((tv)) <= 0xfff0UL) +#define DUK_TVAL_IS_FASTINT(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_FASTINT) +#define DUK_TVAL_IS_NUMBER(tv) (DUK_TVAL_GET_TAG((tv)) <= 0xfff1UL) +#else +#define DUK_TVAL_IS_NUMBER(tv) (DUK_TVAL_GET_TAG((tv)) <= 0xfff0UL) +#define DUK_TVAL_IS_DOUBLE(tv) DUK_TVAL_IS_NUMBER((tv)) +#endif + +/* This is performance critical because it appears in every DECREF. */ +#define DUK_TVAL_IS_HEAP_ALLOCATED(tv) (DUK_TVAL_GET_TAG((tv)) >= DUK_TAG_STRING) + +#if defined(DUK_USE_FASTINT) +DUK_INTERNAL_DECL duk_double_t duk_tval_get_number_packed(duk_tval *tv); +#endif + +#else /* DUK_USE_PACKED_TVAL */ +/* ======================================================================== */ + +/* + * Portable 12-byte representation + */ + +/* Note: not initializing all bytes is normally not an issue: Duktape won't + * read or use the uninitialized bytes so valgrind won't issue warnings. + * In some special cases a harmless valgrind warning may be issued though. + * For example, the DumpHeap debugger command writes out a compiled function's + * 'data' area as is, including any uninitialized bytes, which causes a + * valgrind warning. + */ + +typedef struct duk_tval_struct duk_tval; + +struct duk_tval_struct { + duk_small_uint_t t; + duk_small_uint_t v_extra; + union { + duk_double_t d; + duk_small_int_t i; +#if defined(DUK_USE_FASTINT) + duk_int64_t fi; /* if present, forces 16-byte duk_tval */ +#endif + void *voidptr; + duk_hstring *hstring; + duk_hobject *hobject; + duk_hcompfunc *hcompfunc; + duk_hnatfunc *hnatfunc; + duk_hthread *hthread; + duk_hbuffer *hbuffer; + duk_heaphdr *heaphdr; + duk_c_function lightfunc; + } v; +}; + +typedef struct { + duk_small_uint_t t; + duk_small_uint_t v_extra; + /* The rest of the fields don't matter except for debug dumps and such + * for which a partial initializer may trigger out-ot-bounds memory + * reads. Include a double field which is usually as large or larger + * than pointers (not always however). + */ + duk_double_t d; +} duk_tval_unused; + +#define DUK_TVAL_UNUSED_INITIALIZER() \ + { DUK_TAG_UNUSED, 0, 0.0 } + +#define DUK_TAG_MIN 0 +#define DUK_TAG_NUMBER 0 /* DUK_TAG_NUMBER only defined for non-packed duk_tval */ +#if defined(DUK_USE_FASTINT) +#define DUK_TAG_FASTINT 1 +#endif +#define DUK_TAG_UNDEFINED 2 +#define DUK_TAG_NULL 3 +#define DUK_TAG_BOOLEAN 4 +#define DUK_TAG_POINTER 5 +#define DUK_TAG_LIGHTFUNC 6 +#define DUK_TAG_UNUSED 7 /* marker; not actual tagged type */ +#define DUK_TAG_STRING 8 /* first heap allocated, match bit boundary */ +#define DUK_TAG_OBJECT 9 +#define DUK_TAG_BUFFER 10 +#define DUK_TAG_MAX 10 + +#define DUK_TVAL_IS_VALID_TAG(tv) \ + (DUK_TVAL_GET_TAG((tv)) - DUK_TAG_MIN <= DUK_TAG_MAX - DUK_TAG_MIN) + +/* DUK_TAG_NUMBER is intentionally first, as it is the default clause in code + * to support the 8-byte representation. Further, it is a non-heap-allocated + * type so it should come before DUK_TAG_STRING. Finally, it should not break + * the tag value ranges covered by case-clauses in a switch-case. + */ + +/* setters */ +#define DUK_TVAL_SET_UNDEFINED(tv) do { \ + duk_tval *duk__tv; \ + duk__tv = (tv); \ + duk__tv->t = DUK_TAG_UNDEFINED; \ + } while (0) + +#define DUK_TVAL_SET_UNUSED(tv) do { \ + duk_tval *duk__tv; \ + duk__tv = (tv); \ + duk__tv->t = DUK_TAG_UNUSED; \ + } while (0) + +#define DUK_TVAL_SET_NULL(tv) do { \ + duk_tval *duk__tv; \ + duk__tv = (tv); \ + duk__tv->t = DUK_TAG_NULL; \ + } while (0) + +#define DUK_TVAL_SET_BOOLEAN(tv,val) do { \ + duk_tval *duk__tv; \ + duk__tv = (tv); \ + duk__tv->t = DUK_TAG_BOOLEAN; \ + duk__tv->v.i = (duk_small_int_t) (val); \ + } while (0) + +#if defined(DUK_USE_FASTINT) +#define DUK_TVAL_SET_DOUBLE(tv,val) do { \ + duk_tval *duk__tv; \ + duk_double_t duk__dblval; \ + duk__dblval = (val); \ + DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); /* nop for unpacked duk_tval */ \ + duk__tv = (tv); \ + duk__tv->t = DUK_TAG_NUMBER; \ + duk__tv->v.d = duk__dblval; \ + } while (0) +#define DUK_TVAL_SET_I48(tv,val) do { \ + duk_tval *duk__tv; \ + duk__tv = (tv); \ + duk__tv->t = DUK_TAG_FASTINT; \ + duk__tv->v.fi = (val); \ + } while (0) +#define DUK_TVAL_SET_U32(tv,val) do { \ + duk_tval *duk__tv; \ + duk__tv = (tv); \ + duk__tv->t = DUK_TAG_FASTINT; \ + duk__tv->v.fi = (duk_int64_t) (val); \ + } while (0) +#define DUK_TVAL_SET_I32(tv,val) do { \ + duk_tval *duk__tv; \ + duk__tv = (tv); \ + duk__tv->t = DUK_TAG_FASTINT; \ + duk__tv->v.fi = (duk_int64_t) (val); \ + } while (0) +#define DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv,d) \ + duk_tval_set_number_chkfast_fast((tv), (d)) +#define DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv,d) \ + duk_tval_set_number_chkfast_slow((tv), (d)) +#define DUK_TVAL_SET_NUMBER(tv,val) \ + DUK_TVAL_SET_DOUBLE((tv), (val)) +#define DUK_TVAL_CHKFAST_INPLACE_FAST(tv) do { \ + duk_tval *duk__tv; \ + duk_double_t duk__d; \ + duk__tv = (tv); \ + if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \ + duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \ + DUK_TVAL_SET_NUMBER_CHKFAST_FAST(duk__tv, duk__d); \ + } \ + } while (0) +#define DUK_TVAL_CHKFAST_INPLACE_SLOW(tv) do { \ + duk_tval *duk__tv; \ + duk_double_t duk__d; \ + duk__tv = (tv); \ + if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \ + duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \ + DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(duk__tv, duk__d); \ + } \ + } while (0) +#else /* DUK_USE_FASTINT */ +#define DUK_TVAL_SET_DOUBLE(tv,d) \ + DUK_TVAL_SET_NUMBER((tv), (d)) +#define DUK_TVAL_SET_I48(tv,val) \ + DUK_TVAL_SET_NUMBER((tv), (duk_double_t) (val)) /* XXX: fast int-to-double */ +#define DUK_TVAL_SET_U32(tv,val) \ + DUK_TVAL_SET_NUMBER((tv), (duk_double_t) (val)) +#define DUK_TVAL_SET_I32(tv,val) \ + DUK_TVAL_SET_NUMBER((tv), (duk_double_t) (val)) +#define DUK_TVAL_SET_NUMBER(tv,val) do { \ + duk_tval *duk__tv; \ + duk_double_t duk__dblval; \ + duk__dblval = (val); \ + DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); /* nop for unpacked duk_tval */ \ + duk__tv = (tv); \ + duk__tv->t = DUK_TAG_NUMBER; \ + duk__tv->v.d = duk__dblval; \ + } while (0) +#define DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv,d) \ + DUK_TVAL_SET_NUMBER((tv), (d)) +#define DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv,d) \ + DUK_TVAL_SET_NUMBER((tv), (d)) +#define DUK_TVAL_CHKFAST_INPLACE_FAST(tv) do { } while (0) +#define DUK_TVAL_CHKFAST_INPLACE_SLOW(tv) do { } while (0) +#endif /* DUK_USE_FASTINT */ + +#define DUK_TVAL_SET_FASTINT(tv,i) \ + DUK_TVAL_SET_I48((tv), (i)) /* alias */ + +#define DUK_TVAL_SET_POINTER(tv,hptr) do { \ + duk_tval *duk__tv; \ + duk__tv = (tv); \ + duk__tv->t = DUK_TAG_POINTER; \ + duk__tv->v.voidptr = (hptr); \ + } while (0) + +#define DUK_TVAL_SET_LIGHTFUNC(tv,fp,flags) do { \ + duk_tval *duk__tv; \ + duk__tv = (tv); \ + duk__tv->t = DUK_TAG_LIGHTFUNC; \ + duk__tv->v_extra = (flags); \ + duk__tv->v.lightfunc = (duk_c_function) (fp); \ + } while (0) + +#define DUK_TVAL_SET_STRING(tv,hptr) do { \ + duk_tval *duk__tv; \ + duk__tv = (tv); \ + duk__tv->t = DUK_TAG_STRING; \ + duk__tv->v.hstring = (hptr); \ + } while (0) + +#define DUK_TVAL_SET_OBJECT(tv,hptr) do { \ + duk_tval *duk__tv; \ + duk__tv = (tv); \ + duk__tv->t = DUK_TAG_OBJECT; \ + duk__tv->v.hobject = (hptr); \ + } while (0) + +#define DUK_TVAL_SET_BUFFER(tv,hptr) do { \ + duk_tval *duk__tv; \ + duk__tv = (tv); \ + duk__tv->t = DUK_TAG_BUFFER; \ + duk__tv->v.hbuffer = (hptr); \ + } while (0) + +#define DUK_TVAL_SET_NAN(tv) do { \ + /* in non-packed representation we don't care about which NaN is used */ \ + duk_tval *duk__tv; \ + duk__tv = (tv); \ + duk__tv->t = DUK_TAG_NUMBER; \ + duk__tv->v.d = DUK_DOUBLE_NAN; \ + } while (0) + +#define DUK_TVAL_SET_TVAL(tv,x) do { *(tv) = *(x); } while (0) + +/* getters */ +#define DUK_TVAL_GET_BOOLEAN(tv) ((duk_small_uint_t) (tv)->v.i) +#if defined(DUK_USE_FASTINT) +#define DUK_TVAL_GET_DOUBLE(tv) ((tv)->v.d) +#define DUK_TVAL_GET_FASTINT(tv) ((tv)->v.fi) +#define DUK_TVAL_GET_FASTINT_U32(tv) ((duk_uint32_t) ((tv)->v.fi)) +#define DUK_TVAL_GET_FASTINT_I32(tv) ((duk_int32_t) ((tv)->v.fi)) +#if 0 +#define DUK_TVAL_GET_NUMBER(tv) (DUK_TVAL_IS_FASTINT((tv)) ? \ + (duk_double_t) DUK_TVAL_GET_FASTINT((tv)) : \ + DUK_TVAL_GET_DOUBLE((tv))) +#define DUK_TVAL_GET_NUMBER(tv) duk_tval_get_number_unpacked((tv)) +#else +/* This seems reasonable overall. */ +#define DUK_TVAL_GET_NUMBER(tv) (DUK_TVAL_IS_FASTINT((tv)) ? \ + duk_tval_get_number_unpacked_fastint((tv)) : \ + DUK_TVAL_GET_DOUBLE((tv))) +#endif +#else +#define DUK_TVAL_GET_NUMBER(tv) ((tv)->v.d) +#define DUK_TVAL_GET_DOUBLE(tv) ((tv)->v.d) +#endif /* DUK_USE_FASTINT */ +#define DUK_TVAL_GET_POINTER(tv) ((tv)->v.voidptr) +#define DUK_TVAL_GET_LIGHTFUNC(tv,out_fp,out_flags) do { \ + (out_flags) = (duk_uint32_t) (tv)->v_extra; \ + (out_fp) = (tv)->v.lightfunc; \ + } while (0) +#define DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv) ((tv)->v.lightfunc) +#define DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv) ((duk_small_uint_t) ((tv)->v_extra)) +#define DUK_TVAL_GET_STRING(tv) ((tv)->v.hstring) +#define DUK_TVAL_GET_OBJECT(tv) ((tv)->v.hobject) +#define DUK_TVAL_GET_BUFFER(tv) ((tv)->v.hbuffer) +#define DUK_TVAL_GET_HEAPHDR(tv) ((tv)->v.heaphdr) + +/* decoding */ +#define DUK_TVAL_GET_TAG(tv) ((tv)->t) +#define DUK_TVAL_IS_UNDEFINED(tv) ((tv)->t == DUK_TAG_UNDEFINED) +#define DUK_TVAL_IS_UNUSED(tv) ((tv)->t == DUK_TAG_UNUSED) +#define DUK_TVAL_IS_NULL(tv) ((tv)->t == DUK_TAG_NULL) +#define DUK_TVAL_IS_BOOLEAN(tv) ((tv)->t == DUK_TAG_BOOLEAN) +#define DUK_TVAL_IS_BOOLEAN_TRUE(tv) (((tv)->t == DUK_TAG_BOOLEAN) && ((tv)->v.i != 0)) +#define DUK_TVAL_IS_BOOLEAN_FALSE(tv) (((tv)->t == DUK_TAG_BOOLEAN) && ((tv)->v.i == 0)) +#if defined(DUK_USE_FASTINT) +#define DUK_TVAL_IS_DOUBLE(tv) ((tv)->t == DUK_TAG_NUMBER) +#define DUK_TVAL_IS_FASTINT(tv) ((tv)->t == DUK_TAG_FASTINT) +#define DUK_TVAL_IS_NUMBER(tv) ((tv)->t == DUK_TAG_NUMBER || \ + (tv)->t == DUK_TAG_FASTINT) +#else +#define DUK_TVAL_IS_NUMBER(tv) ((tv)->t == DUK_TAG_NUMBER) +#define DUK_TVAL_IS_DOUBLE(tv) DUK_TVAL_IS_NUMBER((tv)) +#endif /* DUK_USE_FASTINT */ +#define DUK_TVAL_IS_POINTER(tv) ((tv)->t == DUK_TAG_POINTER) +#define DUK_TVAL_IS_LIGHTFUNC(tv) ((tv)->t == DUK_TAG_LIGHTFUNC) +#define DUK_TVAL_IS_STRING(tv) ((tv)->t == DUK_TAG_STRING) +#define DUK_TVAL_IS_OBJECT(tv) ((tv)->t == DUK_TAG_OBJECT) +#define DUK_TVAL_IS_BUFFER(tv) ((tv)->t == DUK_TAG_BUFFER) + +/* This is performance critical because it's needed for every DECREF. + * Take advantage of the fact that the first heap allocated tag is 8, + * so that bit 3 is set for all heap allocated tags (and never set for + * non-heap-allocated tags). + */ +#if 0 +#define DUK_TVAL_IS_HEAP_ALLOCATED(tv) ((tv)->t >= DUK_TAG_STRING) +#endif +#define DUK_TVAL_IS_HEAP_ALLOCATED(tv) ((tv)->t & 0x08) + +#if defined(DUK_USE_FASTINT) +#if 0 +DUK_INTERNAL_DECL duk_double_t duk_tval_get_number_unpacked(duk_tval *tv); +#endif +DUK_INTERNAL_DECL duk_double_t duk_tval_get_number_unpacked_fastint(duk_tval *tv); +#endif + +#endif /* DUK_USE_PACKED_TVAL */ + +/* + * Convenience (independent of representation) + */ + +#define DUK_TVAL_SET_BOOLEAN_TRUE(tv) DUK_TVAL_SET_BOOLEAN((tv), 1) +#define DUK_TVAL_SET_BOOLEAN_FALSE(tv) DUK_TVAL_SET_BOOLEAN((tv), 0) + +#define DUK_TVAL_STRING_IS_SYMBOL(tv) \ + DUK_HSTRING_HAS_SYMBOL(DUK_TVAL_GET_STRING((tv))) + +/* Lightfunc flags packing and unpacking. */ +/* Sign extend: 0x0000##00 -> 0x##000000 -> sign extend to 0xssssss##. + * Avoid signed shifts due to portability limitations. + */ +#define DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags) \ + ((duk_int32_t) (duk_int8_t) (((duk_uint16_t) (lf_flags)) >> 8)) +#define DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags) \ + (((lf_flags) >> 4) & 0x0fU) +#define DUK_LFUNC_FLAGS_GET_NARGS(lf_flags) \ + ((lf_flags) & 0x0fU) +#define DUK_LFUNC_FLAGS_PACK(magic,length,nargs) \ + ((((duk_small_uint_t) (magic)) & 0xffU) << 8) | ((length) << 4) | (nargs) + +#define DUK_LFUNC_NARGS_VARARGS 0x0f /* varargs marker */ +#define DUK_LFUNC_NARGS_MIN 0x00 +#define DUK_LFUNC_NARGS_MAX 0x0e /* max, excl. varargs marker */ +#define DUK_LFUNC_LENGTH_MIN 0x00 +#define DUK_LFUNC_LENGTH_MAX 0x0f +#define DUK_LFUNC_MAGIC_MIN (-0x80) +#define DUK_LFUNC_MAGIC_MAX 0x7f + +/* fastint constants etc */ +#if defined(DUK_USE_FASTINT) +#define DUK_FASTINT_MIN (DUK_I64_CONSTANT(-0x800000000000)) +#define DUK_FASTINT_MAX (DUK_I64_CONSTANT(0x7fffffffffff)) +#define DUK_FASTINT_BITS 48 + +DUK_INTERNAL_DECL void duk_tval_set_number_chkfast_fast(duk_tval *tv, duk_double_t x); +DUK_INTERNAL_DECL void duk_tval_set_number_chkfast_slow(duk_tval *tv, duk_double_t x); +#endif + +#if defined(DUK_USE_ASSERTIONS) +DUK_INTERNAL_DECL void duk_tval_assert_valid(duk_tval *tv); +#define DUK_TVAL_ASSERT_VALID(tv) do { duk_tval_assert_valid((tv)); } while (0) +#else +#define DUK_TVAL_ASSERT_VALID(tv) do {} while (0) +#endif + +#endif /* DUK_TVAL_H_INCLUDED */ +/* #include duk_builtins.h */ +#line 1 "duk_builtins.h" +/* + * Automatically generated by genbuiltins.py, do not edit! + */ + +#if !defined(DUK_BUILTINS_H_INCLUDED) +#define DUK_BUILTINS_H_INCLUDED + +#if defined(DUK_USE_ROM_STRINGS) +#error ROM support not enabled, rerun configure.py with --rom-support +#else /* DUK_USE_ROM_STRINGS */ +#define DUK_STRIDX_UC_UNDEFINED 0 /* 'Undefined' */ +#define DUK_HEAP_STRING_UC_UNDEFINED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_UNDEFINED) +#define DUK_HTHREAD_STRING_UC_UNDEFINED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_UNDEFINED) +#define DUK_STRIDX_UC_NULL 1 /* 'Null' */ +#define DUK_HEAP_STRING_UC_NULL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_NULL) +#define DUK_HTHREAD_STRING_UC_NULL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_NULL) +#define DUK_STRIDX_UC_SYMBOL 2 /* 'Symbol' */ +#define DUK_HEAP_STRING_UC_SYMBOL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_SYMBOL) +#define DUK_HTHREAD_STRING_UC_SYMBOL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_SYMBOL) +#define DUK_STRIDX_UC_ARGUMENTS 3 /* 'Arguments' */ +#define DUK_HEAP_STRING_UC_ARGUMENTS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_ARGUMENTS) +#define DUK_HTHREAD_STRING_UC_ARGUMENTS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_ARGUMENTS) +#define DUK_STRIDX_UC_OBJECT 4 /* 'Object' */ +#define DUK_HEAP_STRING_UC_OBJECT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_OBJECT) +#define DUK_HTHREAD_STRING_UC_OBJECT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_OBJECT) +#define DUK_STRIDX_UC_FUNCTION 5 /* 'Function' */ +#define DUK_HEAP_STRING_UC_FUNCTION(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_FUNCTION) +#define DUK_HTHREAD_STRING_UC_FUNCTION(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_FUNCTION) +#define DUK_STRIDX_UC_ARRAY 6 /* 'Array' */ +#define DUK_HEAP_STRING_UC_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_ARRAY) +#define DUK_HTHREAD_STRING_UC_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_ARRAY) +#define DUK_STRIDX_UC_STRING 7 /* 'String' */ +#define DUK_HEAP_STRING_UC_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_STRING) +#define DUK_HTHREAD_STRING_UC_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_STRING) +#define DUK_STRIDX_UC_BOOLEAN 8 /* 'Boolean' */ +#define DUK_HEAP_STRING_UC_BOOLEAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_BOOLEAN) +#define DUK_HTHREAD_STRING_UC_BOOLEAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_BOOLEAN) +#define DUK_STRIDX_UC_NUMBER 9 /* 'Number' */ +#define DUK_HEAP_STRING_UC_NUMBER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_NUMBER) +#define DUK_HTHREAD_STRING_UC_NUMBER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_NUMBER) +#define DUK_STRIDX_UC_DATE 10 /* 'Date' */ +#define DUK_HEAP_STRING_UC_DATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_DATE) +#define DUK_HTHREAD_STRING_UC_DATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_DATE) +#define DUK_STRIDX_REG_EXP 11 /* 'RegExp' */ +#define DUK_HEAP_STRING_REG_EXP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_REG_EXP) +#define DUK_HTHREAD_STRING_REG_EXP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_REG_EXP) +#define DUK_STRIDX_UC_ERROR 12 /* 'Error' */ +#define DUK_HEAP_STRING_UC_ERROR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_ERROR) +#define DUK_HTHREAD_STRING_UC_ERROR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_ERROR) +#define DUK_STRIDX_MATH 13 /* 'Math' */ +#define DUK_HEAP_STRING_MATH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MATH) +#define DUK_HTHREAD_STRING_MATH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MATH) +#define DUK_STRIDX_JSON 14 /* 'JSON' */ +#define DUK_HEAP_STRING_JSON(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON) +#define DUK_HTHREAD_STRING_JSON(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON) +#define DUK_STRIDX_EMPTY_STRING 15 /* '' */ +#define DUK_HEAP_STRING_EMPTY_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EMPTY_STRING) +#define DUK_HTHREAD_STRING_EMPTY_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EMPTY_STRING) +#define DUK_STRIDX_ARRAY_BUFFER 16 /* 'ArrayBuffer' */ +#define DUK_HEAP_STRING_ARRAY_BUFFER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ARRAY_BUFFER) +#define DUK_HTHREAD_STRING_ARRAY_BUFFER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ARRAY_BUFFER) +#define DUK_STRIDX_DATA_VIEW 17 /* 'DataView' */ +#define DUK_HEAP_STRING_DATA_VIEW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DATA_VIEW) +#define DUK_HTHREAD_STRING_DATA_VIEW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DATA_VIEW) +#define DUK_STRIDX_INT8_ARRAY 18 /* 'Int8Array' */ +#define DUK_HEAP_STRING_INT8_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT8_ARRAY) +#define DUK_HTHREAD_STRING_INT8_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT8_ARRAY) +#define DUK_STRIDX_UINT8_ARRAY 19 /* 'Uint8Array' */ +#define DUK_HEAP_STRING_UINT8_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT8_ARRAY) +#define DUK_HTHREAD_STRING_UINT8_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT8_ARRAY) +#define DUK_STRIDX_UINT8_CLAMPED_ARRAY 20 /* 'Uint8ClampedArray' */ +#define DUK_HEAP_STRING_UINT8_CLAMPED_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT8_CLAMPED_ARRAY) +#define DUK_HTHREAD_STRING_UINT8_CLAMPED_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT8_CLAMPED_ARRAY) +#define DUK_STRIDX_INT16_ARRAY 21 /* 'Int16Array' */ +#define DUK_HEAP_STRING_INT16_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT16_ARRAY) +#define DUK_HTHREAD_STRING_INT16_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT16_ARRAY) +#define DUK_STRIDX_UINT16_ARRAY 22 /* 'Uint16Array' */ +#define DUK_HEAP_STRING_UINT16_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT16_ARRAY) +#define DUK_HTHREAD_STRING_UINT16_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT16_ARRAY) +#define DUK_STRIDX_INT32_ARRAY 23 /* 'Int32Array' */ +#define DUK_HEAP_STRING_INT32_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT32_ARRAY) +#define DUK_HTHREAD_STRING_INT32_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT32_ARRAY) +#define DUK_STRIDX_UINT32_ARRAY 24 /* 'Uint32Array' */ +#define DUK_HEAP_STRING_UINT32_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT32_ARRAY) +#define DUK_HTHREAD_STRING_UINT32_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT32_ARRAY) +#define DUK_STRIDX_FLOAT32_ARRAY 25 /* 'Float32Array' */ +#define DUK_HEAP_STRING_FLOAT32_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FLOAT32_ARRAY) +#define DUK_HTHREAD_STRING_FLOAT32_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FLOAT32_ARRAY) +#define DUK_STRIDX_FLOAT64_ARRAY 26 /* 'Float64Array' */ +#define DUK_HEAP_STRING_FLOAT64_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FLOAT64_ARRAY) +#define DUK_HTHREAD_STRING_FLOAT64_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FLOAT64_ARRAY) +#define DUK_STRIDX_GLOBAL 27 /* 'global' */ +#define DUK_HEAP_STRING_GLOBAL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GLOBAL) +#define DUK_HTHREAD_STRING_GLOBAL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GLOBAL) +#define DUK_STRIDX_OBJ_ENV 28 /* 'ObjEnv' */ +#define DUK_HEAP_STRING_OBJ_ENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_OBJ_ENV) +#define DUK_HTHREAD_STRING_OBJ_ENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_OBJ_ENV) +#define DUK_STRIDX_DEC_ENV 29 /* 'DecEnv' */ +#define DUK_HEAP_STRING_DEC_ENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEC_ENV) +#define DUK_HTHREAD_STRING_DEC_ENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEC_ENV) +#define DUK_STRIDX_UC_BUFFER 30 /* 'Buffer' */ +#define DUK_HEAP_STRING_UC_BUFFER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_BUFFER) +#define DUK_HTHREAD_STRING_UC_BUFFER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_BUFFER) +#define DUK_STRIDX_UC_POINTER 31 /* 'Pointer' */ +#define DUK_HEAP_STRING_UC_POINTER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_POINTER) +#define DUK_HTHREAD_STRING_UC_POINTER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_POINTER) +#define DUK_STRIDX_UC_THREAD 32 /* 'Thread' */ +#define DUK_HEAP_STRING_UC_THREAD(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_THREAD) +#define DUK_HTHREAD_STRING_UC_THREAD(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_THREAD) +#define DUK_STRIDX_EVAL 33 /* 'eval' */ +#define DUK_HEAP_STRING_EVAL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EVAL) +#define DUK_HTHREAD_STRING_EVAL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EVAL) +#define DUK_STRIDX_VALUE 34 /* 'value' */ +#define DUK_HEAP_STRING_VALUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VALUE) +#define DUK_HTHREAD_STRING_VALUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VALUE) +#define DUK_STRIDX_WRITABLE 35 /* 'writable' */ +#define DUK_HEAP_STRING_WRITABLE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WRITABLE) +#define DUK_HTHREAD_STRING_WRITABLE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WRITABLE) +#define DUK_STRIDX_CONFIGURABLE 36 /* 'configurable' */ +#define DUK_HEAP_STRING_CONFIGURABLE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONFIGURABLE) +#define DUK_HTHREAD_STRING_CONFIGURABLE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONFIGURABLE) +#define DUK_STRIDX_ENUMERABLE 37 /* 'enumerable' */ +#define DUK_HEAP_STRING_ENUMERABLE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENUMERABLE) +#define DUK_HTHREAD_STRING_ENUMERABLE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENUMERABLE) +#define DUK_STRIDX_JOIN 38 /* 'join' */ +#define DUK_HEAP_STRING_JOIN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JOIN) +#define DUK_HTHREAD_STRING_JOIN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JOIN) +#define DUK_STRIDX_TO_LOCALE_STRING 39 /* 'toLocaleString' */ +#define DUK_HEAP_STRING_TO_LOCALE_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_LOCALE_STRING) +#define DUK_HTHREAD_STRING_TO_LOCALE_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_LOCALE_STRING) +#define DUK_STRIDX_VALUE_OF 40 /* 'valueOf' */ +#define DUK_HEAP_STRING_VALUE_OF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VALUE_OF) +#define DUK_HTHREAD_STRING_VALUE_OF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VALUE_OF) +#define DUK_STRIDX_TO_UTC_STRING 41 /* 'toUTCString' */ +#define DUK_HEAP_STRING_TO_UTC_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_UTC_STRING) +#define DUK_HTHREAD_STRING_TO_UTC_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_UTC_STRING) +#define DUK_STRIDX_TO_ISO_STRING 42 /* 'toISOString' */ +#define DUK_HEAP_STRING_TO_ISO_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_ISO_STRING) +#define DUK_HTHREAD_STRING_TO_ISO_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_ISO_STRING) +#define DUK_STRIDX_TO_GMT_STRING 43 /* 'toGMTString' */ +#define DUK_HEAP_STRING_TO_GMT_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_GMT_STRING) +#define DUK_HTHREAD_STRING_TO_GMT_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_GMT_STRING) +#define DUK_STRIDX_SOURCE 44 /* 'source' */ +#define DUK_HEAP_STRING_SOURCE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SOURCE) +#define DUK_HTHREAD_STRING_SOURCE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SOURCE) +#define DUK_STRIDX_IGNORE_CASE 45 /* 'ignoreCase' */ +#define DUK_HEAP_STRING_IGNORE_CASE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IGNORE_CASE) +#define DUK_HTHREAD_STRING_IGNORE_CASE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IGNORE_CASE) +#define DUK_STRIDX_MULTILINE 46 /* 'multiline' */ +#define DUK_HEAP_STRING_MULTILINE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MULTILINE) +#define DUK_HTHREAD_STRING_MULTILINE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MULTILINE) +#define DUK_STRIDX_LAST_INDEX 47 /* 'lastIndex' */ +#define DUK_HEAP_STRING_LAST_INDEX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LAST_INDEX) +#define DUK_HTHREAD_STRING_LAST_INDEX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LAST_INDEX) +#define DUK_STRIDX_FLAGS 48 /* 'flags' */ +#define DUK_HEAP_STRING_FLAGS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FLAGS) +#define DUK_HTHREAD_STRING_FLAGS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FLAGS) +#define DUK_STRIDX_INDEX 49 /* 'index' */ +#define DUK_HEAP_STRING_INDEX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INDEX) +#define DUK_HTHREAD_STRING_INDEX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INDEX) +#define DUK_STRIDX_PROTOTYPE 50 /* 'prototype' */ +#define DUK_HEAP_STRING_PROTOTYPE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PROTOTYPE) +#define DUK_HTHREAD_STRING_PROTOTYPE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PROTOTYPE) +#define DUK_STRIDX_CONSTRUCTOR 51 /* 'constructor' */ +#define DUK_HEAP_STRING_CONSTRUCTOR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONSTRUCTOR) +#define DUK_HTHREAD_STRING_CONSTRUCTOR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONSTRUCTOR) +#define DUK_STRIDX_MESSAGE 52 /* 'message' */ +#define DUK_HEAP_STRING_MESSAGE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MESSAGE) +#define DUK_HTHREAD_STRING_MESSAGE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MESSAGE) +#define DUK_STRIDX_LC_BOOLEAN 53 /* 'boolean' */ +#define DUK_HEAP_STRING_LC_BOOLEAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_BOOLEAN) +#define DUK_HTHREAD_STRING_LC_BOOLEAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_BOOLEAN) +#define DUK_STRIDX_LC_NUMBER 54 /* 'number' */ +#define DUK_HEAP_STRING_LC_NUMBER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_NUMBER) +#define DUK_HTHREAD_STRING_LC_NUMBER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_NUMBER) +#define DUK_STRIDX_LC_STRING 55 /* 'string' */ +#define DUK_HEAP_STRING_LC_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_STRING) +#define DUK_HTHREAD_STRING_LC_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_STRING) +#define DUK_STRIDX_LC_SYMBOL 56 /* 'symbol' */ +#define DUK_HEAP_STRING_LC_SYMBOL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_SYMBOL) +#define DUK_HTHREAD_STRING_LC_SYMBOL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_SYMBOL) +#define DUK_STRIDX_LC_OBJECT 57 /* 'object' */ +#define DUK_HEAP_STRING_LC_OBJECT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_OBJECT) +#define DUK_HTHREAD_STRING_LC_OBJECT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_OBJECT) +#define DUK_STRIDX_LC_UNDEFINED 58 /* 'undefined' */ +#define DUK_HEAP_STRING_LC_UNDEFINED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_UNDEFINED) +#define DUK_HTHREAD_STRING_LC_UNDEFINED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_UNDEFINED) +#define DUK_STRIDX_NAN 59 /* 'NaN' */ +#define DUK_HEAP_STRING_NAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NAN) +#define DUK_HTHREAD_STRING_NAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NAN) +#define DUK_STRIDX_INFINITY 60 /* 'Infinity' */ +#define DUK_HEAP_STRING_INFINITY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INFINITY) +#define DUK_HTHREAD_STRING_INFINITY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INFINITY) +#define DUK_STRIDX_MINUS_INFINITY 61 /* '-Infinity' */ +#define DUK_HEAP_STRING_MINUS_INFINITY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MINUS_INFINITY) +#define DUK_HTHREAD_STRING_MINUS_INFINITY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MINUS_INFINITY) +#define DUK_STRIDX_MINUS_ZERO 62 /* '-0' */ +#define DUK_HEAP_STRING_MINUS_ZERO(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MINUS_ZERO) +#define DUK_HTHREAD_STRING_MINUS_ZERO(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MINUS_ZERO) +#define DUK_STRIDX_COMMA 63 /* ',' */ +#define DUK_HEAP_STRING_COMMA(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_COMMA) +#define DUK_HTHREAD_STRING_COMMA(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_COMMA) +#define DUK_STRIDX_NEWLINE_4SPACE 64 /* '\n ' */ +#define DUK_HEAP_STRING_NEWLINE_4SPACE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NEWLINE_4SPACE) +#define DUK_HTHREAD_STRING_NEWLINE_4SPACE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NEWLINE_4SPACE) +#define DUK_STRIDX_BRACKETED_ELLIPSIS 65 /* '[...]' */ +#define DUK_HEAP_STRING_BRACKETED_ELLIPSIS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BRACKETED_ELLIPSIS) +#define DUK_HTHREAD_STRING_BRACKETED_ELLIPSIS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BRACKETED_ELLIPSIS) +#define DUK_STRIDX_INVALID_DATE 66 /* 'Invalid Date' */ +#define DUK_HEAP_STRING_INVALID_DATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INVALID_DATE) +#define DUK_HTHREAD_STRING_INVALID_DATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INVALID_DATE) +#define DUK_STRIDX_LC_ARGUMENTS 67 /* 'arguments' */ +#define DUK_HEAP_STRING_LC_ARGUMENTS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_ARGUMENTS) +#define DUK_HTHREAD_STRING_LC_ARGUMENTS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_ARGUMENTS) +#define DUK_STRIDX_CALLEE 68 /* 'callee' */ +#define DUK_HEAP_STRING_CALLEE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CALLEE) +#define DUK_HTHREAD_STRING_CALLEE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CALLEE) +#define DUK_STRIDX_CALLER 69 /* 'caller' */ +#define DUK_HEAP_STRING_CALLER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CALLER) +#define DUK_HTHREAD_STRING_CALLER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CALLER) +#define DUK_STRIDX_APPLY 70 /* 'apply' */ +#define DUK_HEAP_STRING_APPLY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_APPLY) +#define DUK_HTHREAD_STRING_APPLY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_APPLY) +#define DUK_STRIDX_CONSTRUCT 71 /* 'construct' */ +#define DUK_HEAP_STRING_CONSTRUCT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONSTRUCT) +#define DUK_HTHREAD_STRING_CONSTRUCT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONSTRUCT) +#define DUK_STRIDX_DELETE_PROPERTY 72 /* 'deleteProperty' */ +#define DUK_HEAP_STRING_DELETE_PROPERTY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DELETE_PROPERTY) +#define DUK_HTHREAD_STRING_DELETE_PROPERTY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DELETE_PROPERTY) +#define DUK_STRIDX_GET 73 /* 'get' */ +#define DUK_HEAP_STRING_GET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET) +#define DUK_HTHREAD_STRING_GET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET) +#define DUK_STRIDX_HAS 74 /* 'has' */ +#define DUK_HEAP_STRING_HAS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_HAS) +#define DUK_HTHREAD_STRING_HAS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_HAS) +#define DUK_STRIDX_OWN_KEYS 75 /* 'ownKeys' */ +#define DUK_HEAP_STRING_OWN_KEYS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_OWN_KEYS) +#define DUK_HTHREAD_STRING_OWN_KEYS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_OWN_KEYS) +#define DUK_STRIDX_WELLKNOWN_SYMBOL_TO_PRIMITIVE 76 /* '\x81Symbol.toPrimitive\xff' */ +#define DUK_HEAP_STRING_WELLKNOWN_SYMBOL_TO_PRIMITIVE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WELLKNOWN_SYMBOL_TO_PRIMITIVE) +#define DUK_HTHREAD_STRING_WELLKNOWN_SYMBOL_TO_PRIMITIVE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WELLKNOWN_SYMBOL_TO_PRIMITIVE) +#define DUK_STRIDX_WELLKNOWN_SYMBOL_HAS_INSTANCE 77 /* '\x81Symbol.hasInstance\xff' */ +#define DUK_HEAP_STRING_WELLKNOWN_SYMBOL_HAS_INSTANCE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WELLKNOWN_SYMBOL_HAS_INSTANCE) +#define DUK_HTHREAD_STRING_WELLKNOWN_SYMBOL_HAS_INSTANCE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WELLKNOWN_SYMBOL_HAS_INSTANCE) +#define DUK_STRIDX_WELLKNOWN_SYMBOL_TO_STRING_TAG 78 /* '\x81Symbol.toStringTag\xff' */ +#define DUK_HEAP_STRING_WELLKNOWN_SYMBOL_TO_STRING_TAG(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WELLKNOWN_SYMBOL_TO_STRING_TAG) +#define DUK_HTHREAD_STRING_WELLKNOWN_SYMBOL_TO_STRING_TAG(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WELLKNOWN_SYMBOL_TO_STRING_TAG) +#define DUK_STRIDX_WELLKNOWN_SYMBOL_IS_CONCAT_SPREADABLE 79 /* '\x81Symbol.isConcatSpreadable\xff' */ +#define DUK_HEAP_STRING_WELLKNOWN_SYMBOL_IS_CONCAT_SPREADABLE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WELLKNOWN_SYMBOL_IS_CONCAT_SPREADABLE) +#define DUK_HTHREAD_STRING_WELLKNOWN_SYMBOL_IS_CONCAT_SPREADABLE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WELLKNOWN_SYMBOL_IS_CONCAT_SPREADABLE) +#define DUK_STRIDX_SET_PROTOTYPE_OF 80 /* 'setPrototypeOf' */ +#define DUK_HEAP_STRING_SET_PROTOTYPE_OF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_PROTOTYPE_OF) +#define DUK_HTHREAD_STRING_SET_PROTOTYPE_OF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_PROTOTYPE_OF) +#define DUK_STRIDX___PROTO__ 81 /* '__proto__' */ +#define DUK_HEAP_STRING___PROTO__(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX___PROTO__) +#define DUK_HTHREAD_STRING___PROTO__(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX___PROTO__) +#define DUK_STRIDX_TO_STRING 82 /* 'toString' */ +#define DUK_HEAP_STRING_TO_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_STRING) +#define DUK_HTHREAD_STRING_TO_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_STRING) +#define DUK_STRIDX_TO_JSON 83 /* 'toJSON' */ +#define DUK_HEAP_STRING_TO_JSON(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_JSON) +#define DUK_HTHREAD_STRING_TO_JSON(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_JSON) +#define DUK_STRIDX_TYPE 84 /* 'type' */ +#define DUK_HEAP_STRING_TYPE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TYPE) +#define DUK_HTHREAD_STRING_TYPE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TYPE) +#define DUK_STRIDX_DATA 85 /* 'data' */ +#define DUK_HEAP_STRING_DATA(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DATA) +#define DUK_HTHREAD_STRING_DATA(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DATA) +#define DUK_STRIDX_LC_BUFFER 86 /* 'buffer' */ +#define DUK_HEAP_STRING_LC_BUFFER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_BUFFER) +#define DUK_HTHREAD_STRING_LC_BUFFER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_BUFFER) +#define DUK_STRIDX_LENGTH 87 /* 'length' */ +#define DUK_HEAP_STRING_LENGTH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LENGTH) +#define DUK_HTHREAD_STRING_LENGTH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LENGTH) +#define DUK_STRIDX_SET 88 /* 'set' */ +#define DUK_HEAP_STRING_SET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET) +#define DUK_HTHREAD_STRING_SET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET) +#define DUK_STRIDX_STACK 89 /* 'stack' */ +#define DUK_HEAP_STRING_STACK(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_STACK) +#define DUK_HTHREAD_STRING_STACK(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_STACK) +#define DUK_STRIDX_PC 90 /* 'pc' */ +#define DUK_HEAP_STRING_PC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PC) +#define DUK_HTHREAD_STRING_PC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PC) +#define DUK_STRIDX_LINE_NUMBER 91 /* 'lineNumber' */ +#define DUK_HEAP_STRING_LINE_NUMBER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LINE_NUMBER) +#define DUK_HTHREAD_STRING_LINE_NUMBER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LINE_NUMBER) +#define DUK_STRIDX_INT_TRACEDATA 92 /* '\x82Tracedata' */ +#define DUK_HEAP_STRING_INT_TRACEDATA(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_TRACEDATA) +#define DUK_HTHREAD_STRING_INT_TRACEDATA(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_TRACEDATA) +#define DUK_STRIDX_NAME 93 /* 'name' */ +#define DUK_HEAP_STRING_NAME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NAME) +#define DUK_HTHREAD_STRING_NAME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NAME) +#define DUK_STRIDX_FILE_NAME 94 /* 'fileName' */ +#define DUK_HEAP_STRING_FILE_NAME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FILE_NAME) +#define DUK_HTHREAD_STRING_FILE_NAME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FILE_NAME) +#define DUK_STRIDX_LC_POINTER 95 /* 'pointer' */ +#define DUK_HEAP_STRING_LC_POINTER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_POINTER) +#define DUK_HTHREAD_STRING_LC_POINTER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_POINTER) +#define DUK_STRIDX_INT_TARGET 96 /* '\x82Target' */ +#define DUK_HEAP_STRING_INT_TARGET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_TARGET) +#define DUK_HTHREAD_STRING_INT_TARGET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_TARGET) +#define DUK_STRIDX_INT_NEXT 97 /* '\x82Next' */ +#define DUK_HEAP_STRING_INT_NEXT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_NEXT) +#define DUK_HTHREAD_STRING_INT_NEXT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_NEXT) +#define DUK_STRIDX_INT_BYTECODE 98 /* '\x82Bytecode' */ +#define DUK_HEAP_STRING_INT_BYTECODE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_BYTECODE) +#define DUK_HTHREAD_STRING_INT_BYTECODE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_BYTECODE) +#define DUK_STRIDX_INT_FORMALS 99 /* '\x82Formals' */ +#define DUK_HEAP_STRING_INT_FORMALS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_FORMALS) +#define DUK_HTHREAD_STRING_INT_FORMALS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_FORMALS) +#define DUK_STRIDX_INT_VARMAP 100 /* '\x82Varmap' */ +#define DUK_HEAP_STRING_INT_VARMAP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VARMAP) +#define DUK_HTHREAD_STRING_INT_VARMAP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VARMAP) +#define DUK_STRIDX_INT_SOURCE 101 /* '\x82Source' */ +#define DUK_HEAP_STRING_INT_SOURCE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_SOURCE) +#define DUK_HTHREAD_STRING_INT_SOURCE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_SOURCE) +#define DUK_STRIDX_INT_PC2LINE 102 /* '\x82Pc2line' */ +#define DUK_HEAP_STRING_INT_PC2LINE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_PC2LINE) +#define DUK_HTHREAD_STRING_INT_PC2LINE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_PC2LINE) +#define DUK_STRIDX_INT_MAP 103 /* '\x82Map' */ +#define DUK_HEAP_STRING_INT_MAP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_MAP) +#define DUK_HTHREAD_STRING_INT_MAP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_MAP) +#define DUK_STRIDX_INT_VARENV 104 /* '\x82Varenv' */ +#define DUK_HEAP_STRING_INT_VARENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VARENV) +#define DUK_HTHREAD_STRING_INT_VARENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VARENV) +#define DUK_STRIDX_INT_FINALIZER 105 /* '\x82Finalizer' */ +#define DUK_HEAP_STRING_INT_FINALIZER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_FINALIZER) +#define DUK_HTHREAD_STRING_INT_FINALIZER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_FINALIZER) +#define DUK_STRIDX_INT_VALUE 106 /* '\x82Value' */ +#define DUK_HEAP_STRING_INT_VALUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VALUE) +#define DUK_HTHREAD_STRING_INT_VALUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VALUE) +#define DUK_STRIDX_COMPILE 107 /* 'compile' */ +#define DUK_HEAP_STRING_COMPILE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_COMPILE) +#define DUK_HTHREAD_STRING_COMPILE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_COMPILE) +#define DUK_STRIDX_INPUT 108 /* 'input' */ +#define DUK_HEAP_STRING_INPUT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INPUT) +#define DUK_HTHREAD_STRING_INPUT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INPUT) +#define DUK_STRIDX_ERR_CREATE 109 /* 'errCreate' */ +#define DUK_HEAP_STRING_ERR_CREATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ERR_CREATE) +#define DUK_HTHREAD_STRING_ERR_CREATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ERR_CREATE) +#define DUK_STRIDX_ERR_THROW 110 /* 'errThrow' */ +#define DUK_HEAP_STRING_ERR_THROW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ERR_THROW) +#define DUK_HTHREAD_STRING_ERR_THROW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ERR_THROW) +#define DUK_STRIDX_ENV 111 /* 'env' */ +#define DUK_HEAP_STRING_ENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENV) +#define DUK_HTHREAD_STRING_ENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENV) +#define DUK_STRIDX_HEX 112 /* 'hex' */ +#define DUK_HEAP_STRING_HEX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_HEX) +#define DUK_HTHREAD_STRING_HEX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_HEX) +#define DUK_STRIDX_BASE64