From 88fa92450706e197542d6a69f703ea993ceb6f57 Mon Sep 17 00:00:00 2001 From: Steven Hugg Date: Sat, 15 Aug 2020 15:03:56 -0500 Subject: [PATCH] basic: fuzz test fixes, DEF cycle detector --- package-lock.json | 887 ++++++++++++++++++++++++++++++++++- package.json | 1 + src/common/baseplatform.ts | 2 + src/common/basic/compiler.ts | 133 ++++-- src/common/basic/run.ts | 107 +++-- src/common/basic/runtime.ts | 64 ++- 6 files changed, 1107 insertions(+), 87 deletions(-) diff --git a/package-lock.json b/package-lock.json index d7077f05..09244cbd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,6 +4,156 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/generator": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.11.0.tgz", + "integrity": "sha512-fEm3Uzw7Mc9Xi//qU20cBKatTfs2aOtKqmvy/Vm7RkJEGFQ4xc9myCfbXxqK//ZS8MR/ciOHw6meGASJuKmDfQ==", + "dev": true, + "requires": { + "@babel/types": "^7.11.0", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/helper-function-name": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz", + "integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz", + "integrity": "sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz", + "integrity": "sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg==", + "dev": true, + "requires": { + "@babel/types": "^7.11.0" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", + "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", + "dev": true + }, + "@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@babel/parser": { + "version": "7.11.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.11.3.tgz", + "integrity": "sha512-REo8xv7+sDxkKvoxEywIdsNFiZLybwdI7hcT5uEPyQrSMB4YQ973BfC9OOrD/81MaIjh6UxdulIQXkjmiH3PcA==", + "dev": true + }, + "@babel/template": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz", + "integrity": "sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/parser": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/traverse": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.11.0.tgz", + "integrity": "sha512-ZB2V+LskoWKNpMq6E5UUCrjtDUh5IOTAyIl0dTjIEoXum/iKWkoIEKIRDnUucO6f+2FzNkE0oD4RLKoPIufDtg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.11.0", + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.11.0", + "@babel/parser": "^7.11.0", + "@babel/types": "^7.11.0", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.19" + } + }, + "@babel/types": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.11.0.tgz", + "integrity": "sha512-O53yME4ZZI0jO1EVGtF1ePGl0LHirG4P1ibcD80XyzZcKhcMFeCXmh4Xb1ifGBIV233Qg12x4rBfQgA+tmOukA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.19", + "to-fast-properties": "^2.0.0" + } + }, "@electron/get": { "version": "1.12.2", "resolved": "https://registry.npmjs.org/@electron/get/-/get-1.12.2.tgz", @@ -54,6 +204,36 @@ "@types/jquery": "*" } }, + "@types/escodegen": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@types/escodegen/-/escodegen-0.0.6.tgz", + "integrity": "sha1-UjCpznluBCzabwhtvxnyLqMwZZw=", + "dev": true + }, + "@types/esprima": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/esprima/-/esprima-4.0.2.tgz", + "integrity": "sha512-DKqdyuy7Go7ir6iKhZ0jUvgt/h9Q5zb9xS+fLeeXD2QSHv8gC6TimgujBBGfw8dHrpx4+u2HlMv7pkYOOfuUqg==", + "dev": true, + "requires": { + "@types/estree": "*" + } + }, + "@types/estraverse": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@types/estraverse/-/estraverse-0.0.6.tgz", + "integrity": "sha1-Zp9833KreX5hJfjQD+0z1M8wwiE=", + "dev": true, + "requires": { + "@types/estree": "*" + } + }, + "@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", + "dev": true + }, "@types/file-saver": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@types/file-saver/-/file-saver-2.0.1.tgz", @@ -176,6 +356,21 @@ "picomatch": "^2.0.4" } }, + "append-transform": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-1.0.0.tgz", + "integrity": "sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw==", + "dev": true, + "requires": { + "default-require-extensions": "^2.0.0" + } + }, + "archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", + "dev": true + }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -427,6 +622,36 @@ } } }, + "caching-transform": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-3.0.2.tgz", + "integrity": "sha512-Mtgcv3lh3U0zRii/6qVgQODdPA4G3zhG+jtbCWj39RXuUFTMzH0vcdMtaJS1jPowd+It2Pqr6y3NJMQqOqCE2w==", + "dev": true, + "requires": { + "hasha": "^3.0.0", + "make-dir": "^2.0.0", + "package-hash": "^3.0.0", + "write-file-atomic": "^2.4.2" + }, + "dependencies": { + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + } + } + }, "camelcase": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", @@ -571,6 +796,12 @@ "integrity": "sha1-iSGAEgid/Jtnoze6Fi8VyI4PEEg=", "dev": true }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, "compare-version": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/compare-version/-/compare-version-0.1.2.tgz", @@ -646,12 +877,62 @@ "proto-list": "~1.2.1" } }, + "convert-source-map": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true }, + "cp-file": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/cp-file/-/cp-file-6.2.0.tgz", + "integrity": "sha512-fmvV4caBnofhPe8kOcitBwSn2f39QLjnAnGq3gO9dfd75mUytzKNZB1hde6QHunW2Rt+OwuBOMc3i1tNElbszA==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "make-dir": "^2.0.0", + "nested-error-stacks": "^2.0.0", + "pify": "^4.0.1", + "safe-buffer": "^5.0.1" + }, + "dependencies": { + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + } + } + }, + "cross-spawn": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz", + "integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=", + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "which": "^1.2.9" + } + }, "cssom": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.6.tgz", @@ -719,12 +1000,35 @@ "mimic-response": "^1.0.0" } }, + "deep-equal": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", + "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", + "dev": true, + "requires": { + "is-arguments": "^1.0.4", + "is-date-object": "^1.0.1", + "is-regex": "^1.0.4", + "object-is": "^1.0.1", + "object-keys": "^1.1.1", + "regexp.prototype.flags": "^1.2.0" + } + }, "deep-is": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "dev": true }, + "default-require-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-2.0.0.tgz", + "integrity": "sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc=", + "dev": true, + "requires": { + "strip-bom": "^3.0.0" + } + }, "defer-to-connect": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", @@ -1101,8 +1405,7 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", - "dev": true, - "optional": true + "dev": true }, "escape-string-regexp": { "version": "1.0.5", @@ -1270,6 +1573,35 @@ "to-regex-range": "^5.0.1" } }, + "find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + }, + "dependencies": { + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + } + } + }, "find-up": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", @@ -1310,6 +1642,16 @@ } } }, + "foreground-child": { + "version": "1.5.6", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-1.5.6.tgz", + "integrity": "sha1-T9ca0t/elnibmApcCilZN8svXOk=", + "dev": true, + "requires": { + "cross-spawn": "^4", + "signal-exit": "^3.0.0" + } + }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -1515,6 +1857,12 @@ "tunnel": "^0.0.6" } }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, "globalthis": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.1.tgz", @@ -1617,6 +1965,15 @@ "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", "dev": true }, + "hasha": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hasha/-/hasha-3.0.0.tgz", + "integrity": "sha1-UqMvq4Vp1BymmmH/GiFPjrfIvTk=", + "dev": true, + "requires": { + "is-stream": "^1.0.1" + } + }, "he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -1638,6 +1995,12 @@ "whatwg-encoding": "^1.0.1" } }, + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, "http-cache-semantics": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", @@ -1670,6 +2033,12 @@ "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=", "dev": true }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -1693,6 +2062,18 @@ "dev": true, "optional": true }, + "inversify": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/inversify/-/inversify-5.0.1.tgz", + "integrity": "sha512-Ieh06s48WnEYGcqHepdsJUIJUXpwH5o5vodAX+DK2JA/gjy4EbEcQZxw+uFfzysmKjiLXGYwNG3qDZsKVMcINQ==", + "dev": true + }, + "is-arguments": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz", + "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==", + "dev": true + }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -1811,11 +2192,133 @@ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", "dev": true }, + "istanbul-lib-coverage": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", + "dev": true + }, + "istanbul-lib-hook": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-2.0.7.tgz", + "integrity": "sha512-vrRztU9VRRFDyC+aklfLoeXyNdTfga2EI3udDGn4cZ6fpSXpHLV9X6CHvfoMCPtggg8zvDDmC4b9xfu0z6/llA==", + "dev": true, + "requires": { + "append-transform": "^1.0.0" + } + }, + "istanbul-lib-instrument": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz", + "integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==", + "dev": true, + "requires": { + "@babel/generator": "^7.4.0", + "@babel/parser": "^7.4.3", + "@babel/template": "^7.4.0", + "@babel/traverse": "^7.4.3", + "@babel/types": "^7.4.0", + "istanbul-lib-coverage": "^2.0.5", + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "istanbul-lib-report": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz", + "integrity": "sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "supports-color": "^6.1.0" + }, + "dependencies": { + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "istanbul-lib-source-maps": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", + "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "rimraf": "^2.6.3", + "source-map": "^0.6.1" + }, + "dependencies": { + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + } + } + }, + "istanbul-reports": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.7.tgz", + "integrity": "sha512-uu1F/L1o5Y6LzPVSVZXNOoD/KXpJue9aeLRd0sM9uMXfZvzomB0WxVamWb5ue8kA2vVWEmW7EG+A5n3f1kqHKg==", + "dev": true, + "requires": { + "html-escaper": "^2.0.0" + } + }, "jquery": { "version": "3.5.1", "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.5.1.tgz", "integrity": "sha512-XwIBPqcMn57FxfT+Go5pzySnm4KWkT1Tv7gjrpT1srtf8Weynl6R273VJ5GjkRb51IzMp5nbaPjJXMWeju2MKg==" }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, "js-yaml": { "version": "3.13.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", @@ -1873,12 +2376,127 @@ "xml-name-validator": "^3.0.0" } }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "jsfuzz": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/jsfuzz/-/jsfuzz-1.0.14.tgz", + "integrity": "sha512-/aSOYF5Gv1AcHI/hrHLHazPH4Xxw1FPcv2IDyJX+sH9BE3OVpyzHwiZJJyvIlC2RMJaKbujIFXRlyb8PEH298Q==", + "dev": true, + "requires": { + "@types/escodegen": "^0.0.6", + "@types/esprima": "^4.0.2", + "@types/estraverse": "^0.0.6", + "@types/estree": "^0.0.39", + "deep-equal": "^1.1.0", + "escodegen": "^1.12.0", + "esprima": "^4.0.1", + "estraverse": "^4.3.0", + "inversify": "^5.0.1", + "nyc": "^14.1.1", + "pidusage": "^2.0.17", + "reflect-metadata": "^0.1.13", + "yargs": "^14.2.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "escodegen": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", + "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", + "dev": true, + "requires": { + "esprima": "^4.0.1", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "yargs": { + "version": "14.2.3", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-14.2.3.tgz", + "integrity": "sha512-ZbotRWhF+lkjijC/VhmOT9wSgyBQ7+zr13+YLkhfsSiTriYsMzkTUFP18pFhWwBeMa5gUc1MzbhrO6/VB7c9Xg==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "decamelize": "^1.2.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^15.0.1" + } + }, + "yargs-parser": { + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-15.0.1.tgz", + "integrity": "sha512-0OAMV2mAZQrs3FkNpDQcBk1x5HXb8X4twADss4S0Iuk+2dGnLOE/fRHrsYm542GduMveyA77OF4wrNJuanRCWw==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, "json-buffer": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", "dev": true }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, "json-schema": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", @@ -2023,6 +2641,12 @@ "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", "dev": true }, + "lodash.flattendeep": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", + "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", + "dev": true + }, "lodash.get": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", @@ -2137,6 +2761,15 @@ } } }, + "merge-source-map": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz", + "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", + "dev": true, + "requires": { + "source-map": "^0.6.1" + } + }, "mime-db": { "version": "1.38.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.38.0.tgz", @@ -2304,6 +2937,12 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "nested-error-stacks": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz", + "integrity": "sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug==", + "dev": true + }, "node-environment-flags": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz", @@ -2360,6 +2999,57 @@ "integrity": "sha512-ZG3bLAvdHmhIjaQ/Db1qvBxsGvFMLIRpQszyqbg31VJ53UP++uZX1/gf3Ut96pdwN9AuDwlMqIYLm0UPCdUeHg==", "dev": true }, + "nyc": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/nyc/-/nyc-14.1.1.tgz", + "integrity": "sha512-OI0vm6ZGUnoGZv/tLdZ2esSVzDwUC88SNs+6JoSOMVxA+gKMB8Tk7jBwgemLx4O40lhhvZCVw1C+OYLOBOPXWw==", + "dev": true, + "requires": { + "archy": "^1.0.0", + "caching-transform": "^3.0.2", + "convert-source-map": "^1.6.0", + "cp-file": "^6.2.0", + "find-cache-dir": "^2.1.0", + "find-up": "^3.0.0", + "foreground-child": "^1.5.6", + "glob": "^7.1.3", + "istanbul-lib-coverage": "^2.0.5", + "istanbul-lib-hook": "^2.0.7", + "istanbul-lib-instrument": "^3.3.0", + "istanbul-lib-report": "^2.0.8", + "istanbul-lib-source-maps": "^3.0.6", + "istanbul-reports": "^2.2.4", + "js-yaml": "^3.13.1", + "make-dir": "^2.1.0", + "merge-source-map": "^1.1.0", + "resolve-from": "^4.0.0", + "rimraf": "^2.6.3", + "signal-exit": "^3.0.2", + "spawn-wrap": "^1.4.2", + "test-exclude": "^5.2.3", + "uuid": "^3.3.2", + "yargs": "^13.2.2", + "yargs-parser": "^13.0.0" + }, + "dependencies": { + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + } + } + }, "oauth-sign": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", @@ -2372,6 +3062,16 @@ "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==", "dev": true }, + "object-is": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.2.tgz", + "integrity": "sha512-5lHCz+0uufF6wZ7CRFWJN3hp8Jqblpgve06U5CMQ3f//6iDjPr2PEo9MWCjEssDsa+UZEL4PkFpr+BMop6aKzQ==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, "object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", @@ -2449,6 +3149,12 @@ "wordwrap": "~1.0.0" } }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true + }, "p-cancelable": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", @@ -2476,6 +3182,18 @@ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" }, + "package-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-3.0.0.tgz", + "integrity": "sha512-lOtmukMDVvtkL84rJHI7dpTYq+0rli8N2wlnqUcBuDWCfVhRUfOmnR9SsoHFMLpACvEV60dX7rd0rFaYDZI+FA==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.15", + "hasha": "^3.0.0", + "lodash.flattendeep": "^4.4.0", + "release-zalgo": "^1.0.0" + } + }, "pako": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", @@ -2557,12 +3275,37 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==" }, + "pidusage": { + "version": "2.0.21", + "resolved": "https://registry.npmjs.org/pidusage/-/pidusage-2.0.21.tgz", + "integrity": "sha512-cv3xAQos+pugVX+BfXpHsbyz/dLzX+lr44zNMsYiGxUw+kV5sgQCIcLd1z+0vq+KyC7dJ+/ts2PsfgWfSC3WXA==", + "dev": true, + "requires": { + "safe-buffer": "^5.2.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + } + } + }, "pify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", "dev": true, - "optional": true + "requires": { + "find-up": "^3.0.0" + } }, "pkg-up": { "version": "3.1.0", @@ -2765,6 +3508,25 @@ "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" }, + "regexp.prototype.flags": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz", + "integrity": "sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + } + }, + "release-zalgo": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", + "integrity": "sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=", + "dev": true, + "requires": { + "es6-error": "^4.0.1" + } + }, "request": { "version": "2.88.0", "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", @@ -2852,6 +3614,12 @@ "path-parse": "^1.0.6" } }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, "responselike": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", @@ -2867,6 +3635,15 @@ "integrity": "sha1-2V6Imo/LHmwaT6LMyL46QaL80YU=", "dev": true }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, "roarr": { "version": "2.15.3", "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.3.tgz", @@ -2968,12 +3745,31 @@ "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", "dev": true }, + "signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "dev": true + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "dev": true + }, + "spawn-wrap": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-1.4.3.tgz", + "integrity": "sha512-IgB8md0QW/+tWqcavuFgKYR/qIRvJkRLPJDFaoXtLLUaVcCDK0+HeFTkmQHj3eprcYhc+gOl0aEA1w7qZlYezw==", "dev": true, - "optional": true + "requires": { + "foreground-child": "^1.5.6", + "mkdirp": "^0.5.0", + "os-homedir": "^1.0.1", + "rimraf": "^2.6.2", + "signal-exit": "^3.0.2", + "which": "^1.3.0" + } }, "spdx-correct": { "version": "3.1.1", @@ -3149,12 +3945,84 @@ "integrity": "sha1-rifbOPZgp64uHDt9G8KQgZuFGeY=", "dev": true }, + "test-exclude": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz", + "integrity": "sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g==", + "dev": true, + "requires": { + "glob": "^7.1.3", + "minimatch": "^3.0.4", + "read-pkg-up": "^4.0.0", + "require-main-filename": "^2.0.0" + }, + "dependencies": { + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + } + }, + "read-pkg-up": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", + "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", + "dev": true, + "requires": { + "find-up": "^3.0.0", + "read-pkg": "^3.0.0" + } + } + } + }, "tiny-emitter": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", "integrity": "sha1-HRpW7fxRxD6GPLtTgqcjMONVVCM=", "dev": true }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + }, "to-readable-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", @@ -3465,6 +4333,17 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, + "write-file-atomic": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", + "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, "ws": { "version": "6.1.3", "resolved": "https://registry.npmjs.org/ws/-/ws-6.1.3.tgz", diff --git a/package.json b/package.json index 7f491885..625d6511 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "electron-packager": "^15.0.0", "file-saver": "^2.0.2", "jsdom": "^12.2.0", + "jsfuzz": "^1.0.14", "jszip": "^3.5.0", "localforage": "^1.9.0", "lzg": "^1.0.x", diff --git a/src/common/baseplatform.ts b/src/common/baseplatform.ts index 8dcbba88..fda1eba4 100644 --- a/src/common/baseplatform.ts +++ b/src/common/baseplatform.ts @@ -132,6 +132,8 @@ export interface Platform { startProbing?() : ProbeRecorder; stopProbing?() : void; + + isBlocked?() : boolean; // is blocked, halted, or waiting for input? } export interface Preset { diff --git a/src/common/basic/compiler.ts b/src/common/basic/compiler.ts index 156d6725..38c5f15d 100644 --- a/src/common/basic/compiler.ts +++ b/src/common/basic/compiler.ts @@ -6,8 +6,8 @@ export interface BASICOptions { asciiOnly : boolean; // reject non-ASCII chars? uppercaseOnly : boolean; // convert everything to uppercase? optionalLabels : boolean; // can omit line numbers and use labels? - optionalWhitespace : boolean; // can "crunch" keywords? - varNaming : 'A'|'A1'|'AA'|'*'; // only allow A0-9 for numerics, single letter for arrays/strings + optionalWhitespace : boolean; // can "crunch" keywords? also, eat extra ":" delims + varNaming : 'A'|'A1'|'AA'|'*'; // only allow A0-9 for numerics, single letter for arrays/strings squareBrackets : boolean; // "[" and "]" interchangable with "(" and ")"? tickComments : boolean; // support 'comments? hexOctalConsts : boolean; // support &H and &O integer constants? @@ -43,6 +43,8 @@ export interface BASICOptions { endStmtRequired : boolean; // need END at end? // MISC commandsPerSec? : number; // how many commands per second? + maxLinesPerFile? : number; // limit on # of lines + maxArrayElements? : number; // max array elements (all dimensions) } export interface SourceLocated { @@ -59,8 +61,8 @@ export class CompileError extends Error { } // Lexer regular expression -- each (capture group) handles a different token type -// FLOAT INT HEXOCTAL REMARK IDENT STRING RELOP EXP OPERATORS OTHER WS -const re_toks = /([0-9.]+[E][+-]?\d+|\d+[.][E0-9]*|[.][E0-9]+)|[0]*(\d+)|&([OH][0-9A-F]+)|(['].*)|(\w+[$]?)|(".*?")|([<>]?[=<>#])|(\*\*)|([-+*/^,;:()\[\]\?\\])|(\S+)|(\s+)/gi; +// FLOAT INT HEXOCTAL REMARK IDENT STRING RELOP EXP OPERATORS OTHER WS +const re_toks = /([0-9.]+[E][+-]?\d+|\d+[.][E0-9]*|[.][E0-9]+)|[0]*(\d+)|&([OH][0-9A-F]+)|(['].*)|([A-Z_]\w*[$]?)|(".*?")|([<>]?[=<>#])|(\*\*)|([-+*/^,;:()\[\]\?\\])|(\S+)|(\s+)/gi; export enum TokenType { EOL = 0, @@ -302,6 +304,19 @@ function stripQuotes(s: string) { return s.substr(1, s.length-2); } +function isLiteral(arg: Expr): arg is Literal { + return (arg as any).value != null; +} +function isLookup(arg: Expr): arg is IndOp { + return (arg as any).name != null; +} +function isBinOp(arg: Expr): arg is BinOp { + return (arg as any).op != null && (arg as any).left != null && (arg as any).right != null; +} +function isUnOp(arg: Expr): arg is UnOp { + return (arg as any).op != null && (arg as any).expr != null; +} + ///// BASIC PARSER export class BASICParser { @@ -311,7 +326,9 @@ export class BASICParser { listings: CodeListingMap; labels: { [label: string]: BASICLine }; targets: { [targetlabel: string]: SourceLocation }; - refs: { [name: string]: SourceLocation }; // references + varrefs: { [name: string]: SourceLocation }; // references + fnrefs: { [name: string]: string[] }; // DEF FN call graph + maxlinelen : number = 255; // maximum line length path : string; lineno : number; @@ -327,7 +344,8 @@ export class BASICParser { this.lineno = 0; this.curlabel = null; this.listings = {}; - this.refs = {}; + this.varrefs = {}; + this.fnrefs = {}; this.optionCount = 0; } addError(msg: string, loc?: SourceLocation) { @@ -382,10 +400,7 @@ export class BASICParser { } } else this.dialectError(`optional line numbers`); case TokenType.Int: - if (this.labels[tok.str] != null) this.compileError(`There's a duplicated label "${tok.str}".`); - this.labels[tok.str] = line; - line.label = tok.str; - this.curlabel = tok.str; + this.setCurrentLabel(line, tok.str); break; case TokenType.HexOctalInt: case TokenType.Float: @@ -398,9 +413,16 @@ export class BASICParser { break; } } + setCurrentLabel(line: BASICLine, str: string) { + if (this.labels[str] != null) this.compileError(`There's a duplicated label "${str}".`); + this.labels[str] = line; + line.label = str; + this.curlabel = str; + this.tokens.forEach((tok) => tok.$loc.label = str); + } parseFile(file: string, path: string) : BASICProgram { this.path = path; - var txtlines = file.split(/\n|\r\n/); + var txtlines = file.split(/\n|\r\n?/); var pgmlines = txtlines.map((line) => this.parseLine(line)); var program = { opts: this.opts, lines: pgmlines }; this.checkAll(program); @@ -416,9 +438,7 @@ export class BASICParser { return {label:null, stmts:[]}; } } - tokenize(line: string) : void { - this.lineno++; - this.tokens = []; + _tokenize(line: string) : void { // split identifier regex (if token-crunching enabled) let splitre = this.opts.optionalWhitespace && new RegExp('('+this.opts.validKeywords.map(s => `${s}`).join('|')+')'); // iterate over each token via re_toks regex @@ -428,7 +448,7 @@ export class BASICParser { for (var i = 1; i <= lastTokType; i++) { let s : string = m[i]; if (s != null) { - let loc = { path: this.path, line: this.lineno, start: m.index, end: m.index+s.length, label: this.curlabel }; + let loc = { path: this.path, line: this.lineno, start: m.index, end: m.index+s.length }; // maybe we don't support unicode in 1975? if (this.opts.asciiOnly && !/^[\x00-\x7F]*$/.test(s)) this.dialectError(`non-ASCII characters`); @@ -437,6 +457,9 @@ export class BASICParser { s = s.toUpperCase(); // DATA statement captures whitespace too if (s == 'DATA') lastTokType = TokenType.Whitespace; + // certain keywords shouldn't split for rest of line + if (s == 'DATA') splitre = null; + if (s == 'OPTION') splitre = null; // REM means ignore rest of statement if (lastTokType == TokenType.CatchAll && s.startsWith('REM')) { s = 'REM'; @@ -451,26 +474,31 @@ export class BASICParser { } // un-crunch tokens? if (splitre && i == TokenType.Ident) { - var splittoks = s.split(splitre); - splittoks.forEach((ss) => { - if (ss != '') { - // leftover might be integer - i = /^[0-9]+$/.test(ss) ? TokenType.Int : TokenType.Ident; - // disable crunching after this token? - if (ss == 'DATA' || ss == 'OPTION') - splitre = null; + var splittoks = s.split(splitre).filter((s) => s != ''); // only non-empties + if (splittoks.length > 1) { + splittoks.forEach((ss) => { + // check to see if leftover might be integer, or identifier + if (/^[0-9]+$/.test(ss)) i = TokenType.Int; + else if (/^[A-Z_]\w*[$]?$/.test(ss)) i = TokenType.Ident; + else this.compileError(`Try adding whitespace before "${ss}".`); this.tokens.push({str: ss, type: i, $loc:loc}); - } - }); - } else { - // add token to list - this.tokens.push({str: s, type: i, $loc:loc}); + }); + s = null; + } } + // add token to list + if (s) this.tokens.push({str: s, type: i, $loc:loc}); break; } } } - this.eol = { type: TokenType.EOL, str: "", $loc: { path: this.path, line: this.lineno, start: line.length, label: this.curlabel } }; + } + tokenize(line: string) : void { + this.lineno++; + this.tokens = []; // can't have errors until this is set + this.eol = { type: TokenType.EOL, str: "", $loc: { path: this.path, line: this.lineno, start: line.length } }; + if (line.length > this.maxlinelen) this.compileError(`A line should be no more than ${this.maxlinelen} characters long.`); + this._tokenize(line); } parse() : BASICLine { var line = {label: null, stmts: []}; @@ -502,6 +530,9 @@ export class BASICParser { return false; } parseStatement(): Statement | null { + // eat extra ":" (should have separate property for this) + if (this.opts.optionalWhitespace && this.peekToken().str == ':') return null; + // get the command word var cmdtok = this.consumeToken(); var cmd = cmdtok.str; var stmt; @@ -510,6 +541,7 @@ export class BASICParser { if (cmdtok.str.startsWith("'") && !this.opts.tickComments) this.dialectError(`tick remarks`); return null; case TokenType.Operator: + // "?" is alias for "PRINT" on some platforms if (cmd == this.validKeyword('?')) cmd = 'PRINT'; case TokenType.Ident: // ignore remarks @@ -534,8 +566,11 @@ export class BASICParser { this.pushbackToken(cmdtok); stmt = this.stmt__LET(); break; + } else { + this.compileError(`I don't understand the command "${cmd}".`); } case TokenType.EOL: + if (this.opts.optionalWhitespace) return null; default: this.compileError(`There should be a command here.`); return null; @@ -547,7 +582,7 @@ export class BASICParser { var tok = this.consumeToken(); switch (tok.type) { case TokenType.Ident: - this.refs[tok.str] = tok.$loc; + this.varrefs[tok.str] = tok.$loc; let args = null; if (this.peekToken().str == '(') { this.expectToken('('); @@ -745,6 +780,20 @@ export class BASICParser { break; } } + visitExpr(expr: Expr, callback: (expr:Expr) => void) { + if (isBinOp(expr)) { + this.visitExpr(expr.left, callback); + this.visitExpr(expr.right, callback); + } + if (isUnOp(expr)) { + this.visitExpr(expr.expr, callback); + } + if (isLookup(expr) && expr.args != null) { + for (var arg of expr.args) + this.visitExpr(arg, callback); + } + callback(expr); + } //// STATEMENTS @@ -865,6 +914,10 @@ export class BASICParser { this.compileError(`An array defined by DIM must have at least one dimension.`) else if (arr.args.length > this.opts.maxDimensions) this.dialectError(`more than ${this.opts.maxDimensions} dimensional arrays`); + for (var arrdim of arr.args) { + if (isLiteral(arrdim) && arrdim.value < this.opts.defaultArrayBase) + this.compileError(`An array dimension cannot be less than ${this.opts.defaultArrayBase}.`); + } }); return { command:'DIM', args:lexprs }; } @@ -925,8 +978,26 @@ export class BASICParser { if (!lexpr.name.startsWith('FN')) this.compileError(`Functions defined with DEF must begin with the letters "FN".`) this.expectToken("="); var func = this.parseExpr(); + // build call graph to detect cycles + this.visitExpr(func, (expr:Expr) => { + if (isLookup(expr) && expr.name.startsWith('FN')) { + if (!this.fnrefs[lexpr.name]) + this.fnrefs[lexpr.name] = []; + this.fnrefs[lexpr.name].push(expr.name); + } + }); + this.checkCallGraph(lexpr.name, new Set()); return { command:'DEF', lexpr:lexpr, def:func }; } + // detect cycles in call graph starting at function 'name' + checkCallGraph(name: string, visited: Set) { + if (visited.has(name)) this.compileError(`There was a cycle in the function definition graph for ${name}.`); + visited.add(name); + var refs = this.fnrefs[name] || []; + for (var ref of refs) + this.checkCallGraph(ref, visited); // recurse + visited.delete(name); + } stmt__POP() : NoArgStatement { return { command:'POP' }; } @@ -1550,9 +1621,7 @@ export const MODERN_BASIC : BASICOptions = { // TODO: integer vars // TODO: DEFINT/DEFSTR -// TODO: superfluous ":" ignored on MS basics only? // TODO: excess INPUT ignored, error msg -// TODO: max line len? export const DIALECTS = { "DEFAULT": ALTAIR_BASIC41, diff --git a/src/common/basic/run.ts b/src/common/basic/run.ts index d7722c36..c31e2f80 100644 --- a/src/common/basic/run.ts +++ b/src/common/basic/run.ts @@ -3,43 +3,6 @@ import { BASICParser, DIALECTS, BASICOptions } from "./compiler"; import { BASICRuntime } from "./runtime"; import { lpad, rpad } from "../util"; -function dumpDialectInfo() { - var dialects = new Set(); - var array = {}; - var SELECTED_DIALECTS = ['TINY','ECMA55','HP','DEC','ALTAIR','BASIC80','MODERN']; - SELECTED_DIALECTS.forEach((dkey) => { - dialects.add(DIALECTS[dkey]); - }); - var ALL_KEYWORDS = new Set(); - dialects.forEach((dialect) => { - Object.entries(dialect).forEach(([key, value]) => { - if (value === null) value = "all"; - else if (value === true) value = "Y"; - else if (value === false) value = "-"; - else if (Array.isArray(value)) - value = value.length; - if (!array[key]) array[key] = []; - array[key].push(value); - if (dialect.validKeywords) dialect.validKeywords.map(ALL_KEYWORDS.add.bind(ALL_KEYWORDS)); - }); - }); - dialects.forEach((dialect) => { - ALL_KEYWORDS.forEach((keyword) => { - if (parser.supportsKeyword(keyword)) { - var has = dialect.validKeywords == null || dialect.validKeywords.indexOf(keyword) >= 0; - if (!array[keyword]) array[keyword] = []; - array[keyword].push(has ? "Y" : "-"); - } - }); - }); - Object.entries(array).forEach(([key, arr]) => { - var s = rpad(key, 30) + "|"; - s += (arr as []).map((val) => rpad(val, 9)).join('|'); - console.log(s); - }); - process.exit(0); -} - var readline = require('readline'); var rl = readline.createInterface({ input: process.stdin, @@ -77,16 +40,20 @@ var data = fs.readFileSync(filename, 'utf-8'); try { var pgm = parser.parseFile(data, filename); } catch (e) { + console.log(e); if (parser.errors.length == 0) console.log(`@@@ ${e}`); - else - console.log(e); } parser.errors.forEach((err) => console.log(`@@@ ${err.msg} (line ${err.label})`)); if (parser.errors.length) process.exit(2); // run program -runtime.load(pgm); +try { + runtime.load(pgm); +} catch (e) { + console.log(`### ${e.message} (line ${runtime.getCurrentSourceLocation().label})`); + process.exit(1); +} runtime.reset(); runtime.print = (s:string) => { fs.writeSync(1, s+""); @@ -125,3 +92,63 @@ runtime.resume = function() { }); } runtime.resume(); + +///// + +function dumpDialectInfo() { + var dialects = new Set(); + var array = {}; + var SELECTED_DIALECTS = ['TINY','ECMA55','HP','DEC','ALTAIR','BASIC80','MODERN']; + SELECTED_DIALECTS.forEach((dkey) => { + dialects.add(DIALECTS[dkey]); + }); + var ALL_KEYWORDS = new Set(); + var ALL_FUNCTIONS = new Set(); + var ALL_OPERATORS = new Set(); + dialects.forEach((dialect) => { + Object.entries(dialect).forEach(([key, value]) => { + if (value === null) value = "all"; + else if (value === true) value = "Y"; + else if (value === false) value = "-"; + else if (Array.isArray(value)) + value = value.length; + if (!array[key]) array[key] = []; + array[key].push(value); + if (dialect.validKeywords) dialect.validKeywords.map(ALL_KEYWORDS.add.bind(ALL_KEYWORDS)); + if (dialect.validFunctions) dialect.validFunctions.map(ALL_FUNCTIONS.add.bind(ALL_FUNCTIONS)); + if (dialect.validOperators) dialect.validOperators.map(ALL_OPERATORS.add.bind(ALL_OPERATORS)); + }); + }); + dialects.forEach((dialect) => { + ALL_KEYWORDS.forEach((keyword) => { + if (parser.supportsKeyword(keyword)) { + var has = dialect.validKeywords == null || dialect.validKeywords.indexOf(keyword) >= 0; + keyword = '`'+keyword+'`' + if (!array[keyword]) array[keyword] = []; + array[keyword].push(has ? "Y" : "-"); + } + }); + ALL_OPERATORS.forEach((keyword) => { + var has = dialect.validOperators == null || dialect.validOperators.indexOf(keyword) >= 0; + if (keyword == '#') keyword = '*#*'; + keyword = "*a* " + keyword + " *b*"; + if (!array[keyword]) array[keyword] = []; + array[keyword].push(has ? "Y" : "-"); + }); + ALL_FUNCTIONS.forEach((keyword) => { + if (runtime.supportsFunction(keyword)) { + var has = dialect.validFunctions == null || dialect.validFunctions.indexOf(keyword) >= 0; + keyword = '`'+keyword+'()`' + if (!array[keyword]) array[keyword] = []; + array[keyword].push(has ? "Y" : "-"); + } + }); + }); + Object.entries(array).forEach(([key, arr]) => { + var s = rpad(key, 30) + "|"; + s += (arr as []).map((val) => rpad(val, 9)).join('|'); + console.log(s); + }); + process.exit(0); +} + diff --git a/src/common/basic/runtime.ts b/src/common/basic/runtime.ts index 84fcc76c..2c4f1608 100644 --- a/src/common/basic/runtime.ts +++ b/src/common/basic/runtime.ts @@ -66,6 +66,8 @@ class RNG { } }; +const DEFAULT_MAX_ARRAY_ELEMENTS = 1024*1024; + export class BASICRuntime { program : basic.BASICProgram; @@ -111,6 +113,7 @@ export class BASICRuntime { // initialize program this.program = program; this.opts = program.opts; + if (!this.opts.maxArrayElements) this.opts.maxArrayElements = DEFAULT_MAX_ARRAY_ELEMENTS; this.label2pc = {}; this.label2dataptr = {}; this.allstmts = []; @@ -194,9 +197,12 @@ export class BASICRuntime { // if no valid function list, look for ABC...() functions in prototype if (!fnames) fnames = Object.keys(BASICRuntime.prototype).filter((name) => /^[A-Z]{3,}[$]?$/.test(name)); var dict = {}; - for (var fn of fnames) if (this[fn]) dict[fn] = this[fn].bind(this); + for (var fn of fnames) if (this.supportsFunction(fn)) dict[fn] = this[fn].bind(this); return dict; } + supportsFunction(fnname: string) { + return typeof this[fnname] === 'function'; + } runtimeError(msg : string) { this.curpc--; // we did curpc++ before executing statement @@ -257,7 +263,7 @@ export class BASICRuntime { if (this.trace) console.log(functext); stmt.$run = this.compileJS(functext); } catch (e) { - console.log(functext); + if (functext) console.log(functext); throw e; } } @@ -279,14 +285,16 @@ export class BASICRuntime { } skipToElse() { - do { + while (this.curpc < this.allstmts.length) { // in Altair BASIC, ELSE is bound to the right-most IF // TODO: this is complicated, we should just have nested expressions var cmd = this.allstmts[this.curpc].command; if (cmd == 'ELSE') { this.curpc++; break; } else if (cmd == 'IF') return this.skipToEOL(); this.curpc++; - } while (this.curpc < this.allstmts.length && !this.pc2line.get(this.curpc)); + if (this.pc2line.get(this.curpc)) + break; + } } skipToEOF() { @@ -314,7 +322,7 @@ export class BASICRuntime { var nesting = 0; while (pc < this.allstmts.length) { var stmt = this.allstmts[pc]; - console.log(nesting, pc, stmt); + //console.log(nesting, pc, stmt); if (stmt.command == 'WHILE') { nesting++; } else if (stmt.command == 'WEND') { @@ -461,7 +469,8 @@ export class BASICRuntime { if (!opts) opts = {}; var s = ''; // is it a function? not allowed - if (expr.name.startsWith("FN") || this.builtins[expr.name]) this.runtimeError(`I can't call a function here.`); + if (expr.name.startsWith("FN") || this.builtins[expr.name]) + this.runtimeError(`I can't call a function here.`); // is it a subscript? if (expr.args) { // set array slice (HP BASIC) @@ -590,10 +599,14 @@ export class BASICRuntime { // dimension array dimArray(name: string, ...dims:number[]) { // TODO: maybe do this check at compile-time? + dims = dims.map(Math.round); if (this.arrays[name] != null) { if (this.opts.staticArrays) return; else this.runtimeError(`I already dimensioned this array (${name}) earlier.`) } + if (this.getTotalArrayLength(dims) > this.opts.maxArrayElements) { + this.runtimeError(`I can't create an array with this many elements.`); + } var isstring = name.endsWith('$'); // if numeric value, we use Float64Array which inits to 0 var arrcons = isstring ? Array : Float64Array; @@ -609,6 +622,16 @@ export class BASICRuntime { } } + getTotalArrayLength(dims:number[]) { + var n = 1; + for (var i=0; i this.opts.maxStringLength) @@ -1044,11 +1070,14 @@ export class BASICRuntime { } // FUNCTIONS (uppercase) + // TODO: swizzle names for type-checking ABS(arg : number) : number { return this.checkNum(Math.abs(arg)); } ASC(arg : string) : number { + arg = this.checkString(arg); + if (arg == '') this.runtimeError(`I tried to call ASC() on an empty string.`); return arg.charCodeAt(0); } ATN(arg : number) : number { @@ -1089,6 +1118,8 @@ export class BASICRuntime { return this.checkNum(Math.floor(arg)); } LEFT$(arg : string, count : number) : string { + arg = this.checkString(arg); + count = this.ROUND(count); return arg.substr(0, count); } LEN(arg : string) : number { @@ -1108,6 +1139,9 @@ export class BASICRuntime { return this.checkNum(Math.log10(arg)); } MID$(arg : string, start : number, count : number) : string { + arg = this.checkString(arg); + start = this.ROUND(start); + count = this.ROUND(count); if (start < 1) this.runtimeError(`I can't compute MID$ if the starting index is less than 1.`) if (count == 0) count = arg.length; return arg.substr(start-1, count); @@ -1123,6 +1157,8 @@ export class BASICRuntime { return this.column + 1; } RIGHT$(arg : string, count : number) : string { + arg = this.checkString(arg); + count = this.ROUND(count); return arg.substr(arg.length - count, count); } RND(arg : number) : number { @@ -1134,14 +1170,14 @@ export class BASICRuntime { return this.checkNum(Math.round(arg)); } SGN(arg : number) : number { + this.checkNum(arg); return (arg < 0) ? -1 : (arg > 0) ? 1 : 0; } SIN(arg : number) : number { return this.checkNum(Math.sin(arg)); } SPACE$(arg : number) : string { - arg = this.ROUND(arg); - return (arg > 0) ? ' '.repeat(arg) : ''; + return this.STRING$(arg, ' '); } SPC(arg : number) : string { return this.SPACE$(arg); @@ -1156,13 +1192,17 @@ export class BASICRuntime { STRING$(len : number, chr : number|string) : string { len = this.ROUND(len); if (len <= 0) return ''; - if (typeof chr === 'string') return chr.substr(0,1).repeat(len); - else return String.fromCharCode(chr).repeat(len); + if (len > this.opts.maxStringLength) + this.runtimeError(`I can't create a string longer than ${this.opts.maxStringLength} characters.`); + if (typeof chr === 'string') + return chr.substr(0,1).repeat(len); + else + return String.fromCharCode(chr).repeat(len); } TAB(arg : number) : string { if (arg < 1) { arg = 1; } // TODO: SYSTEM MESSAGE IDENTIFYING THE EXCEPTION var spaces = this.ROUND(arg) - 1 - this.column; - return (spaces > 0) ? ' '.repeat(spaces) : ''; + return this.SPACE$(spaces); } TAN(arg : number) : number { return this.checkNum(Math.tan(arg)); @@ -1196,10 +1236,12 @@ export class BASICRuntime { return isNaN(n) ? 0 : n; // TODO? altair works this way } LPAD$(arg : string, len : number) : string { + arg = this.checkString(arg); while (arg.length < len) arg = " " + arg; return arg; } RPAD$(arg : string, len : number) : string { + arg = this.checkString(arg); while (arg.length < len) arg = arg + " "; return arg; }