diff --git a/package-lock.json b/package-lock.json index cd72051..1c3c2a8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,9 +12,10 @@ "@babel/core": "^7.10.5", "@babel/traverse": "^7.10.5", "@babel/types": "^7.10.5", - "@fink/js-interop": ">=3.1.1", + "@fink/js-interop": ">=2.5", "@fink/snippet": "^2.2.0", - "@fink/std-lib": "^8.5.0" + "@fink/std-lib": "^8.5.0", + "hamt": "^2.2.2" }, "devDependencies": { "@fink/cli": "^8.0.0", @@ -25,7 +26,7 @@ "cz-conventional-changelog": "^3.1.0", "jest-cli": "^27.0.0", "npx-run": "^2.1.2", - "semantic-release": "^17.2.1" + "semantic-release": "^18.0.0" }, "engines": { "node": ">=14.13.0" @@ -170,18 +171,18 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.4.tgz", - "integrity": "sha512-9fHHSGE9zTC++KuXLZcB5FKgvlV83Ox+NLUmQTawovwlJ85+QMhk1CnVk406CQVj97LaWod6KVjl2Sfgw9Aktw==", + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.7.tgz", + "integrity": "sha512-ZNqjjQG/AuFfekFTY+7nY4RgBSklgTu970c7Rj3m/JOhIu5KPBUuTA9AY6zaKcUvk4g6EbDXdBnhi35FAssdSw==", "dependencies": { "@babel/helper-module-imports": "^7.15.4", "@babel/helper-replace-supers": "^7.15.4", "@babel/helper-simple-access": "^7.15.4", "@babel/helper-split-export-declaration": "^7.15.4", - "@babel/helper-validator-identifier": "^7.14.9", + "@babel/helper-validator-identifier": "^7.15.7", "@babel/template": "^7.15.4", "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.4" + "@babel/types": "^7.15.6" }, "engines": { "node": ">=6.9.0" @@ -244,9 +245,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.14.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz", - "integrity": "sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g==", + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", + "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", "engines": { "node": ">=6.9.0" } @@ -286,9 +287,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.15.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.6.tgz", - "integrity": "sha512-S/TSCcsRuCkmpUuoWijua0Snt+f3ewU/8spLo+4AXJCZfT0bVCzLD5MuOKdrx0mlAptbKzn5AdgEIIKXxXkz9Q==", + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.7.tgz", + "integrity": "sha512-rycZXvQ+xS9QyIcJ9HXeDWf1uxqlbVFAUq0Rq0dbc50Zb/+wUe/ehyfzGfm9KZZF0kBejYgxltBXocP+gKdL2g==", "bin": { "parser": "bin/babel-parser.js" }, @@ -509,9 +510,9 @@ "dev": true }, "node_modules/@commitlint/execute-rule": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-13.0.0.tgz", - "integrity": "sha512-lBz2bJhNAgkkU/rFMAw3XBNujbxhxlaFHY3lfKB/MxpAa+pIfmWB3ig9i1VKe0wCvujk02O0WiMleNaRn2KJqw==", + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-13.2.0.tgz", + "integrity": "sha512-6nPwpN0hwTYmsH3WM4hCdN+NrMopgRIuQ0aqZa+jnwMoS/g6ljliQNYfL+m5WO306BaIu1W3yYpbW5aI8gEr0g==", "dev": true, "optional": true, "engines": { @@ -519,15 +520,16 @@ } }, "node_modules/@commitlint/load": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-13.1.0.tgz", - "integrity": "sha512-zlZbjJCWnWmBOSwTXis8H7I6pYk6JbDwOCuARA6B9Y/qt2PD+NCo0E/7EuaaFoxjHl+o56QR5QttuMBrf+BJzg==", + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-13.2.0.tgz", + "integrity": "sha512-Nhkv+hwWCCxWGjmE9jd1U8kfGGCkZVpwzlTtdKxpY+Aj2VCFg3BjY+qA81pMF3oAsIpxchSaZG5llb8kduVjYg==", "dev": true, "optional": true, "dependencies": { - "@commitlint/execute-rule": "^13.0.0", - "@commitlint/resolve-extends": "^13.0.0", - "@commitlint/types": "^13.1.0", + "@commitlint/execute-rule": "^13.2.0", + "@commitlint/resolve-extends": "^13.2.0", + "@commitlint/types": "^13.2.0", + "@endemolshinegroup/cosmiconfig-typescript-loader": "^3.0.2", "chalk": "^4.0.0", "cosmiconfig": "^7.0.0", "lodash": "^4.17.19", @@ -614,9 +616,9 @@ } }, "node_modules/@commitlint/resolve-extends": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-13.0.0.tgz", - "integrity": "sha512-1SyaE+UOsYTkQlTPUOoj4NwxQhGFtYildVS/d0TJuK8a9uAJLw7bhCLH2PEeH5cC2D1do4Eqhx/3bLDrSLH3hg==", + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-13.2.0.tgz", + "integrity": "sha512-HLCMkqMKtvl1yYLZ1Pm0UpFvd0kYjsm1meLOGZ7VkOd9G/XX+Fr1S2G5AT2zeiDw7WUVYK8lGVMNa319bnV+aw==", "dev": true, "optional": true, "dependencies": { @@ -630,9 +632,9 @@ } }, "node_modules/@commitlint/types": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-13.1.0.tgz", - "integrity": "sha512-zcVjuT+OfKt8h91vhBxt05RMcTGEx6DM7Q9QZeuMbXFk6xgbsSEDMMapbJPA1bCZ81fa/1OQBijSYPrKvtt06g==", + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-13.2.0.tgz", + "integrity": "sha512-RRVHEqmk1qn/dIaSQhvuca6k/6Z54G+r/KyimZ8gnAFielGiGUpsFRhIY3qhd5rXClVxDaa3nlcyTWckSccotQ==", "dev": true, "optional": true, "dependencies": { @@ -718,6 +720,25 @@ "node": ">=8" } }, + "node_modules/@endemolshinegroup/cosmiconfig-typescript-loader": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@endemolshinegroup/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-3.0.2.tgz", + "integrity": "sha512-QRVtqJuS1mcT56oHpVegkKBlgtWjXw/gHNWO3eL9oyB5Sc7HBoc2OLG/nYpVfT/Jejvo3NUrD0Udk7XgoyDKkA==", + "dev": true, + "optional": true, + "dependencies": { + "lodash.get": "^4", + "make-error": "^1", + "ts-node": "^9", + "tslib": "^2" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "cosmiconfig": ">=6" + } + }, "node_modules/@fink/cli": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/@fink/cli/-/cli-8.3.2.tgz", @@ -767,9 +788,9 @@ } }, "node_modules/@fink/larix": { - "version": "20.1.0", - "resolved": "https://registry.npmjs.org/@fink/larix/-/larix-20.1.0.tgz", - "integrity": "sha512-JSSnAOpSlxb0bHZ1Fj5t16O/SCCY8WtoCRtWmeONzYfJPkYqXOt3EpA76/3GWsqMlYEmLVdmc3/LuCLNMcyHzg==", + "version": "20.2.0", + "resolved": "https://registry.npmjs.org/@fink/larix/-/larix-20.2.0.tgz", + "integrity": "sha512-zEpKeIOR/lqlCfP6pK3UuFVDFywjAeX/L8AN0T4y5JN8kk17l1xKUuYgzktRZJaTE9gPaZnk3Cu2i2KsOFWq0w==", "dev": true, "dependencies": { "@fink/prattler": "^7.2.0", @@ -860,16 +881,16 @@ } }, "node_modules/@jest/console": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.2.0.tgz", - "integrity": "sha512-35z+RqsK2CCgNxn+lWyK8X4KkaDtfL4BggT7oeZ0JffIiAiEYFYPo5B67V50ZubqDS1ehBrdCR2jduFnIrZOYw==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.2.4.tgz", + "integrity": "sha512-94znCKynPZpDpYHQ6esRJSc11AmONrVkBOBZiD7S+bSubHhrUfbS95EY5HIOxhm4PQO7cnvZkL3oJcY0oMA+Wg==", "dev": true, "dependencies": { - "@jest/types": "^27.1.1", + "@jest/types": "^27.2.4", "@types/node": "*", "chalk": "^4.0.0", - "jest-message-util": "^27.2.0", - "jest-util": "^27.2.0", + "jest-message-util": "^27.2.4", + "jest-util": "^27.2.4", "slash": "^3.0.0" }, "engines": { @@ -947,37 +968,36 @@ } }, "node_modules/@jest/core": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.2.0.tgz", - "integrity": "sha512-E/2NHhq+VMo18DpKkoty8Sjey8Kps5Cqa88A8NP757s6JjYqPdioMuyUBhDiIOGCdQByEp0ou3jskkTszMS0nw==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.2.4.tgz", + "integrity": "sha512-UNQLyy+rXoojNm2MGlapgzWhZD1CT1zcHZQYeiD0xE7MtJfC19Q6J5D/Lm2l7i4V97T30usKDoEtjI8vKwWcLg==", "dev": true, "dependencies": { - "@jest/console": "^27.2.0", - "@jest/reporters": "^27.2.0", - "@jest/test-result": "^27.2.0", - "@jest/transform": "^27.2.0", - "@jest/types": "^27.1.1", + "@jest/console": "^27.2.4", + "@jest/reporters": "^27.2.4", + "@jest/test-result": "^27.2.4", + "@jest/transform": "^27.2.4", + "@jest/types": "^27.2.4", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", "emittery": "^0.8.1", "exit": "^0.1.2", "graceful-fs": "^4.2.4", - "jest-changed-files": "^27.1.1", - "jest-config": "^27.2.0", - "jest-haste-map": "^27.2.0", - "jest-message-util": "^27.2.0", + "jest-changed-files": "^27.2.4", + "jest-config": "^27.2.4", + "jest-haste-map": "^27.2.4", + "jest-message-util": "^27.2.4", "jest-regex-util": "^27.0.6", - "jest-resolve": "^27.2.0", - "jest-resolve-dependencies": "^27.2.0", - "jest-runner": "^27.2.0", - "jest-runtime": "^27.2.0", - "jest-snapshot": "^27.2.0", - "jest-util": "^27.2.0", - "jest-validate": "^27.2.0", - "jest-watcher": "^27.2.0", + "jest-resolve": "^27.2.4", + "jest-resolve-dependencies": "^27.2.4", + "jest-runner": "^27.2.4", + "jest-runtime": "^27.2.4", + "jest-snapshot": "^27.2.4", + "jest-util": "^27.2.4", + "jest-validate": "^27.2.4", + "jest-watcher": "^27.2.4", "micromatch": "^4.0.4", - "p-each-series": "^2.1.0", "rimraf": "^3.0.0", "slash": "^3.0.0", "strip-ansi": "^6.0.0" @@ -1068,12 +1088,12 @@ } }, "node_modules/@jest/core/node_modules/strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "dependencies": { - "ansi-regex": "^5.0.0" + "ansi-regex": "^5.0.1" }, "engines": { "node": ">=8" @@ -1104,62 +1124,62 @@ } }, "node_modules/@jest/environment": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.2.0.tgz", - "integrity": "sha512-iPWmQI0wRIYSZX3wKu4FXHK4eIqkfq6n1DCDJS+v3uby7SOXrHvX4eiTBuEdSvtDRMTIH2kjrSkjHf/F9JIYyQ==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.2.4.tgz", + "integrity": "sha512-wkuui5yr3SSQW0XD0Qm3TATUbL/WE3LDEM3ulC+RCQhMf2yxhci8x7svGkZ4ivJ6Pc94oOzpZ6cdHBAMSYd1ew==", "dev": true, "dependencies": { - "@jest/fake-timers": "^27.2.0", - "@jest/types": "^27.1.1", + "@jest/fake-timers": "^27.2.4", + "@jest/types": "^27.2.4", "@types/node": "*", - "jest-mock": "^27.1.1" + "jest-mock": "^27.2.4" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/@jest/fake-timers": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.2.0.tgz", - "integrity": "sha512-gSu3YHvQOoVaTWYGgHFB7IYFtcF2HBzX4l7s47VcjvkUgL4/FBnE20x7TNLa3W6ABERtGd5gStSwsA8bcn+c4w==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.2.4.tgz", + "integrity": "sha512-cs/TzvwWUM7kAA6Qm/890SK6JJ2pD5RfDNM3SSEom6BmdyV6OiWP1qf/pqo6ts6xwpcM36oN0wSEzcZWc6/B6w==", "dev": true, "dependencies": { - "@jest/types": "^27.1.1", - "@sinonjs/fake-timers": "^7.0.2", + "@jest/types": "^27.2.4", + "@sinonjs/fake-timers": "^8.0.1", "@types/node": "*", - "jest-message-util": "^27.2.0", - "jest-mock": "^27.1.1", - "jest-util": "^27.2.0" + "jest-message-util": "^27.2.4", + "jest-mock": "^27.2.4", + "jest-util": "^27.2.4" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/@jest/globals": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.2.0.tgz", - "integrity": "sha512-raqk9Gf9WC3hlBa57rmRmJfRl9hom2b+qEE/ifheMtwn5USH5VZxzrHHOZg0Zsd/qC2WJ8UtyTwHKQAnNlDMdg==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.2.4.tgz", + "integrity": "sha512-DRsRs5dh0i+fA9mGHylTU19+8fhzNJoEzrgsu+zgJoZth3x8/0juCQ8nVVdW1er4Cqifb/ET7/hACYVPD0dBEA==", "dev": true, "dependencies": { - "@jest/environment": "^27.2.0", - "@jest/types": "^27.1.1", - "expect": "^27.2.0" + "@jest/environment": "^27.2.4", + "@jest/types": "^27.2.4", + "expect": "^27.2.4" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/@jest/reporters": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.2.0.tgz", - "integrity": "sha512-7wfkE3iRTLaT0F51h1mnxH3nQVwDCdbfgXiLuCcNkF1FnxXLH9utHqkSLIiwOTV1AtmiE0YagHbOvx4rnMP/GA==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.2.4.tgz", + "integrity": "sha512-LHeSdDnDZkDnJ8kvnjcqV8P1Yv/32yL4d4XfR5gBiy3xGO0onwll1QEbvtW96fIwhx2nejug0GTaEdNDoyr3fQ==", "dev": true, "dependencies": { "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^27.2.0", - "@jest/test-result": "^27.2.0", - "@jest/transform": "^27.2.0", - "@jest/types": "^27.1.1", + "@jest/console": "^27.2.4", + "@jest/test-result": "^27.2.4", + "@jest/transform": "^27.2.4", + "@jest/types": "^27.2.4", "chalk": "^4.0.0", "collect-v8-coverage": "^1.0.0", "exit": "^0.1.2", @@ -1170,15 +1190,15 @@ "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^4.0.0", "istanbul-reports": "^3.0.2", - "jest-haste-map": "^27.2.0", - "jest-resolve": "^27.2.0", - "jest-util": "^27.2.0", - "jest-worker": "^27.2.0", + "jest-haste-map": "^27.2.4", + "jest-resolve": "^27.2.4", + "jest-util": "^27.2.4", + "jest-worker": "^27.2.4", "slash": "^3.0.0", "source-map": "^0.6.0", "string-length": "^4.0.1", "terminal-link": "^2.0.0", - "v8-to-istanbul": "^8.0.0" + "v8-to-istanbul": "^8.1.0" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" @@ -1295,13 +1315,13 @@ } }, "node_modules/@jest/test-result": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.2.0.tgz", - "integrity": "sha512-JPPqn8h0RGr4HyeY1Km+FivDIjTFzDROU46iAvzVjD42ooGwYoqYO/MQTilhfajdz6jpVnnphFrKZI5OYrBONA==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.2.4.tgz", + "integrity": "sha512-eU+PRo0+lIS01b0dTmMdVZ0TtcRSxEaYquZTRFMQz6CvsehGhx9bRzi9Zdw6VROviJyv7rstU+qAMX5pNBmnfQ==", "dev": true, "dependencies": { - "@jest/console": "^27.2.0", - "@jest/types": "^27.1.1", + "@jest/console": "^27.2.4", + "@jest/types": "^27.2.4", "@types/istanbul-lib-coverage": "^2.0.0", "collect-v8-coverage": "^1.0.0" }, @@ -1310,36 +1330,36 @@ } }, "node_modules/@jest/test-sequencer": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.2.0.tgz", - "integrity": "sha512-PrqarcpzOU1KSAK7aPwfL8nnpaqTMwPe7JBPnaOYRDSe/C6AoJiL5Kbnonqf1+DregxZIRAoDg69R9/DXMGqXA==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.2.4.tgz", + "integrity": "sha512-fpk5eknU3/DXE2QCCG1wv/a468+cfPo3Asu6d6yUtM9LOPh709ubZqrhuUOYfM8hXMrIpIdrv1CdCrWWabX0rQ==", "dev": true, "dependencies": { - "@jest/test-result": "^27.2.0", + "@jest/test-result": "^27.2.4", "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.2.0", - "jest-runtime": "^27.2.0" + "jest-haste-map": "^27.2.4", + "jest-runtime": "^27.2.4" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/@jest/transform": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.2.0.tgz", - "integrity": "sha512-Q8Q/8xXIZYllk1AF7Ou5sV3egOZsdY/Wlv09CSbcexBRcC1Qt6lVZ7jRFAZtbHsEEzvOCyFEC4PcrwKwyjXtCg==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.2.4.tgz", + "integrity": "sha512-n5FlX2TH0oQGwyVDKPxdJ5nI2sO7TJBFe3u3KaAtt7TOiV4yL+Y+rSFDl+Ic5MpbiA/eqXmLAQxjnBmWgS2rEA==", "dev": true, "dependencies": { "@babel/core": "^7.1.0", - "@jest/types": "^27.1.1", + "@jest/types": "^27.2.4", "babel-plugin-istanbul": "^6.0.0", "chalk": "^4.0.0", "convert-source-map": "^1.4.0", "fast-json-stable-stringify": "^2.0.0", "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.2.0", + "jest-haste-map": "^27.2.4", "jest-regex-util": "^27.0.6", - "jest-util": "^27.2.0", + "jest-util": "^27.2.4", "micromatch": "^4.0.4", "pirates": "^4.0.1", "slash": "^3.0.0", @@ -1430,9 +1450,9 @@ } }, "node_modules/@jest/types": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.1.1.tgz", - "integrity": "sha512-yqJPDDseb0mXgKqmNqypCsb85C22K1aY5+LUxh7syIM9n/b0AsaltxNy+o6tt29VcfGDpYEve175bm3uOhcehA==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.2.4.tgz", + "integrity": "sha512-IDO2ezTxeMvQAHxzG/ZvEyA47q0aVfzT95rGFl7bZs/Go0aIucvfDbS2rmnoEdXxlLQhcolmoG/wvL/uKx4tKA==", "dev": true, "dependencies": { "@types/istanbul-lib-coverage": "^2.0.0", @@ -1551,9 +1571,9 @@ } }, "node_modules/@octokit/auth-token": { - "version": "2.4.5", - "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.4.5.tgz", - "integrity": "sha512-BpGYsPgJt05M7/L/5FoE1PiAbdxXFZkX/3kDYcsvd1v6UhlnE5e96dTDr0ezX/EFwciQxf3cNV0loipsURU+WA==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz", + "integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==", "dev": true, "dependencies": { "@octokit/types": "^6.0.3" @@ -1597,18 +1617,18 @@ } }, "node_modules/@octokit/openapi-types": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-10.2.2.tgz", - "integrity": "sha512-EVcXQ+ZrC04cg17AMg1ofocWMxHDn17cB66ZHgYc0eUwjFtxS0oBzkyw2VqIrHBwVgtfoYrq1WMQfQmMjUwthw==", + "version": "10.6.4", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-10.6.4.tgz", + "integrity": "sha512-JVmwWzYTIs6jACYOwD6zu5rdrqGIYsiAsLzTCxdrWIPNKNVjEF6vPTL20shmgJ4qZsq7WPBcLXLsaQD+NLChfg==", "dev": true }, "node_modules/@octokit/plugin-paginate-rest": { - "version": "2.16.3", - "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.16.3.tgz", - "integrity": "sha512-kdc65UEsqze/9fCISq6BxLzeB9qf0vKvKojIfzgwf4tEF+Wy6c9dXnPFE6vgpoDFB1Z5Jek5WFVU6vL1w22+Iw==", + "version": "2.16.7", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.16.7.tgz", + "integrity": "sha512-TMlyVhMPx6La1Ud4PSY4YxqAvb9YPEMs/7R1nBSbsw4wNqG73aBqls0r0dRRCWe5Pm0ZUGS9a94N46iAxlOR8A==", "dev": true, "dependencies": { - "@octokit/types": "^6.28.1" + "@octokit/types": "^6.31.3" }, "peerDependencies": { "@octokit/core": ">=2" @@ -1624,12 +1644,12 @@ } }, "node_modules/@octokit/plugin-rest-endpoint-methods": { - "version": "5.10.4", - "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.10.4.tgz", - "integrity": "sha512-Dh+EAMCYR9RUHwQChH94Skl0lM8Fh99auT8ggck/xTzjJrwVzvsd0YH68oRPqp/HxICzmUjLfaQ9sy1o1sfIiA==", + "version": "5.11.4", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.11.4.tgz", + "integrity": "sha512-iS+GYTijrPUiEiLoDsGJhrbXIvOPfm2+schvr+FxNMs7PeE9Nl4bAMhE8ftfNX3Z1xLxSKwEZh0O7GbWurX5HQ==", "dev": true, "dependencies": { - "@octokit/types": "^6.28.1", + "@octokit/types": "^6.31.2", "deprecation": "^2.3.1" }, "peerDependencies": { @@ -1662,57 +1682,60 @@ } }, "node_modules/@octokit/rest": { - "version": "18.10.0", - "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.10.0.tgz", - "integrity": "sha512-esHR5OKy38bccL/sajHqZudZCvmv4yjovMJzyXlphaUo7xykmtOdILGJ3aAm0mFHmMLmPFmDMJXf39cAjNJsrw==", + "version": "18.11.4", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.11.4.tgz", + "integrity": "sha512-QplypCyYxqMK05JdMSm/bDWZO8VWWaBdzQ9tbF9rEV9rIEiICh+v6q+Vu/Y5hdze8JJaxfUC+PBC7vrnEkZvZg==", "dev": true, "dependencies": { "@octokit/core": "^3.5.1", - "@octokit/plugin-paginate-rest": "^2.16.0", + "@octokit/plugin-paginate-rest": "^2.16.4", "@octokit/plugin-request-log": "^1.0.4", - "@octokit/plugin-rest-endpoint-methods": "^5.9.0" + "@octokit/plugin-rest-endpoint-methods": "5.11.4" } }, "node_modules/@octokit/types": { - "version": "6.28.1", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.28.1.tgz", - "integrity": "sha512-XlxDoQLFO5JnFZgKVQTYTvXRsQFfr/GwDUU108NJ9R5yFPkA2qXhTJjYuul3vE4eLXP40FA2nysOu2zd6boE+w==", + "version": "6.31.3", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.31.3.tgz", + "integrity": "sha512-IUG3uMpsLHrtEL6sCVXbxCgnbKcgpkS4K7gVEytLDvYYalkK3XcuMCHK1YPD8xJglSJAOAbL4MgXp47rS9G49w==", "dev": true, "dependencies": { - "@octokit/openapi-types": "^10.2.2" + "@octokit/openapi-types": "^10.6.4" } }, "node_modules/@semantic-release/commit-analyzer": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@semantic-release/commit-analyzer/-/commit-analyzer-8.0.1.tgz", - "integrity": "sha512-5bJma/oB7B4MtwUkZC2Bf7O1MHfi4gWe4mA+MIQ3lsEV0b422Bvl1z5HRpplDnMLHH3EXMoRdEng6Ds5wUqA3A==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@semantic-release/commit-analyzer/-/commit-analyzer-9.0.1.tgz", + "integrity": "sha512-ncNsnrLmiykhgNZUXNvhhAjNN0me7VGIb0X5hu3ogyi5DDPapjGAHdEffO5vi+HX1BFWLRD/Ximx5PjGAKjAqQ==", "dev": true, "dependencies": { "conventional-changelog-angular": "^5.0.0", "conventional-commits-filter": "^2.0.0", "conventional-commits-parser": "^3.0.7", "debug": "^4.0.0", - "import-from": "^3.0.0", + "import-from": "^4.0.0", "lodash": "^4.17.4", "micromatch": "^4.0.2" }, "engines": { - "node": ">=10.18" + "node": ">=14.17" }, "peerDependencies": { - "semantic-release": ">=16.0.0 <18.0.0" + "semantic-release": ">=18.0.0-beta.1" } }, "node_modules/@semantic-release/error": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-2.2.0.tgz", - "integrity": "sha512-9Tj/qn+y2j+sjCI3Jd+qseGtHjOAeg7dU2/lVcqIQ9TV3QDaDXDYXcoOHU+7o2Hwh8L8ymL4gfuO7KxDs3q2zg==", - "dev": true + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-3.0.0.tgz", + "integrity": "sha512-5hiM4Un+tpl4cKw3lV4UgzJj+SmfNIDCLLw0TepzQxz9ZGV5ixnqkzIVF+3tp0ZHgcMKE+VNGHJjEeyFG2dcSw==", + "dev": true, + "engines": { + "node": ">=14.17" + } }, "node_modules/@semantic-release/github": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-7.2.3.tgz", - "integrity": "sha512-lWjIVDLal+EQBzy697ayUNN8MoBpp+jYIyW2luOdqn5XBH4d9bQGfTnjuLyzARZBHejqh932HVjiH/j4+R7VHw==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-8.0.1.tgz", + "integrity": "sha512-T01lfh4yBZodAeo8t0U+W5hmPYR9BdnfwLDerXnGaYeLXm8+KMx4mQEBAf/UbRVlzmIKTqMx+/s9fY/mSQNV0A==", "dev": true, "dependencies": { "@octokit/rest": "^18.0.0", @@ -1723,7 +1746,7 @@ "dir-glob": "^3.0.0", "fs-extra": "^10.0.0", "globby": "^11.0.0", - "http-proxy-agent": "^4.0.0", + "http-proxy-agent": "^5.0.0", "https-proxy-agent": "^5.0.0", "issue-parser": "^6.0.0", "lodash": "^4.17.4", @@ -1733,10 +1756,25 @@ "url-join": "^4.0.0" }, "engines": { - "node": ">=10.18" + "node": ">=14.17" }, "peerDependencies": { - "semantic-release": ">=16.0.0 <18.0.0" + "semantic-release": ">=18.0.0-beta.1" + } + }, + "node_modules/@semantic-release/github/node_modules/@semantic-release/error": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-2.2.0.tgz", + "integrity": "sha512-9Tj/qn+y2j+sjCI3Jd+qseGtHjOAeg7dU2/lVcqIQ9TV3QDaDXDYXcoOHU+7o2Hwh8L8ymL4gfuO7KxDs3q2zg==", + "dev": true + }, + "node_modules/@semantic-release/github/node_modules/@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "dev": true, + "engines": { + "node": ">= 10" } }, "node_modules/@semantic-release/github/node_modules/fs-extra": { @@ -1753,6 +1791,20 @@ "node": ">=12" } }, + "node_modules/@semantic-release/github/node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/@semantic-release/github/node_modules/jsonfile": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", @@ -1775,9 +1827,9 @@ } }, "node_modules/@semantic-release/npm": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/@semantic-release/npm/-/npm-7.1.3.tgz", - "integrity": "sha512-x52kQ/jR09WjuWdaTEHgQCvZYMOTx68WnS+TZ4fya5ZAJw4oRtJETtrvUw10FdfM28d/keInQdc66R1Gw5+OEQ==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@semantic-release/npm/-/npm-8.0.0.tgz", + "integrity": "sha512-MAlynjIaN5XwBEzsq3xbZ8I+riD9zhLvpPqGCPaZ0j/ySbR0Sg3YG1MYv03fC1aygPFFC5RwefMxKids9llvDg==", "dev": true, "dependencies": { "@semantic-release/error": "^2.2.0", @@ -1795,12 +1847,18 @@ "tempy": "^1.0.0" }, "engines": { - "node": ">=10.19" + "node": ">=14.17" }, "peerDependencies": { - "semantic-release": ">=16.0.0 <18.0.0" + "semantic-release": ">=18.0.0-beta.1" } }, + "node_modules/@semantic-release/npm/node_modules/@semantic-release/error": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-2.2.0.tgz", + "integrity": "sha512-9Tj/qn+y2j+sjCI3Jd+qseGtHjOAeg7dU2/lVcqIQ9TV3QDaDXDYXcoOHU+7o2Hwh8L8ymL4gfuO7KxDs3q2zg==", + "dev": true + }, "node_modules/@semantic-release/npm/node_modules/fs-extra": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", @@ -1852,27 +1910,27 @@ } }, "node_modules/@semantic-release/release-notes-generator": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/@semantic-release/release-notes-generator/-/release-notes-generator-9.0.3.tgz", - "integrity": "sha512-hMZyddr0u99OvM2SxVOIelHzly+PP3sYtJ8XOLHdMp8mrluN5/lpeTnIO27oeCYdupY/ndoGfvrqDjHqkSyhVg==", + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@semantic-release/release-notes-generator/-/release-notes-generator-10.0.2.tgz", + "integrity": "sha512-I4eavIcDan8fNQHskZ2cbWkFMimvgxNkqR2UfuYNwYBgswEl3SJsN8XMf9gZWObt6nXDc2QfDwhjy8DjTZqS3w==", "dev": true, "dependencies": { "conventional-changelog-angular": "^5.0.0", - "conventional-changelog-writer": "^4.0.0", + "conventional-changelog-writer": "^5.0.0", "conventional-commits-filter": "^2.0.0", "conventional-commits-parser": "^3.0.0", "debug": "^4.0.0", "get-stream": "^6.0.0", - "import-from": "^3.0.0", + "import-from": "^4.0.0", "into-stream": "^6.0.0", "lodash": "^4.17.4", "read-pkg-up": "^7.0.0" }, "engines": { - "node": ">=10.18" + "node": ">=14.17" }, "peerDependencies": { - "semantic-release": ">=15.8.0 <18.0.0" + "semantic-release": ">=18.0.0-beta.1" } }, "node_modules/@sinonjs/commons": { @@ -1885,9 +1943,9 @@ } }, "node_modules/@sinonjs/fake-timers": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-7.1.2.tgz", - "integrity": "sha512-iQADsW4LBMISqZ6Ci1dupJL9pprqwcVFTcOsEmQOEhW+KLCVn/Y4Jrvg2k19fIHCp+iFprriYPTdRcQR8NbUPg==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.0.1.tgz", + "integrity": "sha512-AU7kwFxreVd6OAXcAFlKSmZquiRUU0FvYm44k1Y1QbK7Co4m0aqfGMhjykIeQp/H6rcl+nFmj0zfdUcGVs9Dew==", "dev": true, "dependencies": { "@sinonjs/commons": "^1.7.0" @@ -1983,9 +2041,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "16.9.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.9.1.tgz", - "integrity": "sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g==", + "version": "16.10.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.10.2.tgz", + "integrity": "sha512-zCclL4/rx+W5SQTzFs9wyvvyCwoK9QtBpratqz2IYJ3O8Umrn0m3nsTv0wQBk9sRGpvUe9CwPDrQFB10f1FIjQ==", "dev": true }, "node_modules/@types/normalize-package-data": { @@ -2001,9 +2059,9 @@ "dev": true }, "node_modules/@types/prettier": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.3.2.tgz", - "integrity": "sha512-eI5Yrz3Qv4KPUa/nSIAi0h+qX0XyewOliug5F2QAtuRg6Kjg6jfmxe1GIwoIRhZspD1A0RP8ANrPwvEXXtRFog==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.1.tgz", + "integrity": "sha512-Fo79ojj3vdEZOHg3wR9ksAMRz4P3S5fDB5e/YWZiFnyFQI1WY2Vftu9XoXVVtJfxB7Bpce/QTqWSSntkz2Znrw==", "dev": true }, "node_modules/@types/retry": { @@ -2164,6 +2222,13 @@ "node": ">= 8" } }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true, + "optional": true + }, "node_modules/argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -2210,13 +2275,13 @@ "dev": true }, "node_modules/babel-jest": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.2.0.tgz", - "integrity": "sha512-bS2p+KGGVVmWXBa8+i6SO/xzpiz2Q/2LnqLbQknPKefWXVZ67YIjA4iXup/jMOEZplga9PpWn+wrdb3UdDwRaA==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.2.4.tgz", + "integrity": "sha512-f24OmxyWymk5jfgLdlCMu4fTs4ldxFBIdn5sJdhvGC1m08rSkJ5hYbWkNmfBSvE/DjhCVNSHXepxsI6THGfGsg==", "dev": true, "dependencies": { - "@jest/transform": "^27.2.0", - "@jest/types": "^27.1.1", + "@jest/transform": "^27.2.4", + "@jest/types": "^27.2.4", "@types/babel__core": "^7.1.14", "babel-plugin-istanbul": "^6.0.0", "babel-preset-jest": "^27.2.0", @@ -2445,15 +2510,15 @@ "dev": true }, "node_modules/browserslist": { - "version": "4.17.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.0.tgz", - "integrity": "sha512-g2BJ2a0nEYvEFQC208q8mVAhfNwpZ5Mu8BwgtCdZKO3qx98HChmeg448fPdUzld8aFmfLgVh7yymqV+q1lJZ5g==", + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.2.tgz", + "integrity": "sha512-jSDZyqJmkKMEMi7SZAgX5UltFdR5NAO43vY0AwTpu4X3sGH7GLLQ83KiUomgrnvZRCeW0yPPnKqnxPqQOER9zQ==", "dependencies": { - "caniuse-lite": "^1.0.30001254", - "colorette": "^1.3.0", - "electron-to-chromium": "^1.3.830", + "caniuse-lite": "^1.0.30001261", + "electron-to-chromium": "^1.3.854", "escalade": "^3.1.1", - "node-releases": "^1.1.75" + "nanocolors": "^0.2.12", + "node-releases": "^1.1.76" }, "bin": { "browserslist": "cli.js" @@ -2532,9 +2597,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001257", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001257.tgz", - "integrity": "sha512-JN49KplOgHSXpIsVSF+LUyhD8PUp6xPpAXeRrrcBh4KBeP7W864jHn6RvzJgDlrReyeVjMFJL3PLpPvKIxlIHA==", + "version": "1.0.30001263", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001263.tgz", + "integrity": "sha512-doiV5dft6yzWO1WwU19kt8Qz8R0/8DgEziz6/9n2FxUasteZNwNNYSmJO3GLBH8lCVE73AB1RPDPAeYbcO5Cvw==", "funding": { "type": "opencollective", "url": "https://opencollective.com/browserslist" @@ -2632,16 +2697,55 @@ "node": ">=4" } }, - "node_modules/cli-table": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.6.tgz", - "integrity": "sha512-ZkNZbnZjKERTY5NwC2SeMeLeifSPq/pubeRoTpdr3WchLlnZg6hEgvHkK5zL7KNFdd9PmHN8lxrENUwI3cE8vQ==", + "node_modules/cli-table3": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.0.tgz", + "integrity": "sha512-gnB85c3MGC7Nm9I/FkiasNBOKjOiO1RNuXXarQms37q4QMpWdlbBgD/VnOStA2faG1dpXMv31RFApjX1/QdgWQ==", "dev": true, "dependencies": { - "colors": "1.0.3" + "object-assign": "^4.1.0", + "string-width": "^4.2.0" }, "engines": { - "node": ">= 0.2.0" + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "colors": "^1.1.2" + } + }, + "node_modules/cli-table3/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-table3/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-table3/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" } }, "node_modules/cli-width": { @@ -2671,26 +2775,26 @@ } }, "node_modules/cliui/node_modules/string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" + "strip-ansi": "^6.0.1" }, "engines": { "node": ">=8" } }, "node_modules/cliui/node_modules/strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "dependencies": { - "ansi-regex": "^5.0.0" + "ansi-regex": "^5.0.1" }, "engines": { "node": ">=8" @@ -2725,16 +2829,12 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, - "node_modules/colorette": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz", - "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==" - }, "node_modules/colors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", - "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", "dev": true, + "optional": true, "engines": { "node": ">=0.1.90" } @@ -2913,12 +3013,11 @@ } }, "node_modules/conventional-changelog-writer": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-4.1.0.tgz", - "integrity": "sha512-WwKcUp7WyXYGQmkLsX4QmU42AZ1lqlvRW9mqoyiQzdD+rJWbTepdWoKJuwXTS+yq79XKnQNa93/roViPQrAQgw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-5.0.0.tgz", + "integrity": "sha512-HnDh9QHLNWfL6E1uHz6krZEQOgm8hN7z/m7tT16xwd802fwgMN0Wqd7AQYVkhpsjDUx/99oo+nGgvKF657XP5g==", "dev": true, "dependencies": { - "compare-func": "^2.0.0", "conventional-commits-filter": "^2.0.7", "dateformat": "^3.0.0", "handlebars": "^4.7.6", @@ -3017,6 +3116,13 @@ "node": ">=0.10.0" } }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "optional": true + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -3269,6 +3375,16 @@ "node": ">=8" } }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/diff-sequences": { "version": "27.0.6", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.0.6.tgz", @@ -3348,9 +3464,9 @@ "dev": true }, "node_modules/electron-to-chromium": { - "version": "1.3.839", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.839.tgz", - "integrity": "sha512-0O7uPs9LJNjQ/U5mW78qW8gXv9H6Ba3DHZ5/yt8aBsvomOWDkV3MddT7enUYvLQEUVOURjWmgJJWVZ3K98tIwQ==" + "version": "1.3.856", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.856.tgz", + "integrity": "sha512-lSezYIe1/p5qkEswAfaQUseOBiwGwuCvRl/MKzOEVe++DcmQ92+43dznDl4rFJ4Zpu+kevhwyIf7KjJevyDA/A==" }, "node_modules/emittery": { "version": "0.8.1", @@ -3572,16 +3688,16 @@ } }, "node_modules/expect": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-27.2.0.tgz", - "integrity": "sha512-oOTbawMQv7AK1FZURbPTgGSzmhxkjFzoARSvDjOMnOpeWuYQx1tP6rXu9MIX5mrACmyCAM7fSNP8IJO2f1p0CQ==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.2.4.tgz", + "integrity": "sha512-gOtuonQ8TCnbNNCSw2fhVzRf8EFYDII4nB5NmG4IEV0rbUnW1I5zXvoTntU4iicB/Uh0oZr20NGlOLdJiwsOZA==", "dev": true, "dependencies": { - "@jest/types": "^27.1.1", + "@jest/types": "^27.2.4", "ansi-styles": "^5.0.0", "jest-get-type": "^27.0.6", - "jest-matcher-utils": "^27.2.0", - "jest-message-util": "^27.2.0", + "jest-matcher-utils": "^27.2.4", + "jest-message-util": "^27.2.4", "jest-regex-util": "^27.0.6" }, "engines": { @@ -4035,6 +4151,11 @@ "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", "dev": true }, + "node_modules/hamt": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/hamt/-/hamt-2.2.2.tgz", + "integrity": "sha512-4V67NW9SuDo5xqyLiSEIxITsEjOMHZB3JqS/I2ZhzWdjDx8NRJtf6lGqt8RP+nCFZDf8t+XNa5l29z4p2hUFcQ==" + }, "node_modules/handlebars": { "version": "4.7.7", "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", @@ -4222,15 +4343,15 @@ } }, "node_modules/import-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/import-from/-/import-from-3.0.0.tgz", - "integrity": "sha512-CiuXOFFSzkU5x/CR0+z7T91Iht4CXgfCxVOFRhh2Zyhg5wOpWvvDLQUsWl+gcN+QscYBjez8hDCt85O7RLDttQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/import-from/-/import-from-4.0.0.tgz", + "integrity": "sha512-P9J71vT5nLlDeV8FHs5nNxaLbrpfAV5cF5srvbZfpwpcJoM/xZR3hiv+q+SAnuSmuGbXMWud063iIMx/V/EWZQ==", "dev": true, - "dependencies": { - "resolve-from": "^5.0.0" - }, "engines": { - "node": ">=8" + "node": ">=12.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/import-lazy": { @@ -4357,9 +4478,9 @@ } }, "node_modules/is-core-module": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.6.0.tgz", - "integrity": "sha512-wShG8vs60jKfPWpF2KZRaAtvt3a20OAn7+IJ6hLPECpSABLcKtFKTTI4ZtH5QcBruBHlq+WsdHWyz0BCZW7svQ==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.7.0.tgz", + "integrity": "sha512-ByY+tjCciCr+9nLryBYcSD50EOGWt95c7tIsKTG1J2ixKKXPvF7Ej3AVd+UfDydAJom3biBGDBALaO79ktwgEQ==", "dev": true, "dependencies": { "has": "^1.0.3" @@ -4396,9 +4517,9 @@ } }, "node_modules/is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, "dependencies": { "is-extglob": "^2.1.1" @@ -4593,9 +4714,9 @@ } }, "node_modules/istanbul-lib-coverage": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", - "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.1.tgz", + "integrity": "sha512-GvCYYTxaCPqwMjobtVcVKvSHtAGe48MNhGjpK8LtVF8K0ISX7hCKl85LgtuaSneWVyQmaGcW3iXVV3GaZSLpmQ==", "dev": true, "engines": { "node": ">=8" @@ -4697,12 +4818,12 @@ } }, "node_modules/jest-changed-files": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.1.1.tgz", - "integrity": "sha512-5TV9+fYlC2A6hu3qtoyGHprBwCAn0AuGA77bZdUgYvVlRMjHXo063VcWTEAyx6XAZ85DYHqp0+aHKbPlfRDRvA==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.2.4.tgz", + "integrity": "sha512-eeO1C1u4ex7pdTroYXezr+rbr957myyVoKGjcY4R1TJi3A+9v+4fu1Iv9J4eLq1bgFyT3O3iRWU9lZsEE7J72Q==", "dev": true, "dependencies": { - "@jest/types": "^27.1.1", + "@jest/types": "^27.2.4", "execa": "^5.0.0", "throat": "^6.0.1" }, @@ -4711,27 +4832,27 @@ } }, "node_modules/jest-circus": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.2.0.tgz", - "integrity": "sha512-WwENhaZwOARB1nmcboYPSv/PwHBUGRpA4MEgszjr9DLCl97MYw0qZprBwLb7rNzvMwfIvNGG7pefQ5rxyBlzIA==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.2.4.tgz", + "integrity": "sha512-TtheheTElrGjlsY9VxkzUU1qwIx05ItIusMVKnvNkMt4o/PeegLRcjq3Db2Jz0GGdBalJdbzLZBgeulZAJxJWA==", "dev": true, "dependencies": { - "@jest/environment": "^27.2.0", - "@jest/test-result": "^27.2.0", - "@jest/types": "^27.1.1", + "@jest/environment": "^27.2.4", + "@jest/test-result": "^27.2.4", + "@jest/types": "^27.2.4", "@types/node": "*", "chalk": "^4.0.0", "co": "^4.6.0", "dedent": "^0.7.0", - "expect": "^27.2.0", + "expect": "^27.2.4", "is-generator-fn": "^2.0.0", - "jest-each": "^27.2.0", - "jest-matcher-utils": "^27.2.0", - "jest-message-util": "^27.2.0", - "jest-runtime": "^27.2.0", - "jest-snapshot": "^27.2.0", - "jest-util": "^27.2.0", - "pretty-format": "^27.2.0", + "jest-each": "^27.2.4", + "jest-matcher-utils": "^27.2.4", + "jest-message-util": "^27.2.4", + "jest-runtime": "^27.2.4", + "jest-snapshot": "^27.2.4", + "jest-util": "^27.2.4", + "pretty-format": "^27.2.4", "slash": "^3.0.0", "stack-utils": "^2.0.3", "throat": "^6.0.1" @@ -4811,23 +4932,23 @@ } }, "node_modules/jest-cli": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.2.0.tgz", - "integrity": "sha512-bq1X/B/b1kT9y1zIFMEW3GFRX1HEhFybiqKdbxM+j11XMMYSbU9WezfyWIhrSOmPT+iODLATVjfsCnbQs7cfIA==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.2.4.tgz", + "integrity": "sha512-4kpQQkg74HYLaXo3nzwtg4PYxSLgL7puz1LXHj5Tu85KmlIpxQFjRkXlx4V47CYFFIDoyl3rHA/cXOxUWyMpNg==", "dev": true, "dependencies": { - "@jest/core": "^27.2.0", - "@jest/test-result": "^27.2.0", - "@jest/types": "^27.1.1", + "@jest/core": "^27.2.4", + "@jest/test-result": "^27.2.4", + "@jest/types": "^27.2.4", "chalk": "^4.0.0", "exit": "^0.1.2", "graceful-fs": "^4.2.4", "import-local": "^3.0.2", - "jest-config": "^27.2.0", - "jest-util": "^27.2.0", - "jest-validate": "^27.2.0", + "jest-config": "^27.2.4", + "jest-util": "^27.2.4", + "jest-validate": "^27.2.4", "prompts": "^2.0.1", - "yargs": "^16.0.3" + "yargs": "^16.2.0" }, "bin": { "jest": "bin/jest.js" @@ -4912,26 +5033,26 @@ } }, "node_modules/jest-cli/node_modules/string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" + "strip-ansi": "^6.0.1" }, "engines": { "node": ">=8" } }, "node_modules/jest-cli/node_modules/strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "dependencies": { - "ansi-regex": "^5.0.0" + "ansi-regex": "^5.0.1" }, "engines": { "node": ">=8" @@ -4977,32 +5098,32 @@ } }, "node_modules/jest-config": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.2.0.tgz", - "integrity": "sha512-Z1romHpxeNwLxQtouQ4xt07bY6HSFGKTo0xJcvOK3u6uJHveA4LB2P+ty9ArBLpTh3AqqPxsyw9l9GMnWBYS9A==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.2.4.tgz", + "integrity": "sha512-tWy0UxhdzqiKyp4l5Vq4HxLyD+gH5td+GCF3c22/DJ0bYAOsMo+qi2XtbJI6oYMH5JOJQs9nLW/r34nvFCehjA==", "dev": true, "dependencies": { "@babel/core": "^7.1.0", - "@jest/test-sequencer": "^27.2.0", - "@jest/types": "^27.1.1", - "babel-jest": "^27.2.0", + "@jest/test-sequencer": "^27.2.4", + "@jest/types": "^27.2.4", + "babel-jest": "^27.2.4", "chalk": "^4.0.0", "deepmerge": "^4.2.2", "glob": "^7.1.1", "graceful-fs": "^4.2.4", "is-ci": "^3.0.0", - "jest-circus": "^27.2.0", - "jest-environment-jsdom": "^27.2.0", - "jest-environment-node": "^27.2.0", + "jest-circus": "^27.2.4", + "jest-environment-jsdom": "^27.2.4", + "jest-environment-node": "^27.2.4", "jest-get-type": "^27.0.6", - "jest-jasmine2": "^27.2.0", + "jest-jasmine2": "^27.2.4", "jest-regex-util": "^27.0.6", - "jest-resolve": "^27.2.0", - "jest-runner": "^27.2.0", - "jest-util": "^27.2.0", - "jest-validate": "^27.2.0", + "jest-resolve": "^27.2.4", + "jest-runner": "^27.2.4", + "jest-util": "^27.2.4", + "jest-validate": "^27.2.4", "micromatch": "^4.0.4", - "pretty-format": "^27.2.0" + "pretty-format": "^27.2.4" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" @@ -5087,15 +5208,15 @@ } }, "node_modules/jest-diff": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.2.0.tgz", - "integrity": "sha512-QSO9WC6btFYWtRJ3Hac0sRrkspf7B01mGrrQEiCW6TobtViJ9RWL0EmOs/WnBsZDsI/Y2IoSHZA2x6offu0sYw==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.2.4.tgz", + "integrity": "sha512-bLAVlDSCR3gqUPGv+4nzVpEXGsHh98HjUL7Vb2hVyyuBDoQmja8eJb0imUABsuxBeUVmf47taJSAd9nDrwWKEg==", "dev": true, "dependencies": { "chalk": "^4.0.0", "diff-sequences": "^27.0.6", "jest-get-type": "^27.0.6", - "pretty-format": "^27.2.0" + "pretty-format": "^27.2.4" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" @@ -5184,16 +5305,16 @@ } }, "node_modules/jest-each": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.2.0.tgz", - "integrity": "sha512-biDmmUQjg+HZOB7MfY2RHSFL3j418nMoC3TK3pGAj880fQQSxvQe1y2Wy23JJJNUlk6YXiGU0yWy86Le1HBPmA==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.2.4.tgz", + "integrity": "sha512-w9XVc+0EDBUTJS4xBNJ7N2JCcWItFd006lFjz77OarAQcQ10eFDBMrfDv2GBJMKlXe9aq0HrIIF51AXcZrRJyg==", "dev": true, "dependencies": { - "@jest/types": "^27.1.1", + "@jest/types": "^27.2.4", "chalk": "^4.0.0", "jest-get-type": "^27.0.6", - "jest-util": "^27.2.0", - "pretty-format": "^27.2.0" + "jest-util": "^27.2.4", + "pretty-format": "^27.2.4" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" @@ -5270,17 +5391,17 @@ } }, "node_modules/jest-environment-jsdom": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.2.0.tgz", - "integrity": "sha512-wNQJi6Rd/AkUWqTc4gWhuTIFPo7tlMK0RPZXeM6AqRHZA3D3vwvTa9ktAktyVyWYmUoXdYstOfyYMG3w4jt7eA==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.2.4.tgz", + "integrity": "sha512-X70pTXFSypD7AIzKT1mLnDi5hP9w9mdTRcOGOmoDoBrNyNEg4rYm6d4LQWFLc9ps1VnMuDOkFSG0wjSNYGjkng==", "dev": true, "dependencies": { - "@jest/environment": "^27.2.0", - "@jest/fake-timers": "^27.2.0", - "@jest/types": "^27.1.1", + "@jest/environment": "^27.2.4", + "@jest/fake-timers": "^27.2.4", + "@jest/types": "^27.2.4", "@types/node": "*", - "jest-mock": "^27.1.1", - "jest-util": "^27.2.0", + "jest-mock": "^27.2.4", + "jest-util": "^27.2.4", "jsdom": "^16.6.0" }, "engines": { @@ -5288,17 +5409,17 @@ } }, "node_modules/jest-environment-node": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.2.0.tgz", - "integrity": "sha512-WbW+vdM4u88iy6Q3ftUEQOSgMPtSgjm3qixYYK2AKEuqmFO2zmACTw1vFUB0qI/QN88X6hA6ZkVKIdIWWzz+yg==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.2.4.tgz", + "integrity": "sha512-ZbVbFSnbzTvhLOIkqh5lcLuGCCFvtG4xTXIRPK99rV2KzQT3kNg16KZwfTnLNlIiWCE8do960eToeDfcqmpSAw==", "dev": true, "dependencies": { - "@jest/environment": "^27.2.0", - "@jest/fake-timers": "^27.2.0", - "@jest/types": "^27.1.1", + "@jest/environment": "^27.2.4", + "@jest/fake-timers": "^27.2.4", + "@jest/types": "^27.2.4", "@types/node": "*", - "jest-mock": "^27.1.1", - "jest-util": "^27.2.0" + "jest-mock": "^27.2.4", + "jest-util": "^27.2.4" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" @@ -5314,12 +5435,12 @@ } }, "node_modules/jest-haste-map": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.2.0.tgz", - "integrity": "sha512-laFet7QkNlWjwZtMGHCucLvF8o9PAh2cgePRck1+uadSM4E4XH9J4gnx4do+a6do8ZV5XHNEAXEkIoNg5XUH2Q==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.2.4.tgz", + "integrity": "sha512-bkJ4bT00T2K+1NZXbRcyKnbJ42I6QBvoDNMTAQQDBhaGNnZreiQKUNqax0e6hLTx7E75pKDeltVu3V1HAdu+YA==", "dev": true, "dependencies": { - "@jest/types": "^27.1.1", + "@jest/types": "^27.2.4", "@types/graceful-fs": "^4.1.2", "@types/node": "*", "anymatch": "^3.0.3", @@ -5327,8 +5448,8 @@ "graceful-fs": "^4.2.4", "jest-regex-util": "^27.0.6", "jest-serializer": "^27.0.6", - "jest-util": "^27.2.0", - "jest-worker": "^27.2.0", + "jest-util": "^27.2.4", + "jest-worker": "^27.2.4", "micromatch": "^4.0.4", "walker": "^1.0.7" }, @@ -5340,28 +5461,28 @@ } }, "node_modules/jest-jasmine2": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.2.0.tgz", - "integrity": "sha512-NcPzZBk6IkDW3Z2V8orGueheGJJYfT5P0zI/vTO/Jp+R9KluUdgFrgwfvZ0A34Kw6HKgiWFILZmh3oQ/eS+UxA==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.2.4.tgz", + "integrity": "sha512-fcffjO/xLWLVnW2ct3No4EksxM5RyPwHDYu9QU+90cC+/eSMLkFAxS55vkqsxexOO5zSsZ3foVpMQcg/amSeIQ==", "dev": true, "dependencies": { "@babel/traverse": "^7.1.0", - "@jest/environment": "^27.2.0", + "@jest/environment": "^27.2.4", "@jest/source-map": "^27.0.6", - "@jest/test-result": "^27.2.0", - "@jest/types": "^27.1.1", + "@jest/test-result": "^27.2.4", + "@jest/types": "^27.2.4", "@types/node": "*", "chalk": "^4.0.0", "co": "^4.6.0", - "expect": "^27.2.0", + "expect": "^27.2.4", "is-generator-fn": "^2.0.0", - "jest-each": "^27.2.0", - "jest-matcher-utils": "^27.2.0", - "jest-message-util": "^27.2.0", - "jest-runtime": "^27.2.0", - "jest-snapshot": "^27.2.0", - "jest-util": "^27.2.0", - "pretty-format": "^27.2.0", + "jest-each": "^27.2.4", + "jest-matcher-utils": "^27.2.4", + "jest-message-util": "^27.2.4", + "jest-runtime": "^27.2.4", + "jest-snapshot": "^27.2.4", + "jest-util": "^27.2.4", + "pretty-format": "^27.2.4", "throat": "^6.0.1" }, "engines": { @@ -5439,28 +5560,28 @@ } }, "node_modules/jest-leak-detector": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.2.0.tgz", - "integrity": "sha512-e91BIEmbZw5+MHkB4Hnrq7S86coTxUMCkz4n7DLmQYvl9pEKmRx9H/JFH87bBqbIU5B2Ju1soKxRWX6/eGFGpA==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.2.4.tgz", + "integrity": "sha512-SrcHWbe0EHg/bw2uBjVoHacTo5xosl068x2Q0aWsjr2yYuW2XwqrSkZV4lurUop0jhv1709ymG4or+8E4sH27Q==", "dev": true, "dependencies": { "jest-get-type": "^27.0.6", - "pretty-format": "^27.2.0" + "pretty-format": "^27.2.4" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/jest-matcher-utils": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.2.0.tgz", - "integrity": "sha512-F+LG3iTwJ0gPjxBX6HCyrARFXq6jjiqhwBQeskkJQgSLeF1j6ui1RTV08SR7O51XTUhtc8zqpDj8iCG4RGmdKw==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.2.4.tgz", + "integrity": "sha512-nQeLfFAIPPkyhkDfifAPfP/U5wm1x0fLtAzqXZSSKckXDNuk2aaOfQiDYv1Mgf5GY6yOsxfUnvNm3dDjXM+BXw==", "dev": true, "dependencies": { "chalk": "^4.0.0", - "jest-diff": "^27.2.0", + "jest-diff": "^27.2.4", "jest-get-type": "^27.0.6", - "pretty-format": "^27.2.0" + "pretty-format": "^27.2.4" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" @@ -5537,18 +5658,18 @@ } }, "node_modules/jest-message-util": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.2.0.tgz", - "integrity": "sha512-y+sfT/94CiP8rKXgwCOzO1mUazIEdEhrLjuiu+RKmCP+8O/TJTSne9dqQRbFIHBtlR2+q7cddJlWGir8UATu5w==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.2.4.tgz", + "integrity": "sha512-wbKT/BNGnBVB9nzi+IoaLkXt6fbSvqUxx+IYY66YFh96J3goY33BAaNG3uPqaw/Sh/FR9YpXGVDfd5DJdbh4nA==", "dev": true, "dependencies": { "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.1.1", + "@jest/types": "^27.2.4", "@types/stack-utils": "^2.0.0", "chalk": "^4.0.0", "graceful-fs": "^4.2.4", "micromatch": "^4.0.4", - "pretty-format": "^27.2.0", + "pretty-format": "^27.2.4", "slash": "^3.0.0", "stack-utils": "^2.0.3" }, @@ -5627,12 +5748,12 @@ } }, "node_modules/jest-mock": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.1.1.tgz", - "integrity": "sha512-SClsFKuYBf+6SSi8jtAYOuPw8DDMsTElUWEae3zq7vDhH01ayVSIHUSIa8UgbDOUalCFp6gNsaikN0rbxN4dbw==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.2.4.tgz", + "integrity": "sha512-iVRU905rutaAoUcrt5Tm1JoHHWi24YabqEGXjPJI4tAyA6wZ7mzDi3GrZ+M7ebgWBqUkZE93GAx1STk7yCMIQA==", "dev": true, "dependencies": { - "@jest/types": "^27.1.1", + "@jest/types": "^27.2.4", "@types/node": "*" }, "engines": { @@ -5666,19 +5787,19 @@ } }, "node_modules/jest-resolve": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.2.0.tgz", - "integrity": "sha512-v09p9Ib/VtpHM6Cz+i9lEAv1Z/M5NVxsyghRHRMEUOqwPQs3zwTdwp1xS3O/k5LocjKiGS0OTaJoBSpjbM2Jlw==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.2.4.tgz", + "integrity": "sha512-IsAO/3+3BZnKjI2I4f3835TBK/90dxR7Otgufn3mnrDFTByOSXclDi3G2XJsawGV4/18IMLARJ+V7Wm7t+J89Q==", "dev": true, "dependencies": { - "@jest/types": "^27.1.1", + "@jest/types": "^27.2.4", "chalk": "^4.0.0", "escalade": "^3.1.1", "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.2.0", + "jest-haste-map": "^27.2.4", "jest-pnp-resolver": "^1.2.2", - "jest-util": "^27.2.0", - "jest-validate": "^27.2.0", + "jest-util": "^27.2.4", + "jest-validate": "^27.2.4", "resolve": "^1.20.0", "slash": "^3.0.0" }, @@ -5687,14 +5808,14 @@ } }, "node_modules/jest-resolve-dependencies": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.2.0.tgz", - "integrity": "sha512-EY5jc/Y0oxn+oVEEldTidmmdVoZaknKPyDORA012JUdqPyqPL+lNdRyI3pGti0RCydds6coaw6xt4JQY54dKsg==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.2.4.tgz", + "integrity": "sha512-i5s7Uh9B3Q6uwxLpMhNKlgBf6pcemvWaORxsW1zNF/YCY3jd5EftvnGBI+fxVwJ1CBxkVfxqCvm1lpZkbaoGmg==", "dev": true, "dependencies": { - "@jest/types": "^27.1.1", + "@jest/types": "^27.2.4", "jest-regex-util": "^27.0.6", - "jest-snapshot": "^27.2.0" + "jest-snapshot": "^27.2.4" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" @@ -5771,31 +5892,31 @@ } }, "node_modules/jest-runner": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.2.0.tgz", - "integrity": "sha512-Cl+BHpduIc0cIVTjwoyx0pQk4Br8gn+wkr35PmKCmzEdOUnQ2wN7QVXA8vXnMQXSlFkN/+KWnk20TAVBmhgrww==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.2.4.tgz", + "integrity": "sha512-hIo5PPuNUyVDidZS8EetntuuJbQ+4IHWxmHgYZz9FIDbG2wcZjrP6b52uMDjAEQiHAn8yn8ynNe+TL8UuGFYKg==", "dev": true, "dependencies": { - "@jest/console": "^27.2.0", - "@jest/environment": "^27.2.0", - "@jest/test-result": "^27.2.0", - "@jest/transform": "^27.2.0", - "@jest/types": "^27.1.1", + "@jest/console": "^27.2.4", + "@jest/environment": "^27.2.4", + "@jest/test-result": "^27.2.4", + "@jest/transform": "^27.2.4", + "@jest/types": "^27.2.4", "@types/node": "*", "chalk": "^4.0.0", "emittery": "^0.8.1", "exit": "^0.1.2", "graceful-fs": "^4.2.4", "jest-docblock": "^27.0.6", - "jest-environment-jsdom": "^27.2.0", - "jest-environment-node": "^27.2.0", - "jest-haste-map": "^27.2.0", - "jest-leak-detector": "^27.2.0", - "jest-message-util": "^27.2.0", - "jest-resolve": "^27.2.0", - "jest-runtime": "^27.2.0", - "jest-util": "^27.2.0", - "jest-worker": "^27.2.0", + "jest-environment-jsdom": "^27.2.4", + "jest-environment-node": "^27.2.4", + "jest-haste-map": "^27.2.4", + "jest-leak-detector": "^27.2.4", + "jest-message-util": "^27.2.4", + "jest-resolve": "^27.2.4", + "jest-runtime": "^27.2.4", + "jest-util": "^27.2.4", + "jest-worker": "^27.2.4", "source-map-support": "^0.5.6", "throat": "^6.0.1" }, @@ -5874,19 +5995,19 @@ } }, "node_modules/jest-runtime": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.2.0.tgz", - "integrity": "sha512-6gRE9AVVX49hgBbWQ9PcNDeM4upMUXzTpBs0kmbrjyotyUyIJixLPsYjpeTFwAA07PVLDei1iAm2chmWycdGdQ==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.2.4.tgz", + "integrity": "sha512-ICKzzYdjIi70P17MZsLLIgIQFCQmIjMFf+xYww3aUySiUA/QBPUTdUqo5B2eg4HOn9/KkUsV0z6GVgaqAPBJvg==", "dev": true, "dependencies": { - "@jest/console": "^27.2.0", - "@jest/environment": "^27.2.0", - "@jest/fake-timers": "^27.2.0", - "@jest/globals": "^27.2.0", + "@jest/console": "^27.2.4", + "@jest/environment": "^27.2.4", + "@jest/fake-timers": "^27.2.4", + "@jest/globals": "^27.2.4", "@jest/source-map": "^27.0.6", - "@jest/test-result": "^27.2.0", - "@jest/transform": "^27.2.0", - "@jest/types": "^27.1.1", + "@jest/test-result": "^27.2.4", + "@jest/transform": "^27.2.4", + "@jest/types": "^27.2.4", "@types/yargs": "^16.0.0", "chalk": "^4.0.0", "cjs-module-lexer": "^1.0.0", @@ -5895,17 +6016,17 @@ "exit": "^0.1.2", "glob": "^7.1.3", "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.2.0", - "jest-message-util": "^27.2.0", - "jest-mock": "^27.1.1", + "jest-haste-map": "^27.2.4", + "jest-message-util": "^27.2.4", + "jest-mock": "^27.2.4", "jest-regex-util": "^27.0.6", - "jest-resolve": "^27.2.0", - "jest-snapshot": "^27.2.0", - "jest-util": "^27.2.0", - "jest-validate": "^27.2.0", + "jest-resolve": "^27.2.4", + "jest-snapshot": "^27.2.4", + "jest-util": "^27.2.4", + "jest-validate": "^27.2.4", "slash": "^3.0.0", "strip-bom": "^4.0.0", - "yargs": "^16.0.3" + "yargs": "^16.2.0" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" @@ -5979,26 +6100,26 @@ } }, "node_modules/jest-runtime/node_modules/string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" + "strip-ansi": "^6.0.1" }, "engines": { "node": ">=8" } }, "node_modules/jest-runtime/node_modules/strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "dependencies": { - "ansi-regex": "^5.0.0" + "ansi-regex": "^5.0.1" }, "engines": { "node": ">=8" @@ -6057,9 +6178,9 @@ } }, "node_modules/jest-snapshot": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.2.0.tgz", - "integrity": "sha512-MukJvy3KEqemCT2FoT3Gum37CQqso/62PKTfIzWmZVTsLsuyxQmJd2PI5KPcBYFqLlA8LgZLHM8ZlazkVt8LsQ==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.2.4.tgz", + "integrity": "sha512-5DFxK31rYS8X8C6WXsFx8XxrxW3PGa6+9IrUcZdTLg1aEyXDGIeiBh4jbwvh655bg/9vTETbEj/njfZicHTZZw==", "dev": true, "dependencies": { "@babel/core": "^7.7.2", @@ -6068,23 +6189,23 @@ "@babel/plugin-syntax-typescript": "^7.7.2", "@babel/traverse": "^7.7.2", "@babel/types": "^7.0.0", - "@jest/transform": "^27.2.0", - "@jest/types": "^27.1.1", + "@jest/transform": "^27.2.4", + "@jest/types": "^27.2.4", "@types/babel__traverse": "^7.0.4", "@types/prettier": "^2.1.5", "babel-preset-current-node-syntax": "^1.0.0", "chalk": "^4.0.0", - "expect": "^27.2.0", + "expect": "^27.2.4", "graceful-fs": "^4.2.4", - "jest-diff": "^27.2.0", + "jest-diff": "^27.2.4", "jest-get-type": "^27.0.6", - "jest-haste-map": "^27.2.0", - "jest-matcher-utils": "^27.2.0", - "jest-message-util": "^27.2.0", - "jest-resolve": "^27.2.0", - "jest-util": "^27.2.0", + "jest-haste-map": "^27.2.4", + "jest-matcher-utils": "^27.2.4", + "jest-message-util": "^27.2.4", + "jest-resolve": "^27.2.4", + "jest-util": "^27.2.4", "natural-compare": "^1.4.0", - "pretty-format": "^27.2.0", + "pretty-format": "^27.2.4", "semver": "^7.3.2" }, "engines": { @@ -6177,12 +6298,12 @@ } }, "node_modules/jest-util": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.2.0.tgz", - "integrity": "sha512-T5ZJCNeFpqcLBpx+Hl9r9KoxBCUqeWlJ1Htli+vryigZVJ1vuLB9j35grEBASp4R13KFkV7jM52bBGnArpJN6A==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.2.4.tgz", + "integrity": "sha512-mW++4u+fSvAt3YBWm5IpbmRAceUqa2B++JlUZTiuEt2AmNYn0Yw5oay4cP17TGsMINRNPSGiJ2zNnX60g+VbFg==", "dev": true, "dependencies": { - "@jest/types": "^27.1.1", + "@jest/types": "^27.2.4", "@types/node": "*", "chalk": "^4.0.0", "graceful-fs": "^4.2.4", @@ -6264,17 +6385,17 @@ } }, "node_modules/jest-validate": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.2.0.tgz", - "integrity": "sha512-uIEZGkFKk3+4liA81Xu0maG5aGDyPLdp+4ed244c+Ql0k3aLWQYcMbaMLXOIFcb83LPHzYzqQ8hwNnIxTqfAGQ==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.2.4.tgz", + "integrity": "sha512-VMtbxbkd7LHnIH7PChdDtrluCFRJ4b1YV2YJzNwwsASMWftq/HgqiqjvptBOWyWOtevgO3f14wPxkPcLlVBRog==", "dev": true, "dependencies": { - "@jest/types": "^27.1.1", + "@jest/types": "^27.2.4", "camelcase": "^6.2.0", "chalk": "^4.0.0", "jest-get-type": "^27.0.6", "leven": "^3.1.0", - "pretty-format": "^27.2.0" + "pretty-format": "^27.2.4" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" @@ -6363,17 +6484,17 @@ } }, "node_modules/jest-watcher": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.2.0.tgz", - "integrity": "sha512-SjRWhnr+qO8aBsrcnYIyF+qRxNZk6MZH8TIDgvi+VlsyrvOyqg0d+Rm/v9KHiTtC9mGGeFi9BFqgavyWib6xLg==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.2.4.tgz", + "integrity": "sha512-LXC/0+dKxhK7cfF7reflRYlzDIaQE+fL4ynhKhzg8IMILNMuI4xcjXXfUJady7OR4/TZeMg7X8eHx8uan9vqaQ==", "dev": true, "dependencies": { - "@jest/test-result": "^27.2.0", - "@jest/types": "^27.1.1", + "@jest/test-result": "^27.2.4", + "@jest/types": "^27.2.4", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", - "jest-util": "^27.2.0", + "jest-util": "^27.2.4", "string-length": "^4.0.1" }, "engines": { @@ -6478,9 +6599,9 @@ } }, "node_modules/jest-worker": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.2.0.tgz", - "integrity": "sha512-laB0ZVIBz+voh/QQy9dmUuuDsadixeerrKqyVpgPz+CCWiOYjOBabUXHIXZhsdvkWbLqSHbgkAHWl5cg24Q6RA==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.2.4.tgz", + "integrity": "sha512-Zq9A2Pw59KkVjBBKD1i3iE2e22oSjXhUKKuAK1HGX8flGwkm6NMozyEYzKd41hXc64dbd/0eWFeEEuxqXyhM+g==", "dev": true, "dependencies": { "@types/node": "*", @@ -6944,6 +7065,13 @@ "integrity": "sha1-ZHYsSGGAglGKw99Mz11YhtriA0c=", "dev": true }, + "node_modules/lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", + "dev": true, + "optional": true + }, "node_modules/lodash.ismatch": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz", @@ -7019,6 +7147,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "optional": true + }, "node_modules/makeerror": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", @@ -7029,9 +7164,9 @@ } }, "node_modules/map-obj": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.2.1.tgz", - "integrity": "sha512-+WA2/1sPmDj1dlvvJmB5G6JKfY9dpn7EVBUL06+y6PoljPkh+6V1QihwxNkbcGxCRjt2b0F9K0taiCuo7MbdFQ==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", + "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", "dev": true, "engines": { "node": ">=8" @@ -7053,15 +7188,15 @@ } }, "node_modules/marked-terminal": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-4.1.1.tgz", - "integrity": "sha512-t7Mdf6T3PvOEyN01c3tYxDzhyKZ8xnkp8Rs6Fohno63L/0pFTJ5Qtwto2AQVuDtbQiWzD+4E5AAu1Z2iLc8miQ==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-4.2.0.tgz", + "integrity": "sha512-DQfNRV9svZf0Dm9Cf5x5xaVJ1+XjxQW6XjFJ5HFkVyK52SDpj5PCBzS5X5r2w9nHr3mlB0T5201UMLue9fmhUw==", "dev": true, "dependencies": { "ansi-escapes": "^4.3.1", "cardinal": "^2.1.1", "chalk": "^4.1.0", - "cli-table": "^0.3.1", + "cli-table3": "^0.6.0", "node-emoji": "^1.10.0", "supports-hyperlinks": "^2.1.0" }, @@ -7327,6 +7462,11 @@ "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", "dev": true }, + "node_modules/nanocolors": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/nanocolors/-/nanocolors-0.2.12.tgz", + "integrity": "sha512-SFNdALvzW+rVlzqexid6epYdt8H9Zol7xDoQarioEFcFN0JHo4CYNztAxmtfgGTVRCmFlEOqqhBpoFGKqSAMug==" + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -7355,14 +7495,39 @@ } }, "node_modules/node-fetch": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.2.tgz", - "integrity": "sha512-aLoxToI6RfZ+0NOjmWAgn9+LEd30YCkJKFSyWacNZdEKTit/ZMcKjGkTRo8uWEsnIb/hfKecNPEbln02PdWbcA==", + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.5.tgz", + "integrity": "sha512-mmlIVHJEu5rnIxgEgez6b9GgWXbkZj5YZ7fx+2r94a2E+Uirsp6HsPTPlomfdHtpt/B0cdKviwkoaM6pyvUOpQ==", "dev": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, "engines": { "node": "4.x || >=6.0.0" } }, + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", + "dev": true + }, + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=", + "dev": true + }, + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "dev": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -7379,9 +7544,9 @@ } }, "node_modules/node-releases": { - "version": "1.1.75", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.75.tgz", - "integrity": "sha512-Qe5OUajvqrqDSy6wrWFmMwfJ0jVgwiw4T3KqmbTcZ62qW0gQkheXYhcFM1+lOVcGUoRxcEcfyvFMAnDgaF1VWw==" + "version": "1.1.76", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.76.tgz", + "integrity": "sha512-9/IECtNr8dXNmPWmFXepT0/7o5eolGesHUa3mtr0KlgnCvnZxwh2qensKL42JJY2vQKC3nIBXetFAqR+PW1CmA==" }, "node_modules/normalize-package-data": { "version": "3.0.3", @@ -7447,9 +7612,9 @@ } }, "node_modules/npm": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/npm/-/npm-7.23.0.tgz", - "integrity": "sha512-m7WFTwGfiBX+jL4ObX7rIDkug/hG/Jn8vZUjKw4WS8CqMjVydHiWTARLDIll7LtHu5i7ZHBnqXZbL2S73U5p6A==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/npm/-/npm-7.24.1.tgz", + "integrity": "sha512-U7/C++ZgB3zNH/kzhSJMnp3pO2iLrZRGUUXAgCCLB/by+sR+dKVhP/ik9+sTOGk9wk3zbmwHAYDT8igkv1ss0g==", "bundleDependencies": [ "@npmcli/arborist", "@npmcli/ci-detect", @@ -8575,7 +8740,7 @@ } }, "node_modules/npm/node_modules/glob": { - "version": "7.1.7", + "version": "7.2.0", "dev": true, "inBundle": true, "license": "ISC", @@ -8790,16 +8955,15 @@ } }, "node_modules/npm/node_modules/init-package-json": { - "version": "2.0.4", + "version": "2.0.5", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "glob": "^7.1.1", - "npm-package-arg": "^8.1.2", + "npm-package-arg": "^8.1.5", "promzard": "^0.3.0", "read": "~1.0.1", - "read-package-json": "^4.0.0", + "read-package-json": "^4.1.1", "semver": "^7.3.5", "validate-npm-package-license": "^3.0.4", "validate-npm-package-name": "^3.0.0" @@ -9186,7 +9350,7 @@ } }, "node_modules/npm/node_modules/minipass": { - "version": "3.1.3", + "version": "3.1.5", "dev": true, "inBundle": true, "license": "ISC", @@ -10024,7 +10188,7 @@ } }, "node_modules/npm/node_modules/socks-proxy-agent": { - "version": "6.0.0", + "version": "6.1.0", "dev": true, "inBundle": true, "license": "MIT", @@ -10085,6 +10249,11 @@ "safer-buffer": "^2.0.2", "tweetnacl": "~0.14.0" }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, "engines": { "node": ">=0.10.0" } @@ -10398,6 +10567,15 @@ "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", "dev": true }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -10847,13 +11025,13 @@ } }, "node_modules/pretty-format": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.2.0.tgz", - "integrity": "sha512-KyJdmgBkMscLqo8A7K77omgLx5PWPiXJswtTtFV7XgVZv2+qPk6UivpXXO+5k6ZEbWIbLoKdx1pZ6ldINzbwTA==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.2.4.tgz", + "integrity": "sha512-NUjw22WJHldzxyps2YjLZkUj6q1HvjqFezkB9Y2cklN8NtVZN/kZEXGZdFw4uny3oENzV5EEMESrkI0YDUH8vg==", "dev": true, "dependencies": { - "@jest/types": "^27.1.1", - "ansi-regex": "^5.0.0", + "@jest/types": "^27.2.4", + "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", "react-is": "^17.0.1" }, @@ -11311,6 +11489,12 @@ "npm": ">=2.0.0" } }, + "node_modules/rxjs/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, "node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -11335,16 +11519,16 @@ } }, "node_modules/semantic-release": { - "version": "17.4.7", - "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-17.4.7.tgz", - "integrity": "sha512-3Ghu8mKCJgCG3QzE5xphkYWM19lGE3XjFdOXQIKBM2PBpBvgFQ/lXv31oX0+fuN/UjNFO/dqhNs8ATLBhg6zBg==", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-18.0.0.tgz", + "integrity": "sha512-/Szyhq5DTZCYry/aZqpBbK/kqv10ydn6oiiaYOXtPgDbAIkqidZcQOm+mfYFJ0sBTUaOYCKMlcPMgJycP7jDYQ==", "dev": true, "dependencies": { - "@semantic-release/commit-analyzer": "^8.0.0", - "@semantic-release/error": "^2.2.0", - "@semantic-release/github": "^7.0.0", - "@semantic-release/npm": "^7.0.0", - "@semantic-release/release-notes-generator": "^9.0.0", + "@semantic-release/commit-analyzer": "^9.0.0", + "@semantic-release/error": "^3.0.0", + "@semantic-release/github": "^8.0.0", + "@semantic-release/npm": "^8.0.0", + "@semantic-release/release-notes-generator": "^10.0.0", "aggregate-error": "^3.0.0", "cosmiconfig": "^7.0.0", "debug": "^4.0.0", @@ -11373,7 +11557,7 @@ "semantic-release": "bin/semantic-release.js" }, "engines": { - "node": ">=10.19" + "node": ">=14.17" } }, "node_modules/semantic-release/node_modules/figures": { @@ -11428,26 +11612,26 @@ } }, "node_modules/semantic-release/node_modules/string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" + "strip-ansi": "^6.0.1" }, "engines": { "node": ">=8" } }, "node_modules/semantic-release/node_modules/strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "dependencies": { - "ansi-regex": "^5.0.0" + "ansi-regex": "^5.0.1" }, "engines": { "node": ">=8" @@ -11540,9 +11724,9 @@ } }, "node_modules/signal-exit": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.5.tgz", + "integrity": "sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ==", "dev": true }, "node_modules/signale": { @@ -11681,13 +11865,12 @@ "dev": true }, "node_modules/stack-utils": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.4.tgz", - "integrity": "sha512-ERg+H//lSSYlZhBIUu+wJnqg30AbyBbpZlIhcshpn7BNzpoRODZgfyr9J+8ERf3ooC6af3u7Lcl01nleau7MrA==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", + "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", "dev": true, "dependencies": { - "escape-string-regexp": "^2.0.0", - "source-map-support": "^0.5.20" + "escape-string-regexp": "^2.0.0" }, "engines": { "node": ">=10" @@ -11744,12 +11927,12 @@ } }, "node_modules/string-length/node_modules/strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "dependencies": { - "ansi-regex": "^5.0.0" + "ansi-regex": "^5.0.1" }, "engines": { "node": ">=8" @@ -12267,11 +12450,39 @@ "node": ">=8" } }, + "node_modules/ts-node": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz", + "integrity": "sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==", + "dev": true, + "optional": true, + "dependencies": { + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.17", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "typescript": ">=2.7" + } + }, "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", + "dev": true, + "optional": true }, "node_modules/type-check": { "version": "0.3.2", @@ -12315,6 +12526,21 @@ "is-typedarray": "^1.0.0" } }, + "node_modules/typescript": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.3.tgz", + "integrity": "sha512-4xfscpisVgqqDfPaJo5vkd+Qd/ItkoagnHpufr+i2QCHBsNYp+G7UAoyFl8aPtx879u38wPV65rZ8qbGZijalA==", + "dev": true, + "optional": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, "node_modules/uglify-js": { "version": "3.14.2", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.14.2.tgz", @@ -12449,9 +12675,9 @@ "dev": true }, "node_modules/v8-to-istanbul": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.0.0.tgz", - "integrity": "sha512-LkmXi8UUNxnCC+JlH7/fsfsKr5AU110l+SYGJimWNkWhxbN5EyeOtm1MJ0hhvqMMOhGwBj1Fp70Yv9i+hX0QAg==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.0.tgz", + "integrity": "sha512-/PRhfd8aTNp9Ggr62HPzXg2XasNFGy5PBt0Rp04du7/8GNNSgxFL6WBTkgMKSL9bFjH+8kKEG3f37FmxiTqUUA==", "dev": true, "dependencies": { "@types/istanbul-lib-coverage": "^2.0.1", @@ -12666,26 +12892,26 @@ } }, "node_modules/wrap-ansi/node_modules/string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" + "strip-ansi": "^6.0.1" }, "engines": { "node": ">=8" } }, "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "dependencies": { - "ansi-regex": "^5.0.0" + "ansi-regex": "^5.0.1" }, "engines": { "node": ">=8" @@ -12782,9 +13008,9 @@ } }, "node_modules/yargs": { - "version": "17.1.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.1.1.tgz", - "integrity": "sha512-c2k48R0PwKIqKhPMWjeiF6y2xY/gPMUlro0sgxqXpbOIohWiLNXWslsootttv7E1e73QPAMQSg5FeySbVcpsPQ==", + "version": "17.2.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.2.1.tgz", + "integrity": "sha512-XfR8du6ua4K6uLGm5S6fA+FIJom/MdJcFNVY8geLlp2v8GYbOXD4EB1tPNZsRn4vBzKGMgb5DRZMeWuFc2GO8Q==", "dev": true, "dependencies": { "cliui": "^7.0.2", @@ -12818,26 +13044,26 @@ } }, "node_modules/yargs/node_modules/string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" + "strip-ansi": "^6.0.1" }, "engines": { "node": ">=8" } }, "node_modules/yargs/node_modules/strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "dependencies": { - "ansi-regex": "^5.0.0" + "ansi-regex": "^5.0.1" }, "engines": { "node": ">=8" @@ -12851,6 +13077,16 @@ "engines": { "node": ">=10" } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "optional": true, + "engines": { + "node": ">=6" + } } }, "dependencies": { @@ -12953,18 +13189,18 @@ } }, "@babel/helper-module-transforms": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.4.tgz", - "integrity": "sha512-9fHHSGE9zTC++KuXLZcB5FKgvlV83Ox+NLUmQTawovwlJ85+QMhk1CnVk406CQVj97LaWod6KVjl2Sfgw9Aktw==", + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.7.tgz", + "integrity": "sha512-ZNqjjQG/AuFfekFTY+7nY4RgBSklgTu970c7Rj3m/JOhIu5KPBUuTA9AY6zaKcUvk4g6EbDXdBnhi35FAssdSw==", "requires": { "@babel/helper-module-imports": "^7.15.4", "@babel/helper-replace-supers": "^7.15.4", "@babel/helper-simple-access": "^7.15.4", "@babel/helper-split-export-declaration": "^7.15.4", - "@babel/helper-validator-identifier": "^7.14.9", + "@babel/helper-validator-identifier": "^7.15.7", "@babel/template": "^7.15.4", "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.4" + "@babel/types": "^7.15.6" } }, "@babel/helper-optimise-call-expression": { @@ -13009,9 +13245,9 @@ } }, "@babel/helper-validator-identifier": { - "version": "7.14.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz", - "integrity": "sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g==" + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", + "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==" }, "@babel/helper-validator-option": { "version": "7.14.5", @@ -13039,9 +13275,9 @@ } }, "@babel/parser": { - "version": "7.15.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.6.tgz", - "integrity": "sha512-S/TSCcsRuCkmpUuoWijua0Snt+f3ewU/8spLo+4AXJCZfT0bVCzLD5MuOKdrx0mlAptbKzn5AdgEIIKXxXkz9Q==" + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.7.tgz", + "integrity": "sha512-rycZXvQ+xS9QyIcJ9HXeDWf1uxqlbVFAUq0Rq0dbc50Zb/+wUe/ehyfzGfm9KZZF0kBejYgxltBXocP+gKdL2g==" }, "@babel/plugin-syntax-async-generators": { "version": "7.8.4", @@ -13202,22 +13438,23 @@ "dev": true }, "@commitlint/execute-rule": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-13.0.0.tgz", - "integrity": "sha512-lBz2bJhNAgkkU/rFMAw3XBNujbxhxlaFHY3lfKB/MxpAa+pIfmWB3ig9i1VKe0wCvujk02O0WiMleNaRn2KJqw==", + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-13.2.0.tgz", + "integrity": "sha512-6nPwpN0hwTYmsH3WM4hCdN+NrMopgRIuQ0aqZa+jnwMoS/g6ljliQNYfL+m5WO306BaIu1W3yYpbW5aI8gEr0g==", "dev": true, "optional": true }, "@commitlint/load": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-13.1.0.tgz", - "integrity": "sha512-zlZbjJCWnWmBOSwTXis8H7I6pYk6JbDwOCuARA6B9Y/qt2PD+NCo0E/7EuaaFoxjHl+o56QR5QttuMBrf+BJzg==", + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-13.2.0.tgz", + "integrity": "sha512-Nhkv+hwWCCxWGjmE9jd1U8kfGGCkZVpwzlTtdKxpY+Aj2VCFg3BjY+qA81pMF3oAsIpxchSaZG5llb8kduVjYg==", "dev": true, "optional": true, "requires": { - "@commitlint/execute-rule": "^13.0.0", - "@commitlint/resolve-extends": "^13.0.0", - "@commitlint/types": "^13.1.0", + "@commitlint/execute-rule": "^13.2.0", + "@commitlint/resolve-extends": "^13.2.0", + "@commitlint/types": "^13.2.0", + "@endemolshinegroup/cosmiconfig-typescript-loader": "^3.0.2", "chalk": "^4.0.0", "cosmiconfig": "^7.0.0", "lodash": "^4.17.19", @@ -13282,9 +13519,9 @@ } }, "@commitlint/resolve-extends": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-13.0.0.tgz", - "integrity": "sha512-1SyaE+UOsYTkQlTPUOoj4NwxQhGFtYildVS/d0TJuK8a9uAJLw7bhCLH2PEeH5cC2D1do4Eqhx/3bLDrSLH3hg==", + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-13.2.0.tgz", + "integrity": "sha512-HLCMkqMKtvl1yYLZ1Pm0UpFvd0kYjsm1meLOGZ7VkOd9G/XX+Fr1S2G5AT2zeiDw7WUVYK8lGVMNa319bnV+aw==", "dev": true, "optional": true, "requires": { @@ -13295,9 +13532,9 @@ } }, "@commitlint/types": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-13.1.0.tgz", - "integrity": "sha512-zcVjuT+OfKt8h91vhBxt05RMcTGEx6DM7Q9QZeuMbXFk6xgbsSEDMMapbJPA1bCZ81fa/1OQBijSYPrKvtt06g==", + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-13.2.0.tgz", + "integrity": "sha512-RRVHEqmk1qn/dIaSQhvuca6k/6Z54G+r/KyimZ8gnAFielGiGUpsFRhIY3qhd5rXClVxDaa3nlcyTWckSccotQ==", "dev": true, "optional": true, "requires": { @@ -13361,6 +13598,19 @@ } } }, + "@endemolshinegroup/cosmiconfig-typescript-loader": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@endemolshinegroup/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-3.0.2.tgz", + "integrity": "sha512-QRVtqJuS1mcT56oHpVegkKBlgtWjXw/gHNWO3eL9oyB5Sc7HBoc2OLG/nYpVfT/Jejvo3NUrD0Udk7XgoyDKkA==", + "dev": true, + "optional": true, + "requires": { + "lodash.get": "^4", + "make-error": "^1", + "ts-node": "^9", + "tslib": "^2" + } + }, "@fink/cli": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/@fink/cli/-/cli-8.3.2.tgz", @@ -13390,9 +13640,9 @@ "integrity": "sha512-LwV75E4AyyBdmy8vPYjKUtosRMWQSRmP9zn2oDnYeThruuYZ3Im9fqUvPHLCSpAvjHFM8lJxwwZ4GT7ev3aa5w==" }, "@fink/larix": { - "version": "20.1.0", - "resolved": "https://registry.npmjs.org/@fink/larix/-/larix-20.1.0.tgz", - "integrity": "sha512-JSSnAOpSlxb0bHZ1Fj5t16O/SCCY8WtoCRtWmeONzYfJPkYqXOt3EpA76/3GWsqMlYEmLVdmc3/LuCLNMcyHzg==", + "version": "20.2.0", + "resolved": "https://registry.npmjs.org/@fink/larix/-/larix-20.2.0.tgz", + "integrity": "sha512-zEpKeIOR/lqlCfP6pK3UuFVDFywjAeX/L8AN0T4y5JN8kk17l1xKUuYgzktRZJaTE9gPaZnk3Cu2i2KsOFWq0w==", "dev": true, "requires": { "@fink/prattler": "^7.2.0", @@ -13459,16 +13709,16 @@ "dev": true }, "@jest/console": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.2.0.tgz", - "integrity": "sha512-35z+RqsK2CCgNxn+lWyK8X4KkaDtfL4BggT7oeZ0JffIiAiEYFYPo5B67V50ZubqDS1ehBrdCR2jduFnIrZOYw==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.2.4.tgz", + "integrity": "sha512-94znCKynPZpDpYHQ6esRJSc11AmONrVkBOBZiD7S+bSubHhrUfbS95EY5HIOxhm4PQO7cnvZkL3oJcY0oMA+Wg==", "dev": true, "requires": { - "@jest/types": "^27.1.1", + "@jest/types": "^27.2.4", "@types/node": "*", "chalk": "^4.0.0", - "jest-message-util": "^27.2.0", - "jest-util": "^27.2.0", + "jest-message-util": "^27.2.4", + "jest-util": "^27.2.4", "slash": "^3.0.0" }, "dependencies": { @@ -13524,37 +13774,36 @@ } }, "@jest/core": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.2.0.tgz", - "integrity": "sha512-E/2NHhq+VMo18DpKkoty8Sjey8Kps5Cqa88A8NP757s6JjYqPdioMuyUBhDiIOGCdQByEp0ou3jskkTszMS0nw==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.2.4.tgz", + "integrity": "sha512-UNQLyy+rXoojNm2MGlapgzWhZD1CT1zcHZQYeiD0xE7MtJfC19Q6J5D/Lm2l7i4V97T30usKDoEtjI8vKwWcLg==", "dev": true, "requires": { - "@jest/console": "^27.2.0", - "@jest/reporters": "^27.2.0", - "@jest/test-result": "^27.2.0", - "@jest/transform": "^27.2.0", - "@jest/types": "^27.1.1", + "@jest/console": "^27.2.4", + "@jest/reporters": "^27.2.4", + "@jest/test-result": "^27.2.4", + "@jest/transform": "^27.2.4", + "@jest/types": "^27.2.4", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", "emittery": "^0.8.1", "exit": "^0.1.2", "graceful-fs": "^4.2.4", - "jest-changed-files": "^27.1.1", - "jest-config": "^27.2.0", - "jest-haste-map": "^27.2.0", - "jest-message-util": "^27.2.0", + "jest-changed-files": "^27.2.4", + "jest-config": "^27.2.4", + "jest-haste-map": "^27.2.4", + "jest-message-util": "^27.2.4", "jest-regex-util": "^27.0.6", - "jest-resolve": "^27.2.0", - "jest-resolve-dependencies": "^27.2.0", - "jest-runner": "^27.2.0", - "jest-runtime": "^27.2.0", - "jest-snapshot": "^27.2.0", - "jest-util": "^27.2.0", - "jest-validate": "^27.2.0", - "jest-watcher": "^27.2.0", + "jest-resolve": "^27.2.4", + "jest-resolve-dependencies": "^27.2.4", + "jest-runner": "^27.2.4", + "jest-runtime": "^27.2.4", + "jest-snapshot": "^27.2.4", + "jest-util": "^27.2.4", + "jest-validate": "^27.2.4", + "jest-watcher": "^27.2.4", "micromatch": "^4.0.4", - "p-each-series": "^2.1.0", "rimraf": "^3.0.0", "slash": "^3.0.0", "strip-ansi": "^6.0.0" @@ -13610,12 +13859,12 @@ "dev": true }, "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { - "ansi-regex": "^5.0.0" + "ansi-regex": "^5.0.1" } }, "supports-color": { @@ -13636,53 +13885,53 @@ } }, "@jest/environment": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.2.0.tgz", - "integrity": "sha512-iPWmQI0wRIYSZX3wKu4FXHK4eIqkfq6n1DCDJS+v3uby7SOXrHvX4eiTBuEdSvtDRMTIH2kjrSkjHf/F9JIYyQ==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.2.4.tgz", + "integrity": "sha512-wkuui5yr3SSQW0XD0Qm3TATUbL/WE3LDEM3ulC+RCQhMf2yxhci8x7svGkZ4ivJ6Pc94oOzpZ6cdHBAMSYd1ew==", "dev": true, "requires": { - "@jest/fake-timers": "^27.2.0", - "@jest/types": "^27.1.1", + "@jest/fake-timers": "^27.2.4", + "@jest/types": "^27.2.4", "@types/node": "*", - "jest-mock": "^27.1.1" + "jest-mock": "^27.2.4" } }, "@jest/fake-timers": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.2.0.tgz", - "integrity": "sha512-gSu3YHvQOoVaTWYGgHFB7IYFtcF2HBzX4l7s47VcjvkUgL4/FBnE20x7TNLa3W6ABERtGd5gStSwsA8bcn+c4w==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.2.4.tgz", + "integrity": "sha512-cs/TzvwWUM7kAA6Qm/890SK6JJ2pD5RfDNM3SSEom6BmdyV6OiWP1qf/pqo6ts6xwpcM36oN0wSEzcZWc6/B6w==", "dev": true, "requires": { - "@jest/types": "^27.1.1", - "@sinonjs/fake-timers": "^7.0.2", + "@jest/types": "^27.2.4", + "@sinonjs/fake-timers": "^8.0.1", "@types/node": "*", - "jest-message-util": "^27.2.0", - "jest-mock": "^27.1.1", - "jest-util": "^27.2.0" + "jest-message-util": "^27.2.4", + "jest-mock": "^27.2.4", + "jest-util": "^27.2.4" } }, "@jest/globals": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.2.0.tgz", - "integrity": "sha512-raqk9Gf9WC3hlBa57rmRmJfRl9hom2b+qEE/ifheMtwn5USH5VZxzrHHOZg0Zsd/qC2WJ8UtyTwHKQAnNlDMdg==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.2.4.tgz", + "integrity": "sha512-DRsRs5dh0i+fA9mGHylTU19+8fhzNJoEzrgsu+zgJoZth3x8/0juCQ8nVVdW1er4Cqifb/ET7/hACYVPD0dBEA==", "dev": true, "requires": { - "@jest/environment": "^27.2.0", - "@jest/types": "^27.1.1", - "expect": "^27.2.0" + "@jest/environment": "^27.2.4", + "@jest/types": "^27.2.4", + "expect": "^27.2.4" } }, "@jest/reporters": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.2.0.tgz", - "integrity": "sha512-7wfkE3iRTLaT0F51h1mnxH3nQVwDCdbfgXiLuCcNkF1FnxXLH9utHqkSLIiwOTV1AtmiE0YagHbOvx4rnMP/GA==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.2.4.tgz", + "integrity": "sha512-LHeSdDnDZkDnJ8kvnjcqV8P1Yv/32yL4d4XfR5gBiy3xGO0onwll1QEbvtW96fIwhx2nejug0GTaEdNDoyr3fQ==", "dev": true, "requires": { "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^27.2.0", - "@jest/test-result": "^27.2.0", - "@jest/transform": "^27.2.0", - "@jest/types": "^27.1.1", + "@jest/console": "^27.2.4", + "@jest/test-result": "^27.2.4", + "@jest/transform": "^27.2.4", + "@jest/types": "^27.2.4", "chalk": "^4.0.0", "collect-v8-coverage": "^1.0.0", "exit": "^0.1.2", @@ -13693,15 +13942,15 @@ "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^4.0.0", "istanbul-reports": "^3.0.2", - "jest-haste-map": "^27.2.0", - "jest-resolve": "^27.2.0", - "jest-util": "^27.2.0", - "jest-worker": "^27.2.0", + "jest-haste-map": "^27.2.4", + "jest-resolve": "^27.2.4", + "jest-util": "^27.2.4", + "jest-worker": "^27.2.4", "slash": "^3.0.0", "source-map": "^0.6.0", "string-length": "^4.0.1", "terminal-link": "^2.0.0", - "v8-to-istanbul": "^8.0.0" + "v8-to-istanbul": "^8.1.0" }, "dependencies": { "ansi-styles": { @@ -13781,45 +14030,45 @@ } }, "@jest/test-result": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.2.0.tgz", - "integrity": "sha512-JPPqn8h0RGr4HyeY1Km+FivDIjTFzDROU46iAvzVjD42ooGwYoqYO/MQTilhfajdz6jpVnnphFrKZI5OYrBONA==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.2.4.tgz", + "integrity": "sha512-eU+PRo0+lIS01b0dTmMdVZ0TtcRSxEaYquZTRFMQz6CvsehGhx9bRzi9Zdw6VROviJyv7rstU+qAMX5pNBmnfQ==", "dev": true, "requires": { - "@jest/console": "^27.2.0", - "@jest/types": "^27.1.1", + "@jest/console": "^27.2.4", + "@jest/types": "^27.2.4", "@types/istanbul-lib-coverage": "^2.0.0", "collect-v8-coverage": "^1.0.0" } }, "@jest/test-sequencer": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.2.0.tgz", - "integrity": "sha512-PrqarcpzOU1KSAK7aPwfL8nnpaqTMwPe7JBPnaOYRDSe/C6AoJiL5Kbnonqf1+DregxZIRAoDg69R9/DXMGqXA==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.2.4.tgz", + "integrity": "sha512-fpk5eknU3/DXE2QCCG1wv/a468+cfPo3Asu6d6yUtM9LOPh709ubZqrhuUOYfM8hXMrIpIdrv1CdCrWWabX0rQ==", "dev": true, "requires": { - "@jest/test-result": "^27.2.0", + "@jest/test-result": "^27.2.4", "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.2.0", - "jest-runtime": "^27.2.0" + "jest-haste-map": "^27.2.4", + "jest-runtime": "^27.2.4" } }, "@jest/transform": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.2.0.tgz", - "integrity": "sha512-Q8Q/8xXIZYllk1AF7Ou5sV3egOZsdY/Wlv09CSbcexBRcC1Qt6lVZ7jRFAZtbHsEEzvOCyFEC4PcrwKwyjXtCg==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.2.4.tgz", + "integrity": "sha512-n5FlX2TH0oQGwyVDKPxdJ5nI2sO7TJBFe3u3KaAtt7TOiV4yL+Y+rSFDl+Ic5MpbiA/eqXmLAQxjnBmWgS2rEA==", "dev": true, "requires": { "@babel/core": "^7.1.0", - "@jest/types": "^27.1.1", + "@jest/types": "^27.2.4", "babel-plugin-istanbul": "^6.0.0", "chalk": "^4.0.0", "convert-source-map": "^1.4.0", "fast-json-stable-stringify": "^2.0.0", "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.2.0", + "jest-haste-map": "^27.2.4", "jest-regex-util": "^27.0.6", - "jest-util": "^27.2.0", + "jest-util": "^27.2.4", "micromatch": "^4.0.4", "pirates": "^4.0.1", "slash": "^3.0.0", @@ -13885,9 +14134,9 @@ } }, "@jest/types": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.1.1.tgz", - "integrity": "sha512-yqJPDDseb0mXgKqmNqypCsb85C22K1aY5+LUxh7syIM9n/b0AsaltxNy+o6tt29VcfGDpYEve175bm3uOhcehA==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.2.4.tgz", + "integrity": "sha512-IDO2ezTxeMvQAHxzG/ZvEyA47q0aVfzT95rGFl7bZs/Go0aIucvfDbS2rmnoEdXxlLQhcolmoG/wvL/uKx4tKA==", "dev": true, "requires": { "@types/istanbul-lib-coverage": "^2.0.0", @@ -13975,9 +14224,9 @@ } }, "@octokit/auth-token": { - "version": "2.4.5", - "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.4.5.tgz", - "integrity": "sha512-BpGYsPgJt05M7/L/5FoE1PiAbdxXFZkX/3kDYcsvd1v6UhlnE5e96dTDr0ezX/EFwciQxf3cNV0loipsURU+WA==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz", + "integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==", "dev": true, "requires": { "@octokit/types": "^6.0.3" @@ -14021,18 +14270,18 @@ } }, "@octokit/openapi-types": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-10.2.2.tgz", - "integrity": "sha512-EVcXQ+ZrC04cg17AMg1ofocWMxHDn17cB66ZHgYc0eUwjFtxS0oBzkyw2VqIrHBwVgtfoYrq1WMQfQmMjUwthw==", + "version": "10.6.4", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-10.6.4.tgz", + "integrity": "sha512-JVmwWzYTIs6jACYOwD6zu5rdrqGIYsiAsLzTCxdrWIPNKNVjEF6vPTL20shmgJ4qZsq7WPBcLXLsaQD+NLChfg==", "dev": true }, "@octokit/plugin-paginate-rest": { - "version": "2.16.3", - "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.16.3.tgz", - "integrity": "sha512-kdc65UEsqze/9fCISq6BxLzeB9qf0vKvKojIfzgwf4tEF+Wy6c9dXnPFE6vgpoDFB1Z5Jek5WFVU6vL1w22+Iw==", + "version": "2.16.7", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.16.7.tgz", + "integrity": "sha512-TMlyVhMPx6La1Ud4PSY4YxqAvb9YPEMs/7R1nBSbsw4wNqG73aBqls0r0dRRCWe5Pm0ZUGS9a94N46iAxlOR8A==", "dev": true, "requires": { - "@octokit/types": "^6.28.1" + "@octokit/types": "^6.31.3" } }, "@octokit/plugin-request-log": { @@ -14043,12 +14292,12 @@ "requires": {} }, "@octokit/plugin-rest-endpoint-methods": { - "version": "5.10.4", - "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.10.4.tgz", - "integrity": "sha512-Dh+EAMCYR9RUHwQChH94Skl0lM8Fh99auT8ggck/xTzjJrwVzvsd0YH68oRPqp/HxICzmUjLfaQ9sy1o1sfIiA==", + "version": "5.11.4", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.11.4.tgz", + "integrity": "sha512-iS+GYTijrPUiEiLoDsGJhrbXIvOPfm2+schvr+FxNMs7PeE9Nl4bAMhE8ftfNX3Z1xLxSKwEZh0O7GbWurX5HQ==", "dev": true, "requires": { - "@octokit/types": "^6.28.1", + "@octokit/types": "^6.31.2", "deprecation": "^2.3.1" } }, @@ -14078,51 +14327,51 @@ } }, "@octokit/rest": { - "version": "18.10.0", - "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.10.0.tgz", - "integrity": "sha512-esHR5OKy38bccL/sajHqZudZCvmv4yjovMJzyXlphaUo7xykmtOdILGJ3aAm0mFHmMLmPFmDMJXf39cAjNJsrw==", + "version": "18.11.4", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.11.4.tgz", + "integrity": "sha512-QplypCyYxqMK05JdMSm/bDWZO8VWWaBdzQ9tbF9rEV9rIEiICh+v6q+Vu/Y5hdze8JJaxfUC+PBC7vrnEkZvZg==", "dev": true, "requires": { "@octokit/core": "^3.5.1", - "@octokit/plugin-paginate-rest": "^2.16.0", + "@octokit/plugin-paginate-rest": "^2.16.4", "@octokit/plugin-request-log": "^1.0.4", - "@octokit/plugin-rest-endpoint-methods": "^5.9.0" + "@octokit/plugin-rest-endpoint-methods": "5.11.4" } }, "@octokit/types": { - "version": "6.28.1", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.28.1.tgz", - "integrity": "sha512-XlxDoQLFO5JnFZgKVQTYTvXRsQFfr/GwDUU108NJ9R5yFPkA2qXhTJjYuul3vE4eLXP40FA2nysOu2zd6boE+w==", + "version": "6.31.3", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.31.3.tgz", + "integrity": "sha512-IUG3uMpsLHrtEL6sCVXbxCgnbKcgpkS4K7gVEytLDvYYalkK3XcuMCHK1YPD8xJglSJAOAbL4MgXp47rS9G49w==", "dev": true, "requires": { - "@octokit/openapi-types": "^10.2.2" + "@octokit/openapi-types": "^10.6.4" } }, "@semantic-release/commit-analyzer": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@semantic-release/commit-analyzer/-/commit-analyzer-8.0.1.tgz", - "integrity": "sha512-5bJma/oB7B4MtwUkZC2Bf7O1MHfi4gWe4mA+MIQ3lsEV0b422Bvl1z5HRpplDnMLHH3EXMoRdEng6Ds5wUqA3A==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@semantic-release/commit-analyzer/-/commit-analyzer-9.0.1.tgz", + "integrity": "sha512-ncNsnrLmiykhgNZUXNvhhAjNN0me7VGIb0X5hu3ogyi5DDPapjGAHdEffO5vi+HX1BFWLRD/Ximx5PjGAKjAqQ==", "dev": true, "requires": { "conventional-changelog-angular": "^5.0.0", "conventional-commits-filter": "^2.0.0", "conventional-commits-parser": "^3.0.7", "debug": "^4.0.0", - "import-from": "^3.0.0", + "import-from": "^4.0.0", "lodash": "^4.17.4", "micromatch": "^4.0.2" } }, "@semantic-release/error": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-2.2.0.tgz", - "integrity": "sha512-9Tj/qn+y2j+sjCI3Jd+qseGtHjOAeg7dU2/lVcqIQ9TV3QDaDXDYXcoOHU+7o2Hwh8L8ymL4gfuO7KxDs3q2zg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-3.0.0.tgz", + "integrity": "sha512-5hiM4Un+tpl4cKw3lV4UgzJj+SmfNIDCLLw0TepzQxz9ZGV5ixnqkzIVF+3tp0ZHgcMKE+VNGHJjEeyFG2dcSw==", "dev": true }, "@semantic-release/github": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-7.2.3.tgz", - "integrity": "sha512-lWjIVDLal+EQBzy697ayUNN8MoBpp+jYIyW2luOdqn5XBH4d9bQGfTnjuLyzARZBHejqh932HVjiH/j4+R7VHw==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-8.0.1.tgz", + "integrity": "sha512-T01lfh4yBZodAeo8t0U+W5hmPYR9BdnfwLDerXnGaYeLXm8+KMx4mQEBAf/UbRVlzmIKTqMx+/s9fY/mSQNV0A==", "dev": true, "requires": { "@octokit/rest": "^18.0.0", @@ -14133,7 +14382,7 @@ "dir-glob": "^3.0.0", "fs-extra": "^10.0.0", "globby": "^11.0.0", - "http-proxy-agent": "^4.0.0", + "http-proxy-agent": "^5.0.0", "https-proxy-agent": "^5.0.0", "issue-parser": "^6.0.0", "lodash": "^4.17.4", @@ -14143,6 +14392,18 @@ "url-join": "^4.0.0" }, "dependencies": { + "@semantic-release/error": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-2.2.0.tgz", + "integrity": "sha512-9Tj/qn+y2j+sjCI3Jd+qseGtHjOAeg7dU2/lVcqIQ9TV3QDaDXDYXcoOHU+7o2Hwh8L8ymL4gfuO7KxDs3q2zg==", + "dev": true + }, + "@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "dev": true + }, "fs-extra": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", @@ -14154,6 +14415,17 @@ "universalify": "^2.0.0" } }, + "http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "requires": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + } + }, "jsonfile": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", @@ -14173,9 +14445,9 @@ } }, "@semantic-release/npm": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/@semantic-release/npm/-/npm-7.1.3.tgz", - "integrity": "sha512-x52kQ/jR09WjuWdaTEHgQCvZYMOTx68WnS+TZ4fya5ZAJw4oRtJETtrvUw10FdfM28d/keInQdc66R1Gw5+OEQ==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@semantic-release/npm/-/npm-8.0.0.tgz", + "integrity": "sha512-MAlynjIaN5XwBEzsq3xbZ8I+riD9zhLvpPqGCPaZ0j/ySbR0Sg3YG1MYv03fC1aygPFFC5RwefMxKids9llvDg==", "dev": true, "requires": { "@semantic-release/error": "^2.2.0", @@ -14193,6 +14465,12 @@ "tempy": "^1.0.0" }, "dependencies": { + "@semantic-release/error": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-2.2.0.tgz", + "integrity": "sha512-9Tj/qn+y2j+sjCI3Jd+qseGtHjOAeg7dU2/lVcqIQ9TV3QDaDXDYXcoOHU+7o2Hwh8L8ymL4gfuO7KxDs3q2zg==", + "dev": true + }, "fs-extra": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", @@ -14232,18 +14510,18 @@ } }, "@semantic-release/release-notes-generator": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/@semantic-release/release-notes-generator/-/release-notes-generator-9.0.3.tgz", - "integrity": "sha512-hMZyddr0u99OvM2SxVOIelHzly+PP3sYtJ8XOLHdMp8mrluN5/lpeTnIO27oeCYdupY/ndoGfvrqDjHqkSyhVg==", + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@semantic-release/release-notes-generator/-/release-notes-generator-10.0.2.tgz", + "integrity": "sha512-I4eavIcDan8fNQHskZ2cbWkFMimvgxNkqR2UfuYNwYBgswEl3SJsN8XMf9gZWObt6nXDc2QfDwhjy8DjTZqS3w==", "dev": true, "requires": { "conventional-changelog-angular": "^5.0.0", - "conventional-changelog-writer": "^4.0.0", + "conventional-changelog-writer": "^5.0.0", "conventional-commits-filter": "^2.0.0", "conventional-commits-parser": "^3.0.0", "debug": "^4.0.0", "get-stream": "^6.0.0", - "import-from": "^3.0.0", + "import-from": "^4.0.0", "into-stream": "^6.0.0", "lodash": "^4.17.4", "read-pkg-up": "^7.0.0" @@ -14259,9 +14537,9 @@ } }, "@sinonjs/fake-timers": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-7.1.2.tgz", - "integrity": "sha512-iQADsW4LBMISqZ6Ci1dupJL9pprqwcVFTcOsEmQOEhW+KLCVn/Y4Jrvg2k19fIHCp+iFprriYPTdRcQR8NbUPg==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.0.1.tgz", + "integrity": "sha512-AU7kwFxreVd6OAXcAFlKSmZquiRUU0FvYm44k1Y1QbK7Co4m0aqfGMhjykIeQp/H6rcl+nFmj0zfdUcGVs9Dew==", "dev": true, "requires": { "@sinonjs/commons": "^1.7.0" @@ -14354,9 +14632,9 @@ "dev": true }, "@types/node": { - "version": "16.9.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.9.1.tgz", - "integrity": "sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g==", + "version": "16.10.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.10.2.tgz", + "integrity": "sha512-zCclL4/rx+W5SQTzFs9wyvvyCwoK9QtBpratqz2IYJ3O8Umrn0m3nsTv0wQBk9sRGpvUe9CwPDrQFB10f1FIjQ==", "dev": true }, "@types/normalize-package-data": { @@ -14372,9 +14650,9 @@ "dev": true }, "@types/prettier": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.3.2.tgz", - "integrity": "sha512-eI5Yrz3Qv4KPUa/nSIAi0h+qX0XyewOliug5F2QAtuRg6Kjg6jfmxe1GIwoIRhZspD1A0RP8ANrPwvEXXtRFog==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.1.tgz", + "integrity": "sha512-Fo79ojj3vdEZOHg3wR9ksAMRz4P3S5fDB5e/YWZiFnyFQI1WY2Vftu9XoXVVtJfxB7Bpce/QTqWSSntkz2Znrw==", "dev": true }, "@types/retry": { @@ -14504,6 +14782,13 @@ "picomatch": "^2.0.4" } }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true, + "optional": true + }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -14544,13 +14829,13 @@ "dev": true }, "babel-jest": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.2.0.tgz", - "integrity": "sha512-bS2p+KGGVVmWXBa8+i6SO/xzpiz2Q/2LnqLbQknPKefWXVZ67YIjA4iXup/jMOEZplga9PpWn+wrdb3UdDwRaA==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.2.4.tgz", + "integrity": "sha512-f24OmxyWymk5jfgLdlCMu4fTs4ldxFBIdn5sJdhvGC1m08rSkJ5hYbWkNmfBSvE/DjhCVNSHXepxsI6THGfGsg==", "dev": true, "requires": { - "@jest/transform": "^27.2.0", - "@jest/types": "^27.1.1", + "@jest/transform": "^27.2.4", + "@jest/types": "^27.2.4", "@types/babel__core": "^7.1.14", "babel-plugin-istanbul": "^6.0.0", "babel-preset-jest": "^27.2.0", @@ -14732,15 +15017,15 @@ "dev": true }, "browserslist": { - "version": "4.17.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.0.tgz", - "integrity": "sha512-g2BJ2a0nEYvEFQC208q8mVAhfNwpZ5Mu8BwgtCdZKO3qx98HChmeg448fPdUzld8aFmfLgVh7yymqV+q1lJZ5g==", + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.2.tgz", + "integrity": "sha512-jSDZyqJmkKMEMi7SZAgX5UltFdR5NAO43vY0AwTpu4X3sGH7GLLQ83KiUomgrnvZRCeW0yPPnKqnxPqQOER9zQ==", "requires": { - "caniuse-lite": "^1.0.30001254", - "colorette": "^1.3.0", - "electron-to-chromium": "^1.3.830", + "caniuse-lite": "^1.0.30001261", + "electron-to-chromium": "^1.3.854", "escalade": "^3.1.1", - "node-releases": "^1.1.75" + "nanocolors": "^0.2.12", + "node-releases": "^1.1.76" } }, "bser": { @@ -14794,9 +15079,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001257", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001257.tgz", - "integrity": "sha512-JN49KplOgHSXpIsVSF+LUyhD8PUp6xPpAXeRrrcBh4KBeP7W864jHn6RvzJgDlrReyeVjMFJL3PLpPvKIxlIHA==" + "version": "1.0.30001263", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001263.tgz", + "integrity": "sha512-doiV5dft6yzWO1WwU19kt8Qz8R0/8DgEziz6/9n2FxUasteZNwNNYSmJO3GLBH8lCVE73AB1RPDPAeYbcO5Cvw==" }, "capture-stack-trace": { "version": "1.0.1", @@ -14869,13 +15154,43 @@ "restore-cursor": "^2.0.0" } }, - "cli-table": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.6.tgz", - "integrity": "sha512-ZkNZbnZjKERTY5NwC2SeMeLeifSPq/pubeRoTpdr3WchLlnZg6hEgvHkK5zL7KNFdd9PmHN8lxrENUwI3cE8vQ==", + "cli-table3": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.0.tgz", + "integrity": "sha512-gnB85c3MGC7Nm9I/FkiasNBOKjOiO1RNuXXarQms37q4QMpWdlbBgD/VnOStA2faG1dpXMv31RFApjX1/QdgWQ==", "dev": true, "requires": { - "colors": "1.0.3" + "colors": "^1.1.2", + "object-assign": "^4.1.0", + "string-width": "^4.2.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + } } }, "cli-width": { @@ -14902,23 +15217,23 @@ "dev": true }, "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" + "strip-ansi": "^6.0.1" } }, "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { - "ansi-regex": "^5.0.0" + "ansi-regex": "^5.0.1" } } } @@ -14948,16 +15263,12 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, - "colorette": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz", - "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==" - }, "colors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", - "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", - "dev": true + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true, + "optional": true }, "combined-stream": { "version": "1.0.8", @@ -15100,12 +15411,11 @@ } }, "conventional-changelog-writer": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-4.1.0.tgz", - "integrity": "sha512-WwKcUp7WyXYGQmkLsX4QmU42AZ1lqlvRW9mqoyiQzdD+rJWbTepdWoKJuwXTS+yq79XKnQNa93/roViPQrAQgw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-5.0.0.tgz", + "integrity": "sha512-HnDh9QHLNWfL6E1uHz6krZEQOgm8hN7z/m7tT16xwd802fwgMN0Wqd7AQYVkhpsjDUx/99oo+nGgvKF657XP5g==", "dev": true, "requires": { - "compare-func": "^2.0.0", "conventional-commits-filter": "^2.0.7", "dateformat": "^3.0.0", "handlebars": "^4.7.6", @@ -15183,6 +15493,13 @@ "capture-stack-trace": "^1.0.0" } }, + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "optional": true + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -15374,6 +15691,13 @@ "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", "dev": true }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "optional": true + }, "diff-sequences": { "version": "27.0.6", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.0.6.tgz", @@ -15437,9 +15761,9 @@ "dev": true }, "electron-to-chromium": { - "version": "1.3.839", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.839.tgz", - "integrity": "sha512-0O7uPs9LJNjQ/U5mW78qW8gXv9H6Ba3DHZ5/yt8aBsvomOWDkV3MddT7enUYvLQEUVOURjWmgJJWVZ3K98tIwQ==" + "version": "1.3.856", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.856.tgz", + "integrity": "sha512-lSezYIe1/p5qkEswAfaQUseOBiwGwuCvRl/MKzOEVe++DcmQ92+43dznDl4rFJ4Zpu+kevhwyIf7KjJevyDA/A==" }, "emittery": { "version": "0.8.1", @@ -15598,16 +15922,16 @@ } }, "expect": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-27.2.0.tgz", - "integrity": "sha512-oOTbawMQv7AK1FZURbPTgGSzmhxkjFzoARSvDjOMnOpeWuYQx1tP6rXu9MIX5mrACmyCAM7fSNP8IJO2f1p0CQ==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.2.4.tgz", + "integrity": "sha512-gOtuonQ8TCnbNNCSw2fhVzRf8EFYDII4nB5NmG4IEV0rbUnW1I5zXvoTntU4iicB/Uh0oZr20NGlOLdJiwsOZA==", "dev": true, "requires": { - "@jest/types": "^27.1.1", + "@jest/types": "^27.2.4", "ansi-styles": "^5.0.0", "jest-get-type": "^27.0.6", - "jest-matcher-utils": "^27.2.0", - "jest-message-util": "^27.2.0", + "jest-matcher-utils": "^27.2.4", + "jest-message-util": "^27.2.4", "jest-regex-util": "^27.0.6" }, "dependencies": { @@ -15972,6 +16296,11 @@ "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", "dev": true }, + "hamt": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/hamt/-/hamt-2.2.2.tgz", + "integrity": "sha512-4V67NW9SuDo5xqyLiSEIxITsEjOMHZB3JqS/I2ZhzWdjDx8NRJtf6lGqt8RP+nCFZDf8t+XNa5l29z4p2hUFcQ==" + }, "handlebars": { "version": "4.7.7", "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", @@ -16110,13 +16439,10 @@ } }, "import-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/import-from/-/import-from-3.0.0.tgz", - "integrity": "sha512-CiuXOFFSzkU5x/CR0+z7T91Iht4CXgfCxVOFRhh2Zyhg5wOpWvvDLQUsWl+gcN+QscYBjez8hDCt85O7RLDttQ==", - "dev": true, - "requires": { - "resolve-from": "^5.0.0" - } + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/import-from/-/import-from-4.0.0.tgz", + "integrity": "sha512-P9J71vT5nLlDeV8FHs5nNxaLbrpfAV5cF5srvbZfpwpcJoM/xZR3hiv+q+SAnuSmuGbXMWud063iIMx/V/EWZQ==", + "dev": true }, "import-lazy": { "version": "2.1.0", @@ -16215,9 +16541,9 @@ } }, "is-core-module": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.6.0.tgz", - "integrity": "sha512-wShG8vs60jKfPWpF2KZRaAtvt3a20OAn7+IJ6hLPECpSABLcKtFKTTI4ZtH5QcBruBHlq+WsdHWyz0BCZW7svQ==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.7.0.tgz", + "integrity": "sha512-ByY+tjCciCr+9nLryBYcSD50EOGWt95c7tIsKTG1J2ixKKXPvF7Ej3AVd+UfDydAJom3biBGDBALaO79ktwgEQ==", "dev": true, "requires": { "has": "^1.0.3" @@ -16242,9 +16568,9 @@ "dev": true }, "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, "requires": { "is-extglob": "^2.1.1" @@ -16390,9 +16716,9 @@ } }, "istanbul-lib-coverage": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", - "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.1.tgz", + "integrity": "sha512-GvCYYTxaCPqwMjobtVcVKvSHtAGe48MNhGjpK8LtVF8K0ISX7hCKl85LgtuaSneWVyQmaGcW3iXVV3GaZSLpmQ==", "dev": true }, "istanbul-lib-instrument": { @@ -16471,38 +16797,38 @@ "dev": true }, "jest-changed-files": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.1.1.tgz", - "integrity": "sha512-5TV9+fYlC2A6hu3qtoyGHprBwCAn0AuGA77bZdUgYvVlRMjHXo063VcWTEAyx6XAZ85DYHqp0+aHKbPlfRDRvA==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.2.4.tgz", + "integrity": "sha512-eeO1C1u4ex7pdTroYXezr+rbr957myyVoKGjcY4R1TJi3A+9v+4fu1Iv9J4eLq1bgFyT3O3iRWU9lZsEE7J72Q==", "dev": true, "requires": { - "@jest/types": "^27.1.1", + "@jest/types": "^27.2.4", "execa": "^5.0.0", "throat": "^6.0.1" } }, "jest-circus": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.2.0.tgz", - "integrity": "sha512-WwENhaZwOARB1nmcboYPSv/PwHBUGRpA4MEgszjr9DLCl97MYw0qZprBwLb7rNzvMwfIvNGG7pefQ5rxyBlzIA==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.2.4.tgz", + "integrity": "sha512-TtheheTElrGjlsY9VxkzUU1qwIx05ItIusMVKnvNkMt4o/PeegLRcjq3Db2Jz0GGdBalJdbzLZBgeulZAJxJWA==", "dev": true, "requires": { - "@jest/environment": "^27.2.0", - "@jest/test-result": "^27.2.0", - "@jest/types": "^27.1.1", + "@jest/environment": "^27.2.4", + "@jest/test-result": "^27.2.4", + "@jest/types": "^27.2.4", "@types/node": "*", "chalk": "^4.0.0", "co": "^4.6.0", "dedent": "^0.7.0", - "expect": "^27.2.0", + "expect": "^27.2.4", "is-generator-fn": "^2.0.0", - "jest-each": "^27.2.0", - "jest-matcher-utils": "^27.2.0", - "jest-message-util": "^27.2.0", - "jest-runtime": "^27.2.0", - "jest-snapshot": "^27.2.0", - "jest-util": "^27.2.0", - "pretty-format": "^27.2.0", + "jest-each": "^27.2.4", + "jest-matcher-utils": "^27.2.4", + "jest-message-util": "^27.2.4", + "jest-runtime": "^27.2.4", + "jest-snapshot": "^27.2.4", + "jest-util": "^27.2.4", + "pretty-format": "^27.2.4", "slash": "^3.0.0", "stack-utils": "^2.0.3", "throat": "^6.0.1" @@ -16560,23 +16886,23 @@ } }, "jest-cli": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.2.0.tgz", - "integrity": "sha512-bq1X/B/b1kT9y1zIFMEW3GFRX1HEhFybiqKdbxM+j11XMMYSbU9WezfyWIhrSOmPT+iODLATVjfsCnbQs7cfIA==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.2.4.tgz", + "integrity": "sha512-4kpQQkg74HYLaXo3nzwtg4PYxSLgL7puz1LXHj5Tu85KmlIpxQFjRkXlx4V47CYFFIDoyl3rHA/cXOxUWyMpNg==", "dev": true, "requires": { - "@jest/core": "^27.2.0", - "@jest/test-result": "^27.2.0", - "@jest/types": "^27.1.1", + "@jest/core": "^27.2.4", + "@jest/test-result": "^27.2.4", + "@jest/types": "^27.2.4", "chalk": "^4.0.0", "exit": "^0.1.2", "graceful-fs": "^4.2.4", "import-local": "^3.0.2", - "jest-config": "^27.2.0", - "jest-util": "^27.2.0", - "jest-validate": "^27.2.0", + "jest-config": "^27.2.4", + "jest-util": "^27.2.4", + "jest-validate": "^27.2.4", "prompts": "^2.0.1", - "yargs": "^16.0.3" + "yargs": "^16.2.0" }, "dependencies": { "ansi-styles": { @@ -16626,23 +16952,23 @@ "dev": true }, "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" + "strip-ansi": "^6.0.1" } }, "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { - "ansi-regex": "^5.0.0" + "ansi-regex": "^5.0.1" } }, "supports-color": { @@ -16678,32 +17004,32 @@ } }, "jest-config": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.2.0.tgz", - "integrity": "sha512-Z1romHpxeNwLxQtouQ4xt07bY6HSFGKTo0xJcvOK3u6uJHveA4LB2P+ty9ArBLpTh3AqqPxsyw9l9GMnWBYS9A==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.2.4.tgz", + "integrity": "sha512-tWy0UxhdzqiKyp4l5Vq4HxLyD+gH5td+GCF3c22/DJ0bYAOsMo+qi2XtbJI6oYMH5JOJQs9nLW/r34nvFCehjA==", "dev": true, "requires": { "@babel/core": "^7.1.0", - "@jest/test-sequencer": "^27.2.0", - "@jest/types": "^27.1.1", - "babel-jest": "^27.2.0", + "@jest/test-sequencer": "^27.2.4", + "@jest/types": "^27.2.4", + "babel-jest": "^27.2.4", "chalk": "^4.0.0", "deepmerge": "^4.2.2", "glob": "^7.1.1", "graceful-fs": "^4.2.4", "is-ci": "^3.0.0", - "jest-circus": "^27.2.0", - "jest-environment-jsdom": "^27.2.0", - "jest-environment-node": "^27.2.0", + "jest-circus": "^27.2.4", + "jest-environment-jsdom": "^27.2.4", + "jest-environment-node": "^27.2.4", "jest-get-type": "^27.0.6", - "jest-jasmine2": "^27.2.0", + "jest-jasmine2": "^27.2.4", "jest-regex-util": "^27.0.6", - "jest-resolve": "^27.2.0", - "jest-runner": "^27.2.0", - "jest-util": "^27.2.0", - "jest-validate": "^27.2.0", + "jest-resolve": "^27.2.4", + "jest-runner": "^27.2.4", + "jest-util": "^27.2.4", + "jest-validate": "^27.2.4", "micromatch": "^4.0.4", - "pretty-format": "^27.2.0" + "pretty-format": "^27.2.4" }, "dependencies": { "ansi-styles": { @@ -16758,15 +17084,15 @@ } }, "jest-diff": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.2.0.tgz", - "integrity": "sha512-QSO9WC6btFYWtRJ3Hac0sRrkspf7B01mGrrQEiCW6TobtViJ9RWL0EmOs/WnBsZDsI/Y2IoSHZA2x6offu0sYw==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.2.4.tgz", + "integrity": "sha512-bLAVlDSCR3gqUPGv+4nzVpEXGsHh98HjUL7Vb2hVyyuBDoQmja8eJb0imUABsuxBeUVmf47taJSAd9nDrwWKEg==", "dev": true, "requires": { "chalk": "^4.0.0", "diff-sequences": "^27.0.6", "jest-get-type": "^27.0.6", - "pretty-format": "^27.2.0" + "pretty-format": "^27.2.4" }, "dependencies": { "ansi-styles": { @@ -16830,16 +17156,16 @@ } }, "jest-each": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.2.0.tgz", - "integrity": "sha512-biDmmUQjg+HZOB7MfY2RHSFL3j418nMoC3TK3pGAj880fQQSxvQe1y2Wy23JJJNUlk6YXiGU0yWy86Le1HBPmA==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.2.4.tgz", + "integrity": "sha512-w9XVc+0EDBUTJS4xBNJ7N2JCcWItFd006lFjz77OarAQcQ10eFDBMrfDv2GBJMKlXe9aq0HrIIF51AXcZrRJyg==", "dev": true, "requires": { - "@jest/types": "^27.1.1", + "@jest/types": "^27.2.4", "chalk": "^4.0.0", "jest-get-type": "^27.0.6", - "jest-util": "^27.2.0", - "pretty-format": "^27.2.0" + "jest-util": "^27.2.4", + "pretty-format": "^27.2.4" }, "dependencies": { "ansi-styles": { @@ -16894,32 +17220,32 @@ } }, "jest-environment-jsdom": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.2.0.tgz", - "integrity": "sha512-wNQJi6Rd/AkUWqTc4gWhuTIFPo7tlMK0RPZXeM6AqRHZA3D3vwvTa9ktAktyVyWYmUoXdYstOfyYMG3w4jt7eA==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.2.4.tgz", + "integrity": "sha512-X70pTXFSypD7AIzKT1mLnDi5hP9w9mdTRcOGOmoDoBrNyNEg4rYm6d4LQWFLc9ps1VnMuDOkFSG0wjSNYGjkng==", "dev": true, "requires": { - "@jest/environment": "^27.2.0", - "@jest/fake-timers": "^27.2.0", - "@jest/types": "^27.1.1", + "@jest/environment": "^27.2.4", + "@jest/fake-timers": "^27.2.4", + "@jest/types": "^27.2.4", "@types/node": "*", - "jest-mock": "^27.1.1", - "jest-util": "^27.2.0", + "jest-mock": "^27.2.4", + "jest-util": "^27.2.4", "jsdom": "^16.6.0" } }, "jest-environment-node": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.2.0.tgz", - "integrity": "sha512-WbW+vdM4u88iy6Q3ftUEQOSgMPtSgjm3qixYYK2AKEuqmFO2zmACTw1vFUB0qI/QN88X6hA6ZkVKIdIWWzz+yg==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.2.4.tgz", + "integrity": "sha512-ZbVbFSnbzTvhLOIkqh5lcLuGCCFvtG4xTXIRPK99rV2KzQT3kNg16KZwfTnLNlIiWCE8do960eToeDfcqmpSAw==", "dev": true, "requires": { - "@jest/environment": "^27.2.0", - "@jest/fake-timers": "^27.2.0", - "@jest/types": "^27.1.1", + "@jest/environment": "^27.2.4", + "@jest/fake-timers": "^27.2.4", + "@jest/types": "^27.2.4", "@types/node": "*", - "jest-mock": "^27.1.1", - "jest-util": "^27.2.0" + "jest-mock": "^27.2.4", + "jest-util": "^27.2.4" } }, "jest-get-type": { @@ -16929,12 +17255,12 @@ "dev": true }, "jest-haste-map": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.2.0.tgz", - "integrity": "sha512-laFet7QkNlWjwZtMGHCucLvF8o9PAh2cgePRck1+uadSM4E4XH9J4gnx4do+a6do8ZV5XHNEAXEkIoNg5XUH2Q==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.2.4.tgz", + "integrity": "sha512-bkJ4bT00T2K+1NZXbRcyKnbJ42I6QBvoDNMTAQQDBhaGNnZreiQKUNqax0e6hLTx7E75pKDeltVu3V1HAdu+YA==", "dev": true, "requires": { - "@jest/types": "^27.1.1", + "@jest/types": "^27.2.4", "@types/graceful-fs": "^4.1.2", "@types/node": "*", "anymatch": "^3.0.3", @@ -16943,35 +17269,35 @@ "graceful-fs": "^4.2.4", "jest-regex-util": "^27.0.6", "jest-serializer": "^27.0.6", - "jest-util": "^27.2.0", - "jest-worker": "^27.2.0", + "jest-util": "^27.2.4", + "jest-worker": "^27.2.4", "micromatch": "^4.0.4", "walker": "^1.0.7" } }, "jest-jasmine2": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.2.0.tgz", - "integrity": "sha512-NcPzZBk6IkDW3Z2V8orGueheGJJYfT5P0zI/vTO/Jp+R9KluUdgFrgwfvZ0A34Kw6HKgiWFILZmh3oQ/eS+UxA==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.2.4.tgz", + "integrity": "sha512-fcffjO/xLWLVnW2ct3No4EksxM5RyPwHDYu9QU+90cC+/eSMLkFAxS55vkqsxexOO5zSsZ3foVpMQcg/amSeIQ==", "dev": true, "requires": { "@babel/traverse": "^7.1.0", - "@jest/environment": "^27.2.0", + "@jest/environment": "^27.2.4", "@jest/source-map": "^27.0.6", - "@jest/test-result": "^27.2.0", - "@jest/types": "^27.1.1", + "@jest/test-result": "^27.2.4", + "@jest/types": "^27.2.4", "@types/node": "*", "chalk": "^4.0.0", "co": "^4.6.0", - "expect": "^27.2.0", + "expect": "^27.2.4", "is-generator-fn": "^2.0.0", - "jest-each": "^27.2.0", - "jest-matcher-utils": "^27.2.0", - "jest-message-util": "^27.2.0", - "jest-runtime": "^27.2.0", - "jest-snapshot": "^27.2.0", - "jest-util": "^27.2.0", - "pretty-format": "^27.2.0", + "jest-each": "^27.2.4", + "jest-matcher-utils": "^27.2.4", + "jest-message-util": "^27.2.4", + "jest-runtime": "^27.2.4", + "jest-snapshot": "^27.2.4", + "jest-util": "^27.2.4", + "pretty-format": "^27.2.4", "throat": "^6.0.1" }, "dependencies": { @@ -17027,25 +17353,25 @@ } }, "jest-leak-detector": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.2.0.tgz", - "integrity": "sha512-e91BIEmbZw5+MHkB4Hnrq7S86coTxUMCkz4n7DLmQYvl9pEKmRx9H/JFH87bBqbIU5B2Ju1soKxRWX6/eGFGpA==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.2.4.tgz", + "integrity": "sha512-SrcHWbe0EHg/bw2uBjVoHacTo5xosl068x2Q0aWsjr2yYuW2XwqrSkZV4lurUop0jhv1709ymG4or+8E4sH27Q==", "dev": true, "requires": { "jest-get-type": "^27.0.6", - "pretty-format": "^27.2.0" + "pretty-format": "^27.2.4" } }, "jest-matcher-utils": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.2.0.tgz", - "integrity": "sha512-F+LG3iTwJ0gPjxBX6HCyrARFXq6jjiqhwBQeskkJQgSLeF1j6ui1RTV08SR7O51XTUhtc8zqpDj8iCG4RGmdKw==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.2.4.tgz", + "integrity": "sha512-nQeLfFAIPPkyhkDfifAPfP/U5wm1x0fLtAzqXZSSKckXDNuk2aaOfQiDYv1Mgf5GY6yOsxfUnvNm3dDjXM+BXw==", "dev": true, "requires": { "chalk": "^4.0.0", - "jest-diff": "^27.2.0", + "jest-diff": "^27.2.4", "jest-get-type": "^27.0.6", - "pretty-format": "^27.2.0" + "pretty-format": "^27.2.4" }, "dependencies": { "ansi-styles": { @@ -17100,18 +17426,18 @@ } }, "jest-message-util": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.2.0.tgz", - "integrity": "sha512-y+sfT/94CiP8rKXgwCOzO1mUazIEdEhrLjuiu+RKmCP+8O/TJTSne9dqQRbFIHBtlR2+q7cddJlWGir8UATu5w==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.2.4.tgz", + "integrity": "sha512-wbKT/BNGnBVB9nzi+IoaLkXt6fbSvqUxx+IYY66YFh96J3goY33BAaNG3uPqaw/Sh/FR9YpXGVDfd5DJdbh4nA==", "dev": true, "requires": { "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.1.1", + "@jest/types": "^27.2.4", "@types/stack-utils": "^2.0.0", "chalk": "^4.0.0", "graceful-fs": "^4.2.4", "micromatch": "^4.0.4", - "pretty-format": "^27.2.0", + "pretty-format": "^27.2.4", "slash": "^3.0.0", "stack-utils": "^2.0.3" }, @@ -17168,12 +17494,12 @@ } }, "jest-mock": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.1.1.tgz", - "integrity": "sha512-SClsFKuYBf+6SSi8jtAYOuPw8DDMsTElUWEae3zq7vDhH01ayVSIHUSIa8UgbDOUalCFp6gNsaikN0rbxN4dbw==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.2.4.tgz", + "integrity": "sha512-iVRU905rutaAoUcrt5Tm1JoHHWi24YabqEGXjPJI4tAyA6wZ7mzDi3GrZ+M7ebgWBqUkZE93GAx1STk7yCMIQA==", "dev": true, "requires": { - "@jest/types": "^27.1.1", + "@jest/types": "^27.2.4", "@types/node": "*" } }, @@ -17191,19 +17517,19 @@ "dev": true }, "jest-resolve": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.2.0.tgz", - "integrity": "sha512-v09p9Ib/VtpHM6Cz+i9lEAv1Z/M5NVxsyghRHRMEUOqwPQs3zwTdwp1xS3O/k5LocjKiGS0OTaJoBSpjbM2Jlw==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.2.4.tgz", + "integrity": "sha512-IsAO/3+3BZnKjI2I4f3835TBK/90dxR7Otgufn3mnrDFTByOSXclDi3G2XJsawGV4/18IMLARJ+V7Wm7t+J89Q==", "dev": true, "requires": { - "@jest/types": "^27.1.1", + "@jest/types": "^27.2.4", "chalk": "^4.0.0", "escalade": "^3.1.1", "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.2.0", + "jest-haste-map": "^27.2.4", "jest-pnp-resolver": "^1.2.2", - "jest-util": "^27.2.0", - "jest-validate": "^27.2.0", + "jest-util": "^27.2.4", + "jest-validate": "^27.2.4", "resolve": "^1.20.0", "slash": "^3.0.0" }, @@ -17260,42 +17586,42 @@ } }, "jest-resolve-dependencies": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.2.0.tgz", - "integrity": "sha512-EY5jc/Y0oxn+oVEEldTidmmdVoZaknKPyDORA012JUdqPyqPL+lNdRyI3pGti0RCydds6coaw6xt4JQY54dKsg==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.2.4.tgz", + "integrity": "sha512-i5s7Uh9B3Q6uwxLpMhNKlgBf6pcemvWaORxsW1zNF/YCY3jd5EftvnGBI+fxVwJ1CBxkVfxqCvm1lpZkbaoGmg==", "dev": true, "requires": { - "@jest/types": "^27.1.1", + "@jest/types": "^27.2.4", "jest-regex-util": "^27.0.6", - "jest-snapshot": "^27.2.0" + "jest-snapshot": "^27.2.4" } }, "jest-runner": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.2.0.tgz", - "integrity": "sha512-Cl+BHpduIc0cIVTjwoyx0pQk4Br8gn+wkr35PmKCmzEdOUnQ2wN7QVXA8vXnMQXSlFkN/+KWnk20TAVBmhgrww==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.2.4.tgz", + "integrity": "sha512-hIo5PPuNUyVDidZS8EetntuuJbQ+4IHWxmHgYZz9FIDbG2wcZjrP6b52uMDjAEQiHAn8yn8ynNe+TL8UuGFYKg==", "dev": true, "requires": { - "@jest/console": "^27.2.0", - "@jest/environment": "^27.2.0", - "@jest/test-result": "^27.2.0", - "@jest/transform": "^27.2.0", - "@jest/types": "^27.1.1", + "@jest/console": "^27.2.4", + "@jest/environment": "^27.2.4", + "@jest/test-result": "^27.2.4", + "@jest/transform": "^27.2.4", + "@jest/types": "^27.2.4", "@types/node": "*", "chalk": "^4.0.0", "emittery": "^0.8.1", "exit": "^0.1.2", "graceful-fs": "^4.2.4", "jest-docblock": "^27.0.6", - "jest-environment-jsdom": "^27.2.0", - "jest-environment-node": "^27.2.0", - "jest-haste-map": "^27.2.0", - "jest-leak-detector": "^27.2.0", - "jest-message-util": "^27.2.0", - "jest-resolve": "^27.2.0", - "jest-runtime": "^27.2.0", - "jest-util": "^27.2.0", - "jest-worker": "^27.2.0", + "jest-environment-jsdom": "^27.2.4", + "jest-environment-node": "^27.2.4", + "jest-haste-map": "^27.2.4", + "jest-leak-detector": "^27.2.4", + "jest-message-util": "^27.2.4", + "jest-resolve": "^27.2.4", + "jest-runtime": "^27.2.4", + "jest-util": "^27.2.4", + "jest-worker": "^27.2.4", "source-map-support": "^0.5.6", "throat": "^6.0.1" }, @@ -17352,19 +17678,19 @@ } }, "jest-runtime": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.2.0.tgz", - "integrity": "sha512-6gRE9AVVX49hgBbWQ9PcNDeM4upMUXzTpBs0kmbrjyotyUyIJixLPsYjpeTFwAA07PVLDei1iAm2chmWycdGdQ==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.2.4.tgz", + "integrity": "sha512-ICKzzYdjIi70P17MZsLLIgIQFCQmIjMFf+xYww3aUySiUA/QBPUTdUqo5B2eg4HOn9/KkUsV0z6GVgaqAPBJvg==", "dev": true, "requires": { - "@jest/console": "^27.2.0", - "@jest/environment": "^27.2.0", - "@jest/fake-timers": "^27.2.0", - "@jest/globals": "^27.2.0", + "@jest/console": "^27.2.4", + "@jest/environment": "^27.2.4", + "@jest/fake-timers": "^27.2.4", + "@jest/globals": "^27.2.4", "@jest/source-map": "^27.0.6", - "@jest/test-result": "^27.2.0", - "@jest/transform": "^27.2.0", - "@jest/types": "^27.1.1", + "@jest/test-result": "^27.2.4", + "@jest/transform": "^27.2.4", + "@jest/types": "^27.2.4", "@types/yargs": "^16.0.0", "chalk": "^4.0.0", "cjs-module-lexer": "^1.0.0", @@ -17373,17 +17699,17 @@ "exit": "^0.1.2", "glob": "^7.1.3", "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.2.0", - "jest-message-util": "^27.2.0", - "jest-mock": "^27.1.1", + "jest-haste-map": "^27.2.4", + "jest-message-util": "^27.2.4", + "jest-mock": "^27.2.4", "jest-regex-util": "^27.0.6", - "jest-resolve": "^27.2.0", - "jest-snapshot": "^27.2.0", - "jest-util": "^27.2.0", - "jest-validate": "^27.2.0", + "jest-resolve": "^27.2.4", + "jest-snapshot": "^27.2.4", + "jest-util": "^27.2.4", + "jest-validate": "^27.2.4", "slash": "^3.0.0", "strip-bom": "^4.0.0", - "yargs": "^16.0.3" + "yargs": "^16.2.0" }, "dependencies": { "ansi-styles": { @@ -17433,23 +17759,23 @@ "dev": true }, "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" + "strip-ansi": "^6.0.1" } }, "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { - "ansi-regex": "^5.0.0" + "ansi-regex": "^5.0.1" } }, "supports-color": { @@ -17495,9 +17821,9 @@ } }, "jest-snapshot": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.2.0.tgz", - "integrity": "sha512-MukJvy3KEqemCT2FoT3Gum37CQqso/62PKTfIzWmZVTsLsuyxQmJd2PI5KPcBYFqLlA8LgZLHM8ZlazkVt8LsQ==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.2.4.tgz", + "integrity": "sha512-5DFxK31rYS8X8C6WXsFx8XxrxW3PGa6+9IrUcZdTLg1aEyXDGIeiBh4jbwvh655bg/9vTETbEj/njfZicHTZZw==", "dev": true, "requires": { "@babel/core": "^7.7.2", @@ -17506,23 +17832,23 @@ "@babel/plugin-syntax-typescript": "^7.7.2", "@babel/traverse": "^7.7.2", "@babel/types": "^7.0.0", - "@jest/transform": "^27.2.0", - "@jest/types": "^27.1.1", + "@jest/transform": "^27.2.4", + "@jest/types": "^27.2.4", "@types/babel__traverse": "^7.0.4", "@types/prettier": "^2.1.5", "babel-preset-current-node-syntax": "^1.0.0", "chalk": "^4.0.0", - "expect": "^27.2.0", + "expect": "^27.2.4", "graceful-fs": "^4.2.4", - "jest-diff": "^27.2.0", + "jest-diff": "^27.2.4", "jest-get-type": "^27.0.6", - "jest-haste-map": "^27.2.0", - "jest-matcher-utils": "^27.2.0", - "jest-message-util": "^27.2.0", - "jest-resolve": "^27.2.0", - "jest-util": "^27.2.0", + "jest-haste-map": "^27.2.4", + "jest-matcher-utils": "^27.2.4", + "jest-message-util": "^27.2.4", + "jest-resolve": "^27.2.4", + "jest-util": "^27.2.4", "natural-compare": "^1.4.0", - "pretty-format": "^27.2.0", + "pretty-format": "^27.2.4", "semver": "^7.3.2" }, "dependencies": { @@ -17587,12 +17913,12 @@ } }, "jest-util": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.2.0.tgz", - "integrity": "sha512-T5ZJCNeFpqcLBpx+Hl9r9KoxBCUqeWlJ1Htli+vryigZVJ1vuLB9j35grEBASp4R13KFkV7jM52bBGnArpJN6A==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.2.4.tgz", + "integrity": "sha512-mW++4u+fSvAt3YBWm5IpbmRAceUqa2B++JlUZTiuEt2AmNYn0Yw5oay4cP17TGsMINRNPSGiJ2zNnX60g+VbFg==", "dev": true, "requires": { - "@jest/types": "^27.1.1", + "@jest/types": "^27.2.4", "@types/node": "*", "chalk": "^4.0.0", "graceful-fs": "^4.2.4", @@ -17652,17 +17978,17 @@ } }, "jest-validate": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.2.0.tgz", - "integrity": "sha512-uIEZGkFKk3+4liA81Xu0maG5aGDyPLdp+4ed244c+Ql0k3aLWQYcMbaMLXOIFcb83LPHzYzqQ8hwNnIxTqfAGQ==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.2.4.tgz", + "integrity": "sha512-VMtbxbkd7LHnIH7PChdDtrluCFRJ4b1YV2YJzNwwsASMWftq/HgqiqjvptBOWyWOtevgO3f14wPxkPcLlVBRog==", "dev": true, "requires": { - "@jest/types": "^27.1.1", + "@jest/types": "^27.2.4", "camelcase": "^6.2.0", "chalk": "^4.0.0", "jest-get-type": "^27.0.6", "leven": "^3.1.0", - "pretty-format": "^27.2.0" + "pretty-format": "^27.2.4" }, "dependencies": { "ansi-styles": { @@ -17723,17 +18049,17 @@ } }, "jest-watcher": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.2.0.tgz", - "integrity": "sha512-SjRWhnr+qO8aBsrcnYIyF+qRxNZk6MZH8TIDgvi+VlsyrvOyqg0d+Rm/v9KHiTtC9mGGeFi9BFqgavyWib6xLg==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.2.4.tgz", + "integrity": "sha512-LXC/0+dKxhK7cfF7reflRYlzDIaQE+fL4ynhKhzg8IMILNMuI4xcjXXfUJady7OR4/TZeMg7X8eHx8uan9vqaQ==", "dev": true, "requires": { - "@jest/test-result": "^27.2.0", - "@jest/types": "^27.1.1", + "@jest/test-result": "^27.2.4", + "@jest/types": "^27.2.4", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", - "jest-util": "^27.2.0", + "jest-util": "^27.2.4", "string-length": "^4.0.1" }, "dependencies": { @@ -17804,9 +18130,9 @@ } }, "jest-worker": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.2.0.tgz", - "integrity": "sha512-laB0ZVIBz+voh/QQy9dmUuuDsadixeerrKqyVpgPz+CCWiOYjOBabUXHIXZhsdvkWbLqSHbgkAHWl5cg24Q6RA==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.2.4.tgz", + "integrity": "sha512-Zq9A2Pw59KkVjBBKD1i3iE2e22oSjXhUKKuAK1HGX8flGwkm6NMozyEYzKd41hXc64dbd/0eWFeEEuxqXyhM+g==", "dev": true, "requires": { "@types/node": "*", @@ -18175,6 +18501,13 @@ "integrity": "sha1-ZHYsSGGAglGKw99Mz11YhtriA0c=", "dev": true }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", + "dev": true, + "optional": true + }, "lodash.ismatch": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz", @@ -18235,6 +18568,13 @@ "semver": "^6.0.0" } }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "optional": true + }, "makeerror": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", @@ -18245,9 +18585,9 @@ } }, "map-obj": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.2.1.tgz", - "integrity": "sha512-+WA2/1sPmDj1dlvvJmB5G6JKfY9dpn7EVBUL06+y6PoljPkh+6V1QihwxNkbcGxCRjt2b0F9K0taiCuo7MbdFQ==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", + "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", "dev": true }, "marked": { @@ -18257,15 +18597,15 @@ "dev": true }, "marked-terminal": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-4.1.1.tgz", - "integrity": "sha512-t7Mdf6T3PvOEyN01c3tYxDzhyKZ8xnkp8Rs6Fohno63L/0pFTJ5Qtwto2AQVuDtbQiWzD+4E5AAu1Z2iLc8miQ==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-4.2.0.tgz", + "integrity": "sha512-DQfNRV9svZf0Dm9Cf5x5xaVJ1+XjxQW6XjFJ5HFkVyK52SDpj5PCBzS5X5r2w9nHr3mlB0T5201UMLue9fmhUw==", "dev": true, "requires": { "ansi-escapes": "^4.3.1", "cardinal": "^2.1.1", "chalk": "^4.1.0", - "cli-table": "^0.3.1", + "cli-table3": "^0.6.0", "node-emoji": "^1.10.0", "supports-hyperlinks": "^2.1.0" }, @@ -18458,6 +18798,11 @@ "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", "dev": true }, + "nanocolors": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/nanocolors/-/nanocolors-0.2.12.tgz", + "integrity": "sha512-SFNdALvzW+rVlzqexid6epYdt8H9Zol7xDoQarioEFcFN0JHo4CYNztAxmtfgGTVRCmFlEOqqhBpoFGKqSAMug==" + }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -18486,10 +18831,37 @@ } }, "node-fetch": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.2.tgz", - "integrity": "sha512-aLoxToI6RfZ+0NOjmWAgn9+LEd30YCkJKFSyWacNZdEKTit/ZMcKjGkTRo8uWEsnIb/hfKecNPEbln02PdWbcA==", - "dev": true + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.5.tgz", + "integrity": "sha512-mmlIVHJEu5rnIxgEgez6b9GgWXbkZj5YZ7fx+2r94a2E+Uirsp6HsPTPlomfdHtpt/B0cdKviwkoaM6pyvUOpQ==", + "dev": true, + "requires": { + "whatwg-url": "^5.0.0" + }, + "dependencies": { + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", + "dev": true + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=", + "dev": true + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "dev": true, + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + } + } }, "node-int64": { "version": "0.4.0", @@ -18504,9 +18876,9 @@ "dev": true }, "node-releases": { - "version": "1.1.75", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.75.tgz", - "integrity": "sha512-Qe5OUajvqrqDSy6wrWFmMwfJ0jVgwiw4T3KqmbTcZ62qW0gQkheXYhcFM1+lOVcGUoRxcEcfyvFMAnDgaF1VWw==" + "version": "1.1.76", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.76.tgz", + "integrity": "sha512-9/IECtNr8dXNmPWmFXepT0/7o5eolGesHUa3mtr0KlgnCvnZxwh2qensKL42JJY2vQKC3nIBXetFAqR+PW1CmA==" }, "normalize-package-data": { "version": "3.0.3", @@ -18553,9 +18925,9 @@ "dev": true }, "npm": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/npm/-/npm-7.23.0.tgz", - "integrity": "sha512-m7WFTwGfiBX+jL4ObX7rIDkug/hG/Jn8vZUjKw4WS8CqMjVydHiWTARLDIll7LtHu5i7ZHBnqXZbL2S73U5p6A==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/npm/-/npm-7.24.1.tgz", + "integrity": "sha512-U7/C++ZgB3zNH/kzhSJMnp3pO2iLrZRGUUXAgCCLB/by+sR+dKVhP/ik9+sTOGk9wk3zbmwHAYDT8igkv1ss0g==", "dev": true, "requires": { "@npmcli/arborist": "*", @@ -19321,7 +19693,7 @@ } }, "glob": { - "version": "7.1.7", + "version": "7.2.0", "bundled": true, "dev": true, "requires": { @@ -19472,15 +19844,14 @@ "dev": true }, "init-package-json": { - "version": "2.0.4", + "version": "2.0.5", "bundled": true, "dev": true, "requires": { - "glob": "^7.1.1", - "npm-package-arg": "^8.1.2", + "npm-package-arg": "^8.1.5", "promzard": "^0.3.0", "read": "~1.0.1", - "read-package-json": "^4.0.0", + "read-package-json": "^4.1.1", "semver": "^7.3.5", "validate-npm-package-license": "^3.0.4", "validate-npm-package-name": "^3.0.0" @@ -19767,7 +20138,7 @@ } }, "minipass": { - "version": "3.1.3", + "version": "3.1.5", "bundled": true, "dev": true, "requires": { @@ -20358,7 +20729,7 @@ } }, "socks-proxy-agent": { - "version": "6.0.0", + "version": "6.1.0", "bundled": true, "dev": true, "requires": { @@ -20680,6 +21051,12 @@ "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", "dev": true }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -21010,13 +21387,13 @@ "dev": true }, "pretty-format": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.2.0.tgz", - "integrity": "sha512-KyJdmgBkMscLqo8A7K77omgLx5PWPiXJswtTtFV7XgVZv2+qPk6UivpXXO+5k6ZEbWIbLoKdx1pZ6ldINzbwTA==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.2.4.tgz", + "integrity": "sha512-NUjw22WJHldzxyps2YjLZkUj6q1HvjqFezkB9Y2cklN8NtVZN/kZEXGZdFw4uny3oENzV5EEMESrkI0YDUH8vg==", "dev": true, "requires": { - "@jest/types": "^27.1.1", - "ansi-regex": "^5.0.0", + "@jest/types": "^27.2.4", + "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", "react-is": "^17.0.1" }, @@ -21353,6 +21730,14 @@ "dev": true, "requires": { "tslib": "^1.9.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } } }, "safe-buffer": { @@ -21376,16 +21761,16 @@ } }, "semantic-release": { - "version": "17.4.7", - "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-17.4.7.tgz", - "integrity": "sha512-3Ghu8mKCJgCG3QzE5xphkYWM19lGE3XjFdOXQIKBM2PBpBvgFQ/lXv31oX0+fuN/UjNFO/dqhNs8ATLBhg6zBg==", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-18.0.0.tgz", + "integrity": "sha512-/Szyhq5DTZCYry/aZqpBbK/kqv10ydn6oiiaYOXtPgDbAIkqidZcQOm+mfYFJ0sBTUaOYCKMlcPMgJycP7jDYQ==", "dev": true, "requires": { - "@semantic-release/commit-analyzer": "^8.0.0", - "@semantic-release/error": "^2.2.0", - "@semantic-release/github": "^7.0.0", - "@semantic-release/npm": "^7.0.0", - "@semantic-release/release-notes-generator": "^9.0.0", + "@semantic-release/commit-analyzer": "^9.0.0", + "@semantic-release/error": "^3.0.0", + "@semantic-release/github": "^8.0.0", + "@semantic-release/npm": "^8.0.0", + "@semantic-release/release-notes-generator": "^10.0.0", "aggregate-error": "^3.0.0", "cosmiconfig": "^7.0.0", "debug": "^4.0.0", @@ -21445,23 +21830,23 @@ } }, "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" + "strip-ansi": "^6.0.1" } }, "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { - "ansi-regex": "^5.0.0" + "ansi-regex": "^5.0.1" } }, "y18n": { @@ -21529,9 +21914,9 @@ "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==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.5.tgz", + "integrity": "sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ==", "dev": true }, "signale": { @@ -21656,13 +22041,12 @@ "dev": true }, "stack-utils": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.4.tgz", - "integrity": "sha512-ERg+H//lSSYlZhBIUu+wJnqg30AbyBbpZlIhcshpn7BNzpoRODZgfyr9J+8ERf3ooC6af3u7Lcl01nleau7MrA==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", + "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", "dev": true, "requires": { - "escape-string-regexp": "^2.0.0", - "source-map-support": "^0.5.20" + "escape-string-regexp": "^2.0.0" }, "dependencies": { "escape-string-regexp": { @@ -21709,12 +22093,12 @@ }, "dependencies": { "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { - "ansi-regex": "^5.0.0" + "ansi-regex": "^5.0.1" } } } @@ -22113,11 +22497,27 @@ "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", "dev": true }, + "ts-node": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz", + "integrity": "sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==", + "dev": true, + "optional": true, + "requires": { + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.17", + "yn": "3.1.1" + } + }, "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", + "dev": true, + "optional": true }, "type-check": { "version": "0.3.2", @@ -22149,6 +22549,14 @@ "is-typedarray": "^1.0.0" } }, + "typescript": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.3.tgz", + "integrity": "sha512-4xfscpisVgqqDfPaJo5vkd+Qd/ItkoagnHpufr+i2QCHBsNYp+G7UAoyFl8aPtx879u38wPV65rZ8qbGZijalA==", + "dev": true, + "optional": true, + "peer": true + }, "uglify-js": { "version": "3.14.2", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.14.2.tgz", @@ -22255,9 +22663,9 @@ "dev": true }, "v8-to-istanbul": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.0.0.tgz", - "integrity": "sha512-LkmXi8UUNxnCC+JlH7/fsfsKr5AU110l+SYGJimWNkWhxbN5EyeOtm1MJ0hhvqMMOhGwBj1Fp70Yv9i+hX0QAg==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.0.tgz", + "integrity": "sha512-/PRhfd8aTNp9Ggr62HPzXg2XasNFGy5PBt0Rp04du7/8GNNSgxFL6WBTkgMKSL9bFjH+8kKEG3f37FmxiTqUUA==", "dev": true, "requires": { "@types/istanbul-lib-coverage": "^2.0.1", @@ -22429,23 +22837,23 @@ "dev": true }, "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" + "strip-ansi": "^6.0.1" } }, "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { - "ansi-regex": "^5.0.0" + "ansi-regex": "^5.0.1" } } } @@ -22518,9 +22926,9 @@ "dev": true }, "yargs": { - "version": "17.1.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.1.1.tgz", - "integrity": "sha512-c2k48R0PwKIqKhPMWjeiF6y2xY/gPMUlro0sgxqXpbOIohWiLNXWslsootttv7E1e73QPAMQSg5FeySbVcpsPQ==", + "version": "17.2.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.2.1.tgz", + "integrity": "sha512-XfR8du6ua4K6uLGm5S6fA+FIJom/MdJcFNVY8geLlp2v8GYbOXD4EB1tPNZsRn4vBzKGMgb5DRZMeWuFc2GO8Q==", "dev": true, "requires": { "cliui": "^7.0.2", @@ -22539,23 +22947,23 @@ "dev": true }, "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" + "strip-ansi": "^6.0.1" } }, "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { - "ansi-regex": "^5.0.0" + "ansi-regex": "^5.0.1" } }, "y18n": { @@ -22571,6 +22979,13 @@ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", "dev": true + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "optional": true } } } diff --git a/package.json b/package.json index 6347c6c..cece954 100644 --- a/package.json +++ b/package.json @@ -39,10 +39,7 @@ "test": "run jest", "jest": "jest --verbose --runInBand --no-cache ", "cd": "run clean test build release", - "release": "semantic-release --debug", - "sm": "run sm:*", - "sm:build": "fnk --src ../foo.fnk --out-dir ../ --source-maps inline --module-type 'mjs'", - "sm:view": "npx source-map-visualize ../foo.js" + "release": "semantic-release --debug" }, "devDependencies": { "@fink/cli": "^8.0.0", @@ -53,7 +50,7 @@ "cz-conventional-changelog": "^3.1.0", "jest-cli": "^27.0.0", "npx-run": "^2.1.2", - "semantic-release": "^17.2.1" + "semantic-release": "^18.0.0" }, "peerDependencies": { "@fink/js-interop": ">=2.5" @@ -62,9 +59,10 @@ "@babel/core": "^7.10.5", "@babel/traverse": "^7.10.5", "@babel/types": "^7.10.5", - "@fink/js-interop": ">=3.1.1", + "@fink/js-interop": ">=2.5", "@fink/snippet": "^2.2.0", - "@fink/std-lib": "^8.5.0" + "@fink/std-lib": "^8.5.0", + "hamt": "^2.2.2" }, "config": { "commitizen": { diff --git a/src/generate.fnk b/src/generate.fnk index eb52fb2..1e59e74 100644 --- a/src/generate.fnk +++ b/src/generate.fnk @@ -4,21 +4,27 @@ babel_traverse = import '@babel/traverse' {transformFromAstSync} = import '@babel/core' {try_catch} = import '@fink/js-interop/errors.fnk' -{transform} = import './js/transform.fnk' -{init_ctx} = import './js/init.fnk' +{transform} = import './ir/transform.fnk' +{init_ctx} = import './ir/init.fnk' +{optimize} = import './optimize/init.fnk' +{transform_ir} = import './js/init.fnk' +{module_transforms} = import './js/module/init.fnk' +{transform_async} = import './js/async/init.fnk' -{transform_do_expr} = import './js/do-expression.fnk' -{transform_async} = import './js/async.fnk' -{module_transforms} = import './js/module.fnk' -{transform_tail_call} = import './js/tail-call.fnk' +# try_catch_ = fn f: [false, f _] -transform_file = fn fink_ast, code, filename, options: - ctx = init_ctx code, filename, options +transform_file = fn fink_ast, code, filename, {optimize: optim, ...options}: + opts = {...options, optimize: {refs: true, tails: true, unused: true, ...optim}} + + ctx = init_ctx code, filename, opts [error, [js_ast]=[]] = try_catch fn: - transform fink_ast, ctx + [lir] = transform fink_ast, 'mod', ctx + [olir] = optimize lir, opts + {js} = transform_ir olir, opts + [js] extras = match options: {module_type: 'cjs'}: module_transforms @@ -27,9 +33,7 @@ transform_file = fn fink_ast, code, filename, options: match error: false: traverse js_ast, rec: - DoExpression: transform_do_expr AwaitExpression: {enter: transform_async} - ArrowFunctionExpression: {exit: transform_tail_call} ...extras {...js_ast, errors: []} @@ -63,7 +67,8 @@ generate = fn ast, filename, source, options={}: js_ast = transform_file ast, source, filename, options match js_ast: - {errors: [{}]}: + {errors: [?]}: {code: '', source_map: '', errors: js_ast.errors} else: babel_generate js_ast, filename, source, options + diff --git a/src/generate.test.fnk b/src/generate.test.fnk index 185a9cf..2edc3fe 100644 --- a/src/generate.test.fnk +++ b/src/generate.test.fnk @@ -1,8 +1,8 @@ -{describe, it, expect, to_equal, to_match_snapshot} = import '@fink/jest/test.fnk' +{skip, describe, it, expect, to_equal, to_match_snapshot} = import '@fink/jest/test.fnk' {slice} = import '@fink/std-lib/str.fnk' {generate} = import './generate.fnk' -{fink2js} = import './testing/generate.fnk' +{fink2js, fink2js_sm} = import './testing/generate.fnk' @@ -20,6 +20,7 @@ describe 'module types', fn: case = ni default = shrub + out = [dflt, if, spam, ni, foo] " it 'compiles to mjs', fn: @@ -35,6 +36,33 @@ describe 'module types', fn: +describe 'source maps', fn: + code = " + nanu = 345 + foo = {bar: 12345, 'spam ni': nanu, nanu} + bar = 'foo' + ham = 'foo: \${foo} bar:\${bar}' + el = bar {123}
+ ni = spam + foo-bar + a = [1, 'ni'] + [b, c] = a + out = [a, b, c] + func = fn x, y: + x + y + b + y = func bar, a, b + spam ham + r1 = {foo, bar, spam: 123} + " + + + it 'compiles to mjs', fn: + js = fink2js_sm code + expect + js + to_match_snapshot + + + describe 'errors', fn: it 'handles parse errors', fn: {errors: [{error}]} = fink2js ' @@ -50,7 +78,7 @@ describe 'errors', fn: Expected `,` or indented(>=1) new line or `]`. ' - it 'errors with code snippet', fn: + skip.it 'errors with code snippet', fn: {errors: [{message}]} = fink2js ' foo = bar 123 = foo diff --git a/src/generate.test.fnk.snap b/src/generate.test.fnk.snap index 62e6731..bdb9087 100644 --- a/src/generate.test.fnk.snap +++ b/src/generate.test.fnk.snap @@ -3,35 +3,108 @@ exports[`module types compiles to cjs 1`] = ` "require(\\"foobar\\"); -const foo = require(\\"shrub\\"); +const foo_0 = require(\\"shrub\\"); const { - bar: spam, - ni + bar: spam_0 } = require(\\"ni\\"); -// reserved words import const { - default: dflt, - ˆif + ni: ni_0 +} = require(\\"ni\\"); + +const { + ˆdefault: dflt_0 +} = require(\\"es6-module\\"); + +const { + ˆif: if_0 } = require(\\"es6-module\\"); -const shrub = ni; -exports.shrub = shrub; -// reserved export -const ˆcase = ni; -exports.ˆcase = ˆcase; -exports.default = shrub;" +const out_0 = [dflt_0, if_0, spam_0, ni_0, foo_0]; +module.exports = ni_0; +exports.shrub = ni_0; +exports.ˆcase = ni_0; +exports.ˆdefault = ni_0; +exports.out = out_0;" `; exports[`module types compiles to mjs 1`] = ` "import \\"foobar\\"; -import foo from \\"shrub\\"; -import { bar as spam, ni } from \\"ni\\"; -// reserved words import -import { default as dflt, ˆif } from \\"es6-module\\"; -export const shrub = ni; -// reserved export -export const ˆcase = ni; -export default shrub;" +import foo_0 from \\"shrub\\"; +import { bar as spam_0 } from \\"ni\\"; +import { ni as ni_0 } from \\"ni\\"; +import { ˆdefault as dflt_0 } from \\"es6-module\\"; +import { ˆif as if_0 } from \\"es6-module\\"; +const out_0 = [dflt_0, if_0, spam_0, ni_0, foo_0]; +export const shrub = ni_0, + ˆcase = ni_0, + ˆdefault = ni_0, + out = out_0; +export default ni_0;" +`; + +exports[`source maps compiles to mjs 1`] = ` +"const foo_0 = { + bar: 12345, + \\"spam ni\\": 345, + nanu: 345 +}; +const bar_0 = \`foo\`; +const ham_0 = \`foo: \${foo_0} bar:\${bar_0}\`; +const el_0 = bar {123}
; +const ni_0 = spam + fooᜭbar; +const item_0 = \`ni\`; +const a_0 = [1, item_0]; +const out_0 = [a_0, 1, item_0]; + +const func_0 = (x_0, y_0) => { + return x_0 + y_0 + 1; +}; + +const y_1 = func_0(bar_0, a_0, 1); +spam(ham_0); +const r1_0 = { + foo: foo_0, + bar: bar_0, + spam: 123 +}; +export const nanu = 345, + foo = foo_0, + bar = bar_0, + ham = ham_0, + el = el_0, + ni = ni_0, + a = a_0, + out = out_0, + func = func_0, + y = y_1, + r1 = r1_0; +{ + \\"version\\": 3, + \\"sources\\": [ + \\"test.fnk\\" + ], + \\"names\\": [ + \\"foo\\", + \\"bar\\", + \\"nanu\\", + \\"ham\\", + \\"el\\", + \\"div\\", + \\"spam\\", + \\"ni\\", + \\"foo-bar\\", + \\"a\\", + \\"out\\", + \\"c\\", + \\"b\\", + \\"func\\", + \\"x\\", + \\"y\\", + \\"r1\\" + ], + \\"mappings\\": \\"AACAA,MAAAA,KAAG,GAAiC;AAA7BC,EAAAA,GAA6B,EAAxB,KAAwB;AAAjB,WAAiB,EAANC,GAAM;AAAAA,EAAAA,IAAI,EAAJA;AAAA,CAApCF;AACAC,MAAAA,KAAG,GAAI,KAAPA;AACAE,MAAAA,KAAG,GAAI,QAAOH,KAAI,QAAOC,KAAG,EAA5BE;AACAC,MAAAA,IAAE,GAAG,KAAK,IAAI,KAAK,CAAC,CAACC,GAAD,CAAKL,GAAL,CAAS,KAAT,CAAaC,GAAb,CAAaA,CAAAA,KAAG,CAAhB,CAAiBK,IAAjB,CAAsBJ,KAAtB,GAAf,MAALE;AACAG,MAAAA,IAAE,GAAGD,IAAI,GAAGE,OAAZD;AACQ,MAAA,MAAI,GAAH,IAAD;AAARE,MAAAA,GAAC,GAAO,CAAH,CAAG,EAAA,MAAI,CAAZA;AAEAC,MAAAA,KAAG,GAAUC,CAANF,GAAME,EAAHC,CAAGD,EAAAA,MAAC,CAAdD;;AACAG,MAAAA,MAAI,GAAG,CAAGC,GAAH,EAAMC,GAAN;AACL,SAAAD,GAAC,GAAGC,GAAJ,GAAQH,CAAR;AADK,CAAPC;;AAEAE,MAAAA,GAAC,GAAGF,MAAI,CAACZ,KAAD,EAAMQ,GAAN,EAASG,CAAT,CAARG;AACAT,IAAI,CAACH,KAAD,CAAJ;AACAa,MAAAA,IAAE,GAAc;AAAVhB,EAAAA,GAAU,EAAVA,KAAU;AAALC,EAAAA,GAAK,EAALA,KAAK;AAAAK,EAAAA,IAAI,EAAE;AAAN,CAAhBU;aAbAd,IAAI,GAAJA,G;MACAF,GAAG,GAAHA,K;MACAC,GAAG,GAAHA,K;MACAE,GAAG,GAAHA,K;MACAC,EAAE,GAAFA,I;MACAG,EAAE,GAAFA,I;MACAE,CAAC,GAADA,G;MAEAC,GAAG,GAAHA,K;MACAG,IAAI,GAAJA,M;MAEAE,CAAC,GAADA,G;MAEAC,EAAE,GAAFA,I\\" +} +" `; diff --git a/src/ir/arithmitic/init.fnk b/src/ir/arithmitic/init.fnk new file mode 100644 index 0000000..caea89e --- /dev/null +++ b/src/ir/arithmitic/init.fnk @@ -0,0 +1,21 @@ +{add, any} = import '../context.fnk' +{transform_binary, transform_unary} = import '../transform.fnk' + + + +transform_arithmitic = fn node, res_id, ctx: + transform_binary node.op, node.left, node.right, res_id, {loc: node.loc}, ctx + + + +transform_prefix = fn node, res_id, ctx: + transform_unary node.op, node.right, res_id, {loc: node.loc}, ctx + + + +add_arithmitic = fn ctx: + pipe ctx: + add 'arithm', any, transform_arithmitic + add 'arithm:right', any, transform_arithmitic + add 'arithm:prefix', any, transform_prefix + diff --git a/src/ir/arithmitic/init.test.fnk b/src/ir/arithmitic/init.test.fnk new file mode 100644 index 0000000..a5cbe38 --- /dev/null +++ b/src/ir/arithmitic/init.test.fnk @@ -0,0 +1,44 @@ +{fink2lir} = import '../../testing/generate.fnk' +{describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' + + +describe 'binary', fn: + it 'compiles simple', fn: + expect + fink2lir ' + r = foo + bar + ' + to_match_snapshot + + + it 'compiles precedence', fn: + expect + fink2lir ' + r = (1 + 2) * ni + ' + to_match_snapshot + + + it 'compiles nested', fn: + expect + fink2lir ' + foo * bar + ni + ' + to_match_snapshot + + + +describe 'unary', fn: + it 'compiles simple', fn: + expect + fink2lir ' + -foo + ' + to_match_snapshot + + it 'compiles nested', fn: + expect + fink2lir ' + foo * -bar + ' + to_match_snapshot \ No newline at end of file diff --git a/src/ir/arithmitic/init.test.fnk.snap b/src/ir/arithmitic/init.test.fnk.snap new file mode 100644 index 0000000..6547d92 --- /dev/null +++ b/src/ir/arithmitic/init.test.fnk.snap @@ -0,0 +1,59 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`binary compiles nested 1`] = ` +" +rec_e fn exports_0: + id foo, fn left_1: + id bar, fn right_0: + mul left_1, right_0, fn left_0: + id ni, fn right_1: + add left_0, right_1, fn mex_0: + lst_e fn drctvs_0: + mod exports_0, drctvs_0, fn mod_0:" +`; + +exports[`binary compiles precedence 1`] = ` +" +rec_e fn exports_0: + int '1', fn left_1: + int '2', fn right_0: + add left_1, right_0, fn left_0: + id ni, fn right_1: + mul left_0, right_1, fn r_0: + str 'r', fn key_0: + rec_s exports_0, key_0, r_0, fn exports_1: + lst_e fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; + +exports[`binary compiles simple 1`] = ` +" +rec_e fn exports_0: + id foo, fn left_0: + id bar, fn right_0: + add left_0, right_0, fn r_0: + str 'r', fn key_0: + rec_s exports_0, key_0, r_0, fn exports_1: + lst_e fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; + +exports[`unary compiles nested 1`] = ` +" +rec_e fn exports_0: + id foo, fn left_0: + id bar, fn right_1: + sub right_1, fn right_0: + mul left_0, right_0, fn mex_0: + lst_e fn drctvs_0: + mod exports_0, drctvs_0, fn mod_0:" +`; + +exports[`unary compiles simple 1`] = ` +" +rec_e fn exports_0: + id foo, fn right_0: + sub right_0, fn mex_0: + lst_e fn drctvs_0: + mod exports_0, drctvs_0, fn mod_0:" +`; diff --git a/src/ir/assignment/init.fnk b/src/ir/assignment/init.fnk new file mode 100644 index 0000000..3a5a671 --- /dev/null +++ b/src/ir/assignment/init.fnk @@ -0,0 +1,211 @@ +{reverse} = import '@fink/std-lib/iter.fnk' + +{add, any, unique_or_id, ir_fn} = import '../context.fnk' +{transform} = import '../transform.fnk' +{members_as_rec} = import '../literals/record.fnk' +{str} = import '../literals/string.fnk' +{bind, bind_x} = import '../identifier/init.fnk' + + +lst_h = fn lst_id, name_or_id, {loc}, ctx: + ir_fn 'lst_h', [lst_id], name_or_id, {loc}, ctx + + +lst_r = fn lst_id, name_or_id, {loc}, ctx: + ir_fn 'lst_r', [lst_id], name_or_id, {loc}, ctx + + +lst_t = fn lst_id, {loc}, ctx: + ir_fn 'lst_t', [lst_id], 'tail', {loc}, ctx + + +if_v = fn val_id, true_val_id, false_val_id, name_or_id, {loc}, ctx: + ir_fn 'ifv', [val_id, true_val_id, false_val_id], name_or_id, {loc}, ctx + + +rec_g = fn rec_id, key_id, name_or_id, {loc}, ctx: + ir_fn 'rec_g', [rec_id, key_id], name_or_id, {loc}, ctx + + +rec_d = fn rec_id, keys, name_or_id, {loc}, ctx: + ir_fn 'rec_d', [rec_id, ...keys], name_or_id, {loc}, ctx + + + +rec_get = fn rec_id, key_id, val_id, fallback, {loc}, ctx: + match fallback: + false: + rec_g rec_id, key_id, val_id, {loc}, ctx + else: + [rg, tmp_id, next_ctx] = rec_g rec_id, key_id, 'hdm', {loc}, ctx + [fb, out_val_id, end_ctx] = if_v tmp_id, tmp_id, fallback, val_id, {loc}, next_ctx + [[...rg, ...fb], out_val_id, end_ctx] + + + +get_key_val = fn rec_id, expr, fallback, ctx: + [key, key_id, val_id, next_ctx] = match expr: + {left.type: 'ident', right: false}: + [val_id, key_ctx] = bind expr.left, ctx + [key, key_id, next_ctx] = str expr.left.value, 'key', expr.left, key_ctx + [key, key_id, val_id, next_ctx] + + {left.type: 'ident', right.type: 'ident'}: + [val_id, key_ctx] = bind expr.right, ctx + [key, key_id, next_ctx] = str expr.left.value, 'key', expr.left, key_ctx + [key, key_id, val_id, next_ctx] + + {right.type: 'ident'}: + [val_id, key_ctx] = bind expr.right, ctx + [key, key_id, next_ctx] = transform expr.left, 'key', key_ctx + [key, key_id, val_id, next_ctx] + + {left.type: 'ident'}: + [key, key_id, next_ctx] = str expr.left.value, 'key', expr.left, ctx + [key, key_id, 'val', next_ctx] + + else: + [key, key_id, next_ctx] = transform expr.left, 'key', ctx + [key, key_id, 'val', next_ctx] + + [val, out_val_id , end_ctx] = rec_get rec_id, key_id, val_id, fallback, expr, next_ctx + [[...key, ...val], key_id, out_val_id, end_ctx] + + + +transform_dr = fn [expr=false, ...exprs], rec_id, ctx, transform_dl, keys=[], prev=[], fallback=false: + match expr: + false: + [prev, rec_id, ctx] + + {type: 'spread'}: + [val_id, rec_ctx] = bind expr.right, ctx + [sprd, , next_ctx] = rec_d rec_id, keys, val_id, expr, rec_ctx + out = [...prev, ...sprd] + transform_dr exprs, rec_id, next_ctx, transform_dl, keys, out + + {right: false}: + [key_val, key_id, , next_ctx] = get_key_val rec_id, expr, fallback, ctx + out = [...prev, ...key_val] + transform_dr exprs, rec_id, next_ctx, transform_dl, [...keys, key_id], out + + {right.type: 'assign'}: + {left, right} = expr.right + [flbk, flbk_id, dl_ctx] = transform right, 'flbk', ctx + out = [...prev, ...flbk] + next_exprs = [{...expr, right: left}, ...exprs] + transform_dr next_exprs, rec_id, dl_ctx, transform_dl, keys, out, flbk_id + + {left.type: 'member'}: + {exprs: rx} = members_as_rec expr.left, expr.right + transform_dr [...rx, ...exprs], rec_id, ctx, transform_dl, keys, prev, fallback + + {right.type: ? in ['ident', 'empty']}: + [key_val, key_id, , next_ctx] = get_key_val rec_id, expr, fallback, ctx + out = [...prev, ...key_val] + transform_dr exprs, rec_id, next_ctx, transform_dl, [...keys, key_id], out + + {right.type: 'rec'}: + [key_val, key_id, val_id, next_ctx] = get_key_val rec_id, expr, fallback, ctx + [rec_out, , end_ctx] = transform_dr expr.right.exprs, val_id, next_ctx, transform_dl + out = [...prev, ...key_val, ...rec_out] + transform_dr exprs, rec_id, end_ctx, transform_dl, [...keys, key_id], out + + {right.type: 'list'}: + [key_val, key_id, val_id, next_ctx] = get_key_val rec_id, expr, fallback, ctx + [lst_out, , end_ctx] = transform_dl expr.right.exprs, val_id, next_ctx, [] + out = [...prev, ...key_val, ...lst_out] + transform_dr exprs, rec_id, end_ctx, transform_dl, [...keys, key_id], out + + + +head_tail = fn lst_id, val_id, {loc}, ctx, fallback=false: + [tail, tail_id, hd_ctx] = lst_t lst_id, {loc}, ctx + + [val, next_ctx] = match fallback: + false: + [hd, , next_ctx] = lst_h lst_id, val_id, {loc}, hd_ctx + [hd, next_ctx] + else: + [hd, hd_id, next_ctx] = lst_h lst_id, 'hdm', {loc}, hd_ctx + [fb, , end_ctx] = if_v hd_id, hd_id, fallback, val_id, {loc}, next_ctx + [[...hd, ...fb], end_ctx] + + [[...val, ...tail], tail_id, next_ctx] + + + +transform_dl = fn [expr=false, ...exprs], lst_id, ctx, prev=[], fallback: + match expr: + false: + [prev, lst_id, ctx] + + {type: 'ident'}: + [val_id, ht_ctx] = bind expr, ctx + [out, tail_id, next_ctx] = head_tail lst_id, val_id, expr, ht_ctx, fallback + transform_dl exprs, tail_id, next_ctx, [...prev, ...out] + + {type: 'assign'}: + {left, right} = expr + [out, flbk_id, dl_ctx] = transform right, 'flbk', ctx + transform_dl [left, ...exprs], lst_id, dl_ctx, [...prev, ...out], flbk_id + + {type: 'empty'}: + [val_id, ht_ctx] = unique_or_id 'unused', expr, ctx + [out, tail_id, next_ctx] = head_tail lst_id, val_id, expr, ht_ctx + transform_dl exprs, tail_id, next_ctx, [...prev, ...out] + + {type: 'spread'}: + [rtail, rev_id, next_ctx] = lst_r lst_id, 'rtail', expr, ctx + rev_exprs = reverse exprs + [out, tail_id, spread_ctx] = transform_dl rev_exprs, rev_id, next_ctx, [...prev, ...rtail] + + match expr.right: + false: + [out, tail_id, spread_ctx] + else: + [id, rev_ctx] = bind expr.right, spread_ctx + [rev, , next_ctx] = lst_r tail_id, id, expr, rev_ctx + [[...out, ...rev], id, next_ctx] + + {type: 'list'}: + [val_id, ht_ctx] = unique_or_id 'dlst', expr, ctx + [items, tail_id, lst_ctx] = head_tail lst_id, val_id, expr, ht_ctx, fallback + [out, , next_ctx] = transform_dl expr.exprs, val_id, lst_ctx, [] + transform_dl exprs, tail_id, next_ctx, [...prev, ...items, ...out] + + {type: 'rec'}: + [val_id, ht_ctx] = unique_or_id 'drec', expr, ctx + [items, tail_id, rec_ctx] = head_tail lst_id, val_id, expr, ht_ctx, fallback + [out, , next_ctx] = transform_dr expr.exprs, val_id, rec_ctx, transform_dl, [] + transform_dl exprs, tail_id, next_ctx, [...prev, ...items, ...out] + + + +transform_assign = fn node, , ctx: + # TODO assing right to result? + match node.left: + {type: 'list'}: + [right, r_id, next_ctx] = transform node.right, 'dlst', ctx + [left, , end_ctx] = transform_dl node.left.exprs, r_id, next_ctx + [[...right, ...left], end_ctx] + + {type: 'rec'}: + [right, r_id, next_ctx] = transform node.right, 'drec', ctx + [left, , end_ctx] = transform_dr node.left.exprs, r_id, next_ctx, transform_dl + [[...right, ...left], end_ctx] + + {type: 'ident'}: + name = node.left.value + # we have to create the id from the ident so we get correct source-maps + [l_id, r_ctx] = unique_or_id name, node.left, {...ctx, self_name: name} + [right, , {self_name: _, ...bind_ctx}] = transform node.right, l_id, r_ctx + end_ctx = bind_x node.left, l_id, bind_ctx + [right, end_ctx] + + + +add_assignment = fn ctx: + pipe ctx: + add any, '=', transform_assign + diff --git a/src/ir/assignment/init.test.fnk b/src/ir/assignment/init.test.fnk new file mode 100644 index 0000000..de05e74 --- /dev/null +++ b/src/ir/assignment/init.test.fnk @@ -0,0 +1,21 @@ +{fink2lir} = import '../../testing/generate.fnk' +{describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' + + +describe 'assignment', fn: + it 'compiles simple', fn: + expect + fink2lir ' + foo = bar + ' + to_match_snapshot + + + it 'compiles with scopes', fn: + expect + fink2lir ' + foo = 123 + ni = fn foo: + shrub + foo + ' + to_match_snapshot diff --git a/src/ir/assignment/init.test.fnk.snap b/src/ir/assignment/init.test.fnk.snap new file mode 100644 index 0000000..f45e85f --- /dev/null +++ b/src/ir/assignment/init.test.fnk.snap @@ -0,0 +1,31 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`assignment compiles simple 1`] = ` +" +rec_e fn exports_0: + id bar, fn foo_0: + str 'foo', fn key_0: + rec_s exports_0, key_0, foo_0, fn exports_1: + lst_e fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; + +exports[`assignment compiles with scopes 1`] = ` +" +rec_e fn exports_0: + int '123', fn foo_0: + str 'foo', fn key_0: + rec_s exports_0, key_0, foo_0, fn exports_1: + id (fn args_0, ret_0: #fn + lst_h args_0, fn foo_1: + lst_t args_0, fn tail_0: + id shrub, fn left_0: + id foo_1, fn right_0: + add left_0, right_0, fn result_0: + cc ret_0, result_0 + ), fn ni_0: + str 'ni', fn key_1: + rec_s exports_1, key_1, ni_0, fn exports_2: + lst_e fn drctvs_0: + mod exports_2, drctvs_0, fn mod_0:" +`; diff --git a/src/ir/async/init.fnk b/src/ir/async/init.fnk new file mode 100644 index 0000000..5272ea0 --- /dev/null +++ b/src/ir/async/init.fnk @@ -0,0 +1,21 @@ +{add, any, ir_fn} = import '../context.fnk' +{transform} = import '../transform.fnk' + + + +wt = fn future_id, res_id, {loc}, ctx: + ir_fn 'wt', [future_id], res_id, {loc}, ctx + + + +transform_await = fn node, result, ctx: + [future, future_id, next_ctx] = transform node.right, 'futr', ctx + [expr, , end_ctx] = wt future_id, result, node, next_ctx + [[...future, ...expr], end_ctx] + + + +add_async = fn ctx: + pipe ctx: + add 'await', any, transform_await + diff --git a/src/ir/async/init.test.fnk b/src/ir/async/init.test.fnk new file mode 100644 index 0000000..d3ea01a --- /dev/null +++ b/src/ir/async/init.test.fnk @@ -0,0 +1,26 @@ +{fink2lir} = import '../../testing/generate.fnk' +{describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' + + +describe 'await', fn: + it 'compiles', fn: + + expect + fink2lir ' + task1 = fn foo: -await foo + + task2 = fn foo: await (foo + 4) + + task3 = fn foo: + spam = await foo _ + bar + 123 + + a_gen = unfold fn curr=0: + match shrub: + spam: await ni curr + else: curr + 1 + + await ni + ' + to_match_snapshot + diff --git a/src/ir/async/init.test.fnk.snap b/src/ir/async/init.test.fnk.snap new file mode 100644 index 0000000..b616bbc --- /dev/null +++ b/src/ir/async/init.test.fnk.snap @@ -0,0 +1,80 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`await compiles 1`] = ` +" +rec_e fn exports_0: + id (fn args_0, ret_0: #fn + lst_h args_0, fn foo_0: + lst_t args_0, fn tail_0: + id foo_0, fn futr_0: + wt futr_0, fn right_0: + sub right_0, fn result_0: + cc ret_0, result_0 + ), fn task1_0: + str 'task1', fn key_0: + rec_s exports_0, key_0, task1_0, fn exports_1: + id (fn args_1, ret_1: #fn + lst_h args_1, fn foo_1: + lst_t args_1, fn tail_1: + id foo_1, fn left_0: + int '4', fn right_1: + add left_0, right_1, fn futr_1: + wt futr_1, fn result_1: + cc ret_1, result_1 + ), fn task2_0: + str 'task2', fn key_1: + rec_s exports_1, key_1, task2_0, fn exports_2: + id (fn args_2, ret_2: #fn + lst_h args_2, fn foo_2: + lst_t args_2, fn tail_2: + id foo_2, fn callee_0: + lst_e fn cargs_0: + af callee_0, cargs_0, fn futr_2: + wt futr_2, fn spam_0: + id bar, fn left_1: + int '123', fn right_2: + add left_1, right_2, fn result_3: + cc ret_2, result_3 + ), fn task3_0: + str 'task3', fn key_2: + rec_s exports_2, key_2, task3_0, fn exports_3: + id unfold, fn callee_1: + lst_e fn cargs_1: + id (fn args_3, ret_4: #fn + int '0', fn flbk_0: + lst_h args_3, fn hdm_0: + ifv hdm_0, hdm_0, flbk_0, fn curr_0: + lst_t args_3, fn tail_3: + id shrub, fn value_0: + id (fn ret_3: #cn + id (fn: #cn + id curr_0, fn left_2: + int '1', fn right_3: + add left_2, right_3, fn result_5: + cc ret_3, result_5 + ), fn else_0: + id spam, fn val_0: + eq value_0, val_0, fn cond_0: + id (fn: #cn + id ni, fn callee_2: + lst_e fn cargs_2: + id curr_0, fn arg_1: + lst_a cargs_2, arg_1, fn cargs_3: + af callee_2, cargs_3, fn futr_3: + wt futr_3, fn result_6: + cc ret_3, result_6 + ), fn match_res_0: + cif cond_0, match_res_0, else_0 + ), fn match_0: + ac match_0, fn result_4: + cc ret_4, result_4 + ), fn arg_0: + lst_a cargs_1, arg_0, fn cargs_4: + af callee_1, cargs_4, fn a_gen_0: + str 'a_gen', fn key_3: + rec_s exports_3, key_3, a_gen_0, fn exports_4: + id ni, fn futr_4: + wt futr_4, fn mex_0: + lst_e fn drctvs_0: + mod exports_4, drctvs_0, fn mod_0:" +`; diff --git a/src/ir/block/init.fnk b/src/ir/block/init.fnk new file mode 100644 index 0000000..d312b69 --- /dev/null +++ b/src/ir/block/init.fnk @@ -0,0 +1,29 @@ + +{add, any} = import '../context.fnk' +{transform} = import '../transform.fnk' + + + +transform_exprs = fn [expr, ...exprs], res_id, ctx, out=[]: + match exprs: + [?]: + [val, , next_ctx] = transform expr, 'blkv', ctx + transform_exprs exprs, res_id, next_ctx, [...out, ...val] + else: + [val, , next_ctx] = transform expr, res_id, ctx + [[...out, ...val], next_ctx] + + + +transform_block = fn expr, res_id, ctx: + {scopes} = ctx + block_ctx = {...ctx, scopes: [{}, ...scopes]} + [out, next_ctx] = transform_exprs expr.exprs, res_id, block_ctx + [out, {...next_ctx, scopes}] + + + +add_block = fn ctx: + pipe ctx: + add 'block', any, transform_block + diff --git a/src/ir/call/call.fnk b/src/ir/call/call.fnk new file mode 100644 index 0000000..ca28097 --- /dev/null +++ b/src/ir/call/call.fnk @@ -0,0 +1,128 @@ +{is_empty} = import '@fink/std-lib/iter.fnk' + +{unique_or_id, ir_fn} = import '../context.fnk' +{transform} = import '../transform.fnk' +{lst, lst_a, lst_c} = import '../literals/list.fnk' +{lst_h} = import '../assignment/init.fnk' +{fnc} = import '../func/init.fnk' + + + +af = fn fn_id, args_id, name_or_id, {loc}, ctx: + ir_fn 'af', [fn_id, args_id], name_or_id, {loc}, ctx + + + +prtl_func = fn prtl_arg_id, res, res_id, fn_id_or_name, {loc}, ctx: + [args_id, arg_ctx] = unique_or_id 'args', {loc}, ctx + [args, , fn_ctx] = lst_h args_id, prtl_arg_id, {loc}, arg_ctx + body = [...args, ...res] + fnc args_id, res_id, body, fn_id_or_name, {loc}, fn_ctx + + + +add_arg = fn args_id, arg, arg_id, {loc}, ctx: + [args, next_args_id, next_ctx] = lst_a args_id, arg_id, 'cargs', {loc}, ctx + [[...arg, ...args], next_args_id, next_ctx] + + + +spread_arg = fn args_id, arg, arg_id, {loc}, ctx: + [args, next_args_id, next_ctx] = lst_c args_id, arg_id, 'cargs', {loc}, ctx + [[...arg, ...args], next_args_id, next_ctx] + + + +transform_with_partial = fn expr, name, ctx: + {partial_ident: outer_prtl=false} = ctx + + [arg, arg_id, next_ctx] = match outer_prtl: + false: + transform expr, name, ctx + else: + transform expr, name, {...ctx, partial_ident: false} + + {partial_ident: arg_prtl=false} = next_ctx + + match [outer_prtl, arg_prtl]: + [false, ? != false]: + prtl_func arg_prtl, arg, arg_id, 'pfn', expr, {...next_ctx, partial_ident: false} + else: + [arg, arg_id, {...next_ctx, partial_ident: outer_prtl}] + + + +transform_arg = fn expr, args_id, ctx: + [arg, arg_id, next_ctx] = transform_with_partial expr, 'arg', ctx + add_arg args_id, arg, arg_id, expr, next_ctx + + + +transform_spread_arg = fn expr, args_id, ctx: + [arg, arg_id, next_ctx] = transform expr.right, 'sprd', ctx + spread_arg args_id, arg, arg_id, expr, next_ctx + + + +transform_partial_arg = fn expr, args_id, ctx: + [arg, arg_id, next_ctx] = transform expr, 'parg', ctx + add_arg args_id, arg, arg_id, expr, next_ctx + + + +transform_all_args = fn [expr=false, ...exprs], args_id, ctx, out=[]: + match expr: + false: + [out, args_id, ctx] + + {type: 'spread'}: + [arg, next_args_id, next_ctx] = transform_spread_arg expr, args_id, ctx + transform_all_args exprs, next_args_id, next_ctx, [...out, ...arg] + + {type: 'partial'}: + [arg, next_args_id, next_ctx] = transform_partial_arg expr, args_id, ctx + transform_all_args exprs, next_args_id, next_ctx, [...out, ...arg] + + {type: 'empty'}: + # TODO: have a transform for empty + [arg, next_args_id, next_ctx] = add_arg args_id, [], {i: '_', loc: expr.loc}, expr, ctx + transform_all_args exprs, next_args_id, next_ctx, [...out, ...arg] + + else: + [arg, next_args_id, next_ctx] = transform_arg expr, args_id, ctx + transform_all_args exprs, next_args_id, next_ctx, [...out, ...arg] + + + +transform_args = fn expr, ctx: + args = match expr.args: + # TODO should this be done in larix ? + [{type: 'empty'}, ...(is_empty ?)]: [] + else: expr.args + + [empty_args, empty_args_id, args_ctx] = lst 'cargs', expr, ctx + [out, args_id, next_ctx] = transform_all_args args, empty_args_id, args_ctx + [[...empty_args, ...out], args_id, next_ctx] + + + +transform_call = fn node, result, ctx: + {partial_ident: outer_prtl=false} = ctx + + [callee, c_id, args_ctx] = transform node.callee, 'callee', ctx + [args, args_id, next_ctx] = transform_args node, args_ctx + + {partial_ident: call_prtl=false} = next_ctx + + match [outer_prtl, call_prtl]: + [false, ? != false]: + [appl_fn, res_id, fn_ctx] = af c_id, args_id, 'pfn', node, next_ctx + call = [...callee, ...args, ...appl_fn] + [fun, , end_ctx] = prtl_func call_prtl, call, res_id, result, node, fn_ctx + [fun, {...end_ctx, partial_ident: outer_prtl}] + else: + [appl_fn, , end_ctx] = af c_id, args_id, result, node, next_ctx + call = [...callee, ...args, ...appl_fn] + [call, {...end_ctx, partial_ident: outer_prtl}] + + diff --git a/src/ir/call/call.test.fnk b/src/ir/call/call.test.fnk new file mode 100644 index 0000000..d477e8c --- /dev/null +++ b/src/ir/call/call.test.fnk @@ -0,0 +1,45 @@ +{fink2lir} = import '../../testing/generate.fnk' +{describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' + + +describe 'call', fn: + it 'compiles', fn: + expect + fink2lir ' + foo bar + foo bar, spam + foo fn bar: bar * 2 + foo _ + foo bar, , spam + foo bar, ...spam + foo ...bar + foo ...bar, spam + ' + to_match_snapshot + + + it 'compiles as partial', fn: + expect + fink2lir ' + foo ? + foo ?, 123 + foo ...? + foo ...?.bar + foo ?, ...?.bar + ? 123 + ? bar, spam + ?.bar spam + ' + to_match_snapshot + + + it 'compiles with partial args', fn: + expect + fink2lir ' + filter ? == 1 + filter ? or foo ? + filter not ? + map ?.foo + map ? % 2 == 0 + ' + to_match_snapshot diff --git a/src/ir/call/call.test.fnk.snap b/src/ir/call/call.test.fnk.snap new file mode 100644 index 0000000..cb83308 --- /dev/null +++ b/src/ir/call/call.test.fnk.snap @@ -0,0 +1,220 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`call compiles 1`] = ` +" +rec_e fn exports_0: + id foo, fn callee_0: + lst_e fn cargs_0: + id bar, fn arg_0: + lst_a cargs_0, arg_0, fn cargs_1: + af callee_0, cargs_1, fn mex_0: + id foo, fn callee_1: + lst_e fn cargs_2: + id bar, fn arg_1: + lst_a cargs_2, arg_1, fn cargs_3: + id spam, fn arg_2: + lst_a cargs_3, arg_2, fn cargs_4: + af callee_1, cargs_4, fn mex_1: + id foo, fn callee_2: + lst_e fn cargs_5: + id (fn args_0, ret_0: #fn + lst_h args_0, fn bar_0: + lst_t args_0, fn tail_0: + id bar_0, fn left_0: + int '2', fn right_0: + mul left_0, right_0, fn result_0: + cc ret_0, result_0 + ), fn arg_3: + lst_a cargs_5, arg_3, fn cargs_6: + af callee_2, cargs_6, fn mex_2: + id foo, fn callee_3: + lst_e fn cargs_7: + af callee_3, cargs_7, fn mex_3: + id foo, fn callee_4: + lst_e fn cargs_8: + id bar, fn arg_4: + lst_a cargs_8, arg_4, fn cargs_9: + lst_a cargs_9, _, fn cargs_10: + id spam, fn arg_5: + lst_a cargs_10, arg_5, fn cargs_11: + af callee_4, cargs_11, fn mex_4: + id foo, fn callee_5: + lst_e fn cargs_12: + id bar, fn arg_6: + lst_a cargs_12, arg_6, fn cargs_13: + id spam, fn sprd_0: + lst_c cargs_13, sprd_0, fn cargs_14: + af callee_5, cargs_14, fn mex_5: + id foo, fn callee_6: + lst_e fn cargs_15: + id bar, fn sprd_1: + lst_c cargs_15, sprd_1, fn cargs_16: + af callee_6, cargs_16, fn mex_6: + id foo, fn callee_7: + lst_e fn cargs_17: + id bar, fn sprd_2: + lst_c cargs_17, sprd_2, fn cargs_18: + id spam, fn arg_7: + lst_a cargs_18, arg_7, fn cargs_19: + af callee_7, cargs_19, fn mex_7: + lst_e fn drctvs_0: + mod exports_0, drctvs_0, fn mod_0:" +`; + +exports[`call compiles as partial 1`] = ` +" +rec_e fn exports_0: + id (fn args_0, ret_0: #fn + lst_h args_0, fn prtl_0: + id foo, fn callee_0: + lst_e fn cargs_0: + id prtl_0, fn parg_0: + lst_a cargs_0, parg_0, fn cargs_1: + af callee_0, cargs_1, fn pfn_0: + cc ret_0, pfn_0 + ), fn mex_0: + id (fn args_1, ret_1: #fn + lst_h args_1, fn prtl_1: + id foo, fn callee_1: + lst_e fn cargs_2: + id prtl_1, fn parg_1: + lst_a cargs_2, parg_1, fn cargs_3: + int '123', fn arg_0: + lst_a cargs_3, arg_0, fn cargs_4: + af callee_1, cargs_4, fn pfn_1: + cc ret_1, pfn_1 + ), fn mex_1: + id (fn args_2, ret_2: #fn + lst_h args_2, fn prtl_2: + id foo, fn callee_2: + lst_e fn cargs_5: + id prtl_2, fn sprd_0: + lst_c cargs_5, sprd_0, fn cargs_6: + af callee_2, cargs_6, fn pfn_2: + cc ret_2, pfn_2 + ), fn mex_2: + id (fn args_3, ret_3: #fn + lst_h args_3, fn prtl_3: + id foo, fn callee_3: + lst_e fn cargs_7: + id prtl_3, fn left_0: + str 'bar', fn key_0: + rec_g left_0, key_0, fn sprd_1: + lst_c cargs_7, sprd_1, fn cargs_8: + af callee_3, cargs_8, fn pfn_3: + cc ret_3, pfn_3 + ), fn mex_3: + id (fn args_4, ret_4: #fn + lst_h args_4, fn prtl_4: + id foo, fn callee_4: + lst_e fn cargs_9: + id prtl_4, fn parg_2: + lst_a cargs_9, parg_2, fn cargs_10: + id prtl_4, fn left_1: + str 'bar', fn key_1: + rec_g left_1, key_1, fn sprd_2: + lst_c cargs_10, sprd_2, fn cargs_11: + af callee_4, cargs_11, fn pfn_4: + cc ret_4, pfn_4 + ), fn mex_4: + id (fn args_5, ret_5: #fn + lst_h args_5, fn prtl_5: + id prtl_5, fn callee_5: + lst_e fn cargs_12: + int '123', fn arg_1: + lst_a cargs_12, arg_1, fn cargs_13: + af callee_5, cargs_13, fn pfn_5: + cc ret_5, pfn_5 + ), fn mex_5: + id (fn args_6, ret_6: #fn + lst_h args_6, fn prtl_6: + id prtl_6, fn callee_6: + lst_e fn cargs_14: + id bar, fn arg_2: + lst_a cargs_14, arg_2, fn cargs_15: + id spam, fn arg_3: + lst_a cargs_15, arg_3, fn cargs_16: + af callee_6, cargs_16, fn pfn_6: + cc ret_6, pfn_6 + ), fn mex_6: + id (fn args_7, ret_7: #fn + lst_h args_7, fn prtl_7: + id prtl_7, fn left_2: + str 'bar', fn key_2: + rec_g left_2, key_2, fn callee_7: + lst_e fn cargs_17: + id spam, fn arg_4: + lst_a cargs_17, arg_4, fn cargs_18: + af callee_7, cargs_18, fn pfn_7: + cc ret_7, pfn_7 + ), fn mex_7: + lst_e fn drctvs_0: + mod exports_0, drctvs_0, fn mod_0:" +`; + +exports[`call compiles with partial args 1`] = ` +" +rec_e fn exports_0: + id filter, fn callee_0: + lst_e fn cargs_0: + id (fn args_0, ret_0: #fn + lst_h args_0, fn prtl_0: + id prtl_0, fn left_0: + int '1', fn right_0: + eq left_0, right_0, fn arg_0: + cc ret_0, arg_0 + ), fn pfn_0: + lst_a cargs_0, pfn_0, fn cargs_1: + af callee_0, cargs_1, fn mex_0: + id filter, fn callee_1: + lst_e fn cargs_2: + id (fn args_1, ret_1: #fn + lst_h args_1, fn prtl_1: + id prtl_1, fn left_1: + id foo, fn callee_2: + lst_e fn cargs_3: + id prtl_1, fn parg_0: + lst_a cargs_3, parg_0, fn cargs_4: + af callee_2, cargs_4, fn right_1: + or left_1, right_1, fn arg_1: + cc ret_1, arg_1 + ), fn pfn_1: + lst_a cargs_2, pfn_1, fn cargs_5: + af callee_1, cargs_5, fn mex_1: + id filter, fn callee_3: + lst_e fn cargs_6: + id (fn args_2, ret_2: #fn + lst_h args_2, fn prtl_2: + id prtl_2, fn right_2: + not right_2, fn arg_2: + cc ret_2, arg_2 + ), fn pfn_2: + lst_a cargs_6, pfn_2, fn cargs_7: + af callee_3, cargs_7, fn mex_2: + id map, fn callee_4: + lst_e fn cargs_8: + id (fn args_3, ret_3: #fn + lst_h args_3, fn prtl_3: + id prtl_3, fn left_2: + str 'foo', fn key_0: + rec_g left_2, key_0, fn arg_3: + cc ret_3, arg_3 + ), fn pfn_3: + lst_a cargs_8, pfn_3, fn cargs_9: + af callee_4, cargs_9, fn mex_3: + id map, fn callee_5: + lst_e fn cargs_10: + id (fn args_4, ret_4: #fn + lst_h args_4, fn prtl_4: + id prtl_4, fn left_4: + int '2', fn right_3: + rem left_4, right_3, fn left_3: + int '0', fn right_4: + eq left_3, right_4, fn arg_4: + cc ret_4, arg_4 + ), fn pfn_4: + lst_a cargs_10, pfn_4, fn cargs_11: + af callee_5, cargs_11, fn mex_4: + lst_e fn drctvs_0: + mod exports_0, drctvs_0, fn mod_0:" +`; diff --git a/src/js/call/init.fnk b/src/ir/call/init.fnk similarity index 100% rename from src/js/call/init.fnk rename to src/ir/call/init.fnk diff --git a/src/ir/call/pipe.fnk b/src/ir/call/pipe.fnk new file mode 100644 index 0000000..19f7ac9 --- /dev/null +++ b/src/ir/call/pipe.fnk @@ -0,0 +1,48 @@ +{transform} = import '../transform.fnk' +{lst, lst_a} = import '../literals/list.fnk' +{let} = import '../identifier/init.fnk' +{transform_with_partial, af} = import './call.fnk' + + + +apply_step = fn callee_id, arg_id, {loc}, ctx: + [emp, empty_id, args_ctx] = lst 'args', {loc}, ctx + + [args, args_id, ppr_ctx] = match arg_id: + false: + [emp, empty_id, args_ctx] + else: + [with_arg, args_id, next_ctx] = lst_a empty_id, arg_id, 'args', {loc}, args_ctx + [[...emp, ...with_arg], args_id, next_ctx] + + [call, res_id, next_ctx] = af callee_id, args_id, 'ppr', {loc}, ppr_ctx + [[...args, ...call], res_id, next_ctx] + + + +pipe_all = fn [expr=false, ...exprs], prev_res_id, ctx, out=[]: + match expr: + false: + [out, prev_res_id, ctx] + + else: + [callee, callee_id, step_ctx] = transform_with_partial expr, 'pfn', ctx + {partial_ident: _, ...next_ctx} = step_ctx + [call, res_id, end_ctx] = apply_step callee_id, prev_res_id, expr, next_ctx + pipe_all exprs, res_id, end_ctx, [...out, ...callee, ...call] + + + +transform_pipe = fn expr, result, ctx: + [val, val_id, pipe_ctx] = match expr.args: + [?]: + [start_val] = expr.args + transform start_val, 'pps', ctx + else: + [[], false, ctx] + + [calls, res_id, next_ctx] = pipe_all expr.exprs, val_id, pipe_ctx + [res, , end_ctx] = let res_id, result, expr, next_ctx + [[...val, ...calls, ...res], end_ctx] + + diff --git a/src/ir/call/pipe.test.fnk b/src/ir/call/pipe.test.fnk new file mode 100644 index 0000000..f8c2809 --- /dev/null +++ b/src/ir/call/pipe.test.fnk @@ -0,0 +1,45 @@ +{fink2lir} = import '../../testing/generate.fnk' +{describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' + + + +describe 'pipe', fn: + it 'compiles no args', fn: + expect + fink2lir ' + pipe: + foo + bar spam + ' + to_match_snapshot + + + it 'compiles simple', fn: + expect + fink2lir ' + pipe [1, 2, 3]: + shrub ni + map fn item: item * 2 + ' + to_match_snapshot + + + it 'compiles with partials', fn: + expect + fink2lir ' + pipe: + bar ?, 123 + spam ni + [4, 5, ...?] + shrub ? > 1 + ' + to_match_snapshot + + expect + fink2lir ' + foo = bar fn: + pipe: + spam + ?.shrub 123 + ' + to_match_snapshot diff --git a/src/ir/call/pipe.test.fnk.snap b/src/ir/call/pipe.test.fnk.snap new file mode 100644 index 0000000..d01058c --- /dev/null +++ b/src/ir/call/pipe.test.fnk.snap @@ -0,0 +1,149 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`pipe compiles no args 1`] = ` +" +rec_e fn exports_0: + id foo, fn pfn_0: + lst_e fn args_0: + af pfn_0, args_0, fn ppr_0: + id bar, fn callee_0: + lst_e fn cargs_0: + id spam, fn arg_0: + lst_a cargs_0, arg_0, fn cargs_1: + af callee_0, cargs_1, fn pfn_1: + lst_e fn args_1: + lst_a args_1, ppr_0, fn args_2: + af pfn_1, args_2, fn ppr_1: + id ppr_1, fn mex_0: + lst_e fn drctvs_0: + mod exports_0, drctvs_0, fn mod_0:" +`; + +exports[`pipe compiles simple 1`] = ` +" +rec_e fn exports_0: + lst_e fn lst_2: + int '1', fn item_2: + lst_a lst_2, item_2, fn lst_1: + int '2', fn item_1: + lst_a lst_1, item_1, fn lst_0: + int '3', fn item_0: + lst_a lst_0, item_0, fn pps_0: + id shrub, fn callee_0: + lst_e fn cargs_0: + id ni, fn arg_0: + lst_a cargs_0, arg_0, fn cargs_1: + af callee_0, cargs_1, fn pfn_0: + lst_e fn args_0: + lst_a args_0, pps_0, fn args_1: + af pfn_0, args_1, fn ppr_0: + id map, fn callee_1: + lst_e fn cargs_2: + id (fn args_2, ret_0: #fn + lst_h args_2, fn item_3: + lst_t args_2, fn tail_0: + id item_3, fn left_0: + int '2', fn right_0: + mul left_0, right_0, fn result_0: + cc ret_0, result_0 + ), fn arg_1: + lst_a cargs_2, arg_1, fn cargs_3: + af callee_1, cargs_3, fn pfn_1: + lst_e fn args_3: + lst_a args_3, ppr_0, fn args_4: + af pfn_1, args_4, fn ppr_1: + id ppr_1, fn mex_0: + lst_e fn drctvs_0: + mod exports_0, drctvs_0, fn mod_0:" +`; + +exports[`pipe compiles with partials 1`] = ` +" +rec_e fn exports_0: + id (fn args_0, ret_0: #fn + lst_h args_0, fn prtl_0: + id bar, fn callee_0: + lst_e fn cargs_0: + id prtl_0, fn parg_0: + lst_a cargs_0, parg_0, fn cargs_1: + int '123', fn arg_0: + lst_a cargs_1, arg_0, fn cargs_2: + af callee_0, cargs_2, fn pfn_1: + cc ret_0, pfn_1 + ), fn pfn_0: + lst_e fn args_1: + af pfn_0, args_1, fn ppr_0: + id spam, fn callee_1: + lst_e fn cargs_3: + id ni, fn arg_1: + lst_a cargs_3, arg_1, fn cargs_4: + af callee_1, cargs_4, fn pfn_2: + lst_e fn args_2: + lst_a args_2, ppr_0, fn args_3: + af pfn_2, args_3, fn ppr_1: + id (fn args_4, ret_1: #fn + lst_h args_4, fn prtl_1: + lst_e fn lst_2: + int '4', fn item_1: + lst_a lst_2, item_1, fn lst_1: + int '5', fn item_0: + lst_a lst_1, item_0, fn lst_0: + id prtl_1, fn items_0: + lst_c lst_0, items_0, fn pfn_3: + cc ret_1, pfn_3 + ), fn pfn_4: + lst_e fn args_5: + lst_a args_5, ppr_1, fn args_6: + af pfn_4, args_6, fn ppr_2: + id shrub, fn callee_2: + lst_e fn cargs_5: + id (fn args_7, ret_2: #fn + lst_h args_7, fn prtl_2: + id prtl_2, fn left_0: + int '1', fn right_0: + gt left_0, right_0, fn arg_2: + cc ret_2, arg_2 + ), fn pfn_6: + lst_a cargs_5, pfn_6, fn cargs_6: + af callee_2, cargs_6, fn pfn_5: + lst_e fn args_8: + lst_a args_8, ppr_2, fn args_9: + af pfn_5, args_9, fn ppr_3: + id ppr_3, fn mex_0: + lst_e fn drctvs_0: + mod exports_0, drctvs_0, fn mod_0:" +`; + +exports[`pipe compiles with partials 2`] = ` +" +rec_e fn exports_0: + id bar, fn callee_0: + lst_e fn cargs_0: + id (fn args_0, ret_1: #fn + id spam, fn pfn_0: + lst_e fn args_1: + af pfn_0, args_1, fn ppr_0: + id (fn args_2, ret_0: #fn + lst_h args_2, fn prtl_0: + id prtl_0, fn left_0: + str 'shrub', fn key_0: + rec_g left_0, key_0, fn callee_1: + lst_e fn cargs_1: + int '123', fn arg_1: + lst_a cargs_1, arg_1, fn cargs_2: + af callee_1, cargs_2, fn pfn_2: + cc ret_0, pfn_2 + ), fn pfn_1: + lst_e fn args_3: + lst_a args_3, ppr_0, fn args_4: + af pfn_1, args_4, fn ppr_1: + id ppr_1, fn result_0: + cc ret_1, result_0 + ), fn arg_0: + lst_a cargs_0, arg_0, fn cargs_3: + af callee_0, cargs_3, fn foo_0: + str 'foo', fn key_1: + rec_s exports_0, key_1, foo_0, fn exports_1: + lst_e fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; diff --git a/src/ir/comparison/init.fnk b/src/ir/comparison/init.fnk new file mode 100644 index 0000000..43b0048 --- /dev/null +++ b/src/ir/comparison/init.fnk @@ -0,0 +1,21 @@ + +{add, any} = import '../context.fnk' +{transform_binary} = import '../transform.fnk' + + + +transform_comp = fn node, res_id, ctx: + match node: + {left.type: 'comp'}: + {left} = node + right = {...node, left: left.right} + transform_binary 'and', left, right, res_id, node, ctx + + else: + transform_binary node.op, node.left, node.right, res_id, node, ctx + + +add_comparison = fn ctx: + pipe ctx: + add 'comp', any, transform_comp + diff --git a/src/ir/comparison/init.test.fnk b/src/ir/comparison/init.test.fnk new file mode 100644 index 0000000..dc3dc15 --- /dev/null +++ b/src/ir/comparison/init.test.fnk @@ -0,0 +1,40 @@ +{fink2lir} = import '../../testing/generate.fnk' +{skip, describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' + + +describe 'comparison', fn: + it 'compiles simple', fn: + expect + fink2lir " + lt = a < b + gt = a > b + eq = a == b + neq = a != b + gteq = a >= b + lteq = a <= b + " + to_match_snapshot + + + it 'compiles combined', fn: + expect + fink2lir " + lt = a < b < c + gt = a > b > c + eq = a == b == c + neq = a != b != c + gteq = a >= b >= c + lteq = a <= b <= c + " + to_match_snapshot + + + skip.it 'compiles as partials', fn: + expect + fink2lir " + 1 == len ? + ? != 123 + ? > 3 + 1 < ? <= 3 + " + to_match_snapshot diff --git a/src/ir/comparison/init.test.fnk.snap b/src/ir/comparison/init.test.fnk.snap new file mode 100644 index 0000000..b2a7187 --- /dev/null +++ b/src/ir/comparison/init.test.fnk.snap @@ -0,0 +1,109 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`comparison compiles as partials 1`] = ` +"ˆpartial => 1 === len(ˆpartial); + +ˆpartial => ˆpartial !== 123; + +ˆpartial => ˆpartial > 3; + +ˆpartial => 1 < ˆpartial && ˆpartial <= 3;" +`; + +exports[`comparison compiles combined 1`] = ` +" +rec_e fn exports_0: + id a, fn left_1: + id b, fn right_0: + lt left_1, right_0, fn left_0: + id b, fn left_2: + id c, fn right_2: + lt left_2, right_2, fn right_1: + and left_0, right_1, fn lt_0: + str 'lt', fn key_0: + rec_s exports_0, key_0, lt_0, fn exports_1: + id a, fn left_4: + id b, fn right_3: + gt left_4, right_3, fn left_3: + id b, fn left_5: + id c, fn right_5: + gt left_5, right_5, fn right_4: + and left_3, right_4, fn gt_0: + str 'gt', fn key_1: + rec_s exports_1, key_1, gt_0, fn exports_2: + id a, fn left_7: + id b, fn right_6: + eq left_7, right_6, fn left_6: + id b, fn left_8: + id c, fn right_8: + eq left_8, right_8, fn right_7: + and left_6, right_7, fn eq_0: + str 'eq', fn key_2: + rec_s exports_2, key_2, eq_0, fn exports_3: + id a, fn left_10: + id b, fn right_9: + neq left_10, right_9, fn left_9: + id b, fn left_11: + id c, fn right_11: + neq left_11, right_11, fn right_10: + and left_9, right_10, fn neq_0: + str 'neq', fn key_3: + rec_s exports_3, key_3, neq_0, fn exports_4: + id a, fn left_13: + id b, fn right_12: + gte left_13, right_12, fn left_12: + id b, fn left_14: + id c, fn right_14: + gte left_14, right_14, fn right_13: + and left_12, right_13, fn gteq_0: + str 'gteq', fn key_4: + rec_s exports_4, key_4, gteq_0, fn exports_5: + id a, fn left_16: + id b, fn right_15: + lte left_16, right_15, fn left_15: + id b, fn left_17: + id c, fn right_17: + lte left_17, right_17, fn right_16: + and left_15, right_16, fn lteq_0: + str 'lteq', fn key_5: + rec_s exports_5, key_5, lteq_0, fn exports_6: + lst_e fn drctvs_0: + mod exports_6, drctvs_0, fn mod_0:" +`; + +exports[`comparison compiles simple 1`] = ` +" +rec_e fn exports_0: + id a, fn left_0: + id b, fn right_0: + lt left_0, right_0, fn lt_0: + str 'lt', fn key_0: + rec_s exports_0, key_0, lt_0, fn exports_1: + id a, fn left_1: + id b, fn right_1: + gt left_1, right_1, fn gt_0: + str 'gt', fn key_1: + rec_s exports_1, key_1, gt_0, fn exports_2: + id a, fn left_2: + id b, fn right_2: + eq left_2, right_2, fn eq_0: + str 'eq', fn key_2: + rec_s exports_2, key_2, eq_0, fn exports_3: + id a, fn left_3: + id b, fn right_3: + neq left_3, right_3, fn neq_0: + str 'neq', fn key_3: + rec_s exports_3, key_3, neq_0, fn exports_4: + id a, fn left_4: + id b, fn right_4: + gte left_4, right_4, fn gteq_0: + str 'gteq', fn key_4: + rec_s exports_4, key_4, gteq_0, fn exports_5: + id a, fn left_5: + id b, fn right_5: + lte left_5, right_5, fn lteq_0: + str 'lteq', fn key_5: + rec_s exports_5, key_5, lteq_0, fn exports_6: + lst_e fn drctvs_0: + mod exports_6, drctvs_0, fn mod_0:" +`; diff --git a/src/ir/conditionals/init.fnk b/src/ir/conditionals/init.fnk new file mode 100644 index 0000000..fbced63 --- /dev/null +++ b/src/ir/conditionals/init.fnk @@ -0,0 +1,8 @@ +{add, any} = import '../context.fnk' +{transform_match} = import './match.fnk' + + + +add_conditionals = fn ctx: + pipe ctx: + add any, 'match', transform_match diff --git a/src/ir/conditionals/match.fnk b/src/ir/conditionals/match.fnk new file mode 100644 index 0000000..0e67a52 --- /dev/null +++ b/src/ir/conditionals/match.fnk @@ -0,0 +1,272 @@ + +{reverse} = import '@fink/std-lib/iter.fnk' + +{transform} = import '../transform.fnk' +{unique_or_id, ir_fn, get_refs} = import '../context.fnk' +{transform_key, members_as_rec} = import '../literals/record.fnk' +{cc} = import '../func/init.fnk' + +{lst_h, lst_t, lst_r, rec_g, rec_d} = import '../assignment/init.fnk' + + + +ac = fn cont_id, name_or_id, {loc}, ctx: + ir_fn 'ac', [cont_id], name_or_id, {loc}, ctx + + +cn = fn args, body, name_or_id, {loc}, ctx: + ir_fn 'cn', [args, [...body]], name_or_id, {loc}, ctx + + +cif = fn cond_id, true_id, else_id, name_or_id, {loc}, ctx: + ir_fn 'cif', [cond_id, true_id, else_id], name_or_id, {loc}, ctx + + +is_val = fn val_id, name, {loc}, ctx: + ir_fn 'isv', [val_id], name, {loc}, ctx + + +is_l = fn val_id, name_or_id, {loc}, ctx: + ir_fn 'is_l', [val_id], name_or_id, {loc}, ctx + + +is_r = fn val_id, name_or_id, {loc}, ctx: + ir_fn 'is_r', [val_id], name_or_id, {loc}, ctx + + +is_eq = fn left_id, right_id, name_or_id, {loc}, ctx: + ir_fn '==', [left_id, right_id], name_or_id, {loc}, ctx + + + + +transform_exprs = fn [expr=false, ...rest], ctx, out, last_id: + match expr: + false: + [out, last_id, ctx] + else: + [foo, id, next_ctx] = transform expr, 'result', ctx + transform_exprs rest, next_ctx, [...out, ...foo], id + + + +ht = fn [items_id, items], expr, ctx: + [head, head_id, tail_ctx] = lst_h items_id, 'itm', expr, ctx + [tail, tail_id, next_ctx] = lst_t items_id, expr, tail_ctx + + list: + [head_id, [...items, ...head]] + [tail_id, [...tail]] + next_ctx + + + +transform_with_partial = fn expr, name, val_id, {partial_ident, ...ctx}: + [out, id, next_ctx] = transform expr, name, {...ctx, partial_ident: val_id} + [out, id, {...next_ctx, partial_ident}] + + + +match_any = fn [val_id, val], expr, gen_true, else_id, ctx: + [val_cond, cond_id, true_ctx] = is_val val_id, 'cond', expr, ctx + [true_cont, true_id, cif_ctx] = gen_true true_ctx + [if_exp, , cn_ctx] = cif cond_id, true_id, else_id, , expr, cif_ctx + + body = list: + ...val + ...val_cond + ...true_cont + ...if_exp + + cn [], body, 'match', expr, cn_ctx + + + +match_eq = fn [val_id, val], expr, gen_true, else_id, ctx: + [right, right_id, cond_ctx] = transform_with_partial expr, 'val', val_id, ctx + + left_id = match get_refs val_id, cond_ctx: + ? > 0: {i: 'true'} + else: val_id + + [eq_cond, cond_id, true_ctx] = is_eq left_id, right_id, 'cond', expr, cond_ctx + [true_cont, true_id, cif_ctx] = gen_true true_ctx + + [if_exp, , cn_ctx] = cif cond_id, true_id, else_id, , expr, cif_ctx + + + body = list: + ...val + ...right + ...eq_cond + ...true_cont + ...if_exp + + cn [], body, 'match', expr, cn_ctx + + + +match_items = fn items, [expr, ...rest], gen_true, else_id, ctx, match_expr: + match expr: + {type: 'empty'}: + # [tail_id, next_ctx] = unique_or_id 'tail', expr, ctx + [items_id, foo] = items + [lst, tail_id, next_ctx] = lst_t items_id, expr, ctx + tail = [tail_id, [...foo, ...lst]] + match_items tail, rest, gen_true, else_id, next_ctx, match_expr + + + {type: 'spread', right: false}: + [items_id, foo] = items + [lst, tail_id, next_ctx] = lst_r items_id, 'rtail', expr, ctx + tail = [tail_id, [...foo, ...lst]] + rev_rest = reverse rest + match_items tail, rev_rest, gen_true, else_id, next_ctx, match_expr + + + {type: 'spread'}: + # TODO: add support for middle spread + match_expr items, expr.right, gen_true, else_id, ctx + + else: + [item, tail, next_ctx] = ht items, expr, ctx + + match_rest = match rest: + [?]: fn ctx: + match_items tail, rest, gen_true, else_id, ctx, match_expr + else: + gen_true + + match_expr item, expr, match_rest, else_id, next_ctx + + + +match_list = fn [val_id, val_prereq], expr, gen_true, else_id, ctx, match_expr: + [lst_check, is_lst_id, items_ctx] = is_l val_id, 'is_lst', expr, ctx + + [items_match, match_id, cif_ctx] = match_items + [val_id, []], expr.exprs, gen_true, else_id, items_ctx, match_expr + + [if_exp, , cn_ctx] = cif is_lst_id, match_id, else_id, , expr, cif_ctx + + body = list: + ...val_prereq + ...lst_check + ...items_match + ...if_exp + + cn [], body, 'match_lst', expr, cn_ctx + + + +match_props = fn rec_val, [expr, ...rest], gen_true, else_id, ctx, match_expr, keys=[]: + match expr: + {type: 'spread'}: + [rec_id, val] = rec_val + [sprd, val_id, next_ctx] = rec_d rec_id, keys, 'spread', expr, ctx + match_expr [val_id, [...val, ...sprd]], expr.right, gen_true, else_id, next_ctx + + + {type: 'rec:kv', left.type: 'member'}: + {exprs} = members_as_rec expr.left, expr.right + match_props rec_val, [...exprs, ...rest], gen_true, else_id, ctx, match_expr, keys + + + {type: 'rec:kv'}: + [rec_id, val] = rec_val + [key, key_id, rec_ctx] = transform_key expr.left, ctx + [item, item_id, next_ctx] = rec_g rec_id, key_id, 'itm', expr, rec_ctx + + val_expr = match expr: + {right: false}: expr.left + else: expr.right + + match_rest = match rest: + [?]: fn ctx: + match_props [rec_id, []], rest, gen_true, else_id, ctx, match_expr, [...keys, key_id] + else: + gen_true + + match_expr [item_id, [...val, ...key, ...item]], val_expr, match_rest, else_id, next_ctx + + + +match_rec = fn [val_id, val_prereq], expr, gen_true, else_id, ctx, match_expr: + [rec_check, is_rec_id, match_ctx] = is_r val_id, 'is_rec', expr, ctx + + [props_match, match_id, cif_ctx] = match_props + [val_id, []], expr.exprs, gen_true, else_id, match_ctx, match_expr + + [if_exp, , cn_ctx] = cif is_rec_id, match_id, else_id, , expr, cif_ctx + + body = list: + ...val_prereq + ...rec_check + ...props_match + ...if_exp + + cn [], body, 'match_rec', expr, cn_ctx + + + +match_expr = fn val, expr, gen_true, else_id, ctx: + mx = match_expr + match expr: + {type: 'list'}: + match_list val, expr, gen_true, else_id, ctx, mx + + {type: 'rec'}: + match_rec val, expr, gen_true, else_id, ctx, mx + + {type: 'partial'}: + match_any val, expr, gen_true, else_id, ctx + + else: + match_eq val, expr, gen_true, else_id, ctx + + + +match_res_exprs = fn exprs, name, ret_id, {loc}, ctx: + {scopes} = ctx + cond_ctx = {...ctx, scopes: [{}, ...scopes]} + [block, res_id, ret_ctx] = transform_exprs exprs, cond_ctx, [] + [ret, , next_ctx] = cc ret_id, res_id, , {loc}, ret_ctx + [a, b, todo] = cn [], [...block, ...ret], name, {loc}, next_ctx + [a, b, {...todo, scopes}] + + + +match_conditions = fn [expr=false, ...else_exprs], [val_id, val], ret_id, ctx: + match expr: + false: + match_res_exprs [], 'else', ret_id, {todo: 'loc'}, ctx + + {op: 'else'}: + match_res_exprs expr.exprs, 'else', ret_id, {loc: expr.loc}, ctx + + else: + {left, right: true_expr} = expr + + gen_true = fn ctx: + match_res_exprs true_expr.exprs, 'match_res', ret_id, true_expr, ctx + + [el, else_id, next_ctx] = match_conditions else_exprs, [val_id, []], ret_id, ctx + + match_expr [val_id, [...val, ...el]], left, gen_true, else_id, next_ctx + + + +transform_match = fn node, result, ctx: + [ret_id, v_ctx] = unique_or_id 'ret', node, ctx + + [input] = node.args + [value, val_id, cond_ctx] = transform input, 'value', v_ctx + exprs = node.exprs + [[[{args: [, conds]}]], match_id, next_ctx] = match_conditions exprs, [val_id, []], ret_id, cond_ctx + + [cont, , ac_ctx] = cn [ret_id], conds, match_id, node, next_ctx + [acont, , end_ctx] = ac match_id, result, node, ac_ctx + + out = [...value, ...cont, ...acont] + [out, end_ctx] + diff --git a/src/ir/conditionals/match.test.fnk b/src/ir/conditionals/match.test.fnk new file mode 100644 index 0000000..b9a27a9 --- /dev/null +++ b/src/ir/conditionals/match.test.fnk @@ -0,0 +1,234 @@ +{fink2lir} = import '../../testing/generate.fnk' +{skip, describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' + + +describe 'match', fn: + it 'matches simple values', fn: + expect + fink2lir ' + match shrub: + 123: spam + 456: ni + else: shrub + ' + to_match_snapshot + + it 'compiles without else', fn: + expect + fink2lir ' + match shrub: + 123: spam + ' + to_match_snapshot + + + it 'matches value assertions', fn: + expect + fink2lir ' + match 123: + # simple unary + not ?: ni + + # simple binary + ? > 123: ni + + # simple call + ? _: ni + + # simple as call arg + shrub ?: ni + + # any value + ?: true + ' + to_match_snapshot + + + it 'compiles nested match', fn: + expect + fink2lir ' + match foo: + bar: + match spam: + shrub: ni + ' + to_match_snapshot + + + +describe 'match iterables', fn: + it 'matches values', fn: + expect + fink2lir ' + match foo: + [1, 2]: ni + [3, 4, ni]: ni + else: foo + ' + to_match_snapshot + + it 'matches nested tuples', fn: + expect + fink2lir ' + match shrub: + [3, 4, [ni]]: ni + [1, [2, 3]]: [ni, ni] + ' + to_match_snapshot + + + skip.it 'matches empty tuples', fn: + expect + fink2lir ' + match shrub: + []: foo + [1, 2, []]: foo + ' + to_match_snapshot + + + it 'matches ignored items', fn: + expect + fink2lir ' + match foo: + [1, , 2]: ni + else: foo + ' + to_match_snapshot + + + it 'matches complex values', fn: + expect + fink2lir ' + match shrub: + # deep iterable comparison + [3, 4, [ni]]: ni + # TODO: fix semantics for matching [], {} + # [5, 6, [], {}]: foo + [1, [2, 3], 4]: bar + [1, [2, [3, 4]], [5, 6], 7]: spam + ' + to_match_snapshot + + + it 'matches spread', fn: + expect + fink2lir ' + match shrub: + [1, ..., 3]: foo + [..., 4]: foo + ' + to_match_snapshot + + + it 'matches value assertions', fn: + expect + fink2lir ' + match foo: + # nested unary + [not ?]: ni + + # any value + [?]: true + + # nested binary + [? > 123]: ni + + # nested call + [? _]: ni + + # nested member call + [?.is_foo _]: ni + + # nested as call arg + [is_foo ?, bar]: ni + + [1, ...is_empty ?]: ni + [1, ...(1 < length ?)]: ni + ' + to_match_snapshot + + + +describe 'match records', fn: + it 'matches props', fn: + expect + fink2lir " + match shrub: + {foo, bar}: ni + # TODO: fix semantics for matching {} + # {foo: {}}: spam + ni + # TODO: fix semantics for matching [] + # {foo: []}: spam + ni + {foo: 4, ni: {na, nu}}: spam + ni + {foo: 1, foo: {bar: 'spam'}, shrub: {na: 'nu'}}: ni + {ni: {len: 1}, na: {len: 1}}: na + {ni: [na, 123]}: na + " + to_match_snapshot + + + it 'matches calculated props', fn: + expect + fink2lir ' + match shrub: + # calculated props + {(a): {b, c}}: ni + ' + to_match_snapshot + + + it 'matches spread', fn: + expect + fink2lir ' + match shrub: + # spread + {(foo): {x}, ...{bar, spam}}: ni + ' + to_match_snapshot + + + it 'matches member expr keys', fn: + expect + fink2lir ' + match foo: + {foo.bar.spam: ham}: spam + ' + to_match_snapshot + + expect + fink2lir ' + match foo: + {foo.bar.spam: {ham.ni: nu}}: spam + ' + to_match_snapshot + + + it 'matches value assertions', fn: + expect + fink2lir ' + match foo: + # nested unary + {spam: not ?}: ni + + # nested binary + {spam: ? > 123}: ni + + # nested call + {spam: ? _}: ni + + # nested member call + {spam: ?.is_foo _}: ni + + # nested as call arg + {spam: is_foo ?}: ni + + {spam, ...is_empty ?}: ni + {spam, ...("foo" in ?)}: ni + + # any value + {spam: ?}: true + ' + to_match_snapshot + + diff --git a/src/ir/conditionals/match.test.fnk.snap b/src/ir/conditionals/match.test.fnk.snap new file mode 100644 index 0000000..a9a7918 --- /dev/null +++ b/src/ir/conditionals/match.test.fnk.snap @@ -0,0 +1,1216 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`match compiles nested match 1`] = ` +" +rec_e fn exports_0: + id foo, fn value_0: + id (fn ret_0: #cn + id (fn: #cn + cc ret_0 + ), fn else_0: + id bar, fn val_0: + eq value_0, val_0, fn cond_0: + id (fn: #cn + id spam, fn value_1: + id (fn ret_1: #cn + id (fn: #cn + cc ret_1 + ), fn else_1: + id shrub, fn val_1: + eq value_1, val_1, fn cond_1: + id (fn: #cn + id ni, fn result_1: + cc ret_1, result_1 + ), fn match_res_0: + cif cond_1, match_res_0, else_1 + ), fn match_0: + ac match_0, fn result_0: + cc ret_0, result_0 + ), fn match_res_1: + cif cond_0, match_res_1, else_0 + ), fn match_1: + ac match_1, fn mex_0: + lst_e fn drctvs_0: + mod exports_0, drctvs_0, fn mod_0:" +`; + +exports[`match compiles without else 1`] = ` +" +rec_e fn exports_0: + id shrub, fn value_0: + id (fn ret_0: #cn + id (fn: #cn + cc ret_0 + ), fn else_0: + int '123', fn val_0: + eq value_0, val_0, fn cond_0: + id (fn: #cn + id spam, fn result_0: + cc ret_0, result_0 + ), fn match_res_0: + cif cond_0, match_res_0, else_0 + ), fn match_0: + ac match_0, fn mex_0: + lst_e fn drctvs_0: + mod exports_0, drctvs_0, fn mod_0:" +`; + +exports[`match iterables matches complex values 1`] = ` +" +rec_e fn exports_0: + id shrub, fn value_0: + id (fn ret_0: #cn + id (fn: #cn + id (fn: #cn + id (fn: #cn + cc ret_0 + ), fn else_0: + is_l value_0, fn is_lst_0: + id (fn: #cn + lst_h value_0, fn itm_0: + int '1', fn val_0: + eq itm_0, val_0, fn cond_0: + id (fn: #cn + lst_t value_0, fn tail_0: + lst_h tail_0, fn itm_1: + is_l itm_1, fn is_lst_1: + id (fn: #cn + lst_h itm_1, fn itm_2: + int '2', fn val_1: + eq itm_2, val_1, fn cond_1: + id (fn: #cn + lst_t itm_1, fn tail_2: + lst_h tail_2, fn itm_3: + is_l itm_3, fn is_lst_2: + id (fn: #cn + lst_h itm_3, fn itm_4: + int '3', fn val_2: + eq itm_4, val_2, fn cond_2: + id (fn: #cn + lst_t itm_3, fn tail_4: + lst_h tail_4, fn itm_5: + int '4', fn val_3: + eq itm_5, val_3, fn cond_3: + id (fn: #cn + lst_t tail_0, fn tail_1: + lst_h tail_1, fn itm_6: + is_l itm_6, fn is_lst_3: + id (fn: #cn + lst_h itm_6, fn itm_7: + int '5', fn val_4: + eq itm_7, val_4, fn cond_4: + id (fn: #cn + lst_t itm_6, fn tail_7: + lst_h tail_7, fn itm_8: + int '6', fn val_5: + eq itm_8, val_5, fn cond_5: + id (fn: #cn + lst_t tail_1, fn tail_6: + lst_h tail_6, fn itm_9: + int '7', fn val_6: + eq itm_9, val_6, fn cond_6: + id (fn: #cn + id spam, fn result_0: + cc ret_0, result_0 + ), fn match_res_0: + cif cond_6, match_res_0, else_0 + ), fn match_0: + cif cond_5, match_0, else_0 + ), fn match_1: + cif cond_4, match_1, else_0 + ), fn match_2: + cif is_lst_3, match_2, else_0 + ), fn match_lst_0: + cif cond_3, match_lst_0, else_0 + ), fn match_3: + cif cond_2, match_3, else_0 + ), fn match_4: + cif is_lst_2, match_4, else_0 + ), fn match_lst_1: + cif cond_1, match_lst_1, else_0 + ), fn match_5: + cif is_lst_1, match_5, else_0 + ), fn match_lst_2: + cif cond_0, match_lst_2, else_0 + ), fn match_6: + cif is_lst_0, match_6, else_0 + ), fn match_lst_3: + is_l value_0, fn is_lst_4: + id (fn: #cn + lst_h value_0, fn itm_10: + int '1', fn val_7: + eq itm_10, val_7, fn cond_7: + id (fn: #cn + lst_t value_0, fn tail_10: + lst_h tail_10, fn itm_11: + is_l itm_11, fn is_lst_5: + id (fn: #cn + lst_h itm_11, fn itm_12: + int '2', fn val_8: + eq itm_12, val_8, fn cond_8: + id (fn: #cn + lst_t itm_11, fn tail_12: + lst_h tail_12, fn itm_13: + int '3', fn val_9: + eq itm_13, val_9, fn cond_9: + id (fn: #cn + lst_t tail_10, fn tail_11: + lst_h tail_11, fn itm_14: + int '4', fn val_10: + eq itm_14, val_10, fn cond_10: + id (fn: #cn + id bar, fn result_1: + cc ret_0, result_1 + ), fn match_res_1: + cif cond_10, match_res_1, match_lst_3 + ), fn match_7: + cif cond_9, match_7, match_lst_3 + ), fn match_8: + cif cond_8, match_8, match_lst_3 + ), fn match_9: + cif is_lst_5, match_9, match_lst_3 + ), fn match_lst_4: + cif cond_7, match_lst_4, match_lst_3 + ), fn match_10: + cif is_lst_4, match_10, match_lst_3 + ), fn match_lst_5: + is_l value_0, fn is_lst_6: + id (fn: #cn + lst_h value_0, fn itm_15: + int '3', fn val_11: + eq itm_15, val_11, fn cond_11: + id (fn: #cn + lst_t value_0, fn tail_15: + lst_h tail_15, fn itm_16: + int '4', fn val_12: + eq itm_16, val_12, fn cond_12: + id (fn: #cn + lst_t tail_15, fn tail_16: + lst_h tail_16, fn itm_17: + is_l itm_17, fn is_lst_7: + id (fn: #cn + lst_h itm_17, fn itm_18: + id ni, fn val_13: + eq itm_18, val_13, fn cond_13: + id (fn: #cn + id ni, fn result_2: + cc ret_0, result_2 + ), fn match_res_2: + cif cond_13, match_res_2, match_lst_5 + ), fn match_11: + cif is_lst_7, match_11, match_lst_5 + ), fn match_lst_6: + cif cond_12, match_lst_6, match_lst_5 + ), fn match_12: + cif cond_11, match_12, match_lst_5 + ), fn match_13: + cif is_lst_6, match_13, match_lst_5 + ), fn match_lst_7: + ac match_lst_7, fn mex_0: + lst_e fn drctvs_0: + mod exports_0, drctvs_0, fn mod_0:" +`; + +exports[`match iterables matches ignored items 1`] = ` +" +rec_e fn exports_0: + id foo, fn value_0: + id (fn ret_0: #cn + id (fn: #cn + id foo, fn result_0: + cc ret_0, result_0 + ), fn else_0: + is_l value_0, fn is_lst_0: + id (fn: #cn + lst_h value_0, fn itm_0: + int '1', fn val_0: + eq itm_0, val_0, fn cond_0: + id (fn: #cn + lst_t value_0, fn tail_0: + lst_t tail_0, fn tail_1: + lst_h tail_1, fn itm_1: + int '2', fn val_1: + eq itm_1, val_1, fn cond_1: + id (fn: #cn + id ni, fn result_1: + cc ret_0, result_1 + ), fn match_res_0: + cif cond_1, match_res_0, else_0 + ), fn match_0: + cif cond_0, match_0, else_0 + ), fn match_1: + cif is_lst_0, match_1, else_0 + ), fn match_lst_0: + ac match_lst_0, fn mex_0: + lst_e fn drctvs_0: + mod exports_0, drctvs_0, fn mod_0:" +`; + +exports[`match iterables matches nested tuples 1`] = ` +" +rec_e fn exports_0: + id shrub, fn value_0: + id (fn ret_0: #cn + id (fn: #cn + id (fn: #cn + cc ret_0 + ), fn else_0: + is_l value_0, fn is_lst_0: + id (fn: #cn + lst_h value_0, fn itm_0: + int '1', fn val_0: + eq itm_0, val_0, fn cond_0: + id (fn: #cn + lst_t value_0, fn tail_0: + lst_h tail_0, fn itm_1: + is_l itm_1, fn is_lst_1: + id (fn: #cn + lst_h itm_1, fn itm_2: + int '2', fn val_1: + eq itm_2, val_1, fn cond_1: + id (fn: #cn + lst_t itm_1, fn tail_2: + lst_h tail_2, fn itm_3: + int '3', fn val_2: + eq itm_3, val_2, fn cond_2: + id (fn: #cn + lst_e fn lst_1: + id ni, fn item_1: + lst_a lst_1, item_1, fn lst_0: + id ni, fn item_0: + lst_a lst_0, item_0, fn result_0: + cc ret_0, result_0 + ), fn match_res_0: + cif cond_2, match_res_0, else_0 + ), fn match_0: + cif cond_1, match_0, else_0 + ), fn match_1: + cif is_lst_1, match_1, else_0 + ), fn match_lst_0: + cif cond_0, match_lst_0, else_0 + ), fn match_2: + cif is_lst_0, match_2, else_0 + ), fn match_lst_1: + is_l value_0, fn is_lst_2: + id (fn: #cn + lst_h value_0, fn itm_4: + int '3', fn val_3: + eq itm_4, val_3, fn cond_3: + id (fn: #cn + lst_t value_0, fn tail_4: + lst_h tail_4, fn itm_5: + int '4', fn val_4: + eq itm_5, val_4, fn cond_4: + id (fn: #cn + lst_t tail_4, fn tail_5: + lst_h tail_5, fn itm_6: + is_l itm_6, fn is_lst_3: + id (fn: #cn + lst_h itm_6, fn itm_7: + id ni, fn val_5: + eq itm_7, val_5, fn cond_5: + id (fn: #cn + id ni, fn result_1: + cc ret_0, result_1 + ), fn match_res_1: + cif cond_5, match_res_1, match_lst_1 + ), fn match_3: + cif is_lst_3, match_3, match_lst_1 + ), fn match_lst_2: + cif cond_4, match_lst_2, match_lst_1 + ), fn match_4: + cif cond_3, match_4, match_lst_1 + ), fn match_5: + cif is_lst_2, match_5, match_lst_1 + ), fn match_lst_3: + ac match_lst_3, fn mex_0: + lst_e fn drctvs_0: + mod exports_0, drctvs_0, fn mod_0:" +`; + +exports[`match iterables matches spread 1`] = ` +" +rec_e fn exports_0: + id shrub, fn value_0: + id (fn ret_0: #cn + id (fn: #cn + id (fn: #cn + cc ret_0 + ), fn else_0: + is_l value_0, fn is_lst_0: + id (fn: #cn + lst_r value_0, fn rtail_0: + lst_h rtail_0, fn itm_0: + int '4', fn val_0: + eq itm_0, val_0, fn cond_0: + id (fn: #cn + id foo, fn result_0: + cc ret_0, result_0 + ), fn match_res_0: + cif cond_0, match_res_0, else_0 + ), fn match_0: + cif is_lst_0, match_0, else_0 + ), fn match_lst_0: + is_l value_0, fn is_lst_1: + id (fn: #cn + lst_h value_0, fn itm_1: + int '1', fn val_1: + eq itm_1, val_1, fn cond_1: + id (fn: #cn + lst_t value_0, fn tail_1: + lst_r tail_1, fn rtail_1: + lst_h rtail_1, fn itm_2: + int '3', fn val_2: + eq itm_2, val_2, fn cond_2: + id (fn: #cn + id foo, fn result_1: + cc ret_0, result_1 + ), fn match_res_1: + cif cond_2, match_res_1, match_lst_0 + ), fn match_1: + cif cond_1, match_1, match_lst_0 + ), fn match_2: + cif is_lst_1, match_2, match_lst_0 + ), fn match_lst_1: + ac match_lst_1, fn mex_0: + lst_e fn drctvs_0: + mod exports_0, drctvs_0, fn mod_0:" +`; + +exports[`match iterables matches value assertions 1`] = ` +" +rec_e fn exports_0: + id foo, fn value_0: + id (fn ret_0: #cn + id (fn: #cn + id (fn: #cn + id (fn: #cn + id (fn: #cn + id (fn: #cn + id (fn: #cn + id (fn: #cn + id (fn: #cn + cc ret_0 + ), fn else_0: + is_l value_0, fn is_lst_0: + id (fn: #cn + lst_h value_0, fn itm_0: + int '1', fn val_0: + eq itm_0, val_0, fn cond_0: + id (fn: #cn + lst_t value_0, fn tail_0: + int '1', fn left_0: + id length, fn callee_0: + lst_e fn cargs_0: + id tail_0, fn parg_0: + lst_a cargs_0, parg_0, fn cargs_1: + af callee_0, cargs_1, fn right_0: + lt left_0, right_0, fn val_1: + eq true, val_1, fn cond_1: + id (fn: #cn + id ni, fn result_0: + cc ret_0, result_0 + ), fn match_res_0: + cif cond_1, match_res_0, else_0 + ), fn match_0: + cif cond_0, match_0, else_0 + ), fn match_1: + cif is_lst_0, match_1, else_0 + ), fn match_lst_0: + is_l value_0, fn is_lst_1: + id (fn: #cn + lst_h value_0, fn itm_1: + int '1', fn val_2: + eq itm_1, val_2, fn cond_2: + id (fn: #cn + lst_t value_0, fn tail_1: + id is_empty, fn callee_1: + lst_e fn cargs_2: + id tail_1, fn parg_1: + lst_a cargs_2, parg_1, fn cargs_3: + af callee_1, cargs_3, fn val_3: + eq true, val_3, fn cond_3: + id (fn: #cn + id ni, fn result_1: + cc ret_0, result_1 + ), fn match_res_1: + cif cond_3, match_res_1, match_lst_0 + ), fn match_2: + cif cond_2, match_2, match_lst_0 + ), fn match_3: + cif is_lst_1, match_3, match_lst_0 + ), fn match_lst_1: + is_l value_0, fn is_lst_2: + id (fn: #cn + lst_h value_0, fn itm_2: + id is_foo, fn callee_2: + lst_e fn cargs_4: + id itm_2, fn parg_2: + lst_a cargs_4, parg_2, fn cargs_5: + id bar, fn arg_0: + lst_a cargs_5, arg_0, fn cargs_6: + af callee_2, cargs_6, fn val_4: + eq true, val_4, fn cond_4: + id (fn: #cn + id ni, fn result_2: + cc ret_0, result_2 + ), fn match_res_2: + cif cond_4, match_res_2, match_lst_1 + ), fn match_4: + cif is_lst_2, match_4, match_lst_1 + ), fn match_lst_2: + is_l value_0, fn is_lst_3: + id (fn: #cn + lst_h value_0, fn itm_3: + id itm_3, fn left_1: + str 'is_foo', fn key_0: + rec_g left_1, key_0, fn callee_3: + lst_e fn cargs_7: + af callee_3, cargs_7, fn val_5: + eq true, val_5, fn cond_5: + id (fn: #cn + id ni, fn result_3: + cc ret_0, result_3 + ), fn match_res_3: + cif cond_5, match_res_3, match_lst_2 + ), fn match_5: + cif is_lst_3, match_5, match_lst_2 + ), fn match_lst_3: + is_l value_0, fn is_lst_4: + id (fn: #cn + lst_h value_0, fn itm_4: + id itm_4, fn callee_4: + lst_e fn cargs_8: + af callee_4, cargs_8, fn val_6: + eq true, val_6, fn cond_6: + id (fn: #cn + id ni, fn result_4: + cc ret_0, result_4 + ), fn match_res_4: + cif cond_6, match_res_4, match_lst_3 + ), fn match_6: + cif is_lst_4, match_6, match_lst_3 + ), fn match_lst_4: + is_l value_0, fn is_lst_5: + id (fn: #cn + lst_h value_0, fn itm_5: + id itm_5, fn left_2: + int '123', fn right_1: + gt left_2, right_1, fn val_7: + eq true, val_7, fn cond_7: + id (fn: #cn + id ni, fn result_5: + cc ret_0, result_5 + ), fn match_res_5: + cif cond_7, match_res_5, match_lst_4 + ), fn match_7: + cif is_lst_5, match_7, match_lst_4 + ), fn match_lst_5: + is_l value_0, fn is_lst_6: + id (fn: #cn + lst_h value_0, fn itm_6: + isv itm_6, fn cond_8: + id (fn: #cn + id true, fn result_6: + cc ret_0, result_6 + ), fn match_res_6: + cif cond_8, match_res_6, match_lst_5 + ), fn match_8: + cif is_lst_6, match_8, match_lst_5 + ), fn match_lst_6: + is_l value_0, fn is_lst_7: + id (fn: #cn + lst_h value_0, fn itm_7: + id itm_7, fn right_2: + not right_2, fn val_8: + eq true, val_8, fn cond_9: + id (fn: #cn + id ni, fn result_7: + cc ret_0, result_7 + ), fn match_res_7: + cif cond_9, match_res_7, match_lst_6 + ), fn match_9: + cif is_lst_7, match_9, match_lst_6 + ), fn match_lst_7: + ac match_lst_7, fn mex_0: + lst_e fn drctvs_0: + mod exports_0, drctvs_0, fn mod_0:" +`; + +exports[`match iterables matches values 1`] = ` +" +rec_e fn exports_0: + id foo, fn value_0: + id (fn ret_0: #cn + id (fn: #cn + id (fn: #cn + id foo, fn result_0: + cc ret_0, result_0 + ), fn else_0: + is_l value_0, fn is_lst_0: + id (fn: #cn + lst_h value_0, fn itm_0: + int '3', fn val_0: + eq itm_0, val_0, fn cond_0: + id (fn: #cn + lst_t value_0, fn tail_0: + lst_h tail_0, fn itm_1: + int '4', fn val_1: + eq itm_1, val_1, fn cond_1: + id (fn: #cn + lst_t tail_0, fn tail_1: + lst_h tail_1, fn itm_2: + id ni, fn val_2: + eq itm_2, val_2, fn cond_2: + id (fn: #cn + id ni, fn result_1: + cc ret_0, result_1 + ), fn match_res_0: + cif cond_2, match_res_0, else_0 + ), fn match_0: + cif cond_1, match_0, else_0 + ), fn match_1: + cif cond_0, match_1, else_0 + ), fn match_2: + cif is_lst_0, match_2, else_0 + ), fn match_lst_0: + is_l value_0, fn is_lst_1: + id (fn: #cn + lst_h value_0, fn itm_3: + int '1', fn val_3: + eq itm_3, val_3, fn cond_3: + id (fn: #cn + lst_t value_0, fn tail_3: + lst_h tail_3, fn itm_4: + int '2', fn val_4: + eq itm_4, val_4, fn cond_4: + id (fn: #cn + id ni, fn result_2: + cc ret_0, result_2 + ), fn match_res_1: + cif cond_4, match_res_1, match_lst_0 + ), fn match_3: + cif cond_3, match_3, match_lst_0 + ), fn match_4: + cif is_lst_1, match_4, match_lst_0 + ), fn match_lst_1: + ac match_lst_1, fn mex_0: + lst_e fn drctvs_0: + mod exports_0, drctvs_0, fn mod_0:" +`; + +exports[`match matches simple values 1`] = ` +" +rec_e fn exports_0: + id shrub, fn value_0: + id (fn ret_0: #cn + id (fn: #cn + id (fn: #cn + id shrub, fn result_0: + cc ret_0, result_0 + ), fn else_0: + int '456', fn val_0: + eq value_0, val_0, fn cond_0: + id (fn: #cn + id ni, fn result_1: + cc ret_0, result_1 + ), fn match_res_0: + cif cond_0, match_res_0, else_0 + ), fn match_0: + int '123', fn val_1: + eq value_0, val_1, fn cond_1: + id (fn: #cn + id spam, fn result_2: + cc ret_0, result_2 + ), fn match_res_1: + cif cond_1, match_res_1, match_0 + ), fn match_1: + ac match_1, fn mex_0: + lst_e fn drctvs_0: + mod exports_0, drctvs_0, fn mod_0:" +`; + +exports[`match matches value assertions 1`] = ` +" +rec_e fn exports_0: + int '123', fn value_0: + id (fn ret_0: #cn + id (fn: #cn + id (fn: #cn + id (fn: #cn + id (fn: #cn + id (fn: #cn + cc ret_0 + ), fn else_0: + isv value_0, fn cond_0: + id (fn: #cn + id true, fn result_0: + cc ret_0, result_0 + ), fn match_res_0: + cif cond_0, match_res_0, else_0 + ), fn match_0: + id shrub, fn callee_0: + lst_e fn cargs_0: + id value_0, fn parg_0: + lst_a cargs_0, parg_0, fn cargs_1: + af callee_0, cargs_1, fn val_0: + eq true, val_0, fn cond_1: + id (fn: #cn + id ni, fn result_1: + cc ret_0, result_1 + ), fn match_res_1: + cif cond_1, match_res_1, match_0 + ), fn match_1: + id value_0, fn callee_1: + lst_e fn cargs_2: + af callee_1, cargs_2, fn val_1: + eq true, val_1, fn cond_2: + id (fn: #cn + id ni, fn result_2: + cc ret_0, result_2 + ), fn match_res_2: + cif cond_2, match_res_2, match_1 + ), fn match_2: + id value_0, fn left_0: + int '123', fn right_0: + gt left_0, right_0, fn val_2: + eq true, val_2, fn cond_3: + id (fn: #cn + id ni, fn result_3: + cc ret_0, result_3 + ), fn match_res_3: + cif cond_3, match_res_3, match_2 + ), fn match_3: + id value_0, fn right_1: + not right_1, fn val_3: + eq true, val_3, fn cond_4: + id (fn: #cn + id ni, fn result_4: + cc ret_0, result_4 + ), fn match_res_4: + cif cond_4, match_res_4, match_3 + ), fn match_4: + ac match_4, fn mex_0: + lst_e fn drctvs_0: + mod exports_0, drctvs_0, fn mod_0:" +`; + +exports[`match records matches calculated props 1`] = ` +" +rec_e fn exports_0: + id shrub, fn value_0: + id (fn ret_0: #cn + id (fn: #cn + cc ret_0 + ), fn else_0: + is_r value_0, fn is_rec_0: + id (fn: #cn + id a, fn key_0: + rec_g value_0, key_0, fn itm_0: + is_r itm_0, fn is_rec_1: + id (fn: #cn + str 'b', fn key_1: + rec_g itm_0, key_1, fn itm_1: + id b, fn val_0: + eq itm_1, val_0, fn cond_0: + id (fn: #cn + str 'c', fn key_2: + rec_g itm_0, key_2, fn itm_2: + id c, fn val_1: + eq itm_2, val_1, fn cond_1: + id (fn: #cn + id ni, fn result_0: + cc ret_0, result_0 + ), fn match_res_0: + cif cond_1, match_res_0, else_0 + ), fn match_0: + cif cond_0, match_0, else_0 + ), fn match_1: + cif is_rec_1, match_1, else_0 + ), fn match_rec_0: + cif is_rec_0, match_rec_0, else_0 + ), fn match_rec_1: + ac match_rec_1, fn mex_0: + lst_e fn drctvs_0: + mod exports_0, drctvs_0, fn mod_0:" +`; + +exports[`match records matches member expr keys 1`] = ` +" +rec_e fn exports_0: + id foo, fn value_0: + id (fn ret_0: #cn + id (fn: #cn + cc ret_0 + ), fn else_0: + is_r value_0, fn is_rec_0: + id (fn: #cn + str 'foo', fn key_0: + rec_g value_0, key_0, fn itm_0: + is_r itm_0, fn is_rec_1: + id (fn: #cn + str 'bar', fn key_1: + rec_g itm_0, key_1, fn itm_1: + is_r itm_1, fn is_rec_2: + id (fn: #cn + str 'spam', fn key_2: + rec_g itm_1, key_2, fn itm_2: + id ham, fn val_0: + eq itm_2, val_0, fn cond_0: + id (fn: #cn + id spam, fn result_0: + cc ret_0, result_0 + ), fn match_res_0: + cif cond_0, match_res_0, else_0 + ), fn match_0: + cif is_rec_2, match_0, else_0 + ), fn match_rec_0: + cif is_rec_1, match_rec_0, else_0 + ), fn match_rec_1: + cif is_rec_0, match_rec_1, else_0 + ), fn match_rec_2: + ac match_rec_2, fn mex_0: + lst_e fn drctvs_0: + mod exports_0, drctvs_0, fn mod_0:" +`; + +exports[`match records matches member expr keys 2`] = ` +" +rec_e fn exports_0: + id foo, fn value_0: + id (fn ret_0: #cn + id (fn: #cn + cc ret_0 + ), fn else_0: + is_r value_0, fn is_rec_0: + id (fn: #cn + str 'foo', fn key_0: + rec_g value_0, key_0, fn itm_0: + is_r itm_0, fn is_rec_1: + id (fn: #cn + str 'bar', fn key_1: + rec_g itm_0, key_1, fn itm_1: + is_r itm_1, fn is_rec_2: + id (fn: #cn + str 'spam', fn key_2: + rec_g itm_1, key_2, fn itm_2: + is_r itm_2, fn is_rec_3: + id (fn: #cn + str 'ham', fn key_3: + rec_g itm_2, key_3, fn itm_3: + is_r itm_3, fn is_rec_4: + id (fn: #cn + str 'ni', fn key_4: + rec_g itm_3, key_4, fn itm_4: + id nu, fn val_0: + eq itm_4, val_0, fn cond_0: + id (fn: #cn + id spam, fn result_0: + cc ret_0, result_0 + ), fn match_res_0: + cif cond_0, match_res_0, else_0 + ), fn match_0: + cif is_rec_4, match_0, else_0 + ), fn match_rec_0: + cif is_rec_3, match_rec_0, else_0 + ), fn match_rec_1: + cif is_rec_2, match_rec_1, else_0 + ), fn match_rec_2: + cif is_rec_1, match_rec_2, else_0 + ), fn match_rec_3: + cif is_rec_0, match_rec_3, else_0 + ), fn match_rec_4: + ac match_rec_4, fn mex_0: + lst_e fn drctvs_0: + mod exports_0, drctvs_0, fn mod_0:" +`; + +exports[`match records matches props 1`] = ` +" +rec_e fn exports_0: + id shrub, fn value_0: + id (fn ret_0: #cn + id (fn: #cn + id (fn: #cn + id (fn: #cn + id (fn: #cn + id (fn: #cn + cc ret_0 + ), fn else_0: + is_r value_0, fn is_rec_0: + id (fn: #cn + str 'ni', fn key_0: + rec_g value_0, key_0, fn itm_0: + is_l itm_0, fn is_lst_0: + id (fn: #cn + lst_h itm_0, fn itm_1: + id na, fn val_0: + eq itm_1, val_0, fn cond_0: + id (fn: #cn + lst_t itm_0, fn tail_0: + lst_h tail_0, fn itm_2: + int '123', fn val_1: + eq itm_2, val_1, fn cond_1: + id (fn: #cn + id na, fn result_0: + cc ret_0, result_0 + ), fn match_res_0: + cif cond_1, match_res_0, else_0 + ), fn match_0: + cif cond_0, match_0, else_0 + ), fn match_1: + cif is_lst_0, match_1, else_0 + ), fn match_lst_0: + cif is_rec_0, match_lst_0, else_0 + ), fn match_rec_0: + is_r value_0, fn is_rec_1: + id (fn: #cn + str 'ni', fn key_1: + rec_g value_0, key_1, fn itm_3: + is_r itm_3, fn is_rec_2: + id (fn: #cn + str 'len', fn key_2: + rec_g itm_3, key_2, fn itm_4: + int '1', fn val_2: + eq itm_4, val_2, fn cond_2: + id (fn: #cn + str 'na', fn key_3: + rec_g value_0, key_3, fn itm_5: + is_r itm_5, fn is_rec_3: + id (fn: #cn + str 'len', fn key_4: + rec_g itm_5, key_4, fn itm_6: + int '1', fn val_3: + eq itm_6, val_3, fn cond_3: + id (fn: #cn + id na, fn result_1: + cc ret_0, result_1 + ), fn match_res_1: + cif cond_3, match_res_1, match_rec_0 + ), fn match_2: + cif is_rec_3, match_2, match_rec_0 + ), fn match_rec_1: + cif cond_2, match_rec_1, match_rec_0 + ), fn match_3: + cif is_rec_2, match_3, match_rec_0 + ), fn match_rec_2: + cif is_rec_1, match_rec_2, match_rec_0 + ), fn match_rec_3: + is_r value_0, fn is_rec_4: + id (fn: #cn + str 'foo', fn key_5: + rec_g value_0, key_5, fn itm_7: + int '1', fn val_4: + eq itm_7, val_4, fn cond_4: + id (fn: #cn + str 'foo', fn key_6: + rec_g value_0, key_6, fn itm_8: + is_r itm_8, fn is_rec_5: + id (fn: #cn + str 'bar', fn key_7: + rec_g itm_8, key_7, fn itm_9: + str 'spam', fn str_0: + strt str_0, fn val_5: + eq itm_9, val_5, fn cond_5: + id (fn: #cn + str 'shrub', fn key_8: + rec_g value_0, key_8, fn itm_10: + is_r itm_10, fn is_rec_6: + id (fn: #cn + str 'na', fn key_9: + rec_g itm_10, key_9, fn itm_11: + str 'nu', fn str_1: + strt str_1, fn val_6: + eq itm_11, val_6, fn cond_6: + id (fn: #cn + id ni, fn result_2: + cc ret_0, result_2 + ), fn match_res_2: + cif cond_6, match_res_2, match_rec_3 + ), fn match_4: + cif is_rec_6, match_4, match_rec_3 + ), fn match_rec_4: + cif cond_5, match_rec_4, match_rec_3 + ), fn match_5: + cif is_rec_5, match_5, match_rec_3 + ), fn match_rec_5: + cif cond_4, match_rec_5, match_rec_3 + ), fn match_6: + cif is_rec_4, match_6, match_rec_3 + ), fn match_rec_6: + is_r value_0, fn is_rec_7: + id (fn: #cn + str 'foo', fn key_10: + rec_g value_0, key_10, fn itm_12: + int '4', fn val_7: + eq itm_12, val_7, fn cond_7: + id (fn: #cn + str 'ni', fn key_11: + rec_g value_0, key_11, fn itm_13: + is_r itm_13, fn is_rec_8: + id (fn: #cn + str 'na', fn key_12: + rec_g itm_13, key_12, fn itm_14: + id na, fn val_8: + eq itm_14, val_8, fn cond_8: + id (fn: #cn + str 'nu', fn key_13: + rec_g itm_13, key_13, fn itm_15: + id nu, fn val_9: + eq itm_15, val_9, fn cond_9: + id (fn: #cn + id spam, fn left_0: + id ni, fn right_0: + add left_0, right_0, fn result_3: + cc ret_0, result_3 + ), fn match_res_3: + cif cond_9, match_res_3, match_rec_6 + ), fn match_7: + cif cond_8, match_7, match_rec_6 + ), fn match_8: + cif is_rec_8, match_8, match_rec_6 + ), fn match_rec_7: + cif cond_7, match_rec_7, match_rec_6 + ), fn match_9: + cif is_rec_7, match_9, match_rec_6 + ), fn match_rec_8: + is_r value_0, fn is_rec_9: + id (fn: #cn + str 'foo', fn key_14: + rec_g value_0, key_14, fn itm_16: + id foo, fn val_10: + eq itm_16, val_10, fn cond_10: + id (fn: #cn + str 'bar', fn key_15: + rec_g value_0, key_15, fn itm_17: + id bar, fn val_11: + eq itm_17, val_11, fn cond_11: + id (fn: #cn + id ni, fn result_4: + cc ret_0, result_4 + ), fn match_res_4: + cif cond_11, match_res_4, match_rec_8 + ), fn match_10: + cif cond_10, match_10, match_rec_8 + ), fn match_11: + cif is_rec_9, match_11, match_rec_8 + ), fn match_rec_9: + ac match_rec_9, fn mex_0: + lst_e fn drctvs_0: + mod exports_0, drctvs_0, fn mod_0:" +`; + +exports[`match records matches spread 1`] = ` +" +rec_e fn exports_0: + id shrub, fn value_0: + id (fn ret_0: #cn + id (fn: #cn + cc ret_0 + ), fn else_0: + is_r value_0, fn is_rec_0: + id (fn: #cn + id foo, fn key_0: + rec_g value_0, key_0, fn itm_0: + is_r itm_0, fn is_rec_1: + id (fn: #cn + str 'x', fn key_1: + rec_g itm_0, key_1, fn itm_1: + id x, fn val_0: + eq itm_1, val_0, fn cond_0: + id (fn: #cn + rec_d value_0, key_0, fn spread_0: + is_r spread_0, fn is_rec_2: + id (fn: #cn + str 'bar', fn key_2: + rec_g spread_0, key_2, fn itm_2: + id bar, fn val_1: + eq itm_2, val_1, fn cond_1: + id (fn: #cn + str 'spam', fn key_3: + rec_g spread_0, key_3, fn itm_3: + id spam, fn val_2: + eq itm_3, val_2, fn cond_2: + id (fn: #cn + id ni, fn result_0: + cc ret_0, result_0 + ), fn match_res_0: + cif cond_2, match_res_0, else_0 + ), fn match_0: + cif cond_1, match_0, else_0 + ), fn match_1: + cif is_rec_2, match_1, else_0 + ), fn match_rec_0: + cif cond_0, match_rec_0, else_0 + ), fn match_2: + cif is_rec_1, match_2, else_0 + ), fn match_rec_1: + cif is_rec_0, match_rec_1, else_0 + ), fn match_rec_2: + ac match_rec_2, fn mex_0: + lst_e fn drctvs_0: + mod exports_0, drctvs_0, fn mod_0:" +`; + +exports[`match records matches value assertions 1`] = ` +" +rec_e fn exports_0: + id foo, fn value_0: + id (fn ret_0: #cn + id (fn: #cn + id (fn: #cn + id (fn: #cn + id (fn: #cn + id (fn: #cn + id (fn: #cn + id (fn: #cn + id (fn: #cn + cc ret_0 + ), fn else_0: + is_r value_0, fn is_rec_0: + id (fn: #cn + str 'spam', fn key_0: + rec_g value_0, key_0, fn itm_0: + isv itm_0, fn cond_0: + id (fn: #cn + id true, fn result_0: + cc ret_0, result_0 + ), fn match_res_0: + cif cond_0, match_res_0, else_0 + ), fn match_0: + cif is_rec_0, match_0, else_0 + ), fn match_rec_0: + is_r value_0, fn is_rec_1: + id (fn: #cn + str 'spam', fn key_1: + rec_g value_0, key_1, fn itm_1: + id spam, fn val_0: + eq itm_1, val_0, fn cond_1: + id (fn: #cn + rec_d value_0, key_1, fn spread_0: + str 'foo', fn str_0: + strt str_0, fn left_0: + id spread_0, fn right_0: + in left_0, right_0, fn val_1: + eq true, val_1, fn cond_2: + id (fn: #cn + id ni, fn result_1: + cc ret_0, result_1 + ), fn match_res_1: + cif cond_2, match_res_1, match_rec_0 + ), fn match_1: + cif cond_1, match_1, match_rec_0 + ), fn match_2: + cif is_rec_1, match_2, match_rec_0 + ), fn match_rec_1: + is_r value_0, fn is_rec_2: + id (fn: #cn + str 'spam', fn key_2: + rec_g value_0, key_2, fn itm_2: + id spam, fn val_2: + eq itm_2, val_2, fn cond_3: + id (fn: #cn + rec_d value_0, key_2, fn spread_1: + id is_empty, fn callee_0: + lst_e fn cargs_0: + id spread_1, fn parg_0: + lst_a cargs_0, parg_0, fn cargs_1: + af callee_0, cargs_1, fn val_3: + eq true, val_3, fn cond_4: + id (fn: #cn + id ni, fn result_2: + cc ret_0, result_2 + ), fn match_res_2: + cif cond_4, match_res_2, match_rec_1 + ), fn match_3: + cif cond_3, match_3, match_rec_1 + ), fn match_4: + cif is_rec_2, match_4, match_rec_1 + ), fn match_rec_2: + is_r value_0, fn is_rec_3: + id (fn: #cn + str 'spam', fn key_3: + rec_g value_0, key_3, fn itm_3: + id is_foo, fn callee_1: + lst_e fn cargs_2: + id itm_3, fn parg_1: + lst_a cargs_2, parg_1, fn cargs_3: + af callee_1, cargs_3, fn val_4: + eq true, val_4, fn cond_5: + id (fn: #cn + id ni, fn result_3: + cc ret_0, result_3 + ), fn match_res_3: + cif cond_5, match_res_3, match_rec_2 + ), fn match_5: + cif is_rec_3, match_5, match_rec_2 + ), fn match_rec_3: + is_r value_0, fn is_rec_4: + id (fn: #cn + str 'spam', fn key_4: + rec_g value_0, key_4, fn itm_4: + id itm_4, fn left_1: + str 'is_foo', fn key_5: + rec_g left_1, key_5, fn callee_2: + lst_e fn cargs_4: + af callee_2, cargs_4, fn val_5: + eq true, val_5, fn cond_6: + id (fn: #cn + id ni, fn result_4: + cc ret_0, result_4 + ), fn match_res_4: + cif cond_6, match_res_4, match_rec_3 + ), fn match_6: + cif is_rec_4, match_6, match_rec_3 + ), fn match_rec_4: + is_r value_0, fn is_rec_5: + id (fn: #cn + str 'spam', fn key_6: + rec_g value_0, key_6, fn itm_5: + id itm_5, fn callee_3: + lst_e fn cargs_5: + af callee_3, cargs_5, fn val_6: + eq true, val_6, fn cond_7: + id (fn: #cn + id ni, fn result_5: + cc ret_0, result_5 + ), fn match_res_5: + cif cond_7, match_res_5, match_rec_4 + ), fn match_7: + cif is_rec_5, match_7, match_rec_4 + ), fn match_rec_5: + is_r value_0, fn is_rec_6: + id (fn: #cn + str 'spam', fn key_7: + rec_g value_0, key_7, fn itm_6: + id itm_6, fn left_2: + int '123', fn right_1: + gt left_2, right_1, fn val_7: + eq true, val_7, fn cond_8: + id (fn: #cn + id ni, fn result_6: + cc ret_0, result_6 + ), fn match_res_6: + cif cond_8, match_res_6, match_rec_5 + ), fn match_8: + cif is_rec_6, match_8, match_rec_5 + ), fn match_rec_6: + is_r value_0, fn is_rec_7: + id (fn: #cn + str 'spam', fn key_8: + rec_g value_0, key_8, fn itm_7: + id itm_7, fn right_2: + not right_2, fn val_8: + eq true, val_8, fn cond_9: + id (fn: #cn + id ni, fn result_7: + cc ret_0, result_7 + ), fn match_res_7: + cif cond_9, match_res_7, match_rec_6 + ), fn match_9: + cif is_rec_7, match_9, match_rec_6 + ), fn match_rec_7: + ac match_rec_7, fn mex_0: + lst_e fn drctvs_0: + mod exports_0, drctvs_0, fn mod_0:" +`; diff --git a/src/ir/context.fnk b/src/ir/context.fnk new file mode 100644 index 0000000..24b8e68 --- /dev/null +++ b/src/ir/context.fnk @@ -0,0 +1,145 @@ +{is_fn} = import '@fink/std-lib/fn.fnk' +hamt = import 'hamt' +{set, tryGet, empty} = hamt + +any = false + + +add = fn type, op, transformer: fn ctx: + next_transformers = rec: + ...ctx.transformers + (type or op): transformer + + {...ctx, transformers: next_transformers} + + + +get_transformer = fn {op, type}, {transformers}: + match transformers: + {(op): is_fn ?}: + {(op): transform} = transformers + transform + + {(type): is_fn ?}: + {(type): transform} = transformers + transform + + + +unique_name = fn prefix, {loc}, ctx: + {unique_ids} = ctx + {(prefix): cntr=0} = unique_ids + id = {i: '${prefix}_${cntr}', loc} + [id, {...ctx, unique_ids: {...unique_ids, (prefix): cntr + 1}}] + + + +unique_or_id = fn prefix_or_id, {loc}, ctx: + match prefix_or_id: + {i: ?}: + [prefix_or_id, ctx] + false: + [prefix_or_id, ctx] + else: + unique_name prefix_or_id, {loc}, ctx + + + +ir_fn = fn fn_name, args, name_or_id=false, {loc}, ctx: + [res_id, next_ctx] = unique_or_id name_or_id, {loc}, ctx + expr = {f: fn_name, args, loc} + match name_or_id: + false: + [[[expr, []]], , next_ctx] + else: + [[[expr, [res_id]]], res_id, next_ctx] + + + +get_value = fn {i: id}, {values}: + tryGet {}, id, values + + +update_value = fn id, updates, ctx: + curr = get_value id, ctx + values = set id.i, {...curr, ...updates}, ctx.values + {...ctx, values} + + + +get_refs = fn id, ctx: + {refs=0} = get_value id, ctx + refs + + + +inc_ref = fn id, ctx: + {refs=0} = get_value id, ctx + update_value id, {refs: refs + 1}, ctx + + + +inc_refs = fn [id=false, ...rest], ctx: + match id: + false: ctx + else: inc_refs rest, inc_ref id, ctx + + + +dec_ref = fn id, ctx: + {refs=0} = get_value id, ctx + update_value id, {refs: refs - 1}, ctx + + + +dec_refs = fn [id=false, ...exprs], ctx: + match id: + false: ctx + else: dec_refs exprs, dec_ref id, ctx + + + +init_refs = fn [id=false, ...rest], ctx: + match id: + false: ctx + else: init_refs rest, update_value id, {refs: 0}, ctx + + + +is_unused = fn id, ctx: + 0 == get_refs id, ctx + + + +init_ref_counts = fn [expr=false, ...rest], ctx: + match expr: + false: ctx + else: + [{f: op, args}, res] = expr + rest_ctx = match op: + ? in ['fn', 'cn']: + [fn_args, body] = args + init_ref_counts body, init_refs [...fn_args, ...res], ctx + + ? in ['int', 'float', 'str']: + init_refs res, ctx + + else: + init_refs res, inc_refs args, ctx + + init_ref_counts rest, rest_ctx + + + +init_ctx = fn exprs, options={}: + ctx = rec: + ...options + transformers: {} + runtime: {} + unique_ids: {} + values: empty + + + pipe ctx: + init_ref_counts exprs, ? + diff --git a/src/js/errors.fnk b/src/ir/errors.fnk similarity index 100% rename from src/js/errors.fnk rename to src/ir/errors.fnk diff --git a/src/ir/func/init.fnk b/src/ir/func/init.fnk new file mode 100644 index 0000000..33b0879 --- /dev/null +++ b/src/ir/func/init.fnk @@ -0,0 +1,74 @@ +{add, any} = import '../context.fnk' +{transform} = import '../transform.fnk' +{unique_or_id, ir_fn, get_refs} = import '../context.fnk' +{transform_dl} = import '../assignment/init.fnk' +{bind_x} = import '../identifier/init.fnk' + + + +cc = fn ret_id, res_id, name_or_id, {loc}, ctx: + ir_fn 'cc', [ret_id, res_id], name_or_id, {loc}, ctx + + + +fnc = fn args_id, res_id, body, name_or_id, {loc}, ctx: + [ret_id, cc_ctx] = unique_or_id 'ret', {loc}, ctx + [ret, , next_ctx] = cc ret_id, res_id, , {loc}, cc_ctx + ir_fn 'fn', [[args_id, ret_id], [...body, ...ret]], name_or_id, {loc}, next_ctx + + + +zfnc = fn args_id, self_id, res_id, body, name_or_id, {loc}, ctx: + [ret_id, cc_ctx] = unique_or_id 'ret', {loc}, ctx + [ret, , next_ctx] = cc ret_id, res_id, , {loc}, cc_ctx + ir_fn 'fn', [[args_id, ret_id, self_id], [...body, ...ret]], name_or_id, {loc}, next_ctx + + + +transform_exprs = fn [expr=false, ...rest], ctx, out, last_id: + match expr: + false: + [out, last_id, ctx] + {value: 'undefined'}: + [foo, id, next_ctx] = transform expr, 'result', ctx + transform_exprs rest, next_ctx, [...out, ...foo], id + else: + [foo, id, next_ctx] = transform expr, 'result', ctx + transform_exprs rest, next_ctx, [...out, ...foo], id + + + +transform_args = fn {args: exprs, loc}, ctx: + [args_id, next_ctx] = unique_or_id 'args', {loc}, ctx + [args, , end_ctx] = transform_dl exprs, args_id, next_ctx + [args, args_id, end_ctx] + + + +transform_func = fn expr, res_id, {scopes, self_name=false, ...ctx}: + func_ctx = {...ctx, scopes: [{}, ...scopes]} + + [self_id, args_ctx] = match self_name: + false: + [false, func_ctx ] + else: + [self_id, bind_ctx] = unique_or_id '${res_id.i}', expr, func_ctx + [self_id, bind_x {value: self_name}, self_id, bind_ctx] + + [args, args_id, body_ctx] = transform_args expr, args_ctx + [exprs, fn_res_id, fn_ctx] = transform_exprs expr.exprs, body_ctx, [] + body = [...args, ...exprs] + + [fun, , end_ctx] = match self_id: + ? != false and 0 < get_refs ?, fn_ctx: + zfnc args_id, self_id, fn_res_id, body, res_id, expr, fn_ctx + else: + fnc args_id, fn_res_id, body, res_id, expr, fn_ctx + + [fun, {...end_ctx, scopes}] + + + +add_func = fn ctx: + pipe ctx: + add any, 'fn', transform_func diff --git a/src/ir/func/init.test.fnk b/src/ir/func/init.test.fnk new file mode 100644 index 0000000..179824d --- /dev/null +++ b/src/ir/func/init.test.fnk @@ -0,0 +1,140 @@ +{skip, describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' +{fink2lir} = import '../../testing/generate.fnk' + + +describe 'func', fn: + it 'compiles', fn: + expect + fink2lir ' + fun = fn a, b, d: + a + b + c + + f2 = fn foo: fn bar: foo bar + ' + to_match_snapshot + + + it 'compiles func of func', fn: + expect + fink2lir ' + fun5 = fn c: fn d, e: + match [d, e]: + [1, 2]: c + [2, 1]: 1 / c + ' + to_match_snapshot + + + it 'compiles other', fn: + expect + fink2lir ' + fun = fn c, d: + x = 123 + match ni: + c + x: d + c + 1: d + 1 + ' + to_match_snapshot + + + it 'compiles defaults', fn: + expect + fink2lir ' + fun = fn a, b=12, c: + shrub ...a + bar _ + ' + to_match_snapshot + + + it 'compiles empty arg', fn: + expect + fink2lir ' + fun = fn a, , , b: + b + ' + to_match_snapshot + + expect + fink2lir ' + fun = fn _, b: + b + ' + to_match_snapshot + + + it 'compiles spread', fn: + expect + fink2lir ' + fun = fn a, b, ...c: + [a + b, c] + ' + to_match_snapshot + + expect + fink2lir ' + fun = fn a, ...b, c: + [a, b, c] + ' + to_match_snapshot + + expect + fink2lir ' + fun = fn ...a: + a + ' + to_match_snapshot + + it 'compiles destructuring args', fn: + expect + fink2lir ' + fun = fn [a, [b]], [c, ...d]: + [a + b, c] + ' + to_match_snapshot + + + it 'compiles destructuring recs', fn: + expect + fink2lir ' + fun = fn {a, b}, [c, ...d]: + [a + b, c] + ' + to_match_snapshot + + + it 'handles self-ref scoping', fn: + expect + fink2lir " + undefined = foo + bar = fn: fn: undefined + " + to_match_snapshot + + + +describe 'recursive funcs', fn: + it 'compiles recursive calls', fn: + expect + fink2lir ' + fun = fn a, b: + match a: + b: a + else: fun a - 1 + ' + to_match_snapshot + + + skip.it 'handles mutually recursive calls', fn: + expect + fink2lir ' + foo = fn a: + bar a + + bar = fn b: + foo b + ' + to_match_snapshot + + + diff --git a/src/ir/func/init.test.fnk.snap b/src/ir/func/init.test.fnk.snap new file mode 100644 index 0000000..4e2ba01 --- /dev/null +++ b/src/ir/func/init.test.fnk.snap @@ -0,0 +1,412 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`func compiles 1`] = ` +" +rec_e fn exports_0: + id (fn args_0, ret_0: #fn + lst_h args_0, fn a_0: + lst_t args_0, fn tail_0: + lst_h tail_0, fn b_0: + lst_t tail_0, fn tail_1: + lst_h tail_1, fn d_0: + lst_t tail_1, fn tail_2: + id a_0, fn left_1: + id b_0, fn right_0: + add left_1, right_0, fn left_0: + id c, fn right_1: + add left_0, right_1, fn result_0: + cc ret_0, result_0 + ), fn fun_0: + str 'fun', fn key_0: + rec_s exports_0, key_0, fun_0, fn exports_1: + id (fn args_1, ret_2: #fn + lst_h args_1, fn foo_0: + lst_t args_1, fn tail_3: + id (fn args_2, ret_1: #fn + lst_h args_2, fn bar_0: + lst_t args_2, fn tail_4: + id foo_0, fn callee_0: + lst_e fn cargs_0: + id bar_0, fn arg_0: + lst_a cargs_0, arg_0, fn cargs_1: + af callee_0, cargs_1, fn result_2: + cc ret_1, result_2 + ), fn result_1: + cc ret_2, result_1 + ), fn f2_0: + str 'f2', fn key_1: + rec_s exports_1, key_1, f2_0, fn exports_2: + lst_e fn drctvs_0: + mod exports_2, drctvs_0, fn mod_0:" +`; + +exports[`func compiles defaults 1`] = ` +" +rec_e fn exports_0: + id (fn args_0, ret_0: #fn + lst_h args_0, fn a_0: + lst_t args_0, fn tail_0: + int '12', fn flbk_0: + lst_h tail_0, fn hdm_0: + ifv hdm_0, hdm_0, flbk_0, fn b_0: + lst_t tail_0, fn tail_1: + lst_h tail_1, fn c_0: + lst_t tail_1, fn tail_2: + id shrub, fn callee_0: + lst_e fn cargs_0: + id a_0, fn sprd_0: + lst_c cargs_0, sprd_0, fn cargs_1: + af callee_0, cargs_1, fn result_0: + id bar, fn callee_1: + lst_e fn cargs_2: + af callee_1, cargs_2, fn result_1: + cc ret_0, result_1 + ), fn fun_0: + str 'fun', fn key_0: + rec_s exports_0, key_0, fun_0, fn exports_1: + lst_e fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; + +exports[`func compiles destructuring args 1`] = ` +" +rec_e fn exports_0: + id (fn args_0, ret_0: #fn + lst_h args_0, fn dlst_0: + lst_t args_0, fn tail_0: + lst_h dlst_0, fn a_0: + lst_t dlst_0, fn tail_1: + lst_h tail_1, fn dlst_1: + lst_t tail_1, fn tail_2: + lst_h dlst_1, fn b_0: + lst_t dlst_1, fn tail_3: + lst_h tail_0, fn dlst_2: + lst_t tail_0, fn tail_4: + lst_h dlst_2, fn c_0: + lst_t dlst_2, fn tail_5: + lst_r tail_5, fn rtail_0: + lst_r rtail_0, fn d_0: + lst_e fn lst_1: + id a_0, fn left_0: + id b_0, fn right_0: + add left_0, right_0, fn item_1: + lst_a lst_1, item_1, fn lst_0: + id c_0, fn item_0: + lst_a lst_0, item_0, fn result_0: + cc ret_0, result_0 + ), fn fun_0: + str 'fun', fn key_0: + rec_s exports_0, key_0, fun_0, fn exports_1: + lst_e fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; + +exports[`func compiles destructuring recs 1`] = ` +" +rec_e fn exports_0: + id (fn args_0, ret_0: #fn + lst_h args_0, fn drec_0: + lst_t args_0, fn tail_0: + str 'a', fn key_0: + rec_g drec_0, key_0, fn a_0: + str 'b', fn key_1: + rec_g drec_0, key_1, fn b_0: + lst_h tail_0, fn dlst_0: + lst_t tail_0, fn tail_1: + lst_h dlst_0, fn c_0: + lst_t dlst_0, fn tail_2: + lst_r tail_2, fn rtail_0: + lst_r rtail_0, fn d_0: + lst_e fn lst_1: + id a_0, fn left_0: + id b_0, fn right_0: + add left_0, right_0, fn item_1: + lst_a lst_1, item_1, fn lst_0: + id c_0, fn item_0: + lst_a lst_0, item_0, fn result_0: + cc ret_0, result_0 + ), fn fun_0: + str 'fun', fn key_2: + rec_s exports_0, key_2, fun_0, fn exports_1: + lst_e fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; + +exports[`func compiles empty arg 1`] = ` +" +rec_e fn exports_0: + id (fn args_0, ret_0: #fn + lst_h args_0, fn a_0: + lst_t args_0, fn tail_0: + lst_h tail_0, fn unused_0: + lst_t tail_0, fn tail_1: + lst_h tail_1, fn unused_1: + lst_t tail_1, fn tail_2: + lst_h tail_2, fn b_0: + lst_t tail_2, fn tail_3: + id b_0, fn result_0: + cc ret_0, result_0 + ), fn fun_0: + str 'fun', fn key_0: + rec_s exports_0, key_0, fun_0, fn exports_1: + lst_e fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; + +exports[`func compiles empty arg 2`] = ` +" +rec_e fn exports_0: + id (fn args_0, ret_0: #fn + lst_h args_0, fn unused_0: + lst_t args_0, fn tail_0: + lst_h tail_0, fn b_0: + lst_t tail_0, fn tail_1: + id b_0, fn result_0: + cc ret_0, result_0 + ), fn fun_0: + str 'fun', fn key_0: + rec_s exports_0, key_0, fun_0, fn exports_1: + lst_e fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; + +exports[`func compiles func of func 1`] = ` +" +rec_e fn exports_0: + id (fn args_0, ret_2: #fn + lst_h args_0, fn c_0: + lst_t args_0, fn tail_0: + id (fn args_1, ret_1: #fn + lst_h args_1, fn d_0: + lst_t args_1, fn tail_1: + lst_h tail_1, fn e_0: + lst_t tail_1, fn tail_2: + lst_e fn lst_1: + id d_0, fn item_1: + lst_a lst_1, item_1, fn lst_0: + id e_0, fn item_0: + lst_a lst_0, item_0, fn value_0: + id (fn ret_0: #cn + id (fn: #cn + id (fn: #cn + cc ret_0 + ), fn else_0: + is_l value_0, fn is_lst_0: + id (fn: #cn + lst_h value_0, fn itm_0: + int '2', fn val_0: + eq itm_0, val_0, fn cond_0: + id (fn: #cn + lst_t value_0, fn tail_3: + lst_h tail_3, fn itm_1: + int '1', fn val_1: + eq itm_1, val_1, fn cond_1: + id (fn: #cn + int '1', fn left_0: + id c_0, fn right_0: + div left_0, right_0, fn result_2: + cc ret_0, result_2 + ), fn match_res_0: + cif cond_1, match_res_0, else_0 + ), fn match_0: + cif cond_0, match_0, else_0 + ), fn match_1: + cif is_lst_0, match_1, else_0 + ), fn match_lst_0: + is_l value_0, fn is_lst_1: + id (fn: #cn + lst_h value_0, fn itm_2: + int '1', fn val_2: + eq itm_2, val_2, fn cond_2: + id (fn: #cn + lst_t value_0, fn tail_5: + lst_h tail_5, fn itm_3: + int '2', fn val_3: + eq itm_3, val_3, fn cond_3: + id (fn: #cn + id c_0, fn result_3: + cc ret_0, result_3 + ), fn match_res_1: + cif cond_3, match_res_1, match_lst_0 + ), fn match_2: + cif cond_2, match_2, match_lst_0 + ), fn match_3: + cif is_lst_1, match_3, match_lst_0 + ), fn match_lst_1: + ac match_lst_1, fn result_1: + cc ret_1, result_1 + ), fn result_0: + cc ret_2, result_0 + ), fn fun5_0: + str 'fun5', fn key_0: + rec_s exports_0, key_0, fun5_0, fn exports_1: + lst_e fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; + +exports[`func compiles other 1`] = ` +" +rec_e fn exports_0: + id (fn args_0, ret_1: #fn + lst_h args_0, fn c_0: + lst_t args_0, fn tail_0: + lst_h tail_0, fn d_0: + lst_t tail_0, fn tail_1: + int '123', fn x_0: + id ni, fn value_0: + id (fn ret_0: #cn + id (fn: #cn + id (fn: #cn + cc ret_0 + ), fn else_0: + id c_0, fn left_0: + int '1', fn right_0: + add left_0, right_0, fn val_0: + eq value_0, val_0, fn cond_0: + id (fn: #cn + id d_0, fn left_1: + int '1', fn right_1: + add left_1, right_1, fn result_2: + cc ret_0, result_2 + ), fn match_res_0: + cif cond_0, match_res_0, else_0 + ), fn match_0: + id c_0, fn left_2: + id x_0, fn right_2: + add left_2, right_2, fn val_1: + eq value_0, val_1, fn cond_1: + id (fn: #cn + id d_0, fn result_3: + cc ret_0, result_3 + ), fn match_res_1: + cif cond_1, match_res_1, match_0 + ), fn match_1: + ac match_1, fn result_1: + cc ret_1, result_1 + ), fn fun_0: + str 'fun', fn key_0: + rec_s exports_0, key_0, fun_0, fn exports_1: + lst_e fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; + +exports[`func compiles spread 1`] = ` +" +rec_e fn exports_0: + id (fn args_0, ret_0: #fn + lst_h args_0, fn a_0: + lst_t args_0, fn tail_0: + lst_h tail_0, fn b_0: + lst_t tail_0, fn tail_1: + lst_r tail_1, fn rtail_0: + lst_r rtail_0, fn c_0: + lst_e fn lst_1: + id a_0, fn left_0: + id b_0, fn right_0: + add left_0, right_0, fn item_1: + lst_a lst_1, item_1, fn lst_0: + id c_0, fn item_0: + lst_a lst_0, item_0, fn result_0: + cc ret_0, result_0 + ), fn fun_0: + str 'fun', fn key_0: + rec_s exports_0, key_0, fun_0, fn exports_1: + lst_e fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; + +exports[`func compiles spread 2`] = ` +" +rec_e fn exports_0: + id (fn args_0, ret_0: #fn + lst_h args_0, fn a_0: + lst_t args_0, fn tail_0: + lst_r tail_0, fn rtail_0: + lst_h rtail_0, fn c_0: + lst_t rtail_0, fn tail_1: + lst_r tail_1, fn b_0: + lst_e fn lst_2: + id a_0, fn item_2: + lst_a lst_2, item_2, fn lst_1: + id b_0, fn item_1: + lst_a lst_1, item_1, fn lst_0: + id c_0, fn item_0: + lst_a lst_0, item_0, fn result_0: + cc ret_0, result_0 + ), fn fun_0: + str 'fun', fn key_0: + rec_s exports_0, key_0, fun_0, fn exports_1: + lst_e fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; + +exports[`func compiles spread 3`] = ` +" +rec_e fn exports_0: + id (fn args_0, ret_0: #fn + lst_r args_0, fn rtail_0: + lst_r rtail_0, fn a_0: + id a_0, fn result_0: + cc ret_0, result_0 + ), fn fun_0: + str 'fun', fn key_0: + rec_s exports_0, key_0, fun_0, fn exports_1: + lst_e fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; + +exports[`func handles self-ref scoping 1`] = ` +" +rec_e fn exports_0: + id foo, fn undefined_0: + str 'undefined', fn key_0: + rec_s exports_0, key_0, undefined_0, fn exports_1: + id (fn args_0, ret_1: #fn + id (fn args_1, ret_0: #fn + id undefined_0, fn result_1: + cc ret_0, result_1 + ), fn result_0: + cc ret_1, result_0 + ), fn bar_0: + str 'bar', fn key_1: + rec_s exports_1, key_1, bar_0, fn exports_2: + lst_e fn drctvs_0: + mod exports_2, drctvs_0, fn mod_0:" +`; + +exports[`recursive funcs compiles recursive calls 1`] = ` +" +rec_e fn exports_0: + z (fn args_0, ret_1, fun_0_0: #fn + lst_h args_0, fn a_0: + lst_t args_0, fn tail_0: + lst_h tail_0, fn b_0: + lst_t tail_0, fn tail_1: + id a_0, fn value_0: + id (fn ret_0: #cn + id (fn: #cn + id fun_0_0, fn callee_0: + lst_e fn cargs_0: + id a_0, fn left_0: + int '1', fn right_0: + sub left_0, right_0, fn arg_0: + lst_a cargs_0, arg_0, fn cargs_1: + af callee_0, cargs_1, fn result_1: + cc ret_0, result_1 + ), fn else_0: + id b_0, fn val_0: + eq value_0, val_0, fn cond_0: + id (fn: #cn + id a_0, fn result_2: + cc ret_0, result_2 + ), fn match_res_0: + cif cond_0, match_res_0, else_0 + ), fn match_0: + ac match_0, fn result_0: + cc ret_1, result_0 + ), fn fun_0: + str 'fun', fn key_0: + rec_s exports_0, key_0, fun_0, fn exports_1: + lst_e fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; diff --git a/src/ir/group/init.fnk b/src/ir/group/init.fnk new file mode 100644 index 0000000..d431d04 --- /dev/null +++ b/src/ir/group/init.fnk @@ -0,0 +1,26 @@ +{add, any} = import '../context.fnk' +{transform} = import '../transform.fnk' + + + +# TODO: same as in block +transform_exprs = fn [expr, ...exprs], res_id, ctx, out=[]: + match exprs: + [?]: + [val, , next_ctx] = transform expr, 'grpv', ctx + transform_exprs exprs, res_id, next_ctx, [...out, ...val] + else: + [val, , next_ctx] = transform expr, res_id, ctx + [[...out, ...val], next_ctx] + + + + +transform_group = fn expr, res_id, ctx: + transform_exprs expr.exprs, res_id, ctx + + + +add_group = fn ctx: + pipe ctx: + add 'group', any, transform_group diff --git a/src/ir/group/init.test.fnk b/src/ir/group/init.test.fnk new file mode 100644 index 0000000..e11d91d --- /dev/null +++ b/src/ir/group/init.test.fnk @@ -0,0 +1,11 @@ +{fink2lir} = import '../../testing/generate.fnk' +{describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' + + +describe 'group', fn: + it 'compiles', fn: + expect + fink2lir " + foo = (a = bar, spam a) + " + to_match_snapshot diff --git a/src/ir/group/init.test.fnk.snap b/src/ir/group/init.test.fnk.snap new file mode 100644 index 0000000..146a4ca --- /dev/null +++ b/src/ir/group/init.test.fnk.snap @@ -0,0 +1,16 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`group compiles 1`] = ` +" +rec_e fn exports_0: + id bar, fn a_0: + id spam, fn callee_0: + lst_e fn cargs_0: + id a_0, fn arg_0: + lst_a cargs_0, arg_0, fn cargs_1: + af callee_0, cargs_1, fn foo_0: + str 'foo', fn key_0: + rec_s exports_0, key_0, foo_0, fn exports_1: + lst_e fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; diff --git a/src/ir/identifier/init.fnk b/src/ir/identifier/init.fnk new file mode 100644 index 0000000..56b7533 --- /dev/null +++ b/src/ir/identifier/init.fnk @@ -0,0 +1,66 @@ +{add, any, unique_or_id, ir_fn, inc_ref} = import '../context.fnk' + + + +bind = fn {value, loc}, ctx: + {scopes: [scope, ...scopes]} = ctx + [id, next_ctx] = unique_or_id value, {loc}, ctx + + end_ctx = rec: + ...next_ctx + scopes: list: + {...scope, (value): id} + ...scopes + + [id, end_ctx] + + +# TODO rename +bind_x = fn {value}, id, ctx: + {scopes: [scope, ...scopes]} = ctx + + end_ctx = rec: + ...ctx + scopes: list: + # TODO: loc from value or id? + {...scope, (value): id} + ...scopes + + end_ctx + + + +get_ident = fn name, [scope, ...scopes], {loc}, ctx: + match scope: + {(name): ?}: + # TODO should we use loc from args or not? + id = {...scope.(name), loc} + next_ctx = inc_ref id, ctx + [id, next_ctx] + ?: + get_ident name, scopes, {loc}, ctx + else: + # TODO should we use loc from args or not? + [{i: name, loc}, ctx] + + + +let = fn id, res_id, {loc}, ctx: + ir_fn '=', [id], res_id, {loc}, ctx + + + +transform_ident = fn {value, loc}, res_id, ctx: + [id, let_ctx] = get_ident value, ctx.scopes, {loc}, ctx + [epxr, , next_ctx] = let id, res_id, {loc}, let_ctx + [epxr, next_ctx] + + + +add_ident = fn ctx: + pipe ctx: + add 'ident', any, transform_ident + + + + diff --git a/src/ir/init.fnk b/src/ir/init.fnk new file mode 100644 index 0000000..cfa6a77 --- /dev/null +++ b/src/ir/init.fnk @@ -0,0 +1,56 @@ +hamt = import 'hamt' +{empty} = hamt + +{add_assignment} = import './assignment/init.fnk' +{add_func} = import './func/init.fnk' +{add_conditionals} = import './conditionals/init.fnk' +{add_call} = import './call/init.fnk' +{add_literals} = import './literals/init.fnk' +{add_async} = import './async/init.fnk' +{add_logical} = import './logical/init.fnk' +{add_group} = import './group/init.fnk' +{add_module} = import './module/init.fnk' +{add_block} = import './block/init.fnk' +{add_member} = import './prop-access/init.fnk' +{add_ident} = import './identifier/init.fnk' +{add_comparison} = import './comparison/init.fnk' +{add_jsx} = import './jsx/init.fnk' +{add_arithmitic} = import './arithmitic/init.fnk' +{add_partial} = import './partial/init.fnk' + + + +add_transformers = fn ctx: + pipe ctx: + add_module + add_block + add_group + add_func + add_ident + add_assignment + add_literals + add_member + add_arithmitic + add_comparison + add_logical + add_conditionals + add_call + add_jsx + add_partial + add_async + + + +init_ctx = fn code, filename, options: + ctx = rec: + filename, code + options + unique_ids: {} + errors: [] + values: empty + scopes: [{}] + + pipe ctx: + add_transformers + + diff --git a/src/ir/jsx/init.fnk b/src/ir/jsx/init.fnk new file mode 100644 index 0000000..40da46c --- /dev/null +++ b/src/ir/jsx/init.fnk @@ -0,0 +1,139 @@ +{lower_case} = import '@fink/std-lib/str.fnk' + +{add, any, ir_fn} = import '../context.fnk' +{transform} = import '../transform.fnk' +{lst, lst_a} = import '../literals/list.fnk' +{rec_e, rec_s, rec_m} = import '../literals/record.fnk' +{str} = import '../literals/string.fnk' + + +jxe = fn name_id, props_id, chldrn_id, name_or_id, {loc}, ctx: + ir_fn 'jxe', [name_id, props_id, chldrn_id], name_or_id, {loc}, ctx + + +jxf = fn children_id, name_or_id, {loc}, ctx: + ir_fn 'jxf', [children_id], name_or_id, {loc}, ctx + + + +transform_prop_name = fn expr, ctx: + str expr.value, 'prpn', expr, ctx + + +transform_prop_val = fn expr, ctx: + match expr: + {name: {type: 'ident'}, value: false}: + transform expr.name, 'prpv', ctx + else: + transform expr.value, 'prpv', ctx + + + +transform_prop = fn expr, rec_id, ctx: + match expr: + {type: 'spread'}: + [val, val_id, rec_ctx] = transform expr.right, 'sprd', ctx + [rec_exprs, next_rec_id, next_ctx] = rec_m rec_id, val_id, 'props', expr, rec_ctx + [[...val, ...rec_exprs], next_rec_id , next_ctx] + + else: + [key, key_id, val_ctx] = transform_prop_name expr.name, ctx + [val, val_id, rec_ctx] = transform_prop_val expr, val_ctx + [rec_exprs, next_rec_id, next_ctx] = rec_s rec_id, key_id, val_id, 'props', expr, rec_ctx + [[...key, ...val, ...rec_exprs], next_rec_id, next_ctx] + + + +transform_all_props = fn [expr=false, ...rest], rec_id, ctx, out=[]: + match expr: + false: + [out, rec_id, ctx] + else: + [kv, next_rec_id, next_ctx] = transform_prop expr, rec_id, ctx + transform_all_props rest, next_rec_id, next_ctx, [...out, ...kv] + + + +transform_props = fn {props, loc}, ctx: + [rc, start_id, props_ctx] = rec_e 'props', {loc}, ctx + [out, rec_id, next_ctx] = transform_all_props props, start_id, props_ctx + [[...rc, ...out], rec_id, next_ctx] + + + + +transform_child = fn expr, lst_id, ctx: + [item, item_id, ch_ctx] = transform expr, 'chld', ctx + [lst, children_id, next_ctx] = lst_a lst_id, item_id, 'chldrn', expr, ch_ctx + [[...item, ...lst], children_id, next_ctx] + + + +transform_all_children = fn [expr=false, ...rest], lst_id, ctx, out=[]: + match expr: + false: + [out, lst_id, ctx] + else: + [child, out_lst_id, next_ctx] = transform_child expr, lst_id, ctx + transform_all_children rest, out_lst_id, next_ctx, [...out, ...child] + + + +transform_children = fn {children, loc}, ctx: + [ls, start_id, chldrn_ctx] = lst 'chldrn', {loc}, ctx + [out, lst_id, next_ctx] = transform_all_children children, start_id, chldrn_ctx + [[...ls, ...out], lst_id, next_ctx] + + + +first_is_lower = fn [s]: + match lower_case s: + s: true + else: false + + + +transform_elem_ident = fn expr, ctx: + match expr: + {value: first_is_lower ?}: + str expr.value, 'jsxi', expr, ctx + else: + transform expr, 'jsxi', ctx + + + +transform_jsx_elem = fn node, res_id, ctx: + [name, name_id, props_ctx] = transform_elem_ident node.name, ctx + [props, props_id, chldrn_ctx] = transform_props node, props_ctx + [chldrn, chldrn_id, jxe_ctx] = transform_children node, chldrn_ctx + [elem, , next_ctx] = jxe name_id, props_id, chldrn_id, res_id, node, jxe_ctx + [[...name, ...props, ...chldrn, ...elem], next_ctx] + + + +transform_jsx_frag = fn node, res_id, ctx: + [chldrn, chldrn_id, jxf_ctx] = transform_children node, ctx + [elem, , next_ctx] = jxf chldrn_id, res_id, node, jxf_ctx + [[...chldrn, ...elem], next_ctx] + + + +transform_jsx_text = fn node, res_id, ctx: + [txt, , next_ctx] = str node.value, res_id, node, ctx + [txt, next_ctx] + + + +transform_jsx_expr_container = fn node, res_id, ctx: + [val, , next_ctx] = transform node.expr, res_id, ctx + [val, next_ctx] + + + +add_jsx = fn ctx: + pipe ctx: + add 'jsx:frag', any, transform_jsx_frag + add 'jsx:elem', any, transform_jsx_elem + add 'jsx:text', any, transform_jsx_text + add 'jsx:expr', any, transform_jsx_expr_container + diff --git a/src/ir/jsx/init.test.fnk b/src/ir/jsx/init.test.fnk new file mode 100644 index 0000000..325f00c --- /dev/null +++ b/src/ir/jsx/init.test.fnk @@ -0,0 +1,119 @@ +{describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' +{fink2lir} = import '../../testing/generate.fnk' + + +describe 'jsx', fn: + it 'compiles shorthand', fn: + expect + fink2lir 'elem = ' + to_match_snapshot + + + it 'compiles with str params', fn: + expect + fink2lir 'elem = ' + to_match_snapshot + + + it 'compiles hypenate props', fn: + expect + fink2lir 'elem = ' + to_match_snapshot + + + it 'compiles with expr params', fn: + expect + fink2lir 'elem = ' + to_match_snapshot + + expect + fink2lir "elem = " + to_match_snapshot + + + it 'compiles empty elem', fn: + expect + fink2lir 'elem = ' + to_match_snapshot + + + it 'compiles with children and expr', fn: + expect + fink2lir 'elem = + + foo {ni} + ham + spam + + ni + ' + to_match_snapshot + + + it 'compiles fragment', fn: + expect + fink2lir 'elem = <>' + to_match_snapshot + + + it 'compiles fragment with children', fn: + expect + fink2lir 'elem = + <> + foo +

bar

+ ' + to_match_snapshot + + + +describe 'JSX extensions', fn: + it 'compiles shothand props', fn: + expect + fink2lir '' + to_match_snapshot + + + it 'compiles spread', fn: + expect + fink2lir '' + to_match_snapshot + + + it "compiles template str attr", fn: + expect + fink2lir "" + to_match_snapshot + + + it "compiles fink expr as attr values", fn: + expect + fink2lir " foo " + to_match_snapshot + + + it "compiles fink expr with gt comparison", fn: + expect + fink2lir " 123} shrub=1234> ni " + to_match_snapshot + + + it "compiles expr group with call for attr value", fn: + expect + fink2lir "" + to_match_snapshot + + + it "compiles block", fn: + expect + fink2lir ' + + { + foo = spam _ + bar spam, foo, foo + } + + ' + to_match_snapshot + + diff --git a/src/ir/jsx/init.test.fnk.snap b/src/ir/jsx/init.test.fnk.snap new file mode 100644 index 0000000..cb68834 --- /dev/null +++ b/src/ir/jsx/init.test.fnk.snap @@ -0,0 +1,317 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`JSX extensions compiles block 1`] = ` +" +rec_e fn exports_0: + id Foobar, fn jsxi_0: + rec_e fn props_0: + lst_e fn chldrn_0: + str '\\\\n ', fn chld_0: + lst_a chldrn_0, chld_0, fn chldrn_1: + id spam, fn callee_0: + lst_e fn cargs_0: + af callee_0, cargs_0, fn foo_0: + id bar, fn callee_1: + lst_e fn cargs_1: + id spam, fn arg_0: + lst_a cargs_1, arg_0, fn cargs_2: + id foo_0, fn arg_1: + lst_a cargs_2, arg_1, fn cargs_3: + id foo_0, fn arg_2: + lst_a cargs_3, arg_2, fn cargs_4: + af callee_1, cargs_4, fn chld_1: + lst_a chldrn_1, chld_1, fn chldrn_2: + str '\\\\n', fn chld_2: + lst_a chldrn_2, chld_2, fn chldrn_3: + jxe jsxi_0, props_0, chldrn_3, fn mex_0: + lst_e fn drctvs_0: + mod exports_0, drctvs_0, fn mod_0:" +`; + +exports[`JSX extensions compiles expr group with call for attr value 1`] = ` +" +rec_e fn exports_0: + id Foobar, fn jsxi_0: + rec_e fn props_0: + str 'spam', fn prpn_0: + id ham, fn callee_0: + lst_e fn cargs_0: + id ni, fn arg_0: + lst_a cargs_0, arg_0, fn cargs_1: + af callee_0, cargs_1, fn prpv_0: + rec_s props_0, prpn_0, prpv_0, fn props_1: + str 'shrub', fn prpn_1: + int '1234', fn prpv_1: + rec_s props_1, prpn_1, prpv_1, fn props_2: + lst_e fn chldrn_0: + jxe jsxi_0, props_2, chldrn_0, fn mex_0: + lst_e fn drctvs_0: + mod exports_0, drctvs_0, fn mod_0:" +`; + +exports[`JSX extensions compiles fink expr as attr values 1`] = ` +" +rec_e fn exports_0: + id Foobar, fn jsxi_0: + rec_e fn props_0: + str 'spam', fn prpn_0: + id ham, fn prpv_0: + rec_s props_0, prpn_0, prpv_0, fn props_1: + str 'shrub', fn prpn_1: + int '1234', fn prpv_1: + rec_s props_1, prpn_1, prpv_1, fn props_2: + str 'ni', fn prpn_2: + int '123', fn right_0: + sub right_0, fn prpv_2: + rec_s props_2, prpn_2, prpv_2, fn props_3: + lst_e fn chldrn_0: + str ' foo ', fn chld_0: + lst_a chldrn_0, chld_0, fn chldrn_1: + jxe jsxi_0, props_3, chldrn_1, fn mex_0: + lst_e fn drctvs_0: + mod exports_0, drctvs_0, fn mod_0:" +`; + +exports[`JSX extensions compiles fink expr with gt comparison 1`] = ` +" +rec_e fn exports_0: + id Foobar, fn jsxi_0: + rec_e fn props_0: + str 'spam', fn prpn_0: + id foo, fn left_0: + int '123', fn right_0: + gt left_0, right_0, fn prpv_0: + rec_s props_0, prpn_0, prpv_0, fn props_1: + str 'shrub', fn prpn_1: + int '1234', fn prpv_1: + rec_s props_1, prpn_1, prpv_1, fn props_2: + lst_e fn chldrn_0: + str ' ni ', fn chld_0: + lst_a chldrn_0, chld_0, fn chldrn_1: + jxe jsxi_0, props_2, chldrn_1, fn mex_0: + lst_e fn drctvs_0: + mod exports_0, drctvs_0, fn mod_0:" +`; + +exports[`JSX extensions compiles shothand props 1`] = ` +" +rec_e fn exports_0: + id Foobar, fn jsxi_0: + rec_e fn props_0: + str 'spam', fn prpn_0: + id spam, fn prpv_0: + rec_s props_0, prpn_0, prpv_0, fn props_1: + str 'ham-ni', fn prpn_1: + id ham-ni, fn prpv_1: + rec_s props_1, prpn_1, prpv_1, fn props_2: + lst_e fn chldrn_0: + jxe jsxi_0, props_2, chldrn_0, fn mex_0: + lst_e fn drctvs_0: + mod exports_0, drctvs_0, fn mod_0:" +`; + +exports[`JSX extensions compiles spread 1`] = ` +" +rec_e fn exports_0: + id Foobar, fn jsxi_0: + rec_e fn props_0: + str 'spam', fn prpn_0: + id spam, fn prpv_0: + rec_s props_0, prpn_0, prpv_0, fn props_1: + id ham, fn sprd_0: + rec_m props_1, sprd_0, fn props_2: + str 'shrub', fn prpn_1: + id shrub, fn prpv_1: + rec_s props_2, prpn_1, prpv_1, fn props_3: + lst_e fn chldrn_0: + jxe jsxi_0, props_3, chldrn_0, fn mex_0: + lst_e fn drctvs_0: + mod exports_0, drctvs_0, fn mod_0:" +`; + +exports[`JSX extensions compiles template str attr 1`] = ` +" +rec_e fn exports_0: + id Foobar, fn jsxi_0: + rec_e fn props_0: + str 'spam', fn prpn_0: + str 'ni: ', fn str_0: + int '1', fn left_0: + int '2', fn right_0: + add left_0, right_0, fn sx_0: + str '', fn str_1: + strt str_0, sx_0, str_1, fn prpv_0: + rec_s props_0, prpn_0, prpv_0, fn props_1: + lst_e fn chldrn_0: + jxe jsxi_0, props_1, chldrn_0, fn mex_0: + lst_e fn drctvs_0: + mod exports_0, drctvs_0, fn mod_0:" +`; + +exports[`jsx compiles empty elem 1`] = ` +" +rec_e fn exports_0: + str 'b', fn jsxi_0: + rec_e fn props_0: + lst_e fn chldrn_0: + jxe jsxi_0, props_0, chldrn_0, fn elem_0: + str 'elem', fn key_0: + rec_s exports_0, key_0, elem_0, fn exports_1: + lst_e fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; + +exports[`jsx compiles fragment 1`] = ` +" +rec_e fn exports_0: + lst_e fn chldrn_0: + jxf chldrn_0, fn elem_0: + str 'elem', fn key_0: + rec_s exports_0, key_0, elem_0, fn exports_1: + lst_e fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; + +exports[`jsx compiles fragment with children 1`] = ` +" +rec_e fn exports_0: + lst_e fn chldrn_0: + str '\\\\n foo\\\\n ', fn chld_0: + lst_a chldrn_0, chld_0, fn chldrn_1: + str 'p', fn jsxi_0: + rec_e fn props_0: + lst_e fn chldrn_2: + str 'bar', fn chld_2: + lst_a chldrn_2, chld_2, fn chldrn_3: + jxe jsxi_0, props_0, chldrn_3, fn chld_1: + lst_a chldrn_1, chld_1, fn chldrn_4: + str '\\\\n', fn chld_3: + lst_a chldrn_4, chld_3, fn chldrn_5: + jxf chldrn_5, fn elem_0: + str 'elem', fn key_0: + rec_s exports_0, key_0, elem_0, fn exports_1: + lst_e fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; + +exports[`jsx compiles hypenate props 1`] = ` +" +rec_e fn exports_0: + str 'a', fn jsxi_0: + rec_e fn props_0: + str 'foo-bar', fn prpn_0: + str '1234', fn str_0: + strt str_0, fn prpv_0: + rec_s props_0, prpn_0, prpv_0, fn props_1: + lst_e fn chldrn_0: + jxe jsxi_0, props_1, chldrn_0, fn elem_0: + str 'elem', fn key_0: + rec_s exports_0, key_0, elem_0, fn exports_1: + lst_e fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; + +exports[`jsx compiles shorthand 1`] = ` +" +rec_e fn exports_0: + str 'a', fn jsxi_0: + rec_e fn props_0: + lst_e fn chldrn_0: + jxe jsxi_0, props_0, chldrn_0, fn elem_0: + str 'elem', fn key_0: + rec_s exports_0, key_0, elem_0, fn exports_1: + lst_e fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; + +exports[`jsx compiles with children and expr 1`] = ` +" +rec_e fn exports_0: + str 'a', fn jsxi_0: + rec_e fn props_0: + lst_e fn chldrn_0: + str '\\\\n foo ', fn chld_0: + lst_a chldrn_0, chld_0, fn chldrn_1: + id ni, fn chld_1: + lst_a chldrn_1, chld_1, fn chldrn_2: + str '\\\\n ', fn chld_2: + lst_a chldrn_2, chld_2, fn chldrn_3: + str 'b', fn jsxi_1: + rec_e fn props_1: + lst_e fn chldrn_4: + jxe jsxi_1, props_1, chldrn_4, fn chld_3: + lst_a chldrn_3, chld_3, fn chldrn_5: + str ' ham\\\\n spam\\\\n ', fn chld_4: + lst_a chldrn_5, chld_4, fn chldrn_6: + str 'c', fn jsxi_2: + rec_e fn props_2: + lst_e fn chldrn_7: + jxe jsxi_2, props_2, chldrn_7, fn chld_5: + lst_a chldrn_6, chld_5, fn chldrn_8: + str '\\\\n ni\\\\n', fn chld_6: + lst_a chldrn_8, chld_6, fn chldrn_9: + jxe jsxi_0, props_0, chldrn_9, fn elem_0: + str 'elem', fn key_0: + rec_s exports_0, key_0, elem_0, fn exports_1: + lst_e fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; + +exports[`jsx compiles with expr params 1`] = ` +" +rec_e fn exports_0: + str 'a', fn jsxi_0: + rec_e fn props_0: + str 'foo', fn prpn_0: + id foo, fn prpv_0: + rec_s props_0, prpn_0, prpv_0, fn props_1: + str 'bar', fn prpn_1: + int '1234', fn prpv_1: + rec_s props_1, prpn_1, prpv_1, fn props_2: + lst_e fn chldrn_0: + jxe jsxi_0, props_2, chldrn_0, fn elem_0: + str 'elem', fn key_0: + rec_s exports_0, key_0, elem_0, fn exports_1: + lst_e fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; + +exports[`jsx compiles with expr params 2`] = ` +" +rec_e fn exports_0: + str 'a', fn jsxi_0: + rec_e fn props_0: + str 'foo', fn prpn_0: + id foo, fn prpv_0: + rec_s props_0, prpn_0, prpv_0, fn props_1: + str 'bar', fn prpn_1: + str 'ni', fn str_0: + strt str_0, fn prpv_1: + rec_s props_1, prpn_1, prpv_1, fn props_2: + lst_e fn chldrn_0: + jxe jsxi_0, props_2, chldrn_0, fn elem_0: + str 'elem', fn key_0: + rec_s exports_0, key_0, elem_0, fn exports_1: + lst_e fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; + +exports[`jsx compiles with str params 1`] = ` +" +rec_e fn exports_0: + str 'a', fn jsxi_0: + rec_e fn props_0: + str 'foo', fn prpn_0: + id foo, fn prpv_0: + rec_s props_0, prpn_0, prpv_0, fn props_1: + str 'bar', fn prpn_1: + str 'ni', fn str_0: + strt str_0, fn prpv_1: + rec_s props_1, prpn_1, prpv_1, fn props_2: + lst_e fn chldrn_0: + jxe jsxi_0, props_2, chldrn_0, fn elem_0: + str 'elem', fn key_0: + rec_s exports_0, key_0, elem_0, fn exports_1: + lst_e fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; diff --git a/src/js/literals/init.fnk b/src/ir/literals/init.fnk similarity index 100% rename from src/js/literals/init.fnk rename to src/ir/literals/init.fnk diff --git a/src/ir/literals/keywords.fnk b/src/ir/literals/keywords.fnk new file mode 100644 index 0000000..c54f7b7 --- /dev/null +++ b/src/ir/literals/keywords.fnk @@ -0,0 +1,7 @@ +{let} = import '../identifier/init.fnk' + + +transform_keyword = fn {value, loc}, result, ctx: + # transform {type: 'ident', value, loc}, result, ctx, false + [exprs, , next_ctx] = let {i: value, loc}, result, {loc}, ctx + [exprs, next_ctx] diff --git a/src/ir/literals/keywords.test.fnk b/src/ir/literals/keywords.test.fnk new file mode 100644 index 0000000..44a3a55 --- /dev/null +++ b/src/ir/literals/keywords.test.fnk @@ -0,0 +1,12 @@ +{fink2lir} = import '../../testing/generate.fnk' +{describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' + + +describe 'keywords', fn: + it 'transforms literals', fn: + expect + fink2lir ' + x = false + y = true + ' + to_match_snapshot diff --git a/src/ir/literals/keywords.test.fnk.snap b/src/ir/literals/keywords.test.fnk.snap new file mode 100644 index 0000000..6e8ec95 --- /dev/null +++ b/src/ir/literals/keywords.test.fnk.snap @@ -0,0 +1,14 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`keywords transforms literals 1`] = ` +" +rec_e fn exports_0: + id false, fn x_0: + str 'x', fn key_0: + rec_s exports_0, key_0, x_0, fn exports_1: + id true, fn y_0: + str 'y', fn key_1: + rec_s exports_1, key_1, y_0, fn exports_2: + lst_e fn drctvs_0: + mod exports_2, drctvs_0, fn mod_0:" +`; diff --git a/src/ir/literals/list.fnk b/src/ir/literals/list.fnk new file mode 100644 index 0000000..058ae55 --- /dev/null +++ b/src/ir/literals/list.fnk @@ -0,0 +1,56 @@ +{reverse} = import '@fink/std-lib/iter.fnk' +{transform} = import '../transform.fnk' +{unique_or_id, ir_fn} = import '../context.fnk' + + + +lst = fn name_or_id, {loc}, ctx: + ir_fn 'lst', [], name_or_id, {loc}, ctx + + +lst_a = fn lst_id, val_id, name_or_id, {loc}, ctx: + ir_fn 'lst_a', [lst_id, val_id], name_or_id, {loc}, ctx + + +lst_c = fn lst1_id, lst2_id, name_or_id, {loc}, ctx: + ir_fn 'lst_c', [lst1_id, lst2_id], name_or_id, {loc}, ctx + + + +transform_item = fn expr, out_id, ctx: + # could be removed using name in lst_* funcs + [lst_id, item_ctx] = unique_or_id 'lst', expr, ctx + match expr: + {type: 'spread'}: + [items, items_id, lst_ctx] = transform expr.right, 'items', item_ctx + [lst, , next_ctx] = lst_c lst_id, items_id, out_id, expr, lst_ctx + [[...items, ...lst], lst_id , next_ctx] + + # TODO use own transform for empty + {type: 'empty'}: + [lst, , next_ctx] = lst_a lst_id, {i: '_', loc: expr.loc}, out_id, expr, item_ctx + [lst, lst_id, next_ctx] + + else: + [item, item_id, lst_ctx] = transform expr, 'item', item_ctx + [lst, , next_ctx] = lst_a lst_id, item_id, out_id, expr, lst_ctx + [[...item, ...lst], lst_id, next_ctx] + + + +transform_items = fn [expr=false, ...rest], ctx, result_id, out=[]: + match expr: + false: + [out, result_id, ctx] + else: + [item, list_id, next_ctx] = transform_item expr, result_id, ctx + transform_items rest, next_ctx, list_id, [...item, ...out] + + + +transform_list = fn node, result, ctx: + exprs = reverse node.exprs + [out, start_lst_id, next_ctx] = transform_items exprs, ctx, result + [expr, , end_ctx] = lst start_lst_id, node, next_ctx + [[...expr, ...out], end_ctx] + diff --git a/src/ir/literals/list.test.fnk b/src/ir/literals/list.test.fnk new file mode 100644 index 0000000..44917bf --- /dev/null +++ b/src/ir/literals/list.test.fnk @@ -0,0 +1,136 @@ +{skip, describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' +{fink2lir, fink2js} = import '../../testing/generate.fnk' + + +describe 'list', fn: + it 'compiles', fn: + expect + fink2lir ' + array1 = [] + array2 = [1] + array3 = [1, 2] + array4 = [1, , 2] + array5 = list: + a + 1 + 45 + + b + c + [1, 2] + (3 + 3) * 2 + ' + to_match_snapshot + + + it 'compiles spread', fn: + expect + fink2lir ' + array1 = [1, 2, ...b] + array2 = [1, 2, ...b, 3, 4] + ' + to_match_snapshot + + + skip.it 'compiles as partial', fn: + expect + fink2lir ' + [1, ...?, 9] + [?, ?] + ' + to_match_snapshot + + + +describe 'unpacking list', fn: + it 'destructures simple', fn: + expect + fink2lir ' + [a, [b, c]] = [1, [2, 3]] + foo = [b, a] + [z] = [1 + 2, 3 * 4] + [x, y] = foo + ' + to_match_snapshot + + + it 'destructures with defaults', fn: + expect + fink2lir ' + [a=12, b=34] = foo + out = [a, b] + ' + to_match_snapshot + + expect + fink2lir ' + [[a, b=0]=[1, 2], c=34] = foo + out = [a, b, c] + ' + to_match_snapshot + + + it 'destructures spread', fn: + expect + fink2lir " + [a, b, c] = ni + [, , d] = ni + [head, ...tail] = ni + [...items, last] = '1234' + [first, second, ...middle, penultimate, end] = '123' + [ni, ..., nu] = '123' + [..., nuna] = '123' + " + to_match_snapshot + + + it 'destructures recs', fn: + expect + fink2lir " + [{a, b}, c] = ni + " + to_match_snapshot + + + +describe 'optimizations', fn: + + it 'reuses item refs', fn: + expect + fink2lir ' + [a, [b, c]] = [1, [2, 3]] + foo = [b, a] + [z] = [1 + 2, 3 * 4] + [x, y] = foo + log a, b, c, foo, z, x, y + ', {optimize: {refs: true, tails: true, unused: true}} + to_match_snapshot + + + it 'optimizes spreads', fn: + expect + fink2js ' + y = [1, 2] + [..., spam] = y + [...sp, shrub] = [1, 2, 3] + [x] = sp + [...spl] = lala + log x, y, spl, lala, sp, shrub + ', {optimize: {refs: true, tails: true, unused: true}} + to_match_snapshot + + + it 'ignores empty concats', fn: + expect + fink2lir ' + foo = [...b] + ham = [] + spam = [foo, ...ham] + ', {optimize: {refs: true, tails: true, unused: true}} + to_match_snapshot + + + it 'removes tails', fn: + expect + fink2lir ' + [bar, spam, ham] = [...shrub] + ni = bar + spam + ham + ', {optimize: {refs: true, tails: true, unused: true}} + to_match_snapshot + diff --git a/src/ir/literals/list.test.fnk.snap b/src/ir/literals/list.test.fnk.snap new file mode 100644 index 0000000..f34cd62 --- /dev/null +++ b/src/ir/literals/list.test.fnk.snap @@ -0,0 +1,319 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`list compiles 1`] = ` +" +rec_e fn exports_0: + lst_e fn array1_0: + str 'array1', fn key_0: + rec_s exports_0, key_0, array1_0, fn exports_1: + lst_e fn lst_0: + int '1', fn item_0: + lst_a lst_0, item_0, fn array2_0: + str 'array2', fn key_1: + rec_s exports_1, key_1, array2_0, fn exports_2: + lst_e fn lst_2: + int '1', fn item_2: + lst_a lst_2, item_2, fn lst_1: + int '2', fn item_1: + lst_a lst_1, item_1, fn array3_0: + str 'array3', fn key_2: + rec_s exports_2, key_2, array3_0, fn exports_3: + lst_e fn lst_5: + int '1', fn item_4: + lst_a lst_5, item_4, fn lst_4: + lst_a lst_4, _, fn lst_3: + int '2', fn item_3: + lst_a lst_3, item_3, fn array4_0: + str 'array4', fn key_3: + rec_s exports_3, key_3, array4_0, fn exports_4: + lst_e fn lst_10: + id a, fn left_5: + int '1', fn right_2: + add left_5, right_2, fn left_4: + int '45', fn right_3: + add left_4, right_3, fn left_3: + id b, fn right_4: + add left_3, right_4, fn left_2: + id c, fn right_5: + add left_2, right_5, fn item_9: + lst_a lst_10, item_9, fn lst_7: + lst_e fn lst_9: + int '1', fn item_8: + lst_a lst_9, item_8, fn lst_8: + int '2', fn item_7: + lst_a lst_8, item_7, fn item_6: + lst_a lst_7, item_6, fn lst_6: + int '3', fn left_1: + int '3', fn right_0: + add left_1, right_0, fn left_0: + int '2', fn right_1: + mul left_0, right_1, fn item_5: + lst_a lst_6, item_5, fn array5_0: + str 'array5', fn key_4: + rec_s exports_4, key_4, array5_0, fn exports_5: + lst_e fn drctvs_0: + mod exports_5, drctvs_0, fn mod_0:" +`; + +exports[`list compiles spread 1`] = ` +" +rec_e fn exports_0: + lst_e fn lst_2: + int '1', fn item_1: + lst_a lst_2, item_1, fn lst_1: + int '2', fn item_0: + lst_a lst_1, item_0, fn lst_0: + id b, fn items_0: + lst_c lst_0, items_0, fn array1_0: + str 'array1', fn key_0: + rec_s exports_0, key_0, array1_0, fn exports_1: + lst_e fn lst_7: + int '1', fn item_5: + lst_a lst_7, item_5, fn lst_6: + int '2', fn item_4: + lst_a lst_6, item_4, fn lst_5: + id b, fn items_1: + lst_c lst_5, items_1, fn lst_4: + int '3', fn item_3: + lst_a lst_4, item_3, fn lst_3: + int '4', fn item_2: + lst_a lst_3, item_2, fn array2_0: + str 'array2', fn key_1: + rec_s exports_1, key_1, array2_0, fn exports_2: + lst_e fn drctvs_0: + mod exports_2, drctvs_0, fn mod_0:" +`; + +exports[`optimizations ignores empty concats 1`] = ` +" +rec_e fn exports_0: + tpl, fn lst_0: + lst_c lst_0, b, fn foo_0: + str 'foo', fn key_0: + rec_s exports_0, key_0, foo_0, fn exports_1: + tpl, fn ham_0: + str 'ham', fn key_1: + rec_s exports_1, key_1, ham_0, fn exports_2: + tpl foo_0, fn spam_0: + str 'spam', fn key_2: + rec_s exports_2, key_2, spam_0, fn exports_3: + tpl, fn drctvs_0: + mod exports_3, drctvs_0, fn mod_0:" +`; + +exports[`optimizations optimizes spreads 1`] = ` +"const y_0 = [1, 2]; +log(1, y_0, lala, lala, [1, 2], 3); +export const y = y_0;" +`; + +exports[`optimizations removes tails 1`] = ` +" +rec_e fn exports_0: + tpl, fn lst_0: + lst_c lst_0, shrub, fn dlst_0: + tpl_i dlst_0, 0, fn bar_0: + tpl_i dlst_0, 1, fn spam_0: + tpl_i dlst_0, 2, fn ham_0: + add bar_0, spam_0, fn left_0: + add left_0, ham_0, fn ni_0: + str 'ni', fn key_0: + rec_s exports_0, key_0, ni_0, fn exports_1: + tpl, fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; + +exports[`optimizations reuses item refs 1`] = ` +" +rec_e fn exports_0: + int '1', fn item_3: + int '2', fn item_2: + int '3', fn item_1: + tpl item_2, item_3, fn foo_0: + str 'foo', fn key_0: + rec_s exports_0, key_0, foo_0, fn exports_1: + int '1', fn left_1: + int '2', fn right_1: + add left_1, right_1, fn item_7: + tpl item_3, item_2, item_1, foo_0, item_7, item_2, item_3, fn cargs_7: + af log, cargs_7, fn mex_3: + tpl, fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; + +exports[`unpacking list destructures recs 1`] = ` +" +rec_e fn exports_0: + id ni, fn dlst_0: + lst_h dlst_0, fn drec_0: + lst_t dlst_0, fn tail_0: + str 'a', fn key_0: + rec_g drec_0, key_0, fn a_0: + str 'b', fn key_1: + rec_g drec_0, key_1, fn b_0: + lst_h tail_0, fn c_0: + lst_t tail_0, fn tail_1: + lst_e fn drctvs_0: + mod exports_0, drctvs_0, fn mod_0:" +`; + +exports[`unpacking list destructures simple 1`] = ` +" +rec_e fn exports_0: + lst_e fn lst_3: + int '1', fn item_3: + lst_a lst_3, item_3, fn lst_0: + lst_e fn lst_2: + int '2', fn item_2: + lst_a lst_2, item_2, fn lst_1: + int '3', fn item_1: + lst_a lst_1, item_1, fn item_0: + lst_a lst_0, item_0, fn dlst_0: + lst_h dlst_0, fn a_0: + lst_t dlst_0, fn tail_0: + lst_h tail_0, fn dlst_1: + lst_t tail_0, fn tail_1: + lst_h dlst_1, fn b_0: + lst_t dlst_1, fn tail_2: + lst_h tail_2, fn c_0: + lst_t tail_2, fn tail_3: + lst_e fn lst_5: + id b_0, fn item_5: + lst_a lst_5, item_5, fn lst_4: + id a_0, fn item_4: + lst_a lst_4, item_4, fn foo_0: + str 'foo', fn key_0: + rec_s exports_0, key_0, foo_0, fn exports_1: + lst_e fn lst_7: + int '1', fn left_1: + int '2', fn right_1: + add left_1, right_1, fn item_7: + lst_a lst_7, item_7, fn lst_6: + int '3', fn left_0: + int '4', fn right_0: + mul left_0, right_0, fn item_6: + lst_a lst_6, item_6, fn dlst_2: + lst_h dlst_2, fn z_0: + lst_t dlst_2, fn tail_4: + id foo_0, fn dlst_3: + lst_h dlst_3, fn x_0: + lst_t dlst_3, fn tail_5: + lst_h tail_5, fn y_0: + lst_t tail_5, fn tail_6: + lst_e fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; + +exports[`unpacking list destructures spread 1`] = ` +" +rec_e fn exports_0: + id ni, fn dlst_0: + lst_h dlst_0, fn a_0: + lst_t dlst_0, fn tail_0: + lst_h tail_0, fn b_0: + lst_t tail_0, fn tail_1: + lst_h tail_1, fn c_0: + lst_t tail_1, fn tail_2: + id ni, fn dlst_1: + lst_h dlst_1, fn unused_0: + lst_t dlst_1, fn tail_3: + lst_h tail_3, fn unused_1: + lst_t tail_3, fn tail_4: + lst_h tail_4, fn d_0: + lst_t tail_4, fn tail_5: + id ni, fn dlst_2: + lst_h dlst_2, fn head_0: + lst_t dlst_2, fn tail_6: + lst_r tail_6, fn rtail_0: + lst_r rtail_0, fn tail_7: + str '1234', fn str_0: + strt str_0, fn dlst_3: + lst_r dlst_3, fn rtail_1: + lst_h rtail_1, fn last_0: + lst_t rtail_1, fn tail_8: + lst_r tail_8, fn items_0: + str '123', fn str_1: + strt str_1, fn dlst_4: + lst_h dlst_4, fn first_0: + lst_t dlst_4, fn tail_9: + lst_h tail_9, fn second_0: + lst_t tail_9, fn tail_10: + lst_r tail_10, fn rtail_2: + lst_h rtail_2, fn end_0: + lst_t rtail_2, fn tail_11: + lst_h tail_11, fn penultimate_0: + lst_t tail_11, fn tail_12: + lst_r tail_12, fn middle_0: + str '123', fn str_2: + strt str_2, fn dlst_5: + lst_h dlst_5, fn ni_0: + lst_t dlst_5, fn tail_13: + lst_r tail_13, fn rtail_3: + lst_h rtail_3, fn nu_0: + lst_t rtail_3, fn tail_14: + str '123', fn str_3: + strt str_3, fn dlst_6: + lst_r dlst_6, fn rtail_4: + lst_h rtail_4, fn nuna_0: + lst_t rtail_4, fn tail_15: + lst_e fn drctvs_0: + mod exports_0, drctvs_0, fn mod_0:" +`; + +exports[`unpacking list destructures with defaults 1`] = ` +" +rec_e fn exports_0: + id foo, fn dlst_0: + int '12', fn flbk_0: + lst_h dlst_0, fn hdm_0: + ifv hdm_0, hdm_0, flbk_0, fn a_0: + lst_t dlst_0, fn tail_0: + int '34', fn flbk_1: + lst_h tail_0, fn hdm_1: + ifv hdm_1, hdm_1, flbk_1, fn b_0: + lst_t tail_0, fn tail_1: + lst_e fn lst_1: + id a_0, fn item_1: + lst_a lst_1, item_1, fn lst_0: + id b_0, fn item_0: + lst_a lst_0, item_0, fn out_0: + str 'out', fn key_0: + rec_s exports_0, key_0, out_0, fn exports_1: + lst_e fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; + +exports[`unpacking list destructures with defaults 2`] = ` +" +rec_e fn exports_0: + id foo, fn dlst_0: + lst_e fn lst_1: + int '1', fn item_1: + lst_a lst_1, item_1, fn lst_0: + int '2', fn item_0: + lst_a lst_0, item_0, fn flbk_0: + lst_h dlst_0, fn hdm_0: + ifv hdm_0, hdm_0, flbk_0, fn dlst_1: + lst_t dlst_0, fn tail_0: + lst_h dlst_1, fn a_0: + lst_t dlst_1, fn tail_1: + int '0', fn flbk_1: + lst_h tail_1, fn hdm_1: + ifv hdm_1, hdm_1, flbk_1, fn b_0: + lst_t tail_1, fn tail_2: + int '34', fn flbk_2: + lst_h tail_0, fn hdm_2: + ifv hdm_2, hdm_2, flbk_2, fn c_0: + lst_t tail_0, fn tail_3: + lst_e fn lst_4: + id a_0, fn item_4: + lst_a lst_4, item_4, fn lst_3: + id b_0, fn item_3: + lst_a lst_3, item_3, fn lst_2: + id c_0, fn item_2: + lst_a lst_2, item_2, fn out_0: + str 'out', fn key_0: + rec_s exports_0, key_0, out_0, fn exports_1: + lst_e fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; diff --git a/src/ir/literals/number.fnk b/src/ir/literals/number.fnk new file mode 100644 index 0000000..620df04 --- /dev/null +++ b/src/ir/literals/number.fnk @@ -0,0 +1,23 @@ + +{rx, matches} = import '@fink/std-lib/regex.fnk' +{ir_fn} = import '../context.fnk' + + +float = fn {value, loc}, res_id, ctx: + ir_fn 'float', [value], res_id, {loc}, ctx + + +int = fn {value, loc}, res_id, ctx: + ir_fn 'int', [value], res_id, {loc}, ctx + + + +transform_number = fn expr, res_id, ctx: + [exprs, , next_ctx] = match expr.value: + matches ?, rx'\.': + float expr, res_id, ctx + else: + int expr, res_id, ctx + + [exprs, next_ctx] + diff --git a/src/ir/literals/number.test.fnk b/src/ir/literals/number.test.fnk new file mode 100644 index 0000000..ccbf888 --- /dev/null +++ b/src/ir/literals/number.test.fnk @@ -0,0 +1,36 @@ +{fink2lir} = import '../../testing/generate.fnk' +{describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' + + +describe 'numbers', fn: + it 'transforms integers', fn: + expect + fink2lir ' + x = 1234578 + y = 0123 + z = 123_456_789 + ' + to_match_snapshot + + + it 'transforms floats', fn: + expect + fink2lir ' + x = 1.234578 + y = 1.23e45 + z = 1.23e-45 + a = 1.23e+45 + ' + to_match_snapshot + + + it 'transforms hex, octet, binary', fn: + expect + fink2lir ' + h = 0x123456789ABCDEF0 + o = 0o12345670 + b = 0b01010 + ' + to_match_snapshot + + diff --git a/src/ir/literals/number.test.fnk.snap b/src/ir/literals/number.test.fnk.snap new file mode 100644 index 0000000..b5bb561 --- /dev/null +++ b/src/ir/literals/number.test.fnk.snap @@ -0,0 +1,52 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`numbers transforms floats 1`] = ` +" +rec_e fn exports_0: + float '1.234578', fn x_0: + str 'x', fn key_0: + rec_s exports_0, key_0, x_0, fn exports_1: + float '1.23e45', fn y_0: + str 'y', fn key_1: + rec_s exports_1, key_1, y_0, fn exports_2: + float '1.23e-45', fn z_0: + str 'z', fn key_2: + rec_s exports_2, key_2, z_0, fn exports_3: + float '1.23e+45', fn a_0: + str 'a', fn key_3: + rec_s exports_3, key_3, a_0, fn exports_4: + lst_e fn drctvs_0: + mod exports_4, drctvs_0, fn mod_0:" +`; + +exports[`numbers transforms hex, octet, binary 1`] = ` +" +rec_e fn exports_0: + int '0x123456789ABCDEF0', fn h_0: + str 'h', fn key_0: + rec_s exports_0, key_0, h_0, fn exports_1: + int '0o12345670', fn o_0: + str 'o', fn key_1: + rec_s exports_1, key_1, o_0, fn exports_2: + int '0b01010', fn b_0: + str 'b', fn key_2: + rec_s exports_2, key_2, b_0, fn exports_3: + lst_e fn drctvs_0: + mod exports_3, drctvs_0, fn mod_0:" +`; + +exports[`numbers transforms integers 1`] = ` +" +rec_e fn exports_0: + int '1234578', fn x_0: + str 'x', fn key_0: + rec_s exports_0, key_0, x_0, fn exports_1: + int '0123', fn y_0: + str 'y', fn key_1: + rec_s exports_1, key_1, y_0, fn exports_2: + int '123_456_789', fn z_0: + str 'z', fn key_2: + rec_s exports_2, key_2, z_0, fn exports_3: + lst_e fn drctvs_0: + mod exports_3, drctvs_0, fn mod_0:" +`; diff --git a/src/ir/literals/record.fnk b/src/ir/literals/record.fnk new file mode 100644 index 0000000..7cc9637 --- /dev/null +++ b/src/ir/literals/record.fnk @@ -0,0 +1,92 @@ +{reverse} = import '@fink/std-lib/iter.fnk' +{transform} = import '../transform.fnk' +{unique_or_id, ir_fn} = import '../context.fnk' + +{str} = import './string.fnk' + + + +rec_m = fn rec1_id, rec2_id, name_or_id, {loc}, ctx: + ir_fn 'rec_m', [rec1_id, rec2_id], name_or_id, {loc}, ctx + + +rec_s = fn rec_id, key_id, val_id, name_or_id, {loc}, ctx: + ir_fn 'rec_s', [rec_id, key_id, val_id], name_or_id, {loc}, ctx + + +rec_e = fn name_or_id, {loc}, ctx: + ir_fn 'rec', [], name_or_id, {loc}, ctx + + + +members_as_rec = fn expr, val: + match expr: + {type: 'member'}: + kv = {type: 'rec:kv', left: expr.right, right: val} + nval = {type: 'rec', exprs: [kv], loc: expr.loc} + members_as_rec expr.left, nval + else: + kv = {type: 'rec:kv', left: expr, right: val} + {type: 'rec', exprs: [kv], loc: expr.loc} + + + +transform_key = fn expr, ctx: + match expr: + {type: 'ident'}: + str expr.value, 'key', expr, ctx + else: + transform expr, 'key', ctx + + + +transform_val = fn expr, key_id, ctx: + match expr: + {left: {type: 'ident'}, right: false}: + transform expr.left, 'val', ctx + + {right: false}: + [[], key_id, ctx] + + else: + transform expr.right, 'val', ctx + + + +transform_kv = fn expr, out_id, ctx: + [rec_id, key_ctx] = unique_or_id 'rec', expr, ctx + match expr: + {type: 'spread'}: + [val, val_id, rec_ctx] = transform expr.right, 'sprd', key_ctx + [rec_exprs, , next_ctx] = rec_m rec_id, val_id, out_id, expr, rec_ctx + [[...val, ...rec_exprs], rec_id , next_ctx] + + else: + [key, key_id, val_ctx] = transform_key expr.left, key_ctx + [val, val_id, rec_ctx] = transform_val expr, key_id, val_ctx + [rec_exprs, , next_ctx] = rec_s rec_id, key_id, val_id, out_id, expr, rec_ctx + [[...key, ...val, ...rec_exprs], rec_id, next_ctx] + + + +transform_entries = fn [expr=false, ...rest], ctx, result_id, out=[]: + match expr: + false: + [out, result_id, ctx] + + {left.type: 'member'}: + {exprs} = members_as_rec expr.left, expr.right + transform_entries [...exprs, ...rest], ctx, result_id, out + + else: + [kv, rec_id, next_ctx] = transform_kv expr, result_id, ctx + transform_entries rest, next_ctx, rec_id, [...kv, ...out] + + + +transform_record = fn node, result, ctx: + exprs = reverse node.exprs + [out, rec_id, rec_ctx] = transform_entries exprs, ctx, result + [rec_exprs, , next_ctx] = rec_e rec_id, node, rec_ctx + [[...rec_exprs, ...out], next_ctx] + diff --git a/src/ir/literals/record.test.fnk b/src/ir/literals/record.test.fnk new file mode 100644 index 0000000..dfc461f --- /dev/null +++ b/src/ir/literals/record.test.fnk @@ -0,0 +1,129 @@ +{describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' +{fink2lir} = import '../../testing/generate.fnk' + + +describe 'record', fn: + it 'compiles simple', fn: + expect + fink2lir 'foo = {}' + to_match_snapshot + + + it 'compiles shorthand', fn: + expect + fink2lir 'shrub = {foo, π, ƒ, foo-bar}' + to_match_snapshot + + expect + fink2lir 'foo = {a, delete, true, false}' + to_match_snapshot + + expect + fink2lir "foo = {'foo'}" + to_match_snapshot + + + it 'compiles spread', fn: + expect + fink2lir 'foo = {a, b, ...c}' + to_match_snapshot + + + it 'compiles key:val', fn: + expect + fink2lir "foo = {a: 1, b: 123, 'c-d-e': cde}" + to_match_snapshot + + expect + fink2lir ' + obj7 = {a: 123, b: 123 and 123 and 1345, c: fn a, b: 134} + ' + to_match_snapshot + + + it 'compiles calculaged props', fn: + expect + fink2lir " + foo = rec: + 'spam': 456 + 'spam-\${ham}': 'ni' + " + to_match_snapshot + + + it 'compiles member expr as keys', fn: + expect + fink2lir "foo = {...bar, spam.ham.ni: 'ni', na: 1234, ...nu}" + to_match_snapshot + + expect + fink2lir "foo = {...bar, spam.ham: {ni.na: 'ni'}, ...nu}" + to_match_snapshot + + + + +describe 'unpacking record', fn: + it 'compiles simple', fn: + expect + fink2lir "{a, 'b': b, (foo bar): {c}} = ni" + to_match_snapshot + + + it 'compiles nested', fn: + expect + fink2lir "{a, b: {c, d}, e} = ni" + to_match_snapshot + + expect + fink2lir "{a, b: [c, d], e} = ni" + to_match_snapshot + + + it 'compiles spread', fn: + expect + fink2lir '{a, a: {b, c}, ...f} = foo' + to_match_snapshot + + + it 'destructuress tpls', fn: + expect + fink2lir '{foo: [bar, spam]} = shrub' + to_match_snapshot + + + it 'compiles empty', fn: + expect + fink2lir '{foo: _, bar} = shrub' + to_match_snapshot + + + it 'compiles defaults', fn: + expect + fink2lir '{x=1, π: pi=2, ni: {y, z}} = foo' + to_match_snapshot + + + it 'compiles member expr as keys', fn: + expect + fink2lir "{spam.ham.ni: ni, ...rest} = foo" + to_match_snapshot + + expect + fink2lir "{spam.ham.ni: {ni: nu, foo.bar: bar}, ...rest} = foo" + to_match_snapshot + + expect + fink2lir "{foo-bar.spam-ham.ni: {ni: nu, foo.bar: bar}, ...rest} = foo" + to_match_snapshot + + + +describe 'rec optimizations', fn: + it 'optimizes key-refs', fn: + expect + fink2lir + 'foo = {π, ƒ, foo-bar}' + {optimize: {refs: true, tails: true, unused: true}} + to_match_snapshot + diff --git a/src/ir/literals/record.test.fnk.snap b/src/ir/literals/record.test.fnk.snap new file mode 100644 index 0000000..e559676 --- /dev/null +++ b/src/ir/literals/record.test.fnk.snap @@ -0,0 +1,406 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`rec optimizations optimizes key-refs 1`] = ` +" +rec_e fn exports_0: + rec_e fn rec_2: + str 'π', fn key_2: + rec_s rec_2, key_2, π, fn rec_1: + str 'ƒ', fn key_1: + rec_s rec_1, key_1, ƒ, fn rec_0: + str 'foo-bar', fn key_0: + rec_s rec_0, key_0, foo-bar, fn foo_0: + str 'foo', fn key_3: + rec_s exports_0, key_3, foo_0, fn exports_1: + tpl, fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; + +exports[`record compiles calculaged props 1`] = ` +" +rec_e fn exports_0: + rec_e fn rec_1: + str 'spam', fn str_3: + strt str_3, fn key_1: + int '456', fn val_1: + rec_s rec_1, key_1, val_1, fn rec_0: + str 'spam-', fn str_0: + id ham, fn sx_0: + str '', fn str_1: + strt str_0, sx_0, str_1, fn key_0: + str 'ni', fn str_2: + strt str_2, fn val_0: + rec_s rec_0, key_0, val_0, fn foo_0: + str 'foo', fn key_2: + rec_s exports_0, key_2, foo_0, fn exports_1: + lst_e fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; + +exports[`record compiles key:val 1`] = ` +" +rec_e fn exports_0: + rec_e fn rec_2: + str 'a', fn key_2: + int '1', fn val_2: + rec_s rec_2, key_2, val_2, fn rec_1: + str 'b', fn key_1: + int '123', fn val_1: + rec_s rec_1, key_1, val_1, fn rec_0: + str 'c-d-e', fn str_0: + strt str_0, fn key_0: + id cde, fn val_0: + rec_s rec_0, key_0, val_0, fn foo_0: + str 'foo', fn key_3: + rec_s exports_0, key_3, foo_0, fn exports_1: + lst_e fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; + +exports[`record compiles key:val 2`] = ` +" +rec_e fn exports_0: + rec_e fn rec_2: + str 'a', fn key_2: + int '123', fn val_2: + rec_s rec_2, key_2, val_2, fn rec_1: + str 'b', fn key_1: + int '123', fn left_0: + int '123', fn left_1: + int '1345', fn right_1: + and left_1, right_1, fn right_0: + and left_0, right_0, fn val_1: + rec_s rec_1, key_1, val_1, fn rec_0: + str 'c', fn key_0: + id (fn args_0, ret_0: #fn + lst_h args_0, fn a_0: + lst_t args_0, fn tail_0: + lst_h tail_0, fn b_0: + lst_t tail_0, fn tail_1: + int '134', fn result_0: + cc ret_0, result_0 + ), fn val_0: + rec_s rec_0, key_0, val_0, fn obj7_0: + str 'obj7', fn key_3: + rec_s exports_0, key_3, obj7_0, fn exports_1: + lst_e fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; + +exports[`record compiles member expr as keys 1`] = ` +" +rec_e fn exports_0: + rec_e fn rec_5: + id bar, fn sprd_1: + rec_m rec_5, sprd_1, fn rec_2: + str 'spam', fn key_1: + rec_e fn rec_3: + str 'ham', fn key_2: + rec_e fn rec_4: + str 'ni', fn key_3: + str 'ni', fn str_0: + strt str_0, fn val_3: + rec_s rec_4, key_3, val_3, fn val_2: + rec_s rec_3, key_2, val_2, fn val_1: + rec_s rec_2, key_1, val_1, fn rec_1: + str 'na', fn key_0: + int '1234', fn val_0: + rec_s rec_1, key_0, val_0, fn rec_0: + id nu, fn sprd_0: + rec_m rec_0, sprd_0, fn foo_0: + str 'foo', fn key_4: + rec_s exports_0, key_4, foo_0, fn exports_1: + lst_e fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; + +exports[`record compiles member expr as keys 2`] = ` +" +rec_e fn exports_0: + rec_e fn rec_5: + id bar, fn sprd_1: + rec_m rec_5, sprd_1, fn rec_1: + str 'spam', fn key_0: + rec_e fn rec_2: + str 'ham', fn key_1: + rec_e fn rec_3: + str 'ni', fn key_2: + rec_e fn rec_4: + str 'na', fn key_3: + str 'ni', fn str_0: + strt str_0, fn val_3: + rec_s rec_4, key_3, val_3, fn val_2: + rec_s rec_3, key_2, val_2, fn val_1: + rec_s rec_2, key_1, val_1, fn val_0: + rec_s rec_1, key_0, val_0, fn rec_0: + id nu, fn sprd_0: + rec_m rec_0, sprd_0, fn foo_0: + str 'foo', fn key_4: + rec_s exports_0, key_4, foo_0, fn exports_1: + lst_e fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; + +exports[`record compiles shorthand 1`] = ` +" +rec_e fn exports_0: + rec_e fn rec_3: + str 'foo', fn key_3: + id foo, fn val_3: + rec_s rec_3, key_3, val_3, fn rec_2: + str 'π', fn key_2: + id π, fn val_2: + rec_s rec_2, key_2, val_2, fn rec_1: + str 'ƒ', fn key_1: + id ƒ, fn val_1: + rec_s rec_1, key_1, val_1, fn rec_0: + str 'foo-bar', fn key_0: + id foo-bar, fn val_0: + rec_s rec_0, key_0, val_0, fn shrub_0: + str 'shrub', fn key_4: + rec_s exports_0, key_4, shrub_0, fn exports_1: + lst_e fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; + +exports[`record compiles shorthand 2`] = ` +" +rec_e fn exports_0: + rec_e fn rec_3: + str 'a', fn key_3: + id a, fn val_3: + rec_s rec_3, key_3, val_3, fn rec_2: + str 'delete', fn key_2: + id delete, fn val_2: + rec_s rec_2, key_2, val_2, fn rec_1: + str 'true', fn key_1: + id true, fn val_1: + rec_s rec_1, key_1, val_1, fn rec_0: + str 'false', fn key_0: + id false, fn val_0: + rec_s rec_0, key_0, val_0, fn foo_0: + str 'foo', fn key_4: + rec_s exports_0, key_4, foo_0, fn exports_1: + lst_e fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; + +exports[`record compiles shorthand 3`] = ` +" +rec_e fn exports_0: + rec_e fn rec_0: + str 'foo', fn str_0: + strt str_0, fn key_0: + rec_s rec_0, key_0, key_0, fn foo_0: + str 'foo', fn key_1: + rec_s exports_0, key_1, foo_0, fn exports_1: + lst_e fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; + +exports[`record compiles simple 1`] = ` +" +rec_e fn exports_0: + rec_e fn foo_0: + str 'foo', fn key_0: + rec_s exports_0, key_0, foo_0, fn exports_1: + lst_e fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; + +exports[`record compiles spread 1`] = ` +" +rec_e fn exports_0: + rec_e fn rec_2: + str 'a', fn key_1: + id a, fn val_1: + rec_s rec_2, key_1, val_1, fn rec_1: + str 'b', fn key_0: + id b, fn val_0: + rec_s rec_1, key_0, val_0, fn rec_0: + id c, fn sprd_0: + rec_m rec_0, sprd_0, fn foo_0: + str 'foo', fn key_2: + rec_s exports_0, key_2, foo_0, fn exports_1: + lst_e fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; + +exports[`unpacking record compiles defaults 1`] = ` +" +rec_e fn exports_0: + id foo, fn drec_0: + int '1', fn flbk_0: + str 'x', fn key_0: + rec_g drec_0, key_0, fn hdm_0: + ifv hdm_0, hdm_0, flbk_0, fn x_0: + int '2', fn flbk_1: + str 'π', fn key_1: + rec_g drec_0, key_1, fn hdm_1: + ifv hdm_1, hdm_1, flbk_1, fn pi_0: + str 'ni', fn key_2: + rec_g drec_0, key_2, fn val_0: + str 'y', fn key_3: + rec_g val_0, key_3, fn y_0: + str 'z', fn key_4: + rec_g val_0, key_4, fn z_0: + lst_e fn drctvs_0: + mod exports_0, drctvs_0, fn mod_0:" +`; + +exports[`unpacking record compiles empty 1`] = ` +" +rec_e fn exports_0: + id shrub, fn drec_0: + str 'foo', fn key_0: + rec_g drec_0, key_0, fn val_0: + str 'bar', fn key_1: + rec_g drec_0, key_1, fn bar_0: + lst_e fn drctvs_0: + mod exports_0, drctvs_0, fn mod_0:" +`; + +exports[`unpacking record compiles member expr as keys 1`] = ` +" +rec_e fn exports_0: + id foo, fn drec_0: + str 'spam', fn key_0: + rec_g drec_0, key_0, fn val_0: + str 'ham', fn key_1: + rec_g val_0, key_1, fn val_1: + str 'ni', fn key_2: + rec_g val_1, key_2, fn ni_0: + rec_d drec_0, key_0, fn rest_0: + lst_e fn drctvs_0: + mod exports_0, drctvs_0, fn mod_0:" +`; + +exports[`unpacking record compiles member expr as keys 2`] = ` +" +rec_e fn exports_0: + id foo, fn drec_0: + str 'spam', fn key_0: + rec_g drec_0, key_0, fn val_0: + str 'ham', fn key_1: + rec_g val_0, key_1, fn val_1: + str 'ni', fn key_2: + rec_g val_1, key_2, fn val_2: + str 'ni', fn key_3: + rec_g val_2, key_3, fn nu_0: + str 'foo', fn key_4: + rec_g val_2, key_4, fn val_3: + str 'bar', fn key_5: + rec_g val_3, key_5, fn bar_0: + rec_d drec_0, key_0, fn rest_0: + lst_e fn drctvs_0: + mod exports_0, drctvs_0, fn mod_0:" +`; + +exports[`unpacking record compiles member expr as keys 3`] = ` +" +rec_e fn exports_0: + id foo, fn drec_0: + str 'foo-bar', fn key_0: + rec_g drec_0, key_0, fn val_0: + str 'spam-ham', fn key_1: + rec_g val_0, key_1, fn val_1: + str 'ni', fn key_2: + rec_g val_1, key_2, fn val_2: + str 'ni', fn key_3: + rec_g val_2, key_3, fn nu_0: + str 'foo', fn key_4: + rec_g val_2, key_4, fn val_3: + str 'bar', fn key_5: + rec_g val_3, key_5, fn bar_0: + rec_d drec_0, key_0, fn rest_0: + lst_e fn drctvs_0: + mod exports_0, drctvs_0, fn mod_0:" +`; + +exports[`unpacking record compiles nested 1`] = ` +" +rec_e fn exports_0: + id ni, fn drec_0: + str 'a', fn key_0: + rec_g drec_0, key_0, fn a_0: + str 'b', fn key_1: + rec_g drec_0, key_1, fn val_0: + str 'c', fn key_2: + rec_g val_0, key_2, fn c_0: + str 'd', fn key_3: + rec_g val_0, key_3, fn d_0: + str 'e', fn key_4: + rec_g drec_0, key_4, fn e_0: + lst_e fn drctvs_0: + mod exports_0, drctvs_0, fn mod_0:" +`; + +exports[`unpacking record compiles nested 2`] = ` +" +rec_e fn exports_0: + id ni, fn drec_0: + str 'a', fn key_0: + rec_g drec_0, key_0, fn a_0: + str 'b', fn key_1: + rec_g drec_0, key_1, fn val_0: + lst_h val_0, fn c_0: + lst_t val_0, fn tail_0: + lst_h tail_0, fn d_0: + lst_t tail_0, fn tail_1: + str 'e', fn key_2: + rec_g drec_0, key_2, fn e_0: + lst_e fn drctvs_0: + mod exports_0, drctvs_0, fn mod_0:" +`; + +exports[`unpacking record compiles simple 1`] = ` +" +rec_e fn exports_0: + id ni, fn drec_0: + str 'a', fn key_0: + rec_g drec_0, key_0, fn a_0: + str 'b', fn str_0: + strt str_0, fn key_1: + rec_g drec_0, key_1, fn b_0: + id foo, fn callee_0: + lst_e fn cargs_0: + id bar, fn arg_0: + lst_a cargs_0, arg_0, fn cargs_1: + af callee_0, cargs_1, fn key_2: + rec_g drec_0, key_2, fn val_0: + str 'c', fn key_3: + rec_g val_0, key_3, fn c_0: + lst_e fn drctvs_0: + mod exports_0, drctvs_0, fn mod_0:" +`; + +exports[`unpacking record compiles spread 1`] = ` +" +rec_e fn exports_0: + id foo, fn drec_0: + str 'a', fn key_0: + rec_g drec_0, key_0, fn a_0: + str 'a', fn key_1: + rec_g drec_0, key_1, fn val_0: + str 'b', fn key_2: + rec_g val_0, key_2, fn b_0: + str 'c', fn key_3: + rec_g val_0, key_3, fn c_0: + rec_d drec_0, key_0, key_1, fn f_0: + lst_e fn drctvs_0: + mod exports_0, drctvs_0, fn mod_0:" +`; + +exports[`unpacking record destructuress tpls 1`] = ` +" +rec_e fn exports_0: + id shrub, fn drec_0: + str 'foo', fn key_0: + rec_g drec_0, key_0, fn val_0: + lst_h val_0, fn bar_0: + lst_t val_0, fn tail_0: + lst_h tail_0, fn spam_0: + lst_t tail_0, fn tail_1: + lst_e fn drctvs_0: + mod exports_0, drctvs_0, fn mod_0:" +`; diff --git a/src/ir/literals/regex.test.fnk b/src/ir/literals/regex.test.fnk new file mode 100644 index 0000000..d9c0d00 --- /dev/null +++ b/src/ir/literals/regex.test.fnk @@ -0,0 +1,37 @@ +{describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' +{raw} = import '@fink/std-lib/str.fnk' + +{fink2lir} = import '../../testing/generate.fnk' + + + +describe 'regex', fn: + it 'compiles single line', fn: + expect + fink2lir raw" + regex = rx'(?\d{4})-(?\d{2})-(?\d{2})' + " + to_match_snapshot + + + it 'compiles multiline', fn: + # TODO: loxia should handle this instead of runtime std-lib + expect + fink2lir raw" + regex = rx' + (?\d{4})- # year part of a date + (?\d{2})- # month part of a date + (?\d{2}) # day part of a date + ' + " + to_match_snapshot + + + it 'compiles escape char', fn: + expect + fink2lir raw" + regex = rx'.+/\#.+\\' + " + to_match_snapshot + + diff --git a/src/ir/literals/regex.test.fnk.snap b/src/ir/literals/regex.test.fnk.snap new file mode 100644 index 0000000..cc5477f --- /dev/null +++ b/src/ir/literals/regex.test.fnk.snap @@ -0,0 +1,37 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`regex compiles escape char 1`] = ` +" +rec_e fn exports_0: + id rx, fn tag_0: + str '.+/\\\\#.+\\\\\\\\', fn str_0: + strtt tag_0, str_0, fn regex_0: + str 'regex', fn key_0: + rec_s exports_0, key_0, regex_0, fn exports_1: + lst_e fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; + +exports[`regex compiles multiline 1`] = ` +" +rec_e fn exports_0: + id rx, fn tag_0: + str '(?\\\\d{4})- # year part of a date\\\\n(?\\\\d{2})- # month part of a date\\\\n(?\\\\d{2}) # day part of a date\\\\n', fn str_0: + strtt tag_0, str_0, fn regex_0: + str 'regex', fn key_0: + rec_s exports_0, key_0, regex_0, fn exports_1: + lst_e fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; + +exports[`regex compiles single line 1`] = ` +" +rec_e fn exports_0: + id rx, fn tag_0: + str '(?\\\\d{4})-(?\\\\d{2})-(?\\\\d{2})', fn str_0: + strtt tag_0, str_0, fn regex_0: + str 'regex', fn key_0: + rec_s exports_0, key_0, regex_0, fn exports_1: + lst_e fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; diff --git a/src/ir/literals/string.fnk b/src/ir/literals/string.fnk new file mode 100644 index 0000000..4e8f2a2 --- /dev/null +++ b/src/ir/literals/string.fnk @@ -0,0 +1,43 @@ +{transform} = import '../transform.fnk' +{ir_fn} = import '../context.fnk' + + + +str = fn value, name_or_id, {loc}, ctx: + ir_fn 'str', [value], name_or_id, {loc}, ctx + + +str_t = fn ids, name_or_id, {loc}, ctx: + ir_fn 'strt', ids, name_or_id, {loc}, ctx + + +str_tt = fn tag_id, ids, name_or_id, {loc}, ctx: + ir_fn 'strtt', [tag_id, ...ids], name_or_id, {loc}, ctx + + + +transform_parts = fn [expr=false, ...rest], ctx, ids=[], out=[]: + match expr: + false: + [out, ids, ctx] + + {type: 'string:text'}: + [exprs, str_id, next_ctx] = str expr.value, 'str', expr, ctx + transform_parts rest, next_ctx, [...ids, str_id], [...out, ...exprs] + + else: + [item, id, next_ctx] = transform expr, 'sx', ctx + transform_parts rest, next_ctx, [...ids, id], [...out, ...item] + + + +transform_string = fn node, result, ctx: + [out, ids, next_ctx] = transform_parts node.exprs, ctx + match node: + {tag: false}: + [expr, , end_ctx] = str_t ids, result, node, next_ctx + [[...out, ...expr], end_ctx] + else: + [tag, tag_id, st_ctx] = transform node.tag, 'tag', next_ctx + [expr, , end_ctx] = str_tt tag_id, ids, result, node, st_ctx + [[...tag, ...out, ...expr], end_ctx] diff --git a/src/ir/literals/string.test.fnk b/src/ir/literals/string.test.fnk new file mode 100644 index 0000000..7b30c5b --- /dev/null +++ b/src/ir/literals/string.test.fnk @@ -0,0 +1,54 @@ +{fink2lir} = import '../../testing/generate.fnk' +{describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' + + +describe 'string', fn: + + it 'compiles simple', fn: + expect + fink2lir " + str = 'ab' + " + to_match_snapshot + + + it 'compiles multiline', fn: + expect + fink2lir " + str = ' + line 1 + line 2 with leading space + line 3' + " + to_match_snapshot + + + it 'compiles escape chars', fn: + expect + fink2lir " + str1 = 'foo`bar\\nspam\\`ni' + str2 = \"foo\\\\\" + " + to_match_snapshot + + + it 'compiles tagged template string', fn: + expect + fink2lir " + str = foo'bar \${ni spam, shrub} na' + " + to_match_snapshot + + + it 'compiles multiline with expressions', fn: + expect + fink2lir " + str = ' + bar + spam \${shrub + ni}\${foo} + ni + ' + " + to_match_snapshot + + diff --git a/src/ir/literals/string.test.fnk.snap b/src/ir/literals/string.test.fnk.snap new file mode 100644 index 0000000..abadcf9 --- /dev/null +++ b/src/ir/literals/string.test.fnk.snap @@ -0,0 +1,75 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`string compiles escape chars 1`] = ` +" +rec_e fn exports_0: + str 'foo\`bar\\\\nspam\\\\\`ni', fn str_0: + strt str_0, fn str1_0: + str 'str1', fn key_0: + rec_s exports_0, key_0, str1_0, fn exports_1: + str 'foo\\\\\\\\', fn str_1: + strt str_1, fn str2_0: + str 'str2', fn key_1: + rec_s exports_1, key_1, str2_0, fn exports_2: + lst_e fn drctvs_0: + mod exports_2, drctvs_0, fn mod_0:" +`; + +exports[`string compiles multiline 1`] = ` +" +rec_e fn exports_0: + str 'line 1\\\\nline 2 with leading space\\\\nline 3', fn str_1: + strt str_1, fn str_0: + str 'str', fn key_0: + rec_s exports_0, key_0, str_0, fn exports_1: + lst_e fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; + +exports[`string compiles multiline with expressions 1`] = ` +" +rec_e fn exports_0: + str 'bar\\\\nspam ', fn str_1: + id shrub, fn left_0: + id ni, fn right_0: + add left_0, right_0, fn sx_0: + str '', fn str_2: + id foo, fn sx_1: + str '\\\\nni\\\\n', fn str_3: + strt str_1, sx_0, str_2, sx_1, str_3, fn str_0: + str 'str', fn key_0: + rec_s exports_0, key_0, str_0, fn exports_1: + lst_e fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; + +exports[`string compiles simple 1`] = ` +" +rec_e fn exports_0: + str 'ab', fn str_1: + strt str_1, fn str_0: + str 'str', fn key_0: + rec_s exports_0, key_0, str_0, fn exports_1: + lst_e fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; + +exports[`string compiles tagged template string 1`] = ` +" +rec_e fn exports_0: + id foo, fn tag_0: + str 'bar ', fn str_1: + id ni, fn callee_0: + lst_e fn cargs_0: + id spam, fn arg_0: + lst_a cargs_0, arg_0, fn cargs_1: + id shrub, fn arg_1: + lst_a cargs_1, arg_1, fn cargs_2: + af callee_0, cargs_2, fn sx_0: + str ' na', fn str_2: + strtt tag_0, str_1, sx_0, str_2, fn str_0: + str 'str', fn key_0: + rec_s exports_0, key_0, str_0, fn exports_1: + lst_e fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; diff --git a/src/ir/logical/in.fnk b/src/ir/logical/in.fnk new file mode 100644 index 0000000..70b5d36 --- /dev/null +++ b/src/ir/logical/in.fnk @@ -0,0 +1,10 @@ +{transform_binary} = import '../transform.fnk' + + + +transform_in = fn node, res_id, ctx: + transform_binary 'in', node.left, node.right, res_id, node, ctx + + + + diff --git a/src/ir/logical/in.test.fnk b/src/ir/logical/in.test.fnk new file mode 100644 index 0000000..7371d05 --- /dev/null +++ b/src/ir/logical/in.test.fnk @@ -0,0 +1,25 @@ +{fink2lir} = import '../../testing/generate.fnk' +{skip, describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' + + +describe 'in', fn: + it 'compiles with default runtime', fn: + expect + fink2lir " + foo = 1 in [1, 2, 3] + bar = '2' in '1234' + spam = key in {foo: bar} + shrub = item in ni + " + to_match_snapshot + + + skip.it 'compiles as partial', fn: + expect + fink2lir " + ? in [1, 2, 3] + foo in ? + " + to_match_snapshot + + diff --git a/src/ir/logical/in.test.fnk.snap b/src/ir/logical/in.test.fnk.snap new file mode 100644 index 0000000..73e0c7f --- /dev/null +++ b/src/ir/logical/in.test.fnk.snap @@ -0,0 +1,47 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`in compiles as partial 1`] = ` +"import { _in_ } from \\"@fink/js-interop/runtime.js\\"; + +ˆpartial => _in_(ˆpartial, [1, 2, 3]); + +ˆpartial => _in_(foo, ˆpartial);" +`; + +exports[`in compiles with default runtime 1`] = ` +" +rec_e fn exports_0: + int '1', fn left_0: + lst_e fn lst_2: + int '1', fn item_2: + lst_a lst_2, item_2, fn lst_1: + int '2', fn item_1: + lst_a lst_1, item_1, fn lst_0: + int '3', fn item_0: + lst_a lst_0, item_0, fn right_0: + in left_0, right_0, fn foo_0: + str 'foo', fn key_0: + rec_s exports_0, key_0, foo_0, fn exports_1: + str '2', fn str_0: + strt str_0, fn left_1: + str '1234', fn str_1: + strt str_1, fn right_1: + in left_1, right_1, fn bar_0: + str 'bar', fn key_1: + rec_s exports_1, key_1, bar_0, fn exports_2: + id key, fn left_2: + rec_e fn rec_0: + str 'foo', fn key_2: + id bar_0, fn val_0: + rec_s rec_0, key_2, val_0, fn right_2: + in left_2, right_2, fn spam_0: + str 'spam', fn key_3: + rec_s exports_2, key_3, spam_0, fn exports_3: + id item, fn left_3: + id ni, fn right_3: + in left_3, right_3, fn shrub_0: + str 'shrub', fn key_4: + rec_s exports_3, key_4, shrub_0, fn exports_4: + lst_e fn drctvs_0: + mod exports_4, drctvs_0, fn mod_0:" +`; diff --git a/src/ir/logical/init.fnk b/src/ir/logical/init.fnk new file mode 100644 index 0000000..b9cc015 --- /dev/null +++ b/src/ir/logical/init.fnk @@ -0,0 +1,22 @@ +{add, any} = import '../context.fnk' +{transform_binary, transform_unary} = import '../transform.fnk' +{transform_in} = import './in.fnk' + + + +transform_not = fn node, res_id, ctx: + transform_unary node.op, node.right, res_id, node, ctx + + + +transform_logical = fn node, res_id, ctx: + transform_binary node.op, node.left, node.right, res_id, node, ctx + + + +add_logical = fn ctx: + pipe ctx: + add any, 'and', transform_logical + add any, 'or', transform_logical + add any, 'not', transform_not + add any, 'in', transform_in diff --git a/src/ir/logical/init.test.fnk b/src/ir/logical/init.test.fnk new file mode 100644 index 0000000..72b92f0 --- /dev/null +++ b/src/ir/logical/init.test.fnk @@ -0,0 +1,24 @@ +{fink2lir} = import '../../testing/generate.fnk' +{skip, describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' + + +describe 'logical', fn: + it 'compiles', fn: + expect + fink2lir " + foo = a or b or c + bar = a and b and c + spam = not a + " + to_match_snapshot + + + skip.it 'compiles as partial', fn: + expect + fink2lir " + ? or foo ? + ? and spam + not ? + " + to_match_snapshot + diff --git a/src/ir/logical/init.test.fnk.snap b/src/ir/logical/init.test.fnk.snap new file mode 100644 index 0000000..3497e66 --- /dev/null +++ b/src/ir/logical/init.test.fnk.snap @@ -0,0 +1,34 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`logical compiles 1`] = ` +" +rec_e fn exports_0: + id a, fn left_0: + id b, fn left_1: + id c, fn right_1: + or left_1, right_1, fn right_0: + or left_0, right_0, fn foo_0: + str 'foo', fn key_0: + rec_s exports_0, key_0, foo_0, fn exports_1: + id a, fn left_2: + id b, fn left_3: + id c, fn right_3: + and left_3, right_3, fn right_2: + and left_2, right_2, fn bar_0: + str 'bar', fn key_1: + rec_s exports_1, key_1, bar_0, fn exports_2: + id a, fn right_4: + not right_4, fn spam_0: + str 'spam', fn key_2: + rec_s exports_2, key_2, spam_0, fn exports_3: + lst_e fn drctvs_0: + mod exports_3, drctvs_0, fn mod_0:" +`; + +exports[`logical compiles as partial 1`] = ` +"ˆpartial => ˆpartial || foo(ˆpartial); + +ˆpartial => ˆpartial && spam; + +ˆpartial => !ˆpartial;" +`; diff --git a/src/ir/module/import.fnk b/src/ir/module/import.fnk new file mode 100644 index 0000000..acfe56d --- /dev/null +++ b/src/ir/module/import.fnk @@ -0,0 +1,58 @@ +{ir_fn} = import '../context.fnk' +{transform} = import '../transform.fnk' +{bind} = import '../identifier/init.fnk' +{str} = import '../literals/string.fnk' + + + +impd = fn uri_id, res_id, {loc}, ctx: + ir_fn 'impd', [uri_id], res_id, {loc}, ctx + + + +imp = fn uri_id, key_id, res_id, {loc}, ctx: + match key_id: + false: ir_fn 'imp', [uri_id], res_id, {loc}, ctx + else: ir_fn 'imp', [uri_id, key_id], res_id, {loc}, ctx + + + + +get_key_val = fn expr, ctx: + [val_id, key_ctx] = match expr: + {right: false}: bind expr.left, ctx + {right.type: 'ident'}: bind expr.right, ctx + + [key, key_id, next_ctx] = str expr.left.value, 'key', expr.left, key_ctx + [key, key_id, val_id, next_ctx] + + + +transform_imp_rec = fn [expr=false, ...exprs], uri_id, ctx, out=[]: + match expr: + false: + [out, ctx] + + {type: 'rec:kv'}: + [key, key_id, val_id, imp_ctx] = get_key_val expr, ctx + [imps, , next_ctx] = imp uri_id, key_id, val_id, expr, imp_ctx + transform_imp_rec exprs, uri_id, next_ctx, [...out, ...key, ...imps] + + + +transform_imp = fn node, uri_id, ctx: + match node: + {type: 'rec'}: + transform_imp_rec node.exprs, uri_id, ctx + + {type: 'ident'}: + [val_id, imp_ctx] = bind node, ctx + [imps, , next_ctx] = imp uri_id, false, val_id, node, imp_ctx + [imps, next_ctx] + + + +transform_import = fn node, res_id, ctx: + [loc, loc_id, next_ctx] = transform node.right, 'src', ctx + [imps, , end_ctx] = impd loc_id, res_id, node, next_ctx + [[...loc, ...imps], end_ctx] diff --git a/src/ir/module/import.test.fnk b/src/ir/module/import.test.fnk new file mode 100644 index 0000000..1b9bed6 --- /dev/null +++ b/src/ir/module/import.test.fnk @@ -0,0 +1,41 @@ +{fink2lir} = import '../../testing/generate.fnk' +{describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' + + +describe 'import', fn: + it 'imports exported values', fn: + expect + fink2lir " + {bar} = import './spam.fnk' + {foo: spam} = import './shrub.fnk' + {π, delete} = import './ni.fnk' + {foo-bar} = import './ham.fnk' + " + to_match_snapshot + + + it 'imports as side effect', fn: + expect + fink2lir " + import './spam.fnk' + " + to_match_snapshot + + + it 'imports dynamically with static URL', fn: + expect + fink2lir " + ni = fn: import './shrub.fnk' + " + to_match_snapshot + + + it 'imports with dynamic URLs', fn: + expect + fink2lir " + shrub = fn: import foo + ni = fn: import '\${foo}' + na = fn: import './\${foo}.fnk' + " + to_match_snapshot + diff --git a/src/ir/module/import.test.fnk.snap b/src/ir/module/import.test.fnk.snap new file mode 100644 index 0000000..78c7df8 --- /dev/null +++ b/src/ir/module/import.test.fnk.snap @@ -0,0 +1,85 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`import imports as side effect 1`] = ` +" +rec_e fn exports_0: + str './spam.fnk', fn str_0: + strt str_0, fn uri_0: + imp uri_0, fn sidefx_0: + lst_e fn drctvs_0: + mod exports_0, drctvs_0, fn mod_0:" +`; + +exports[`import imports dynamically with static URL 1`] = ` +" +rec_e fn exports_0: + id (fn args_0, ret_0: #fn + str './shrub.fnk', fn str_0: + strt str_0, fn src_0: + impd src_0, fn result_0: + cc ret_0, result_0 + ), fn ni_0: + str 'ni', fn key_0: + rec_s exports_0, key_0, ni_0, fn exports_1: + lst_e fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; + +exports[`import imports exported values 1`] = ` +" +rec_e fn exports_0: + str './spam.fnk', fn str_0: + strt str_0, fn uri_0: + str 'bar', fn key_0: + imp uri_0, key_0, fn bar_0: + str './shrub.fnk', fn str_1: + strt str_1, fn uri_1: + str 'foo', fn key_1: + imp uri_1, key_1, fn spam_0: + str './ni.fnk', fn str_2: + strt str_2, fn uri_2: + str 'π', fn key_2: + imp uri_2, key_2, fn π_0: + str 'delete', fn key_3: + imp uri_2, key_3, fn delete_0: + str './ham.fnk', fn str_3: + strt str_3, fn uri_3: + str 'foo-bar', fn key_4: + imp uri_3, key_4, fn foo-bar_0: + lst_e fn drctvs_0: + mod exports_0, drctvs_0, fn mod_0:" +`; + +exports[`import imports with dynamic URLs 1`] = ` +" +rec_e fn exports_0: + id (fn args_0, ret_0: #fn + id foo, fn src_0: + impd src_0, fn result_0: + cc ret_0, result_0 + ), fn shrub_0: + str 'shrub', fn key_0: + rec_s exports_0, key_0, shrub_0, fn exports_1: + id (fn args_1, ret_1: #fn + str '', fn str_0: + id foo, fn sx_0: + str '', fn str_1: + strt str_0, sx_0, str_1, fn src_1: + impd src_1, fn result_1: + cc ret_1, result_1 + ), fn ni_0: + str 'ni', fn key_1: + rec_s exports_1, key_1, ni_0, fn exports_2: + id (fn args_2, ret_2: #fn + str './', fn str_2: + id foo, fn sx_1: + str '.fnk', fn str_3: + strt str_2, sx_1, str_3, fn src_2: + impd src_2, fn result_2: + cc ret_2, result_2 + ), fn na_0: + str 'na', fn key_2: + rec_s exports_2, key_2, na_0, fn exports_3: + lst_e fn drctvs_0: + mod exports_3, drctvs_0, fn mod_0:" +`; diff --git a/src/ir/module/init.fnk b/src/ir/module/init.fnk new file mode 100644 index 0000000..7ea6151 --- /dev/null +++ b/src/ir/module/init.fnk @@ -0,0 +1,89 @@ +{starts_with} = import '@fink/std-lib/str.fnk' +{add, any, ir_fn} = import '../context.fnk' +{transform} = import '../transform.fnk' +{str} = import '../literals/string.fnk' +{rec_e, rec_s} = import '../literals/record.fnk' +{lst, lst_a} = import '../literals/list.fnk' +{transform_import, transform_imp, imp} = import './import.fnk' + + + +mod = fn exp_id, dirs_id, res_id, {loc}, ctx: + ir_fn 'mod', [exp_id, dirs_id], res_id, {loc}, ctx + + + +ident_to_key = fn {value: name, loc}, ctx: + str name, 'key', {loc}, ctx + + + +add_export = fn exp_id, expr, ctx: + [val, , key_ctx] = transform expr, 'ares', ctx + [..., [ , [val_id]]] = val + + [key, key_id, exp_ctx] = ident_to_key expr.left, key_ctx + [rec_exprs, next_exp_id, next_ctx] = rec_s exp_id, key_id, val_id, 'exports', expr, exp_ctx + + [[...val, ...key, ...rec_exprs], next_exp_id, next_ctx] + + + +transform_exprs = fn [expr=false, ...rest], exp_id, ctx, out: + match expr: + false: + [out, exp_id, ctx] + + {right.op: 'import'}: + [uri, uri_id, next_ctx] = transform expr.right.right, 'uri', ctx + [imps, end_ctx] = transform_imp expr.left, uri_id, next_ctx + transform_exprs rest, exp_id, end_ctx, [...out, ...uri, ...imps] + + {op: 'import'}: + [uri, uri_id, imp_ctx] = transform expr.right, 'uri', ctx + [imps, , next_ctx] = imp uri_id, false, 'sidefx', expr, imp_ctx + transform_exprs rest, exp_id, next_ctx, [...out, ...uri, ...imps] + + {op: '=', left.type: 'ident'}: + [exprs, next_exp_id, next_ctx] = add_export exp_id, expr, ctx + transform_exprs rest, next_exp_id, next_ctx, [...out, ...exprs] + + else: + [foo, , next_ctx] = transform expr, 'mex', ctx + transform_exprs rest, exp_id, next_ctx, [...out, ...foo] + + + +transform_directives = fn expr, ctx: + # TODO: directives should be handled as separate AST node in larix + [drctvs, dirs_id, next_ctx] = lst 'drctvs', expr, ctx + + {exprs: [{comments}]} = expr + + match comments: + {leading: [{op: '#', loc: {start: {line: 1}}, value: starts_with ?, '!'}]}: + [{value: shbang}] = comments.leading + + [shb, sh_id, d_ctx] = str '#${shbang}', 'shbng', expr, next_ctx + [next_drctvs, lst_id, end_ctx] = lst_a dirs_id, sh_id, 'drctvs', expr, d_ctx + [[...drctvs, ...shb, ...next_drctvs], lst_id, end_ctx] + else: + [drctvs, dirs_id, next_ctx] + + + +transform_module = fn expr, result, ctx: + [exp_rec, exp_id, dirs_ctx] = rec_e 'exports', expr, ctx + [directives, dirs_id, exprs_ctx] = transform_directives expr, dirs_ctx + [block, last_exp_id, mod_ctx] = transform_exprs expr.exprs, exp_id, exprs_ctx, [] + [mod_exprs, , next_ctx] = mod last_exp_id, dirs_id, result, expr, mod_ctx + out = [...exp_rec, ...block, ...directives, ...mod_exprs] + [out, next_ctx] + + + +add_module = fn ctx: + pipe ctx: + add 'module', any, transform_module + add 'import', any, transform_import + diff --git a/src/ir/module/init.test.fnk b/src/ir/module/init.test.fnk new file mode 100644 index 0000000..27d80e0 --- /dev/null +++ b/src/ir/module/init.test.fnk @@ -0,0 +1,30 @@ +{fink2lir} = import '../../testing/generate.fnk' +{describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' + + +describe 'module', fn: + it 'handles comments', fn: + expect + fink2lir " + #!/usr/bin/env node + + # leading comment + + # expr comment + foo = 1234 + + # trailing comment + " + to_match_snapshot + + + it 'handles exports', fn: + expect + fink2lir " + delete = fn: true + π = fn: true + foo_bar = 1234 + foo-bar = 1234 + " + to_match_snapshot + diff --git a/src/ir/module/init.test.fnk.snap b/src/ir/module/init.test.fnk.snap new file mode 100644 index 0000000..4dd01b7 --- /dev/null +++ b/src/ir/module/init.test.fnk.snap @@ -0,0 +1,38 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`module handles comments 1`] = ` +" +rec_e fn exports_0: + int '1234', fn foo_0: + str 'foo', fn key_0: + rec_s exports_0, key_0, foo_0, fn exports_1: + lst_e fn drctvs_0: + str '#!/usr/bin/env node', fn shbng_0: + lst_a drctvs_0, shbng_0, fn drctvs_1: + mod exports_1, drctvs_1, fn mod_0:" +`; + +exports[`module handles exports 1`] = ` +" +rec_e fn exports_0: + id (fn args_0, ret_0: #fn + id true, fn result_0: + cc ret_0, result_0 + ), fn delete_0: + str 'delete', fn key_0: + rec_s exports_0, key_0, delete_0, fn exports_1: + id (fn args_1, ret_1: #fn + id true, fn result_1: + cc ret_1, result_1 + ), fn π_0: + str 'π', fn key_1: + rec_s exports_1, key_1, π_0, fn exports_2: + int '1234', fn foo_bar_0: + str 'foo_bar', fn key_2: + rec_s exports_2, key_2, foo_bar_0, fn exports_3: + int '1234', fn foo-bar_0: + str 'foo-bar', fn key_3: + rec_s exports_3, key_3, foo-bar_0, fn exports_4: + lst_e fn drctvs_0: + mod exports_4, drctvs_0, fn mod_0:" +`; diff --git a/src/ir/partial/init.fnk b/src/ir/partial/init.fnk new file mode 100644 index 0000000..b7b0902 --- /dev/null +++ b/src/ir/partial/init.fnk @@ -0,0 +1,23 @@ +{add, inc_ref, unique_or_id} = import '../context.fnk' + +{let} = import '../identifier/init.fnk' + + + +transform_partial = fn expr, result, ctx: + {partial_ident=false} = ctx + + [prtl, prtl_ctx] = match partial_ident: + false: unique_or_id 'prtl', expr, ctx + else: [partial_ident, ctx] + + next_ctx = inc_ref prtl, prtl_ctx + + [prt, , end_ctx] = let prtl, result, expr, {...next_ctx, partial_ident: prtl} + [prt, end_ctx] + + + +add_partial = fn ctx: + pipe ctx: + add 'partial', '?', transform_partial diff --git a/src/ir/prop-access/init.fnk b/src/ir/prop-access/init.fnk new file mode 100644 index 0000000..f2f17b1 --- /dev/null +++ b/src/ir/prop-access/init.fnk @@ -0,0 +1,24 @@ +{add, any} = import '../context.fnk' +{transform} = import '../transform.fnk' +{str} = import '../literals/string.fnk' +{rec_g} = import '../assignment/init.fnk' + + + +transform_member = fn {left, right, loc}, result, ctx: + [left_exprs, left_id, key_ctx] = transform left, 'left', ctx + + [key, key_id, rec_ctx] = match right: + {type: 'ident'}: + str right.value, 'key', right, key_ctx + else: + transform right, 'key', key_ctx + + [val, , next_ctx] = rec_g left_id, key_id, result, {loc}, rec_ctx + [[...left_exprs, ...key, ...val], next_ctx] + + + +add_member = fn ctx: + pipe ctx: + add any, '.', transform_member diff --git a/src/ir/prop-access/init.test.fnk b/src/ir/prop-access/init.test.fnk new file mode 100644 index 0000000..d0f5540 --- /dev/null +++ b/src/ir/prop-access/init.test.fnk @@ -0,0 +1,27 @@ +{fink2lir} = import '../../testing/generate.fnk' +{skip, describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' + + +describe 'member', fn: + it 'compiles', fn: + expect + fink2lir " + foo = spam.shrub + computed_member = item.'bar spam' + computed_member2 = item.(get_key foo) + reserved_prop = item.arguments + js_safe_unicode = [item.π, item.ƒ] + js_unsfae = item.foo-bar + " + to_match_snapshot + + + skip.it 'compiles partial', fn: + expect + fink2lir " + ?.foo + ?.foo.bar + ?.foo == bar + " + to_match_snapshot + diff --git a/src/ir/prop-access/init.test.fnk.snap b/src/ir/prop-access/init.test.fnk.snap new file mode 100644 index 0000000..8a89183 --- /dev/null +++ b/src/ir/prop-access/init.test.fnk.snap @@ -0,0 +1,57 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`member compiles 1`] = ` +" +rec_e fn exports_0: + id spam, fn left_0: + str 'shrub', fn key_0: + rec_g left_0, key_0, fn foo_0: + str 'foo', fn key_1: + rec_s exports_0, key_1, foo_0, fn exports_1: + id item, fn left_1: + str 'bar spam', fn str_0: + strt str_0, fn key_2: + rec_g left_1, key_2, fn computed_member_0: + str 'computed_member', fn key_3: + rec_s exports_1, key_3, computed_member_0, fn exports_2: + id item, fn left_2: + id get_key, fn callee_0: + lst_e fn cargs_0: + id foo_0, fn arg_0: + lst_a cargs_0, arg_0, fn cargs_1: + af callee_0, cargs_1, fn key_4: + rec_g left_2, key_4, fn computed_member2_0: + str 'computed_member2', fn key_5: + rec_s exports_2, key_5, computed_member2_0, fn exports_3: + id item, fn left_3: + str 'arguments', fn key_6: + rec_g left_3, key_6, fn reserved_prop_0: + str 'reserved_prop', fn key_7: + rec_s exports_3, key_7, reserved_prop_0, fn exports_4: + lst_e fn lst_1: + id item, fn left_5: + str 'π', fn key_9: + rec_g left_5, key_9, fn item_1: + lst_a lst_1, item_1, fn lst_0: + id item, fn left_4: + str 'ƒ', fn key_8: + rec_g left_4, key_8, fn item_0: + lst_a lst_0, item_0, fn js_safe_unicode_0: + str 'js_safe_unicode', fn key_10: + rec_s exports_4, key_10, js_safe_unicode_0, fn exports_5: + id item, fn left_6: + str 'foo-bar', fn key_11: + rec_g left_6, key_11, fn js_unsfae_0: + str 'js_unsfae', fn key_12: + rec_s exports_5, key_12, js_unsfae_0, fn exports_6: + lst_e fn drctvs_0: + mod exports_6, drctvs_0, fn mod_0:" +`; + +exports[`member compiles partial 1`] = ` +"ˆpartial => ˆpartial.foo; + +ˆpartial => ˆpartial.foo.bar; + +ˆpartial => ˆpartial.foo === bar;" +`; diff --git a/src/ir/serialize.fnk b/src/ir/serialize.fnk new file mode 100644 index 0000000..e924a78 --- /dev/null +++ b/src/ir/serialize.fnk @@ -0,0 +1,93 @@ +{replace_all, rx} = import '@fink/std-lib/regex.fnk' +{join} = import '@fink/std-lib/iter.fnk' + + + +a2s = fn [arg=false, ...args], out=[]: + match arg: + false: match out: + [?]: ' ${out | join ', '}' + else: '' + {i: ?}: + a2s args, [...out, arg.i] + else: + a2s args, [...out, arg] + + + +raw = fn s: + replace_all s, rx'(\n)', '\\n' + + +ops = rec: + '==': 'eq' + '!=': 'neq' + '>': 'gt' + '<': 'lt' + '>=': 'gte' + '<=': 'lte' + '+': 'add' + '-': 'sub' + '*': 'mul' + '^': 'pow' + '/': 'div' + '%': 'rem' + + +serialize = fn [curr=false, ...rest], out='', indent='': + match curr: + false: + out + + [{f: '='}]: + [{args: [val]}, ids] = curr + serialize + rest + '${out}\n${indent}id ${val.i}, fn${a2s ids}:' + ' ${indent}' + + [{f: ? in ['str', 'int', 'float']}]: + [{f, args: [val]}, ids] = curr + serialize + rest + '${out}\n${indent}${f} \'${raw val}\', fn${a2s ids}:' + ' ${indent}' + + [{f: ? in ['lst', 'rec']}]: + [{f}, ids] = curr + serialize + rest + '${out}\n${indent}${f}_e fn${a2s ids}:' + ' ${indent}' + + [{f: 'fn', args: [[?, ?, ?]]}]: + [{f: op, args: [args, body]}, ids] = curr + serialize + rest + '${out}\n${indent}z (fn${a2s args}: #${op}${serialize body, '', ' ${indent}'} + ${indent}), fn${a2s ids}:' + ' ${indent}' + + [{f: ? in ['cn', 'fn']}]: + [{f: op, args: [args, body]}, ids] = curr + serialize + rest + '${out}\n${indent}id (fn${a2s args}: #${op}${serialize body, '', ' ${indent}'} + ${indent}), fn${a2s ids}:' + ' ${indent}' + + [{f: ? in ['cc', 'cif', 'cf']}]: + [{f: op, args}] = curr + serialize + rest + '${out}\n${indent}${op}${a2s args}' + ' ${indent}' + + [, [?]]: + [{f, args}, ids] = curr + {(f): opf=f} = ops + serialize + rest + '${out}\n${indent}${opf}${a2s args}, fn${a2s ids}:' + ' ${indent}' + diff --git a/src/ir/transform.fnk b/src/ir/transform.fnk new file mode 100644 index 0000000..26f3f62 --- /dev/null +++ b/src/ir/transform.fnk @@ -0,0 +1,36 @@ +{throw_err} = import '@fink/js-interop/errors.fnk' +{transform_error} = import './errors.fnk' + +{get_transformer, unique_or_id, ir_fn} = import './context.fnk' + + + +transform = fn expr, name_or_id, ctx: + [id, next_ctx] = unique_or_id name_or_id, expr, ctx + + transform_expr = get_transformer expr, next_ctx + + [out, end_ctx] = match transform_expr: + ?: transform_expr expr, id, next_ctx + else: throw_err transform_error 'Unknown expression.', expr, next_ctx + + [out, id, end_ctx] + + + +transform_binary = fn op, left, right, res_id, {loc}, ctx: + [l, l_id, r_ctx] = transform left, 'left', ctx + [r, r_id, next_ctx] = transform right, 'right', r_ctx + + [exp, , end_ctx] = ir_fn op, [l_id, r_id], res_id, {loc}, next_ctx + [[...l, ...r, ...exp], end_ctx] + + + +transform_unary = fn op, right, res_id, {loc}, ctx: + [r, r_id, next_ctx] = transform right, 'right', ctx + + [exp, , end_ctx] = ir_fn op, [r_id], res_id, {loc}, next_ctx + [[...r, ...exp], end_ctx] + + diff --git a/src/js/arithmitic/init.fnk b/src/js/arithmitic/init.fnk index 93991f1..092ad16 100644 --- a/src/js/arithmitic/init.fnk +++ b/src/js/arithmitic/init.fnk @@ -1,42 +1,15 @@ -babel_types = import '@babel/types' -{binaryExpression, unaryExpression} = babel_types +{add} = import '../context.fnk' -{add, any} = import '../context.fnk' +{transform_binary, transform_binary_or_unary} = import '../transform.fnk' -{transform_with_partial_lr, transform_with_partial} = import '../partial/init.fnk' - -transform_op = rec: - '^': '**' - - - -transform_arithmitic = fn {op, left, right}, ctx: - {(op): operator=op} = transform_op - - [left_js, right_js, next_ctx, wrap_partial] = transform_with_partial_lr left, right, ctx - - js = binaryExpression operator, left_js, right_js - - wrap_partial js, next_ctx - - - - - -transform_unary = fn {op, right}, ctx: - [wrap_partial, right_js, next_ctx] = transform_with_partial right, ctx - - js = unaryExpression op, right_js - - wrap_partial js, next_ctx - - - -add_arithmitic = fn ctx: +add_arithmitic= fn ctx: pipe ctx: - add 'arithm', any, transform_arithmitic - add 'arithm:right', any, transform_arithmitic - add 'arithm:prefix', any, transform_unary + add '+', transform_binary + add '-', transform_binary_or_unary + add '*', transform_binary + add '/', transform_binary + add '^', transform_binary + add '%', transform_binary diff --git a/src/js/arithmitic/init.test.fnk b/src/js/arithmitic/init.test.fnk index 9d31cf6..d941560 100644 --- a/src/js/arithmitic/init.test.fnk +++ b/src/js/arithmitic/init.test.fnk @@ -1,5 +1,5 @@ +{skip, describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' {fink2js} = import '../../testing/generate.fnk' -{describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' describe 'binary', fn: @@ -20,7 +20,7 @@ describe 'binary', fn: to_match_snapshot - it 'compiles as partial', fn: + skip.it 'compiles as partial', fn: expect fink2js ' add = a + ? diff --git a/src/js/arithmitic/init.test.fnk.snap b/src/js/arithmitic/init.test.fnk.snap index f309999..7b5b8c4 100644 --- a/src/js/arithmitic/init.test.fnk.snap +++ b/src/js/arithmitic/init.test.fnk.snap @@ -1,11 +1,16 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`binary compiles 1`] = ` -"export const math_precedence1 = -1 + 0 + 1 + 2 * (3 % 1); -export const math_precedence2 = -1 + 0 + (1 + 2) * (3 / 2); -export const multi_line_assign = 123 + 234 + (-567 - 1111); -export const group1 = (1 + 2) * 3; -export const group2 = 34234 ** -34234 + 1;" +"const math_precedence1_0 = -1 + 0 + 1 + 2 * (3 % 1); +const math_precedence2_0 = -1 + 0 + (1 + 2) * (3 / 2); +const multi_line_assign_0 = 123 + 234 + (-567 - 1111); +const group1_0 = (1 + 2) * 3; +const group2_0 = 34234 ** -34234 + 1; +export const math_precedence1 = math_precedence1_0, + math_precedence2 = math_precedence2_0, + multi_line_assign = multi_line_assign_0, + group1 = group1_0, + group2 = group2_0;" `; exports[`binary compiles as partial 1`] = ` diff --git a/src/js/assignment/init.fnk b/src/js/assignment/init.fnk deleted file mode 100644 index 4ce4c13..0000000 --- a/src/js/assignment/init.fnk +++ /dev/null @@ -1,241 +0,0 @@ -babel_types = import '@babel/types' -{ - blockStatement, variableDeclaration, variableDeclarator, doExpression - arrayExpression, assignmentExpression, callExpression - memberExpression, identifier, expressionStatement, arrayPattern, restElement - numericLiteral, awaitExpression, logicalExpression -} = babel_types -{map, map_ac, filter, fold, length, is_empty} = import '@fink/std-lib/iter.fnk' - -{unique_ident} = import '../../js/types.fnk' -{transform_left: xform_left} = import '../../js/left.fnk' -{wrap_with_comment_loc} = import '../comments/init.fnk' -{add, any} = import '../context.fnk' -{transform} = import '../transform.fnk' - - - -transform_left = fn node, ctx: - [left, next_ctx] = transform node, {...ctx, is_binding: true} - js = xform_left left - [js, next_ctx] - - - -has_spread_not_last = fn {left}: - match left: - # {type: 'list', exprs: [..., {type: 'spread'}, ..., {type: ? != 'spread'}]}: - # true - {type: 'list'}: - [...exprs, ] = left.exprs - - [spread=false] = pipe exprs: - filter ?.type == 'spread' - - spread - else: - false - - -transform_spread_left = fn {left}, ctx: - [before, middle, end] = pipe left.exprs: - fold [], fn expr, [before=[], middle=false, end=[]]: - match expr: - {type: 'spread', right: false}: - [before, {type: 'empty'}, end] - - {type: 'spread', right: {}}: - [before, expr.right, end] - - else: - match middle: - false: [[...before, expr], middle, end] - else: [before, middle, [...end, expr]] - - exprs = match before: - is_empty ?: - # TODO missing loc - [middle, {type: 'list', exprs: end}] - else: - # TODO missing loc - [{type: 'list', exprs: before}, middle, {type: 'list', exprs: end}] - - transform_left {...left, exprs}, ctx - - - -slice = fn items, start, end=false: - start_num = numericLiteral start - - start_end = match end: - false: - [start_num] - else: - end_num = numericLiteral end - [start_num, end_num] - - callExpression - memberExpression - items - identifier 'slice' - start_end - - - -transform_spread_right = fn expr, ctx: - {left, right} = expr - [items, init_ctx] = unique_ident 'items', ctx - # TODO: wrap declarator? - [init, next_ctx] = transform right, init_ctx - - items_init = wrap_with_comment_loc - variableDeclaration - 'const' - list: - variableDeclarator - arrayPattern [restElement items] - init - left - - len = (length left.exprs) - 1 - [[idx]] = pipe left.exprs: - map_ac fn expr, idx=0: - [[idx, expr], idx + 1] - filter fn [, {type}]: - type == 'spread' - - slices = list: - slice items, idx, idx - len - slice items, idx - len - - result_items = match idx: - 0: slices - else: [items, ...slices] - - js = doExpression - wrap_with_comment_loc - blockStatement list: - items_init - expressionStatement arrayExpression result_items - left - [js, next_ctx] - - - -has_await = fn node: - match node: - {left: {type: 'list', exprs: [{op: 'await'}]}}: - true - else: - false - - - -transform_await_left = fn node, ctx: - {left: {exprs: [{right: expr}, ...rest_exprs], ...rest_left}} = node - left = {...rest_left, exprs: [expr, ...rest_exprs]} - transform_left left, ctx - - - - -transform_await_right = fn expr, ctx: - {left, right} = expr - [items, iter_ctx] = unique_ident 'items', ctx - [iter, init_ctx] = unique_ident 'iter', iter_ctx - - [init, next_ctx] = transform right, init_ctx - - items_init = wrap_with_comment_loc - variableDeclaration 'const', [variableDeclarator items, init] - right - - iter_init = wrap_with_comment_loc - variableDeclaration - 'const' - list: - variableDeclarator - iter - callExpression - memberExpression - rec: - ...logicalExpression - '||' - memberExpression - items - memberExpression - identifier 'Symbol' - identifier 'asyncIterator' - true - memberExpression - items - memberExpression - identifier 'Symbol' - identifier 'iterator' - true - leadingComments: [{type: 'CommentBlock', value: 'istanbul ignore next'}] - identifier 'call' - [items] - right - - [...right_exprs] = pipe left.exprs: - map fn expr: - wrap_with_comment_loc - memberExpression - awaitExpression - callExpression - memberExpression - iter - identifier 'next' - [] - identifier 'value' - expr - - js = doExpression - wrap_with_comment_loc - blockStatement list: - items_init - iter_init - expressionStatement - arrayExpression right_exprs - right - - [js, next_ctx] - - - -transform_assign_left = fn node, ctx: - transform_left node.left, ctx - - - -transform_assign_right = fn node, ctx: - transform node.right, ctx - - - - -transform_assign = fn node, ctx: - [left_transform, right_transform] = match node: - has_await ?: - [transform_await_left, transform_await_right] - - has_spread_not_last ?: - [transform_spread_left, transform_spread_right] - - else: - [transform_assign_left, transform_assign_right] - - - [left, right_ctx] = left_transform node, ctx - [right, next_ctx] = right_transform node, {...right_ctx, is_binding: false} - - js = assignmentExpression '=', left, right - [js, next_ctx] - - - -add_assignment = fn ctx: - pipe ctx: - add any, '=', transform_assign - diff --git a/src/js/assignment/init.test.fnk b/src/js/assignment/init.test.fnk index 180663d..811bc72 100644 --- a/src/js/assignment/init.test.fnk +++ b/src/js/assignment/init.test.fnk @@ -1,5 +1,5 @@ -{fink2js} = import '../../testing/generate.fnk' {describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' +{fink2js} = import '../../testing/generate.fnk' describe 'assignment', fn: @@ -19,25 +19,8 @@ describe 'assignment', fn: + 234 + -567 - 1111 - ' - to_match_snapshot - - -describe 'unpacking lists', fn: - it 'compiles leading, last', fn: - expect - fink2js " - [...leading, last] = '1234' - " + foo-bar = spam + ' to_match_snapshot - it 'compiles first, some, last', fn: - expect - fink2js " - # enhanced destructuring - [foo, bar, ...spam, ni, shrub] = '123' - - [a, , ..., b, c] = '123' - " - to_match_snapshot diff --git a/src/js/assignment/init.test.fnk.snap b/src/js/assignment/init.test.fnk.snap index 9714939..89ea345 100644 --- a/src/js/assignment/init.test.fnk.snap +++ b/src/js/assignment/init.test.fnk.snap @@ -1,43 +1,12 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`assignment compiles 1`] = ` -"export const assign = 1; -// simple -export const assign2 = assign; -export const no_clash_with_await = 13; -export const assign_lang_const1 = true; -export const assign_lang_const2 = false; -export const multi_line_assign = 123 + 234 + (-567 - 1111);" -`; - -exports[`unpacking lists compiles first, some, last 1`] = ` -"let _do_result; - -{ - const [...ˆitems_1] = \`123\`; - _do_result = [ˆitems_1, ˆitems_1.slice(2, -2), ˆitems_1.slice(-2)]; -} -// enhanced destructuring -const [[foo, bar], spam, [ni, shrub]] = _do_result; -_do_result = undefined; - -let _do_result2; - -{ - const [...ˆitems_2] = \`123\`; - _do_result2 = [ˆitems_2, ˆitems_2.slice(2, -2), ˆitems_2.slice(-2)]; -} -const [[a,,],, [b, c]] = _do_result2; -_do_result2 = undefined;" -`; - -exports[`unpacking lists compiles leading, last 1`] = ` -"let _do_result; - -{ - const [...ˆitems_1] = \`1234\`; - _do_result = [ˆitems_1.slice(0, -1), ˆitems_1.slice(-1)]; -} -const [leading, [last]] = _do_result; -_do_result = undefined;" +"const multi_line_assign_0 = 123 + 234 + (-567 - 1111); +export const assign = 1, + assign2 = 1, + no_clash_with_await = 13, + assign_lang_const1 = true, + assign_lang_const2 = false, + multi_line_assign = multi_line_assign_0, + fooᜭbar = spam;" `; diff --git a/src/js/async.fnk b/src/js/async.fnk deleted file mode 100644 index ce03f3e..0000000 --- a/src/js/async.fnk +++ /dev/null @@ -1,18 +0,0 @@ -babel_types = import '@babel/types' -{isArrowFunctionExpression} = babel_types -{set_props} = import '@fink/js-interop/reflect.fnk' - - -[no_result] = [] - - -transform_async = fn path: - # TODO: should avoid mutating nodes - match path: - isArrowFunctionExpression ?: - set_props path.node, {async: true} - - {parentPath: {}}: - transform_async path.parentPath - - no_result diff --git a/src/js/async/init.fnk b/src/js/async/init.fnk index f493407..6a1616b 100644 --- a/src/js/async/init.fnk +++ b/src/js/async/init.fnk @@ -1,20 +1,33 @@ -babel_types = import '@babel/types' -{awaitExpression} = babel_types +types = import '@babel/types' +{awaitExpression, isArrowFunctionExpression} = types +{set_props} = import '@fink/js-interop/reflect.fnk' -{add, any} = import '../context.fnk' -{transform} = import '../transform.fnk' +{add, get_js, set_js2} = import '../context.fnk' +[no_result] = [] -transform_await = fn node, ctx: - [right, next_ctx] = transform node.right, ctx - js = awaitExpression right - [js, next_ctx] +transform_async = fn path: + match path: + isArrowFunctionExpression ?: + set_props path.node, {async: true} + + {parentPath: ?}: + transform_async path.parentPath + + no_result + + + +transform_wt = fn expr, ctx: + [{args: [right_id]}] = expr + js = awaitExpression get_js right_id, ctx + set_js2 expr, js, ctx add_async = fn ctx: pipe ctx: - add 'await', any, transform_await + add 'wt', transform_wt diff --git a/src/js/async/init.test.fnk b/src/js/async/init.test.fnk index f6c6462..a7ddb64 100644 --- a/src/js/async/init.test.fnk +++ b/src/js/async/init.test.fnk @@ -1,10 +1,9 @@ -{fink2js} = import '../../testing/generate.fnk' {describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' +{fink2js} = import '../../testing/generate.fnk' describe 'await', fn: it 'compiles', fn: - expect fink2js ' task1 = fn foo: -await foo @@ -13,7 +12,7 @@ describe 'await', fn: task3 = fn foo: spam = await foo _ - bar + 123 + bar + 123 + spam a_gen = unfold fn curr=0: match shrub: @@ -25,13 +24,12 @@ describe 'await', fn: to_match_snapshot - it 'handles awaiting async iterables', fn: - + it 'does not inline into func body', fn: expect fink2js ' - [await foo, bar] = pipe: - unfold fn cntr=0: - await cntr + 1 + task1 = fn foo: + bar = await foo + shrub fn ni: + ni + bar ' to_match_snapshot - diff --git a/src/js/async/init.test.fnk.snap b/src/js/async/init.test.fnk.snap index 5806e33..5ccebda 100644 --- a/src/js/async/init.test.fnk.snap +++ b/src/js/async/init.test.fnk.snap @@ -1,44 +1,48 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`await compiles 1`] = ` -"export const task1 = async foo => -(await foo); -export const task2 = async foo => await (foo + 4); -export const task3 = async foo => { - const spam = await foo(); - return bar + 123; +"const task1_0 = async foo_0 => { + const right_0 = await foo_0; + return -right_0; }; -export const a_gen = unfold(async (curr = 0) => { - const ˆvalue_1 = shrub; + +const task2_0 = async foo_1 => { + const result_1 = await (foo_1 + 4); + return result_1; +}; + +const task3_0 = async foo_2 => { + const futr_2 = foo_2(); + const spam_0 = await futr_2; + return bar + 123 + spam_0; +}; + +const a_gen_0 = unfold(async hdm_0 => { + const curr_0 = undefined === hdm_0 ? 0 : hdm_0; /* istanbul ignore else */ - if (ˆvalue_1 === spam) { - return await ni(curr); + if (shrub === spam) { + const futr_3 = ni(curr_0); + const result_6 = await futr_3; + return result_6; } - { - return curr + 1; - } + return curr_0 + 1; }); -await ni;" +export const task1 = task1_0, + task2 = task2_0, + task3 = task3_0, + a_gen = a_gen_0;" `; -exports[`await handles awaiting async iterables 1`] = ` -"let _do_result; - -{ - let _do_result2; +exports[`await does not inline into func body 1`] = ` +"const task1_0 = async foo_0 => { + const bar_0 = await foo_0; + const result_1 = shrub(ni_0 => { + return ni_0 + bar_0; + }); + return result_1; +}; - { - let ˆpipe_result_3 = undefined; - _do_result2 = ˆpipe_result_3 = unfold(async (cntr = 0) => (await cntr) + 1)(ˆpipe_result_3); - } - const ˆitems_1 = _do_result2; - _do_result2 = undefined; - const ˆiter_2 = ( - /*istanbul ignore next*/ - ˆitems_1[Symbol.asyncIterator] || ˆitems_1[Symbol.iterator]).call(ˆitems_1); - _do_result = [(await ˆiter_2.next()).value, (await ˆiter_2.next()).value]; -} -const [foo, bar] = _do_result; -_do_result = undefined;" +export const task1 = task1_0;" `; diff --git a/src/js/block/init.fnk b/src/js/block/init.fnk deleted file mode 100644 index 3ae4012..0000000 --- a/src/js/block/init.fnk +++ /dev/null @@ -1,56 +0,0 @@ -babel_types = import '@babel/types' -{ - doExpression, blockStatement, isAssignmentExpression, expressionStatement - variableDeclaration, variableDeclarator -} = babel_types -{length} = import '@fink/std-lib/iter.fnk' - -{add, any} = import '../context.fnk' -{wrap_with_comment_loc} = import '../comments/init.fnk' -{transform, map_with_ctx, collect_with_ctx} = import '../transform.fnk' - - - -block_statement = fn expr, ctx: - [st, next_ctx] = transform expr, ctx - - js = match st: - isAssignmentExpression ?: - wrap_with_comment_loc - variableDeclaration - 'const' - [variableDeclarator st.left, st.right] - expr - - else: - wrap_with_comment_loc - expressionStatement st - expr - - [js, next_ctx] - - -exprs_block = fn exprs, ctx: - pipe exprs: - map_with_ctx block_statement - collect_with_ctx ctx - - -transform_block = fn node, ctx: - {exprs} = node - - match exprs: - 1 == length ?: - [expr] = exprs - transform expr, ctx - else: - [js_exprs, next_ctx] = exprs_block exprs, ctx - js = doExpression blockStatement js_exprs - [js, next_ctx] - - - -add_block = fn ctx: - pipe ctx: - add 'block', any, transform_block - diff --git a/src/js/call/call.fnk b/src/js/call/call.fnk index 34410d1..4bb8c10 100644 --- a/src/js/call/call.fnk +++ b/src/js/call/call.fnk @@ -1,65 +1,117 @@ -babel_types = import '@babel/types' -{callExpression, identifier} = babel_types +types = import '@babel/types' +{ + callExpression, breakStatement, assignmentExpression + expressionStatement, returnStatement + identifier, continueStatement, variableDeclaration, variableDeclarator +} = types +{null} = import '@fink/js-interop/nullish.fnk' +{map} = import '@fink/std-lib/iter.fnk' + +{add, get_js, get_js_literal, set_js2, with_loc} = import '../context.fnk' +{get_value} = import '../../ir/context.fnk' +{ident} = import '../identifier/init.fnk' + + + +as_call_args = fn args: + match args: + {type: 'ArrayExpression'}: + pipe args: + ?.elements + map fn arg: match arg: + null: identifier 'undefined' + else: arg + [...?] + # else: + # [spreadElement args] + + + +transform_apply_fn = fn expr, ctx: + [{args: [callee_id, args_id]}] = expr + callee = get_js callee_id, ctx + args = as_call_args get_js args_id, ctx + js = callExpression callee, args + set_js2 expr, js, ctx -{map, filter, zip, length} = import '@fink/std-lib/iter.fnk' -{transform, map_with_ctx, collect_with_ctx} = import '../transform.fnk' -{transform_with_partial, partial_wrapper, no_wrapper} = import '../partial/init.fnk' +transform_continue_with_fn = fn expr, ctx: + [{args: [callee_id, new_args_id]}] = expr + #set by func/init.fnk + {args_id, label_id} = get_value callee_id, ctx + new_args = get_js new_args_id, ctx -transform_multiple_args = fn args, ctx: - pipe args: - map_with_ctx fn expr, arg_ctx: - match expr: - {type: 'empty'}: - [(identifier 'undefined'), arg_ctx] - else: - transform expr, arg_ctx - collect_with_ctx ctx + js = list: + expressionStatement + assignmentExpression + '=' + ident args_id + new_args + continueStatement ident label_id + [js, ctx] -transform_single_arg = fn [expr], ctx: - match expr: - {type: 'empty'}: - [[], ctx] - else: - transform_multiple_args [expr], ctx +transform_apply_cont = fn expr, ctx: + [{args: [cont_id]}, [res_id]] = expr + cont = get_js cont_id, ctx + {label: ret_ident} = cont -transform_args = fn args, ctx, default_wrap_partial: - [js_args, next_ctx] = match args: - 1 == length ?: - transform_single_arg args, ctx - else: - transform_multiple_args args, ctx + js = list: + # TODO should that happen inside the cn transform + # TODO loc + variableDeclaration 'let', list: + variableDeclarator + ret_ident + cont + # TODO loc + variableDeclaration 'const', list: + variableDeclarator + ident res_id + ret_ident - [wrap_partial=default_wrap_partial] = pipe zip args, js_args: - filter fn [arg, js_arg]: match arg: - {type: 'partial'}: true - {type: 'spread', right: {type: 'partial'}}: true - {type: 'spread'}: js_arg.is_partial - else: false - map fn: partial_wrapper + [js, ctx] - [wrap_partial, js_args, next_ctx] +transform_continue_with_cont = fn expr, ctx: + [{args: [ret_id, res_id=false]}] = expr + ret = get_js_literal ret_id, ctx + match res_id: + false: + match ret: + {type: 'ReturnStatement'}: + [[ret], ctx] + else: + [[], ctx] -transform_call = fn node, ctx: - [callee, wrap_partial, args, end_ctx] = match node.callee: - # TODO: small pipe foo | bar ?, spam - {type: 'call'}: - [callee, args_ctx] = transform node.callee, ctx - [callee, ...transform_args node.args, args_ctx, no_wrapper] else: - [wrap_partial_callee, callee, args_ctx] = transform_with_partial node.callee, ctx - [callee, ...transform_args node.args, args_ctx, wrap_partial_callee] + res = get_js res_id, ctx + match ret: + {type: 'ReturnStatement'}: + js = with_loc res, returnStatement res + [[js], ctx] + else: + exprs = list: + with_loc res, expressionStatement + assignmentExpression '=', ret, res + with_loc res, rec: + ...breakStatement ident ret_id + leadingComments: [{type: 'CommentBlock', value: ' istanbul ignore next '}] + [exprs, ctx] + + - js = callExpression callee, args - wrap_partial js, end_ctx +add_calls = fn ctx: + pipe ctx: + add 'ac', transform_apply_cont + add 'cc', transform_continue_with_cont + add 'af', transform_apply_fn + add 'cf', transform_continue_with_fn diff --git a/src/js/call/call.test.fnk b/src/js/call/call.test.fnk index 6af2a45..060b84c 100644 --- a/src/js/call/call.test.fnk +++ b/src/js/call/call.test.fnk @@ -1,43 +1,104 @@ +{skip, describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' {fink2js} = import '../../testing/generate.fnk' -{describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' describe 'call', fn: + it 'compiles', fn: expect fink2js ' - call1 = a ni, x=123, ...x + call1 = a ni, x call2 = a ni call3 = a _ call4 = a fn x: x * 2 call5 = a foo, , bar + call6 = a foo, ...bar + call7 = a ...foo + ' + to_match_snapshot + + + it 'compiles with partial arg', fn: + expect + fink2js ' + p1 = foo ? + p2 = foo ?, 123, ? + ' + to_match_snapshot + + + it 'compiles with partial spread arg', fn: + expect + fink2js ' + p1 = foo ...? + p2 = foo ...?.bar + p3 = foo ...?.bar.spam + # TODO p4 = foo ...bar ? + p4 = fn prtl: foo ...bar prtl + p7 = ? 123 + p8 = ? bar, spam + p9 = ?.bar spam + ' + to_match_snapshot + + + it 'compiles with partial callee', fn: + expect + fink2js ' + p1 = ? 123 + p2 = ? bar, spam + p3 = ?.bar spam + ' + to_match_snapshot + + + it 'compiles with partial exprs as args', fn: + expect + fink2js ' + pa1 = filter ? == 1 + pa2 = filter ? or foo ? + pa3 = filter not ? + pa4 = map ?.foo + pa5 = map ? % 2 == 0 + pa6 = foo bar, spam == ? ' to_match_snapshot - it 'compiles as partial', fn: + + +describe 'recursive functions', fn: + it 'compiles with self reference', fn: expect fink2js ' - foo ? - foo ?, 123 - foo ...? - foo ...?.bar - ? 123 - ? bar, spam - ?.bar spam + foo = fn cntr: + match cntr: + 0: [cntr] + 1: [...foo cntr - 1] + else: [cntr, ...foo cntr - 1] ' to_match_snapshot - it 'compiles with partial args', fn: + it 'compiles to while loop', fn: expect fink2js ' - filter ? == 1 - filter ? or foo ? - filter not ? - map ?.foo - map ? % 2 == 0 + gcd = fn x, y: + match y: + 0: x + else: gcd y, x % y ' to_match_snapshot + skip.it 'compiles spread', fn: + expect + fink2js ' + fun = fn a, b, ...args: + match a: + b: fun ...args + else: b + ' + to_match_snapshot + + diff --git a/src/js/call/call.test.fnk.snap b/src/js/call/call.test.fnk.snap index f456939..e9f5068 100644 --- a/src/js/call/call.test.fnk.snap +++ b/src/js/call/call.test.fnk.snap @@ -1,33 +1,169 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`call compiles 1`] = ` -"export const call1 = a(ni, x = 123, ...x); -export const call2 = a(ni); -export const call3 = a(); -export const call4 = a(x => x * 2); -export const call5 = a(foo, undefined, bar);" +"const call1_0 = a(ni, x); +const call2_0 = a(ni); +const call3_0 = a(); +const call4_0 = a(x_0 => { + return x_0 * 2; +}); +const call5_0 = a(foo, undefined, bar); +const call6_0 = a(foo, ...bar); +const call7_0 = a(...foo); +export const call1 = call1_0, + call2 = call2_0, + call3 = call3_0, + call4 = call4_0, + call5 = call5_0, + call6 = call6_0, + call7 = call7_0;" `; -exports[`call compiles as partial 1`] = ` -"ˆpartial => foo(ˆpartial); +exports[`call compiles with partial arg 1`] = ` +"const p1_0 = prtl_0 => { + const pfn_0 = foo(prtl_0); + return pfn_0; +}; -ˆpartial => foo(ˆpartial, 123); +const p2_0 = prtl_1 => { + const pfn_1 = foo(prtl_1, 123, prtl_1); + return pfn_1; +}; -ˆpartial => foo(...ˆpartial); +export const p1 = p1_0, + p2 = p2_0;" +`; + +exports[`call compiles with partial callee 1`] = ` +"const p1_0 = prtl_0 => { + const pfn_0 = prtl_0(123); + return pfn_0; +}; + +const p2_0 = prtl_1 => { + const pfn_1 = prtl_1(bar, spam); + return pfn_1; +}; + +const p3_0 = prtl_2 => { + const pfn_2 = prtl_2.bar(spam); + return pfn_2; +}; + +export const p1 = p1_0, + p2 = p2_0, + p3 = p3_0;" +`; + +exports[`call compiles with partial exprs as args 1`] = ` +"const pa1_0 = filter(prtl_0 => { + return prtl_0 === 1; +}); +const pa2_0 = filter(prtl_1 => { + const right_1 = foo(prtl_1); + return prtl_1 || right_1; +}); +const pa3_0 = filter(prtl_2 => { + return !prtl_2; +}); +const pa4_0 = map(prtl_3 => { + return prtl_3.foo; +}); +const pa5_0 = map(prtl_4 => { + return prtl_4 % 2 === 0; +}); +const pa6_0 = foo(bar, prtl_5 => { + return spam === prtl_5; +}); +export const pa1 = pa1_0, + pa2 = pa2_0, + pa3 = pa3_0, + pa4 = pa4_0, + pa5 = pa5_0, + pa6 = pa6_0;" +`; + +exports[`call compiles with partial spread arg 1`] = ` +"const p1_0 = prtl_0 => { + const pfn_0 = foo(...prtl_0); + return pfn_0; +}; + +const p2_0 = prtl_1 => { + const pfn_1 = foo(...prtl_1.bar); + return pfn_1; +}; -ˆpartial => foo(...ˆpartial.bar); +const p3_0 = prtl_2 => { + const pfn_2 = foo(...prtl_2.bar.spam); + return pfn_2; +}; -ˆpartial => ˆpartial(123); +const p4_0 = prtl_3 => { + const sprd_3 = bar(prtl_3); + const result_0 = foo(...sprd_3); + return result_0; +}; -ˆpartial => ˆpartial(bar, spam); +const p7_0 = prtl_4 => { + const pfn_3 = prtl_4(123); + return pfn_3; +}; -ˆpartial => ˆpartial.bar(spam);" +const p8_0 = prtl_5 => { + const pfn_4 = prtl_5(bar, spam); + return pfn_4; +}; + +const p9_0 = prtl_6 => { + const pfn_5 = prtl_6.bar(spam); + return pfn_5; +}; + +export const p1 = p1_0, + p2 = p2_0, + p3 = p3_0, + p4 = p4_0, + p7 = p7_0, + p8 = p8_0, + p9 = p9_0;" +`; + +exports[`recursive functions compiles to while loop 1`] = ` +"const gcd_0 = (...args_0) => { + gcd_0: do { + const x_0 = args_0[0]; + const y_0 = args_0[1]; + + /* istanbul ignore else */ + if (y_0 === 0) { + return x_0; + } + + args_0 = [y_0, x_0 % y_0]; + continue gcd_0; + } while (true); +}; + +export const gcd = gcd_0;" `; -exports[`call compiles with partial args 1`] = ` -"filter(ˆpartial => ˆpartial === 1); -filter(ˆpartial => ˆpartial || foo(ˆpartial)); -filter(ˆpartial => !ˆpartial); -map(ˆpartial => ˆpartial.foo); -map(ˆpartial => ˆpartial % 2 === 0);" +exports[`recursive functions compiles with self reference 1`] = ` +"const foo_0 = cntr_0 => { + /* istanbul ignore else */ + if (cntr_0 === 0) { + return [cntr_0]; + } + + /* istanbul ignore else */ + if (cntr_0 === 1) { + const items_1 = foo_0(cntr_0 - 1); + return [...items_1]; + } + + const items_0 = foo_0(cntr_0 - 1); + return [cntr_0, ...items_0]; +}; + +export const foo = foo_0;" `; diff --git a/src/js/call/pipe.fnk b/src/js/call/pipe.fnk deleted file mode 100644 index 5384113..0000000 --- a/src/js/call/pipe.fnk +++ /dev/null @@ -1,51 +0,0 @@ -babel_types = import '@babel/types' -{callExpression, doExpression, blockStatement} = babel_types -{is_empty} = import '@fink/std-lib/iter.fnk' - -{assign, lets, undef, unique_ident} = import '../../js/types.fnk' -{wrap_with_comment_loc} = import '../comments/init.fnk' -{transform, map_with_ctx, collect_with_ctx} = import '../transform.fnk' -{transform_with_partial} = import '../partial/init.fnk' - - - -transform_pipe_step = fn result: fn expr, ctx: - callee_ctx = {...ctx, partial_ident: result} - - [is_partial, callee, {partial_ident: _, ...next_ctx}] = transform_with_partial expr, callee_ctx, false - - step = match is_partial: - false: - assign result, callExpression callee, [result] - else: - assign result, callee - - js = wrap_with_comment_loc step, expr - [js, next_ctx] - - - -transform_pipe = fn node, ctx: - {exprs} = node - - [start_value, id_ctx] = match node.args: - is_empty ?: - [(undef _), ctx] - else: - [arg] = node.args - transform arg, ctx - - [result, pipe_ctx] = unique_ident 'pipe_result', id_ctx - - [pipe_calls, next_ctx] = pipe exprs: - map_with_ctx transform_pipe_step result - collect_with_ctx pipe_ctx - - js = doExpression - blockStatement list: - wrap_with_comment_loc - lets result, start_value - start_value - ...pipe_calls - - [js, next_ctx] diff --git a/src/js/call/pipe.test.fnk b/src/js/call/pipe.test.fnk index b16030b..848a554 100644 --- a/src/js/call/pipe.test.fnk +++ b/src/js/call/pipe.test.fnk @@ -1,21 +1,32 @@ +{skip, describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' {fink2js} = import '../../testing/generate.fnk' -{describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' describe 'pipe', fn: it 'compiles', fn: - expect fink2js ' - pipe: + p1 = pipe: foo - bar ?, {foo} + bar ?, 123 spam - [...?] + ?.spam 456 + ?.nini + [4, 5, ...?] - pipe [1, 2, 3]: + p2 = pipe [1, 2, 3]: map fn item: item * 2 + [...?] + ' + to_match_snapshot + + expect + fink2js ' + foo = bar fn: + pipe: + spam + ?.shrub 123 ' to_match_snapshot @@ -29,7 +40,7 @@ describe 'small pipe |', fn: ' to_match_snapshot - it 'handles precedence', fn: + skip.it 'handles precedence', fn: expect fink2js ' foo = "foo" | matches rx"[a-z]", ? diff --git a/src/js/call/pipe.test.fnk.snap b/src/js/call/pipe.test.fnk.snap index 0c0bcd6..c48ce70 100644 --- a/src/js/call/pipe.test.fnk.snap +++ b/src/js/call/pipe.test.fnk.snap @@ -1,19 +1,53 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`pipe compiles 1`] = ` -"{ - let ˆpipe_result_1 = undefined; - ˆpipe_result_1 = foo(ˆpipe_result_1); - ˆpipe_result_1 = bar(ˆpipe_result_1, { - foo - }); - ˆpipe_result_1 = spam(ˆpipe_result_1); - ˆpipe_result_1 = [...ˆpipe_result_1]; -} -{ - let ˆpipe_result_2 = [1, 2, 3]; - ˆpipe_result_2 = map(item => item * 2)(ˆpipe_result_2); -}" +"const ppr_0 = foo(); + +const ppr_1 = (prtl_0 => { + const pfn_2 = bar(prtl_0, 123); + return pfn_2; +})(ppr_0); + +const ppr_2 = spam(ppr_1); + +const ppr_3 = (prtl_1 => { + const pfn_5 = prtl_1.spam(456); + return pfn_5; +})(ppr_2); + +const ppr_4 = (prtl_2 => { + return prtl_2.nini; +})(ppr_3); + +const ppr_5 = (prtl_3 => { + return [4, 5, ...prtl_3]; +})(ppr_4); + +const pfn_10 = map(item_5 => { + return item_5 * 2; +}); +const ppr_6 = pfn_10([1, 2, 3]); + +const ppr_7 = (prtl_4 => { + return [...prtl_4]; +})(ppr_6); + +export const p1 = ppr_5, + p2 = ppr_7;" +`; + +exports[`pipe compiles 2`] = ` +"const foo_0 = bar(() => { + const ppr_0 = spam(); + + const ppr_1 = (prtl_0 => { + const pfn_2 = prtl_0.shrub(123); + return pfn_2; + })(ppr_0); + + return ppr_1; +}); +export const foo = foo_0;" `; exports[`small pipe | handles precedence 1`] = ` @@ -21,4 +55,7 @@ exports[`small pipe | handles precedence 1`] = ` export const bar = [ham(spam), ni(shrub)];" `; -exports[`small pipe | pipes 1`] = `"export const foo = is_int(134);"`; +exports[`small pipe | pipes 1`] = ` +"const foo_0 = is_int(134); +export const foo = foo_0;" +`; diff --git a/src/js/comments/init.fnk b/src/js/comments/init.fnk deleted file mode 100644 index 4af379a..0000000 --- a/src/js/comments/init.fnk +++ /dev/null @@ -1,31 +0,0 @@ -{map} = import '@fink/std-lib/iter.fnk' - - -transform_comment = fn {op, value, loc}: - match op: - '---': {type: 'CommentBlock', value, loc} - else: {type: 'CommentLine', value, loc} - - -transform_comments = fn comments: - pipe comments: - map fn comment: transform_comment comment - - -get_comments = fn {comments={}}, {leadingComments=[]}: - {leading=[], trailing=[]} = comments - - rec: - leadingComments: list: - ...transform_comments leading - ...leadingComments - trailingComments: [...transform_comments trailing] - - -wrap_with_comment_loc = fn js_node, larix_node: - comments = get_comments larix_node, js_node - {loc} = larix_node - - match js_node: - {loc: {}}: {...js_node, ...comments} - else: {...js_node, ...comments, loc} diff --git a/src/js/comments/init.test.fnk b/src/js/comments/init.test.fnk deleted file mode 100644 index 36d5e7d..0000000 --- a/src/js/comments/init.test.fnk +++ /dev/null @@ -1,23 +0,0 @@ -{fink2js} = import '../../testing/generate.fnk' -{describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' - - -describe 'comment', fn: - it 'compiles', fn: - - expect - fink2js ' - # leading expression - spam = ni - - --- - Shrub ni. - --- - bar = fn: - --- single line block --- - spam - - # trailing module - ' - to_match_snapshot - diff --git a/src/js/comments/init.test.fnk.snap b/src/js/comments/init.test.fnk.snap deleted file mode 100644 index f57b4d1..0000000 --- a/src/js/comments/init.test.fnk.snap +++ /dev/null @@ -1,13 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`comment compiles 1`] = ` -"// leading expression -export const spam = ni; - -/* -Shrub ni. -*/ -export const bar = () => -/* single line block */ -spam;" -`; diff --git a/src/js/comparison/init.fnk b/src/js/comparison/init.fnk index d3b80e2..11b19d1 100644 --- a/src/js/comparison/init.fnk +++ b/src/js/comparison/init.fnk @@ -1,35 +1,14 @@ -babel_types = import '@babel/types' -{binaryExpression, logicalExpression} = babel_types - -{add, any} = import '../context.fnk' -{transform_with_partial_lr} = import '../partial/init.fnk' - - - -transform_op = rec: - '==': '===' - '!=': '!==' - - - -transform_comp = fn {op, left, right}, ctx: - {(op): operator=op} = transform_op - - [bin_left, bin_right, next_ctx, wrap_partial] = transform_with_partial_lr left, right, ctx - - js = match left: - {op: ? in ['<', '>', '<=', '>=', '==', '!=']}: - logicalExpression '&&', - bin_left - binaryExpression operator, bin_left.right, bin_right - else: - binaryExpression operator, bin_left, bin_right - - wrap_partial js, next_ctx +{add} = import '../context.fnk' +{transform_binary} = import '../transform.fnk' add_comparison = fn ctx: pipe ctx: - add 'comp', any, transform_comp + add '==', transform_binary + add '!=', transform_binary + add '>', transform_binary + add '<', transform_binary + add '<=', transform_binary + add '>=', transform_binary diff --git a/src/js/comparison/init.test.fnk b/src/js/comparison/init.test.fnk index 20f969e..8a2a067 100644 --- a/src/js/comparison/init.test.fnk +++ b/src/js/comparison/init.test.fnk @@ -1,5 +1,5 @@ +{skip, describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' {fink2js} = import '../../testing/generate.fnk' -{describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' describe 'comparison', fn: @@ -29,7 +29,7 @@ describe 'comparison', fn: to_match_snapshot - it 'compiles as partials', fn: + skip.it 'compiles as partials', fn: expect fink2js " 1 == len ? diff --git a/src/js/comparison/init.test.fnk.snap b/src/js/comparison/init.test.fnk.snap index 4d5eabc..36fcf8b 100644 --- a/src/js/comparison/init.test.fnk.snap +++ b/src/js/comparison/init.test.fnk.snap @@ -11,19 +11,31 @@ exports[`comparison compiles as partials 1`] = ` `; exports[`comparison compiles combined 1`] = ` -"export const lt = a < b && b < c; -export const gt = a > b && b > c; -export const eq = a === b && b === c; -export const neq = a !== b && b !== c; -export const gteq = a >= b && b >= c; -export const lteq = a <= b && b <= c;" +"const lt_0 = a < b && b < c; +const gt_0 = a > b && b > c; +const eq_0 = a === b && b === c; +const neq_0 = a !== b && b !== c; +const gteq_0 = a >= b && b >= c; +const lteq_0 = a <= b && b <= c; +export const lt = lt_0, + gt = gt_0, + eq = eq_0, + neq = neq_0, + gteq = gteq_0, + lteq = lteq_0;" `; exports[`comparison compiles simple 1`] = ` -"export const lt = a < b; -export const gt = a > b; -export const eq = a === b; -export const neq = a !== b; -export const gteq = a >= b; -export const lteq = a <= b;" +"const lt_0 = a < b; +const gt_0 = a > b; +const eq_0 = a === b; +const neq_0 = a !== b; +const gteq_0 = a >= b; +const lteq_0 = a <= b; +export const lt = lt_0, + gt = gt_0, + eq = eq_0, + neq = neq_0, + gteq = gteq_0, + lteq = lteq_0;" `; diff --git a/src/js/conditionals/init.fnk b/src/js/conditionals/init.fnk index fbced63..ecd4f42 100644 --- a/src/js/conditionals/init.fnk +++ b/src/js/conditionals/init.fnk @@ -1,8 +1,95 @@ -{add, any} = import '../context.fnk' -{transform_match} = import './match.fnk' +types = import '@babel/types' +{conditionalExpression, binaryExpression, identifier, ifStatement} = types + +{dec_ref, get_refs} = import '../../ir/context.fnk' +{add, get_js, set_js2} = import '../context.fnk' + + + +transform_if_val = fn expr, ctx: + [{args: [val_id, true_id, false_id]}] = expr + val = get_js val_id, ctx + true_js = get_js true_id, ctx + false_js = get_js false_id, ctx + + js = conditionalExpression + binaryExpression + '===' + identifier 'undefined' + val + false_js + true_js + + set_js2 expr, js, ctx + + + +transform_is_val = fn expr, ctx: + [{args: [val_id]}] = expr + val = get_js val_id, ctx + + js = binaryExpression + '!==' + identifier 'undefined' + val + + set_js2 expr, js, ctx + + +transform_is_rec = fn expr, ctx: + [{args: [val_id]}] = expr + val = get_js val_id, ctx + + js = binaryExpression + '!=' + identifier 'null' + val + + set_js2 expr, js, ctx + + + +transform_is_lst = fn expr, ctx: + [{args: [val_id]}] = expr + val = get_js val_id, ctx + + js = binaryExpression + '!=' + identifier 'null' + val + + set_js2 expr, js, ctx + + + +transform_if = fn expr, ctx: + [{args: [cond_id, true_id, else_id], loc}] = expr + cond_c = get_js cond_id, ctx + true_c = get_js true_id, ctx + + if_true_js = rec: + ...ifStatement cond_c, true_c + leadingComments: [{type: 'CommentBlock', value: ' istanbul ignore else '}] + loc + + match get_refs else_id, ctx: + ? == 1: + else_js = get_js else_id, ctx + else_exprs = match else_js: + {type: 'BlockStatement'}: + else_js.body + [[if_true_js, ...else_exprs], ctx] + + ? > 1: + next_ctx = dec_ref else_id, ctx + [[if_true_js], next_ctx] add_conditionals = fn ctx: pipe ctx: - add any, 'match', transform_match + add 'ifv', transform_if_val + add 'isv', transform_is_val + add 'is_r', transform_is_rec + add 'is_l', transform_is_lst + add 'cif', transform_if diff --git a/src/js/conditionals/match.fnk b/src/js/conditionals/match.fnk deleted file mode 100644 index 77bca24..0000000 --- a/src/js/conditionals/match.fnk +++ /dev/null @@ -1,304 +0,0 @@ -babel_types = import '@babel/types' -{ - blockStatement, breakStatement, labeledStatement, objectPattern - objectProperty, expressionStatement, ifStatement - doExpression, stringLiteral, memberExpression, restElement - identifier, optionalMemberExpression -} = babel_types -{map, filter, length, is_empty} = import '@fink/std-lib/iter.fnk' - -{eq, not_nullish, not_undefiend, typof, consts, unique_ident} = import '../../js/types.fnk' - -{get_key} = import '../literals/record.fnk' -{wrap_with_comment_loc} = import '../comments/init.fnk' -{transform, map_with_ctx, collect_with_ctx} = import '../transform.fnk' -{transform_with_partial} = import '../partial/init.fnk' - - - -iter = fn value: - symb = identifier 'Symbol' - iterator = identifier 'iterator' - symb_iter = memberExpression symb, iterator - optionalMemberExpression value, symb_iter, true, true - - - -is_iterable = fn value: - eq - typof iter value - stringLiteral 'function' - - -comp = fn id, expected, ctx: - match expected: - {type: 'partial'}: - cond = not_undefiend id - [cond, ctx] - else: - value_ctx = {...ctx, partial_ident: id} - [wrap_with_partial, value, {partial_ident: _, ...next_ctx}] = transform_with_partial expected, value_ctx, false - - cond = match wrap_with_partial: - false: eq id, value - else: value - - [cond, next_ctx] - - - -match_props = fn props, emit_result, ctx, cond: - [{id, prop}, ...rest] = props - - value = match prop: - {type: 'spread'}: - prop - {right: false}: - prop.left - else: - prop.right - - emit = match props: - 1 == length ?: - emit_result - else: - fn ctx: match_props rest, emit_result, ctx, cond - - match_condition id, value, emit, ctx, cond - - - -fix_member_prop = fn expr: - match expr: - {left: {type: 'member'}}: - {left, right} = expr.left - value = {type: 'rec', exprs: [{...expr, left: right}], loc: expr.loc} - fix_member_prop {...expr, left, right: value} - else: - expr - - -match_record = fn value, record, emit_result, ctx, cond: - [id_props, props_ctx] = pipe record.exprs: - map_with_ctx fn orig_prop, id_ctx: - prop = fix_member_prop orig_prop - [id, next_ctx] = unique_ident 'p', id_ctx - [{id, prop}, next_ctx] - - collect_with_ctx ctx - - [props, result_ctx] = pipe id_props: - map_with_ctx fn {id, prop}, prop_ctx: - match prop: - {type: 'spread'}: - [(restElement id), prop_ctx] - else: - [computed, key, next_ctx] = get_key prop, prop_ctx - js = objectProperty key, id, computed - [js, next_ctx] - collect_with_ctx props_ctx - - decl = objectPattern props - - [result, end_ctx] = match id_props: - is_empty ?: - emit_result ctx - else: - [prop_match, next_ctx] = match_props - id_props, emit_result, result_ctx, cond - js = blockStatement list: - consts decl, value - prop_match - [js, next_ctx] - - js = rec: - ...ifStatement - not_nullish value - result - leadingComments: list: rec: - type: 'CommentBlock' - value: ' istanbul ignore else ' - - [js, end_ctx] - - - -match_elems = fn elems, emit_result, ctx, cond: - [{id, value}, ...rest] = elems - - emit = match elems: - 1 == length ?: - emit_result - else: - fn ctx: match_elems rest, emit_result, ctx, cond - - match_condition id, value, emit, ctx, cond - - - -get_array_decl = fn arr, id_elems, right, ctx: - [...exprs] = pipe id_elems: - map fn {id, value}: - match value: - # e.g. empty elems in [,, foo, bar] - {type: 'empty'}: - value - - # e.g. spread in [foo, ..., bar] - {type: 'spread', right: false}: - value - - # e.g. spread in [foo, ...bar, spam] - {type: 'spread', right: {}}: - ident = {type: 'ident', value: id.name} - {...value, right: ident} - - else: - {type: 'ident', value: id.name} - - left = {type: 'list', exprs, loc: arr.loc} - - [decl, next_ctx] = transform - rec: - type: 'assign' - op: '=' - left - right: {type: 'ident', value: right.name, loc: arr.loc} - loc: arr.loc - ctx - - js = consts decl.left, decl.right - [js, next_ctx] - - - -match_array = fn value, arr, emit_result, ctx, cond: - [id_elems, elems_ctx] = pipe arr.exprs: - map_with_ctx fn expr, expr_ctx: - [id, next_ctx] = unique_ident 'a', expr_ctx - [{id, value: expr}, next_ctx] - collect_with_ctx ctx - - [array_decl, result_ctx] = get_array_decl arr, id_elems, value, elems_ctx - - [...filtered_id_elems] = pipe id_elems: - filter fn {value}: - match value: - # empty elements need no matching - {type: 'empty'}: false - - # empty spreads need no matching - {type: 'spread', right: false}: false - - {type: 'spread', right: {}}: true - - else: true - - [result, end_ctx] = match id_elems: - is_empty ?: - emit_result result_ctx - else: - [matched, next_ctx] = match_elems - filtered_id_elems, emit_result, result_ctx, cond - js = blockStatement [array_decl, matched] - [js, next_ctx] - - js = rec: - ...ifStatement - is_iterable value - result - leadingComments: list: rec: - type: 'CommentBlock' - value: ' istanbul ignore else ' - - [js, end_ctx] - - - -match_simple = fn value, expr, emit_result, ctx: - [cond, result_ctx] = comp value, expr, {...ctx, wrap: 'loc'} - [result, next_ctx] = emit_result result_ctx - js = rec: - ...ifStatement cond, result - leadingComments: list: rec: - type: 'CommentBlock' - value: ' istanbul ignore else ' - - [js, next_ctx] - - - -match_condition = fn value, expr, emit_result, ctx, cond: - [js_expr, next_ctx] = match expr: - {type: 'rec'}: - match_record value, expr, emit_result, ctx, cond - - {type: 'list'}: - match_array value, expr, emit_result, ctx, cond - - {type: 'spread'}: - match_condition value, expr.right, emit_result, ctx, cond - - else: - match_simple value, expr, emit_result, ctx - - js = wrap_with_comment_loc js_expr, cond - [js, next_ctx] - - - -split_condition = fn {left, right}: - [left, right] - - - -match_all = fn value, matches, emit, ctx: - [exprs, end_ctx] = pipe matches: - map_with_ctx fn expr, expr_ctx: - match expr: - {type: 'block', op: 'else'}: - {op: _, ...block} = expr - [js_expr, next_ctx] = emit block, expr_ctx - js = wrap_with_comment_loc js_expr, block - [js, next_ctx] - else: - [condition, result] = split_condition expr - emit_result = fn ctx: emit result, ctx - match_condition value, condition, emit_result, expr_ctx, condition - collect_with_ctx ctx - - [exprs, end_ctx] - - - -result_emitter = fn break_lbl: fn result, ctx: - [result_js, next_ctx] = transform result, ctx - js = blockStatement list: - expressionStatement result_js - breakStatement break_lbl - - [js, next_ctx] - - - -transform_match = fn node, ctx: - {exprs} = node - [inputs] = node.args - - [value, match_ctx] = unique_ident 'value', ctx - [break_lbl, inputs_ctx] = unique_ident 'match', match_ctx - - emit_result = result_emitter break_lbl - - [inputs_js, next_ctx] = transform inputs, inputs_ctx - [match_exprs, end_ctx] = match_all value, exprs, emit_result, next_ctx - - js = doExpression - blockStatement list: - labeledStatement - break_lbl - blockStatement list: - consts value, inputs_js - ...match_exprs - - [js, end_ctx] diff --git a/src/js/conditionals/match.test.fnk b/src/js/conditionals/match.test.fnk index 05204ff..f3faf16 100644 --- a/src/js/conditionals/match.test.fnk +++ b/src/js/conditionals/match.test.fnk @@ -1,5 +1,5 @@ +{skip, describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' {fink2js} = import '../../testing/generate.fnk' -{describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' describe 'match', fn: @@ -18,6 +18,64 @@ describe 'match', fn: ' to_match_snapshot + it 'compiles match with ref', fn: + expect + fink2js ' + spam = match foo: + 1: + x = 123 + [1, x, x] + 2: + [2, foo] + else: + [3, foo] + ' + to_match_snapshot + + expect + fink2js ' + spam = match foo: + 1: + x = 123 + [1, x, x] + 2: + y = 45678 + [2, foo, y, y] + else: + [3, foo, z] + ' + to_match_snapshot + + expect + fink2js ' + spam = match foo: + 1: + x = 123 + [1, x, x] + 2: + y = 45678 + [2, foo, y, y] + else: + z = 1234 + [3, foo, z, z] + ' + to_match_snapshot + + expect + fink2js ' + spam = match foo: + 1: + x = 123 + [1, x, x] + 2: + y = 45678 + [2, foo, y] + else: + z = 1234 + [3, foo, z, z] + ' + to_match_snapshot + it 'matches value assertions', fn: expect @@ -63,31 +121,76 @@ describe 'match', fn: to_match_snapshot + it 'handles scoping', fn: + expect + fink2js ' + foo = nanu + + test = fn foo, bar: + match foo: + bar: + foo + spam: + foo = bar * 2 + [foo, bar, foo] + ' + to_match_snapshot describe 'match iterables', fn: it 'matches values', fn: expect fink2js ' match shrub: - # deep iterable comparison [1, 2, [ni]]: ni - # TODO: fix semantics for matching [], {} - [1, 2, [], {}]: foo [1, [2, 3], 4]: bar [1, [2, [3, 4]], [5, 6], 7]: spam ' to_match_snapshot - it 'matches spread', fn: + it 'matches with ignored items', fn: expect fink2js ' - # spread and ignored elems match shrub: [1, ,2]: foo + ' + to_match_snapshot + + + it 'handles non iterables', fn: + expect + fink2js " + [expr=false, ...exprs] = args + match expr: + false: + [out, ctx] + + [? in [1, 2]]: + foo exprs, expr + + [, , [foo ?, ctx]]: + foo expr, exprs + " + to_match_snapshot + + + skip.it 'matches empty tuples', fn: + expect + fink2js ' + match shrub: + []: foo + [1, 2, []]: foo + ' + to_match_snapshot + + + it 'matches spread', fn: + expect + fink2js ' + match shrub: [1, ..., 3]: foo - [..., 2]: foo - [1, ...[2, 3], 4]: foo + [..., 4]: foo + [5, ...[6, 7], 9]: foo ' to_match_snapshot @@ -113,6 +216,7 @@ describe 'match iterables', fn: # nested as call arg [is_foo ?]: ni + [is_foo ?, bar]: ni [1, ...is_empty ?]: ni [1, ...(1 < length ?)]: ni @@ -126,13 +230,15 @@ describe 'match records', fn: expect fink2js " match shrub: + {foo, bar}: ni # TODO: fix semantics for matching {} - {foo: {}}: spam + ni + # TODO: {foo: {}}: spam + ni # TODO: fix semantics for matching [] - {foo: []}: spam + ni + # {foo: []}: spam + ni {foo: 4, ni: {na, nu}}: spam + ni {foo: 1, foo: {bar: 'spam'}, shrub: {na: 'nu'}}: ni {ni: {len: 1}, na: {len: 1}}: na + {ni: [foo, 1234]}: na " to_match_snapshot @@ -141,7 +247,6 @@ describe 'match records', fn: expect fink2js ' match shrub: - # calculated props {(a): {b, c}}: ni ' to_match_snapshot @@ -152,7 +257,7 @@ describe 'match records', fn: fink2js ' match shrub: # spread - {(foo): {}, ...{bar, spam}}: ni + {(foo): ?, ...{bar, spam}}: ni ' to_match_snapshot @@ -160,17 +265,13 @@ describe 'match records', fn: it 'matches member expr keys', fn: expect fink2js ' - match foo: + match shrub: {foo.bar.spam: ham}: spam + {foo.bar.spam: {ham.ni: nu}}: ham + {foo: {bar.spam: {ham.ni: nu}, spam}}: ham ' to_match_snapshot - expect - fink2js ' - match foo: - {foo.bar.spam: {ham.ni: nu}}: spam - ' - to_match_snapshot it 'matches value assertions', fn: @@ -201,18 +302,3 @@ describe 'match records', fn: to_match_snapshot - -describe 'match value assertions', fn: - it 'compiles do-expr', fn: - expect - fink2js ' - foo = match bar: - spam: - ni - shrub foobar - else: - shrub - spam ni - ' - to_match_snapshot - diff --git a/src/js/conditionals/match.test.fnk.snap b/src/js/conditionals/match.test.fnk.snap index 7e08a00..994f757 100644 --- a/src/js/conditionals/match.test.fnk.snap +++ b/src/js/conditionals/match.test.fnk.snap @@ -1,555 +1,721 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`match compiles nested match 1`] = ` -"export const test = () => { - const ˆvalue_1 = foo; +exports[`match compiles match with ref 1`] = ` +"let ret_0; +ret_0: { /* istanbul ignore else */ - if (ˆvalue_1 === bar) { - { - { - ˆmatch_4: { - const ˆvalue_3 = spam; + if (foo === 1) { + ret_0 = [1, 123, 123]; - /* istanbul ignore else */ - if (ˆvalue_3 === shrub) { - ni; - break ˆmatch_4; - } - } + /* istanbul ignore next */ + break ret_0; + } + + /* istanbul ignore else */ + if (foo === 2) { + ret_0 = [2, foo]; + + /* istanbul ignore next */ + break ret_0; + } + + ret_0 = [3, foo]; + + /* istanbul ignore next */ + break ret_0; +} + +const spam_0 = ret_0; +export const spam = spam_0;" +`; + +exports[`match compiles match with ref 2`] = ` +"let ret_0; + +ret_0: { + /* istanbul ignore else */ + if (foo === 1) { + ret_0 = [1, 123, 123]; + + /* istanbul ignore next */ + break ret_0; + } + + /* istanbul ignore else */ + if (foo === 2) { + ret_0 = [2, foo, 45678, 45678]; + + /* istanbul ignore next */ + break ret_0; + } + + ret_0 = [3, foo, z]; + + /* istanbul ignore next */ + break ret_0; +} + +const spam_0 = ret_0; +export const spam = spam_0;" +`; + +exports[`match compiles match with ref 3`] = ` +"let ret_0; + +ret_0: { + /* istanbul ignore else */ + if (foo === 1) { + ret_0 = [1, 123, 123]; + + /* istanbul ignore next */ + break ret_0; + } + + /* istanbul ignore else */ + if (foo === 2) { + ret_0 = [2, foo, 45678, 45678]; + + /* istanbul ignore next */ + break ret_0; + } + + ret_0 = [3, foo, 1234, 1234]; + + /* istanbul ignore next */ + break ret_0; +} + +const spam_0 = ret_0; +export const spam = spam_0;" +`; + +exports[`match compiles match with ref 4`] = ` +"let ret_0; + +ret_0: { + /* istanbul ignore else */ + if (foo === 1) { + ret_0 = [1, 123, 123]; + + /* istanbul ignore next */ + break ret_0; + } + + /* istanbul ignore else */ + if (foo === 2) { + ret_0 = [2, foo, 45678]; + + /* istanbul ignore next */ + break ret_0; + } + + ret_0 = [3, foo, 1234, 1234]; + + /* istanbul ignore next */ + break ret_0; +} + +const spam_0 = ret_0; +export const spam = spam_0;" +`; + +exports[`match compiles nested match 1`] = ` +"const test_0 = () => { + /* istanbul ignore else */ + if (foo === bar) { + let ret_1; + + ret_1: { + /* istanbul ignore else */ + if (spam === shrub) { + ret_1 = ni; + + /* istanbul ignore next */ + break ret_1; } - return bar; } + + const result_1 = ret_1; + return bar; } -};" + + /* istanbul ignore next */ + return; +}; + +export const test = test_0;" `; exports[`match compiles without else 1`] = ` -"{ - ˆmatch_2: { - const ˆvalue_1 = shrub; +"let ret_0; - /* istanbul ignore else */ - if (ˆvalue_1 === 123) { - spam; - break ˆmatch_2; - } +ret_0: { + /* istanbul ignore else */ + if (shrub === 123) { + ret_0 = spam; + + /* istanbul ignore next */ + break ret_0; } -}" +} + +const mex_0 = ret_0;" `; -exports[`match iterables matches spread 1`] = ` -"// spread and ignored elems -{ - ˆmatch_2: { - const ˆvalue_1 = shrub; +exports[`match handles scoping 1`] = ` +"const test_0 = (foo_1, bar_0) => { + /* istanbul ignore else */ + if (foo_1 === bar_0) { + return foo_1; + } + + /* istanbul ignore else */ + if (foo_1 === spam) { + const foo_2 = bar_0 * 2; + return [foo_2, bar_0, foo_2]; + } + + /* istanbul ignore next */ + return; +}; + +export const foo = nanu, + test = test_0;" +`; +exports[`match iterables handles non iterables 1`] = ` +"import { _in_ } from \\"@fink/js-interop/runtime.js\\"; +const hdm_0 = args[0]; +const expr_0 = undefined === hdm_0 ? false : hdm_0; +const tail_0 = args.slice(1); +let ret_0; + +ret_0: { + /* istanbul ignore else */ + if (expr_0 === false) { + ret_0 = [out, ctx]; + + /* istanbul ignore next */ + break ret_0; + } + + /* istanbul ignore else */ + if (null != expr_0) { /* istanbul ignore else */ - if (typeof ˆvalue_1?.[Symbol.iterator] === \\"function\\") { - const [ˆa_3,, ˆa_5] = ˆvalue_1; + if (true === _in_(expr_0[0], [1, 2])) { + const result_1 = foo(tail_0, expr_0); + ret_0 = result_1; - /* istanbul ignore else */ - if (ˆa_3 === 1) - /* istanbul ignore else */ - if (ˆa_5 === 2) { - foo; - break ˆmatch_2; - } + /* istanbul ignore next */ + break ret_0; } + } - /* istanbul ignore else */ - if (typeof ˆvalue_1?.[Symbol.iterator] === \\"function\\") { - let _do_result; + /* istanbul ignore else */ + if (null != expr_0) { + const itm_0 = expr_0[2]; - { - const [...ˆitems_9] = ˆvalue_1; - _do_result = [ˆitems_9, ˆitems_9.slice(1, -1), ˆitems_9.slice(-1)]; - } - const [[ˆa_6],, [ˆa_8]] = _do_result; - _do_result = undefined; + /* istanbul ignore else */ + if (null != itm_0) { + const val_0 = foo(itm_0[0], ctx); /* istanbul ignore else */ - if (ˆa_6 === 1) - /* istanbul ignore else */ - if (ˆa_8 === 3) { - foo; - break ˆmatch_2; - } + if (true === val_0) { + const result_0 = foo(expr_0, tail_0); + ret_0 = result_0; + + /* istanbul ignore next */ + break ret_0; + } } + } +} - /* istanbul ignore else */ - if (typeof ˆvalue_1?.[Symbol.iterator] === \\"function\\") { - let _do_result2; +const mex_1 = ret_0;" +`; - { - const [...ˆitems_12] = ˆvalue_1; - _do_result2 = [ˆitems_12.slice(0, -1), ˆitems_12.slice(-1)]; - } - const [, [ˆa_11]] = _do_result2; - _do_result2 = undefined; +exports[`match iterables matches spread 1`] = ` +"let ret_0; +ret_0: { + /* istanbul ignore else */ + if (null != shrub) { + /* istanbul ignore else */ + if (shrub[0] === 1) { /* istanbul ignore else */ - if (ˆa_11 === 2) { - foo; - break ˆmatch_2; + if (shrub.at(-1) === 3) { + ret_0 = foo; + + /* istanbul ignore next */ + break ret_0; } } + } + /* istanbul ignore else */ + if (null != shrub) { /* istanbul ignore else */ - if (typeof ˆvalue_1?.[Symbol.iterator] === \\"function\\") { - let _do_result3; + if (shrub.at(-1) === 4) { + ret_0 = foo; - { - const [...ˆitems_16] = ˆvalue_1; - _do_result3 = [ˆitems_16, ˆitems_16.slice(1, -1), ˆitems_16.slice(-1)]; - } - const [[ˆa_13], ˆa_14, [ˆa_15]] = _do_result3; - _do_result3 = undefined; + /* istanbul ignore next */ + break ret_0; + } + } + /* istanbul ignore else */ + if (null != shrub) { + /* istanbul ignore else */ + if (shrub[0] === 5) { /* istanbul ignore else */ - if (ˆa_13 === 1) + if (null != shrub.slice(1)) { /* istanbul ignore else */ - if (typeof ˆa_14?.[Symbol.iterator] === \\"function\\") { - const [ˆa_17, ˆa_18] = ˆa_14; - + if (shrub[1] === 6) { /* istanbul ignore else */ - if (ˆa_17 === 2) - /* istanbul ignore else */ - if (ˆa_18 === 3) - /* istanbul ignore else */ - if (ˆa_15 === 4) { - foo; - break ˆmatch_2; - } + if (shrub[2] === 7) { + ret_0 = foo; + + /* istanbul ignore next */ + break ret_0; + } } + } } } -}" +} + +const mex_0 = ret_0;" `; exports[`match iterables matches value assertions 1`] = ` -"{ - ˆmatch_2: { - const ˆvalue_1 = foo; - - // nested unary +"let ret_0; +ret_0: { + /* istanbul ignore else */ + if (null != foo) { /* istanbul ignore else */ - if (typeof ˆvalue_1?.[Symbol.iterator] === \\"function\\") { - const [ˆa_3] = ˆvalue_1; - - // nested unary + if (true === !foo[0]) { + ret_0 = ni; - /* istanbul ignore else */ - if (!ˆa_3) { - ni; - break ˆmatch_2; - } + /* istanbul ignore next */ + break ret_0; } + } - // any value - + /* istanbul ignore else */ + if (null != foo) { /* istanbul ignore else */ - if (typeof ˆvalue_1?.[Symbol.iterator] === \\"function\\") { - const [ˆa_4] = ˆvalue_1; + if (undefined !== foo[0]) { + ret_0 = true; - // any value + /* istanbul ignore next */ + break ret_0; + } + } - /* istanbul ignore else */ - if (ˆa_4 !== undefined) { - true; - break ˆmatch_2; - } + /* istanbul ignore else */ + if (null != foo) { + /* istanbul ignore else */ + if (true === foo[0] > 123) { + ret_0 = ni; + + /* istanbul ignore next */ + break ret_0; } + } - // nested binary + /* istanbul ignore else */ + if (null != foo) { + const val_7 = foo[0](); /* istanbul ignore else */ - if (typeof ˆvalue_1?.[Symbol.iterator] === \\"function\\") { - const [ˆa_5] = ˆvalue_1; - - // nested binary + if (true === val_7) { + ret_0 = ni; - /* istanbul ignore else */ - if (ˆa_5 > 123) { - ni; - break ˆmatch_2; - } + /* istanbul ignore next */ + break ret_0; } + } - // nested call + /* istanbul ignore else */ + if (null != foo) { + const val_6 = foo[0].is_foo(); /* istanbul ignore else */ - if (typeof ˆvalue_1?.[Symbol.iterator] === \\"function\\") { - const [ˆa_6] = ˆvalue_1; + if (true === val_6) { + ret_0 = ni; - // nested call - - /* istanbul ignore else */ - if (ˆa_6()) { - ni; - break ˆmatch_2; - } + /* istanbul ignore next */ + break ret_0; } + } - // nested member call + /* istanbul ignore else */ + if (null != foo) { + const val_5 = is_foo(foo[0]); /* istanbul ignore else */ - if (typeof ˆvalue_1?.[Symbol.iterator] === \\"function\\") { - const [ˆa_7] = ˆvalue_1; - - // nested member call + if (true === val_5) { + ret_0 = ni; - /* istanbul ignore else */ - if (ˆa_7.is_foo()) { - ni; - break ˆmatch_2; - } + /* istanbul ignore next */ + break ret_0; } + } - // nested as call arg + /* istanbul ignore else */ + if (null != foo) { + const val_4 = is_foo(foo[0], bar); /* istanbul ignore else */ - if (typeof ˆvalue_1?.[Symbol.iterator] === \\"function\\") { - const [ˆa_8] = ˆvalue_1; + if (true === val_4) { + ret_0 = ni; - // nested as call arg - - /* istanbul ignore else */ - if (is_foo(ˆa_8)) { - ni; - break ˆmatch_2; - } + /* istanbul ignore next */ + break ret_0; } + } + /* istanbul ignore else */ + if (null != foo) { /* istanbul ignore else */ - if (typeof ˆvalue_1?.[Symbol.iterator] === \\"function\\") { - const [ˆa_9, ...ˆa_10] = ˆvalue_1; + if (foo[0] === 1) { + const val_3 = is_empty(foo.slice(1)); /* istanbul ignore else */ - if (ˆa_9 === 1) - /* istanbul ignore else */ - if (is_empty(ˆa_10)) { - ni; - break ˆmatch_2; - } + if (true === val_3) { + ret_0 = ni; + + /* istanbul ignore next */ + break ret_0; + } } + } + /* istanbul ignore else */ + if (null != foo) { /* istanbul ignore else */ - if (typeof ˆvalue_1?.[Symbol.iterator] === \\"function\\") { - const [ˆa_11, ...ˆa_12] = ˆvalue_1; + if (foo[0] === 1) { + const right_0 = length(foo.slice(1)); /* istanbul ignore else */ - if (ˆa_11 === 1) - /* istanbul ignore else */ - if (1 < length(ˆa_12)) { - ni; - break ˆmatch_2; - } + if (true === 1 < right_0) { + ret_0 = ni; + + /* istanbul ignore next */ + break ret_0; + } } } -}" +} + +const mex_0 = ret_0;" `; exports[`match iterables matches values 1`] = ` -"{ - ˆmatch_2: { - const ˆvalue_1 = shrub; - - // deep iterable comparison +"let ret_0; +ret_0: { + /* istanbul ignore else */ + if (null != shrub) { /* istanbul ignore else */ - if (typeof ˆvalue_1?.[Symbol.iterator] === \\"function\\") { - const [ˆa_3, ˆa_4, ˆa_5] = ˆvalue_1; - // deep iterable comparison - + if (shrub[0] === 1) { /* istanbul ignore else */ - if (ˆa_3 === 1) // deep iterable comparison + if (shrub[1] === 2) { + const itm_17 = shrub[2]; /* istanbul ignore else */ - if (ˆa_4 === 2) // deep iterable comparison - + if (null != itm_17) { /* istanbul ignore else */ - if (typeof ˆa_5?.[Symbol.iterator] === \\"function\\") { - const [ˆa_6] = ˆa_5; + if (itm_17[0] === ni) { + ret_0 = ni; - // deep iterable comparison - - /* istanbul ignore else */ - if (ˆa_6 === ni) { - ni; - break ˆmatch_2; - } + /* istanbul ignore next */ + break ret_0; } + } + } } + } - // TODO: fix semantics for matching [], {} - + /* istanbul ignore else */ + if (null != shrub) { /* istanbul ignore else */ - if (typeof ˆvalue_1?.[Symbol.iterator] === \\"function\\") { - const [ˆa_7, ˆa_8, ˆa_9, ˆa_10] = ˆvalue_1; - // TODO: fix semantics for matching [], {} + if (shrub[0] === 1) { + const itm_11 = shrub[1]; /* istanbul ignore else */ - if (ˆa_7 === 1) // TODO: fix semantics for matching [], {} - + if (null != itm_11) { /* istanbul ignore else */ - if (ˆa_8 === 2) // TODO: fix semantics for matching [], {} - + if (itm_11[0] === 2) { /* istanbul ignore else */ - if (typeof ˆa_9?.[Symbol.iterator] === \\"function\\") // TODO: fix semantics for matching [], {} - + if (itm_11[1] === 3) { /* istanbul ignore else */ - if (ˆa_10 != null) { - foo; - break ˆmatch_2; - } - } + if (shrub[2] === 4) { + ret_0 = bar; - /* istanbul ignore else */ - if (typeof ˆvalue_1?.[Symbol.iterator] === \\"function\\") { - const [ˆa_11, ˆa_12, ˆa_13] = ˆvalue_1; - - /* istanbul ignore else */ - if (ˆa_11 === 1) - /* istanbul ignore else */ - if (typeof ˆa_12?.[Symbol.iterator] === \\"function\\") { - const [ˆa_14, ˆa_15] = ˆa_12; - - /* istanbul ignore else */ - if (ˆa_14 === 2) - /* istanbul ignore else */ - if (ˆa_15 === 3) - /* istanbul ignore else */ - if (ˆa_13 === 4) { - bar; - break ˆmatch_2; - } + /* istanbul ignore next */ + break ret_0; + } + } } + } } + } + /* istanbul ignore else */ + if (null != shrub) { /* istanbul ignore else */ - if (typeof ˆvalue_1?.[Symbol.iterator] === \\"function\\") { - const [ˆa_16, ˆa_17, ˆa_18, ˆa_19] = ˆvalue_1; + if (shrub[0] === 1) { + const itm_1 = shrub[1]; /* istanbul ignore else */ - if (ˆa_16 === 1) + if (null != itm_1) { /* istanbul ignore else */ - if (typeof ˆa_17?.[Symbol.iterator] === \\"function\\") { - const [ˆa_20, ˆa_21] = ˆa_17; + if (itm_1[0] === 2) { + const itm_3 = itm_1[1]; /* istanbul ignore else */ - if (ˆa_20 === 2) + if (null != itm_3) { /* istanbul ignore else */ - if (typeof ˆa_21?.[Symbol.iterator] === \\"function\\") { - const [ˆa_22, ˆa_23] = ˆa_21; - + if (itm_3[0] === 3) { /* istanbul ignore else */ - if (ˆa_22 === 3) + if (itm_3[1] === 4) { + const itm_6 = shrub[2]; + /* istanbul ignore else */ - if (ˆa_23 === 4) + if (null != itm_6) { /* istanbul ignore else */ - if (typeof ˆa_18?.[Symbol.iterator] === \\"function\\") { - const [ˆa_24, ˆa_25] = ˆa_18; - + if (itm_6[0] === 5) { /* istanbul ignore else */ - if (ˆa_24 === 5) + if (itm_6[1] === 6) { /* istanbul ignore else */ - if (ˆa_25 === 6) - /* istanbul ignore else */ - if (ˆa_19 === 7) { - spam; - break ˆmatch_2; - } + if (shrub[3] === 7) { + ret_0 = spam; + + /* istanbul ignore next */ + break ret_0; + } + } } + } + } } + } } + } } } -}" -`; +} -exports[`match matches simple values 1`] = ` -"{ - ˆmatch_2: { - const ˆvalue_1 = shrub; +const mex_0 = ret_0;" +`; - // simple value +exports[`match iterables matches with ignored items 1`] = ` +"let ret_0; +ret_0: { + /* istanbul ignore else */ + if (null != shrub) { /* istanbul ignore else */ - if (ˆvalue_1 === 123) { - spam; - break ˆmatch_2; - } + if (shrub[0] === 1) { + /* istanbul ignore else */ + if (shrub[2] === 2) { + ret_0 = foo; - // fallback if none of above match - { - shrub; - break ˆmatch_2; + /* istanbul ignore next */ + break ret_0; + } } } -}" +} + +const mex_0 = ret_0;" +`; + +exports[`match matches simple values 1`] = ` +"let ret_0; + +ret_0: { + /* istanbul ignore else */ + if (shrub === 123) { + ret_0 = spam; + + /* istanbul ignore next */ + break ret_0; + } + + ret_0 = shrub; + + /* istanbul ignore next */ + break ret_0; +} + +const mex_0 = ret_0;" `; exports[`match matches value assertions 1`] = ` -"{ - ˆmatch_2: { - const ˆvalue_1 = 123; +"let ret_0; - // simple unary +ret_0: { + /* istanbul ignore else */ + if (true === !123) { + ret_0 = ni; - /* istanbul ignore else */ - if (!ˆvalue_1) { - ni; - break ˆmatch_2; - } + /* istanbul ignore next */ + break ret_0; + } - // simple binary + /* istanbul ignore else */ + if (true === 123 > 123) { + ret_0 = ni; - /* istanbul ignore else */ - if (ˆvalue_1 > 123) { - ni; - break ˆmatch_2; - } + /* istanbul ignore next */ + break ret_0; + } - // simple call + const val_1 = 123(); - /* istanbul ignore else */ - if (ˆvalue_1()) { - ni; - break ˆmatch_2; - } + /* istanbul ignore else */ + if (true === val_1) { + ret_0 = ni; + + /* istanbul ignore next */ + break ret_0; + } - // simple as call arg + const val_0 = shrub(123); - /* istanbul ignore else */ - if (shrub(ˆvalue_1)) { - ni; - break ˆmatch_2; - } + /* istanbul ignore else */ + if (true === val_0) { + ret_0 = ni; - // any value + /* istanbul ignore next */ + break ret_0; + } - /* istanbul ignore else */ - if (ˆvalue_1 !== undefined) { - true; - break ˆmatch_2; - } + /* istanbul ignore else */ + if (undefined !== 123) { + ret_0 = true; + + /* istanbul ignore next */ + break ret_0; } -}" +} + +const mex_0 = ret_0;" `; exports[`match records matches calculated props 1`] = ` -"{ - ˆmatch_2: { - const ˆvalue_1 = shrub; +"let ret_0; - // calculated props +ret_0: { + /* istanbul ignore else */ + if (null != shrub) { + const itm_0 = shrub[a]; /* istanbul ignore else */ - if (ˆvalue_1 != null) { - const { - [a]: ˆp_3 - } = ˆvalue_1; - - // calculated props - + if (null != itm_0) { /* istanbul ignore else */ - if (ˆp_3 != null) { - const { - b: ˆp_4, - c: ˆp_5 - } = ˆp_3; - // calculated props - + if (itm_0.b === b) { /* istanbul ignore else */ - if (ˆp_4 === b) // calculated props + if (itm_0.c === c) { + ret_0 = ni; - /* istanbul ignore else */ - if (ˆp_5 === c) { - ni; - break ˆmatch_2; - } + /* istanbul ignore next */ + break ret_0; + } } } } -}" +} + +const mex_0 = ret_0;" `; exports[`match records matches member expr keys 1`] = ` -"{ - ˆmatch_2: { - const ˆvalue_1 = foo; +"let ret_0; + +ret_0: { + /* istanbul ignore else */ + if (null != shrub) { + const itm_11 = shrub.foo; /* istanbul ignore else */ - if (ˆvalue_1 != null) { - const { - foo: ˆp_3 - } = ˆvalue_1; + if (null != itm_11) { + const itm_12 = itm_11.bar; + + /* istanbul ignore else */ + if (null != itm_12) { + /* istanbul ignore else */ + if (itm_12.spam === ham) { + ret_0 = spam; + + /* istanbul ignore next */ + break ret_0; + } + } + } + } + + /* istanbul ignore else */ + if (null != shrub) { + const itm_6 = shrub.foo; + + /* istanbul ignore else */ + if (null != itm_6) { + const itm_7 = itm_6.bar; /* istanbul ignore else */ - if (ˆp_3 != null) { - const { - bar: ˆp_4 - } = ˆp_3; + if (null != itm_7) { + const itm_8 = itm_7.spam; /* istanbul ignore else */ - if (ˆp_4 != null) { - const { - spam: ˆp_5 - } = ˆp_4; + if (null != itm_8) { + const itm_9 = itm_8.ham; /* istanbul ignore else */ - if (ˆp_5 === ham) { - spam; - break ˆmatch_2; + if (null != itm_9) { + /* istanbul ignore else */ + if (itm_9.ni === nu) { + ret_0 = ham; + + /* istanbul ignore next */ + break ret_0; + } } } } } } -}" -`; -exports[`match records matches member expr keys 2`] = ` -"{ - ˆmatch_2: { - const ˆvalue_1 = foo; + /* istanbul ignore else */ + if (null != shrub) { + const itm_0 = shrub.foo; /* istanbul ignore else */ - if (ˆvalue_1 != null) { - const { - foo: ˆp_3 - } = ˆvalue_1; + if (null != itm_0) { + const itm_1 = itm_0.bar; /* istanbul ignore else */ - if (ˆp_3 != null) { - const { - bar: ˆp_4 - } = ˆp_3; + if (null != itm_1) { + const itm_2 = itm_1.spam; /* istanbul ignore else */ - if (ˆp_4 != null) { - const { - spam: ˆp_5 - } = ˆp_4; + if (null != itm_2) { + const itm_3 = itm_2.ham; /* istanbul ignore else */ - if (ˆp_5 != null) { - const { - ham: ˆp_6 - } = ˆp_5; - + if (null != itm_3) { /* istanbul ignore else */ - if (ˆp_6 != null) { - const { - ni: ˆp_7 - } = ˆp_6; - + if (itm_3.ni === nu) { /* istanbul ignore else */ - if (ˆp_7 === nu) { - spam; - break ˆmatch_2; + if (itm_0.spam === spam) { + ret_0 = ham; + + /* istanbul ignore next */ + break ret_0; } } } @@ -557,348 +723,278 @@ exports[`match records matches member expr keys 2`] = ` } } } -}" +} + +const mex_0 = ret_0;" `; exports[`match records matches props 1`] = ` -"{ - ˆmatch_2: { - const ˆvalue_1 = shrub; - - // TODO: fix semantics for matching {} +"let ret_0; +ret_0: { + /* istanbul ignore else */ + if (null != shrub) { /* istanbul ignore else */ - if (ˆvalue_1 != null) { - const { - foo: ˆp_3 - } = ˆvalue_1; - - // TODO: fix semantics for matching {} - + if (shrub.foo === foo) { /* istanbul ignore else */ - if (ˆp_3 != null) { - spam + ni; - break ˆmatch_2; + if (shrub.bar === bar) { + ret_0 = ni; + + /* istanbul ignore next */ + break ret_0; } } + } - // TODO: fix semantics for matching [] - + /* istanbul ignore else */ + if (null != shrub) { /* istanbul ignore else */ - if (ˆvalue_1 != null) { - const { - foo: ˆp_4 - } = ˆvalue_1; - - // TODO: fix semantics for matching [] + if (shrub.foo === 4) { + const itm_13 = shrub.ni; /* istanbul ignore else */ - if (typeof ˆp_4?.[Symbol.iterator] === \\"function\\") { - spam + ni; - break ˆmatch_2; + if (null != itm_13) { + /* istanbul ignore else */ + if (itm_13.na === na) { + /* istanbul ignore else */ + if (itm_13.nu === nu) { + ret_0 = spam + ni; + + /* istanbul ignore next */ + break ret_0; + } + } } } + } + /* istanbul ignore else */ + if (null != shrub) { /* istanbul ignore else */ - if (ˆvalue_1 != null) { - const { - foo: ˆp_5, - ni: ˆp_6 - } = ˆvalue_1; + if (shrub.foo === 1) { + const itm_8 = shrub.foo; /* istanbul ignore else */ - if (ˆp_5 === 4) + if (null != itm_8) { /* istanbul ignore else */ - if (ˆp_6 != null) { - const { - na: ˆp_7, - nu: ˆp_8 - } = ˆp_6; + if (itm_8.bar === \`spam\`) { + const itm_10 = shrub.shrub; /* istanbul ignore else */ - if (ˆp_7 === na) + if (null != itm_10) { /* istanbul ignore else */ - if (ˆp_8 === nu) { - spam + ni; - break ˆmatch_2; + if (itm_10.na === \`nu\`) { + ret_0 = ni; + + /* istanbul ignore next */ + break ret_0; } + } } + } } + } - /* istanbul ignore else */ - if (ˆvalue_1 != null) { - const { - foo: ˆp_9, - foo: ˆp_10, - shrub: ˆp_11 - } = ˆvalue_1; + /* istanbul ignore else */ + if (null != shrub) { + const itm_3 = shrub.ni; + /* istanbul ignore else */ + if (null != itm_3) { /* istanbul ignore else */ - if (ˆp_9 === 1) - /* istanbul ignore else */ - if (ˆp_10 != null) { - const { - bar: ˆp_12 - } = ˆp_10; + if (itm_3.len === 1) { + const itm_5 = shrub.na; + /* istanbul ignore else */ + if (null != itm_5) { /* istanbul ignore else */ - if (ˆp_12 === \`spam\`) - /* istanbul ignore else */ - if (ˆp_11 != null) { - const { - na: ˆp_13 - } = ˆp_11; + if (itm_5.len === 1) { + ret_0 = na; - /* istanbul ignore else */ - if (ˆp_13 === \`nu\`) { - ni; - break ˆmatch_2; - } - } + /* istanbul ignore next */ + break ret_0; + } } + } } + } - /* istanbul ignore else */ - if (ˆvalue_1 != null) { - const { - ni: ˆp_14, - na: ˆp_15 - } = ˆvalue_1; + /* istanbul ignore else */ + if (null != shrub) { + const itm_0 = shrub.ni; + /* istanbul ignore else */ + if (null != itm_0) { /* istanbul ignore else */ - if (ˆp_14 != null) { - const { - len: ˆp_16 - } = ˆp_14; - + if (itm_0[0] === foo) { /* istanbul ignore else */ - if (ˆp_16 === 1) - /* istanbul ignore else */ - if (ˆp_15 != null) { - const { - len: ˆp_17 - } = ˆp_15; + if (itm_0[1] === 1234) { + ret_0 = na; - /* istanbul ignore else */ - if (ˆp_17 === 1) { - na; - break ˆmatch_2; - } - } + /* istanbul ignore next */ + break ret_0; + } } } } -}" +} + +const mex_0 = ret_0;" `; exports[`match records matches spread 1`] = ` -"{ - ˆmatch_2: { - const ˆvalue_1 = shrub; - - // spread +"let ret_0; +ret_0: { + /* istanbul ignore else */ + if (null != shrub) { /* istanbul ignore else */ - if (ˆvalue_1 != null) { + if (undefined !== shrub[foo]) { const { - [foo]: ˆp_3, - ...ˆp_4 - } = ˆvalue_1; - // spread + [foo]: _foo, + ...spread_0 + } = shrub; /* istanbul ignore else */ - if (ˆp_3 != null) // spread - // spread - + if (null != spread_0) { /* istanbul ignore else */ - if (ˆp_4 != null) { - const { - bar: ˆp_5, - spam: ˆp_6 - } = ˆp_4; - // spread - + if (spread_0.bar === bar) { /* istanbul ignore else */ - if (ˆp_5 === bar) // spread + if (spread_0.spam === spam) { + ret_0 = ni; - /* istanbul ignore else */ - if (ˆp_6 === spam) { - ni; - break ˆmatch_2; - } + /* istanbul ignore next */ + break ret_0; + } } + } } } -}" +} + +const mex_0 = ret_0;" `; exports[`match records matches value assertions 1`] = ` "import { _in_ } from \\"@fink/js-interop/runtime.js\\"; -{ - ˆmatch_2: { - const ˆvalue_1 = foo; - - // nested unary +let ret_0; +ret_0: { + /* istanbul ignore else */ + if (null != foo) { /* istanbul ignore else */ - if (ˆvalue_1 != null) { - const { - spam: ˆp_3 - } = ˆvalue_1; - - // nested unary + if (true === !foo.spam) { + ret_0 = ni; - /* istanbul ignore else */ - if (!ˆp_3) { - ni; - break ˆmatch_2; - } + /* istanbul ignore next */ + break ret_0; } + } - // nested binary - + /* istanbul ignore else */ + if (null != foo) { /* istanbul ignore else */ - if (ˆvalue_1 != null) { - const { - spam: ˆp_4 - } = ˆvalue_1; - - // nested binary + if (true === foo.spam > 123) { + ret_0 = ni; - /* istanbul ignore else */ - if (ˆp_4 > 123) { - ni; - break ˆmatch_2; - } + /* istanbul ignore next */ + break ret_0; } + } - // nested call + /* istanbul ignore else */ + if (null != foo) { + const val_6 = foo.spam(); /* istanbul ignore else */ - if (ˆvalue_1 != null) { - const { - spam: ˆp_5 - } = ˆvalue_1; - - // nested call + if (true === val_6) { + ret_0 = ni; - /* istanbul ignore else */ - if (ˆp_5()) { - ni; - break ˆmatch_2; - } + /* istanbul ignore next */ + break ret_0; } + } - // nested member call + /* istanbul ignore else */ + if (null != foo) { + const val_5 = foo.spam.is_foo(); /* istanbul ignore else */ - if (ˆvalue_1 != null) { - const { - spam: ˆp_6 - } = ˆvalue_1; - - // nested member call + if (true === val_5) { + ret_0 = ni; - /* istanbul ignore else */ - if (ˆp_6.is_foo()) { - ni; - break ˆmatch_2; - } + /* istanbul ignore next */ + break ret_0; } + } - // nested as call arg + /* istanbul ignore else */ + if (null != foo) { + const val_4 = is_foo(foo.spam); /* istanbul ignore else */ - if (ˆvalue_1 != null) { - const { - spam: ˆp_7 - } = ˆvalue_1; - - // nested as call arg + if (true === val_4) { + ret_0 = ni; - /* istanbul ignore else */ - if (is_foo(ˆp_7)) { - ni; - break ˆmatch_2; - } + /* istanbul ignore next */ + break ret_0; } + } - /* istanbul ignore else */ - if (ˆvalue_1 != null) { - const { - spam: ˆp_8, - ...ˆp_9 - } = ˆvalue_1; - - /* istanbul ignore else */ - if (ˆp_8 === spam) - /* istanbul ignore else */ - if (is_empty(ˆp_9)) { - ni; - break ˆmatch_2; - } - } + /* istanbul ignore else */ + if (null != foo) { + const key_2 = \`spam\`; /* istanbul ignore else */ - if (ˆvalue_1 != null) { + if (foo.spam === spam) { const { - spam: ˆp_10, - ...ˆp_11 - } = ˆvalue_1; + spam: _key_2, + ...spread_1 + } = foo; + const val_3 = is_empty(spread_1); /* istanbul ignore else */ - if (ˆp_10 === spam) - /* istanbul ignore else */ - if (_in_(\`foo\`, ˆp_11)) { - ni; - break ˆmatch_2; - } + if (true === val_3) { + ret_0 = ni; + + /* istanbul ignore next */ + break ret_0; + } } + } - // any value + /* istanbul ignore else */ + if (null != foo) { + const key_1 = \`spam\`; /* istanbul ignore else */ - if (ˆvalue_1 != null) { + if (foo.spam === spam) { const { - spam: ˆp_12 - } = ˆvalue_1; - - // any value + spam: _key_1, + ...spread_0 + } = foo; /* istanbul ignore else */ - if (ˆp_12 !== undefined) { - true; - break ˆmatch_2; + if (true === _in_(\`foo\`, spread_0)) { + ret_0 = ni; + + /* istanbul ignore next */ + break ret_0; } } } -}" -`; - -exports[`match value assertions compiles do-expr 1`] = ` -"let _do_result; - -ˆmatch_2: { - const ˆvalue_1 = bar; /* istanbul ignore else */ - if (ˆvalue_1 === spam) { - { - ni; - _do_result = shrub(foobar); - } - break ˆmatch_2; - } + if (null != foo) { + /* istanbul ignore else */ + if (undefined !== foo.spam) { + ret_0 = true; - { - { - shrub; - _do_result = spam(ni); + /* istanbul ignore next */ + break ret_0; } - break ˆmatch_2; } } -export const foo = _do_result; -_do_result = undefined;" +const mex_0 = ret_0;" `; diff --git a/src/js/context.fnk b/src/js/context.fnk index 6b9d51c..26d3537 100644 --- a/src/js/context.fnk +++ b/src/js/context.fnk @@ -1,38 +1,52 @@ -{is_fn} = import '@fink/std-lib/fn.fnk' +{update_value, get_value} = import '../ir/context.fnk' +{ident} = import './identifier/init.fnk' -{add_runtime_fn, set_runtime_impl} = import './runtime.fnk' -any = false +set_js = fn id, js, ctx: + update_value id, {js}, ctx -add = fn type, op, transformer: fn {transformers, ...ctx}: - next_transformers = rec: - ...transformers - (type or op): transformer +set_js2 = fn [{loc}, [id]], js, ctx: + update_value id, {js: {...js, loc}}, ctx - {transformers: next_transformers, ...ctx} + +with_loc = fn {loc}, expr: + {...expr, loc} + + +get_js = fn id, ctx: + val = get_value id, ctx + match val: + # TODO: use inline: true? + {ignore_refs: true}: with_loc id, val.js + {inline: true}: with_loc id, val.js + {inline: false}: ident id + {refs: ? > 1}: ident id + {js: ?}: with_loc id, val.js + else: ident id +add_runtime_requirement = fn func, {runtime, ...ctx}: + {...ctx, runtime: {...runtime, (func): true}} -add_with_runtime = fn type, op, transformer, impl_uri: fn ctx: - built_in_name = '_${op}_' - pipe ctx: - add_runtime_fn built_in_name, ? - set_runtime_impl built_in_name, impl_uri, ? - add type, op, transformer +# TODO: inlining should be handled at optimization level in ir +get_js_literal = fn id, ctx: + {js=get_js id, ctx} = get_value id, ctx + js -get_transformer = fn {op, type}, {transformers}: - match transformers: - {(op): is_fn ?}: - {(op): transform} = transformers - transform - {(type): is_fn ?}: - {(type): transform} = transformers - transform +add = fn name, transformer: fn {transformers, ...ctx}: + next_transformers = rec: + ...transformers + (name): transformer + + {transformers: next_transformers, ...ctx} + + - else: - false +get_transformer = fn [{f: name}], {transformers}: + {(name): transform} = transformers + transform diff --git a/src/js/do-expression.fnk b/src/js/do-expression.fnk deleted file mode 100644 index 092ee1a..0000000 --- a/src/js/do-expression.fnk +++ /dev/null @@ -1,173 +0,0 @@ -babel_types = import '@babel/types' -{ - assignmentExpression, returnStatement - isDoExpression, isBlockStatement, isLabeledStatement - isVariableDeclarator, isArrowFunctionExpression, isExpressionStatement - isAssignmentExpression - isReturnStatement - arrowFunctionExpression, callExpression, blockStatement -} = babel_types -{set_props} = import '@fink/js-interop/reflect.fnk' -{undefined} = import '@fink/js-interop/nullish.fnk' -{fold, map, is_empty} = import '@fink/std-lib/iter.fnk' -{wrap_with_comment_loc} = import './comments/init.fnk' - -{lets, assign, undef} = import './types.fnk' - - -get_body = ?.get 'body' - - - -consume_all = fold fn: undefined - - - -simple = fn body, sl=false: - match body: - isBlockStatement ?: - [stmnt, ...rest] = get_body body - - match rest: - is_empty ?: - # e.g. fn arg: match ...: ... - match {sl, stmnt}: - {sl: true, stmnt: isLabeledStatement ?}: - stmnt.node.body - else: - simple stmnt - else: - body.node - else: - body.node - - - -last_expressions = fn path: - match path: - isDoExpression ?: - body = get_body path - [...last_expressions body] - - isBlockStatement ?: - body = get_body path - [..., last] = body - match last: - isExpressionStatement ?: - [last] - else: - [...last_expressions last] - - --- istanbul ignore else --- - isLabeledStatement ?: - body = get_body path - - # TODO: don't use mutable obj - items = [] - body.traverse - rec: - LabeledStatement: ?.skip _ - - BreakStatement: fn brk: - last = brk.getSibling brk.key - 1 - items.push last - undefined - items - - - -replace_with_return = fn path: - pipe last_expressions path: - map fn expr: - expr.replaceWith - wrap_with_comment_loc - returnStatement expr.node.expression - expr.node.expression - - # TODO: no need for e.g. breaks after a return - sibl = expr.getSibling expr.key + 1 - match sibl: - # TODO `?:` - --- istanbul ignore next --- - {}: - sibl.remove _ - - consume_all - - - -replace_with_assign = fn target, path: - id = path.parentPath.scope.generateUidIdentifier 'do_result' - #TODO: don't mutate - set_props target.node, {init: id} - - # TODO: needs loc - target.parentPath.insertBefore lets id - target.parentPath.insertBefore simple get_body path - target.parentPath.insertAfter assign id, undef _ - - pipe last_expressions path: - map fn expr: - expr.replaceWith - wrap_with_comment_loc - assignmentExpression '=', id, expr.node.expression - expr.node.expression - - consume_all - - -replace_with_simple_assign = fn target, path: - id = target.node.left - target.parentPath.insertBefore blockStatement path.node.body.body - - pipe last_expressions path: - map fn expr: - expr.replaceWith - wrap_with_comment_loc - assignmentExpression '=', id, expr.node.expression - expr.node.expression - - consume_all - - target.replaceWithMultiple [] - - - -transform_do_expr = fn path: - {parentPath: parent} = path - - match parent: - isVariableDeclarator ?: - replace_with_assign parent, path - - isArrowFunctionExpression ?: - body = get_body path - - set_props parent.node, {body: simple body, true} - - replace_with_return path - - isExpressionStatement ?: - # this is used e.g. for conditional at the module level - parent.replaceWith - get_body path - - isReturnStatement ?: - body = get_body path - - parent.replaceWith - simple body, true - - replace_with_return path - - - isAssignmentExpression ?: - replace_with_simple_assign parent, path - - else: - # TODO: {spam.ham.ni: {foo, bar} = spam - arrow = arrowFunctionExpression [], path.node - path.replaceWith - callExpression arrow, [] - - undefined diff --git a/src/js/func/init.fnk b/src/js/func/init.fnk index 5ed7e2e..e47962f 100644 --- a/src/js/func/init.fnk +++ b/src/js/func/init.fnk @@ -1,36 +1,175 @@ -babel_types = import '@babel/types' -{arrowFunctionExpression} = babel_types +types = import '@babel/types' +{ + arrowFunctionExpression, blockStatement, returnStatement, restElement + labeledStatement, doWhileStatement, booleanLiteral +} = types -{unique_ident} = import '../../js/types.fnk' -{transform_left} = import '../../js/left.fnk' -{add, any} = import '../context.fnk' -{transform_block} = import '../block/init.fnk' -{transform, map_with_ctx, collect_with_ctx} = import '../transform.fnk' +{get_refs, dec_ref, update_value} = import '../../ir/context.fnk' +{transform_exprs} = import '../transform.fnk' +{add, set_js, set_js2} = import '../context.fnk' +{ident} = import '../identifier/init.fnk' +clean_args = fn args, body, ctx, out=[]: + match args: + {c: ? < 0}: + [out, body, ctx] -transform_arg = fn arg, ctx: - match arg: - {type: 'empty'}: - unique_ident '', ctx + {(args.c): ?}: + clean_args {...args, c: args.c - 1}, body, ctx, [args.(args.c), ...out] + + else: + # TODO: unique id + unused = ident {i: '_${args.c}'} + clean_args {...args, c: args.c - 1}, body, ctx, [unused, ...out] + + + +# These are mostly ir transformations, should this be done as a prep step +split_args_body = fn [expr=false, ...exprs], args_id, ctx, args={c: -1}, body=[]: + match expr: + false: + [args, body, ctx] + + [{f: 'tpl_i', args: [{i: args_id.i}]}]: + [{args: [tpl_id, idx]}, [arg_id]] = expr + + match idx: + ? < 0: + split_args_body exprs, args_id, ctx, args, [...body, expr] + else: match args: + {foo: true}: + [foo] = expr + nexpr = [{...foo, args: [tpl_id, idx - args.c - 1]}, [arg_id]] + split_args_body exprs, args_id, ctx, args, [...body, nexpr] + else: + arg = ident arg_id + nargs = {...args, c: idx, (idx): arg} + next_ctx = pipe ctx: + set_js2 expr, arg, ? + dec_ref args_id, ? + split_args_body exprs, args_id, next_ctx, nargs, body + + [{f: 'tpl_s', args: [{i: args_id.i}]}]: + [{args: [args_id, start, end], ...rex}, res] = expr + [foo, next_ctx] = match [start, end]: + [args.c + 1, 0]: + slc = ident args_id + next_ctx = set_js2 expr, slc, ctx + [[], next_ctx] + else: + [[[{...rex, args: [args_id, start - args.c - 1, end]}, res]], ctx] + split_args_body exprs, args_id, next_ctx, {...args, foo: true}, [...body, ...foo] + + [{f: ? in ['fn', 'cn']}]: + [foo, bar] = expr + {args: [fargs, fbody]} = foo + [next_args, next_body, next_ctx] = split_args_body fbody, args_id, ctx, args + nexpr = [{...foo, args: [fargs, next_body]}, bar] + split_args_body exprs, args_id, next_ctx, next_args, [...body, nexpr] + + else: + split_args_body exprs, args_id, ctx, args, [...body, expr] + + + +transform_normal_fn = fn expr, ctx: + [{args: [fn_args, fn_block]}, [res_id]] = expr + [args_id, ret_id, self_id=false] = fn_args + + ret = rec: + ...returnStatement _ + leadingComments: [{type: 'CommentBlock', value: ' istanbul ignore next '}] + + self_ctx = set_js ret_id, ret, ctx + + body_ctx = match self_id: + false: self_ctx + else: + pipe self_ctx: + # set recursive calls to use res_id + # instead of using a Z-combinator and self_id + set_js self_id, (ident res_id), ? + # make sure calls to self_id always use res_id + update_value self_id, {ignore_refs: true}, ? + + [args, block, fn_ctx] = pipe body_ctx: + split_args_body fn_block, args_id, ? + clean_args ...? + + all_args = match get_refs args_id, fn_ctx: + ? > 0: [...args, restElement ident args_id] + else: args + + [body, next_ctx] = transform_exprs block, fn_ctx + + js = arrowFunctionExpression all_args, blockStatement body + + set_js2 expr, js, next_ctx + + + +# TODO merge with transform_normal_fn +transform_tco_fn = fn expr, ctx: + [{args: [fn_args, block]}, [res_id]] = expr + [args_id, ret_id, self_id] = fn_args + + ret = rec: + ...returnStatement _ + leadingComments: [{type: 'CommentBlock', value: ' istanbul ignore next '}] + + body_ctx = pipe ctx: + # set recursive calls and continue label to use res_id + # instead of a Z-combinator and self_id + set_js ret_id, ret, ? + set_js self_id, (ident res_id), ? + # make sure continue statements and calls to self_id always use res_id + update_value self_id, {args_id, label_id: res_id, ignore_refs: true}, ? + + [body, next_ctx] = transform_exprs block, body_ctx + + js = arrowFunctionExpression + [restElement ident args_id] + blockStatement list: + labeledStatement + ident res_id + doWhileStatement + booleanLiteral true + blockStatement body + + set_js2 expr, js, next_ctx + + + +transform_fn = fn expr, ctx: + match expr: + [{tco: true}]: + transform_tco_fn expr, ctx else: - [t_arg, next_ctx] = transform arg, ctx - js_arg = transform_left t_arg - [js_arg, next_ctx] + transform_normal_fn expr, ctx -transform_func = fn node, ctx: - [params, next_ctx] = pipe node.args: - map_with_ctx transform_arg - collect_with_ctx ctx +transform_cont = fn expr, ctx: + [{args: [args, block]}] = expr - [body, end_ctx] = transform_block node, next_ctx - js = arrowFunctionExpression params, body + [ret_id=false] = args + [body, next_ctx]= transform_exprs block, ctx - [js, end_ctx] + js = match ret_id: + false: + blockStatement body + else: + labeledStatement + ident ret_id + blockStatement body + + set_js2 expr, js, next_ctx -add_func = fn ctx: + +add_funcs = fn ctx: pipe ctx: - add any, 'fn', transform_func + add 'fn', transform_fn + add 'cn', transform_cont + diff --git a/src/js/func/init.test.fnk b/src/js/func/init.test.fnk index b2149ec..32120c6 100644 --- a/src/js/func/init.test.fnk +++ b/src/js/func/init.test.fnk @@ -1,79 +1,166 @@ -{fink2js} = import '../../testing/generate.fnk' {describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' +{fink2js} = import '../../testing/generate.fnk' describe 'func', fn: + it 'compiles no args', fn: + expect + fink2js " + fun = fn: 'shrub' + " + to_match_snapshot + + + it 'compiles simple', fn: + expect + fink2js ' + fun = fn a, b, c: + a + b + c + ' + to_match_snapshot + + + it 'compiles empty arg', fn: + expect + fink2js ' + fun = fn a, , , b: + a + b + ' + to_match_snapshot + + expect + fink2js ' + fun = fn a, , , b: + b + ' + to_match_snapshot + + expect + fink2js ' + fun = fn _, a: + a + ' + to_match_snapshot + + it 'compiles spread', fn: expect fink2js ' - fun = fn a, b=12, ...d: a + b + c + fun = fn a, b, ...c: + [a + b, c] ' to_match_snapshot + expect + fink2js ' + fun = fn a, ...b: + [a, b] + ' + to_match_snapshot - it 'compiles single line', fn: expect - fink2js " - fun = fn: 'shrub' - " + fink2js ' + fun = fn ...a: + [a] + ' to_match_snapshot + expect + fink2js ' + fun = fn a, b, ...args: + match a: + b: + [c, d] = args + [a, c, d] + else: b + ' + to_match_snapshot - it 'compiles func of func', fn: + it 'compiles middle spread', fn: expect fink2js ' - fun5 = fn c: fn d, e: - match [d, e]: - [1, 2]: c - [2, 1]: 1 / c + fun = fn a, b, ...c, d: + [a + b, c, d] ' to_match_snapshot - it 'compiles other', fn: + it 'compiles destructuring args', fn: expect fink2js ' - fun = fn c, d: - x = 123 - match ni: - c + x: d - c + 1: d + 1 + fun = fn [a, [b]], [c, ...d]: + [a + b, c, d] ' to_match_snapshot + expect + fink2js ' + fun = fn {a, b}, [c, ...d]: + [a + b, c] + ' + to_match_snapshot - it 'compiles defaults', fn: + + it 'compiles destructuring args in body', fn: expect fink2js ' - fun = fn a, b=12, c: - shrub ...a - bar _ + fun = fn a, b, ...c: + [d, e] = c + [a + b, c, d, e] ' to_match_snapshot - it 'compiles empty arg', fn: + it 'compiles func of func', fn: expect fink2js ' - fun = fn a, , , b: - b + fun5 = fn c: fn d, e: + match [d, e]: + [1, 2]: c + [2, 1]: 1 / c ' to_match_snapshot - it 'eliminates tail calls', fn: + it 'compiles defaults', fn: expect fink2js ' - fun = fn a, b=1: - match a: - b: a - else: fun a - 1 + fun = fn a, b=12, c: + ni = shrub a, b + bar b, ni ' to_match_snapshot + + +describe 'recursive functions', fn: + it 'compiles with self reference', fn: + expect + fink2js ' + foo = fn cntr: + match cntr: + 0: [cntr] + 1: [...foo cntr - 1] + else: [cntr, ...foo cntr - 1] + ' + to_match_snapshot + + + it 'compiles to while loop', fn: + expect + fink2js ' + gcd = fn x, y: + match y: + 0: x + else: gcd y, x % y + ' + to_match_snapshot + + + it 'compiles spread', fn: expect fink2js ' - fun = fn ...args: + fun = fn a, b, ...args: match a: b: fun ...args else: b diff --git a/src/js/func/init.test.fnk.snap b/src/js/func/init.test.fnk.snap index f184e3f..814567e 100644 --- a/src/js/func/init.test.fnk.snap +++ b/src/js/func/init.test.fnk.snap @@ -1,101 +1,213 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`func compiles defaults 1`] = ` -"export const fun = (a, b = 12, c) => { - shrub(...a); - return bar(); -};" +"const fun_0 = (a_0, hdm_0) => { + const b_0 = undefined === hdm_0 ? 12 : hdm_0; + const ni_0 = shrub(a_0, b_0); + const result_1 = bar(b_0, ni_0); + return result_1; +}; + +export const fun = fun_0;" `; -exports[`func compiles empty arg 1`] = `"export const fun = (a, ˆ_1, ˆ_2, b) => b;"`; +exports[`func compiles destructuring args 1`] = ` +"const fun_0 = (dlst_0, dlst_2) => { + return [dlst_0[0] + dlst_0[1][0], dlst_2[0], dlst_2.slice(1)]; +}; -exports[`func compiles func of func 1`] = ` -"export const fun5 = c => (d, e) => { - const ˆvalue_1 = [d, e]; +export const fun = fun_0;" +`; - /* istanbul ignore else */ - if (typeof ˆvalue_1?.[Symbol.iterator] === \\"function\\") { - const [ˆa_3, ˆa_4] = ˆvalue_1; +exports[`func compiles destructuring args 2`] = ` +"const fun_0 = (drec_0, dlst_0) => { + return [drec_0.a + drec_0.b, dlst_0[0]]; +}; + +export const fun = fun_0;" +`; + +exports[`func compiles destructuring args in body 1`] = ` +"const fun_0 = (a_0, b_0, ...args_0) => { + return [a_0 + b_0, args_0, args_0[0], args_0[1]]; +}; + +export const fun = fun_0;" +`; + +exports[`func compiles empty arg 1`] = ` +"const fun_0 = (a_0, _1, _2, b_0) => { + return a_0 + b_0; +}; + +export const fun = fun_0;" +`; + +exports[`func compiles empty arg 2`] = ` +"const fun_0 = (_0, _1, _2, b_0) => { + return b_0; +}; + +export const fun = fun_0;" +`; + +exports[`func compiles empty arg 3`] = ` +"const fun_0 = (_0, a_0) => { + return a_0; +}; + +export const fun = fun_0;" +`; + +exports[`func compiles func of func 1`] = ` +"const fun5_0 = c_0 => { + return (d_0, e_0) => { + const value_0 = [d_0, e_0]; /* istanbul ignore else */ - if (ˆa_3 === 1) + if (null != value_0) { /* istanbul ignore else */ - if (ˆa_4 === 2) { - return c; + if (d_0 === 1) { + /* istanbul ignore else */ + if (e_0 === 2) { + return c_0; + } } - } - - /* istanbul ignore else */ - if (typeof ˆvalue_1?.[Symbol.iterator] === \\"function\\") { - const [ˆa_5, ˆa_6] = ˆvalue_1; + } /* istanbul ignore else */ - if (ˆa_5 === 2) + if (null != value_0) { /* istanbul ignore else */ - if (ˆa_6 === 1) { - return 1 / c; + if (d_0 === 2) { + /* istanbul ignore else */ + if (e_0 === 1) { + return 1 / c_0; + } } - } -};" + } + + /* istanbul ignore next */ + return; + }; +}; + +export const fun5 = fun5_0;" `; -exports[`func compiles other 1`] = ` -"export const fun = (c, d) => { - const x = 123; - { - const ˆvalue_1 = ni; +exports[`func compiles middle spread 1`] = ` +"const fun_0 = (a_0, b_0, ...args_0) => { + return [a_0 + b_0, args_0.slice(0, -1), args_0.at(-1)]; +}; - /* istanbul ignore else */ - if (ˆvalue_1 === c + x) { - return d; - } +export const fun = fun_0;" +`; - /* istanbul ignore else */ - if (ˆvalue_1 === c + 1) { - return d + 1; - } - } -};" +exports[`func compiles no args 1`] = ` +"const fun_0 = () => { + return \`shrub\`; +}; + +export const fun = fun_0;" `; -exports[`func compiles single line 1`] = `"export const fun = () => \`shrub\`;"`; +exports[`func compiles simple 1`] = ` +"const fun_0 = (a_0, b_0, c_0) => { + return a_0 + b_0 + c_0; +}; -exports[`func compiles spread 1`] = `"export const fun = (a, b = 12, ...d) => a + b + c;"`; +export const fun = fun_0;" +`; -exports[`func eliminates tail calls 1`] = ` -"export const fun = (..._args) => { - while (true) { - const [a, b = 1] = _args; - const ˆvalue_1 = a; +exports[`func compiles spread 1`] = ` +"const fun_0 = (a_0, b_0, ...args_0) => { + return [a_0 + b_0, args_0]; +}; - /* istanbul ignore else */ - if (ˆvalue_1 === b) { - return a; - } +export const fun = fun_0;" +`; - { - _args = [a - 1]; - continue; - } +exports[`func compiles spread 2`] = ` +"const fun_0 = (a_0, ...args_0) => { + return [a_0, args_0]; +}; + +export const fun = fun_0;" +`; + +exports[`func compiles spread 3`] = ` +"const fun_0 = (...args_0) => { + return [args_0]; +}; + +export const fun = fun_0;" +`; + +exports[`func compiles spread 4`] = ` +"const fun_0 = (a_0, b_0, c_0, d_0) => { + /* istanbul ignore else */ + if (a_0 === b_0) { + return [a_0, c_0, d_0]; } -};" + + return b_0; +}; + +export const fun = fun_0;" `; -exports[`func eliminates tail calls 2`] = ` -"export const fun = (..._args) => { - while (true) { - const [...args] = _args; - const ˆvalue_1 = a; +exports[`recursive functions compiles spread 1`] = ` +"const fun_0 = (...args_0) => { + fun_0: do { + const b_0 = args_0[1]; /* istanbul ignore else */ - if (ˆvalue_1 === b) { - _args = [...args]; - continue; + if (args_0[0] === b_0) { + args_0 = [...args_0.slice(2)]; + continue fun_0; } - { - return b; + return b_0; + } while (true); +}; + +export const fun = fun_0;" +`; + +exports[`recursive functions compiles to while loop 1`] = ` +"const gcd_0 = (...args_0) => { + gcd_0: do { + const x_0 = args_0[0]; + const y_0 = args_0[1]; + + /* istanbul ignore else */ + if (y_0 === 0) { + return x_0; } + + args_0 = [y_0, x_0 % y_0]; + continue gcd_0; + } while (true); +}; + +export const gcd = gcd_0;" +`; + +exports[`recursive functions compiles with self reference 1`] = ` +"const foo_0 = cntr_0 => { + /* istanbul ignore else */ + if (cntr_0 === 0) { + return [cntr_0]; } -};" + + /* istanbul ignore else */ + if (cntr_0 === 1) { + const items_1 = foo_0(cntr_0 - 1); + return [...items_1]; + } + + const items_0 = foo_0(cntr_0 - 1); + return [cntr_0, ...items_0]; +}; + +export const foo = foo_0;" `; diff --git a/src/js/group/init.fnk b/src/js/group/init.fnk deleted file mode 100644 index a115e98..0000000 --- a/src/js/group/init.fnk +++ /dev/null @@ -1,15 +0,0 @@ -{add, any} = import '../context.fnk' -{transform} = import '../transform.fnk' - - - -transform_group = fn node, ctx: - # TODO: what if group has multiple expr - [expr] = node.exprs - transform expr, ctx - - - -add_group = fn ctx: - pipe ctx: - add 'group', any, transform_group diff --git a/src/js/identifier.fnk b/src/js/identifier.fnk deleted file mode 100644 index 0b6bfa7..0000000 --- a/src/js/identifier.fnk +++ /dev/null @@ -1,30 +0,0 @@ -{rx , matches, replace} = import '@fink/std-lib/regex.fnk' - - - -acceptable_idents = rx' - ^(?!(?: - do|if|in|for|let|new|try|var|case|enum|void|with|break|catch|class| - const|super|while|yield|delete|export|import|public|return|static|switch| - typeof|default|extends|finally|package|private|continue|function| - arguments|interface|protected|implements|instanceof|null|undefined - )$) - [_$\p{L}][-_$\p{L}\p{N}]*$' - - -# valid hyphen replacements for js idents [ˉ, ـ, ᅳ, ᅳ, ᐨ, ᜭ] -hyphen_replacement = 'ᜭ' - - -escape_prop = fn name: - replace name, rx'-', hyphen_replacement - - -escape_ident = fn ident, {ident_prefix}: - name = escape_prop ident - - match name: - matches ?, acceptable_idents: - name - else: - '${ident_prefix}${name}' diff --git a/src/js/identifier/init.fnk b/src/js/identifier/init.fnk index af76bef..3e08a12 100644 --- a/src/js/identifier/init.fnk +++ b/src/js/identifier/init.fnk @@ -1,18 +1,108 @@ -babel_types = import '@babel/types' -{identifier} = babel_types +types = import '@babel/types' +{identifier} = types -{escape_ident} = import '../../js/identifier.fnk' -{add, any} = import '../context.fnk' +{rx , matches, replace} = import '@fink/std-lib/regex.fnk' -transform_ident = fn {value}, ctx: - name = escape_ident value, ctx - js = identifier name - [js, ctx] +acceptable_idents = rx' + ^(?!(?: + do|if|in|for|let|new|try|var|case|enum|void|with|break|catch|class| + const|super|while|yield|delete|export|import|public|return|static|switch| + typeof|default|extends|finally|package|private|continue|function| + arguments|interface|protected|implements|instanceof|null|undefined + )$) + [_$\p{L}][_$\p{L}\p{N}]*$' +# valid hyphen replacements for js idents [ˉ, ـ, ᅳ, ᅳ, ᐨ, ᜭ] +hyphen_replacement = 'ᜭ' + + +escape_hyphen = fn name: + replace name, rx'-', hyphen_replacement + + +is_js_ident = fn ident: + matches ident, acceptable_idents + + +escape_ident = fn ident: + name = escape_hyphen ident + + match name: + matches ?, acceptable_idents: + name + else: + 'ˆ${name}' + + + +replace_refs = fn [id=false, ...ids], renames, out=[]: + match id: + false: + out + else: + {(id.i): new_id=escape_ident id.i} = renames + replace_refs ids, renames, [...out, {...id, i: new_id}] + + + +rename = fn [id=false, ...ids], renames, out=[]: + match id: + false: + [out, renames] + else: + new_id = escape_ident id.i + nrs = {...renames, (id.i): new_id} + rename ids, nrs, [...out, {...id, i: new_id}] + + + + +safe_names = fn [curr=false, ...exprs], renames={}, out=[]: + match curr: + false: [out, renames] + + [{f: ? in ['int', 'float', 'str']}]: + [expr, res] = curr + [nres, next_ren] = rename res, renames + safe_names exprs, next_ren, [...out, [expr, nres]] + + [{f: ? in ['tpl_i', 'tpl_s']}]: + [expr, res] = curr + {args: [tpl_id, ...rest_args]} = expr + nargs = replace_refs [tpl_id], renames + nexpr = {...expr, args: [...nargs, ...rest_args]} + [nres, next_ren] = rename res, renames + safe_names exprs, next_ren, [...out, [nexpr, nres]] + + [{f: ? in ['fn', 'cn']}]: + [expr, res] = curr + {args: [args, body]} = expr + [nargs, bod_ren] = rename args, renames + [nbody, res_ren] = safe_names body, bod_ren + nexpr = {...expr, args: [nargs, nbody]} + [nres, next_ren] = rename res, res_ren + safe_names exprs, next_ren, [...out, [nexpr, nres]] + + else: + [expr, res] = curr + {args} = expr + nargs = replace_refs args, renames + nexpr = {...expr, args: nargs} + [nres, next_ren] = rename res, renames + safe_names exprs, next_ren, [...out, [nexpr, nres]] + + + +replace_idents = fn exprs: + [out] = safe_names exprs + out + + +ident = fn {i, loc}: + rec: + ...identifier i + loc -add_ident = fn ctx: - pipe ctx: - add 'ident', any, transform_ident diff --git a/src/js/identifier/init.test.fnk b/src/js/identifier/init.test.fnk index bc46d0f..948a111 100644 --- a/src/js/identifier/init.test.fnk +++ b/src/js/identifier/init.test.fnk @@ -1,17 +1,17 @@ -{fink2js} = import '../../testing/generate.fnk' {describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' +{fink2js} = import '../../testing/generate.fnk' describe 'identifiers', fn: it 'escapes reserved JS identifiers', fn: expect fink2js ' - {do, if, in, for, let, new, try, var, case, enum, void} = foobar - {with, break, catch, class, const, super, while, yield, delete} = spam - {export, import, public, return, static, switch, typeof, default} = ham - {extends, finally, package, private, continue, function} = ni - {arguments, interface, protected, implements, instanceof} = nu - {undefined, null} = nu + do=1, if=1, in=1, for=1, let=1, new=1, try=1, var=1, case=1, enum=1, void=1 + with=1, break=1, catch=1, class=1, const=1, super=1, while=1, yield=1, delete=1 + export=1, import=1, public=1, return=1, static=1, switch=1, typeof=1, default=1 + extends=1, finally=1, package=1, private=1, continue=1, function=1 + arguments=1, interface=1, protected=1, implements=1, instanceof=1 + undefined=1, null=1 ' to_match_snapshot @@ -19,7 +19,7 @@ describe 'identifiers', fn: it 'escapes hyphenated idents', fn: expect fink2js ' - foo-bar = spam-ni + foo-bar = spam + ni-ni ' to_match_snapshot diff --git a/src/js/identifier/init.test.fnk.snap b/src/js/identifier/init.test.fnk.snap index 6790e36..3680a22 100644 --- a/src/js/identifier/init.test.fnk.snap +++ b/src/js/identifier/init.test.fnk.snap @@ -1,67 +1,62 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`identifiers does not escape true, false 1`] = `"export const foo = [true, false];"`; +exports[`identifiers does not escape true, false 1`] = ` +"const foo_0 = [true, false]; +export const foo = foo_0;" +`; exports[`identifiers does not escapes unicode names 1`] = ` -"export const ƒ = shrub; -export const π = ni; -export const ಠ_ಠ = 1234;" +"export const ƒ = shrub, + π = ni, + ಠ_ಠ = 1234;" `; -exports[`identifiers escapes hyphenated idents 1`] = `"export const fooᜭbar = spamᜭni;"`; +exports[`identifiers escapes hyphenated idents 1`] = ` +"const fooᜭbar_0 = spam + niᜭni; +export const fooᜭbar = fooᜭbar_0;" +`; exports[`identifiers escapes reserved JS identifiers 1`] = ` -"const { - \\"do\\": ˆdo, - \\"if\\": ˆif, - \\"in\\": ˆin, - \\"for\\": ˆfor, - \\"let\\": ˆlet, - \\"new\\": ˆnew, - \\"try\\": ˆtry, - \\"var\\": ˆvar, - \\"case\\": ˆcase, - \\"enum\\": ˆenum, - \\"void\\": ˆvoid -} = foobar; -const { - \\"with\\": ˆwith, - \\"break\\": ˆbreak, - \\"catch\\": ˆcatch, - \\"class\\": ˆclass, - \\"const\\": ˆconst, - \\"super\\": ˆsuper, - \\"while\\": ˆwhile, - \\"yield\\": ˆyield, - \\"delete\\": ˆdelete -} = spam; -const { - \\"export\\": ˆexport, - \\"import\\": ˆimport, - \\"public\\": ˆpublic, - \\"return\\": ˆreturn, - \\"static\\": ˆstatic, - \\"switch\\": ˆswitch, - \\"typeof\\": ˆtypeof, - \\"default\\": ˆdefault -} = ham; -const { - \\"extends\\": ˆextends, - \\"finally\\": ˆfinally, - \\"package\\": ˆpackage, - \\"private\\": ˆprivate, - \\"continue\\": ˆcontinue, - \\"function\\": ˆfunction -} = ni; -const { - \\"arguments\\": ˆarguments, - \\"interface\\": ˆinterface, - \\"protected\\": ˆprotected, - \\"implements\\": ˆimplements, - \\"instanceof\\": ˆinstanceof -} = nu; -const { - \\"undefined\\": ˆundefined, - \\"null\\": ˆnull -} = nu;" +"export const ˆdo = 1, + ˆif = 1, + ˆin = 1, + ˆfor = 1, + ˆlet = 1, + ˆnew = 1, + ˆtry = 1, + ˆvar = 1, + ˆcase = 1, + ˆenum = 1, + ˆvoid = 1, + ˆwith = 1, + ˆbreak = 1, + ˆcatch = 1, + ˆclass = 1, + ˆconst = 1, + ˆsuper = 1, + ˆwhile = 1, + ˆyield = 1, + ˆdelete = 1, + ˆexport = 1, + ˆimport = 1, + ˆpublic = 1, + ˆreturn = 1, + ˆstatic = 1, + ˆswitch = 1, + ˆtypeof = 1, + ˆdefault = 1, + ˆextends = 1, + ˆfinally = 1, + ˆpackage = 1, + ˆprivate = 1, + ˆcontinue = 1, + ˆfunction = 1, + ˆarguments = 1, + ˆinterface = 1, + ˆprotected = 1, + ˆimplements = 1, + ˆinstanceof = 1, + ˆundefined = 1, + ˆnull = 1; +export default 1;" `; diff --git a/src/js/init.fnk b/src/js/init.fnk index 149cce4..c96ace1 100644 --- a/src/js/init.fnk +++ b/src/js/init.fnk @@ -1,62 +1,160 @@ -{add_assignment} = import './assignment/init.fnk' -{add_func} = import './func/init.fnk' +{reverse} = import '@fink/std-lib/iter.fnk' + +{init_ctx, update_value, get_value} = import '../ir/context.fnk' + +{replace_idents} = import './identifier/init.fnk' + +{add_module, transfrom_module} = import './module/init.fnk' +{add_import} = import './module/import.fnk' + +{add_number} = import './literals/number.fnk' +{add_string} = import './literals/string.fnk' +{add_list} = import './literals/list.fnk' +{add_record} = import './literals/record.fnk' + {add_conditionals} = import './conditionals/init.fnk' -{add_call} = import './call/init.fnk' -{add_literals} = import './literals/init.fnk' -{add_spread} = import './spread/init.fnk' -{add_async} = import './async/init.fnk' + {add_logical} = import './logical/init.fnk' -{add_group} = import './group/init.fnk' -{add_module} = import './module/init.fnk' -{add_member} = import './prop-access/init.fnk' -{add_ident} = import './identifier/init.fnk' +{add_in} = import './logical/in.fnk' + +{add_arithmitic} = import './arithmitic/init.fnk' + {add_comparison} = import './comparison/init.fnk' + +{add_funcs} = import './func/init.fnk' +{add_calls} = import './call/call.fnk' + {add_jsx} = import './jsx/init.fnk' -{add_arithmitic} = import './arithmitic/init.fnk' -{add_block} = import './block/init.fnk' -{add_partial} = import './partial/init.fnk' -{init_runtimes} = import './runtime.fnk' +{add_async} = import './async/init.fnk' add_transformers = fn ctx: pipe ctx: add_module - add_ident - add_partial - add_literals - add_group - add_member + add_import + add_number + add_string + add_list + add_record + add_in add_logical add_comparison add_arithmitic - add_assignment - add_spread add_async - add_func + add_funcs add_conditionals - add_call - add_async + add_calls add_jsx - add_block -init_ctx = fn code, filename, options: - ctx = rec: - filename - code - errors: [] +prepare_rets = fn [expr=false, ...exprs], ctx: + match expr: + false: + ctx - options + [{f: 'ac'}]: + [{args: [cont_id]}, res_ids] = expr + next_ctx = update_value cont_id, {res_ids}, ctx + prepare_rets exprs, next_ctx - unique_id: 1 - ident_prefix: 'ˆ' + else: + prepare_rets exprs, ctx - ignoreable_imports: [] - pipe ctx: - init_runtimes - add_transformers + +prepare_exports = fn [expr=false, ...exprs], ctx, rec_id: + match expr: + false: + ctx + + [{f: 'mod'}]: + [{args: [next_rec_id]}] = expr + prepare_exports exprs, ctx, next_rec_id + + [{f:'rec_s'}, [{i: rec_id.i}]]: + [{args: [next_rec_id, , val_id]}] = expr + next_ctx = update_value val_id, {inline: false}, ctx + prepare_exports exprs, next_ctx, next_rec_id + + else: + prepare_exports exprs, ctx, rec_id + + + +prepare_imports = fn [expr=false, ...exprs], ctx: + match expr: + false: + ctx + + [{f: 'imp'}]: + [{args: [sr_id]}] = expr + # TODO: is there a better option than setting ref? + next_ctx = update_value sr_id, {refs: 1}, ctx + prepare_imports exprs, next_ctx + + else: + prepare_imports exprs, ctx + + + +prepare_non_inlinable = fn [expr=false, ...exprs], ctx: + match expr: + false: + ctx + + [{f: 'af'}]: + [, [res_id]] = expr + next_ctx = update_value res_id, {inline: false}, ctx + prepare_non_inlinable exprs, next_ctx + + [{f: 'wt'}]: + [, [res_id]] = expr + next_ctx = update_value res_id, {inline: false}, ctx + prepare_non_inlinable exprs, next_ctx + + [{f: 'str'}]: + [, [res_id]] = expr + next_ctx = update_value res_id, {tp: 'str'}, ctx + prepare_non_inlinable exprs, next_ctx + + [{f: 'jxe'}]: + [{args: [elem_id]}] = expr + + next_ctx = match get_value elem_id, ctx: + {tp: 'str'}: ctx + else: update_value elem_id, {inline: false}, ctx + + prepare_non_inlinable exprs, next_ctx + + [{f: ? in ['int', 'float']}]: + [, [res_id]] = expr + next_ctx = update_value res_id, {inline: true}, ctx + prepare_non_inlinable exprs, next_ctx + + [{f: ? in ['fn', 'cn']}]: + [{args: [, body]}] = expr + prepare_non_inlinable [...body, ...exprs], ctx + + else: + prepare_non_inlinable exprs, ctx + + + +transform_ir = fn input_exprs, options: + exprs = replace_idents input_exprs + rev_expr = reverse exprs + + ctx = pipe options: + init_ctx exprs, ? + prepare_rets rev_expr, ? + prepare_imports rev_expr, ? + prepare_exports rev_expr, ? + prepare_non_inlinable exprs, ? + add_transformers ? + + transfrom_module exprs, ctx + diff --git a/src/js/jsx/init.fnk b/src/js/jsx/init.fnk index 3ad38b1..e78855a 100644 --- a/src/js/jsx/init.fnk +++ b/src/js/jsx/init.fnk @@ -7,96 +7,118 @@ babel_types = import '@babel/types' {length} = import '@fink/std-lib/iter.fnk' -{add, any} = import '../context.fnk' -{transform, map_with_ctx, collect_with_ctx} = import '../transform.fnk' +{add, set_js2, get_js, get_js_literal, with_loc} = import '../context.fnk' +transform_prop_id = fn key: + match key: + {type: 'Identifier'}: + with_loc key, jsxIdentifier key.name -transform_jsx_elem = fn node, ctx: - id = jsxIdentifier node.name.value + {type: 'StringLiteral'}: + with_loc key, jsxIdentifier key.value - [attrs, children_ctx] = pipe node.props: - map_with_ctx fn expr, expr_ctx: - match expr: - {type: 'spread'}: - [attr, next_ctx] = transform expr.right, expr_ctx - spread = jsxSpreadAttribute attr - [spread, next_ctx] - else: - transform expr, expr_ctx - collect_with_ctx ctx - [children, next_ctx] = pipe node.children: - map_with_ctx transform - collect_with_ctx children_ctx - js = jsxElement - jsxOpeningElement id, attrs, node.self_closing - jsxClosingElement id - children +transform_prop_val = fn value: + match value: + {type: 'TemplateLiteral', quasis: 1 == length ?}: + # TODO: should happen at optimization level + {quasis: [{value: {raw: str}}]} = value + with_loc value, stringLiteral str + else: + with_loc value, jsxExpressionContainer value - [js, next_ctx] +transform_props = fn [prop=false, ...props], out=[]: + match prop: + false: + out -transform_jsx_frag = fn node, ctx: - [children, next_ctx] = pipe node.children: - map_with_ctx transform - collect_with_ctx ctx + {type: 'ObjectProperty'}: + attr = jsxAttribute + transform_prop_id prop.key + transform_prop_val prop.value + transform_props props, [...out, attr] + + {type: 'SpreadElement'}: + attr = jsxSpreadAttribute prop.argument + transform_props props, [...out, attr] - js = jsxFragment - jsxOpeningFragment _ - jsxClosingFragment _ - children - [js, next_ctx] +transform_children = fn [chld=false, ...children], out=[]: + match chld: + false: + out + {type: 'TemplateLiteral', quasis: 1 == length ?}: + # TODO: should happen at optimization level + {quasis: [{value: {raw: str}}]} = chld + js = with_loc chld, jsxText str + transform_children children, [...out, js] + + {type: 'JSXElement'}: + transform_children children, [...out, chld] + + else: + js = with_loc chld, jsxExpressionContainer chld + transform_children children, [...out, js] -transform_jsx_attr = fn node, ctx: - {name} = node - [value, next_ctx] = match node: - {value: {type: 'string', exprs: 1 == length ?}}: - {exprs: [str]} = node.value - [[stringLiteral str.value], ctx] - {value: {type: 'jsx:expr'}}: - [val, next_ctx] = transform node.value, ctx - [[val], next_ctx] +transform_jxe = fn expr, ctx: + [{args: [name_id, props_id, chldrn_id]}] = expr - {value: false}: - [val, next_ctx] = transform name, ctx - [[jsxExpressionContainer val], next_ctx] + id_v = get_js_literal name_id, ctx + id = match id_v: + {type: 'TemplateLiteral'}: + {quasis: [{value: {raw: name}}]} = id_v + with_loc name_id, jsxIdentifier name else: - [val, next_ctx] = transform node.value, ctx - [[jsxExpressionContainer val], next_ctx] + jsxIdentifier (get_js name_id, ctx).name - id = jsxIdentifier name.value - js = jsxAttribute id, ...value - [js, next_ctx] + props = pipe props_id: + get_js_literal ?, ctx + ?.properties + transform_props + children = pipe chldrn_id: + get_js_literal ?, ctx + ?.elements + transform_children + js = jsxElement + jsxOpeningElement id, props, 0 == length children + jsxClosingElement id + children -transform_jsx_text = fn node, ctx: - js = jsxText node.value - [js, ctx] + set_js2 expr, js, ctx -transform_jsx_expr_container = fn node, ctx: - [val, next_ctx] = transform node.expr, ctx - js = jsxExpressionContainer val - [js, next_ctx] +transform_jxf = fn expr, ctx: + [{args: [chldrn_id]}] = expr + + children = pipe chldrn_id: + get_js_literal ?, ctx + ?.elements + transform_children + + js = jsxFragment + jsxOpeningFragment _ + jsxClosingFragment _ + children + + set_js2 expr, js, ctx add_jsx = fn ctx: pipe ctx: - add 'jsx:frag', any, transform_jsx_frag - add 'jsx:elem', any, transform_jsx_elem - add 'jsx:attr', any, transform_jsx_attr - add 'jsx:text', any, transform_jsx_text - add 'jsx:expr', any, transform_jsx_expr_container + add 'jxe', transform_jxe + add 'jxf', transform_jxf + diff --git a/src/js/jsx/init.test.fnk b/src/js/jsx/init.test.fnk index e30b483..56e0bac 100644 --- a/src/js/jsx/init.test.fnk +++ b/src/js/jsx/init.test.fnk @@ -1,11 +1,11 @@ -{fink2js} = import '../../testing/generate.fnk' {describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' +{fink2js} = import '../../testing/generate.fnk' describe 'jsx', fn: it 'compiles shorthand', fn: expect - fink2js 'elem = ' + fink2js 'elem = ' to_match_snapshot @@ -41,7 +41,7 @@ describe 'jsx', fn: expect fink2js 'elem = - foo {ni} + foo {ni + 1} {na} ham spam @@ -66,41 +66,70 @@ describe 'jsx', fn: to_match_snapshot + it 'compiles elem from rec', fn: + expect + fink2js ' + Shrub = fn {...props}: + {Foobar} = spam + + ' + to_match_snapshot + + it 'handles ident clashes for lowercaae elems', fn: + expect + fink2js ' + Foo = fn {label}: + + ' + to_match_snapshot + describe 'JSX extensions', fn: it 'compiles shothand props', fn: expect - fink2js '' + fink2js 'elem = ' to_match_snapshot it 'compiles spread', fn: expect - fink2js '' + fink2js 'elem = ' to_match_snapshot it "compiles template str attr", fn: expect - fink2js "" + fink2js "elem = " to_match_snapshot it "compiles fink expr as attr values", fn: expect - fink2js " foo " + fink2js "elem = foo " to_match_snapshot it "compiles fink expr with gt comparison", fn: expect - fink2js " 123} shrub=1234> ni " + fink2js "elem = 123} shrub=1234> ni " to_match_snapshot it "compiles expr group with call for attr value", fn: expect - fink2js "" + fink2js "elem = " to_match_snapshot + it "compiles block", fn: + expect + fink2js ' + elem = + { + foo = spam _ + bar spam, foo, foo + } + + ' + to_match_snapshot + diff --git a/src/js/jsx/init.test.fnk.snap b/src/js/jsx/init.test.fnk.snap index 7741c9f..f6c8b7b 100644 --- a/src/js/jsx/init.test.fnk.snap +++ b/src/js/jsx/init.test.fnk.snap @@ -1,44 +1,114 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`JSX extensions compiles expr group with call for attr value 1`] = `";"`; +exports[`JSX extensions compiles block 1`] = ` +"const foo_0 = spam(); +const chld_1 = bar(spam, foo_0, foo_0); +const elem_0 = + {chld_1} +; +export const elem = elem_0;" +`; -exports[`JSX extensions compiles fink expr as attr values 1`] = `" foo ;"`; +exports[`JSX extensions compiles expr group with call for attr value 1`] = ` +"const prpv_0 = ham(ni); +const elem_0 = ; +export const elem = elem_0;" +`; -exports[`JSX extensions compiles fink expr with gt comparison 1`] = `" 123} shrub={1234}> ni ;"`; +exports[`JSX extensions compiles fink expr as attr values 1`] = ` +"const elem_0 = foo ; +export const elem = elem_0;" +`; -exports[`JSX extensions compiles shothand props 1`] = `";"`; +exports[`JSX extensions compiles fink expr with gt comparison 1`] = ` +"const elem_0 = 123} shrub={1234}> ni ; +export const elem = elem_0;" +`; -exports[`JSX extensions compiles spread 1`] = `";"`; +exports[`JSX extensions compiles shothand props 1`] = ` +"const elem_0 = ; +export const elem = elem_0;" +`; -exports[`JSX extensions compiles template str attr 1`] = `";"`; +exports[`JSX extensions compiles spread 1`] = ` +"const elem_0 = ; +export const elem = elem_0;" +`; -exports[`jsx compiles empty elem 1`] = `"export const elem = ;"`; +exports[`JSX extensions compiles template str attr 1`] = ` +"const elem_0 = ; +export const elem = elem_0;" +`; + +exports[`jsx compiles elem from rec 1`] = ` +"const Shrub_0 = drec_0 => { + const { ...props_0 + } = drec_0; + const Foobar_0 = spam.Foobar; + return ; +}; -exports[`jsx compiles fragment 1`] = `"export const elem = <>;"`; +export const Shrub = Shrub_0;" +`; + +exports[`jsx compiles empty elem 1`] = ` +"const elem_0 = ; +export const elem = elem_0;" +`; + +exports[`jsx compiles fragment 1`] = ` +"const elem_0 = <>; +export const elem = elem_0;" +`; exports[`jsx compiles fragment with children 1`] = ` -"export const elem = <> +"const elem_0 = <> foo

bar

-;" +; +export const elem = elem_0;" `; -exports[`jsx compiles hypenate props 1`] = `"export const elem =
;"`; +exports[`jsx compiles hypenate props 1`] = ` +"const elem_0 = ; +export const elem = elem_0;" +`; -exports[`jsx compiles shorthand 1`] = `"export const elem = ;"`; +exports[`jsx compiles shorthand 1`] = ` +"const elem_0 = ; +export const elem = elem_0;" +`; exports[`jsx compiles with children and expr 1`] = ` -"export const elem = - foo {ni} +"const elem_0 = + foo {ni + 1} {na} ham spam ni -;" +; +export const elem = elem_0;" +`; + +exports[`jsx compiles with expr params 1`] = ` +"const elem_0 = ; +export const elem = elem_0;" `; -exports[`jsx compiles with expr params 1`] = `"export const elem = ;"`; +exports[`jsx compiles with expr params 2`] = ` +"const elem_0 = ; +export const elem = elem_0;" +`; -exports[`jsx compiles with expr params 2`] = `"export const elem = ;"`; +exports[`jsx compiles with str params 1`] = ` +"const elem_0 = ; +export const elem = elem_0;" +`; -exports[`jsx compiles with str params 1`] = `"export const elem = ;"`; +exports[`jsx handles ident clashes for lowercaae elems 1`] = ` +"const Foo_0 = drec_0 => { + return ; +}; + +export const Foo = Foo_0;" +`; diff --git a/src/js/left.fnk b/src/js/left.fnk deleted file mode 100644 index 20872da..0000000 --- a/src/js/left.fnk +++ /dev/null @@ -1,28 +0,0 @@ -babel_types = import '@babel/types' -{ - isAssignmentExpression, assignmentPattern, isSpreadElement, restElement - isArrayExpression, arrayPattern, isObjectExpression, objectPattern -} = babel_types - -{map} = import '@fink/std-lib/iter.fnk' - - -transform_left = fn val: - match val: - isAssignmentExpression ?: - assignmentPattern val.left, val.right - - isSpreadElement ?: - restElement val.argument - - isArrayExpression ?: - arrayPattern list: - ... pipe val.elements: - map fn item: transform_left item - - isObjectExpression ?: - objectPattern list: - ... pipe val.properties: - map fn prop: transform_left prop - - else: val diff --git a/src/js/literals/keywords.fnk b/src/js/literals/keywords.fnk deleted file mode 100644 index e99e056..0000000 --- a/src/js/literals/keywords.fnk +++ /dev/null @@ -1,10 +0,0 @@ -babel_types = import '@babel/types' -{booleanLiteral} = babel_types - - -transform_keyword = fn node, ctx: - js = match node: - {'value': 'true'}: booleanLiteral true - --- istanbul ignore next --- - {'value': 'false'}: booleanLiteral false - [js, ctx] \ No newline at end of file diff --git a/src/js/literals/keywords.test.fnk b/src/js/literals/keywords.test.fnk index 5824328..7fd01ef 100644 --- a/src/js/literals/keywords.test.fnk +++ b/src/js/literals/keywords.test.fnk @@ -1,5 +1,5 @@ -{fink2js} = import '../../testing/generate.fnk' {describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' +{fink2js} = import '../../testing/generate.fnk' describe 'keywords', fn: diff --git a/src/js/literals/keywords.test.fnk.snap b/src/js/literals/keywords.test.fnk.snap index 6c39eb1..3504432 100644 --- a/src/js/literals/keywords.test.fnk.snap +++ b/src/js/literals/keywords.test.fnk.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`keywords transforms literals 1`] = ` -"export const x = false; -export const y = true;" +"export const x = false, + y = true;" `; diff --git a/src/js/literals/list.fnk b/src/js/literals/list.fnk index 4d00964..b78a323 100644 --- a/src/js/literals/list.fnk +++ b/src/js/literals/list.fnk @@ -1,33 +1,113 @@ -babel_types = import '@babel/types' -{arrayExpression} = babel_types +types = import '@babel/types' +{ + arrayExpression, spreadElement, memberExpression, numericLiteral + callExpression, identifier +} = types + {null} = import '@fink/js-interop/nullish.fnk' -{map, filter, zip} = import '@fink/std-lib/iter.fnk' -{transform, map_with_ctx, collect_with_ctx} = import '../transform.fnk' -{partial_wrapper, no_wrapper} = import '../partial/init.fnk' +{add, get_js, set_js2, with_loc} = import '../context.fnk' + + + +ids_to_js = fn [id=false, ...rest], ctx, out=[]: + match id: + false: + out + {i: '_'}: + ids_to_js rest, ctx, [...out, null] + else: + item = get_js id, ctx + # console.log id, arg + ids_to_js rest, ctx, [...out, item] + + + +transform_tpl = fn expr, ctx: + [{args: items_ids}] = expr + js = arrayExpression + ids_to_js items_ids, ctx + set_js2 expr, js, ctx + + + +transform_tpl_i = fn expr, ctx: + [{args: [tpl_id, idx]}] = expr + js = match idx: + ? < 0: + callExpression + memberExpression + get_js tpl_id, ctx + identifier 'at' + [numericLiteral idx] + else: + memberExpression + get_js tpl_id, ctx + numericLiteral idx + true + + set_js2 expr, js, ctx + + + +transform_tpl_s = fn expr, ctx: + [{args: [items_id, start_idx, end_idx]}] = expr + items = get_js items_id, ctx + + start = numericLiteral start_idx + + args = match end_idx: + ? >= 0: [start] + else: [start, numericLiteral end_idx] + + js = callExpression + memberExpression items, identifier 'slice' + args + + set_js2 expr, js, ctx + + + +elems_or_spread = fn expr: + match expr: + {type: 'ArrayExpression'}: + expr.elements + else: + [with_loc expr, spreadElement expr] + + + +transform_list_append = fn expr, ctx: + [{args: [items_id, val_id]}] = expr + elems = elems_or_spread get_js items_id, ctx + elem = match val_id: + {i: '_'}: null + else: get_js val_id, ctx + + js = arrayExpression [...elems, elem] + set_js2 expr, js, ctx + + +transform_list_chain = fn expr, ctx: + [{args: [items1_id, items2_id]}] = expr + elems1 = elems_or_spread get_js items1_id, ctx + elems2 = elems_or_spread get_js items2_id, ctx + js = arrayExpression [...elems1, ...elems2] + set_js2 expr, js, ctx -transform_list = fn node, ctx: - [elems, next_ctx] = pipe node.exprs: - map_with_ctx fn elem, elem_ctx: - match elem: - {type: 'empty'}: - [null, elem_ctx] - else: - transform elem, elem_ctx - collect_with_ctx ctx - # TODO: same as in call.fnk - [wrap_partial=no_wrapper] = pipe zip node.exprs, elems: - filter fn [arg, js_arg]: match arg: - {type: 'partial'}: true - {type: 'spread', right.type: 'partial'}: true - {type: 'spread'}: js_arg.is_partial - else: false - map fn: - partial_wrapper +add_list = fn ctx: + pipe ctx: + add 'tpl', transform_tpl + add 'tpl_i', transform_tpl_i + add 'tpl_s', transform_tpl_s - js = arrayExpression elems + # add 'lst', transform_empty_list + add 'lst_a', transform_list_append + add 'lst_c', transform_list_chain + # add 'lst_h', transform_list_head + # add 'lst_t', transform_list_tail + # add 'lst_r', transform_list_reverse - wrap_partial js, next_ctx diff --git a/src/js/literals/list.test.fnk b/src/js/literals/list.test.fnk index 76c35eb..564b1c0 100644 --- a/src/js/literals/list.test.fnk +++ b/src/js/literals/list.test.fnk @@ -1,5 +1,6 @@ +{skip, describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' + {fink2js} = import '../../testing/generate.fnk' -{describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' describe 'list', fn: @@ -8,8 +9,9 @@ describe 'list', fn: fink2js ' array1 = [] array2 = [1] - array3 = [1, 2, 4, (a _), ...b] - array4 = list: + array3 = [1, 2] + array4 = [1, , 2] + array5 = list: a + 1 + 45 + b + c [1, 2] @@ -18,7 +20,29 @@ describe 'list', fn: to_match_snapshot - it 'compiles as partial', fn: + it 'compiles spread', fn: + expect + fink2js ' + foo = [...b] + bar = [1, 2, ...b] + spam = [1, 2, ...b, 123] + ' + to_match_snapshot + + expect + fink2js ' + foo = [1, 2, 3] + bar = [...foo, 4, 5, 6] + spam = [7] + shrub = [...bar, ...spam] + ni = [...nu, na] + nie = [...nu, , na] + ham = [...nu, ...na] + ' + to_match_snapshot + + + skip.it 'compiles as partial', fn: expect fink2js ' [1, ...?, 9] @@ -28,18 +52,107 @@ describe 'list', fn: describe 'unpacking list', fn: - it 'compiles', fn: + it 'destructures known tuples', fn: + expect + fink2js ' + [a, [b, c]] = [1, [2, 3]] + foo = [b, a] + [z] = [1 + 2, 3 * 4] + [x, y] = foo + [, ...w] = [] + out = [a, b, c, foo, z, x, y, w] + ' + to_match_snapshot + + it 'destructures missing item', fn: + expect + fink2js ' + [a, , b] = foo + out = [a, b] + ' + to_match_snapshot + + it 'destructures spread', fn: + expect + fink2js ' + [..., a] = foo + out = a + ' + to_match_snapshot + + expect + fink2js ' + [a, ..., b] = foo + out = [a, b] + ' + to_match_snapshot + + expect + fink2js ' + [a, ..., b, c] = foo + out = [a, b, c] + ' + to_match_snapshot + + expect + fink2js ' + [a, ...b] = foo + out = [a, ...b] + ' + to_match_snapshot + + expect + fink2js ' + [a, ...b, c] = foo + out = [a, b, c] + ' + to_match_snapshot + + expect + fink2js ' + [a, b, ...c, d] = foo + out = [a, b, c, d] + ' + to_match_snapshot + + expect + fink2js ' + [a, b, ...c, d, e] = foo + out = [a, b, c, d, e] + ' + to_match_snapshot + + + it 'destructures recs', fn: expect fink2js " - [a, b, c] = ni - [,, d] = ni - [head, ...tail] = ni - [...items, last] = '1234' - [first, second, ...middle, penultimate, end] = '123' - [ni, ..., nu] = '123' - [..., nuna] = '123' + [{a, b}, c] = ni + out = [a, b, c] " to_match_snapshot + it 'destructures with defaults', fn: + expect + fink2js ' + [a=12, b=34] = foo + out = [a, b] + ' + to_match_snapshot + + expect + fink2js ' + [[a, b=0]=[1, 2], c=34] = foo + out = [a, b, c] + ' + to_match_snapshot + + + it 'TODO', fn: + expect + fink2js " + [bar, spam, ham] = [...shrub] + ni = bar + spam + ham + " + to_match_snapshot diff --git a/src/js/literals/list.test.fnk.snap b/src/js/literals/list.test.fnk.snap index 54fc323..81c042a 100644 --- a/src/js/literals/list.test.fnk.snap +++ b/src/js/literals/list.test.fnk.snap @@ -1,10 +1,16 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`list compiles 1`] = ` -"export const array1 = []; -export const array2 = [1]; -export const array3 = [1, 2, 4, a(), ...b]; -export const array4 = [a + 1 + 45 + b + c, [1, 2], (3 + 3) * 2];" +"const array1_0 = []; +const array2_0 = [1]; +const array3_0 = [1, 2]; +const array4_0 = [1,, 2]; +const array5_0 = [a + 1 + 45 + b + c, [1, 2], (3 + 3) * 2]; +export const array1 = array1_0, + array2 = array2_0, + array3 = array3_0, + array4 = array4_0, + array5 = array5_0;" `; exports[`list compiles as partial 1`] = ` @@ -13,44 +19,103 @@ exports[`list compiles as partial 1`] = ` ˆpartial => [ˆpartial, ˆpartial];" `; -exports[`unpacking list compiles 1`] = ` -"const [a, b, c] = ni; -const [,, d] = ni; -const [head, ...tail] = ni; +exports[`list compiles spread 1`] = ` +"const foo_0 = [...b]; +const bar_0 = [1, 2, ...b]; +const spam_0 = [1, 2, ...b, 123]; +export const foo = foo_0, + bar = bar_0, + spam = spam_0;" +`; + +exports[`list compiles spread 2`] = ` +"const foo_0 = [1, 2, 3]; +const bar_0 = [1, 2, 3, 4, 5, 6]; +const spam_0 = [7]; +const shrub_0 = [1, 2, 3, 4, 5, 6, 7]; +const ni_0 = [...nu, na]; +const nie_0 = [...nu,, na]; +const ham_0 = [...nu, ...na]; +export const foo = foo_0, + bar = bar_0, + spam = spam_0, + shrub = shrub_0, + ni = ni_0, + nie = nie_0, + ham = ham_0;" +`; + +exports[`unpacking list TODO 1`] = ` +"const dlst_0 = [...shrub]; +const ni_0 = dlst_0[0] + dlst_0[1] + dlst_0[2]; +export const ni = ni_0;" +`; + +exports[`unpacking list destructures known tuples 1`] = ` +"const foo_0 = [2, 1]; +const out_0 = [1, 2, 3, foo_0, 1 + 2, 2, 1, []]; +export const foo = foo_0, + out = out_0;" +`; + +exports[`unpacking list destructures missing item 1`] = ` +"const out_0 = [foo[0], foo[2]]; +export const out = out_0;" +`; + +exports[`unpacking list destructures recs 1`] = ` +"const drec_0 = ni[0]; +const out_0 = [drec_0.a, drec_0.b, ni[1]]; +export const out = out_0;" +`; -let _do_result; +exports[`unpacking list destructures spread 1`] = ` +"const a_0 = foo.at(-1); +export const out = a_0;" +`; -{ - const [...ˆitems_1] = \`1234\`; - _do_result = [ˆitems_1.slice(0, -1), ˆitems_1.slice(-1)]; -} -const [items, [last]] = _do_result; -_do_result = undefined; +exports[`unpacking list destructures spread 2`] = ` +"const out_0 = [foo[0], foo.at(-1)]; +export const out = out_0;" +`; + +exports[`unpacking list destructures spread 3`] = ` +"const out_0 = [foo[0], foo.at(-2), foo.at(-1)]; +export const out = out_0;" +`; -let _do_result2; +exports[`unpacking list destructures spread 4`] = ` +"const out_0 = [foo[0], ...foo.slice(1)]; +export const out = out_0;" +`; -{ - const [...ˆitems_2] = \`123\`; - _do_result2 = [ˆitems_2, ˆitems_2.slice(2, -2), ˆitems_2.slice(-2)]; -} -const [[first, second], middle, [penultimate, end]] = _do_result2; -_do_result2 = undefined; +exports[`unpacking list destructures spread 5`] = ` +"const out_0 = [foo[0], foo.slice(1, -1), foo.at(-1)]; +export const out = out_0;" +`; -let _do_result3; +exports[`unpacking list destructures spread 6`] = ` +"const out_0 = [foo[0], foo[1], foo.slice(2, -1), foo.at(-1)]; +export const out = out_0;" +`; -{ - const [...ˆitems_3] = \`123\`; - _do_result3 = [ˆitems_3, ˆitems_3.slice(1, -1), ˆitems_3.slice(-1)]; -} -const [[ni],, [nu]] = _do_result3; -_do_result3 = undefined; +exports[`unpacking list destructures spread 7`] = ` +"const out_0 = [foo[0], foo[1], foo.slice(2, -2), foo.at(-2), foo.at(-1)]; +export const out = out_0;" +`; -let _do_result4; +exports[`unpacking list destructures with defaults 1`] = ` +"const hdm_0 = foo[0]; +const hdm_1 = foo[1]; +const out_0 = [undefined === hdm_0 ? 12 : hdm_0, undefined === hdm_1 ? 34 : hdm_1]; +export const out = out_0;" +`; -{ - const [...ˆitems_4] = \`123\`; - _do_result4 = [ˆitems_4.slice(0, -1), ˆitems_4.slice(-1)]; -} -const [, [nuna]] = _do_result4; -_do_result4 = undefined;" +exports[`unpacking list destructures with defaults 2`] = ` +"const hdm_0 = foo[0]; +const dlst_1 = undefined === hdm_0 ? [1, 2] : hdm_0; +const hdm_1 = dlst_1[1]; +const hdm_2 = foo[1]; +const out_0 = [dlst_1[0], undefined === hdm_1 ? 0 : hdm_1, undefined === hdm_2 ? 34 : hdm_2]; +export const out = out_0;" `; diff --git a/src/js/literals/number.fnk b/src/js/literals/number.fnk index a60e02a..0b0f3e2 100644 --- a/src/js/literals/number.fnk +++ b/src/js/literals/number.fnk @@ -1,19 +1,32 @@ -babel_types = import '@babel/types' -{numericLiteral} = babel_types -{rx, matches} = import '@fink/std-lib/regex.fnk' -{parse_float, parse_int} = import '@fink/std-lib/num.fnk' +types = import '@babel/types' +{numericLiteral} = types +{parse_int, parse_float} = import '@fink/std-lib/num.js' +{add, set_js2} = import '../context.fnk' -transform_number = fn {value}, ctx: - js = match value: - matches ?, rx'\.': - numericLiteral parse_float value - else: - num = parse_int value - rec: - ...numericLiteral num - extra: {raw: value, rawValue: num} - [js, ctx] + +transform_int = fn expr, ctx: + [{args: [value]}] = expr + # TODO parse_int does not parse 0[bxo].+ nor 1_000 + val = parse_int value + js = rec: + ...numericLiteral val + extra: {rawValue: val, raw: value} + + set_js2 expr, js, ctx + + +transform_float = fn expr, ctx: + [{args: [value]}] = expr + js = numericLiteral parse_float value + set_js2 expr, js, ctx + + + +add_number = fn ctx: + pipe ctx: + add 'int', transform_int + add 'float', transform_float diff --git a/src/js/literals/number.test.fnk b/src/js/literals/number.test.fnk index 9867398..43c4220 100644 --- a/src/js/literals/number.test.fnk +++ b/src/js/literals/number.test.fnk @@ -1,5 +1,5 @@ -{fink2js} = import '../../testing/generate.fnk' {describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' +{fink2js} = import '../../testing/generate.fnk' describe 'numbers', fn: diff --git a/src/js/literals/number.test.fnk.snap b/src/js/literals/number.test.fnk.snap index eaac22c..b92adf3 100644 --- a/src/js/literals/number.test.fnk.snap +++ b/src/js/literals/number.test.fnk.snap @@ -1,20 +1,20 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`numbers transforms floats 1`] = ` -"export const x = 1.234578; -export const y = 1.23e+45; -export const z = 1.23e-45; -export const a = 1.23e+45;" +"export const x = 1.234578, + y = 1.23e+45, + z = 1.23e-45, + a = 1.23e+45;" `; exports[`numbers transforms hex, octet, binary 1`] = ` -"export const h = 0x123456789ABCDEF0; -export const o = 0o12345670; -export const b = 0b01010;" +"export const h = 0x123456789ABCDEF0, + o = 0o12345670, + b = 0b01010;" `; exports[`numbers transforms integers 1`] = ` -"export const x = 1234578; -export const y = 0123; -export const z = 123_456_789;" +"export const x = 1234578, + y = 0123, + z = 123_456_789;" `; diff --git a/src/js/literals/record.fnk b/src/js/literals/record.fnk index b5b4646..748d25e 100644 --- a/src/js/literals/record.fnk +++ b/src/js/literals/record.fnk @@ -1,198 +1,141 @@ -babel_types = import '@babel/types' +types = import '@babel/types' { - objectExpression, objectProperty, assignmentPattern, doExpression - blockStatement, expressionStatement, assignmentExpression, spreadElement - optionalMemberExpression, identifier -} = babel_types + objectExpression, objectProperty, objectPattern + memberExpression, identifier + spreadElement, restElement, variableDeclaration + variableDeclarator, stringLiteral +} = types +{map} = import '@fink/std-lib/iter.fnk' -{filter, filter_ac, while, is_empty} = import '@fink/std-lib/iter.fnk' -{map, zip} = import '@fink/std-lib/iter.fnk' +{inc_ref} = import '../../ir/context.fnk' +{is_js_ident, ident} = import '../identifier/init.fnk' +{add, get_js, get_js_literal, set_js2, with_loc} = import '../context.fnk' -{raw_str, unique_ident, ident, lets} = import '../../js/types.fnk' -{transform, map_with_ctx, collect_with_ctx} = import '../transform.fnk' -{partial_wrapper, no_wrapper} = import '../partial/init.fnk' -optional = true -not_computed = false +transform_rec = fn expr, ctx: + js = objectExpression [] + set_js2 expr, js, ctx -has_member_keys = fn expr: - [found=false] = expr.exprs | filter fn expr: - match expr: - {left: {type: 'member'}}: true - else: false - found != false - - - -get_path = fn expr: - match expr.type: - 'member': - list: - ... get_path expr.left - ... get_path expr.right +props_or_spread = fn obj: + match obj: + {type: 'ObjectExpression'}: + obj.properties else: - [identifier expr.value] + [with_loc obj, spreadElement obj] -transform_member_prop = fn [key, ...parents], rec_val, value: - next_value = match parents: - is_empty ?: - value - else: - next_rec_val = optionalMemberExpression rec_val, key, not_computed, optional - transform_member_prop parents, next_rec_val, value - - objectExpression list: - spreadElement rec_val - objectProperty key, next_value +transform_rec_set = fn expr, ctx: + [{args: [rec_id, key_id, val_id]}] = expr + props = props_or_spread get_js rec_id, ctx + key = get_js key_id, ctx + val = get_js val_id, ctx + prop = match key: + {type: 'TemplateLiteral', quasis: [?, ?]}: + objectProperty key, val, true + {type: 'TemplateLiteral', quasis: [{value: {raw: is_js_ident ?}}]}: + {quasis: [{value: {raw: value}}]} = key + objectProperty + with_loc key, identifier value + val -transform_member_or_plain_prop = fn initial_rec: fn expr, ctx: - [val, next_ctx] = match expr: - {left: {type: 'member'}}: - path = get_path expr.left - [value, end_ctx] = transform expr.right, ctx - js = transform_member_prop path, initial_rec, value - [js, end_ctx] + {type: 'TemplateLiteral'}: + {quasis: [{value: {raw: value}}]} = key + # TODO: needs unescaping + objectProperty + with_loc key, stringLiteral value + val else: - [prop, end_ctx] = transform expr, ctx - js = objectExpression list: - spreadElement initial_rec - prop - [js, end_ctx] - - js = expressionStatement - assignmentExpression '=', initial_rec, val - - [js, next_ctx] - - - -transform_rec_regular_props = fn rec_expr, ctx: - [...exprs] = rec_expr.exprs | while fn expr: - match expr: - {left: {type: 'member'}}: false - else: true - - transform {...rec_expr, exprs}, ctx - + objectProperty key, val, true + js = objectExpression [...props, prop] + set_js2 expr, js, ctx -transform_member_props = fn expr, ctx: - [initial_rec, next_ctx] = unique_ident 'rec', ctx - [rec_updates, end_ctx] = pipe expr.exprs: - filter_ac fn expr, keep=false, ctx: - do_keep = match expr: - {left: {type: 'member'}}: true - else: keep - [do_keep, do_keep, ctx] - map_with_ctx transform_member_or_plain_prop initial_rec - collect_with_ctx next_ctx - [initial_rec, rec_updates, end_ctx] +transform_rec_get = fn expr, ctx: + [{args: [rec_id, key_id]}] = expr + rec_js = get_js rec_id, ctx + key = get_js_literal key_id, ctx + [computed, final_key] = match key: + {type: 'TemplateLiteral', quasis: [?, ?]}: + [true, key] -transform_with_member_expr_keys = fn expr, ctx: - [initial_rec, props_ctx] = transform_rec_regular_props expr, ctx - - [tmp_rec, rec_updates, end_ctx] = transform_member_props expr, props_ctx - - js = doExpression - blockStatement list: - lets tmp_rec, initial_rec - ...rec_updates - expressionStatement tmp_rec - - [js, end_ctx] - - - -transform_record = fn expr, ctx: - match expr: - ctx.is_binding != true and has_member_keys ?: - transform_with_member_expr_keys expr, ctx + {type: 'TemplateLiteral', quasis: [{value: {raw: is_js_ident ?}}]}: + {quasis: [{value: {raw: value}}]} = key + [false, with_loc key, identifier value] else: - [props, next_ctx] = pipe expr.exprs: - map_with_ctx transform - collect_with_ctx ctx + [true, get_js key_id, ctx] - [wrap_partial=no_wrapper] = pipe zip expr.exprs, props: - filter fn [prop, js_prop]: match prop: - {right.type: 'partial'}: true - {type: 'spread'}: js_prop.is_partial - else: false - map fn: - partial_wrapper + js = memberExpression rec_js, final_key, computed - js = objectExpression props - wrap_partial js, next_ctx + set_js2 expr, js, ctx -str_key = fn {value, loc}, ctx: - str = raw_str value - [{...str, loc}, ctx] +transform_rec_del_keys = fn expr, ctx: + [{args: [rec_id, ...key_ids]}, [result_id]] = expr + rec_js = get_js rec_id, ctx + ignored_props = pipe key_ids: + map fn key_id: + key = get_js_literal key_id, ctx + val = identifier '_${key_id.i}' + match key: + {type: 'TemplateLiteral', quasis: [?, ?]}: + objectProperty key, val, true + {type: 'TemplateLiteral', quasis: [{value: {raw: is_js_ident ?}}]}: + {quasis: [{value: {raw: value}}]} = key + objectProperty + identifier value + val -get_key = fn {left: key}, ctx: - match key: - {type: 'group'}: - [true, ...transform key, ctx] - {type: 'string'}: - [true, ...transform key, ctx] - else: - id = ident key.value, ctx - match id: - {name: key.value}: - [false, id, ctx] - else: - [false, ...str_key key, ctx] + {type: 'TemplateLiteral'}: + {quasis: [{value: {raw: value}}]} = key + # TODO: needs unescaping + objectProperty + stringLiteral value + val + else: + objectProperty key, val, true + [...?] -get_value = fn {left, right}, ctx: - match right: - false: - transform left, ctx - {type: 'empty'}: - unique_ident 'unused', ctx - else: - transform right, ctx + js = variableDeclaration 'const', list: + variableDeclarator + objectPattern [...ignored_props, restElement ident result_id] + rec_js + next_ctx = inc_ref result_id, ctx + set_js2 expr, js, next_ctx -transform_kv = fn expr, ctx: - match expr: - {left: {type: 'member'}}: - {left, right} = expr.left - value = {type: 'rec', exprs: [{...expr, left: right}], loc: expr.loc} - prop = {...expr, left, right: value} - transform prop, ctx - else: - [computed, key, next_ctx] = get_key expr, ctx - [value, end_ctx] = get_value expr, next_ctx +transform_rec_merge = fn expr, ctx: + [{args: [rec1_id, rec2_id]}] = expr + props1 = props_or_spread get_js rec1_id, ctx + props2 = props_or_spread get_js rec2_id, ctx + js = objectExpression [...props1, ...props2] + set_js2 expr, js, ctx - shorthand = match expr: - {right: false}: true - else: false - final_value = match expr: - {right: {type: 'assign'}}: - assignmentPattern value.left, value.right - else: - value - js = objectProperty key, final_value, computed, shorthand - [js, end_ctx] +add_record = fn ctx: + pipe ctx: + add 'rec', transform_rec + add 'rec_g', transform_rec_get + add 'rec_s', transform_rec_set + add 'rec_d', transform_rec_del_keys + add 'rec_m', transform_rec_merge diff --git a/src/js/literals/record.test.fnk b/src/js/literals/record.test.fnk index 4e1a8bc..c024caf 100644 --- a/src/js/literals/record.test.fnk +++ b/src/js/literals/record.test.fnk @@ -11,7 +11,9 @@ describe 'record', fn: it 'compiles shorthand', fn: expect - fink2js 'foo = {foo, π, ƒ, foo-bar}' + fink2js ' + foo = {bar, π, ƒ, foo-bar} + ' to_match_snapshot expect @@ -25,7 +27,12 @@ describe 'record', fn: it 'compiles spread', fn: expect - fink2js 'foo = {a, b, ...c}' + fink2js ' + foo = {a, b, ...c} + bar = {...foo, ...ni} + spam = {...ham, ni} + ni = {...na, ...nu} + ' to_match_snapshot @@ -41,6 +48,16 @@ describe 'record', fn: to_match_snapshot + it 'compiles calculated props', fn: + expect + fink2js " + foo = rec: + 'spam': 456 + 'spam-\${ham}': 'ni' + " + to_match_snapshot + + it 'compiles idents that are not js prop-names', fn: expect fink2js " @@ -52,36 +69,6 @@ describe 'record', fn: " to_match_snapshot - it 'compiles multiline', fn: - expect - fink2js 'foo = { - a: 123 - - b: 123 - and 123 - and 1345 - - c: fn a, b: 134 - - d: foo a + 3 - } - ' - to_match_snapshot - - expect - fink2js 'foo = rec: - a: 123 - - b: 123 - and 123 - and 1345 - - c: fn a, b: 134 - - d: foo a + 3 - ' - to_match_snapshot - it 'compiles member expr as keys', fn: expect @@ -94,78 +81,89 @@ describe 'record', fn: - -describe 'partial', fn: - it 'compiles', fn: +describe 'unpacking record', fn: + it 'compiles simple', fn: expect fink2js ' - {foo: bar, ...?} - {foo: ?, bar: spam} + {a, b, c: cc} = ni + out = [a, b, cc] ' to_match_snapshot - -describe 'calculated props', fn: - it 'compiles', fn: + it 'compiles non js idents', fn: expect - fink2js " - foo = rec: - 'spam': 456 - 'spam-\${ham}': 'ni' - " + fink2js ' + {foo, π, ƒ, delete} = spam + out = [foo, π, ƒ, delete] + ' to_match_snapshot - - -describe 'unpacking record', fn: - it 'compiles simple', fn: + it 'compiles computed keys', fn: expect - fink2js '{a, b, c} = ni' + fink2js " + {'n i': a, (ni): b, 'foo\${bar}': {c}} = foo + out = [a, b, c] + " to_match_snapshot - it 'compiles non js idents', fn: + it 'destructuress tpls', fn: expect - fink2js '{foo, π, ƒ, delete} = spam' + fink2js ' + {foo: [bar, spam]} = shrub + out = [spam, bar] + ' to_match_snapshot it 'compiles spread', fn: expect - fink2js '{e, ...f} = {e: 0, foo: 12, bar: 34}' + fink2js ' + {a, "foo-\${bar}": b, ...c} = foo + out = [a, b, c] + ' to_match_snapshot it 'compiles empty', fn: expect - fink2js '{foo: _ , bar} = {foo: 12, bar: 34}' + fink2js ' + {foo: _ , bar, ...shrub} = foo + out = [bar, shrub] + ' to_match_snapshot it 'compiles defaults', fn: expect - fink2js '{x=1, π=2, ni: {y, z}} = {ni: {y: 1, z: 2}}' - to_match_snapshot - - - it 'compiles computed keys', fn: - expect - fink2js "{'n i': ni} = foo" + fink2js ' + {a=1, b: bb=2, ni: {c, d}} = foo + out = [a, bb, c, d] + ' to_match_snapshot it 'compiles member expr as keys', fn: expect - fink2js "{spam.ham.ni: ni, ...rest} = foo" + fink2js ' + {spam.ham.ni: ni, ...rest} = foo + out = [ni, rest] + ' to_match_snapshot expect - fink2js "{spam.ham.ni: {ni: nu, foo.bar: bar}, ...rest} = foo" + fink2js ' + {spam.ham.ni: {ni: nu, foo.bar: bar}, ...rest} = foo + out = [nu, bar, rest] + ' to_match_snapshot expect - fink2js "{foo-bar.spam-ham.ni: {ni: nu, foo.bar: bar}, ...rest} = foo" + fink2js ' + {foo-bar.spam-ham.ni: {ni: nu, foo.bar: bar}, ...rest} = foo + out = [nu, bar, rest] + ' to_match_snapshot diff --git a/src/js/literals/record.test.fnk.snap b/src/js/literals/record.test.fnk.snap index 2131aef..89de4a0 100644 --- a/src/js/literals/record.test.fnk.snap +++ b/src/js/literals/record.test.fnk.snap @@ -1,253 +1,204 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`calculated props compiles 1`] = ` -"export const foo = { - [\`spam\`]: 456, +exports[`record compiles calculated props 1`] = ` +"const foo_0 = { + spam: 456, [\`spam-\${ham}\`]: \`ni\` -};" -`; - -exports[`partial compiles 1`] = ` -"ˆpartial => ({ - foo: bar, - ...ˆpartial -}); - -ˆpartial => ({ - foo: ˆpartial, - bar: spam -});" +}; +export const foo = foo_0;" `; exports[`record compiles idents that are not js prop-names 1`] = ` -"export const foo = { +"const foo_0 = { foo: bar, π: 3.12, ƒ: \`fink\`, \\"foo-bar\\": spam -};" +}; +export const foo = foo_0;" `; exports[`record compiles key:val 1`] = ` -"export const foo = { +"const foo_0 = { a: 1, b: 123, - [\`c-d-e\`]: cde -};" + \\"c-d-e\\": cde +}; +export const foo = foo_0;" `; exports[`record compiles key:val 2`] = ` -"export const obj7 = { +"const obj7_0 = { a: 123, b: 123 && 123 && 1345, - c: (a, b) => 134 -};" + c: () => { + return 134; + } +}; +export const obj7 = obj7_0;" `; exports[`record compiles member expr as keys 1`] = ` -"let _do_result; - -{ - let ˆrec_1 = { ...bar - }; - ˆrec_1 = { ...ˆrec_1, - spam: { ...ˆrec_1?.spam, - ham: { ...ˆrec_1?.spam?.ham, - ni: \`ni\` - } +"const foo_0 = { ...bar, + spam: { + ham: { + ni: \`ni\` } - }; - ˆrec_1 = { ...ˆrec_1, - na: 1234 - }; - ˆrec_1 = { ...ˆrec_1, - ...nu - }; - _do_result = ˆrec_1; -} -export const foo = _do_result; -_do_result = undefined;" + }, + na: 1234, + ...nu +}; +export const foo = foo_0;" `; exports[`record compiles member expr as keys 2`] = ` -"let _do_result; - -{ - let ˆrec_1 = { ...bar - }; - ˆrec_1 = { ...ˆrec_1, - spam: { ...ˆrec_1?.spam, - ham: (() => { - let ˆrec_2 = {}; - ˆrec_2 = { ...ˆrec_2, - ni: { ...ˆrec_2?.ni, - na: \`ni\` - } - }; - return ˆrec_2; - })() +"const foo_0 = { ...bar, + spam: { + ham: { + ni: { + na: \`ni\` + } } - }; - ˆrec_1 = { ...ˆrec_1, - ...nu - }; - _do_result = ˆrec_1; -} -export const foo = _do_result; -_do_result = undefined;" -`; - -exports[`record compiles multiline 1`] = ` -"export const foo = { - a: 123, - b: 123 && 123 && 1345, - c: (a, b) => 134, - d: foo(a + 3) -};" -`; - -exports[`record compiles multiline 2`] = ` -"export const foo = { - a: 123, - b: 123 && 123 && 1345, - c: (a, b) => 134, - d: foo(a + 3) -};" + }, + ...nu +}; +export const foo = foo_0;" `; exports[`record compiles shorthand 1`] = ` -"export const foo = { - foo, - π, - ƒ, +"const foo_0 = { + bar: bar, + π: π, + ƒ: ƒ, \\"foo-bar\\": fooᜭbar -};" +}; +export const foo = foo_0;" `; exports[`record compiles shorthand 2`] = ` -"export const foo = { - a, +"const foo_0 = { + a: a, \\"delete\\": ˆdelete, - true, - false -};" + true: true, + false: false +}; +export const foo = foo_0;" `; exports[`record compiles shorthand 3`] = ` -"export const foo = { - [\`foo\`]: \`foo\` -};" +"const key_0 = \`foo\`; +const foo_0 = { + [key_0]: key_0 +}; +export const foo = foo_0;" `; -exports[`record compiles simple 1`] = `"export const foo = {};"`; +exports[`record compiles simple 1`] = ` +"const foo_0 = {}; +export const foo = foo_0;" +`; exports[`record compiles spread 1`] = ` -"export const foo = { - a, - b, +"const foo_0 = { + a: a, + b: b, ...c -};" +}; +const bar_0 = { ...foo_0, + ...ni +}; +const spam_0 = { ...ham, + ni: ni +}; +const ni_0 = { ...na, + ...nu +}; +export const foo = foo_0, + bar = bar_0, + spam = spam_0, + ni = ni_0;" `; exports[`unpacking record compiles computed keys 1`] = ` -"const { - [\`n i\`]: ni -} = foo;" +"const out_0 = [foo[\`n i\`], foo[ni], foo[\`foo\${bar}\`].c]; +export const out = out_0;" `; exports[`unpacking record compiles defaults 1`] = ` -"const { - x = 1, - π = 2, - ni: { - y, - z - } -} = { - ni: { - y: 1, - z: 2 - } -};" +"const hdm_0 = foo.a; +const hdm_1 = foo.b; +const val_0 = foo.ni; +const out_0 = [undefined === hdm_0 ? 1 : hdm_0, undefined === hdm_1 ? 2 : hdm_1, val_0.c, val_0.d]; +export const out = out_0;" `; exports[`unpacking record compiles empty 1`] = ` -"const { - foo: ˆunused_1, - bar -} = { - foo: 12, - bar: 34 -};" +"const key_1 = \`bar\`; +const { + foo: _key_0, + bar: _key_1, + ...shrub_0 +} = foo; +const out_0 = [foo.bar, shrub_0]; +export const out = out_0;" `; exports[`unpacking record compiles member expr as keys 1`] = ` -"const { - spam: { - ham: { - ni: ni - } - }, - ...rest -} = foo;" +"const key_0 = \`spam\`; +const { + spam: _key_0, + ...rest_0 +} = foo; +const out_0 = [foo.spam.ham.ni, rest_0]; +export const out = out_0;" `; exports[`unpacking record compiles member expr as keys 2`] = ` -"const { - spam: { - ham: { - ni: { - ni: nu, - foo: { - bar: bar - } - } - } - }, - ...rest -} = foo;" +"const key_0 = \`spam\`; +const val_2 = foo.spam.ham.ni; +const { + spam: _key_0, + ...rest_0 +} = foo; +const out_0 = [val_2.ni, val_2.foo.bar, rest_0]; +export const out = out_0;" `; exports[`unpacking record compiles member expr as keys 3`] = ` -"const { - \\"foo-bar\\": { - \\"spam-ham\\": { - ni: { - ni: nu, - foo: { - bar: bar - } - } - } - }, - ...rest -} = foo;" +"const key_0 = \`foo-bar\`; +const val_2 = foo[key_0][\`spam-ham\`].ni; +const { + \\"foo-bar\\": _key_0, + ...rest_0 +} = foo; +const out_0 = [val_2.ni, val_2.foo.bar, rest_0]; +export const out = out_0;" `; exports[`unpacking record compiles non js idents 1`] = ` -"const { - foo, - π, - ƒ, - \\"delete\\": ˆdelete -} = spam;" +"const out_0 = [spam.foo, spam.π, spam.ƒ, spam[\`delete\`]]; +export const out = out_0;" `; exports[`unpacking record compiles simple 1`] = ` -"const { - a, - b, - c -} = ni;" +"const out_0 = [ni.a, ni.b, ni.c]; +export const out = out_0;" `; exports[`unpacking record compiles spread 1`] = ` -"const { - e, - ...f -} = { - e: 0, - foo: 12, - bar: 34 -};" +"const key_0 = \`a\`; +const key_1 = \`foo-\${bar}\`; +const { + a: _key_0, + [\`foo-\${bar}\`]: _key_1, + ...c_0 +} = foo; +const out_0 = [foo.a, foo[\`foo-\${bar}\`], c_0]; +export const out = out_0;" +`; + +exports[`unpacking record destructuress tpls 1`] = ` +"const val_0 = shrub.foo; +const out_0 = [val_0[1], val_0[0]]; +export const out = out_0;" `; diff --git a/src/js/literals/regex.test.fnk.snap b/src/js/literals/regex.test.fnk.snap index c55bc67..606c9d7 100644 --- a/src/js/literals/regex.test.fnk.snap +++ b/src/js/literals/regex.test.fnk.snap @@ -1,12 +1,19 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`regex compiles escape char 1`] = `"export const regex = rx\`.+/\\\\#.+\\\\\\\\\`;"`; +exports[`regex compiles escape char 1`] = ` +"const regex_0 = rx\`.+/\\\\#.+\\\\\\\\\`; +export const regex = regex_0;" +`; exports[`regex compiles multiline 1`] = ` -"export const regex = rx\`(?\\\\d{4})- # year part of a date +"const regex_0 = rx\`(?\\\\d{4})- # year part of a date (?\\\\d{2})- # month part of a date (?\\\\d{2}) # day part of a date -\`;" +\`; +export const regex = regex_0;" `; -exports[`regex compiles single line 1`] = `"export const regex = rx\`(?\\\\d{4})-(?\\\\d{2})-(?\\\\d{2})\`;"`; +exports[`regex compiles single line 1`] = ` +"const regex_0 = rx\`(?\\\\d{4})-(?\\\\d{2})-(?\\\\d{2})\`; +export const regex = regex_0;" +`; diff --git a/src/js/literals/string.fnk b/src/js/literals/string.fnk index d168ee0..ed2ea77 100644 --- a/src/js/literals/string.fnk +++ b/src/js/literals/string.fnk @@ -1,37 +1,66 @@ -babel_types = import '@babel/types' -{templateElement, templateLiteral, taggedTemplateExpression} = babel_types +types = import '@babel/types' +{templateLiteral, taggedTemplateExpression, templateElement} = types + {rx, replace_all} = import '@fink/std-lib/regex.fnk' -{map, filter} = import '@fink/std-lib/iter.fnk' -{transform, drop_if, map_with_ctx, collect_with_ctx} = import '../transform.fnk' +{add, get_js, set_js2} = import '../context.fnk' -transform_string = fn node, ctx: - {exprs: parts, tag} = node - quasies = pipe parts: - filter ?.type == 'string:text' +transform_str = fn expr, ctx: + [{args: [value], loc}] = expr + raw = replace_all + value + rx'\\([\s\S])|([`])' + '\\$1$2' - map fn part: - templateElement rec: - raw: replace_all - part.value - rx'\\([\s\S])|(`)' - '\\$1$2' + js = templateLiteral + list: + rec: + ...templateElement {raw} + loc + [] + set_js2 expr, js, ctx - [expressions, next_ctx] = pipe parts: - drop_if ?.type == 'string:text' - map_with_ctx transform - collect_with_ctx ctx - templ_str = templateLiteral [...quasies], expressions - match tag: - false: - [templ_str, next_ctx] +split_exprs = fn [part=false, ...parts], ctx, isq=true, quasis=[], exprs=[]: + match part: + false: [quasis, exprs] else: - [tag, end_ctx] = transform node.tag, next_ctx - tagged_str = taggedTemplateExpression tag, templ_str - [tagged_str, end_ctx] + js = get_js part, ctx + match true: + isq: + [elem] = js.quasis + split_exprs parts, ctx, false, [...quasis, elem], exprs + else: + split_exprs parts, ctx, true, quasis, [...exprs, js] + + + +transform_template = fn expr, ctx: + [{args: parts}] = expr + [quasis, exprs] = split_exprs parts, ctx + js = templateLiteral quasis, exprs + set_js2 expr, js, ctx + + + +transform_tagged_template = fn expr, ctx: + [{args: [tag_id, ...parts]}] = expr + tag = get_js tag_id, ctx + [quasis, exprs] = split_exprs parts, ctx + tl = templateLiteral quasis, exprs + js = taggedTemplateExpression tag, tl + set_js2 expr, js, ctx + + + + +add_string = fn ctx: + pipe ctx: + add 'str', transform_str + add 'strt', transform_template + add 'strtt', transform_tagged_template diff --git a/src/js/literals/string.test.fnk b/src/js/literals/string.test.fnk index 65d680d..7f0cffc 100644 --- a/src/js/literals/string.test.fnk +++ b/src/js/literals/string.test.fnk @@ -1,5 +1,5 @@ -{fink2js} = import '../../testing/generate.fnk' {describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' +{fink2js} = import '../../testing/generate.fnk' describe 'string', fn: @@ -27,7 +27,7 @@ describe 'string', fn: expect fink2js " str1 = 'foo`bar\\nspam\\`ni' - str2 = \"foo\\\\\" + str2 = 'foo\\\\' " to_match_snapshot diff --git a/src/js/literals/string.test.fnk.snap b/src/js/literals/string.test.fnk.snap index dd81863..655b5c5 100644 --- a/src/js/literals/string.test.fnk.snap +++ b/src/js/literals/string.test.fnk.snap @@ -1,23 +1,34 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`string compiles escape chars 1`] = ` -"export const str1 = \`foo\\\\\`bar\\\\nspam\\\\\`ni\`; -export const str2 = \`foo\\\\\\\\\`;" +"const str1_0 = \`foo\\\\\`bar\\\\nspam\\\\\`ni\`; +const str2_0 = \`foo\\\\\\\\\`; +export const str1 = str1_0, + str2 = str2_0;" `; exports[`string compiles multiline 1`] = ` -"export const str = \`line 1 +"const str_0 = \`line 1 line 2 with leading space -line 3\`;" +line 3\`; +export const str = str_0;" `; exports[`string compiles multiline with expressions 1`] = ` -"export const str = \`bar +"const str_0 = \`bar spam \${shrub + ni}\${foo} ni -\`;" +\`; +export const str = str_0;" `; -exports[`string compiles simple 1`] = `"export const str = \`ab\`;"`; +exports[`string compiles simple 1`] = ` +"const str_0 = \`ab\`; +export const str = str_0;" +`; -exports[`string compiles tagged template string 1`] = `"export const str = foo\`bar \${ni(spam, shrub)} na\`;"`; +exports[`string compiles tagged template string 1`] = ` +"const sx_0 = ni(spam, shrub); +const str_0 = foo\`bar \${sx_0} na\`; +export const str = str_0;" +`; diff --git a/src/js/logical/in.fnk b/src/js/logical/in.fnk index 359248b..ac95cc9 100644 --- a/src/js/logical/in.fnk +++ b/src/js/logical/in.fnk @@ -1,23 +1,26 @@ -babel_types = import '@babel/types' -{identifier, callExpression} = babel_types +types = import '@babel/types' +{identifier, callExpression} = types -{use_runtime_fn} = import '../runtime.fnk' -{transform_with_partial_lr} = import '../partial/init.fnk' +{add, get_js, set_js2, add_runtime_requirement} = import '../context.fnk' -transform_in = fn node, ctx: - runtime_fn = '_${node.op}_' - expr_ctx = use_runtime_fn runtime_fn, ctx - - [left, right, next_ctx, wrap_partial] = transform_with_partial_lr node.left, node.right, expr_ctx +transform_in = fn expr, ctx: + [{args: [left_id, right_id]}] = expr js = callExpression - identifier runtime_fn - [left, right] + identifier '_in_' + list: + get_js left_id, ctx + get_js right_id, ctx - wrap_partial js, next_ctx + pipe ctx: + set_js2 expr, js, ? + add_runtime_requirement 'in', ? +add_in = fn ctx: + pipe ctx: + add 'in', transform_in diff --git a/src/js/logical/in.test.fnk b/src/js/logical/in.test.fnk index 0775070..3dadeb8 100644 --- a/src/js/logical/in.test.fnk +++ b/src/js/logical/in.test.fnk @@ -1,12 +1,12 @@ +{skip, describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' {fink2js} = import '../../testing/generate.fnk' -{describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' describe 'in', fn: it 'compiles with default runtime', fn: expect fink2js " - foo = 1 in [1, 2, 3] + foo = 1 in [1, x, 3] bar = '2' in '1234' spam = key in {foo: bar} shrub = item in ni @@ -14,11 +14,11 @@ describe 'in', fn: to_match_snapshot - it 'compiles with custom runtime', fn: + skip.it 'compiles with custom runtime', fn: expect fink2js " {better_in: _in_} = import './foo.fnk' - foo = 1 in [1, 2, 3] + foo = 1 in [1, x, 3] bar = '2' in '1234' spam = key in {foo: bar} shrub = item in ni @@ -26,7 +26,7 @@ describe 'in', fn: to_match_snapshot - it 'compiles as partial', fn: + skip.it 'compiles as partial', fn: expect fink2js " ? in [1, 2, 3] @@ -35,7 +35,7 @@ describe 'in', fn: to_match_snapshot - it 'compiles with custom runtime import', fn: + skip.it 'compiles with custom runtime import', fn: expect fink2js " {_in_} = import './foo.fnk' diff --git a/src/js/logical/in.test.fnk.snap b/src/js/logical/in.test.fnk.snap index db2c2bd..05fff4d 100644 --- a/src/js/logical/in.test.fnk.snap +++ b/src/js/logical/in.test.fnk.snap @@ -22,10 +22,19 @@ exports[`in compiles with custom runtime import 1`] = `"import { _in_ } from \\" exports[`in compiles with default runtime 1`] = ` "import { _in_ } from \\"@fink/js-interop/runtime.js\\"; -export const foo = _in_(1, [1, 2, 3]); -export const bar = _in_(\`2\`, \`1234\`); -export const spam = _in_(key, { - foo: bar + +const foo_0 = _in_(1, [1, x, 3]); + +const bar_0 = _in_(\`2\`, \`1234\`); + +const spam_0 = _in_(key, { + foo: bar_0 }); -export const shrub = _in_(item, ni);" + +const shrub_0 = _in_(item, ni); + +export const foo = foo_0, + bar = bar_0, + spam = spam_0, + shrub = shrub_0;" `; diff --git a/src/js/logical/init.fnk b/src/js/logical/init.fnk index 528fb1b..cca3958 100644 --- a/src/js/logical/init.fnk +++ b/src/js/logical/init.fnk @@ -1,45 +1,24 @@ -babel_types = import '@babel/types' -{logicalExpression, unaryExpression} = babel_types +types = import '@babel/types' +{logicalExpression} = types -{add, add_with_runtime, any} = import '../context.fnk' +{add, get_js, set_js2} = import '../context.fnk' -{transform_in} = import './in.fnk' -{transform_with_partial_lr, transform_with_partial} = import '../partial/init.fnk' +{transform_unary} = import '../transform.fnk' -transform_op = rec: - 'and': '&&' - 'or': '||' - 'not': '!' - - - -transform_not = fn node, ctx: - {(node.op): op} = transform_op - [wrap_partial, right, next_ctx] = transform_with_partial node.right, ctx - - js = unaryExpression op, right - - wrap_partial js, next_ctx - - - -transform_logical = fn node, ctx: - {(node.op): op} = transform_op - - [left, right, next_ctx, wrap_partial] = transform_with_partial_lr node.left, node.right, ctx - - js = logicalExpression op, left, right - - wrap_partial js, next_ctx +transform_binary = fn jsop: fn expr, ctx: + [{args: [left_id, right_id]}] = expr + left = get_js left_id, ctx + right = get_js right_id, ctx + js = logicalExpression jsop, left, right + set_js2 expr, js, ctx add_logical = fn ctx: pipe ctx: - add any, 'and', transform_logical - add any, 'or', transform_logical - add any, 'not', transform_not - # TODO: should this live in iterables? - add_with_runtime any, 'in', transform_in + add 'and', transform_binary '&&' + add 'or', transform_binary '||' + add 'not', transform_unary + diff --git a/src/js/logical/init.test.fnk b/src/js/logical/init.test.fnk index 9d2f7cd..db24621 100644 --- a/src/js/logical/init.test.fnk +++ b/src/js/logical/init.test.fnk @@ -1,5 +1,5 @@ {fink2js} = import '../../testing/generate.fnk' -{describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' +{skip, describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' describe 'logical', fn: @@ -13,7 +13,7 @@ describe 'logical', fn: to_match_snapshot - it 'compiles as partial', fn: + skip.it 'compiles as partial', fn: expect fink2js " ? or foo ? diff --git a/src/js/logical/init.test.fnk.snap b/src/js/logical/init.test.fnk.snap index 86ecd0c..b6234a4 100644 --- a/src/js/logical/init.test.fnk.snap +++ b/src/js/logical/init.test.fnk.snap @@ -1,9 +1,12 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`logical compiles 1`] = ` -"export const foo = a || b || c; -export const bar = a && b && c; -export const spam = !a;" +"const foo_0 = a || b || c; +const bar_0 = a && b && c; +const spam_0 = !a; +export const foo = foo_0, + bar = bar_0, + spam = spam_0;" `; exports[`logical compiles as partial 1`] = ` diff --git a/src/js/module.fnk b/src/js/module.fnk deleted file mode 100644 index 89f691e..0000000 --- a/src/js/module.fnk +++ /dev/null @@ -1,77 +0,0 @@ -babel_types = import '@babel/types' -{ - identifier, assignmentExpression, expressionStatement - memberExpression, callExpression, objectProperty, objectPattern - variableDeclaration, variableDeclarator - isImportDefaultSpecifier, isImportSpecifier -} = babel_types - -{map} = import '@fink/std-lib/iter.fnk' - - -[no_result] = [] - - -transform_specifiers = fn {specifiers, source}: - init = callExpression - identifier 'require' - [source] - - [first] = specifiers - - match first: - isImportDefaultSpecifier ?: - [{local}] = specifiers - variableDeclaration 'const', [variableDeclarator local, init] - - isImportSpecifier ?: - props = pipe specifiers: - map fn node: - objectProperty - node.imported - node.local - false - node.imported.name == node.local.name - - variableDeclaration 'const', list: - variableDeclarator - objectPattern [...props] - init - - else: - expressionStatement init - - -# ImportNamespaceSpecifier: -module_transforms = rec: - ImportDeclaration: fn path: - path.replaceWith transform_specifiers path.node - no_result - - ExportDefaultDeclaration: fn path: - id = path.node.declaration - foo = expressionStatement - assignmentExpression - '=' - memberExpression - identifier 'exports' - identifier 'default' - id - - path.insertAfter foo - path.remove _ - no_result - - ExportNamedDeclaration: fn path: - {declarations: [{id}]} = path.node.declaration - foo = expressionStatement - assignmentExpression - '=' - memberExpression - identifier 'exports' - id - id - - path.insertAfter foo - path.replaceWith path.node.declaration - no_result diff --git a/src/js/module/import.fnk b/src/js/module/import.fnk index 5aadbcb..d75f932 100644 --- a/src/js/module/import.fnk +++ b/src/js/module/import.fnk @@ -1,8 +1,13 @@ -babel_types = import '@babel/types' -{callExpression, Import: async_import} = babel_types +types = import '@babel/types' +{ + identifier, importDeclaration, importSpecifier, callExpression, stringLiteral + importDefaultSpecifier, import: import_js +} = types {ends_with, starts_with, slice, is_str} = import '@fink/std-lib/str.fnk' -{transform} = import '../transform.fnk' +{get_refs} = import '../../ir/context.fnk' +{add, set_js2, get_js, get_js_literal} = import '../context.fnk' +{escape_ident, ident} = import '../identifier/init.fnk' @@ -25,23 +30,60 @@ resolve_ext = fn import_url, options: -transform_import = fn node, ctx: - {options} = ctx +get_runtime_imports = fn ctx: + specs = match ctx: + {runtime.in: true}: + list: + importSpecifier + identifier '_in_' + identifier '_in_' - [right, next_ctx] = match node.right: - {type: 'string', exprs: [..., {type: 'string:text'}]}: - [...exprs, url] = node.right.exprs + else: [] - transform - rec: - ...node.right - exprs: [...exprs, {...url, value: resolve_ext url.value, options}] - ctx + match specs: + [?]: [importDeclaration specs, stringLiteral '@fink/js-interop/runtime.js'] + else: [] + + + + +transform_import = fn expr, ctx: + [{args: [uri_id, key_id=false]}, [res_id]] = expr + + {quasis: [{value: {raw: value}}]} = get_js_literal uri_id, ctx + uri = stringLiteral resolve_ext value, ctx + + specs = match [res_id, key_id]: + [0 == get_refs ?, ctx]: + [] + [, false]: + [importDefaultSpecifier ident res_id] else: - transform node.right, ctx + {quasis: [{value: {raw: key}}]} = get_js key_id, ctx + list: + importSpecifier + ident res_id + identifier escape_ident key + + js = importDeclaration specs, uri + [[js], ctx] + + + +transform_dyn_import = fn expr, ctx: + [{args: [uri_id]}] = expr + uri = get_js uri_id, ctx js = callExpression - async_import _ - [right] + import_js _ + [uri] + + set_js2 expr, js, ctx + + + +add_import = fn ctx: + pipe ctx: + add 'imp', transform_import + add 'impd', transform_dyn_import - [js, next_ctx] \ No newline at end of file diff --git a/src/js/module/import.test.fnk b/src/js/module/import.test.fnk index 5beb9ed..5356370 100644 --- a/src/js/module/import.test.fnk +++ b/src/js/module/import.test.fnk @@ -1,5 +1,5 @@ -{fink2js} = import '../../testing/generate.fnk' {describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' +{fink2js} = import '../../testing/generate.fnk' describe 'import', fn: @@ -10,6 +10,8 @@ describe 'import', fn: {foo: spam} = import './shrub.fnk' {π, delete} = import './ni.fnk' {foo-bar} = import './ham.fnk' + shrub = import './shrub.fnk' + out = [bar, spam, π, delete, foo-bar, shrub] " to_match_snapshot @@ -17,7 +19,7 @@ describe 'import', fn: it 'imports dynamically with static URL', fn: expect fink2js " - ni = await import './shrub.fnk' + ni = fn: import './shrub.fnk' " to_match_snapshot @@ -25,10 +27,9 @@ describe 'import', fn: it 'imports with dynamic URLs', fn: expect fink2js " - foo = bar + spam - shrub = await import foo - ni = await import '\${foo}' - na = await import './\${foo}.fnk' + shrub = fn: import foo + ni = fn: import '\${foo}' + na = fn: import './\${foo}.fnk' " to_match_snapshot @@ -40,10 +41,11 @@ describe 'import', fn: # {is_str} = import '@fink/std-lib/str.fnk' {bar} = import './spam.fnk' - {foo: spam} = await import './shrub.fnk' - na = await import './\${foo}.fnk' + {foo: spam} = fn: import './shrub.fnk' + na = fn: import './\${foo}.fnk' import './foo.fnk' ni = import '../ni.fnk' + out = [is_str, bar, ni] " {import: {ext: {rel: '.fnk', abs: '.js'}}} to_match_snapshot @@ -63,6 +65,7 @@ describe 'import', fn: expect fink2js " foo = import './foo.fnk' + out = [foo] " to_match_snapshot diff --git a/src/js/module/import.test.fnk.snap b/src/js/module/import.test.fnk.snap index ca7ae30..3e0634e 100644 --- a/src/js/module/import.test.fnk.snap +++ b/src/js/module/import.test.fnk.snap @@ -1,14 +1,28 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`import imports default export 1`] = `"import foo from \\"./foo.js\\";"`; +exports[`import imports default export 1`] = ` +"import foo_0 from \\"./foo.js\\"; +const out_0 = [foo_0]; +export const out = out_0;" +`; + +exports[`import imports dynamically with static URL 1`] = ` +"const ni_0 = () => { + return import(\`./shrub.fnk\`); +}; -exports[`import imports dynamically with static URL 1`] = `"export const ni = await import(\`./shrub.js\`);"`; +export const ni = ni_0;" +`; exports[`import imports exported values 1`] = ` -"import { bar } from \\"./spam.js\\"; -import { foo as spam } from \\"./shrub.js\\"; -import { π, ˆdelete } from \\"./ni.js\\"; -import { fooᜭbar } from \\"./ham.js\\";" +"import { bar as bar_0 } from \\"./spam.js\\"; +import { foo as spam_0 } from \\"./shrub.js\\"; +import { π as π_0 } from \\"./ni.js\\"; +import { ˆdelete as delete_0 } from \\"./ni.js\\"; +import { fooᜭbar as fooᜭbar_0 } from \\"./ham.js\\"; +import shrub_0 from \\"./shrub.js\\"; +const out_0 = [bar_0, spam_0, π_0, delete_0, fooᜭbar_0, shrub_0]; +export const out = out_0;" `; exports[`import imports module 1`] = ` @@ -17,20 +31,34 @@ import \\"@fink/foo/bar.js\\";" `; exports[`import imports with dynamic URLs 1`] = ` -"export const foo = bar + spam; -export const shrub = await import(foo); -export const ni = await import(\`\${foo}\`); -export const na = await import(\`./\${foo}.js\`);" +"const shrub_0 = () => { + return import(foo); +}; + +const ni_0 = () => { + return import(\`\${foo}\`); +}; + +const na_0 = () => { + return import(\`./\${foo}.fnk\`); +}; + +export const shrub = shrub_0, + ni = ni_0, + na = na_0;" `; exports[`import imports without transforming ext 1`] = ` -"// -import { is_str } from \\"@fink/std-lib/str.js\\"; -import { bar } from \\"./spam.fnk\\"; -const { - foo: spam -} = await import(\`./shrub.fnk\`); -export const na = await import(\`./\${foo}.fnk\`); +"import { is_str as is_str_0 } from \\"@fink/std-lib/str.js\\"; +import { bar as bar_0 } from \\"./spam.fnk\\"; + +const na_0 = () => { + return import(\`./\${foo}.fnk\`); +}; + import \\"./foo.fnk\\"; -import ni from \\"../ni.fnk\\";" +import ni_0 from \\"../ni.fnk\\"; +const out_0 = [is_str_0, bar_0, ni_0]; +export const na = na_0, + out = out_0;" `; diff --git a/src/js/module/init.fnk b/src/js/module/init.fnk index 2de09df..550a318 100644 --- a/src/js/module/init.fnk +++ b/src/js/module/init.fnk @@ -1,185 +1,171 @@ -babel_types = import '@babel/types' +types = import '@babel/types' { - file, program, interpreterDirective, stringLiteral - importDeclaration, importSpecifier, importDefaultSpecifier - exportNamedDeclaration, exportDefaultDeclaration, identifier -} = babel_types -{starts_with, slice} = import '@fink/std-lib/str.fnk' -{map_ac, filter, fold} = import '@fink/std-lib/iter.fnk' - -{add, any} = import '../context.fnk' -{wrap_with_comment_loc} = import '../comments/init.fnk' -{block_statement} = import '../block/init.fnk' -{transform, is_ignorable_import} = import '../transform.fnk' -{map_with_ctx, drop_if, collect_with_ctx} = import '../transform.fnk' - -{transform_import: transform_async_import, resolve_ext} = import './import.fnk' -{set_runtime_impl, is_runtime_fn, get_runtime_imports} = import '../runtime.fnk' - - - -get_hashbang = fn expr: - {comments} = expr - match comments: - {leading: [{op: '#', loc: {start: {line: 1}}, value: starts_with ?, '!'}]}: - [first, ...rest] = comments.leading - shebang = interpreterDirective '${slice first.value, 1}' - [[shebang], {...expr, comments: {...comments, leading: rest}}] - else: - [[], expr] + file, program, exportNamedDeclaration, exportDefaultDeclaration, identifier + assignmentExpression, expressionStatement + memberExpression, callExpression, objectProperty, objectPattern + variableDeclaration, variableDeclarator + isImportDefaultSpecifier, isImportSpecifier, interpreterDirective +} = types +{map} = import '@fink/std-lib/iter.fnk' +{slice} = import '@fink/std-lib/str.fnk' ---- istanbul ignore next --- -ignorable_import = fn expr, ctx: - match expr: - {type: 'assign', right: is_ignorable_import ?, ctx}: - true - else: - false +{add, get_js, get_js_literal, with_loc} = import '../context.fnk' +{transform_exprs} = import '../transform.fnk' +{escape_ident} = import '../identifier/init.fnk' +{get_runtime_imports} = import './import.fnk' +[no_result] = [] -add_runtime_fn_overrides = fn expr, ctx: - match expr: - {type: 'assign', right.op: 'import', left.type: 'rec'}: - {right.right.exprs: [{value: uri}]} = expr - next_ctx = pipe expr.left.exprs: - filter fn {left, right}: - match right: - false: is_runtime_fn left.value, ctx - else: is_runtime_fn right.value, ctx +transform_specifiers = fn {specifiers, source}: + init = callExpression + identifier 'require' + [source] - fold ctx, fn {left, right}, override_ctx: - name = match right: - false: left.value - else: right.value - set_runtime_impl name, uri, override_ctx + [first] = specifiers - [expr, next_ctx] - else: - [expr, ctx] + match first: + isImportDefaultSpecifier ?: + [{local}] = specifiers + variableDeclaration 'const', [variableDeclarator local, init] + isImportSpecifier ?: + props = pipe specifiers: + map fn node: + objectProperty + node.imported + node.local + false + node.imported.name == node.local.name + [...?] + variableDeclaration 'const', list: + variableDeclarator + objectPattern [...props] + init -imported_specs = fn exprs, ctx: - pipe exprs: - map_ac fn prop, , imp_ctx: - [right, left_ctx] = match prop: - {right: false}: - transform prop.left, imp_ctx - else: - transform prop.right, imp_ctx + else: + expressionStatement init - match prop: - {left.value: 'default'}: - imp = importSpecifier right, identifier prop.left.value - [imp, ,left_ctx] - else: - [left, next_ctx] = transform prop.left, left_ctx - imp = importSpecifier right, left - [imp, , next_ctx] - collect_with_ctx ctx +module_transforms = rec: + ImportDeclaration: fn path: + path.replaceWith transform_specifiers path.node + no_result + + +get_exports = fn [prop=false, ...props], decls=[], dflt_decl=[]: + match prop: + false: + named_decls = match decls: + [?]: [exportNamedDeclaration variableDeclaration 'const', decls] + else: [] + [...named_decls, ...dflt_decl] + else: + {key, value} = prop + match key: + {type: 'StringLiteral', value: 'default'}: + dd = exportDefaultDeclaration value + ident = with_loc key, identifier escape_ident key.value + decl = with_loc key, variableDeclarator ident, value + get_exports props, [...decls, decl], [...dflt_decl, dd] + + {type: 'StringLiteral'}: + ident = with_loc key, identifier escape_ident key.value + decl = with_loc key, variableDeclarator ident, value + get_exports props, [...decls, decl], dflt_decl -transform_import = fn node, ctx: - {options} = ctx - {right: {right: {exprs: [{value: url}]}}} = node + else: + ident = with_loc key, identifier escape_ident key.name + decl = with_loc key, variableDeclarator ident, value + get_exports props, [...decls, decl], dflt_decl - [imports, end_ctx] = match node.left: - {type: 'ident'}: - [imp, next_ctx] = transform node.left, ctx - [[importDefaultSpecifier imp], next_ctx] - --- istanbul ignore next TODO: it is only else --- - {type: 'rec'}: - imported_specs node.left.exprs, ctx - js = importDeclaration - imports - wrap_with_comment_loc - stringLiteral resolve_ext url, options - node.right.right +assign_st = fn left, right, value: + expressionStatement + assignmentExpression + '=' + memberExpression + identifier left + right + value - [js, end_ctx] +get_cjs_exports = fn [prop=false, ...props], exports=[]: + match prop: + false: + exports + else: + {key, value} = prop + match key: + {type: 'StringLiteral', value: 'default'}: + ident = with_loc key, identifier escape_ident key.value + exp = with_loc key, assign_st 'exports', ident, value + dflt = with_loc key, assign_st 'module', (identifier 'exports'), value + get_cjs_exports props, [dflt, ...exports, exp] + + {type: 'StringLiteral'}: + ident = with_loc key, identifier escape_ident key.value + exp = with_loc key, assign_st 'exports', ident, value + get_cjs_exports props, [...exports, exp] -transform_body_expr = fn expr, expr_ctx: - match expr: - {op: 'import'}: - {right: {exprs: [url]}} = expr - js = wrap_with_comment_loc - importDeclaration - [], stringLiteral resolve_ext url.value, expr_ctx.options - expr - [js, expr_ctx] + else: + ident = with_loc key, identifier escape_ident key.name + exp = with_loc key, assign_st 'exports', ident, value + get_cjs_exports props, [...exports, exp] - {right: {op: 'import'}}: - [imp, next_ctx] = transform_import expr, expr_ctx - js = wrap_with_comment_loc imp, expr - [js, next_ctx] - {type: 'assign', left: {type: 'ident', value: 'default'}}: - [decl, next_ctx] = transform expr.right, expr_ctx - js = wrap_with_comment_loc - exportDefaultDeclaration decl - expr - [js, next_ctx] - {type: 'assign', left: {type: 'ident'}}: - # we don't want to double up on comments? - {comments: _, ...decl} = expr - [decl_st, next_ctx] = block_statement decl, expr_ctx - js = wrap_with_comment_loc - exportNamedDeclaration decl_st - expr - [js, next_ctx] - else: - block_statement expr, expr_ctx +transform_mod_exports = fn expr, ctx: + [{args: [exports_id]}] = expr + {properties: exports} = get_js exports_id, ctx + export_statements = match ctx: + {module_type: 'cjs'}: get_cjs_exports exports + else: get_exports exports + [export_statements, ctx] -insert_imports = fn [body, ctx]: - [imports, end_ctx] = pipe ctx: - get_runtime_imports ? - drop_if ignorable_import - map_with_ctx transform_body_expr - collect_with_ctx ctx - [[...imports, ...body], end_ctx] +transfrom_module = fn exprs, ctx: + [body, next_ctx] = transform_exprs exprs, ctx + [..., last] = exprs + [{args: [ , drctvs_id]}] = last + drctvs = get_js_literal drctvs_id, next_ctx -transform_module = fn node, ctx: - [maybe_shebang_or_pragmas, ...rest] = node.exprs - [interpreter, first] = get_hashbang maybe_shebang_or_pragmas + directives = match drctvs: + {elements: [{type: 'TemplateLiteral'}]}: + [{quasis: [{value: {raw: value}}]}] = drctvs.elements + [interpreterDirective slice value, 2] + else: + [] - [body, end_ctx] = pipe [first, ...rest]: - map_with_ctx add_runtime_fn_overrides - drop_if ignorable_import - map_with_ctx transform_body_expr - collect_with_ctx ctx - insert_imports + runtime_imports = get_runtime_imports next_ctx js = file program - body + [...runtime_imports, ...body] [] 'module' - ...interpreter + ...directives - [js, end_ctx] + {...next_ctx, js} add_module = fn ctx: pipe ctx: - add 'module', any, transform_module - add 'import', any, transform_async_import + add 'mod', transform_mod_exports + diff --git a/src/js/module/init.test.fnk b/src/js/module/init.test.fnk index b1c38d2..4535d56 100644 --- a/src/js/module/init.test.fnk +++ b/src/js/module/init.test.fnk @@ -1,20 +1,14 @@ -{fink2js} = import '../../testing/generate.fnk' {describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' +{fink2js} = import '../../testing/generate.fnk' describe 'module', fn: - it 'handles comments', fn: - + it 'handles directives', fn: expect fink2js " #!/usr/bin/env node - # leading comment - - # expr comment foo = 1234 - - # trailing comment " to_match_snapshot @@ -26,5 +20,27 @@ describe 'module', fn: π = fn: true foo_bar = 1234 foo-bar = 1234 + default = 456 + " + to_match_snapshot + + expect + fink2js " + delete = fn: true + π = fn: true + foo_bar = 1234 + foo-bar = 1234 + default = 456 + ", {module_type: 'cjs'} + to_match_snapshot + + + + it 'handles side effects', fn: + expect + fink2js " + foo bar + shrub.ni foo + spam = ni " to_match_snapshot \ No newline at end of file diff --git a/src/js/module/init.test.fnk.snap b/src/js/module/init.test.fnk.snap index e174433..0ed37db 100644 --- a/src/js/module/init.test.fnk.snap +++ b/src/js/module/init.test.fnk.snap @@ -1,15 +1,46 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`module handles comments 1`] = ` +exports[`module handles directives 1`] = ` "#!/usr/bin/env node -// leading comment -// expr comment export const foo = 1234;" `; exports[`module handles exports 1`] = ` -"export const ˆdelete = () => true; -export const π = () => true; -export const foo_bar = 1234; -export const fooᜭbar = 1234;" +"const delete_0 = () => { + return true; +}; + +const π_0 = () => { + return true; +}; + +export const ˆdelete = delete_0, + π = π_0, + foo_bar = 1234, + fooᜭbar = 1234, + ˆdefault = 456; +export default 456;" +`; + +exports[`module handles exports 2`] = ` +"const delete_0 = () => { + return true; +}; + +const π_0 = () => { + return true; +}; + +module.exports = 456; +exports.ˆdelete = delete_0; +exports.π = π_0; +exports.foo_bar = 1234; +exports.fooᜭbar = 1234; +exports.ˆdefault = 456;" +`; + +exports[`module handles side effects 1`] = ` +"foo(bar); +shrub.ni(foo); +export const spam = ni;" `; diff --git a/src/js/partial/init.fnk b/src/js/partial/init.fnk deleted file mode 100644 index 300bf08..0000000 --- a/src/js/partial/init.fnk +++ /dev/null @@ -1,70 +0,0 @@ -babel_types = import '@babel/types' -{identifier, arrowFunctionExpression} = babel_types - -{add} = import '../context.fnk' -{transform} = import '../transform.fnk' - - - - - -partial_wrapper = fn js, ctx: - {partial_ident} = ctx - name = match partial_ident: - {name: {}}: - partial_ident.name - else: - '${ctx.ident_prefix}partial' - - partial_id = identifier name - [{is_partial: true, ...arrowFunctionExpression [partial_id], js}, ctx] - - -no_wrapper = fn js, ctx: [js, ctx] - - - -transform_with_partial = fn expr, ctx, default_wrapper=no_wrapper: - [js, next_ctx] = match expr: - {type: 'partial'}: - [js, next_ctx] = transform expr, ctx - [{params: [js], body: js, is_partial: true}, next_ctx] - else: - transform expr, ctx - - match js: - {is_partial: true}: - [partial_wrapper, js.body, next_ctx] - else: - [default_wrapper, js, next_ctx] - - - - -transform_with_partial_lr = fn left, right, ctx: - [wrapper_l, js_l, right_ctx] = transform_with_partial left, ctx - [wrapper, js_r, next_ctx] = transform_with_partial right, right_ctx, wrapper_l - - [js_l, js_r, next_ctx, wrapper] - - - - -transform_partial = fn , ctx: - {partial_ident} = ctx - - name = match partial_ident: - {name: {}}: - partial_ident.name - else: - '${ctx.ident_prefix}partial' - - js = identifier name - - [js, ctx] - - - -add_partial = fn ctx: - pipe ctx: - add 'partial', '?', transform_partial diff --git a/src/js/prop-access/init.fnk b/src/js/prop-access/init.fnk deleted file mode 100644 index 2708f4b..0000000 --- a/src/js/prop-access/init.fnk +++ /dev/null @@ -1,45 +0,0 @@ -babel_types = import '@babel/types' -{memberExpression, identifier} = babel_types - -{escape_prop} = import '../../js/identifier.fnk' -{raw_str} = import '../../js/types.fnk' - -{add, any} = import '../context.fnk' -{transform_with_partial} = import '../partial/init.fnk' - - -safe_prop_ident = fn {loc, value}, ctx : - id = escape_prop value - match id: - value: - [false, {loc, ...identifier id}, ctx] - else: - [true, {loc, ...raw_str value}, ctx] - - - -transform_right = fn right, ctx, default_wrap_partial: - match right: - {type: 'ident'}: - [computed, js, next_ctx] = safe_prop_ident right, ctx - [computed, default_wrap_partial, js, next_ctx] - # TODO add support for foo.?.bar and foo.(?).bar - else: - [wrap_partial, js, next_ctx] = transform_with_partial right, ctx, default_wrap_partial - [true, wrap_partial, js, next_ctx] - - - -transform_member = fn {left, right}, ctx: - [wrap_l, memb_left, right_ctx] = transform_with_partial left, ctx - [computed, wrap_partial, memb_right, next_ctx] = transform_right right, right_ctx, wrap_l - - js = memberExpression memb_left, memb_right, computed - - wrap_partial js, next_ctx - - - -add_member = fn ctx: - pipe ctx: - add any, '.', transform_member diff --git a/src/js/prop-access/init.test.fnk b/src/js/prop-access/init.test.fnk index dd27f52..bdab6cb 100644 --- a/src/js/prop-access/init.test.fnk +++ b/src/js/prop-access/init.test.fnk @@ -1,5 +1,5 @@ +{skip, describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' {fink2js} = import '../../testing/generate.fnk' -{describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' describe 'member', fn: @@ -11,12 +11,12 @@ describe 'member', fn: computed_member2 = item.(get_key foo) reserved_prop = item.arguments js_safe_unicode = [item.π, item.ƒ] - js_unsfae = item.foo-bar + js_unsafe = item.foo-bar " to_match_snapshot - it 'compiles partial', fn: + skip.it 'compiles partial', fn: expect fink2js " ?.foo diff --git a/src/js/prop-access/init.test.fnk.snap b/src/js/prop-access/init.test.fnk.snap index 991f55e..7b2da24 100644 --- a/src/js/prop-access/init.test.fnk.snap +++ b/src/js/prop-access/init.test.fnk.snap @@ -1,12 +1,19 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`member compiles 1`] = ` -"export const foo = spam.shrub; -export const computed_member = item[\`bar spam\`]; -export const computed_member2 = item[get_key(foo)]; -export const reserved_prop = item.arguments; -export const js_safe_unicode = [item.π, item.ƒ]; -export const js_unsfae = item[\\"foo-bar\\"];" +"const foo_0 = spam.shrub; +const computed_member_0 = item[\`bar spam\`]; +const key_4 = get_key(foo_0); +const computed_member2_0 = item[key_4]; +const reserved_prop_0 = item[\`arguments\`]; +const js_safe_unicode_0 = [item.π, item.ƒ]; +const js_unsafe_0 = item[\`foo-bar\`]; +export const foo = foo_0, + computed_member = computed_member_0, + computed_member2 = computed_member2_0, + reserved_prop = reserved_prop_0, + js_safe_unicode = js_safe_unicode_0, + js_unsafe = js_unsafe_0;" `; exports[`member compiles partial 1`] = ` diff --git a/src/js/runtime.fnk b/src/js/runtime.fnk deleted file mode 100644 index f68deb1..0000000 --- a/src/js/runtime.fnk +++ /dev/null @@ -1,94 +0,0 @@ -{is_str} = import '@fink/std-lib/str.fnk' -{filter, map} = import '@fink/std-lib/iter.fnk' - - -default_in_runtime = '@fink/js-interop/runtime.js' - - -add_runtime_fn = fn name, ctx: - {runtime} = ctx - rec: - ...ctx - runtime: rec: - ...runtime - names: [...runtime.names, name] - - - -set_runtime_impl = fn name, uri=default_in_runtime, ctx: - {runtime} = ctx - - overrides = match runtime: - {impl: {(name): is_str ?}}: - [...runtime.overrides, name] - else: - runtime.overrides - - rec: - ...ctx - runtime: rec: - ...runtime - overrides - impl: rec: - ...runtime.impl - (name): uri - - - -use_runtime_fn = fn name, ctx: - {runtime} = ctx - rec: - ...ctx - runtime: rec: - ...runtime - used: list: - name, - ...runtime.used | filter ? != name - - - -runtime_impl = fn ident, ctx: - {runtime: {impl: {(ident): uri}}} = ctx - uri - - - -is_runtime_fn = fn name, ctx: - name in ctx.runtime.names - - - -get_runtime_imports = fn ctx: - {runtime} = ctx - - pipe runtime.used: - # If it was overridden it was imported, no need to create an extra import - filter fn name: - not name in runtime.overrides - - map fn name: - uri = runtime_impl name, ctx - left = {type: 'ident', value: name} - [uri, {type: 'rec:kv', left, right: false}] - - map fn [uri, kv]: - rec: - type: 'assign' - op: '=' - left: {type: 'rec', exprs: [kv]} - right: rec: - op: 'import' - right: rec: - type: 'string' - exprs: [{type: 'string:text', value: uri}] - - - -init_runtimes = fn ctx: - rec: - ...ctx - runtime: rec: - names: [] - used: [] - overrides: [] - impl: {} diff --git a/src/js/spread/init.fnk b/src/js/spread/init.fnk deleted file mode 100644 index 0695736..0000000 --- a/src/js/spread/init.fnk +++ /dev/null @@ -1,22 +0,0 @@ -babel_types = import '@babel/types' -{spreadElement} = babel_types - -{add, any} = import '../context.fnk' -{transform} = import '../transform.fnk' - - -transform_spread = fn node, ctx: - [right, next_ctx] = transform node.right, ctx - match right: - {is_partial: true}: - js = spreadElement right.body - [{...js, is_partial: true}, next_ctx] - else: - js = spreadElement right - [js, next_ctx] - - - -add_spread = fn ctx: - pipe ctx: - add any, '...', transform_spread diff --git a/src/js/tail-call.fnk b/src/js/tail-call.fnk deleted file mode 100644 index 44dce60..0000000 --- a/src/js/tail-call.fnk +++ /dev/null @@ -1,82 +0,0 @@ - -{ - arrayExpression, arrayPattern, booleanLiteral, restElement, whileStatement - blockStatement, continueStatement - isVariableDeclarator, isCallExpression, isReturnStatement -} = import '@babel/types' - -{consts, assign} = import './types.fnk' - -{fold, filter, is_empty} = import '@fink/std-lib/iter.fnk' - - - -get_references = fn path: - {parentPath: {node.id: {name}, scope: {bindings}}} = path - bindings.(name).referencePaths - - - -filter_tail_calls = fn path: filter fn ref: match ref: - { - parentPath: isCallExpression ? - parentPath.parentPath: isReturnStatement ? - parentPath: path == ?.getFunctionParent _ - }: - true - else: - false - - - -get_tail_call_returns = fn path: - refs = get_references path - - pipe refs: - filter_tail_calls path - - - -replace_tail_calls_with_args_assing = fn args, tcs: - tcs | fold _, fn ref: - ret_st = ref.parentPath.parentPath - ret_st.replaceWithMultiple list: - assign - args - arrayExpression ref.parent.arguments - continueStatement _ - - - -replace_body_with_loop = fn path, args: - body = path.get 'body' - {node: {params}} = path - - body.unshiftContainer - 'body' - consts - arrayPattern params - args - - path.set 'params', [restElement args] - - path.set 'body', blockStatement list: - whileStatement - booleanLiteral true - path.node.body - - - -transform_tail_call = fn path: - match path: - {parentPath: isVariableDeclarator ?}: - [...tcs] = get_tail_call_returns path - - match tcs: - not is_empty ?: - args = path.scope.generateUidIdentifier 'args' - - replace_tail_calls_with_args_assing args, tcs - - replace_body_with_loop path, args - diff --git a/src/js/transform.fnk b/src/js/transform.fnk index d340d5c..17b8bd2 100644 --- a/src/js/transform.fnk +++ b/src/js/transform.fnk @@ -1,78 +1,124 @@ -{is_str} = import '@fink/std-lib/str.fnk' -{fold_ac, map_ac, filter} = import '@fink/std-lib/iter.fnk' -{try_catch, throw_err} = import '@fink/js-interop/errors.fnk' +types = import '@babel/types' +{ + binaryExpression, unaryExpression, expressionStatement + variableDeclaration, variableDeclarator +} = types -{add_loc} = import '../js/types.fnk' +# {throw_err} = import '@fink/js-interop/errors.fnk' +# {transform_error} = import '../ir/errors.fnk' -{transform_error} = import './errors.fnk' -{get_transformer} = import './context.fnk' +{get_transformer, get_js, get_js_literal, set_js2, with_loc} = import './context.fnk' +{get_value} = import '../ir/context.fnk' +{ident} = import './identifier/init.fnk' -{wrap_with_comment_loc} = import './comments/init.fnk' ---- istanbul ignore next --- -add_ignorable_import = fn uri: fn ctx: - {...ctx, ignoreable_imports: [...ctx.ignoreable_imports, uri]} +ops_to_js = rec: + '^': '**' + '==': '===' + '!=': '!==' + 'not': '!' -is_ignorable_import = fn expr, ctx: - match expr: - {op: 'import', right: {exprs: [{value: is_str ?}]}}: - [{value: uri}] = expr.right.exprs - uri in ctx.ignoreable_imports - else: - false +transform_binary = fn expr, ctx: + [{f: op, args: [left_id, right_id]}] = expr + left = get_js left_id, ctx + right = get_js right_id, ctx + {(op): jsop=op} = ops_to_js + js = binaryExpression jsop, left, right + set_js2 expr, js, ctx -wrap_node = fn ctx, js_node, node: - match ctx: - {wrap: 'loc'}: - add_loc node, js_node - else: - wrap_with_comment_loc js_node, node +transform_unary = fn expr, ctx: + [{f: op, args: [right_id]}] = expr + right = get_js right_id, ctx + {(op): jsop=op} = ops_to_js + js = unaryExpression jsop, right + set_js2 expr, js, ctx -map_with_ctx = fn fnc: - map_ac fn item, , ctx: - [value, next_ctx] = fnc item, ctx - [value, , next_ctx] -# TODO: std-lib -drop_if = fn cond: filter fn item, , ctx: - not cond item, ctx +transform_binary_or_unary = fn expr, ctx: + match expr: + [{args: [, ?]}]: transform_binary expr, ctx + else: transform_unary expr, ctx -collect_with_ctx = fn ctx: fn items: - items | fold_ac [], ctx, fn item, items, , curr_ctx: - [[...items, item], , curr_ctx] +transform = fn expr, ctx: + transform_expr = get_transformer expr, ctx + # match transform_expr: + # ?: + # transform_expr expr, ctx + # else: + # [, , , fnk_expr] = expr + # throw_err transform_error 'Unknown expression.', fnk_expr, ctx + transform_expr expr, ctx -transform_with_comments = fn transform_expr, node, ctx: - [err, result] = try_catch fn: - transform_expr node, ctx +transform_body_expr = fn expr, ctx: + [{f: op}, [res_id]] = expr + next_ctx = transform expr, ctx + res_val = get_value res_id, next_ctx - match err: - false: - [js_node, next_ctx] = result - js = wrap_node next_ctx, js_node, node - [js, next_ctx] - {transform_error: {}}: - throw_err err - else: - throw_err transform_error err, node, ctx + match [op, res_val]: + [, {inline: false, refs: ? > 0}]: + id = ident res_id + js = with_loc res_id, variableDeclaration 'const', list: + with_loc res_id, variableDeclarator id, res_val.js + [[js], next_ctx] + [, {inline: ? != true, refs: ? > 1}]: + val = get_js_literal res_id, next_ctx + js = match val: + {type: 'VariableDeclaration'}: + # TODO: use loc from res_id, val or expr? + with_loc res_id, val + else: + # TODO: use loc from res_id, val or expr? + # id = with_loc {loc: todo}, ident res_id + id = ident res_id + with_loc res_id, variableDeclaration 'const', list: + with_loc res_id, variableDeclarator id, val -transform = fn node, ctx: - transform_expr = get_transformer node, ctx + [[js], next_ctx] + + # unused calls assumed to have side effects + ['af', {refs: ? == 0}]: + val = get_js_literal res_id, next_ctx + js = with_loc res_id, expressionStatement val + [[js], next_ctx] - match transform_expr: - false: - throw_err transform_error 'Unknown expression.', node, ctx else: - transform_with_comments transform_expr, node, ctx + [[], next_ctx] + + + +transform_exprs = fn [expr=false, ...exprs], ctx, body=[]: + match expr: + false: [body, ctx] + + [{f: ? in ['cf', 'cc', 'cif', 'ac', 'imp']}]: + [body_exprs, next_ctx] = transform expr, ctx + transform_exprs exprs, next_ctx, [...body, ...body_exprs] + + [{f: 'cn'}]: + next_ctx = transform expr, ctx + transform_exprs exprs, next_ctx, body + + [{f: 'mod'}]: + [body_exprs, next_ctx] = transform expr, ctx + transform_exprs exprs, next_ctx, [...body, ...body_exprs] + + [ , [?]]: + [body_exprs, next_ctx] = transform_body_expr expr, ctx + transform_exprs exprs, next_ctx, [...body, ...body_exprs] + + + + diff --git a/src/js/types.fnk b/src/js/types.fnk deleted file mode 100644 index 0ab2361..0000000 --- a/src/js/types.fnk +++ /dev/null @@ -1,74 +0,0 @@ -babe_types = import '@babel/types' -{ - variableDeclaration, variableDeclarator - nullLiteral, identifier, expressionStatement - binaryExpression, unaryExpression, assignmentExpression -} = babe_types - - - -{escape_ident} = import './identifier.fnk' - - - -add_loc = fn larix_node, js_node: - {...js_node, loc: larix_node.loc} - - - -typof = fn value: unaryExpression 'typeof', value - - -eq = fn left, right: binaryExpression '===', left, right - -undef = fn: identifier 'undefined' - - -not_nullish = fn value: - binaryExpression '!=', value, nullLiteral _ - - -not_undefiend = fn value: - binaryExpression '!==', value, undef _ - - - -ident = fn name, ctx: - identifier escape_ident name, ctx - - - -unique_ident = fn name, ctx: - {unique_id, ident_prefix} = ctx - js = ident '${ident_prefix}${name}_${unique_id}', ctx - [js, {...ctx, unique_id: unique_id + 1}] - - - -raw_str = fn value: - rec: - type: 'StringLiteral' - value - extra: rec: - raw: '"${value}"' - rawValue: value - - - -consts = fn left, init: - variableDeclaration - 'const' - [variableDeclarator left, init] - - - -lets = fn left, init: - variableDeclaration - 'let' - [variableDeclarator left, init] - - - -assign = fn left, right: - expressionStatement - assignmentExpression '=', left, right diff --git a/src/optimize/init.fnk b/src/optimize/init.fnk new file mode 100644 index 0000000..5a10087 --- /dev/null +++ b/src/optimize/init.fnk @@ -0,0 +1,55 @@ +{init_ctx} = import '../ir/context.fnk' +{optimize_unused} = import './unused.fnk' +{optimize_refs} = import './refs.fnk' +{optimize_tails} = import './tail-calls.fnk' +{optimize_names} = import './short-ids.fnk' + + + +maybe_opt_refs = fn ir, ctx: + match ctx: + {optimize.refs: true}: + [nir] = optimize_refs ir, ctx + [nir, init_ctx nir, ctx] + else: + [ir, ctx] + + + +maybe_opt_tails = fn ir, ctx: + match ctx: + {optimize.tails: true}: + [nir] = optimize_tails ir, ctx + [nir, init_ctx nir, ctx] + else: + [ir, ctx] + + + +maybe_opt_unused = fn ir, ctx: + match ctx: + {optimize.unused: true}: + [nir] = optimize_unused ir, ctx + [nir, init_ctx nir, ctx] + else: + [ir, ctx] + + + +maybe_opt_names = fn ir, ctx: + match ctx: + {optimize.names: true}: + optimize_names ir, ctx + else: + [ir, ctx] + + + +optimize = fn exprs, options: + pipe [exprs, init_ctx exprs, options]: + maybe_opt_refs ...? + maybe_opt_tails ...? + maybe_opt_unused ...? + maybe_opt_names ...? + + diff --git a/src/optimize/init.test.fnk b/src/optimize/init.test.fnk new file mode 100644 index 0000000..173dd8f --- /dev/null +++ b/src/optimize/init.test.fnk @@ -0,0 +1,99 @@ +{fink2lir} = import '../testing/generate.fnk' +{describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' + + + +describe 'optimize', fn: + it 'foo', fn: + expect + fink2lir ' + a = 1 + b = 2 + c = [a, b] + [d, e] = c + f = d + e + ', {optimize: {refs: true, tails: true, unused: true}} + to_match_snapshot + + + it 'optimizes values', fn: + expect + fink2lir ' + y = [1, 2] + x = 3 + [foo, [bar, ni], shrub] = [4, [x, 5], y] + [..., spam] = y + [...sp, spam] = [1, 2, 3] + [x] = sp + [...spl] = lala + log foo, bar, ni, shrub, spam, sp, x, spl + ', {optimize: {refs: true, tails: true, unused: true}} + to_match_snapshot + + + it 'optimizes functions', fn: + expect + fink2lir ' + ni = 123 + + spam = fn foo, bar: + [a, b] = [bar, foo] + a + b + ni + + spam foo, bar + ', {optimize: {refs: true, tails: true, unused: true}} + to_match_snapshot + + + it 'optimizes conts', fn: + expect + fink2lir ' + ni = 123 + + spam = fn foo, bar: + [spam, ham] = match foo: + bar: [1, ni] + else: [2, ni * 2] + + spam + ni + ham + + spam foo, bar + ', {optimize: {refs: true, tails: true, unused: true}} + to_match_snapshot + + + it 'optimizes ac ...>> res: cc ..., res', fn: + expect + fink2lir ' + gcd = fn x, y: + match y: + 0: x + else: gcd y, x % y + ', {optimize: {refs: true, tails: true, unused: true}} + to_match_snapshot + + + it 'optimizes using short names', fn: + expect + fink2lir ' + ham = 3 + + foobar = spam + ham + + shrurb = fn spam, ham: + spam + ham + + nanu = fn foo, bar: + foo + bar + ham + + ni = fn foo, bar, spam, ham, ni: + [foo, bar, spam, ham, ni] + + na = fn foo, bar, spam, ham, ni: + [foo, bar, spam, ham, ni] + + nu = fn foo, bar, spam, ham, ni: + [foo, bar, spam, ham, ni] + + ', {optimize: {refs: true, tails: true, unused: true, names: true}} + to_match_snapshot diff --git a/src/optimize/init.test.fnk.snap b/src/optimize/init.test.fnk.snap new file mode 100644 index 0000000..0ac37a3 --- /dev/null +++ b/src/optimize/init.test.fnk.snap @@ -0,0 +1,191 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`optimize foo 1`] = ` +" +rec_e fn exports_0: + int '1', fn a_0: + str 'a', fn key_0: + rec_s exports_0, key_0, a_0, fn exports_1: + int '2', fn b_0: + str 'b', fn key_1: + rec_s exports_1, key_1, b_0, fn exports_2: + tpl a_0, b_0, fn c_0: + str 'c', fn key_2: + rec_s exports_2, key_2, c_0, fn exports_3: + add a_0, b_0, fn f_0: + str 'f', fn key_3: + rec_s exports_3, key_3, f_0, fn exports_4: + tpl, fn drctvs_0: + mod exports_4, drctvs_0, fn mod_0:" +`; + +exports[`optimize optimizes ac ...>> res: cc ..., res 1`] = ` +" +rec_e fn exports_0: + z (fn args_0, ret_1, gcd_0_0: #fn + tpl_i args_0, 0, fn x_0: + tpl_i args_0, 1, fn y_0: + id (fn: #cn + rem x_0, y_0, fn arg_1: + tpl y_0, arg_1, fn cargs_2: + cf gcd_0_0, cargs_2 + ), fn else_0: + int '0', fn val_0: + eq y_0, val_0, fn cond_0: + id (fn: #cn + cc ret_1, x_0 + ), fn match_res_0: + cif cond_0, match_res_0, else_0 + ), fn gcd_0: + str 'gcd', fn key_0: + rec_s exports_0, key_0, gcd_0, fn exports_1: + tpl, fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; + +exports[`optimize optimizes conts 1`] = ` +" +rec_e fn exports_0: + int '123', fn ni_0: + str 'ni', fn key_0: + rec_s exports_0, key_0, ni_0, fn exports_1: + id (fn args_0, ret_1: #fn + tpl_i args_0, 0, fn foo_0: + tpl_i args_0, 1, fn bar_0: + id (fn ret_0: #cn + id (fn: #cn + int '2', fn item_1: + int '2', fn right_0: + mul ni_0, right_0, fn item_0: + tpl item_1, item_0, fn result_1: + cc ret_0, result_1 + ), fn else_0: + eq foo_0, bar_0, fn cond_0: + id (fn: #cn + int '1', fn item_3: + tpl item_3, ni_0, fn result_2: + cc ret_0, result_2 + ), fn match_res_0: + cif cond_0, match_res_0, else_0 + ), fn match_0: + ac match_0, fn dlst_0: + tpl_i dlst_0, 0, fn spam_1: + tpl_i dlst_0, 1, fn ham_0: + add spam_1, ni_0, fn left_1: + add left_1, ham_0, fn result_3: + cc ret_1, result_3 + ), fn spam_0: + str 'spam', fn key_1: + rec_s exports_1, key_1, spam_0, fn exports_2: + tpl foo, bar, fn cargs_2: + af spam_0, cargs_2, fn mex_0: + tpl, fn drctvs_0: + mod exports_2, drctvs_0, fn mod_0:" +`; + +exports[`optimize optimizes functions 1`] = ` +" +rec_e fn exports_0: + int '123', fn ni_0: + str 'ni', fn key_0: + rec_s exports_0, key_0, ni_0, fn exports_1: + id (fn args_0, ret_0: #fn + tpl_i args_0, 0, fn foo_0: + tpl_i args_0, 1, fn bar_0: + add bar_0, foo_0, fn left_0: + add left_0, ni_0, fn result_1: + cc ret_0, result_1 + ), fn spam_0: + str 'spam', fn key_1: + rec_s exports_1, key_1, spam_0, fn exports_2: + tpl foo, bar, fn cargs_2: + af spam_0, cargs_2, fn mex_0: + tpl, fn drctvs_0: + mod exports_2, drctvs_0, fn mod_0:" +`; + +exports[`optimize optimizes using short names 1`] = ` +" +rec_e fn a: + int '3', fn b: + str 'ham', fn c: + rec_s a, c, b, fn d: + add spam, b, fn e: + str 'foobar', fn f: + rec_s d, f, e, fn g: + id (fn h, i: #fn + tpl_i h, 0, fn j: + tpl_i h, 1, fn k: + add j, k, fn l: + cc i, l + ), fn m: + str 'shrurb', fn n: + rec_s g, n, m, fn o: + id (fn p, q: #fn + tpl_i p, 0, fn r: + tpl_i p, 1, fn s: + add r, s, fn t: + add t, b, fn u: + cc q, u + ), fn v: + str 'nanu', fn w: + rec_s o, w, v, fn x: + id (fn y, z: #fn + tpl_i y, 0, fn A: + tpl_i y, 1, fn B: + tpl_i y, 2, fn C: + tpl_i y, 3, fn D: + tpl_i y, 4, fn E: + tpl A, B, C, D, E, fn F: + cc z, F + ), fn G: + str 'ni', fn H: + rec_s x, H, G, fn I: + id (fn J, K: #fn + tpl_i J, 0, fn L: + tpl_i J, 1, fn M: + tpl_i J, 2, fn N: + tpl_i J, 3, fn O: + tpl_i J, 4, fn P: + tpl L, M, N, O, P, fn Q: + cc K, Q + ), fn R: + str 'na', fn S: + rec_s I, S, R, fn T: + id (fn U, V: #fn + tpl_i U, 0, fn W: + tpl_i U, 1, fn X: + tpl_i U, 2, fn Y: + tpl_i U, 3, fn Z: + tpl_i U, 4, fn aa: + tpl W, X, Y, Z, aa, fn ab: + cc V, ab + ), fn ac: + str 'nu', fn ad: + rec_s T, ad, ac, fn ae: + tpl, fn af: + mod ae, af, fn ag:" +`; + +exports[`optimize optimizes values 1`] = ` +" +rec_e fn exports_0: + int '1', fn item_1: + int '2', fn item_0: + tpl item_1, item_0, fn y_0: + str 'y', fn key_0: + rec_s exports_0, key_0, y_0, fn exports_1: + int '3', fn x_0: + str 'x', fn key_1: + rec_s exports_1, key_1, x_0, fn exports_2: + int '4', fn item_6: + int '5', fn item_4: + int '1', fn item_9: + int '2', fn item_8: + int '3', fn item_7: + tpl item_9, item_8, fn sp_0: + tpl item_6, x_0, item_4, y_0, item_7, sp_0, item_9, lala, fn cargs_8: + af log, cargs_8, fn mex_5: + tpl, fn drctvs_0: + mod exports_2, drctvs_0, fn mod_0:" +`; diff --git a/src/optimize/refs.fnk b/src/optimize/refs.fnk new file mode 100644 index 0000000..98210ca --- /dev/null +++ b/src/optimize/refs.fnk @@ -0,0 +1,290 @@ +{reverse} = import '@fink/std-lib/iter.fnk' + +{update_value, get_value} = import '../ir/context.fnk' + + + +replace_arg_alias = fn arg, ctx: + {alias: new_arg=arg} = get_value arg, ctx + match new_arg: + arg: arg + else: replace_arg_alias new_arg, ctx + + + +replace_args_aliases = fn [arg=false, ...args], ctx, out=[]: + match arg: + false: + out + else: + renamed_arg = replace_arg_alias arg, ctx + # TODO: carry loc over? + replace_args_aliases args, ctx, [...out, {...renamed_arg, loc: arg.loc}] + + + +optimize_args = fn expr, ctx: + {args} = expr + o_args = replace_args_aliases args, ctx + {...expr, args: o_args} + + + +add_alias = fn id, target, ctx: + # TODO: loc? + # update_value id, {alias: {...id, i: target.i}}, ctx + update_value id, {alias: target}, ctx + + + +optimize_lst = fn [expr, res], ctx: + [res_id] = res + opt_expr = {...expr, f: 'tpl', args: []} + next_ctx = update_value res_id, {type: 'tpl', items: []}, ctx + [[opt_expr, res], next_ctx] + + + +optimize_lst_a = fn [expr, res], ctx: + [res_id] = res + opt_expr = optimize_args expr, ctx + {args: [lst_id, val_id]} = opt_expr + info = get_value lst_id, ctx + + match info: + {type: 'tpl', items: ?}: + {items} = get_value lst_id, ctx + + next_ctx = update_value res_id, {type: 'tpl', items: [...items, val_id]}, ctx + expr = {...opt_expr, f: 'tpl', args: [...items, val_id]} + [[[expr, res]], next_ctx] + + else: + next_ctx = update_value res_id, {type: 'lst'}, ctx + [[[opt_expr, res]], next_ctx] + + + +optimize_lst_h = fn [expr, res], ctx: + [res_id] = res + opt_expr = optimize_args expr, ctx + {args: [lst_id]} = opt_expr + info = get_value lst_id, ctx + match info: + {type: 'tpl', items: [?]}: + {items: [val_id]} = info + next_ctx = add_alias res_id, val_id, ctx + [[], next_ctx] + + {type: 'tpl', slice_of: ?}: + [lst_id, start, end, inc] = info.slice_of + idx = match inc: + 1: start + else: end - 1 + [[[{...opt_expr, f: 'tpl_i', args: [lst_id, idx]}, res]], ctx] + + {type: 'tpl'}: + [[[{...opt_expr, f: 'tpl_i', args: [lst_id, 0]}, res]], ctx] + + else: + [[[{...opt_expr, f: 'tpl_i', args: [lst_id, 0]}, res]], ctx] + + + +optimize_lst_t = fn [expr, res], ctx: + [res_id] = res + opt_expr = optimize_args expr, ctx + {args: [lst_id]} = opt_expr + + info = get_value lst_id, ctx + match info: + {type: 'tpl', items: [?]}: + {items: [, ...items]} = info + foo = {...opt_expr, f: 'tpl', args: items} + next_ctx = update_value res_id, {type: 'tpl', items}, ctx + [[[foo, res]], next_ctx] + + {type: 'tpl', items: ?}: + next_ctx = add_alias res_id, lst_id, ctx + [[], next_ctx] + + {type: 'tpl', slice_of: ?}: + [lst_id, start, end, inc] = info.slice_of + args = match inc: + 1: [lst_id, start + 1, end] + else: [lst_id, start, end - 1] + + next_ctx = update_value res_id, {type: 'tpl', slice_of: [...args, inc]}, ctx + foo = {...opt_expr, f: 'tpl_s', args} + [[[foo, res]], next_ctx] + + {type: 'tpl'}: + next_ctx = update_value res_id, {type: 'tpl', slice_of: [lst_id, 1, 0, 1]}, ctx + foo = {...opt_expr, f: 'tpl_s', args: [lst_id, 1, 0]} + [[[foo, res]], next_ctx] + + else: + next_ctx = update_value res_id, {type: 'tpl', slice_of: [lst_id, 1, 0, 1]}, ctx + foo = {...opt_expr, f: 'tpl_s', args: [lst_id, 1, 0]} + [[[foo, res]], next_ctx] + + + +optimize_lst_c = fn [expr, res], ctx: + [res_id] = res + opt_expr = optimize_args expr, ctx + {args: [lst1_id, lst2_id]} = opt_expr + info1 = get_value lst1_id, ctx + info2 = get_value lst2_id, ctx + + match [info1, info2]: + [{type: 'tpl', items: ?}, {type: 'tpl', items: ?}]: + {items: [...items1]} = info1 + {items: [...items2]} = info2 + items = [...items1, ...items2] + next_ctx = update_value res_id, {type: 'tpl', items}, ctx + foo = {...opt_expr, f: 'tpl', args: items} + [[[foo, res]], next_ctx] + + else: + next_ctx = update_value res_id, {type: 'tpl'}, ctx + [[[opt_expr, res]], next_ctx] + + + +optimize_lst_r = fn [expr, res], ctx: + [res_id] = res + opt_expr = optimize_args expr, ctx + {args: [lst_id]} = opt_expr + info = get_value lst_id, ctx + + match info: + {tpr: ?}: + {tpr} = info + next_ctx = add_alias res_id, tpr, ctx + [[], next_ctx] + + {type: 'tpl', items: ?}: + # find existing tpl instead of creating + items = reverse info.items + next_ctx = update_value res_id, {type: 'tpl', items, tpr: lst_id}, ctx + foo = {...opt_expr, f: 'tpl', args: items} + [[[foo, res]], next_ctx] + + {type: 'tpl', slice_of: ?}: + [tpl_id, start_idx, end_idx, inc] = info.slice_of + + slice_of = match inc: + 1: [tpl_id, start_idx, end_idx, -inc] + else: [tpl_id, start_idx, end_idx, -inc] + + next_ctx = update_value res_id, {type: 'tpl', slice_of, tpr: lst_id}, ctx + + match inc: + 1: + [[[opt_expr, res]], next_ctx] + else: + foo = {...opt_expr, f: 'tpl_s', args: [tpl_id, start_idx, end_idx]} + [[[foo, res]], next_ctx] + + else: + slice_of = [lst_id, 0, 0, -1] + next_ctx = update_value res_id, {type: 'tpl', slice_of, tpr: lst_id}, ctx + [[[opt_expr, res]], next_ctx] + + + +optimize_body = fn [expr, res], ctx, optimize_refs: + {args: [args, body]} = expr + + body_ctx = match expr: + {f: 'fn'}: + [args_id] = args + update_value args_id, {type: 'tpl'}, ctx + else: + ctx + + [o_body, next_ctx] = optimize_refs body, body_ctx, [] + [[[{...expr, args: [args, o_body]}, res]], next_ctx] + + + +optimize_cn = fn [expr, res], exprs, ctx, optimize_refs, out: + [cont_id] = res + [[ret_id], body] = expr.args + + [ + [{f: ac_op, args: [ac_id]}, [res_id]] + [{f: cc_op, args: [cc_ret_id, ret_arg]}]=[{args: []}] + ] = exprs + + match [ac_op, ac_id, cc_op, res_id]: + ['ac', cont_id, 'cc', ret_arg]: + b_ctx = add_alias ret_id, cc_ret_id, ctx + [o_body, next_ctx] = optimize_refs body, b_ctx, [] + [, , ...oexprs] = exprs + optimize_refs oexprs, next_ctx, [...out, ...o_body] + + else: + [of_cn, next_ctx] = optimize_body [expr, res], ctx, optimize_refs + optimize_refs exprs, next_ctx, [...out, ...of_cn] + + + +optimize_refs = fn [expr=false, ...exprs], ctx, out=[]: + + match expr: + false: + [out, ctx] + + [{f:'lst'}]: + [opt, next_ctx] = optimize_lst expr, ctx + optimize_refs exprs, next_ctx, [...out, opt] + + [{f: 'lst_a'}]: + [opt, next_ctx] = optimize_lst_a expr, ctx + optimize_refs exprs, next_ctx, [...out, ...opt] + + [{f:'lst_h'}]: + [opt, next_ctx] = optimize_lst_h expr, ctx + optimize_refs exprs, next_ctx, [...out, ...opt] + + [{f: 'lst_t'}]: + [opt, next_ctx] = optimize_lst_t expr, ctx + optimize_refs exprs, next_ctx, [...out, ...opt] + + [{f: 'lst_c'}]: + [opt, next_ctx] = optimize_lst_c expr, ctx + optimize_refs exprs, next_ctx, [...out, ...opt] + + [{f: 'lst_r'}]: + [opt, next_ctx] = optimize_lst_r expr, ctx + optimize_refs exprs, next_ctx, [...out, ...opt] + + [{f: '='}]: + [{args: [target]}, [res_id]] = expr + next_ctx = add_alias res_id, target, ctx + optimize_refs exprs, next_ctx, out + + [{f: ? in ['int', 'float', 'str']}]: + optimize_refs exprs, ctx, [...out, expr] + + [{f: 'cn'}]: + orf = optimize_refs + optimize_cn expr, exprs, ctx, orf, out + + [{f: 'fn'}]: + orf = optimize_refs + [opt, next_ctx] = optimize_body expr, ctx, orf + optimize_refs exprs, next_ctx , [...out, ...opt] + + [{f: '+'}]: + [foo, res] = expr + o_expr = optimize_args foo, ctx + optimize_refs exprs, ctx, [...out, [o_expr, res]] + + else: + [foo, res] = expr + o_expr = optimize_args foo, ctx + optimize_refs exprs, ctx, [...out, [o_expr, res]] + diff --git a/src/optimize/short-ids.fnk b/src/optimize/short-ids.fnk new file mode 100644 index 0000000..28f5218 --- /dev/null +++ b/src/optimize/short-ids.fnk @@ -0,0 +1,81 @@ +{length} = import '@fink/std-lib/iter.fnk' +{floor} = import '@fink/std-lib/math.fnk' + + +alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' +base = length alphabet + + +to_id = fn idx, out='': + div = floor idx / base + rem = idx % base + match div: + 0: + '${alphabet.(rem)}${out}' + else: + to_id div - 1, '${alphabet.(rem)}${out}' + + + +get_new_id = fn id, renames: + {id_cntr=0} = renames + new_id = to_id id_cntr + nrs = {...renames, id_cntr: id_cntr + 1, (id.i): new_id} + [{...id, i: new_id}, nrs] + + + +replace_refs = fn [id=false, ...ids], renames, out=[]: + match id: + false: out + else: + {(id.i): new_id=id.i} = renames + replace_refs ids, renames, [...out, {...id, i: new_id}] + + + +rename = fn [id=false, ...ids], renames, out=[]: + match id: + false: [out, renames] + else: + [new_id, next_renames] = get_new_id id, renames + rename ids, next_renames, [...out, new_id] + + + +shorten_names = fn [curr=false, ...rest], renames={}, out=[]: + match curr: + false: [out, renames] + + [{f: ? in ['int', 'float', 'str']}]: + [expr, res] = curr + [nres, next_ren] = rename res, renames + shorten_names rest, next_ren, [...out, [expr, nres]] + + [{f: ? in ['tpl_i', 'tpl_s']}]: + [expr, res] = curr + {args: [tpl_id, ...args]} = expr + [ntpl_id] = replace_refs [tpl_id], renames + [nres, next_ren] = rename res, renames + shorten_names rest, next_ren, [...out, [{...expr, args: [ntpl_id, ...args]}, nres]] + + [{f: ? in ['fn', 'cn']}]: + [expr, res] = curr + [args, body] = expr.args + [nargs, bod_ren] = rename args, renames + [nbody, res_ren] = shorten_names body, bod_ren + [nres, next_ren] = rename res, res_ren + shorten_names rest, next_ren, [...out, [{...expr, args: [nargs, nbody]}, nres]] + + else: + [expr, res] = curr + nargs = replace_refs expr.args, renames + [nres, next_ren] = rename res, renames + shorten_names rest, next_ren, [...out, [{...expr, args: nargs}, nres]] + + + +optimize_names = fn exprs, ctx: + [ir] = shorten_names exprs + [ir, ctx] + diff --git a/src/optimize/tail-calls.fnk b/src/optimize/tail-calls.fnk new file mode 100644 index 0000000..da39da2 --- /dev/null +++ b/src/optimize/tail-calls.fnk @@ -0,0 +1,74 @@ +{get_value, update_value} = import '../ir/context.fnk' + + +set_curr_fn = fn curr_fn, ctx: + {...ctx, curr_fn} + + +get_curr_fn = fn ctx: + {curr_fn=[]} = ctx + curr_fn + + + +optimize_body = fn [expr, res], ctx, optimize_tails: + {args: [args, body]} = expr + [o_body, next_ctx] = optimize_tails body, ctx, [] + [[[{...expr, args: [args, o_body]}, res]], next_ctx] + + + +optimize_fn = fn [expr, res], ctx, optimize_tails: + {args: [args, body]} = expr + [ , ret_id, fn_id] = args + prev_curr_fn = get_curr_fn ctx + body_ctx = set_curr_fn [fn_id, ret_id], ctx + + [o_body, next_ctx] = optimize_tails body, body_ctx, [] + + opt = match get_value fn_id, next_ctx: + {tco: true}: + {...expr, f: 'fn', args: [args, o_body], tco: true} + else: + {...expr, args: [args, o_body]} + + end_ctx = set_curr_fn prev_curr_fn, next_ctx + [[[opt, res]], end_ctx] + + + +optimize_af = fn [expr, res], exprs, ctx: + {args: [callee_id, ...args]} = expr + [next_expr, ...rest_exprs] = exprs + [curr_fn_id={}, ret_id] = get_curr_fn ctx + + match [callee_id.i, next_expr]: + [curr_fn_id.i, [{f: 'cc', args: [{i: ret_id.i}]}]]: + opt_expr = {...expr, f: 'cf', args: [callee_id, ...args]} + next_ctx = update_value curr_fn_id, {tco: true}, ctx + [[[opt_expr, []]], rest_exprs, next_ctx] + + else: + [[[expr, res]], exprs, ctx] + + + +optimize_tails = fn [expr=false, ...exprs], ctx, out=[]: + match expr: + false: + [out, ctx] + + [{f: 'fn', args: [[?, ?, ?]]}]: + [opt, next_ctx] = optimize_fn expr, ctx, optimize_tails + optimize_tails exprs, next_ctx, [...out, ...opt] + + [{f: ? in ['cn', 'fn']}]: + [opt, next_ctx] = optimize_body expr, ctx, optimize_tails + optimize_tails exprs, next_ctx, [...out, ...opt] + + [{f: 'af'}]: + [opt, rest_exprs, next_ctx] = optimize_af expr, exprs, ctx + optimize_tails rest_exprs, next_ctx, [...out, ...opt] + + else: + optimize_tails exprs, ctx, [...out, expr] diff --git a/src/optimize/unused.fnk b/src/optimize/unused.fnk new file mode 100644 index 0000000..424934a --- /dev/null +++ b/src/optimize/unused.fnk @@ -0,0 +1,47 @@ +{reverse} = import '@fink/std-lib/iter.fnk' + +{is_unused, dec_refs} = import '../ir/context.fnk' + + + + +get_ref_args = fn [{f: op, args}]: + match op: + ? in ['int', 'float', 'str']: [] + ? in ['tpl_i', 'tpl_s']: + [tpl_id] = args + [tpl_id] + else: args + + + + +remove_unused = fn [expr=false, ...exprs], ctx, out: + match expr: + false: + [out, ctx] + + [{f: ? in ['mod', 'imp', 'af', 'ac', 'cc', 'cif', 'cf']}]: + remove_unused exprs, ctx, [expr, ...out] + + [, [is_unused ?, ctx]]: + args = get_ref_args expr + next_ctx = dec_refs args, ctx + remove_unused exprs, next_ctx, out + + [{f: ? in ['fn', 'cn']}]: + [{f: op, args: [args, body], ...rest}, res] = expr + rbody = reverse body + [obody, next_ctx] = remove_unused rbody, ctx, [] + oexpr = {f: op, args: [args, obody], ...rest} + remove_unused exprs, next_ctx, [[oexpr, res], ...out] + + else: + remove_unused exprs, ctx, [expr, ...out] + + + +optimize_unused = fn exprs, ctx: + rexprs = reverse exprs + remove_unused rexprs, ctx, [] + diff --git a/src/testing/generate.fnk b/src/testing/generate.fnk index d76ae0e..e797808 100644 --- a/src/testing/generate.fnk +++ b/src/testing/generate.fnk @@ -1,9 +1,24 @@ -{parse} = import '@fink/larix/parser.fnk' {is_empty} = import '@fink/std-lib/iter.fnk' +{obj_to_json} = import '@fink/std-lib/json.fnk' + +{parse} = import '@fink/larix/parser.fnk' {generate} = import '../generate.fnk' +{init_ctx} = import '../ir/init.fnk' +{serialize} = import '../ir/serialize.fnk' +{transform} = import '../ir/transform.fnk' +{optimize} = import '../optimize/init.fnk' + +fink2lir = fn source, options: + filename = 'test.fnk' + ast = parse source, filename + ctx = init_ctx source, filename, options + [exprs] = transform ast, 'mod', ctx + [out] = optimize exprs, options + serialize out + fink2js = fn source, options: filename = 'test.fnk' @@ -20,3 +35,19 @@ fink2js = fn source, options: else: {errors: ast.errors} + + +pretty_source_map = fn {sourcesContent: _, ...source_map}: + obj_to_json source_map, , 2 + + + +fink2js_sm = fn source: + filename = 'test.fnk' + ast = parse source, filename + options = {module_type: 'mjs', source_maps: true} + {code, source_map} = generate ast, filename, source, options + + '${code} + ${pretty_source_map source_map} + '