├── .babelrc ├── .eslintrc.js ├── .github └── workflows │ └── check.yml ├── .gitignore ├── LICENSE ├── README.md ├── examples ├── .eslintrc.js ├── README.md ├── adapt.js ├── contains-this.js ├── identifier-counter.js └── increment.js ├── gen ├── .eslintrc.js ├── adapt.js ├── clone-reducer.js ├── director.js ├── lazy-clone-reducer.js ├── memoize.js ├── monoidal-reducer.js ├── thunked-director.js ├── thunked-monoidal-reducer.js ├── thunkify-class.js └── thunkify.js ├── package-lock.json ├── package.json ├── scripts ├── build │ ├── generate-adapt.js │ ├── generate-clone-reducer.js │ ├── generate-director.js │ ├── generate-lazy-clone-reducer.js │ ├── generate-memoize.js │ ├── generate-monoidal-reducer.js │ └── generate-thunkify.js └── lib │ └── utilities.js ├── src ├── index.js └── reducers.js └── test ├── .eslintrc.js ├── adapt.js ├── clone-reducer.js ├── lazy-clone-reducer.js ├── monoidal-reducer.js ├── thunk.js └── unit.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015"], 3 | "sourceMaps": "true" 4 | } 5 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: 'eslint:recommended', 3 | env: { 4 | es6: true, 5 | node: true, 6 | browser: false, 7 | }, 8 | parserOptions: { 9 | ecmaVersion: 6, 10 | sourceType: 'module', 11 | }, 12 | plugins: [], 13 | rules: { 14 | 'arrow-parens': ['error', 'as-needed'], 15 | 'array-bracket-spacing': ['error', 'never'], 16 | 'brace-style': ['error', '1tbs'], 17 | 'camelcase': 'error', 18 | 'comma-dangle': ['error', 'always-multiline'], 19 | 'comma-spacing': ['error', { before: false, after: true }], 20 | 'comma-style': ['error', 'last'], 21 | 'computed-property-spacing': ['error', 'never'], 22 | 'consistent-return': 'error', 23 | 'consistent-this': ['error', 'self'], 24 | 'curly': ['error', 'multi-line'], 25 | 'dot-notation': 'error', 26 | 'eol-last': 'error', 27 | 'eqeqeq': ['error', 'smart'], 28 | 'guard-for-in': 'error', 29 | 'indent': ['error', 2, { SwitchCase: 1, VariableDeclarator: { var: 2, let: 2, const: 3 } }], 30 | 'key-spacing': ['error', { beforeColon: false, afterColon: true }], 31 | 'keyword-spacing': 'error', 32 | 'max-len': ['warn', 120], 33 | 'no-alert': 'error', 34 | 'no-caller': 'error', 35 | 'no-catch-shadow': 'error', 36 | 'no-console': 'warn', 37 | 'no-else-return': 'error', 38 | 'no-empty': ['error', { allowEmptyCatch: true }], 39 | 'no-eval': 'error', 40 | 'no-extend-native': 'error', 41 | 'no-extra-bind': 'error', 42 | 'no-extra-parens': 'warn', 43 | 'no-fallthrough': 'error', 44 | 'no-floating-decimal': 'error', 45 | 'no-implied-eval': 'error', 46 | 'no-inner-declarations': ['error', 'both'], 47 | 'no-lonely-if': 'error', 48 | 'no-loop-func': 'error', 49 | 'no-mixed-spaces-and-tabs': 'error', 50 | 'no-multi-spaces': 'error', 51 | 'no-multiple-empty-lines': ['error', { max: 2 }], 52 | 'no-negated-condition': 'error', 53 | 'no-param-reassign': 'warn', 54 | 'no-redeclare': 'error', 55 | 'no-return-assign': 'error', 56 | 'no-self-compare': 'error', 57 | 'no-sequences': 'error', 58 | 'no-shadow': ['error', { builtinGlobals: true }], 59 | 'no-shadow-restricted-names': 'error', 60 | 'no-spaced-func': 'error', 61 | 'no-trailing-spaces': 'error', 62 | 'no-undef': 'error', 63 | 'no-undefined': 'error', 64 | 'no-underscore-dangle': 'off', 65 | 'no-unused-vars': ['error', { vars: 'all', args: 'after-used' }], 66 | 'no-use-before-define': ['error', 'nofunc'], 67 | 'no-useless-call': 'error', 68 | 'no-useless-escape': 'error', 69 | 'no-var': 'error', 70 | 'no-warning-comments': 'off', 71 | 'no-with': 'error', 72 | 'object-curly-spacing': ['error', 'always'], 73 | 'object-shorthand': ['error', 'always'], 74 | 'prefer-arrow-callback': ['error'], 75 | 'quotes': ['error', 'single'], 76 | 'semi': ['error', 'always'], 77 | 'semi-spacing': ['error', { before: false, after: true }], 78 | 'space-before-blocks': 'error', 79 | 'space-before-function-paren': ['error', { anonymous: 'always', named: 'never' }], 80 | 'space-in-parens': 'error', 81 | 'space-infix-ops': 'error', 82 | 'space-unary-ops': 'error', 83 | 'spaced-comment': ['warn', 'always', { block: { markers: ['!'], exceptions: ['*'] } }], 84 | 'strict': 'off', 85 | 'valid-jsdoc': 'warn', 86 | 'wrap-iife': ['error', 'outside'], 87 | 'yoda': ['error', 'never'], 88 | }, 89 | }; 90 | -------------------------------------------------------------------------------- /.github/workflows/check.yml: -------------------------------------------------------------------------------- 1 | name: check 2 | 3 | on: 4 | push: 5 | branches: 6 | - es2019 7 | pull_request: 8 | 9 | jobs: 10 | pre: 11 | name: Prerequisites 12 | if: github.event_name == 'pull_request' 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - name: Checkout 17 | uses: actions/checkout@v2 18 | with: 19 | fetch-depth: 0 20 | 21 | - name: Enforce CLA signature 22 | env: 23 | COMMIT_RANGE: ${{ github.event.pull_request.base.sha }}...${{ github.event.pull_request.head.sha }} 24 | run: curl https://raw.githubusercontent.com/shapesecurity/CLA/HEAD/cla-check.sh | bash 25 | 26 | check: 27 | needs: pre 28 | if: | 29 | !cancelled() && !failure() 30 | runs-on: ubuntu-latest 31 | 32 | strategy: 33 | matrix: 34 | node: [14, 16, 18] 35 | 36 | name: Check - node ${{ matrix.node }} 37 | 38 | steps: 39 | - name: Checkout 40 | uses: actions/checkout@v2 41 | 42 | - name: Setup node 43 | uses: actions/setup-node@v2 44 | with: 45 | node-version: ${{ matrix.node }} 46 | 47 | - name: Install dependencies 48 | run: npm ci 49 | 50 | - name: Build 51 | run: npm run build 52 | 53 | - name: Lint 54 | run: npm run lint -- --quiet 55 | 56 | - name: Test 57 | run: npm test 58 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | dist 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Shift Reducer 2 | ============= 3 | 4 | 5 | ## About 6 | 7 | This module provides several reducers and related tooling for [Shift format](https://github.com/shapesecurity/shift-spec) ASTs. 8 | 9 | 10 | ## Status 11 | 12 | [Stable](http://nodejs.org/api/documentation.html#documentation_stability_index). 13 | 14 | 15 | ## Installation 16 | 17 | ```sh 18 | npm install shift-reducer 19 | ``` 20 | 21 | 22 | ## Usage 23 | 24 | See [examples](./examples). 25 | 26 | 27 | ### Fantasy Land 28 | 29 | ![Fantasy Land logo](https://github.com/fantasyland/fantasy-land/raw/master/logo.png "Fantasy Land") 30 | 31 | `MonoidalReducer` is compatible with [Fantasy Land](https://github.com/fantasyland/fantasy-land) Monoids. 32 | 33 | 34 | ## Contributing 35 | 36 | * Open a Github issue with a description of your desired change. If one exists already, leave a message stating that you are working on it with the date you expect it to be complete. 37 | * Fork this repo, and clone the forked repo. 38 | * Install dependencies with `npm install`. 39 | * Build and test in your environment with `npm run build && npm test`. 40 | * Create a feature branch. Make your changes. Add tests. 41 | * Build and test in your environment with `npm run build && npm test`. 42 | * Make a commit that includes the text "fixes #*XX*" where *XX* is the Github issue. 43 | * Open a Pull Request on Github. 44 | 45 | 46 | ## License 47 | 48 | Copyright 2014 Shape Security, Inc. 49 | 50 | Licensed under the Apache License, Version 2.0 (the "License"); 51 | you may not use this file except in compliance with the License. 52 | You may obtain a copy of the License at 53 | 54 | http://www.apache.org/licenses/LICENSE-2.0 55 | 56 | Unless required by applicable law or agreed to in writing, software 57 | distributed under the License is distributed on an "AS IS" BASIS, 58 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 59 | See the License for the specific language governing permissions and 60 | limitations under the License. 61 | -------------------------------------------------------------------------------- /examples/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: '../.eslintrc.js', 3 | rules: { 4 | 'no-unused-vars': 'off', 5 | 'no-console': 'off', 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | Usage Examples 2 | ============== 3 | 4 | * [adapt.js](./adapt.js): three uses of the `adapt` helper: count the nodes in a tree, list the nodes in a tree, give a map from nodes to their parent 5 | * [contains-this.js](./contains-this.js): check if a function refers to `this` 6 | * [identifier-counter.js](./identifier-counter.js): count the number of identifiers in a program 7 | * [increment.js](./increment.js): create a copy of the AST with all numbers incremented, doing as little work as possible 8 | * [shapesecurity/shift-scope-js](https://github.com/shapesecurity/shift-scope-js): derive a program's scope tree 9 | * [shapesecurity/shift-validator-js](https://github.com/shapesecurity/shift-validator-js): validate a Shift format AST 10 | * [shapesecurity/shift-codegen-js](https://github.com/shapesecurity/shift-codegen-js): generate an ECMAScript program 11 | -------------------------------------------------------------------------------- /examples/adapt.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | let { reduce, adapt, ConcatReducer, PlusReducer, MonoidalReducer } = require('..'); 4 | 5 | 6 | function countNodes(tree) { 7 | let reducer = adapt(data => data + 1, new PlusReducer); 8 | return reduce(reducer, tree); 9 | } 10 | 11 | function flatten(tree) { 12 | let reducer = adapt((data, node) => [node].concat(data), new ConcatReducer); 13 | return reduce(reducer, tree); 14 | } 15 | 16 | function findParents(tree) { 17 | let monoid = { 18 | empty: () => ({ 19 | pairs: [], 20 | children: [], 21 | }), 22 | concat: (a, b) => ({ 23 | pairs: a.pairs.concat(b.pairs), 24 | children: a.children.concat(b.children), 25 | }), 26 | }; 27 | let reducer = adapt( 28 | ({ pairs, children }, node) => ({ 29 | pairs: pairs.concat(children.map(child => [child, node])), 30 | children: [node], 31 | }), 32 | new MonoidalReducer(monoid) 33 | ); 34 | let pairs = reduce(reducer, tree).pairs; 35 | return new Map(pairs); 36 | } 37 | 38 | 39 | let sample = require('shift-parser').parseScript('0 + 1'); 40 | 41 | console.log('Count:'); 42 | console.log(countNodes(sample)); 43 | 44 | console.log('Flattened:'); 45 | console.log(flatten(sample)); 46 | 47 | console.log('Parents:'); 48 | console.log(findParents(sample)); 49 | -------------------------------------------------------------------------------- /examples/contains-this.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { parseScript } = require('shift-parser'); 4 | const { thunkedReduce, ThunkedMonoidalReducer } = require('..'); 5 | 6 | class ContainsThisReducer extends ThunkedMonoidalReducer { 7 | static containsThis(fn) { 8 | if (fn.type !== 'FunctionExpression' && fn.type !== 'FunctionDeclaration') { 9 | throw new TypeError('ContainsThisReducer must be passed a function node'); 10 | } 11 | return thunkedReduce(new this, fn.params) || thunkedReduce(new this, fn.body); 12 | } 13 | 14 | constructor() { 15 | super({ 16 | empty: () => false, 17 | concatThunk: (a, b) => a || b(), 18 | }); 19 | 20 | /* Equivalently: 21 | super({ 22 | empty: () => false, 23 | isAbsorbing: a => a, 24 | concat: (a, b) => a || b, 25 | }); 26 | */ 27 | } 28 | 29 | reduceThisExpression(node) { 30 | return true; 31 | } 32 | 33 | reduceFunctionDeclaration() { 34 | return false; 35 | } 36 | 37 | reduceFunctionExpression() { 38 | return false; 39 | } 40 | 41 | reduceGetter(node, { name, body }) { 42 | return name(); 43 | } 44 | 45 | reduceSetter({ name, param, body }) { 46 | return name(); 47 | } 48 | 49 | reduceMethod(node, { name, params, body }) { 50 | return name(); 51 | } 52 | } 53 | 54 | let functionWithoutThis = parseScript(` 55 | function f() { 56 | return function inner() { 57 | return this; 58 | } 59 | } 60 | `).statements[0]; 61 | console.log(ContainsThisReducer.containsThis(functionWithoutThis)); 62 | 63 | let functionWithThis = parseScript(` 64 | function f() { 65 | return () => this; 66 | } 67 | `).statements[0]; 68 | console.log(ContainsThisReducer.containsThis(functionWithThis)); 69 | -------------------------------------------------------------------------------- /examples/identifier-counter.js: -------------------------------------------------------------------------------- 1 | const { parseScript } = require('shift-parser'); 2 | const { reduce, MonoidalReducer } = require('..'); 3 | 4 | class IdentifierCounter extends MonoidalReducer { 5 | static count(program) { 6 | return reduce(new this, program); 7 | } 8 | 9 | constructor() { 10 | // The constructor can be omitted entirely by extending PlusReducer instead of MonoidalReducer 11 | class Sum { 12 | static empty() { 13 | return 0; 14 | } 15 | concat(a) { 16 | return this + a; 17 | } 18 | } 19 | super(Sum); 20 | } 21 | 22 | reduceIdentifierExpression(node) { 23 | return 1; 24 | } 25 | } 26 | 27 | let program = 'function f() { hello(world); }'; 28 | console.dir(IdentifierCounter.count(parseScript(program))); 29 | -------------------------------------------------------------------------------- /examples/increment.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { parseScript } = require('shift-parser'); 4 | const { thunkedReduce, LazyCloneReducer, thunkify, memoize } = require('..'); 5 | 6 | class IncrementingReducer extends LazyCloneReducer { 7 | reduceLiteralNumericExpression(node) { 8 | return { 9 | type: 'LiteralNumericExpression', 10 | value: node.value + 1, 11 | }; 12 | } 13 | } 14 | let increment = memoize(thunkify(new IncrementingReducer)); 15 | 16 | let sample = parseScript('1 + 2; x;'); 17 | let updated = thunkedReduce(increment, sample); 18 | console.dir(updated, { depth: null }); 19 | 20 | console.log(sample.statements[1] === updated.statements[1]); // true 21 | 22 | let updatedAgain = thunkedReduce(increment, sample); 23 | console.log(updated === updatedAgain); // true 24 | -------------------------------------------------------------------------------- /gen/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: '../.eslintrc.js', 3 | rules: { 4 | 'no-unused-vars': 'off', 5 | 'max-len': 'off', 6 | 'no-extra-parens': 'off', 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /gen/adapt.js: -------------------------------------------------------------------------------- 1 | // Generated by generate-adapt.js 2 | /** 3 | * Copyright 2018 Shape Security, Inc. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License") 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | const Shift = require('shift-ast'); 19 | 20 | module.exports = (fn, reducer) => ({ 21 | __proto__: reducer, 22 | 23 | reduceArrayAssignmentTarget(node, data) { 24 | return fn(super.reduceArrayAssignmentTarget(node, data), node); 25 | }, 26 | 27 | reduceArrayBinding(node, data) { 28 | return fn(super.reduceArrayBinding(node, data), node); 29 | }, 30 | 31 | reduceArrayExpression(node, data) { 32 | return fn(super.reduceArrayExpression(node, data), node); 33 | }, 34 | 35 | reduceArrowExpression(node, data) { 36 | return fn(super.reduceArrowExpression(node, data), node); 37 | }, 38 | 39 | reduceAssignmentExpression(node, data) { 40 | return fn(super.reduceAssignmentExpression(node, data), node); 41 | }, 42 | 43 | reduceAssignmentTargetIdentifier(node, data) { 44 | return fn(super.reduceAssignmentTargetIdentifier(node, data), node); 45 | }, 46 | 47 | reduceAssignmentTargetPropertyIdentifier(node, data) { 48 | return fn(super.reduceAssignmentTargetPropertyIdentifier(node, data), node); 49 | }, 50 | 51 | reduceAssignmentTargetPropertyProperty(node, data) { 52 | return fn(super.reduceAssignmentTargetPropertyProperty(node, data), node); 53 | }, 54 | 55 | reduceAssignmentTargetWithDefault(node, data) { 56 | return fn(super.reduceAssignmentTargetWithDefault(node, data), node); 57 | }, 58 | 59 | reduceAwaitExpression(node, data) { 60 | return fn(super.reduceAwaitExpression(node, data), node); 61 | }, 62 | 63 | reduceBinaryExpression(node, data) { 64 | return fn(super.reduceBinaryExpression(node, data), node); 65 | }, 66 | 67 | reduceBindingIdentifier(node, data) { 68 | return fn(super.reduceBindingIdentifier(node, data), node); 69 | }, 70 | 71 | reduceBindingPropertyIdentifier(node, data) { 72 | return fn(super.reduceBindingPropertyIdentifier(node, data), node); 73 | }, 74 | 75 | reduceBindingPropertyProperty(node, data) { 76 | return fn(super.reduceBindingPropertyProperty(node, data), node); 77 | }, 78 | 79 | reduceBindingWithDefault(node, data) { 80 | return fn(super.reduceBindingWithDefault(node, data), node); 81 | }, 82 | 83 | reduceBlock(node, data) { 84 | return fn(super.reduceBlock(node, data), node); 85 | }, 86 | 87 | reduceBlockStatement(node, data) { 88 | return fn(super.reduceBlockStatement(node, data), node); 89 | }, 90 | 91 | reduceBreakStatement(node, data) { 92 | return fn(super.reduceBreakStatement(node, data), node); 93 | }, 94 | 95 | reduceCallExpression(node, data) { 96 | return fn(super.reduceCallExpression(node, data), node); 97 | }, 98 | 99 | reduceCatchClause(node, data) { 100 | return fn(super.reduceCatchClause(node, data), node); 101 | }, 102 | 103 | reduceClassDeclaration(node, data) { 104 | return fn(super.reduceClassDeclaration(node, data), node); 105 | }, 106 | 107 | reduceClassElement(node, data) { 108 | return fn(super.reduceClassElement(node, data), node); 109 | }, 110 | 111 | reduceClassExpression(node, data) { 112 | return fn(super.reduceClassExpression(node, data), node); 113 | }, 114 | 115 | reduceCompoundAssignmentExpression(node, data) { 116 | return fn(super.reduceCompoundAssignmentExpression(node, data), node); 117 | }, 118 | 119 | reduceComputedMemberAssignmentTarget(node, data) { 120 | return fn(super.reduceComputedMemberAssignmentTarget(node, data), node); 121 | }, 122 | 123 | reduceComputedMemberExpression(node, data) { 124 | return fn(super.reduceComputedMemberExpression(node, data), node); 125 | }, 126 | 127 | reduceComputedPropertyName(node, data) { 128 | return fn(super.reduceComputedPropertyName(node, data), node); 129 | }, 130 | 131 | reduceConditionalExpression(node, data) { 132 | return fn(super.reduceConditionalExpression(node, data), node); 133 | }, 134 | 135 | reduceContinueStatement(node, data) { 136 | return fn(super.reduceContinueStatement(node, data), node); 137 | }, 138 | 139 | reduceDataProperty(node, data) { 140 | return fn(super.reduceDataProperty(node, data), node); 141 | }, 142 | 143 | reduceDebuggerStatement(node, data) { 144 | return fn(super.reduceDebuggerStatement(node, data), node); 145 | }, 146 | 147 | reduceDirective(node, data) { 148 | return fn(super.reduceDirective(node, data), node); 149 | }, 150 | 151 | reduceDoWhileStatement(node, data) { 152 | return fn(super.reduceDoWhileStatement(node, data), node); 153 | }, 154 | 155 | reduceEmptyStatement(node, data) { 156 | return fn(super.reduceEmptyStatement(node, data), node); 157 | }, 158 | 159 | reduceExport(node, data) { 160 | return fn(super.reduceExport(node, data), node); 161 | }, 162 | 163 | reduceExportAllFrom(node, data) { 164 | return fn(super.reduceExportAllFrom(node, data), node); 165 | }, 166 | 167 | reduceExportDefault(node, data) { 168 | return fn(super.reduceExportDefault(node, data), node); 169 | }, 170 | 171 | reduceExportFrom(node, data) { 172 | return fn(super.reduceExportFrom(node, data), node); 173 | }, 174 | 175 | reduceExportFromSpecifier(node, data) { 176 | return fn(super.reduceExportFromSpecifier(node, data), node); 177 | }, 178 | 179 | reduceExportLocalSpecifier(node, data) { 180 | return fn(super.reduceExportLocalSpecifier(node, data), node); 181 | }, 182 | 183 | reduceExportLocals(node, data) { 184 | return fn(super.reduceExportLocals(node, data), node); 185 | }, 186 | 187 | reduceExpressionStatement(node, data) { 188 | return fn(super.reduceExpressionStatement(node, data), node); 189 | }, 190 | 191 | reduceForAwaitStatement(node, data) { 192 | return fn(super.reduceForAwaitStatement(node, data), node); 193 | }, 194 | 195 | reduceForInStatement(node, data) { 196 | return fn(super.reduceForInStatement(node, data), node); 197 | }, 198 | 199 | reduceForOfStatement(node, data) { 200 | return fn(super.reduceForOfStatement(node, data), node); 201 | }, 202 | 203 | reduceForStatement(node, data) { 204 | return fn(super.reduceForStatement(node, data), node); 205 | }, 206 | 207 | reduceFormalParameters(node, data) { 208 | return fn(super.reduceFormalParameters(node, data), node); 209 | }, 210 | 211 | reduceFunctionBody(node, data) { 212 | return fn(super.reduceFunctionBody(node, data), node); 213 | }, 214 | 215 | reduceFunctionDeclaration(node, data) { 216 | return fn(super.reduceFunctionDeclaration(node, data), node); 217 | }, 218 | 219 | reduceFunctionExpression(node, data) { 220 | return fn(super.reduceFunctionExpression(node, data), node); 221 | }, 222 | 223 | reduceGetter(node, data) { 224 | return fn(super.reduceGetter(node, data), node); 225 | }, 226 | 227 | reduceIdentifierExpression(node, data) { 228 | return fn(super.reduceIdentifierExpression(node, data), node); 229 | }, 230 | 231 | reduceIfStatement(node, data) { 232 | return fn(super.reduceIfStatement(node, data), node); 233 | }, 234 | 235 | reduceImport(node, data) { 236 | return fn(super.reduceImport(node, data), node); 237 | }, 238 | 239 | reduceImportNamespace(node, data) { 240 | return fn(super.reduceImportNamespace(node, data), node); 241 | }, 242 | 243 | reduceImportSpecifier(node, data) { 244 | return fn(super.reduceImportSpecifier(node, data), node); 245 | }, 246 | 247 | reduceLabeledStatement(node, data) { 248 | return fn(super.reduceLabeledStatement(node, data), node); 249 | }, 250 | 251 | reduceLiteralBooleanExpression(node, data) { 252 | return fn(super.reduceLiteralBooleanExpression(node, data), node); 253 | }, 254 | 255 | reduceLiteralInfinityExpression(node, data) { 256 | return fn(super.reduceLiteralInfinityExpression(node, data), node); 257 | }, 258 | 259 | reduceLiteralNullExpression(node, data) { 260 | return fn(super.reduceLiteralNullExpression(node, data), node); 261 | }, 262 | 263 | reduceLiteralNumericExpression(node, data) { 264 | return fn(super.reduceLiteralNumericExpression(node, data), node); 265 | }, 266 | 267 | reduceLiteralRegExpExpression(node, data) { 268 | return fn(super.reduceLiteralRegExpExpression(node, data), node); 269 | }, 270 | 271 | reduceLiteralStringExpression(node, data) { 272 | return fn(super.reduceLiteralStringExpression(node, data), node); 273 | }, 274 | 275 | reduceMethod(node, data) { 276 | return fn(super.reduceMethod(node, data), node); 277 | }, 278 | 279 | reduceModule(node, data) { 280 | return fn(super.reduceModule(node, data), node); 281 | }, 282 | 283 | reduceNewExpression(node, data) { 284 | return fn(super.reduceNewExpression(node, data), node); 285 | }, 286 | 287 | reduceNewTargetExpression(node, data) { 288 | return fn(super.reduceNewTargetExpression(node, data), node); 289 | }, 290 | 291 | reduceObjectAssignmentTarget(node, data) { 292 | return fn(super.reduceObjectAssignmentTarget(node, data), node); 293 | }, 294 | 295 | reduceObjectBinding(node, data) { 296 | return fn(super.reduceObjectBinding(node, data), node); 297 | }, 298 | 299 | reduceObjectExpression(node, data) { 300 | return fn(super.reduceObjectExpression(node, data), node); 301 | }, 302 | 303 | reduceReturnStatement(node, data) { 304 | return fn(super.reduceReturnStatement(node, data), node); 305 | }, 306 | 307 | reduceScript(node, data) { 308 | return fn(super.reduceScript(node, data), node); 309 | }, 310 | 311 | reduceSetter(node, data) { 312 | return fn(super.reduceSetter(node, data), node); 313 | }, 314 | 315 | reduceShorthandProperty(node, data) { 316 | return fn(super.reduceShorthandProperty(node, data), node); 317 | }, 318 | 319 | reduceSpreadElement(node, data) { 320 | return fn(super.reduceSpreadElement(node, data), node); 321 | }, 322 | 323 | reduceSpreadProperty(node, data) { 324 | return fn(super.reduceSpreadProperty(node, data), node); 325 | }, 326 | 327 | reduceStaticMemberAssignmentTarget(node, data) { 328 | return fn(super.reduceStaticMemberAssignmentTarget(node, data), node); 329 | }, 330 | 331 | reduceStaticMemberExpression(node, data) { 332 | return fn(super.reduceStaticMemberExpression(node, data), node); 333 | }, 334 | 335 | reduceStaticPropertyName(node, data) { 336 | return fn(super.reduceStaticPropertyName(node, data), node); 337 | }, 338 | 339 | reduceSuper(node, data) { 340 | return fn(super.reduceSuper(node, data), node); 341 | }, 342 | 343 | reduceSwitchCase(node, data) { 344 | return fn(super.reduceSwitchCase(node, data), node); 345 | }, 346 | 347 | reduceSwitchDefault(node, data) { 348 | return fn(super.reduceSwitchDefault(node, data), node); 349 | }, 350 | 351 | reduceSwitchStatement(node, data) { 352 | return fn(super.reduceSwitchStatement(node, data), node); 353 | }, 354 | 355 | reduceSwitchStatementWithDefault(node, data) { 356 | return fn(super.reduceSwitchStatementWithDefault(node, data), node); 357 | }, 358 | 359 | reduceTemplateElement(node, data) { 360 | return fn(super.reduceTemplateElement(node, data), node); 361 | }, 362 | 363 | reduceTemplateExpression(node, data) { 364 | return fn(super.reduceTemplateExpression(node, data), node); 365 | }, 366 | 367 | reduceThisExpression(node, data) { 368 | return fn(super.reduceThisExpression(node, data), node); 369 | }, 370 | 371 | reduceThrowStatement(node, data) { 372 | return fn(super.reduceThrowStatement(node, data), node); 373 | }, 374 | 375 | reduceTryCatchStatement(node, data) { 376 | return fn(super.reduceTryCatchStatement(node, data), node); 377 | }, 378 | 379 | reduceTryFinallyStatement(node, data) { 380 | return fn(super.reduceTryFinallyStatement(node, data), node); 381 | }, 382 | 383 | reduceUnaryExpression(node, data) { 384 | return fn(super.reduceUnaryExpression(node, data), node); 385 | }, 386 | 387 | reduceUpdateExpression(node, data) { 388 | return fn(super.reduceUpdateExpression(node, data), node); 389 | }, 390 | 391 | reduceVariableDeclaration(node, data) { 392 | return fn(super.reduceVariableDeclaration(node, data), node); 393 | }, 394 | 395 | reduceVariableDeclarationStatement(node, data) { 396 | return fn(super.reduceVariableDeclarationStatement(node, data), node); 397 | }, 398 | 399 | reduceVariableDeclarator(node, data) { 400 | return fn(super.reduceVariableDeclarator(node, data), node); 401 | }, 402 | 403 | reduceWhileStatement(node, data) { 404 | return fn(super.reduceWhileStatement(node, data), node); 405 | }, 406 | 407 | reduceWithStatement(node, data) { 408 | return fn(super.reduceWithStatement(node, data), node); 409 | }, 410 | 411 | reduceYieldExpression(node, data) { 412 | return fn(super.reduceYieldExpression(node, data), node); 413 | }, 414 | 415 | reduceYieldGeneratorExpression(node, data) { 416 | return fn(super.reduceYieldGeneratorExpression(node, data), node); 417 | }, 418 | }); 419 | -------------------------------------------------------------------------------- /gen/clone-reducer.js: -------------------------------------------------------------------------------- 1 | // Generated by generate-clone-reducer.js 2 | /** 3 | * Copyright 2018 Shape Security, Inc. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License") 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | const Shift = require('shift-ast'); 19 | 20 | module.exports = class CloneReducer { 21 | reduceArrayAssignmentTarget(node, { elements, rest }) { 22 | return new Shift.ArrayAssignmentTarget({ elements, rest }); 23 | } 24 | 25 | reduceArrayBinding(node, { elements, rest }) { 26 | return new Shift.ArrayBinding({ elements, rest }); 27 | } 28 | 29 | reduceArrayExpression(node, { elements }) { 30 | return new Shift.ArrayExpression({ elements }); 31 | } 32 | 33 | reduceArrowExpression(node, { params, body }) { 34 | return new Shift.ArrowExpression({ isAsync: node.isAsync, params, body }); 35 | } 36 | 37 | reduceAssignmentExpression(node, { binding, expression }) { 38 | return new Shift.AssignmentExpression({ binding, expression }); 39 | } 40 | 41 | reduceAssignmentTargetIdentifier(node) { 42 | return new Shift.AssignmentTargetIdentifier({ name: node.name }); 43 | } 44 | 45 | reduceAssignmentTargetPropertyIdentifier(node, { binding, init }) { 46 | return new Shift.AssignmentTargetPropertyIdentifier({ binding, init }); 47 | } 48 | 49 | reduceAssignmentTargetPropertyProperty(node, { name, binding }) { 50 | return new Shift.AssignmentTargetPropertyProperty({ name, binding }); 51 | } 52 | 53 | reduceAssignmentTargetWithDefault(node, { binding, init }) { 54 | return new Shift.AssignmentTargetWithDefault({ binding, init }); 55 | } 56 | 57 | reduceAwaitExpression(node, { expression }) { 58 | return new Shift.AwaitExpression({ expression }); 59 | } 60 | 61 | reduceBinaryExpression(node, { left, right }) { 62 | return new Shift.BinaryExpression({ left, operator: node.operator, right }); 63 | } 64 | 65 | reduceBindingIdentifier(node) { 66 | return new Shift.BindingIdentifier({ name: node.name }); 67 | } 68 | 69 | reduceBindingPropertyIdentifier(node, { binding, init }) { 70 | return new Shift.BindingPropertyIdentifier({ binding, init }); 71 | } 72 | 73 | reduceBindingPropertyProperty(node, { name, binding }) { 74 | return new Shift.BindingPropertyProperty({ name, binding }); 75 | } 76 | 77 | reduceBindingWithDefault(node, { binding, init }) { 78 | return new Shift.BindingWithDefault({ binding, init }); 79 | } 80 | 81 | reduceBlock(node, { statements }) { 82 | return new Shift.Block({ statements }); 83 | } 84 | 85 | reduceBlockStatement(node, { block }) { 86 | return new Shift.BlockStatement({ block }); 87 | } 88 | 89 | reduceBreakStatement(node) { 90 | return new Shift.BreakStatement({ label: node.label }); 91 | } 92 | 93 | reduceCallExpression(node, { callee, arguments: _arguments }) { 94 | return new Shift.CallExpression({ callee, arguments: _arguments }); 95 | } 96 | 97 | reduceCatchClause(node, { binding, body }) { 98 | return new Shift.CatchClause({ binding, body }); 99 | } 100 | 101 | reduceClassDeclaration(node, { name, super: _super, elements }) { 102 | return new Shift.ClassDeclaration({ name, super: _super, elements }); 103 | } 104 | 105 | reduceClassElement(node, { method }) { 106 | return new Shift.ClassElement({ isStatic: node.isStatic, method }); 107 | } 108 | 109 | reduceClassExpression(node, { name, super: _super, elements }) { 110 | return new Shift.ClassExpression({ name, super: _super, elements }); 111 | } 112 | 113 | reduceCompoundAssignmentExpression(node, { binding, expression }) { 114 | return new Shift.CompoundAssignmentExpression({ binding, operator: node.operator, expression }); 115 | } 116 | 117 | reduceComputedMemberAssignmentTarget(node, { object, expression }) { 118 | return new Shift.ComputedMemberAssignmentTarget({ object, expression }); 119 | } 120 | 121 | reduceComputedMemberExpression(node, { object, expression }) { 122 | return new Shift.ComputedMemberExpression({ object, expression }); 123 | } 124 | 125 | reduceComputedPropertyName(node, { expression }) { 126 | return new Shift.ComputedPropertyName({ expression }); 127 | } 128 | 129 | reduceConditionalExpression(node, { test, consequent, alternate }) { 130 | return new Shift.ConditionalExpression({ test, consequent, alternate }); 131 | } 132 | 133 | reduceContinueStatement(node) { 134 | return new Shift.ContinueStatement({ label: node.label }); 135 | } 136 | 137 | reduceDataProperty(node, { name, expression }) { 138 | return new Shift.DataProperty({ name, expression }); 139 | } 140 | 141 | reduceDebuggerStatement(node) { 142 | return new Shift.DebuggerStatement; 143 | } 144 | 145 | reduceDirective(node) { 146 | return new Shift.Directive({ rawValue: node.rawValue }); 147 | } 148 | 149 | reduceDoWhileStatement(node, { body, test }) { 150 | return new Shift.DoWhileStatement({ body, test }); 151 | } 152 | 153 | reduceEmptyStatement(node) { 154 | return new Shift.EmptyStatement; 155 | } 156 | 157 | reduceExport(node, { declaration }) { 158 | return new Shift.Export({ declaration }); 159 | } 160 | 161 | reduceExportAllFrom(node) { 162 | return new Shift.ExportAllFrom({ moduleSpecifier: node.moduleSpecifier }); 163 | } 164 | 165 | reduceExportDefault(node, { body }) { 166 | return new Shift.ExportDefault({ body }); 167 | } 168 | 169 | reduceExportFrom(node, { namedExports }) { 170 | return new Shift.ExportFrom({ namedExports, moduleSpecifier: node.moduleSpecifier }); 171 | } 172 | 173 | reduceExportFromSpecifier(node) { 174 | return new Shift.ExportFromSpecifier({ name: node.name, exportedName: node.exportedName }); 175 | } 176 | 177 | reduceExportLocalSpecifier(node, { name }) { 178 | return new Shift.ExportLocalSpecifier({ name, exportedName: node.exportedName }); 179 | } 180 | 181 | reduceExportLocals(node, { namedExports }) { 182 | return new Shift.ExportLocals({ namedExports }); 183 | } 184 | 185 | reduceExpressionStatement(node, { expression }) { 186 | return new Shift.ExpressionStatement({ expression }); 187 | } 188 | 189 | reduceForAwaitStatement(node, { left, right, body }) { 190 | return new Shift.ForAwaitStatement({ left, right, body }); 191 | } 192 | 193 | reduceForInStatement(node, { left, right, body }) { 194 | return new Shift.ForInStatement({ left, right, body }); 195 | } 196 | 197 | reduceForOfStatement(node, { left, right, body }) { 198 | return new Shift.ForOfStatement({ left, right, body }); 199 | } 200 | 201 | reduceForStatement(node, { init, test, update, body }) { 202 | return new Shift.ForStatement({ init, test, update, body }); 203 | } 204 | 205 | reduceFormalParameters(node, { items, rest }) { 206 | return new Shift.FormalParameters({ items, rest }); 207 | } 208 | 209 | reduceFunctionBody(node, { directives, statements }) { 210 | return new Shift.FunctionBody({ directives, statements }); 211 | } 212 | 213 | reduceFunctionDeclaration(node, { name, params, body }) { 214 | return new Shift.FunctionDeclaration({ isAsync: node.isAsync, isGenerator: node.isGenerator, name, params, body }); 215 | } 216 | 217 | reduceFunctionExpression(node, { name, params, body }) { 218 | return new Shift.FunctionExpression({ isAsync: node.isAsync, isGenerator: node.isGenerator, name, params, body }); 219 | } 220 | 221 | reduceGetter(node, { name, body }) { 222 | return new Shift.Getter({ name, body }); 223 | } 224 | 225 | reduceIdentifierExpression(node) { 226 | return new Shift.IdentifierExpression({ name: node.name }); 227 | } 228 | 229 | reduceIfStatement(node, { test, consequent, alternate }) { 230 | return new Shift.IfStatement({ test, consequent, alternate }); 231 | } 232 | 233 | reduceImport(node, { defaultBinding, namedImports }) { 234 | return new Shift.Import({ defaultBinding, namedImports, moduleSpecifier: node.moduleSpecifier }); 235 | } 236 | 237 | reduceImportNamespace(node, { defaultBinding, namespaceBinding }) { 238 | return new Shift.ImportNamespace({ defaultBinding, namespaceBinding, moduleSpecifier: node.moduleSpecifier }); 239 | } 240 | 241 | reduceImportSpecifier(node, { binding }) { 242 | return new Shift.ImportSpecifier({ name: node.name, binding }); 243 | } 244 | 245 | reduceLabeledStatement(node, { body }) { 246 | return new Shift.LabeledStatement({ label: node.label, body }); 247 | } 248 | 249 | reduceLiteralBooleanExpression(node) { 250 | return new Shift.LiteralBooleanExpression({ value: node.value }); 251 | } 252 | 253 | reduceLiteralInfinityExpression(node) { 254 | return new Shift.LiteralInfinityExpression; 255 | } 256 | 257 | reduceLiteralNullExpression(node) { 258 | return new Shift.LiteralNullExpression; 259 | } 260 | 261 | reduceLiteralNumericExpression(node) { 262 | return new Shift.LiteralNumericExpression({ value: node.value }); 263 | } 264 | 265 | reduceLiteralRegExpExpression(node) { 266 | return new Shift.LiteralRegExpExpression({ pattern: node.pattern, global: node.global, ignoreCase: node.ignoreCase, multiLine: node.multiLine, dotAll: node.dotAll, unicode: node.unicode, sticky: node.sticky }); 267 | } 268 | 269 | reduceLiteralStringExpression(node) { 270 | return new Shift.LiteralStringExpression({ value: node.value }); 271 | } 272 | 273 | reduceMethod(node, { name, params, body }) { 274 | return new Shift.Method({ isAsync: node.isAsync, isGenerator: node.isGenerator, name, params, body }); 275 | } 276 | 277 | reduceModule(node, { directives, items }) { 278 | return new Shift.Module({ directives, items }); 279 | } 280 | 281 | reduceNewExpression(node, { callee, arguments: _arguments }) { 282 | return new Shift.NewExpression({ callee, arguments: _arguments }); 283 | } 284 | 285 | reduceNewTargetExpression(node) { 286 | return new Shift.NewTargetExpression; 287 | } 288 | 289 | reduceObjectAssignmentTarget(node, { properties, rest }) { 290 | return new Shift.ObjectAssignmentTarget({ properties, rest }); 291 | } 292 | 293 | reduceObjectBinding(node, { properties, rest }) { 294 | return new Shift.ObjectBinding({ properties, rest }); 295 | } 296 | 297 | reduceObjectExpression(node, { properties }) { 298 | return new Shift.ObjectExpression({ properties }); 299 | } 300 | 301 | reduceReturnStatement(node, { expression }) { 302 | return new Shift.ReturnStatement({ expression }); 303 | } 304 | 305 | reduceScript(node, { directives, statements }) { 306 | return new Shift.Script({ directives, statements }); 307 | } 308 | 309 | reduceSetter(node, { name, param, body }) { 310 | return new Shift.Setter({ name, param, body }); 311 | } 312 | 313 | reduceShorthandProperty(node, { name }) { 314 | return new Shift.ShorthandProperty({ name }); 315 | } 316 | 317 | reduceSpreadElement(node, { expression }) { 318 | return new Shift.SpreadElement({ expression }); 319 | } 320 | 321 | reduceSpreadProperty(node, { expression }) { 322 | return new Shift.SpreadProperty({ expression }); 323 | } 324 | 325 | reduceStaticMemberAssignmentTarget(node, { object }) { 326 | return new Shift.StaticMemberAssignmentTarget({ object, property: node.property }); 327 | } 328 | 329 | reduceStaticMemberExpression(node, { object }) { 330 | return new Shift.StaticMemberExpression({ object, property: node.property }); 331 | } 332 | 333 | reduceStaticPropertyName(node) { 334 | return new Shift.StaticPropertyName({ value: node.value }); 335 | } 336 | 337 | reduceSuper(node) { 338 | return new Shift.Super; 339 | } 340 | 341 | reduceSwitchCase(node, { test, consequent }) { 342 | return new Shift.SwitchCase({ test, consequent }); 343 | } 344 | 345 | reduceSwitchDefault(node, { consequent }) { 346 | return new Shift.SwitchDefault({ consequent }); 347 | } 348 | 349 | reduceSwitchStatement(node, { discriminant, cases }) { 350 | return new Shift.SwitchStatement({ discriminant, cases }); 351 | } 352 | 353 | reduceSwitchStatementWithDefault(node, { discriminant, preDefaultCases, defaultCase, postDefaultCases }) { 354 | return new Shift.SwitchStatementWithDefault({ discriminant, preDefaultCases, defaultCase, postDefaultCases }); 355 | } 356 | 357 | reduceTemplateElement(node) { 358 | return new Shift.TemplateElement({ rawValue: node.rawValue }); 359 | } 360 | 361 | reduceTemplateExpression(node, { tag, elements }) { 362 | return new Shift.TemplateExpression({ tag, elements }); 363 | } 364 | 365 | reduceThisExpression(node) { 366 | return new Shift.ThisExpression; 367 | } 368 | 369 | reduceThrowStatement(node, { expression }) { 370 | return new Shift.ThrowStatement({ expression }); 371 | } 372 | 373 | reduceTryCatchStatement(node, { body, catchClause }) { 374 | return new Shift.TryCatchStatement({ body, catchClause }); 375 | } 376 | 377 | reduceTryFinallyStatement(node, { body, catchClause, finalizer }) { 378 | return new Shift.TryFinallyStatement({ body, catchClause, finalizer }); 379 | } 380 | 381 | reduceUnaryExpression(node, { operand }) { 382 | return new Shift.UnaryExpression({ operator: node.operator, operand }); 383 | } 384 | 385 | reduceUpdateExpression(node, { operand }) { 386 | return new Shift.UpdateExpression({ isPrefix: node.isPrefix, operator: node.operator, operand }); 387 | } 388 | 389 | reduceVariableDeclaration(node, { declarators }) { 390 | return new Shift.VariableDeclaration({ kind: node.kind, declarators }); 391 | } 392 | 393 | reduceVariableDeclarationStatement(node, { declaration }) { 394 | return new Shift.VariableDeclarationStatement({ declaration }); 395 | } 396 | 397 | reduceVariableDeclarator(node, { binding, init }) { 398 | return new Shift.VariableDeclarator({ binding, init }); 399 | } 400 | 401 | reduceWhileStatement(node, { test, body }) { 402 | return new Shift.WhileStatement({ test, body }); 403 | } 404 | 405 | reduceWithStatement(node, { object, body }) { 406 | return new Shift.WithStatement({ object, body }); 407 | } 408 | 409 | reduceYieldExpression(node, { expression }) { 410 | return new Shift.YieldExpression({ expression }); 411 | } 412 | 413 | reduceYieldGeneratorExpression(node, { expression }) { 414 | return new Shift.YieldGeneratorExpression({ expression }); 415 | } 416 | }; 417 | -------------------------------------------------------------------------------- /gen/director.js: -------------------------------------------------------------------------------- 1 | // Generated by generate-director.js 2 | /** 3 | * Copyright 2018 Shape Security, Inc. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License") 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | const director = { 19 | ArrayAssignmentTarget(reducer, node) { 20 | return reducer.reduceArrayAssignmentTarget(node, { elements: node.elements.map(v => v && this[v.type](reducer, v)), rest: node.rest && this[node.rest.type](reducer, node.rest) }); 21 | }, 22 | 23 | ArrayBinding(reducer, node) { 24 | return reducer.reduceArrayBinding(node, { elements: node.elements.map(v => v && this[v.type](reducer, v)), rest: node.rest && this[node.rest.type](reducer, node.rest) }); 25 | }, 26 | 27 | ArrayExpression(reducer, node) { 28 | return reducer.reduceArrayExpression(node, { elements: node.elements.map(v => v && this[v.type](reducer, v)) }); 29 | }, 30 | 31 | ArrowExpression(reducer, node) { 32 | return reducer.reduceArrowExpression(node, { params: this.FormalParameters(reducer, node.params), body: this[node.body.type](reducer, node.body) }); 33 | }, 34 | 35 | AssignmentExpression(reducer, node) { 36 | return reducer.reduceAssignmentExpression(node, { binding: this[node.binding.type](reducer, node.binding), expression: this[node.expression.type](reducer, node.expression) }); 37 | }, 38 | 39 | AssignmentTargetIdentifier(reducer, node) { 40 | return reducer.reduceAssignmentTargetIdentifier(node); 41 | }, 42 | 43 | AssignmentTargetPropertyIdentifier(reducer, node) { 44 | return reducer.reduceAssignmentTargetPropertyIdentifier(node, { binding: this.AssignmentTargetIdentifier(reducer, node.binding), init: node.init && this[node.init.type](reducer, node.init) }); 45 | }, 46 | 47 | AssignmentTargetPropertyProperty(reducer, node) { 48 | return reducer.reduceAssignmentTargetPropertyProperty(node, { name: this[node.name.type](reducer, node.name), binding: this[node.binding.type](reducer, node.binding) }); 49 | }, 50 | 51 | AssignmentTargetWithDefault(reducer, node) { 52 | return reducer.reduceAssignmentTargetWithDefault(node, { binding: this[node.binding.type](reducer, node.binding), init: this[node.init.type](reducer, node.init) }); 53 | }, 54 | 55 | AwaitExpression(reducer, node) { 56 | return reducer.reduceAwaitExpression(node, { expression: this[node.expression.type](reducer, node.expression) }); 57 | }, 58 | 59 | BinaryExpression(reducer, node) { 60 | return reducer.reduceBinaryExpression(node, { left: this[node.left.type](reducer, node.left), right: this[node.right.type](reducer, node.right) }); 61 | }, 62 | 63 | BindingIdentifier(reducer, node) { 64 | return reducer.reduceBindingIdentifier(node); 65 | }, 66 | 67 | BindingPropertyIdentifier(reducer, node) { 68 | return reducer.reduceBindingPropertyIdentifier(node, { binding: this.BindingIdentifier(reducer, node.binding), init: node.init && this[node.init.type](reducer, node.init) }); 69 | }, 70 | 71 | BindingPropertyProperty(reducer, node) { 72 | return reducer.reduceBindingPropertyProperty(node, { name: this[node.name.type](reducer, node.name), binding: this[node.binding.type](reducer, node.binding) }); 73 | }, 74 | 75 | BindingWithDefault(reducer, node) { 76 | return reducer.reduceBindingWithDefault(node, { binding: this[node.binding.type](reducer, node.binding), init: this[node.init.type](reducer, node.init) }); 77 | }, 78 | 79 | Block(reducer, node) { 80 | return reducer.reduceBlock(node, { statements: node.statements.map(v => this[v.type](reducer, v)) }); 81 | }, 82 | 83 | BlockStatement(reducer, node) { 84 | return reducer.reduceBlockStatement(node, { block: this.Block(reducer, node.block) }); 85 | }, 86 | 87 | BreakStatement(reducer, node) { 88 | return reducer.reduceBreakStatement(node); 89 | }, 90 | 91 | CallExpression(reducer, node) { 92 | return reducer.reduceCallExpression(node, { callee: this[node.callee.type](reducer, node.callee), arguments: node.arguments.map(v => this[v.type](reducer, v)) }); 93 | }, 94 | 95 | CatchClause(reducer, node) { 96 | return reducer.reduceCatchClause(node, { binding: node.binding && this[node.binding.type](reducer, node.binding), body: this.Block(reducer, node.body) }); 97 | }, 98 | 99 | ClassDeclaration(reducer, node) { 100 | return reducer.reduceClassDeclaration(node, { name: this.BindingIdentifier(reducer, node.name), super: node.super && this[node.super.type](reducer, node.super), elements: node.elements.map(v => this.ClassElement(reducer, v)) }); 101 | }, 102 | 103 | ClassElement(reducer, node) { 104 | return reducer.reduceClassElement(node, { method: this[node.method.type](reducer, node.method) }); 105 | }, 106 | 107 | ClassExpression(reducer, node) { 108 | return reducer.reduceClassExpression(node, { name: node.name && this.BindingIdentifier(reducer, node.name), super: node.super && this[node.super.type](reducer, node.super), elements: node.elements.map(v => this.ClassElement(reducer, v)) }); 109 | }, 110 | 111 | CompoundAssignmentExpression(reducer, node) { 112 | return reducer.reduceCompoundAssignmentExpression(node, { binding: this[node.binding.type](reducer, node.binding), expression: this[node.expression.type](reducer, node.expression) }); 113 | }, 114 | 115 | ComputedMemberAssignmentTarget(reducer, node) { 116 | return reducer.reduceComputedMemberAssignmentTarget(node, { object: this[node.object.type](reducer, node.object), expression: this[node.expression.type](reducer, node.expression) }); 117 | }, 118 | 119 | ComputedMemberExpression(reducer, node) { 120 | return reducer.reduceComputedMemberExpression(node, { object: this[node.object.type](reducer, node.object), expression: this[node.expression.type](reducer, node.expression) }); 121 | }, 122 | 123 | ComputedPropertyName(reducer, node) { 124 | return reducer.reduceComputedPropertyName(node, { expression: this[node.expression.type](reducer, node.expression) }); 125 | }, 126 | 127 | ConditionalExpression(reducer, node) { 128 | return reducer.reduceConditionalExpression(node, { test: this[node.test.type](reducer, node.test), consequent: this[node.consequent.type](reducer, node.consequent), alternate: this[node.alternate.type](reducer, node.alternate) }); 129 | }, 130 | 131 | ContinueStatement(reducer, node) { 132 | return reducer.reduceContinueStatement(node); 133 | }, 134 | 135 | DataProperty(reducer, node) { 136 | return reducer.reduceDataProperty(node, { name: this[node.name.type](reducer, node.name), expression: this[node.expression.type](reducer, node.expression) }); 137 | }, 138 | 139 | DebuggerStatement(reducer, node) { 140 | return reducer.reduceDebuggerStatement(node); 141 | }, 142 | 143 | Directive(reducer, node) { 144 | return reducer.reduceDirective(node); 145 | }, 146 | 147 | DoWhileStatement(reducer, node) { 148 | return reducer.reduceDoWhileStatement(node, { body: this[node.body.type](reducer, node.body), test: this[node.test.type](reducer, node.test) }); 149 | }, 150 | 151 | EmptyStatement(reducer, node) { 152 | return reducer.reduceEmptyStatement(node); 153 | }, 154 | 155 | Export(reducer, node) { 156 | return reducer.reduceExport(node, { declaration: this[node.declaration.type](reducer, node.declaration) }); 157 | }, 158 | 159 | ExportAllFrom(reducer, node) { 160 | return reducer.reduceExportAllFrom(node); 161 | }, 162 | 163 | ExportDefault(reducer, node) { 164 | return reducer.reduceExportDefault(node, { body: this[node.body.type](reducer, node.body) }); 165 | }, 166 | 167 | ExportFrom(reducer, node) { 168 | return reducer.reduceExportFrom(node, { namedExports: node.namedExports.map(v => this.ExportFromSpecifier(reducer, v)) }); 169 | }, 170 | 171 | ExportFromSpecifier(reducer, node) { 172 | return reducer.reduceExportFromSpecifier(node); 173 | }, 174 | 175 | ExportLocalSpecifier(reducer, node) { 176 | return reducer.reduceExportLocalSpecifier(node, { name: this.IdentifierExpression(reducer, node.name) }); 177 | }, 178 | 179 | ExportLocals(reducer, node) { 180 | return reducer.reduceExportLocals(node, { namedExports: node.namedExports.map(v => this.ExportLocalSpecifier(reducer, v)) }); 181 | }, 182 | 183 | ExpressionStatement(reducer, node) { 184 | return reducer.reduceExpressionStatement(node, { expression: this[node.expression.type](reducer, node.expression) }); 185 | }, 186 | 187 | ForAwaitStatement(reducer, node) { 188 | return reducer.reduceForAwaitStatement(node, { left: this[node.left.type](reducer, node.left), right: this[node.right.type](reducer, node.right), body: this[node.body.type](reducer, node.body) }); 189 | }, 190 | 191 | ForInStatement(reducer, node) { 192 | return reducer.reduceForInStatement(node, { left: this[node.left.type](reducer, node.left), right: this[node.right.type](reducer, node.right), body: this[node.body.type](reducer, node.body) }); 193 | }, 194 | 195 | ForOfStatement(reducer, node) { 196 | return reducer.reduceForOfStatement(node, { left: this[node.left.type](reducer, node.left), right: this[node.right.type](reducer, node.right), body: this[node.body.type](reducer, node.body) }); 197 | }, 198 | 199 | ForStatement(reducer, node) { 200 | return reducer.reduceForStatement(node, { init: node.init && this[node.init.type](reducer, node.init), test: node.test && this[node.test.type](reducer, node.test), update: node.update && this[node.update.type](reducer, node.update), body: this[node.body.type](reducer, node.body) }); 201 | }, 202 | 203 | FormalParameters(reducer, node) { 204 | return reducer.reduceFormalParameters(node, { items: node.items.map(v => this[v.type](reducer, v)), rest: node.rest && this[node.rest.type](reducer, node.rest) }); 205 | }, 206 | 207 | FunctionBody(reducer, node) { 208 | return reducer.reduceFunctionBody(node, { directives: node.directives.map(v => this.Directive(reducer, v)), statements: node.statements.map(v => this[v.type](reducer, v)) }); 209 | }, 210 | 211 | FunctionDeclaration(reducer, node) { 212 | return reducer.reduceFunctionDeclaration(node, { name: this.BindingIdentifier(reducer, node.name), params: this.FormalParameters(reducer, node.params), body: this.FunctionBody(reducer, node.body) }); 213 | }, 214 | 215 | FunctionExpression(reducer, node) { 216 | return reducer.reduceFunctionExpression(node, { name: node.name && this.BindingIdentifier(reducer, node.name), params: this.FormalParameters(reducer, node.params), body: this.FunctionBody(reducer, node.body) }); 217 | }, 218 | 219 | Getter(reducer, node) { 220 | return reducer.reduceGetter(node, { name: this[node.name.type](reducer, node.name), body: this.FunctionBody(reducer, node.body) }); 221 | }, 222 | 223 | IdentifierExpression(reducer, node) { 224 | return reducer.reduceIdentifierExpression(node); 225 | }, 226 | 227 | IfStatement(reducer, node) { 228 | return reducer.reduceIfStatement(node, { test: this[node.test.type](reducer, node.test), consequent: this[node.consequent.type](reducer, node.consequent), alternate: node.alternate && this[node.alternate.type](reducer, node.alternate) }); 229 | }, 230 | 231 | Import(reducer, node) { 232 | return reducer.reduceImport(node, { defaultBinding: node.defaultBinding && this.BindingIdentifier(reducer, node.defaultBinding), namedImports: node.namedImports.map(v => this.ImportSpecifier(reducer, v)) }); 233 | }, 234 | 235 | ImportNamespace(reducer, node) { 236 | return reducer.reduceImportNamespace(node, { defaultBinding: node.defaultBinding && this.BindingIdentifier(reducer, node.defaultBinding), namespaceBinding: this.BindingIdentifier(reducer, node.namespaceBinding) }); 237 | }, 238 | 239 | ImportSpecifier(reducer, node) { 240 | return reducer.reduceImportSpecifier(node, { binding: this.BindingIdentifier(reducer, node.binding) }); 241 | }, 242 | 243 | LabeledStatement(reducer, node) { 244 | return reducer.reduceLabeledStatement(node, { body: this[node.body.type](reducer, node.body) }); 245 | }, 246 | 247 | LiteralBooleanExpression(reducer, node) { 248 | return reducer.reduceLiteralBooleanExpression(node); 249 | }, 250 | 251 | LiteralInfinityExpression(reducer, node) { 252 | return reducer.reduceLiteralInfinityExpression(node); 253 | }, 254 | 255 | LiteralNullExpression(reducer, node) { 256 | return reducer.reduceLiteralNullExpression(node); 257 | }, 258 | 259 | LiteralNumericExpression(reducer, node) { 260 | return reducer.reduceLiteralNumericExpression(node); 261 | }, 262 | 263 | LiteralRegExpExpression(reducer, node) { 264 | return reducer.reduceLiteralRegExpExpression(node); 265 | }, 266 | 267 | LiteralStringExpression(reducer, node) { 268 | return reducer.reduceLiteralStringExpression(node); 269 | }, 270 | 271 | Method(reducer, node) { 272 | return reducer.reduceMethod(node, { name: this[node.name.type](reducer, node.name), params: this.FormalParameters(reducer, node.params), body: this.FunctionBody(reducer, node.body) }); 273 | }, 274 | 275 | Module(reducer, node) { 276 | return reducer.reduceModule(node, { directives: node.directives.map(v => this.Directive(reducer, v)), items: node.items.map(v => this[v.type](reducer, v)) }); 277 | }, 278 | 279 | NewExpression(reducer, node) { 280 | return reducer.reduceNewExpression(node, { callee: this[node.callee.type](reducer, node.callee), arguments: node.arguments.map(v => this[v.type](reducer, v)) }); 281 | }, 282 | 283 | NewTargetExpression(reducer, node) { 284 | return reducer.reduceNewTargetExpression(node); 285 | }, 286 | 287 | ObjectAssignmentTarget(reducer, node) { 288 | return reducer.reduceObjectAssignmentTarget(node, { properties: node.properties.map(v => this[v.type](reducer, v)), rest: node.rest && this[node.rest.type](reducer, node.rest) }); 289 | }, 290 | 291 | ObjectBinding(reducer, node) { 292 | return reducer.reduceObjectBinding(node, { properties: node.properties.map(v => this[v.type](reducer, v)), rest: node.rest && this.BindingIdentifier(reducer, node.rest) }); 293 | }, 294 | 295 | ObjectExpression(reducer, node) { 296 | return reducer.reduceObjectExpression(node, { properties: node.properties.map(v => this[v.type](reducer, v)) }); 297 | }, 298 | 299 | ReturnStatement(reducer, node) { 300 | return reducer.reduceReturnStatement(node, { expression: node.expression && this[node.expression.type](reducer, node.expression) }); 301 | }, 302 | 303 | Script(reducer, node) { 304 | return reducer.reduceScript(node, { directives: node.directives.map(v => this.Directive(reducer, v)), statements: node.statements.map(v => this[v.type](reducer, v)) }); 305 | }, 306 | 307 | Setter(reducer, node) { 308 | return reducer.reduceSetter(node, { name: this[node.name.type](reducer, node.name), param: this[node.param.type](reducer, node.param), body: this.FunctionBody(reducer, node.body) }); 309 | }, 310 | 311 | ShorthandProperty(reducer, node) { 312 | return reducer.reduceShorthandProperty(node, { name: this.IdentifierExpression(reducer, node.name) }); 313 | }, 314 | 315 | SpreadElement(reducer, node) { 316 | return reducer.reduceSpreadElement(node, { expression: this[node.expression.type](reducer, node.expression) }); 317 | }, 318 | 319 | SpreadProperty(reducer, node) { 320 | return reducer.reduceSpreadProperty(node, { expression: this[node.expression.type](reducer, node.expression) }); 321 | }, 322 | 323 | StaticMemberAssignmentTarget(reducer, node) { 324 | return reducer.reduceStaticMemberAssignmentTarget(node, { object: this[node.object.type](reducer, node.object) }); 325 | }, 326 | 327 | StaticMemberExpression(reducer, node) { 328 | return reducer.reduceStaticMemberExpression(node, { object: this[node.object.type](reducer, node.object) }); 329 | }, 330 | 331 | StaticPropertyName(reducer, node) { 332 | return reducer.reduceStaticPropertyName(node); 333 | }, 334 | 335 | Super(reducer, node) { 336 | return reducer.reduceSuper(node); 337 | }, 338 | 339 | SwitchCase(reducer, node) { 340 | return reducer.reduceSwitchCase(node, { test: this[node.test.type](reducer, node.test), consequent: node.consequent.map(v => this[v.type](reducer, v)) }); 341 | }, 342 | 343 | SwitchDefault(reducer, node) { 344 | return reducer.reduceSwitchDefault(node, { consequent: node.consequent.map(v => this[v.type](reducer, v)) }); 345 | }, 346 | 347 | SwitchStatement(reducer, node) { 348 | return reducer.reduceSwitchStatement(node, { discriminant: this[node.discriminant.type](reducer, node.discriminant), cases: node.cases.map(v => this.SwitchCase(reducer, v)) }); 349 | }, 350 | 351 | SwitchStatementWithDefault(reducer, node) { 352 | return reducer.reduceSwitchStatementWithDefault(node, { discriminant: this[node.discriminant.type](reducer, node.discriminant), preDefaultCases: node.preDefaultCases.map(v => this.SwitchCase(reducer, v)), defaultCase: this.SwitchDefault(reducer, node.defaultCase), postDefaultCases: node.postDefaultCases.map(v => this.SwitchCase(reducer, v)) }); 353 | }, 354 | 355 | TemplateElement(reducer, node) { 356 | return reducer.reduceTemplateElement(node); 357 | }, 358 | 359 | TemplateExpression(reducer, node) { 360 | return reducer.reduceTemplateExpression(node, { tag: node.tag && this[node.tag.type](reducer, node.tag), elements: node.elements.map(v => this[v.type](reducer, v)) }); 361 | }, 362 | 363 | ThisExpression(reducer, node) { 364 | return reducer.reduceThisExpression(node); 365 | }, 366 | 367 | ThrowStatement(reducer, node) { 368 | return reducer.reduceThrowStatement(node, { expression: this[node.expression.type](reducer, node.expression) }); 369 | }, 370 | 371 | TryCatchStatement(reducer, node) { 372 | return reducer.reduceTryCatchStatement(node, { body: this.Block(reducer, node.body), catchClause: this.CatchClause(reducer, node.catchClause) }); 373 | }, 374 | 375 | TryFinallyStatement(reducer, node) { 376 | return reducer.reduceTryFinallyStatement(node, { body: this.Block(reducer, node.body), catchClause: node.catchClause && this.CatchClause(reducer, node.catchClause), finalizer: this.Block(reducer, node.finalizer) }); 377 | }, 378 | 379 | UnaryExpression(reducer, node) { 380 | return reducer.reduceUnaryExpression(node, { operand: this[node.operand.type](reducer, node.operand) }); 381 | }, 382 | 383 | UpdateExpression(reducer, node) { 384 | return reducer.reduceUpdateExpression(node, { operand: this[node.operand.type](reducer, node.operand) }); 385 | }, 386 | 387 | VariableDeclaration(reducer, node) { 388 | return reducer.reduceVariableDeclaration(node, { declarators: node.declarators.map(v => this.VariableDeclarator(reducer, v)) }); 389 | }, 390 | 391 | VariableDeclarationStatement(reducer, node) { 392 | return reducer.reduceVariableDeclarationStatement(node, { declaration: this.VariableDeclaration(reducer, node.declaration) }); 393 | }, 394 | 395 | VariableDeclarator(reducer, node) { 396 | return reducer.reduceVariableDeclarator(node, { binding: this[node.binding.type](reducer, node.binding), init: node.init && this[node.init.type](reducer, node.init) }); 397 | }, 398 | 399 | WhileStatement(reducer, node) { 400 | return reducer.reduceWhileStatement(node, { test: this[node.test.type](reducer, node.test), body: this[node.body.type](reducer, node.body) }); 401 | }, 402 | 403 | WithStatement(reducer, node) { 404 | return reducer.reduceWithStatement(node, { object: this[node.object.type](reducer, node.object), body: this[node.body.type](reducer, node.body) }); 405 | }, 406 | 407 | YieldExpression(reducer, node) { 408 | return reducer.reduceYieldExpression(node, { expression: node.expression && this[node.expression.type](reducer, node.expression) }); 409 | }, 410 | 411 | YieldGeneratorExpression(reducer, node) { 412 | return reducer.reduceYieldGeneratorExpression(node, { expression: this[node.expression.type](reducer, node.expression) }); 413 | }, 414 | }; 415 | 416 | module.exports = function reduce(reducer, node) { 417 | return director[node.type](reducer, node); 418 | }; 419 | -------------------------------------------------------------------------------- /gen/lazy-clone-reducer.js: -------------------------------------------------------------------------------- 1 | // Generated by generate-lazy-clone-reducer.js 2 | /** 3 | * Copyright 2018 Shape Security, Inc. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License") 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | const Shift = require('shift-ast'); 19 | 20 | module.exports = class LazyCloneReducer { 21 | reduceArrayAssignmentTarget(node, { elements, rest }) { 22 | if ((node.elements.length === elements.length && node.elements.every((v, i) => v === elements[i])) && node.rest === rest) { 23 | return node; 24 | } 25 | return new Shift.ArrayAssignmentTarget({ elements, rest }); 26 | } 27 | 28 | reduceArrayBinding(node, { elements, rest }) { 29 | if ((node.elements.length === elements.length && node.elements.every((v, i) => v === elements[i])) && node.rest === rest) { 30 | return node; 31 | } 32 | return new Shift.ArrayBinding({ elements, rest }); 33 | } 34 | 35 | reduceArrayExpression(node, { elements }) { 36 | if ((node.elements.length === elements.length && node.elements.every((v, i) => v === elements[i]))) { 37 | return node; 38 | } 39 | return new Shift.ArrayExpression({ elements }); 40 | } 41 | 42 | reduceArrowExpression(node, { params, body }) { 43 | if (node.params === params && node.body === body) { 44 | return node; 45 | } 46 | return new Shift.ArrowExpression({ isAsync: node.isAsync, params, body }); 47 | } 48 | 49 | reduceAssignmentExpression(node, { binding, expression }) { 50 | if (node.binding === binding && node.expression === expression) { 51 | return node; 52 | } 53 | return new Shift.AssignmentExpression({ binding, expression }); 54 | } 55 | 56 | reduceAssignmentTargetIdentifier(node) { 57 | return node; 58 | } 59 | 60 | reduceAssignmentTargetPropertyIdentifier(node, { binding, init }) { 61 | if (node.binding === binding && node.init === init) { 62 | return node; 63 | } 64 | return new Shift.AssignmentTargetPropertyIdentifier({ binding, init }); 65 | } 66 | 67 | reduceAssignmentTargetPropertyProperty(node, { name, binding }) { 68 | if (node.name === name && node.binding === binding) { 69 | return node; 70 | } 71 | return new Shift.AssignmentTargetPropertyProperty({ name, binding }); 72 | } 73 | 74 | reduceAssignmentTargetWithDefault(node, { binding, init }) { 75 | if (node.binding === binding && node.init === init) { 76 | return node; 77 | } 78 | return new Shift.AssignmentTargetWithDefault({ binding, init }); 79 | } 80 | 81 | reduceAwaitExpression(node, { expression }) { 82 | if (node.expression === expression) { 83 | return node; 84 | } 85 | return new Shift.AwaitExpression({ expression }); 86 | } 87 | 88 | reduceBinaryExpression(node, { left, right }) { 89 | if (node.left === left && node.right === right) { 90 | return node; 91 | } 92 | return new Shift.BinaryExpression({ left, operator: node.operator, right }); 93 | } 94 | 95 | reduceBindingIdentifier(node) { 96 | return node; 97 | } 98 | 99 | reduceBindingPropertyIdentifier(node, { binding, init }) { 100 | if (node.binding === binding && node.init === init) { 101 | return node; 102 | } 103 | return new Shift.BindingPropertyIdentifier({ binding, init }); 104 | } 105 | 106 | reduceBindingPropertyProperty(node, { name, binding }) { 107 | if (node.name === name && node.binding === binding) { 108 | return node; 109 | } 110 | return new Shift.BindingPropertyProperty({ name, binding }); 111 | } 112 | 113 | reduceBindingWithDefault(node, { binding, init }) { 114 | if (node.binding === binding && node.init === init) { 115 | return node; 116 | } 117 | return new Shift.BindingWithDefault({ binding, init }); 118 | } 119 | 120 | reduceBlock(node, { statements }) { 121 | if ((node.statements.length === statements.length && node.statements.every((v, i) => v === statements[i]))) { 122 | return node; 123 | } 124 | return new Shift.Block({ statements }); 125 | } 126 | 127 | reduceBlockStatement(node, { block }) { 128 | if (node.block === block) { 129 | return node; 130 | } 131 | return new Shift.BlockStatement({ block }); 132 | } 133 | 134 | reduceBreakStatement(node) { 135 | return node; 136 | } 137 | 138 | reduceCallExpression(node, { callee, arguments: _arguments }) { 139 | if (node.callee === callee && (node.arguments.length === _arguments.length && node.arguments.every((v, i) => v === _arguments[i]))) { 140 | return node; 141 | } 142 | return new Shift.CallExpression({ callee, arguments: _arguments }); 143 | } 144 | 145 | reduceCatchClause(node, { binding, body }) { 146 | if (node.binding === binding && node.body === body) { 147 | return node; 148 | } 149 | return new Shift.CatchClause({ binding, body }); 150 | } 151 | 152 | reduceClassDeclaration(node, { name, super: _super, elements }) { 153 | if (node.name === name && node.super === _super && (node.elements.length === elements.length && node.elements.every((v, i) => v === elements[i]))) { 154 | return node; 155 | } 156 | return new Shift.ClassDeclaration({ name, super: _super, elements }); 157 | } 158 | 159 | reduceClassElement(node, { method }) { 160 | if (node.method === method) { 161 | return node; 162 | } 163 | return new Shift.ClassElement({ isStatic: node.isStatic, method }); 164 | } 165 | 166 | reduceClassExpression(node, { name, super: _super, elements }) { 167 | if (node.name === name && node.super === _super && (node.elements.length === elements.length && node.elements.every((v, i) => v === elements[i]))) { 168 | return node; 169 | } 170 | return new Shift.ClassExpression({ name, super: _super, elements }); 171 | } 172 | 173 | reduceCompoundAssignmentExpression(node, { binding, expression }) { 174 | if (node.binding === binding && node.expression === expression) { 175 | return node; 176 | } 177 | return new Shift.CompoundAssignmentExpression({ binding, operator: node.operator, expression }); 178 | } 179 | 180 | reduceComputedMemberAssignmentTarget(node, { object, expression }) { 181 | if (node.object === object && node.expression === expression) { 182 | return node; 183 | } 184 | return new Shift.ComputedMemberAssignmentTarget({ object, expression }); 185 | } 186 | 187 | reduceComputedMemberExpression(node, { object, expression }) { 188 | if (node.object === object && node.expression === expression) { 189 | return node; 190 | } 191 | return new Shift.ComputedMemberExpression({ object, expression }); 192 | } 193 | 194 | reduceComputedPropertyName(node, { expression }) { 195 | if (node.expression === expression) { 196 | return node; 197 | } 198 | return new Shift.ComputedPropertyName({ expression }); 199 | } 200 | 201 | reduceConditionalExpression(node, { test, consequent, alternate }) { 202 | if (node.test === test && node.consequent === consequent && node.alternate === alternate) { 203 | return node; 204 | } 205 | return new Shift.ConditionalExpression({ test, consequent, alternate }); 206 | } 207 | 208 | reduceContinueStatement(node) { 209 | return node; 210 | } 211 | 212 | reduceDataProperty(node, { name, expression }) { 213 | if (node.name === name && node.expression === expression) { 214 | return node; 215 | } 216 | return new Shift.DataProperty({ name, expression }); 217 | } 218 | 219 | reduceDebuggerStatement(node) { 220 | return node; 221 | } 222 | 223 | reduceDirective(node) { 224 | return node; 225 | } 226 | 227 | reduceDoWhileStatement(node, { body, test }) { 228 | if (node.body === body && node.test === test) { 229 | return node; 230 | } 231 | return new Shift.DoWhileStatement({ body, test }); 232 | } 233 | 234 | reduceEmptyStatement(node) { 235 | return node; 236 | } 237 | 238 | reduceExport(node, { declaration }) { 239 | if (node.declaration === declaration) { 240 | return node; 241 | } 242 | return new Shift.Export({ declaration }); 243 | } 244 | 245 | reduceExportAllFrom(node) { 246 | return node; 247 | } 248 | 249 | reduceExportDefault(node, { body }) { 250 | if (node.body === body) { 251 | return node; 252 | } 253 | return new Shift.ExportDefault({ body }); 254 | } 255 | 256 | reduceExportFrom(node, { namedExports }) { 257 | if ((node.namedExports.length === namedExports.length && node.namedExports.every((v, i) => v === namedExports[i]))) { 258 | return node; 259 | } 260 | return new Shift.ExportFrom({ namedExports, moduleSpecifier: node.moduleSpecifier }); 261 | } 262 | 263 | reduceExportFromSpecifier(node) { 264 | return node; 265 | } 266 | 267 | reduceExportLocalSpecifier(node, { name }) { 268 | if (node.name === name) { 269 | return node; 270 | } 271 | return new Shift.ExportLocalSpecifier({ name, exportedName: node.exportedName }); 272 | } 273 | 274 | reduceExportLocals(node, { namedExports }) { 275 | if ((node.namedExports.length === namedExports.length && node.namedExports.every((v, i) => v === namedExports[i]))) { 276 | return node; 277 | } 278 | return new Shift.ExportLocals({ namedExports }); 279 | } 280 | 281 | reduceExpressionStatement(node, { expression }) { 282 | if (node.expression === expression) { 283 | return node; 284 | } 285 | return new Shift.ExpressionStatement({ expression }); 286 | } 287 | 288 | reduceForAwaitStatement(node, { left, right, body }) { 289 | if (node.left === left && node.right === right && node.body === body) { 290 | return node; 291 | } 292 | return new Shift.ForAwaitStatement({ left, right, body }); 293 | } 294 | 295 | reduceForInStatement(node, { left, right, body }) { 296 | if (node.left === left && node.right === right && node.body === body) { 297 | return node; 298 | } 299 | return new Shift.ForInStatement({ left, right, body }); 300 | } 301 | 302 | reduceForOfStatement(node, { left, right, body }) { 303 | if (node.left === left && node.right === right && node.body === body) { 304 | return node; 305 | } 306 | return new Shift.ForOfStatement({ left, right, body }); 307 | } 308 | 309 | reduceForStatement(node, { init, test, update, body }) { 310 | if (node.init === init && node.test === test && node.update === update && node.body === body) { 311 | return node; 312 | } 313 | return new Shift.ForStatement({ init, test, update, body }); 314 | } 315 | 316 | reduceFormalParameters(node, { items, rest }) { 317 | if ((node.items.length === items.length && node.items.every((v, i) => v === items[i])) && node.rest === rest) { 318 | return node; 319 | } 320 | return new Shift.FormalParameters({ items, rest }); 321 | } 322 | 323 | reduceFunctionBody(node, { directives, statements }) { 324 | if ((node.directives.length === directives.length && node.directives.every((v, i) => v === directives[i])) && (node.statements.length === statements.length && node.statements.every((v, i) => v === statements[i]))) { 325 | return node; 326 | } 327 | return new Shift.FunctionBody({ directives, statements }); 328 | } 329 | 330 | reduceFunctionDeclaration(node, { name, params, body }) { 331 | if (node.name === name && node.params === params && node.body === body) { 332 | return node; 333 | } 334 | return new Shift.FunctionDeclaration({ isAsync: node.isAsync, isGenerator: node.isGenerator, name, params, body }); 335 | } 336 | 337 | reduceFunctionExpression(node, { name, params, body }) { 338 | if (node.name === name && node.params === params && node.body === body) { 339 | return node; 340 | } 341 | return new Shift.FunctionExpression({ isAsync: node.isAsync, isGenerator: node.isGenerator, name, params, body }); 342 | } 343 | 344 | reduceGetter(node, { name, body }) { 345 | if (node.name === name && node.body === body) { 346 | return node; 347 | } 348 | return new Shift.Getter({ name, body }); 349 | } 350 | 351 | reduceIdentifierExpression(node) { 352 | return node; 353 | } 354 | 355 | reduceIfStatement(node, { test, consequent, alternate }) { 356 | if (node.test === test && node.consequent === consequent && node.alternate === alternate) { 357 | return node; 358 | } 359 | return new Shift.IfStatement({ test, consequent, alternate }); 360 | } 361 | 362 | reduceImport(node, { defaultBinding, namedImports }) { 363 | if (node.defaultBinding === defaultBinding && (node.namedImports.length === namedImports.length && node.namedImports.every((v, i) => v === namedImports[i]))) { 364 | return node; 365 | } 366 | return new Shift.Import({ defaultBinding, namedImports, moduleSpecifier: node.moduleSpecifier }); 367 | } 368 | 369 | reduceImportNamespace(node, { defaultBinding, namespaceBinding }) { 370 | if (node.defaultBinding === defaultBinding && node.namespaceBinding === namespaceBinding) { 371 | return node; 372 | } 373 | return new Shift.ImportNamespace({ defaultBinding, namespaceBinding, moduleSpecifier: node.moduleSpecifier }); 374 | } 375 | 376 | reduceImportSpecifier(node, { binding }) { 377 | if (node.binding === binding) { 378 | return node; 379 | } 380 | return new Shift.ImportSpecifier({ name: node.name, binding }); 381 | } 382 | 383 | reduceLabeledStatement(node, { body }) { 384 | if (node.body === body) { 385 | return node; 386 | } 387 | return new Shift.LabeledStatement({ label: node.label, body }); 388 | } 389 | 390 | reduceLiteralBooleanExpression(node) { 391 | return node; 392 | } 393 | 394 | reduceLiteralInfinityExpression(node) { 395 | return node; 396 | } 397 | 398 | reduceLiteralNullExpression(node) { 399 | return node; 400 | } 401 | 402 | reduceLiteralNumericExpression(node) { 403 | return node; 404 | } 405 | 406 | reduceLiteralRegExpExpression(node) { 407 | return node; 408 | } 409 | 410 | reduceLiteralStringExpression(node) { 411 | return node; 412 | } 413 | 414 | reduceMethod(node, { name, params, body }) { 415 | if (node.name === name && node.params === params && node.body === body) { 416 | return node; 417 | } 418 | return new Shift.Method({ isAsync: node.isAsync, isGenerator: node.isGenerator, name, params, body }); 419 | } 420 | 421 | reduceModule(node, { directives, items }) { 422 | if ((node.directives.length === directives.length && node.directives.every((v, i) => v === directives[i])) && (node.items.length === items.length && node.items.every((v, i) => v === items[i]))) { 423 | return node; 424 | } 425 | return new Shift.Module({ directives, items }); 426 | } 427 | 428 | reduceNewExpression(node, { callee, arguments: _arguments }) { 429 | if (node.callee === callee && (node.arguments.length === _arguments.length && node.arguments.every((v, i) => v === _arguments[i]))) { 430 | return node; 431 | } 432 | return new Shift.NewExpression({ callee, arguments: _arguments }); 433 | } 434 | 435 | reduceNewTargetExpression(node) { 436 | return node; 437 | } 438 | 439 | reduceObjectAssignmentTarget(node, { properties, rest }) { 440 | if ((node.properties.length === properties.length && node.properties.every((v, i) => v === properties[i])) && node.rest === rest) { 441 | return node; 442 | } 443 | return new Shift.ObjectAssignmentTarget({ properties, rest }); 444 | } 445 | 446 | reduceObjectBinding(node, { properties, rest }) { 447 | if ((node.properties.length === properties.length && node.properties.every((v, i) => v === properties[i])) && node.rest === rest) { 448 | return node; 449 | } 450 | return new Shift.ObjectBinding({ properties, rest }); 451 | } 452 | 453 | reduceObjectExpression(node, { properties }) { 454 | if ((node.properties.length === properties.length && node.properties.every((v, i) => v === properties[i]))) { 455 | return node; 456 | } 457 | return new Shift.ObjectExpression({ properties }); 458 | } 459 | 460 | reduceReturnStatement(node, { expression }) { 461 | if (node.expression === expression) { 462 | return node; 463 | } 464 | return new Shift.ReturnStatement({ expression }); 465 | } 466 | 467 | reduceScript(node, { directives, statements }) { 468 | if ((node.directives.length === directives.length && node.directives.every((v, i) => v === directives[i])) && (node.statements.length === statements.length && node.statements.every((v, i) => v === statements[i]))) { 469 | return node; 470 | } 471 | return new Shift.Script({ directives, statements }); 472 | } 473 | 474 | reduceSetter(node, { name, param, body }) { 475 | if (node.name === name && node.param === param && node.body === body) { 476 | return node; 477 | } 478 | return new Shift.Setter({ name, param, body }); 479 | } 480 | 481 | reduceShorthandProperty(node, { name }) { 482 | if (node.name === name) { 483 | return node; 484 | } 485 | return new Shift.ShorthandProperty({ name }); 486 | } 487 | 488 | reduceSpreadElement(node, { expression }) { 489 | if (node.expression === expression) { 490 | return node; 491 | } 492 | return new Shift.SpreadElement({ expression }); 493 | } 494 | 495 | reduceSpreadProperty(node, { expression }) { 496 | if (node.expression === expression) { 497 | return node; 498 | } 499 | return new Shift.SpreadProperty({ expression }); 500 | } 501 | 502 | reduceStaticMemberAssignmentTarget(node, { object }) { 503 | if (node.object === object) { 504 | return node; 505 | } 506 | return new Shift.StaticMemberAssignmentTarget({ object, property: node.property }); 507 | } 508 | 509 | reduceStaticMemberExpression(node, { object }) { 510 | if (node.object === object) { 511 | return node; 512 | } 513 | return new Shift.StaticMemberExpression({ object, property: node.property }); 514 | } 515 | 516 | reduceStaticPropertyName(node) { 517 | return node; 518 | } 519 | 520 | reduceSuper(node) { 521 | return node; 522 | } 523 | 524 | reduceSwitchCase(node, { test, consequent }) { 525 | if (node.test === test && (node.consequent.length === consequent.length && node.consequent.every((v, i) => v === consequent[i]))) { 526 | return node; 527 | } 528 | return new Shift.SwitchCase({ test, consequent }); 529 | } 530 | 531 | reduceSwitchDefault(node, { consequent }) { 532 | if ((node.consequent.length === consequent.length && node.consequent.every((v, i) => v === consequent[i]))) { 533 | return node; 534 | } 535 | return new Shift.SwitchDefault({ consequent }); 536 | } 537 | 538 | reduceSwitchStatement(node, { discriminant, cases }) { 539 | if (node.discriminant === discriminant && (node.cases.length === cases.length && node.cases.every((v, i) => v === cases[i]))) { 540 | return node; 541 | } 542 | return new Shift.SwitchStatement({ discriminant, cases }); 543 | } 544 | 545 | reduceSwitchStatementWithDefault(node, { discriminant, preDefaultCases, defaultCase, postDefaultCases }) { 546 | if (node.discriminant === discriminant && (node.preDefaultCases.length === preDefaultCases.length && node.preDefaultCases.every((v, i) => v === preDefaultCases[i])) && node.defaultCase === defaultCase && (node.postDefaultCases.length === postDefaultCases.length && node.postDefaultCases.every((v, i) => v === postDefaultCases[i]))) { 547 | return node; 548 | } 549 | return new Shift.SwitchStatementWithDefault({ discriminant, preDefaultCases, defaultCase, postDefaultCases }); 550 | } 551 | 552 | reduceTemplateElement(node) { 553 | return node; 554 | } 555 | 556 | reduceTemplateExpression(node, { tag, elements }) { 557 | if (node.tag === tag && (node.elements.length === elements.length && node.elements.every((v, i) => v === elements[i]))) { 558 | return node; 559 | } 560 | return new Shift.TemplateExpression({ tag, elements }); 561 | } 562 | 563 | reduceThisExpression(node) { 564 | return node; 565 | } 566 | 567 | reduceThrowStatement(node, { expression }) { 568 | if (node.expression === expression) { 569 | return node; 570 | } 571 | return new Shift.ThrowStatement({ expression }); 572 | } 573 | 574 | reduceTryCatchStatement(node, { body, catchClause }) { 575 | if (node.body === body && node.catchClause === catchClause) { 576 | return node; 577 | } 578 | return new Shift.TryCatchStatement({ body, catchClause }); 579 | } 580 | 581 | reduceTryFinallyStatement(node, { body, catchClause, finalizer }) { 582 | if (node.body === body && node.catchClause === catchClause && node.finalizer === finalizer) { 583 | return node; 584 | } 585 | return new Shift.TryFinallyStatement({ body, catchClause, finalizer }); 586 | } 587 | 588 | reduceUnaryExpression(node, { operand }) { 589 | if (node.operand === operand) { 590 | return node; 591 | } 592 | return new Shift.UnaryExpression({ operator: node.operator, operand }); 593 | } 594 | 595 | reduceUpdateExpression(node, { operand }) { 596 | if (node.operand === operand) { 597 | return node; 598 | } 599 | return new Shift.UpdateExpression({ isPrefix: node.isPrefix, operator: node.operator, operand }); 600 | } 601 | 602 | reduceVariableDeclaration(node, { declarators }) { 603 | if ((node.declarators.length === declarators.length && node.declarators.every((v, i) => v === declarators[i]))) { 604 | return node; 605 | } 606 | return new Shift.VariableDeclaration({ kind: node.kind, declarators }); 607 | } 608 | 609 | reduceVariableDeclarationStatement(node, { declaration }) { 610 | if (node.declaration === declaration) { 611 | return node; 612 | } 613 | return new Shift.VariableDeclarationStatement({ declaration }); 614 | } 615 | 616 | reduceVariableDeclarator(node, { binding, init }) { 617 | if (node.binding === binding && node.init === init) { 618 | return node; 619 | } 620 | return new Shift.VariableDeclarator({ binding, init }); 621 | } 622 | 623 | reduceWhileStatement(node, { test, body }) { 624 | if (node.test === test && node.body === body) { 625 | return node; 626 | } 627 | return new Shift.WhileStatement({ test, body }); 628 | } 629 | 630 | reduceWithStatement(node, { object, body }) { 631 | if (node.object === object && node.body === body) { 632 | return node; 633 | } 634 | return new Shift.WithStatement({ object, body }); 635 | } 636 | 637 | reduceYieldExpression(node, { expression }) { 638 | if (node.expression === expression) { 639 | return node; 640 | } 641 | return new Shift.YieldExpression({ expression }); 642 | } 643 | 644 | reduceYieldGeneratorExpression(node, { expression }) { 645 | if (node.expression === expression) { 646 | return node; 647 | } 648 | return new Shift.YieldGeneratorExpression({ expression }); 649 | } 650 | }; 651 | -------------------------------------------------------------------------------- /gen/monoidal-reducer.js: -------------------------------------------------------------------------------- 1 | // Generated by generate-monoidal-reducer.js 2 | /** 3 | * Copyright 2018 Shape Security, Inc. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License") 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | const Shift = require('shift-ast'); 19 | 20 | module.exports = class MonoidalReducer { 21 | constructor(monoid) { 22 | let identity = monoid.empty(); 23 | this.identity = identity; 24 | let concat; 25 | if (monoid.prototype && typeof monoid.prototype.concat === 'function') { 26 | concat = Function.prototype.call.bind(monoid.prototype.concat); 27 | } else if (typeof monoid.concat === 'function') { 28 | concat = monoid.concat; 29 | } else { 30 | throw new TypeError('Monoid must provide a `concat` method'); 31 | } 32 | this.append = (...args) => args.reduce(concat, identity); 33 | } 34 | 35 | reduceArrayAssignmentTarget(node, { elements, rest }) { 36 | return this.append(...elements.filter(n => n != null), rest == null ? this.identity : rest); 37 | } 38 | 39 | reduceArrayBinding(node, { elements, rest }) { 40 | return this.append(...elements.filter(n => n != null), rest == null ? this.identity : rest); 41 | } 42 | 43 | reduceArrayExpression(node, { elements }) { 44 | return this.append(...elements.filter(n => n != null)); 45 | } 46 | 47 | reduceArrowExpression(node, { params, body }) { 48 | return this.append(params, body); 49 | } 50 | 51 | reduceAssignmentExpression(node, { binding, expression }) { 52 | return this.append(binding, expression); 53 | } 54 | 55 | reduceAssignmentTargetIdentifier(node) { 56 | return this.identity; 57 | } 58 | 59 | reduceAssignmentTargetPropertyIdentifier(node, { binding, init }) { 60 | return this.append(binding, init == null ? this.identity : init); 61 | } 62 | 63 | reduceAssignmentTargetPropertyProperty(node, { name, binding }) { 64 | return this.append(name, binding); 65 | } 66 | 67 | reduceAssignmentTargetWithDefault(node, { binding, init }) { 68 | return this.append(binding, init); 69 | } 70 | 71 | reduceAwaitExpression(node, { expression }) { 72 | return expression; 73 | } 74 | 75 | reduceBinaryExpression(node, { left, right }) { 76 | return this.append(left, right); 77 | } 78 | 79 | reduceBindingIdentifier(node) { 80 | return this.identity; 81 | } 82 | 83 | reduceBindingPropertyIdentifier(node, { binding, init }) { 84 | return this.append(binding, init == null ? this.identity : init); 85 | } 86 | 87 | reduceBindingPropertyProperty(node, { name, binding }) { 88 | return this.append(name, binding); 89 | } 90 | 91 | reduceBindingWithDefault(node, { binding, init }) { 92 | return this.append(binding, init); 93 | } 94 | 95 | reduceBlock(node, { statements }) { 96 | return this.append(...statements); 97 | } 98 | 99 | reduceBlockStatement(node, { block }) { 100 | return block; 101 | } 102 | 103 | reduceBreakStatement(node) { 104 | return this.identity; 105 | } 106 | 107 | reduceCallExpression(node, { callee, arguments: _arguments }) { 108 | return this.append(callee, ..._arguments); 109 | } 110 | 111 | reduceCatchClause(node, { binding, body }) { 112 | return this.append(binding == null ? this.identity : binding, body); 113 | } 114 | 115 | reduceClassDeclaration(node, { name, super: _super, elements }) { 116 | return this.append(name, _super == null ? this.identity : _super, ...elements); 117 | } 118 | 119 | reduceClassElement(node, { method }) { 120 | return method; 121 | } 122 | 123 | reduceClassExpression(node, { name, super: _super, elements }) { 124 | return this.append(name == null ? this.identity : name, _super == null ? this.identity : _super, ...elements); 125 | } 126 | 127 | reduceCompoundAssignmentExpression(node, { binding, expression }) { 128 | return this.append(binding, expression); 129 | } 130 | 131 | reduceComputedMemberAssignmentTarget(node, { object, expression }) { 132 | return this.append(object, expression); 133 | } 134 | 135 | reduceComputedMemberExpression(node, { object, expression }) { 136 | return this.append(object, expression); 137 | } 138 | 139 | reduceComputedPropertyName(node, { expression }) { 140 | return expression; 141 | } 142 | 143 | reduceConditionalExpression(node, { test, consequent, alternate }) { 144 | return this.append(test, consequent, alternate); 145 | } 146 | 147 | reduceContinueStatement(node) { 148 | return this.identity; 149 | } 150 | 151 | reduceDataProperty(node, { name, expression }) { 152 | return this.append(name, expression); 153 | } 154 | 155 | reduceDebuggerStatement(node) { 156 | return this.identity; 157 | } 158 | 159 | reduceDirective(node) { 160 | return this.identity; 161 | } 162 | 163 | reduceDoWhileStatement(node, { body, test }) { 164 | return this.append(body, test); 165 | } 166 | 167 | reduceEmptyStatement(node) { 168 | return this.identity; 169 | } 170 | 171 | reduceExport(node, { declaration }) { 172 | return declaration; 173 | } 174 | 175 | reduceExportAllFrom(node) { 176 | return this.identity; 177 | } 178 | 179 | reduceExportDefault(node, { body }) { 180 | return body; 181 | } 182 | 183 | reduceExportFrom(node, { namedExports }) { 184 | return this.append(...namedExports); 185 | } 186 | 187 | reduceExportFromSpecifier(node) { 188 | return this.identity; 189 | } 190 | 191 | reduceExportLocalSpecifier(node, { name }) { 192 | return name; 193 | } 194 | 195 | reduceExportLocals(node, { namedExports }) { 196 | return this.append(...namedExports); 197 | } 198 | 199 | reduceExpressionStatement(node, { expression }) { 200 | return expression; 201 | } 202 | 203 | reduceForAwaitStatement(node, { left, right, body }) { 204 | return this.append(left, right, body); 205 | } 206 | 207 | reduceForInStatement(node, { left, right, body }) { 208 | return this.append(left, right, body); 209 | } 210 | 211 | reduceForOfStatement(node, { left, right, body }) { 212 | return this.append(left, right, body); 213 | } 214 | 215 | reduceForStatement(node, { init, test, update, body }) { 216 | return this.append(init == null ? this.identity : init, test == null ? this.identity : test, update == null ? this.identity : update, body); 217 | } 218 | 219 | reduceFormalParameters(node, { items, rest }) { 220 | return this.append(...items, rest == null ? this.identity : rest); 221 | } 222 | 223 | reduceFunctionBody(node, { directives, statements }) { 224 | return this.append(...directives, ...statements); 225 | } 226 | 227 | reduceFunctionDeclaration(node, { name, params, body }) { 228 | return this.append(name, params, body); 229 | } 230 | 231 | reduceFunctionExpression(node, { name, params, body }) { 232 | return this.append(name == null ? this.identity : name, params, body); 233 | } 234 | 235 | reduceGetter(node, { name, body }) { 236 | return this.append(name, body); 237 | } 238 | 239 | reduceIdentifierExpression(node) { 240 | return this.identity; 241 | } 242 | 243 | reduceIfStatement(node, { test, consequent, alternate }) { 244 | return this.append(test, consequent, alternate == null ? this.identity : alternate); 245 | } 246 | 247 | reduceImport(node, { defaultBinding, namedImports }) { 248 | return this.append(defaultBinding == null ? this.identity : defaultBinding, ...namedImports); 249 | } 250 | 251 | reduceImportNamespace(node, { defaultBinding, namespaceBinding }) { 252 | return this.append(defaultBinding == null ? this.identity : defaultBinding, namespaceBinding); 253 | } 254 | 255 | reduceImportSpecifier(node, { binding }) { 256 | return binding; 257 | } 258 | 259 | reduceLabeledStatement(node, { body }) { 260 | return body; 261 | } 262 | 263 | reduceLiteralBooleanExpression(node) { 264 | return this.identity; 265 | } 266 | 267 | reduceLiteralInfinityExpression(node) { 268 | return this.identity; 269 | } 270 | 271 | reduceLiteralNullExpression(node) { 272 | return this.identity; 273 | } 274 | 275 | reduceLiteralNumericExpression(node) { 276 | return this.identity; 277 | } 278 | 279 | reduceLiteralRegExpExpression(node) { 280 | return this.identity; 281 | } 282 | 283 | reduceLiteralStringExpression(node) { 284 | return this.identity; 285 | } 286 | 287 | reduceMethod(node, { name, params, body }) { 288 | return this.append(name, params, body); 289 | } 290 | 291 | reduceModule(node, { directives, items }) { 292 | return this.append(...directives, ...items); 293 | } 294 | 295 | reduceNewExpression(node, { callee, arguments: _arguments }) { 296 | return this.append(callee, ..._arguments); 297 | } 298 | 299 | reduceNewTargetExpression(node) { 300 | return this.identity; 301 | } 302 | 303 | reduceObjectAssignmentTarget(node, { properties, rest }) { 304 | return this.append(...properties, rest == null ? this.identity : rest); 305 | } 306 | 307 | reduceObjectBinding(node, { properties, rest }) { 308 | return this.append(...properties, rest == null ? this.identity : rest); 309 | } 310 | 311 | reduceObjectExpression(node, { properties }) { 312 | return this.append(...properties); 313 | } 314 | 315 | reduceReturnStatement(node, { expression }) { 316 | return expression == null ? this.identity : expression; 317 | } 318 | 319 | reduceScript(node, { directives, statements }) { 320 | return this.append(...directives, ...statements); 321 | } 322 | 323 | reduceSetter(node, { name, param, body }) { 324 | return this.append(name, param, body); 325 | } 326 | 327 | reduceShorthandProperty(node, { name }) { 328 | return name; 329 | } 330 | 331 | reduceSpreadElement(node, { expression }) { 332 | return expression; 333 | } 334 | 335 | reduceSpreadProperty(node, { expression }) { 336 | return expression; 337 | } 338 | 339 | reduceStaticMemberAssignmentTarget(node, { object }) { 340 | return object; 341 | } 342 | 343 | reduceStaticMemberExpression(node, { object }) { 344 | return object; 345 | } 346 | 347 | reduceStaticPropertyName(node) { 348 | return this.identity; 349 | } 350 | 351 | reduceSuper(node) { 352 | return this.identity; 353 | } 354 | 355 | reduceSwitchCase(node, { test, consequent }) { 356 | return this.append(test, ...consequent); 357 | } 358 | 359 | reduceSwitchDefault(node, { consequent }) { 360 | return this.append(...consequent); 361 | } 362 | 363 | reduceSwitchStatement(node, { discriminant, cases }) { 364 | return this.append(discriminant, ...cases); 365 | } 366 | 367 | reduceSwitchStatementWithDefault(node, { discriminant, preDefaultCases, defaultCase, postDefaultCases }) { 368 | return this.append(discriminant, ...preDefaultCases, defaultCase, ...postDefaultCases); 369 | } 370 | 371 | reduceTemplateElement(node) { 372 | return this.identity; 373 | } 374 | 375 | reduceTemplateExpression(node, { tag, elements }) { 376 | return this.append(tag == null ? this.identity : tag, ...elements); 377 | } 378 | 379 | reduceThisExpression(node) { 380 | return this.identity; 381 | } 382 | 383 | reduceThrowStatement(node, { expression }) { 384 | return expression; 385 | } 386 | 387 | reduceTryCatchStatement(node, { body, catchClause }) { 388 | return this.append(body, catchClause); 389 | } 390 | 391 | reduceTryFinallyStatement(node, { body, catchClause, finalizer }) { 392 | return this.append(body, catchClause == null ? this.identity : catchClause, finalizer); 393 | } 394 | 395 | reduceUnaryExpression(node, { operand }) { 396 | return operand; 397 | } 398 | 399 | reduceUpdateExpression(node, { operand }) { 400 | return operand; 401 | } 402 | 403 | reduceVariableDeclaration(node, { declarators }) { 404 | return this.append(...declarators); 405 | } 406 | 407 | reduceVariableDeclarationStatement(node, { declaration }) { 408 | return declaration; 409 | } 410 | 411 | reduceVariableDeclarator(node, { binding, init }) { 412 | return this.append(binding, init == null ? this.identity : init); 413 | } 414 | 415 | reduceWhileStatement(node, { test, body }) { 416 | return this.append(test, body); 417 | } 418 | 419 | reduceWithStatement(node, { object, body }) { 420 | return this.append(object, body); 421 | } 422 | 423 | reduceYieldExpression(node, { expression }) { 424 | return expression == null ? this.identity : expression; 425 | } 426 | 427 | reduceYieldGeneratorExpression(node, { expression }) { 428 | return expression; 429 | } 430 | }; 431 | -------------------------------------------------------------------------------- /gen/thunked-director.js: -------------------------------------------------------------------------------- 1 | // Generated by generate-director.js 2 | /** 3 | * Copyright 2018 Shape Security, Inc. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License") 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | const director = { 19 | ArrayAssignmentTarget(reducer, node) { 20 | return reducer.reduceArrayAssignmentTarget(node, { elements: node.elements.map(v => v && (() => this[v.type](reducer, v))), rest: node.rest && (() => this[node.rest.type](reducer, node.rest)) }); 21 | }, 22 | 23 | ArrayBinding(reducer, node) { 24 | return reducer.reduceArrayBinding(node, { elements: node.elements.map(v => v && (() => this[v.type](reducer, v))), rest: node.rest && (() => this[node.rest.type](reducer, node.rest)) }); 25 | }, 26 | 27 | ArrayExpression(reducer, node) { 28 | return reducer.reduceArrayExpression(node, { elements: node.elements.map(v => v && (() => this[v.type](reducer, v))) }); 29 | }, 30 | 31 | ArrowExpression(reducer, node) { 32 | return reducer.reduceArrowExpression(node, { params: (() => this.FormalParameters(reducer, node.params)), body: (() => this[node.body.type](reducer, node.body)) }); 33 | }, 34 | 35 | AssignmentExpression(reducer, node) { 36 | return reducer.reduceAssignmentExpression(node, { binding: (() => this[node.binding.type](reducer, node.binding)), expression: (() => this[node.expression.type](reducer, node.expression)) }); 37 | }, 38 | 39 | AssignmentTargetIdentifier(reducer, node) { 40 | return reducer.reduceAssignmentTargetIdentifier(node); 41 | }, 42 | 43 | AssignmentTargetPropertyIdentifier(reducer, node) { 44 | return reducer.reduceAssignmentTargetPropertyIdentifier(node, { binding: (() => this.AssignmentTargetIdentifier(reducer, node.binding)), init: node.init && (() => this[node.init.type](reducer, node.init)) }); 45 | }, 46 | 47 | AssignmentTargetPropertyProperty(reducer, node) { 48 | return reducer.reduceAssignmentTargetPropertyProperty(node, { name: (() => this[node.name.type](reducer, node.name)), binding: (() => this[node.binding.type](reducer, node.binding)) }); 49 | }, 50 | 51 | AssignmentTargetWithDefault(reducer, node) { 52 | return reducer.reduceAssignmentTargetWithDefault(node, { binding: (() => this[node.binding.type](reducer, node.binding)), init: (() => this[node.init.type](reducer, node.init)) }); 53 | }, 54 | 55 | AwaitExpression(reducer, node) { 56 | return reducer.reduceAwaitExpression(node, { expression: (() => this[node.expression.type](reducer, node.expression)) }); 57 | }, 58 | 59 | BinaryExpression(reducer, node) { 60 | return reducer.reduceBinaryExpression(node, { left: (() => this[node.left.type](reducer, node.left)), right: (() => this[node.right.type](reducer, node.right)) }); 61 | }, 62 | 63 | BindingIdentifier(reducer, node) { 64 | return reducer.reduceBindingIdentifier(node); 65 | }, 66 | 67 | BindingPropertyIdentifier(reducer, node) { 68 | return reducer.reduceBindingPropertyIdentifier(node, { binding: (() => this.BindingIdentifier(reducer, node.binding)), init: node.init && (() => this[node.init.type](reducer, node.init)) }); 69 | }, 70 | 71 | BindingPropertyProperty(reducer, node) { 72 | return reducer.reduceBindingPropertyProperty(node, { name: (() => this[node.name.type](reducer, node.name)), binding: (() => this[node.binding.type](reducer, node.binding)) }); 73 | }, 74 | 75 | BindingWithDefault(reducer, node) { 76 | return reducer.reduceBindingWithDefault(node, { binding: (() => this[node.binding.type](reducer, node.binding)), init: (() => this[node.init.type](reducer, node.init)) }); 77 | }, 78 | 79 | Block(reducer, node) { 80 | return reducer.reduceBlock(node, { statements: node.statements.map(v => (() => this[v.type](reducer, v))) }); 81 | }, 82 | 83 | BlockStatement(reducer, node) { 84 | return reducer.reduceBlockStatement(node, { block: (() => this.Block(reducer, node.block)) }); 85 | }, 86 | 87 | BreakStatement(reducer, node) { 88 | return reducer.reduceBreakStatement(node); 89 | }, 90 | 91 | CallExpression(reducer, node) { 92 | return reducer.reduceCallExpression(node, { callee: (() => this[node.callee.type](reducer, node.callee)), arguments: node.arguments.map(v => (() => this[v.type](reducer, v))) }); 93 | }, 94 | 95 | CatchClause(reducer, node) { 96 | return reducer.reduceCatchClause(node, { binding: node.binding && (() => this[node.binding.type](reducer, node.binding)), body: (() => this.Block(reducer, node.body)) }); 97 | }, 98 | 99 | ClassDeclaration(reducer, node) { 100 | return reducer.reduceClassDeclaration(node, { name: (() => this.BindingIdentifier(reducer, node.name)), super: node.super && (() => this[node.super.type](reducer, node.super)), elements: node.elements.map(v => (() => this.ClassElement(reducer, v))) }); 101 | }, 102 | 103 | ClassElement(reducer, node) { 104 | return reducer.reduceClassElement(node, { method: (() => this[node.method.type](reducer, node.method)) }); 105 | }, 106 | 107 | ClassExpression(reducer, node) { 108 | return reducer.reduceClassExpression(node, { name: node.name && (() => this.BindingIdentifier(reducer, node.name)), super: node.super && (() => this[node.super.type](reducer, node.super)), elements: node.elements.map(v => (() => this.ClassElement(reducer, v))) }); 109 | }, 110 | 111 | CompoundAssignmentExpression(reducer, node) { 112 | return reducer.reduceCompoundAssignmentExpression(node, { binding: (() => this[node.binding.type](reducer, node.binding)), expression: (() => this[node.expression.type](reducer, node.expression)) }); 113 | }, 114 | 115 | ComputedMemberAssignmentTarget(reducer, node) { 116 | return reducer.reduceComputedMemberAssignmentTarget(node, { object: (() => this[node.object.type](reducer, node.object)), expression: (() => this[node.expression.type](reducer, node.expression)) }); 117 | }, 118 | 119 | ComputedMemberExpression(reducer, node) { 120 | return reducer.reduceComputedMemberExpression(node, { object: (() => this[node.object.type](reducer, node.object)), expression: (() => this[node.expression.type](reducer, node.expression)) }); 121 | }, 122 | 123 | ComputedPropertyName(reducer, node) { 124 | return reducer.reduceComputedPropertyName(node, { expression: (() => this[node.expression.type](reducer, node.expression)) }); 125 | }, 126 | 127 | ConditionalExpression(reducer, node) { 128 | return reducer.reduceConditionalExpression(node, { test: (() => this[node.test.type](reducer, node.test)), consequent: (() => this[node.consequent.type](reducer, node.consequent)), alternate: (() => this[node.alternate.type](reducer, node.alternate)) }); 129 | }, 130 | 131 | ContinueStatement(reducer, node) { 132 | return reducer.reduceContinueStatement(node); 133 | }, 134 | 135 | DataProperty(reducer, node) { 136 | return reducer.reduceDataProperty(node, { name: (() => this[node.name.type](reducer, node.name)), expression: (() => this[node.expression.type](reducer, node.expression)) }); 137 | }, 138 | 139 | DebuggerStatement(reducer, node) { 140 | return reducer.reduceDebuggerStatement(node); 141 | }, 142 | 143 | Directive(reducer, node) { 144 | return reducer.reduceDirective(node); 145 | }, 146 | 147 | DoWhileStatement(reducer, node) { 148 | return reducer.reduceDoWhileStatement(node, { body: (() => this[node.body.type](reducer, node.body)), test: (() => this[node.test.type](reducer, node.test)) }); 149 | }, 150 | 151 | EmptyStatement(reducer, node) { 152 | return reducer.reduceEmptyStatement(node); 153 | }, 154 | 155 | Export(reducer, node) { 156 | return reducer.reduceExport(node, { declaration: (() => this[node.declaration.type](reducer, node.declaration)) }); 157 | }, 158 | 159 | ExportAllFrom(reducer, node) { 160 | return reducer.reduceExportAllFrom(node); 161 | }, 162 | 163 | ExportDefault(reducer, node) { 164 | return reducer.reduceExportDefault(node, { body: (() => this[node.body.type](reducer, node.body)) }); 165 | }, 166 | 167 | ExportFrom(reducer, node) { 168 | return reducer.reduceExportFrom(node, { namedExports: node.namedExports.map(v => (() => this.ExportFromSpecifier(reducer, v))) }); 169 | }, 170 | 171 | ExportFromSpecifier(reducer, node) { 172 | return reducer.reduceExportFromSpecifier(node); 173 | }, 174 | 175 | ExportLocalSpecifier(reducer, node) { 176 | return reducer.reduceExportLocalSpecifier(node, { name: (() => this.IdentifierExpression(reducer, node.name)) }); 177 | }, 178 | 179 | ExportLocals(reducer, node) { 180 | return reducer.reduceExportLocals(node, { namedExports: node.namedExports.map(v => (() => this.ExportLocalSpecifier(reducer, v))) }); 181 | }, 182 | 183 | ExpressionStatement(reducer, node) { 184 | return reducer.reduceExpressionStatement(node, { expression: (() => this[node.expression.type](reducer, node.expression)) }); 185 | }, 186 | 187 | ForAwaitStatement(reducer, node) { 188 | return reducer.reduceForAwaitStatement(node, { left: (() => this[node.left.type](reducer, node.left)), right: (() => this[node.right.type](reducer, node.right)), body: (() => this[node.body.type](reducer, node.body)) }); 189 | }, 190 | 191 | ForInStatement(reducer, node) { 192 | return reducer.reduceForInStatement(node, { left: (() => this[node.left.type](reducer, node.left)), right: (() => this[node.right.type](reducer, node.right)), body: (() => this[node.body.type](reducer, node.body)) }); 193 | }, 194 | 195 | ForOfStatement(reducer, node) { 196 | return reducer.reduceForOfStatement(node, { left: (() => this[node.left.type](reducer, node.left)), right: (() => this[node.right.type](reducer, node.right)), body: (() => this[node.body.type](reducer, node.body)) }); 197 | }, 198 | 199 | ForStatement(reducer, node) { 200 | return reducer.reduceForStatement(node, { init: node.init && (() => this[node.init.type](reducer, node.init)), test: node.test && (() => this[node.test.type](reducer, node.test)), update: node.update && (() => this[node.update.type](reducer, node.update)), body: (() => this[node.body.type](reducer, node.body)) }); 201 | }, 202 | 203 | FormalParameters(reducer, node) { 204 | return reducer.reduceFormalParameters(node, { items: node.items.map(v => (() => this[v.type](reducer, v))), rest: node.rest && (() => this[node.rest.type](reducer, node.rest)) }); 205 | }, 206 | 207 | FunctionBody(reducer, node) { 208 | return reducer.reduceFunctionBody(node, { directives: node.directives.map(v => (() => this.Directive(reducer, v))), statements: node.statements.map(v => (() => this[v.type](reducer, v))) }); 209 | }, 210 | 211 | FunctionDeclaration(reducer, node) { 212 | return reducer.reduceFunctionDeclaration(node, { name: (() => this.BindingIdentifier(reducer, node.name)), params: (() => this.FormalParameters(reducer, node.params)), body: (() => this.FunctionBody(reducer, node.body)) }); 213 | }, 214 | 215 | FunctionExpression(reducer, node) { 216 | return reducer.reduceFunctionExpression(node, { name: node.name && (() => this.BindingIdentifier(reducer, node.name)), params: (() => this.FormalParameters(reducer, node.params)), body: (() => this.FunctionBody(reducer, node.body)) }); 217 | }, 218 | 219 | Getter(reducer, node) { 220 | return reducer.reduceGetter(node, { name: (() => this[node.name.type](reducer, node.name)), body: (() => this.FunctionBody(reducer, node.body)) }); 221 | }, 222 | 223 | IdentifierExpression(reducer, node) { 224 | return reducer.reduceIdentifierExpression(node); 225 | }, 226 | 227 | IfStatement(reducer, node) { 228 | return reducer.reduceIfStatement(node, { test: (() => this[node.test.type](reducer, node.test)), consequent: (() => this[node.consequent.type](reducer, node.consequent)), alternate: node.alternate && (() => this[node.alternate.type](reducer, node.alternate)) }); 229 | }, 230 | 231 | Import(reducer, node) { 232 | return reducer.reduceImport(node, { defaultBinding: node.defaultBinding && (() => this.BindingIdentifier(reducer, node.defaultBinding)), namedImports: node.namedImports.map(v => (() => this.ImportSpecifier(reducer, v))) }); 233 | }, 234 | 235 | ImportNamespace(reducer, node) { 236 | return reducer.reduceImportNamespace(node, { defaultBinding: node.defaultBinding && (() => this.BindingIdentifier(reducer, node.defaultBinding)), namespaceBinding: (() => this.BindingIdentifier(reducer, node.namespaceBinding)) }); 237 | }, 238 | 239 | ImportSpecifier(reducer, node) { 240 | return reducer.reduceImportSpecifier(node, { binding: (() => this.BindingIdentifier(reducer, node.binding)) }); 241 | }, 242 | 243 | LabeledStatement(reducer, node) { 244 | return reducer.reduceLabeledStatement(node, { body: (() => this[node.body.type](reducer, node.body)) }); 245 | }, 246 | 247 | LiteralBooleanExpression(reducer, node) { 248 | return reducer.reduceLiteralBooleanExpression(node); 249 | }, 250 | 251 | LiteralInfinityExpression(reducer, node) { 252 | return reducer.reduceLiteralInfinityExpression(node); 253 | }, 254 | 255 | LiteralNullExpression(reducer, node) { 256 | return reducer.reduceLiteralNullExpression(node); 257 | }, 258 | 259 | LiteralNumericExpression(reducer, node) { 260 | return reducer.reduceLiteralNumericExpression(node); 261 | }, 262 | 263 | LiteralRegExpExpression(reducer, node) { 264 | return reducer.reduceLiteralRegExpExpression(node); 265 | }, 266 | 267 | LiteralStringExpression(reducer, node) { 268 | return reducer.reduceLiteralStringExpression(node); 269 | }, 270 | 271 | Method(reducer, node) { 272 | return reducer.reduceMethod(node, { name: (() => this[node.name.type](reducer, node.name)), params: (() => this.FormalParameters(reducer, node.params)), body: (() => this.FunctionBody(reducer, node.body)) }); 273 | }, 274 | 275 | Module(reducer, node) { 276 | return reducer.reduceModule(node, { directives: node.directives.map(v => (() => this.Directive(reducer, v))), items: node.items.map(v => (() => this[v.type](reducer, v))) }); 277 | }, 278 | 279 | NewExpression(reducer, node) { 280 | return reducer.reduceNewExpression(node, { callee: (() => this[node.callee.type](reducer, node.callee)), arguments: node.arguments.map(v => (() => this[v.type](reducer, v))) }); 281 | }, 282 | 283 | NewTargetExpression(reducer, node) { 284 | return reducer.reduceNewTargetExpression(node); 285 | }, 286 | 287 | ObjectAssignmentTarget(reducer, node) { 288 | return reducer.reduceObjectAssignmentTarget(node, { properties: node.properties.map(v => (() => this[v.type](reducer, v))), rest: node.rest && (() => this[node.rest.type](reducer, node.rest)) }); 289 | }, 290 | 291 | ObjectBinding(reducer, node) { 292 | return reducer.reduceObjectBinding(node, { properties: node.properties.map(v => (() => this[v.type](reducer, v))), rest: node.rest && (() => this.BindingIdentifier(reducer, node.rest)) }); 293 | }, 294 | 295 | ObjectExpression(reducer, node) { 296 | return reducer.reduceObjectExpression(node, { properties: node.properties.map(v => (() => this[v.type](reducer, v))) }); 297 | }, 298 | 299 | ReturnStatement(reducer, node) { 300 | return reducer.reduceReturnStatement(node, { expression: node.expression && (() => this[node.expression.type](reducer, node.expression)) }); 301 | }, 302 | 303 | Script(reducer, node) { 304 | return reducer.reduceScript(node, { directives: node.directives.map(v => (() => this.Directive(reducer, v))), statements: node.statements.map(v => (() => this[v.type](reducer, v))) }); 305 | }, 306 | 307 | Setter(reducer, node) { 308 | return reducer.reduceSetter(node, { name: (() => this[node.name.type](reducer, node.name)), param: (() => this[node.param.type](reducer, node.param)), body: (() => this.FunctionBody(reducer, node.body)) }); 309 | }, 310 | 311 | ShorthandProperty(reducer, node) { 312 | return reducer.reduceShorthandProperty(node, { name: (() => this.IdentifierExpression(reducer, node.name)) }); 313 | }, 314 | 315 | SpreadElement(reducer, node) { 316 | return reducer.reduceSpreadElement(node, { expression: (() => this[node.expression.type](reducer, node.expression)) }); 317 | }, 318 | 319 | SpreadProperty(reducer, node) { 320 | return reducer.reduceSpreadProperty(node, { expression: (() => this[node.expression.type](reducer, node.expression)) }); 321 | }, 322 | 323 | StaticMemberAssignmentTarget(reducer, node) { 324 | return reducer.reduceStaticMemberAssignmentTarget(node, { object: (() => this[node.object.type](reducer, node.object)) }); 325 | }, 326 | 327 | StaticMemberExpression(reducer, node) { 328 | return reducer.reduceStaticMemberExpression(node, { object: (() => this[node.object.type](reducer, node.object)) }); 329 | }, 330 | 331 | StaticPropertyName(reducer, node) { 332 | return reducer.reduceStaticPropertyName(node); 333 | }, 334 | 335 | Super(reducer, node) { 336 | return reducer.reduceSuper(node); 337 | }, 338 | 339 | SwitchCase(reducer, node) { 340 | return reducer.reduceSwitchCase(node, { test: (() => this[node.test.type](reducer, node.test)), consequent: node.consequent.map(v => (() => this[v.type](reducer, v))) }); 341 | }, 342 | 343 | SwitchDefault(reducer, node) { 344 | return reducer.reduceSwitchDefault(node, { consequent: node.consequent.map(v => (() => this[v.type](reducer, v))) }); 345 | }, 346 | 347 | SwitchStatement(reducer, node) { 348 | return reducer.reduceSwitchStatement(node, { discriminant: (() => this[node.discriminant.type](reducer, node.discriminant)), cases: node.cases.map(v => (() => this.SwitchCase(reducer, v))) }); 349 | }, 350 | 351 | SwitchStatementWithDefault(reducer, node) { 352 | return reducer.reduceSwitchStatementWithDefault(node, { discriminant: (() => this[node.discriminant.type](reducer, node.discriminant)), preDefaultCases: node.preDefaultCases.map(v => (() => this.SwitchCase(reducer, v))), defaultCase: (() => this.SwitchDefault(reducer, node.defaultCase)), postDefaultCases: node.postDefaultCases.map(v => (() => this.SwitchCase(reducer, v))) }); 353 | }, 354 | 355 | TemplateElement(reducer, node) { 356 | return reducer.reduceTemplateElement(node); 357 | }, 358 | 359 | TemplateExpression(reducer, node) { 360 | return reducer.reduceTemplateExpression(node, { tag: node.tag && (() => this[node.tag.type](reducer, node.tag)), elements: node.elements.map(v => (() => this[v.type](reducer, v))) }); 361 | }, 362 | 363 | ThisExpression(reducer, node) { 364 | return reducer.reduceThisExpression(node); 365 | }, 366 | 367 | ThrowStatement(reducer, node) { 368 | return reducer.reduceThrowStatement(node, { expression: (() => this[node.expression.type](reducer, node.expression)) }); 369 | }, 370 | 371 | TryCatchStatement(reducer, node) { 372 | return reducer.reduceTryCatchStatement(node, { body: (() => this.Block(reducer, node.body)), catchClause: (() => this.CatchClause(reducer, node.catchClause)) }); 373 | }, 374 | 375 | TryFinallyStatement(reducer, node) { 376 | return reducer.reduceTryFinallyStatement(node, { body: (() => this.Block(reducer, node.body)), catchClause: node.catchClause && (() => this.CatchClause(reducer, node.catchClause)), finalizer: (() => this.Block(reducer, node.finalizer)) }); 377 | }, 378 | 379 | UnaryExpression(reducer, node) { 380 | return reducer.reduceUnaryExpression(node, { operand: (() => this[node.operand.type](reducer, node.operand)) }); 381 | }, 382 | 383 | UpdateExpression(reducer, node) { 384 | return reducer.reduceUpdateExpression(node, { operand: (() => this[node.operand.type](reducer, node.operand)) }); 385 | }, 386 | 387 | VariableDeclaration(reducer, node) { 388 | return reducer.reduceVariableDeclaration(node, { declarators: node.declarators.map(v => (() => this.VariableDeclarator(reducer, v))) }); 389 | }, 390 | 391 | VariableDeclarationStatement(reducer, node) { 392 | return reducer.reduceVariableDeclarationStatement(node, { declaration: (() => this.VariableDeclaration(reducer, node.declaration)) }); 393 | }, 394 | 395 | VariableDeclarator(reducer, node) { 396 | return reducer.reduceVariableDeclarator(node, { binding: (() => this[node.binding.type](reducer, node.binding)), init: node.init && (() => this[node.init.type](reducer, node.init)) }); 397 | }, 398 | 399 | WhileStatement(reducer, node) { 400 | return reducer.reduceWhileStatement(node, { test: (() => this[node.test.type](reducer, node.test)), body: (() => this[node.body.type](reducer, node.body)) }); 401 | }, 402 | 403 | WithStatement(reducer, node) { 404 | return reducer.reduceWithStatement(node, { object: (() => this[node.object.type](reducer, node.object)), body: (() => this[node.body.type](reducer, node.body)) }); 405 | }, 406 | 407 | YieldExpression(reducer, node) { 408 | return reducer.reduceYieldExpression(node, { expression: node.expression && (() => this[node.expression.type](reducer, node.expression)) }); 409 | }, 410 | 411 | YieldGeneratorExpression(reducer, node) { 412 | return reducer.reduceYieldGeneratorExpression(node, { expression: (() => this[node.expression.type](reducer, node.expression)) }); 413 | }, 414 | }; 415 | 416 | module.exports = function thunkedReduce(reducer, node) { 417 | return director[node.type](reducer, node); 418 | }; 419 | -------------------------------------------------------------------------------- /gen/thunked-monoidal-reducer.js: -------------------------------------------------------------------------------- 1 | // Generated by generate-monoidal-reducer.js 2 | /** 3 | * Copyright 2018 Shape Security, Inc. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License") 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | const Shift = require('shift-ast'); 19 | 20 | module.exports = class MonoidalReducer { 21 | constructor(monoid) { 22 | let identity = monoid.empty(); 23 | this.identity = identity; 24 | 25 | let concatThunk; 26 | if (monoid.prototype && typeof monoid.prototype.concatThunk === 'function') { 27 | concatThunk = Function.prototype.call.bind(monoid.prototype.concatThunk); 28 | } else if (typeof monoid.concatThunk === 'function') { 29 | concatThunk = monoid.concatThunk; 30 | } else { 31 | let concat; 32 | if (monoid.prototype && typeof monoid.prototype.concat === 'function') { 33 | concat = Function.prototype.call.bind(monoid.prototype.concat); 34 | } else if (typeof monoid.concat === 'function') { 35 | concat = monoid.concat; 36 | } else { 37 | throw new TypeError('Monoid must provide a `concatThunk` or `concat` method'); 38 | } 39 | if (typeof monoid.isAbsorbing === 'function') { 40 | let isAbsorbing = monoid.isAbsorbing; 41 | concatThunk = (a, b) => isAbsorbing(a) ? a : concat(a, b()); 42 | } else { 43 | concatThunk = (a, b) => concat(a, b()); 44 | } 45 | } 46 | this.append = (...args) => args.reduce(concatThunk, identity); 47 | } 48 | 49 | reduceArrayAssignmentTarget(node, { elements, rest }) { 50 | return this.append(...elements.filter(n => n != null), rest == null ? () => this.identity : rest); 51 | } 52 | 53 | reduceArrayBinding(node, { elements, rest }) { 54 | return this.append(...elements.filter(n => n != null), rest == null ? () => this.identity : rest); 55 | } 56 | 57 | reduceArrayExpression(node, { elements }) { 58 | return this.append(...elements.filter(n => n != null)); 59 | } 60 | 61 | reduceArrowExpression(node, { params, body }) { 62 | return this.append(params, body); 63 | } 64 | 65 | reduceAssignmentExpression(node, { binding, expression }) { 66 | return this.append(binding, expression); 67 | } 68 | 69 | reduceAssignmentTargetIdentifier(node) { 70 | return this.identity; 71 | } 72 | 73 | reduceAssignmentTargetPropertyIdentifier(node, { binding, init }) { 74 | return this.append(binding, init == null ? () => this.identity : init); 75 | } 76 | 77 | reduceAssignmentTargetPropertyProperty(node, { name, binding }) { 78 | return this.append(name, binding); 79 | } 80 | 81 | reduceAssignmentTargetWithDefault(node, { binding, init }) { 82 | return this.append(binding, init); 83 | } 84 | 85 | reduceAwaitExpression(node, { expression }) { 86 | return expression(); 87 | } 88 | 89 | reduceBinaryExpression(node, { left, right }) { 90 | return this.append(left, right); 91 | } 92 | 93 | reduceBindingIdentifier(node) { 94 | return this.identity; 95 | } 96 | 97 | reduceBindingPropertyIdentifier(node, { binding, init }) { 98 | return this.append(binding, init == null ? () => this.identity : init); 99 | } 100 | 101 | reduceBindingPropertyProperty(node, { name, binding }) { 102 | return this.append(name, binding); 103 | } 104 | 105 | reduceBindingWithDefault(node, { binding, init }) { 106 | return this.append(binding, init); 107 | } 108 | 109 | reduceBlock(node, { statements }) { 110 | return this.append(...statements); 111 | } 112 | 113 | reduceBlockStatement(node, { block }) { 114 | return block(); 115 | } 116 | 117 | reduceBreakStatement(node) { 118 | return this.identity; 119 | } 120 | 121 | reduceCallExpression(node, { callee, arguments: _arguments }) { 122 | return this.append(callee, ..._arguments); 123 | } 124 | 125 | reduceCatchClause(node, { binding, body }) { 126 | return this.append(binding == null ? () => this.identity : binding, body); 127 | } 128 | 129 | reduceClassDeclaration(node, { name, super: _super, elements }) { 130 | return this.append(name, _super == null ? () => this.identity : _super, ...elements); 131 | } 132 | 133 | reduceClassElement(node, { method }) { 134 | return method(); 135 | } 136 | 137 | reduceClassExpression(node, { name, super: _super, elements }) { 138 | return this.append(name == null ? () => this.identity : name, _super == null ? () => this.identity : _super, ...elements); 139 | } 140 | 141 | reduceCompoundAssignmentExpression(node, { binding, expression }) { 142 | return this.append(binding, expression); 143 | } 144 | 145 | reduceComputedMemberAssignmentTarget(node, { object, expression }) { 146 | return this.append(object, expression); 147 | } 148 | 149 | reduceComputedMemberExpression(node, { object, expression }) { 150 | return this.append(object, expression); 151 | } 152 | 153 | reduceComputedPropertyName(node, { expression }) { 154 | return expression(); 155 | } 156 | 157 | reduceConditionalExpression(node, { test, consequent, alternate }) { 158 | return this.append(test, consequent, alternate); 159 | } 160 | 161 | reduceContinueStatement(node) { 162 | return this.identity; 163 | } 164 | 165 | reduceDataProperty(node, { name, expression }) { 166 | return this.append(name, expression); 167 | } 168 | 169 | reduceDebuggerStatement(node) { 170 | return this.identity; 171 | } 172 | 173 | reduceDirective(node) { 174 | return this.identity; 175 | } 176 | 177 | reduceDoWhileStatement(node, { body, test }) { 178 | return this.append(body, test); 179 | } 180 | 181 | reduceEmptyStatement(node) { 182 | return this.identity; 183 | } 184 | 185 | reduceExport(node, { declaration }) { 186 | return declaration(); 187 | } 188 | 189 | reduceExportAllFrom(node) { 190 | return this.identity; 191 | } 192 | 193 | reduceExportDefault(node, { body }) { 194 | return body(); 195 | } 196 | 197 | reduceExportFrom(node, { namedExports }) { 198 | return this.append(...namedExports); 199 | } 200 | 201 | reduceExportFromSpecifier(node) { 202 | return this.identity; 203 | } 204 | 205 | reduceExportLocalSpecifier(node, { name }) { 206 | return name(); 207 | } 208 | 209 | reduceExportLocals(node, { namedExports }) { 210 | return this.append(...namedExports); 211 | } 212 | 213 | reduceExpressionStatement(node, { expression }) { 214 | return expression(); 215 | } 216 | 217 | reduceForAwaitStatement(node, { left, right, body }) { 218 | return this.append(left, right, body); 219 | } 220 | 221 | reduceForInStatement(node, { left, right, body }) { 222 | return this.append(left, right, body); 223 | } 224 | 225 | reduceForOfStatement(node, { left, right, body }) { 226 | return this.append(left, right, body); 227 | } 228 | 229 | reduceForStatement(node, { init, test, update, body }) { 230 | return this.append(init == null ? () => this.identity : init, test == null ? () => this.identity : test, update == null ? () => this.identity : update, body); 231 | } 232 | 233 | reduceFormalParameters(node, { items, rest }) { 234 | return this.append(...items, rest == null ? () => this.identity : rest); 235 | } 236 | 237 | reduceFunctionBody(node, { directives, statements }) { 238 | return this.append(...directives, ...statements); 239 | } 240 | 241 | reduceFunctionDeclaration(node, { name, params, body }) { 242 | return this.append(name, params, body); 243 | } 244 | 245 | reduceFunctionExpression(node, { name, params, body }) { 246 | return this.append(name == null ? () => this.identity : name, params, body); 247 | } 248 | 249 | reduceGetter(node, { name, body }) { 250 | return this.append(name, body); 251 | } 252 | 253 | reduceIdentifierExpression(node) { 254 | return this.identity; 255 | } 256 | 257 | reduceIfStatement(node, { test, consequent, alternate }) { 258 | return this.append(test, consequent, alternate == null ? () => this.identity : alternate); 259 | } 260 | 261 | reduceImport(node, { defaultBinding, namedImports }) { 262 | return this.append(defaultBinding == null ? () => this.identity : defaultBinding, ...namedImports); 263 | } 264 | 265 | reduceImportNamespace(node, { defaultBinding, namespaceBinding }) { 266 | return this.append(defaultBinding == null ? () => this.identity : defaultBinding, namespaceBinding); 267 | } 268 | 269 | reduceImportSpecifier(node, { binding }) { 270 | return binding(); 271 | } 272 | 273 | reduceLabeledStatement(node, { body }) { 274 | return body(); 275 | } 276 | 277 | reduceLiteralBooleanExpression(node) { 278 | return this.identity; 279 | } 280 | 281 | reduceLiteralInfinityExpression(node) { 282 | return this.identity; 283 | } 284 | 285 | reduceLiteralNullExpression(node) { 286 | return this.identity; 287 | } 288 | 289 | reduceLiteralNumericExpression(node) { 290 | return this.identity; 291 | } 292 | 293 | reduceLiteralRegExpExpression(node) { 294 | return this.identity; 295 | } 296 | 297 | reduceLiteralStringExpression(node) { 298 | return this.identity; 299 | } 300 | 301 | reduceMethod(node, { name, params, body }) { 302 | return this.append(name, params, body); 303 | } 304 | 305 | reduceModule(node, { directives, items }) { 306 | return this.append(...directives, ...items); 307 | } 308 | 309 | reduceNewExpression(node, { callee, arguments: _arguments }) { 310 | return this.append(callee, ..._arguments); 311 | } 312 | 313 | reduceNewTargetExpression(node) { 314 | return this.identity; 315 | } 316 | 317 | reduceObjectAssignmentTarget(node, { properties, rest }) { 318 | return this.append(...properties, rest == null ? () => this.identity : rest); 319 | } 320 | 321 | reduceObjectBinding(node, { properties, rest }) { 322 | return this.append(...properties, rest == null ? () => this.identity : rest); 323 | } 324 | 325 | reduceObjectExpression(node, { properties }) { 326 | return this.append(...properties); 327 | } 328 | 329 | reduceReturnStatement(node, { expression }) { 330 | return expression == null ? this.identity : expression(); 331 | } 332 | 333 | reduceScript(node, { directives, statements }) { 334 | return this.append(...directives, ...statements); 335 | } 336 | 337 | reduceSetter(node, { name, param, body }) { 338 | return this.append(name, param, body); 339 | } 340 | 341 | reduceShorthandProperty(node, { name }) { 342 | return name(); 343 | } 344 | 345 | reduceSpreadElement(node, { expression }) { 346 | return expression(); 347 | } 348 | 349 | reduceSpreadProperty(node, { expression }) { 350 | return expression(); 351 | } 352 | 353 | reduceStaticMemberAssignmentTarget(node, { object }) { 354 | return object(); 355 | } 356 | 357 | reduceStaticMemberExpression(node, { object }) { 358 | return object(); 359 | } 360 | 361 | reduceStaticPropertyName(node) { 362 | return this.identity; 363 | } 364 | 365 | reduceSuper(node) { 366 | return this.identity; 367 | } 368 | 369 | reduceSwitchCase(node, { test, consequent }) { 370 | return this.append(test, ...consequent); 371 | } 372 | 373 | reduceSwitchDefault(node, { consequent }) { 374 | return this.append(...consequent); 375 | } 376 | 377 | reduceSwitchStatement(node, { discriminant, cases }) { 378 | return this.append(discriminant, ...cases); 379 | } 380 | 381 | reduceSwitchStatementWithDefault(node, { discriminant, preDefaultCases, defaultCase, postDefaultCases }) { 382 | return this.append(discriminant, ...preDefaultCases, defaultCase, ...postDefaultCases); 383 | } 384 | 385 | reduceTemplateElement(node) { 386 | return this.identity; 387 | } 388 | 389 | reduceTemplateExpression(node, { tag, elements }) { 390 | return this.append(tag == null ? () => this.identity : tag, ...elements); 391 | } 392 | 393 | reduceThisExpression(node) { 394 | return this.identity; 395 | } 396 | 397 | reduceThrowStatement(node, { expression }) { 398 | return expression(); 399 | } 400 | 401 | reduceTryCatchStatement(node, { body, catchClause }) { 402 | return this.append(body, catchClause); 403 | } 404 | 405 | reduceTryFinallyStatement(node, { body, catchClause, finalizer }) { 406 | return this.append(body, catchClause == null ? () => this.identity : catchClause, finalizer); 407 | } 408 | 409 | reduceUnaryExpression(node, { operand }) { 410 | return operand(); 411 | } 412 | 413 | reduceUpdateExpression(node, { operand }) { 414 | return operand(); 415 | } 416 | 417 | reduceVariableDeclaration(node, { declarators }) { 418 | return this.append(...declarators); 419 | } 420 | 421 | reduceVariableDeclarationStatement(node, { declaration }) { 422 | return declaration(); 423 | } 424 | 425 | reduceVariableDeclarator(node, { binding, init }) { 426 | return this.append(binding, init == null ? () => this.identity : init); 427 | } 428 | 429 | reduceWhileStatement(node, { test, body }) { 430 | return this.append(test, body); 431 | } 432 | 433 | reduceWithStatement(node, { object, body }) { 434 | return this.append(object, body); 435 | } 436 | 437 | reduceYieldExpression(node, { expression }) { 438 | return expression == null ? this.identity : expression(); 439 | } 440 | 441 | reduceYieldGeneratorExpression(node, { expression }) { 442 | return expression(); 443 | } 444 | }; 445 | -------------------------------------------------------------------------------- /gen/thunkify-class.js: -------------------------------------------------------------------------------- 1 | // Generated by generate-thunkify.js 2 | /** 3 | * Copyright 2018 Shape Security, Inc. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License") 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | module.exports = function thunkifyClass(reducerClass) { 19 | return class extends reducerClass { 20 | reduceArrayAssignmentTarget(node, { elements, rest }) { 21 | return super.reduceArrayAssignmentTarget(node, { elements: elements.map(n => n == null ? null : n()), rest: rest == null ? null : rest() }); 22 | } 23 | 24 | reduceArrayBinding(node, { elements, rest }) { 25 | return super.reduceArrayBinding(node, { elements: elements.map(n => n == null ? null : n()), rest: rest == null ? null : rest() }); 26 | } 27 | 28 | reduceArrayExpression(node, { elements }) { 29 | return super.reduceArrayExpression(node, { elements: elements.map(n => n == null ? null : n()) }); 30 | } 31 | 32 | reduceArrowExpression(node, { params, body }) { 33 | return super.reduceArrowExpression(node, { params: params(), body: body() }); 34 | } 35 | 36 | reduceAssignmentExpression(node, { binding, expression }) { 37 | return super.reduceAssignmentExpression(node, { binding: binding(), expression: expression() }); 38 | } 39 | 40 | reduceAssignmentTargetIdentifier(node) { 41 | return super.reduceAssignmentTargetIdentifier(node); 42 | } 43 | 44 | reduceAssignmentTargetPropertyIdentifier(node, { binding, init }) { 45 | return super.reduceAssignmentTargetPropertyIdentifier(node, { binding: binding(), init: init == null ? null : init() }); 46 | } 47 | 48 | reduceAssignmentTargetPropertyProperty(node, { name, binding }) { 49 | return super.reduceAssignmentTargetPropertyProperty(node, { name: name(), binding: binding() }); 50 | } 51 | 52 | reduceAssignmentTargetWithDefault(node, { binding, init }) { 53 | return super.reduceAssignmentTargetWithDefault(node, { binding: binding(), init: init() }); 54 | } 55 | 56 | reduceAwaitExpression(node, { expression }) { 57 | return super.reduceAwaitExpression(node, { expression: expression() }); 58 | } 59 | 60 | reduceBinaryExpression(node, { left, right }) { 61 | return super.reduceBinaryExpression(node, { left: left(), right: right() }); 62 | } 63 | 64 | reduceBindingIdentifier(node) { 65 | return super.reduceBindingIdentifier(node); 66 | } 67 | 68 | reduceBindingPropertyIdentifier(node, { binding, init }) { 69 | return super.reduceBindingPropertyIdentifier(node, { binding: binding(), init: init == null ? null : init() }); 70 | } 71 | 72 | reduceBindingPropertyProperty(node, { name, binding }) { 73 | return super.reduceBindingPropertyProperty(node, { name: name(), binding: binding() }); 74 | } 75 | 76 | reduceBindingWithDefault(node, { binding, init }) { 77 | return super.reduceBindingWithDefault(node, { binding: binding(), init: init() }); 78 | } 79 | 80 | reduceBlock(node, { statements }) { 81 | return super.reduceBlock(node, { statements: statements.map(n => n()) }); 82 | } 83 | 84 | reduceBlockStatement(node, { block }) { 85 | return super.reduceBlockStatement(node, { block: block() }); 86 | } 87 | 88 | reduceBreakStatement(node) { 89 | return super.reduceBreakStatement(node); 90 | } 91 | 92 | reduceCallExpression(node, { callee, arguments: _arguments }) { 93 | return super.reduceCallExpression(node, { callee: callee(), arguments: _arguments.map(n => n()) }); 94 | } 95 | 96 | reduceCatchClause(node, { binding, body }) { 97 | return super.reduceCatchClause(node, { binding: binding == null ? null : binding(), body: body() }); 98 | } 99 | 100 | reduceClassDeclaration(node, { name, super: _super, elements }) { 101 | return super.reduceClassDeclaration(node, { name: name(), super: _super == null ? null : _super(), elements: elements.map(n => n()) }); 102 | } 103 | 104 | reduceClassElement(node, { method }) { 105 | return super.reduceClassElement(node, { method: method() }); 106 | } 107 | 108 | reduceClassExpression(node, { name, super: _super, elements }) { 109 | return super.reduceClassExpression(node, { name: name == null ? null : name(), super: _super == null ? null : _super(), elements: elements.map(n => n()) }); 110 | } 111 | 112 | reduceCompoundAssignmentExpression(node, { binding, expression }) { 113 | return super.reduceCompoundAssignmentExpression(node, { binding: binding(), expression: expression() }); 114 | } 115 | 116 | reduceComputedMemberAssignmentTarget(node, { object, expression }) { 117 | return super.reduceComputedMemberAssignmentTarget(node, { object: object(), expression: expression() }); 118 | } 119 | 120 | reduceComputedMemberExpression(node, { object, expression }) { 121 | return super.reduceComputedMemberExpression(node, { object: object(), expression: expression() }); 122 | } 123 | 124 | reduceComputedPropertyName(node, { expression }) { 125 | return super.reduceComputedPropertyName(node, { expression: expression() }); 126 | } 127 | 128 | reduceConditionalExpression(node, { test, consequent, alternate }) { 129 | return super.reduceConditionalExpression(node, { test: test(), consequent: consequent(), alternate: alternate() }); 130 | } 131 | 132 | reduceContinueStatement(node) { 133 | return super.reduceContinueStatement(node); 134 | } 135 | 136 | reduceDataProperty(node, { name, expression }) { 137 | return super.reduceDataProperty(node, { name: name(), expression: expression() }); 138 | } 139 | 140 | reduceDebuggerStatement(node) { 141 | return super.reduceDebuggerStatement(node); 142 | } 143 | 144 | reduceDirective(node) { 145 | return super.reduceDirective(node); 146 | } 147 | 148 | reduceDoWhileStatement(node, { body, test }) { 149 | return super.reduceDoWhileStatement(node, { body: body(), test: test() }); 150 | } 151 | 152 | reduceEmptyStatement(node) { 153 | return super.reduceEmptyStatement(node); 154 | } 155 | 156 | reduceExport(node, { declaration }) { 157 | return super.reduceExport(node, { declaration: declaration() }); 158 | } 159 | 160 | reduceExportAllFrom(node) { 161 | return super.reduceExportAllFrom(node); 162 | } 163 | 164 | reduceExportDefault(node, { body }) { 165 | return super.reduceExportDefault(node, { body: body() }); 166 | } 167 | 168 | reduceExportFrom(node, { namedExports }) { 169 | return super.reduceExportFrom(node, { namedExports: namedExports.map(n => n()) }); 170 | } 171 | 172 | reduceExportFromSpecifier(node) { 173 | return super.reduceExportFromSpecifier(node); 174 | } 175 | 176 | reduceExportLocalSpecifier(node, { name }) { 177 | return super.reduceExportLocalSpecifier(node, { name: name() }); 178 | } 179 | 180 | reduceExportLocals(node, { namedExports }) { 181 | return super.reduceExportLocals(node, { namedExports: namedExports.map(n => n()) }); 182 | } 183 | 184 | reduceExpressionStatement(node, { expression }) { 185 | return super.reduceExpressionStatement(node, { expression: expression() }); 186 | } 187 | 188 | reduceForAwaitStatement(node, { left, right, body }) { 189 | return super.reduceForAwaitStatement(node, { left: left(), right: right(), body: body() }); 190 | } 191 | 192 | reduceForInStatement(node, { left, right, body }) { 193 | return super.reduceForInStatement(node, { left: left(), right: right(), body: body() }); 194 | } 195 | 196 | reduceForOfStatement(node, { left, right, body }) { 197 | return super.reduceForOfStatement(node, { left: left(), right: right(), body: body() }); 198 | } 199 | 200 | reduceForStatement(node, { init, test, update, body }) { 201 | return super.reduceForStatement(node, { init: init == null ? null : init(), test: test == null ? null : test(), update: update == null ? null : update(), body: body() }); 202 | } 203 | 204 | reduceFormalParameters(node, { items, rest }) { 205 | return super.reduceFormalParameters(node, { items: items.map(n => n()), rest: rest == null ? null : rest() }); 206 | } 207 | 208 | reduceFunctionBody(node, { directives, statements }) { 209 | return super.reduceFunctionBody(node, { directives: directives.map(n => n()), statements: statements.map(n => n()) }); 210 | } 211 | 212 | reduceFunctionDeclaration(node, { name, params, body }) { 213 | return super.reduceFunctionDeclaration(node, { name: name(), params: params(), body: body() }); 214 | } 215 | 216 | reduceFunctionExpression(node, { name, params, body }) { 217 | return super.reduceFunctionExpression(node, { name: name == null ? null : name(), params: params(), body: body() }); 218 | } 219 | 220 | reduceGetter(node, { name, body }) { 221 | return super.reduceGetter(node, { name: name(), body: body() }); 222 | } 223 | 224 | reduceIdentifierExpression(node) { 225 | return super.reduceIdentifierExpression(node); 226 | } 227 | 228 | reduceIfStatement(node, { test, consequent, alternate }) { 229 | return super.reduceIfStatement(node, { test: test(), consequent: consequent(), alternate: alternate == null ? null : alternate() }); 230 | } 231 | 232 | reduceImport(node, { defaultBinding, namedImports }) { 233 | return super.reduceImport(node, { defaultBinding: defaultBinding == null ? null : defaultBinding(), namedImports: namedImports.map(n => n()) }); 234 | } 235 | 236 | reduceImportNamespace(node, { defaultBinding, namespaceBinding }) { 237 | return super.reduceImportNamespace(node, { defaultBinding: defaultBinding == null ? null : defaultBinding(), namespaceBinding: namespaceBinding() }); 238 | } 239 | 240 | reduceImportSpecifier(node, { binding }) { 241 | return super.reduceImportSpecifier(node, { binding: binding() }); 242 | } 243 | 244 | reduceLabeledStatement(node, { body }) { 245 | return super.reduceLabeledStatement(node, { body: body() }); 246 | } 247 | 248 | reduceLiteralBooleanExpression(node) { 249 | return super.reduceLiteralBooleanExpression(node); 250 | } 251 | 252 | reduceLiteralInfinityExpression(node) { 253 | return super.reduceLiteralInfinityExpression(node); 254 | } 255 | 256 | reduceLiteralNullExpression(node) { 257 | return super.reduceLiteralNullExpression(node); 258 | } 259 | 260 | reduceLiteralNumericExpression(node) { 261 | return super.reduceLiteralNumericExpression(node); 262 | } 263 | 264 | reduceLiteralRegExpExpression(node) { 265 | return super.reduceLiteralRegExpExpression(node); 266 | } 267 | 268 | reduceLiteralStringExpression(node) { 269 | return super.reduceLiteralStringExpression(node); 270 | } 271 | 272 | reduceMethod(node, { name, params, body }) { 273 | return super.reduceMethod(node, { name: name(), params: params(), body: body() }); 274 | } 275 | 276 | reduceModule(node, { directives, items }) { 277 | return super.reduceModule(node, { directives: directives.map(n => n()), items: items.map(n => n()) }); 278 | } 279 | 280 | reduceNewExpression(node, { callee, arguments: _arguments }) { 281 | return super.reduceNewExpression(node, { callee: callee(), arguments: _arguments.map(n => n()) }); 282 | } 283 | 284 | reduceNewTargetExpression(node) { 285 | return super.reduceNewTargetExpression(node); 286 | } 287 | 288 | reduceObjectAssignmentTarget(node, { properties, rest }) { 289 | return super.reduceObjectAssignmentTarget(node, { properties: properties.map(n => n()), rest: rest == null ? null : rest() }); 290 | } 291 | 292 | reduceObjectBinding(node, { properties, rest }) { 293 | return super.reduceObjectBinding(node, { properties: properties.map(n => n()), rest: rest == null ? null : rest() }); 294 | } 295 | 296 | reduceObjectExpression(node, { properties }) { 297 | return super.reduceObjectExpression(node, { properties: properties.map(n => n()) }); 298 | } 299 | 300 | reduceReturnStatement(node, { expression }) { 301 | return super.reduceReturnStatement(node, { expression: expression == null ? null : expression() }); 302 | } 303 | 304 | reduceScript(node, { directives, statements }) { 305 | return super.reduceScript(node, { directives: directives.map(n => n()), statements: statements.map(n => n()) }); 306 | } 307 | 308 | reduceSetter(node, { name, param, body }) { 309 | return super.reduceSetter(node, { name: name(), param: param(), body: body() }); 310 | } 311 | 312 | reduceShorthandProperty(node, { name }) { 313 | return super.reduceShorthandProperty(node, { name: name() }); 314 | } 315 | 316 | reduceSpreadElement(node, { expression }) { 317 | return super.reduceSpreadElement(node, { expression: expression() }); 318 | } 319 | 320 | reduceSpreadProperty(node, { expression }) { 321 | return super.reduceSpreadProperty(node, { expression: expression() }); 322 | } 323 | 324 | reduceStaticMemberAssignmentTarget(node, { object }) { 325 | return super.reduceStaticMemberAssignmentTarget(node, { object: object() }); 326 | } 327 | 328 | reduceStaticMemberExpression(node, { object }) { 329 | return super.reduceStaticMemberExpression(node, { object: object() }); 330 | } 331 | 332 | reduceStaticPropertyName(node) { 333 | return super.reduceStaticPropertyName(node); 334 | } 335 | 336 | reduceSuper(node) { 337 | return super.reduceSuper(node); 338 | } 339 | 340 | reduceSwitchCase(node, { test, consequent }) { 341 | return super.reduceSwitchCase(node, { test: test(), consequent: consequent.map(n => n()) }); 342 | } 343 | 344 | reduceSwitchDefault(node, { consequent }) { 345 | return super.reduceSwitchDefault(node, { consequent: consequent.map(n => n()) }); 346 | } 347 | 348 | reduceSwitchStatement(node, { discriminant, cases }) { 349 | return super.reduceSwitchStatement(node, { discriminant: discriminant(), cases: cases.map(n => n()) }); 350 | } 351 | 352 | reduceSwitchStatementWithDefault(node, { discriminant, preDefaultCases, defaultCase, postDefaultCases }) { 353 | return super.reduceSwitchStatementWithDefault(node, { discriminant: discriminant(), preDefaultCases: preDefaultCases.map(n => n()), defaultCase: defaultCase(), postDefaultCases: postDefaultCases.map(n => n()) }); 354 | } 355 | 356 | reduceTemplateElement(node) { 357 | return super.reduceTemplateElement(node); 358 | } 359 | 360 | reduceTemplateExpression(node, { tag, elements }) { 361 | return super.reduceTemplateExpression(node, { tag: tag == null ? null : tag(), elements: elements.map(n => n()) }); 362 | } 363 | 364 | reduceThisExpression(node) { 365 | return super.reduceThisExpression(node); 366 | } 367 | 368 | reduceThrowStatement(node, { expression }) { 369 | return super.reduceThrowStatement(node, { expression: expression() }); 370 | } 371 | 372 | reduceTryCatchStatement(node, { body, catchClause }) { 373 | return super.reduceTryCatchStatement(node, { body: body(), catchClause: catchClause() }); 374 | } 375 | 376 | reduceTryFinallyStatement(node, { body, catchClause, finalizer }) { 377 | return super.reduceTryFinallyStatement(node, { body: body(), catchClause: catchClause == null ? null : catchClause(), finalizer: finalizer() }); 378 | } 379 | 380 | reduceUnaryExpression(node, { operand }) { 381 | return super.reduceUnaryExpression(node, { operand: operand() }); 382 | } 383 | 384 | reduceUpdateExpression(node, { operand }) { 385 | return super.reduceUpdateExpression(node, { operand: operand() }); 386 | } 387 | 388 | reduceVariableDeclaration(node, { declarators }) { 389 | return super.reduceVariableDeclaration(node, { declarators: declarators.map(n => n()) }); 390 | } 391 | 392 | reduceVariableDeclarationStatement(node, { declaration }) { 393 | return super.reduceVariableDeclarationStatement(node, { declaration: declaration() }); 394 | } 395 | 396 | reduceVariableDeclarator(node, { binding, init }) { 397 | return super.reduceVariableDeclarator(node, { binding: binding(), init: init == null ? null : init() }); 398 | } 399 | 400 | reduceWhileStatement(node, { test, body }) { 401 | return super.reduceWhileStatement(node, { test: test(), body: body() }); 402 | } 403 | 404 | reduceWithStatement(node, { object, body }) { 405 | return super.reduceWithStatement(node, { object: object(), body: body() }); 406 | } 407 | 408 | reduceYieldExpression(node, { expression }) { 409 | return super.reduceYieldExpression(node, { expression: expression == null ? null : expression() }); 410 | } 411 | 412 | reduceYieldGeneratorExpression(node, { expression }) { 413 | return super.reduceYieldGeneratorExpression(node, { expression: expression() }); 414 | } 415 | }; 416 | }; 417 | -------------------------------------------------------------------------------- /gen/thunkify.js: -------------------------------------------------------------------------------- 1 | // Generated by generate-thunkify.js 2 | /** 3 | * Copyright 2018 Shape Security, Inc. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License") 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | module.exports = function thunkify(reducer) { 19 | return { 20 | reduceArrayAssignmentTarget(node, { elements, rest }) { 21 | return reducer.reduceArrayAssignmentTarget(node, { elements: elements.map(n => n == null ? null : n()), rest: rest == null ? null : rest() }); 22 | }, 23 | 24 | reduceArrayBinding(node, { elements, rest }) { 25 | return reducer.reduceArrayBinding(node, { elements: elements.map(n => n == null ? null : n()), rest: rest == null ? null : rest() }); 26 | }, 27 | 28 | reduceArrayExpression(node, { elements }) { 29 | return reducer.reduceArrayExpression(node, { elements: elements.map(n => n == null ? null : n()) }); 30 | }, 31 | 32 | reduceArrowExpression(node, { params, body }) { 33 | return reducer.reduceArrowExpression(node, { params: params(), body: body() }); 34 | }, 35 | 36 | reduceAssignmentExpression(node, { binding, expression }) { 37 | return reducer.reduceAssignmentExpression(node, { binding: binding(), expression: expression() }); 38 | }, 39 | 40 | reduceAssignmentTargetIdentifier(node) { 41 | return reducer.reduceAssignmentTargetIdentifier(node); 42 | }, 43 | 44 | reduceAssignmentTargetPropertyIdentifier(node, { binding, init }) { 45 | return reducer.reduceAssignmentTargetPropertyIdentifier(node, { binding: binding(), init: init == null ? null : init() }); 46 | }, 47 | 48 | reduceAssignmentTargetPropertyProperty(node, { name, binding }) { 49 | return reducer.reduceAssignmentTargetPropertyProperty(node, { name: name(), binding: binding() }); 50 | }, 51 | 52 | reduceAssignmentTargetWithDefault(node, { binding, init }) { 53 | return reducer.reduceAssignmentTargetWithDefault(node, { binding: binding(), init: init() }); 54 | }, 55 | 56 | reduceAwaitExpression(node, { expression }) { 57 | return reducer.reduceAwaitExpression(node, { expression: expression() }); 58 | }, 59 | 60 | reduceBinaryExpression(node, { left, right }) { 61 | return reducer.reduceBinaryExpression(node, { left: left(), right: right() }); 62 | }, 63 | 64 | reduceBindingIdentifier(node) { 65 | return reducer.reduceBindingIdentifier(node); 66 | }, 67 | 68 | reduceBindingPropertyIdentifier(node, { binding, init }) { 69 | return reducer.reduceBindingPropertyIdentifier(node, { binding: binding(), init: init == null ? null : init() }); 70 | }, 71 | 72 | reduceBindingPropertyProperty(node, { name, binding }) { 73 | return reducer.reduceBindingPropertyProperty(node, { name: name(), binding: binding() }); 74 | }, 75 | 76 | reduceBindingWithDefault(node, { binding, init }) { 77 | return reducer.reduceBindingWithDefault(node, { binding: binding(), init: init() }); 78 | }, 79 | 80 | reduceBlock(node, { statements }) { 81 | return reducer.reduceBlock(node, { statements: statements.map(n => n()) }); 82 | }, 83 | 84 | reduceBlockStatement(node, { block }) { 85 | return reducer.reduceBlockStatement(node, { block: block() }); 86 | }, 87 | 88 | reduceBreakStatement(node) { 89 | return reducer.reduceBreakStatement(node); 90 | }, 91 | 92 | reduceCallExpression(node, { callee, arguments: _arguments }) { 93 | return reducer.reduceCallExpression(node, { callee: callee(), arguments: _arguments.map(n => n()) }); 94 | }, 95 | 96 | reduceCatchClause(node, { binding, body }) { 97 | return reducer.reduceCatchClause(node, { binding: binding == null ? null : binding(), body: body() }); 98 | }, 99 | 100 | reduceClassDeclaration(node, { name, super: _super, elements }) { 101 | return reducer.reduceClassDeclaration(node, { name: name(), super: _super == null ? null : _super(), elements: elements.map(n => n()) }); 102 | }, 103 | 104 | reduceClassElement(node, { method }) { 105 | return reducer.reduceClassElement(node, { method: method() }); 106 | }, 107 | 108 | reduceClassExpression(node, { name, super: _super, elements }) { 109 | return reducer.reduceClassExpression(node, { name: name == null ? null : name(), super: _super == null ? null : _super(), elements: elements.map(n => n()) }); 110 | }, 111 | 112 | reduceCompoundAssignmentExpression(node, { binding, expression }) { 113 | return reducer.reduceCompoundAssignmentExpression(node, { binding: binding(), expression: expression() }); 114 | }, 115 | 116 | reduceComputedMemberAssignmentTarget(node, { object, expression }) { 117 | return reducer.reduceComputedMemberAssignmentTarget(node, { object: object(), expression: expression() }); 118 | }, 119 | 120 | reduceComputedMemberExpression(node, { object, expression }) { 121 | return reducer.reduceComputedMemberExpression(node, { object: object(), expression: expression() }); 122 | }, 123 | 124 | reduceComputedPropertyName(node, { expression }) { 125 | return reducer.reduceComputedPropertyName(node, { expression: expression() }); 126 | }, 127 | 128 | reduceConditionalExpression(node, { test, consequent, alternate }) { 129 | return reducer.reduceConditionalExpression(node, { test: test(), consequent: consequent(), alternate: alternate() }); 130 | }, 131 | 132 | reduceContinueStatement(node) { 133 | return reducer.reduceContinueStatement(node); 134 | }, 135 | 136 | reduceDataProperty(node, { name, expression }) { 137 | return reducer.reduceDataProperty(node, { name: name(), expression: expression() }); 138 | }, 139 | 140 | reduceDebuggerStatement(node) { 141 | return reducer.reduceDebuggerStatement(node); 142 | }, 143 | 144 | reduceDirective(node) { 145 | return reducer.reduceDirective(node); 146 | }, 147 | 148 | reduceDoWhileStatement(node, { body, test }) { 149 | return reducer.reduceDoWhileStatement(node, { body: body(), test: test() }); 150 | }, 151 | 152 | reduceEmptyStatement(node) { 153 | return reducer.reduceEmptyStatement(node); 154 | }, 155 | 156 | reduceExport(node, { declaration }) { 157 | return reducer.reduceExport(node, { declaration: declaration() }); 158 | }, 159 | 160 | reduceExportAllFrom(node) { 161 | return reducer.reduceExportAllFrom(node); 162 | }, 163 | 164 | reduceExportDefault(node, { body }) { 165 | return reducer.reduceExportDefault(node, { body: body() }); 166 | }, 167 | 168 | reduceExportFrom(node, { namedExports }) { 169 | return reducer.reduceExportFrom(node, { namedExports: namedExports.map(n => n()) }); 170 | }, 171 | 172 | reduceExportFromSpecifier(node) { 173 | return reducer.reduceExportFromSpecifier(node); 174 | }, 175 | 176 | reduceExportLocalSpecifier(node, { name }) { 177 | return reducer.reduceExportLocalSpecifier(node, { name: name() }); 178 | }, 179 | 180 | reduceExportLocals(node, { namedExports }) { 181 | return reducer.reduceExportLocals(node, { namedExports: namedExports.map(n => n()) }); 182 | }, 183 | 184 | reduceExpressionStatement(node, { expression }) { 185 | return reducer.reduceExpressionStatement(node, { expression: expression() }); 186 | }, 187 | 188 | reduceForAwaitStatement(node, { left, right, body }) { 189 | return reducer.reduceForAwaitStatement(node, { left: left(), right: right(), body: body() }); 190 | }, 191 | 192 | reduceForInStatement(node, { left, right, body }) { 193 | return reducer.reduceForInStatement(node, { left: left(), right: right(), body: body() }); 194 | }, 195 | 196 | reduceForOfStatement(node, { left, right, body }) { 197 | return reducer.reduceForOfStatement(node, { left: left(), right: right(), body: body() }); 198 | }, 199 | 200 | reduceForStatement(node, { init, test, update, body }) { 201 | return reducer.reduceForStatement(node, { init: init == null ? null : init(), test: test == null ? null : test(), update: update == null ? null : update(), body: body() }); 202 | }, 203 | 204 | reduceFormalParameters(node, { items, rest }) { 205 | return reducer.reduceFormalParameters(node, { items: items.map(n => n()), rest: rest == null ? null : rest() }); 206 | }, 207 | 208 | reduceFunctionBody(node, { directives, statements }) { 209 | return reducer.reduceFunctionBody(node, { directives: directives.map(n => n()), statements: statements.map(n => n()) }); 210 | }, 211 | 212 | reduceFunctionDeclaration(node, { name, params, body }) { 213 | return reducer.reduceFunctionDeclaration(node, { name: name(), params: params(), body: body() }); 214 | }, 215 | 216 | reduceFunctionExpression(node, { name, params, body }) { 217 | return reducer.reduceFunctionExpression(node, { name: name == null ? null : name(), params: params(), body: body() }); 218 | }, 219 | 220 | reduceGetter(node, { name, body }) { 221 | return reducer.reduceGetter(node, { name: name(), body: body() }); 222 | }, 223 | 224 | reduceIdentifierExpression(node) { 225 | return reducer.reduceIdentifierExpression(node); 226 | }, 227 | 228 | reduceIfStatement(node, { test, consequent, alternate }) { 229 | return reducer.reduceIfStatement(node, { test: test(), consequent: consequent(), alternate: alternate == null ? null : alternate() }); 230 | }, 231 | 232 | reduceImport(node, { defaultBinding, namedImports }) { 233 | return reducer.reduceImport(node, { defaultBinding: defaultBinding == null ? null : defaultBinding(), namedImports: namedImports.map(n => n()) }); 234 | }, 235 | 236 | reduceImportNamespace(node, { defaultBinding, namespaceBinding }) { 237 | return reducer.reduceImportNamespace(node, { defaultBinding: defaultBinding == null ? null : defaultBinding(), namespaceBinding: namespaceBinding() }); 238 | }, 239 | 240 | reduceImportSpecifier(node, { binding }) { 241 | return reducer.reduceImportSpecifier(node, { binding: binding() }); 242 | }, 243 | 244 | reduceLabeledStatement(node, { body }) { 245 | return reducer.reduceLabeledStatement(node, { body: body() }); 246 | }, 247 | 248 | reduceLiteralBooleanExpression(node) { 249 | return reducer.reduceLiteralBooleanExpression(node); 250 | }, 251 | 252 | reduceLiteralInfinityExpression(node) { 253 | return reducer.reduceLiteralInfinityExpression(node); 254 | }, 255 | 256 | reduceLiteralNullExpression(node) { 257 | return reducer.reduceLiteralNullExpression(node); 258 | }, 259 | 260 | reduceLiteralNumericExpression(node) { 261 | return reducer.reduceLiteralNumericExpression(node); 262 | }, 263 | 264 | reduceLiteralRegExpExpression(node) { 265 | return reducer.reduceLiteralRegExpExpression(node); 266 | }, 267 | 268 | reduceLiteralStringExpression(node) { 269 | return reducer.reduceLiteralStringExpression(node); 270 | }, 271 | 272 | reduceMethod(node, { name, params, body }) { 273 | return reducer.reduceMethod(node, { name: name(), params: params(), body: body() }); 274 | }, 275 | 276 | reduceModule(node, { directives, items }) { 277 | return reducer.reduceModule(node, { directives: directives.map(n => n()), items: items.map(n => n()) }); 278 | }, 279 | 280 | reduceNewExpression(node, { callee, arguments: _arguments }) { 281 | return reducer.reduceNewExpression(node, { callee: callee(), arguments: _arguments.map(n => n()) }); 282 | }, 283 | 284 | reduceNewTargetExpression(node) { 285 | return reducer.reduceNewTargetExpression(node); 286 | }, 287 | 288 | reduceObjectAssignmentTarget(node, { properties, rest }) { 289 | return reducer.reduceObjectAssignmentTarget(node, { properties: properties.map(n => n()), rest: rest == null ? null : rest() }); 290 | }, 291 | 292 | reduceObjectBinding(node, { properties, rest }) { 293 | return reducer.reduceObjectBinding(node, { properties: properties.map(n => n()), rest: rest == null ? null : rest() }); 294 | }, 295 | 296 | reduceObjectExpression(node, { properties }) { 297 | return reducer.reduceObjectExpression(node, { properties: properties.map(n => n()) }); 298 | }, 299 | 300 | reduceReturnStatement(node, { expression }) { 301 | return reducer.reduceReturnStatement(node, { expression: expression == null ? null : expression() }); 302 | }, 303 | 304 | reduceScript(node, { directives, statements }) { 305 | return reducer.reduceScript(node, { directives: directives.map(n => n()), statements: statements.map(n => n()) }); 306 | }, 307 | 308 | reduceSetter(node, { name, param, body }) { 309 | return reducer.reduceSetter(node, { name: name(), param: param(), body: body() }); 310 | }, 311 | 312 | reduceShorthandProperty(node, { name }) { 313 | return reducer.reduceShorthandProperty(node, { name: name() }); 314 | }, 315 | 316 | reduceSpreadElement(node, { expression }) { 317 | return reducer.reduceSpreadElement(node, { expression: expression() }); 318 | }, 319 | 320 | reduceSpreadProperty(node, { expression }) { 321 | return reducer.reduceSpreadProperty(node, { expression: expression() }); 322 | }, 323 | 324 | reduceStaticMemberAssignmentTarget(node, { object }) { 325 | return reducer.reduceStaticMemberAssignmentTarget(node, { object: object() }); 326 | }, 327 | 328 | reduceStaticMemberExpression(node, { object }) { 329 | return reducer.reduceStaticMemberExpression(node, { object: object() }); 330 | }, 331 | 332 | reduceStaticPropertyName(node) { 333 | return reducer.reduceStaticPropertyName(node); 334 | }, 335 | 336 | reduceSuper(node) { 337 | return reducer.reduceSuper(node); 338 | }, 339 | 340 | reduceSwitchCase(node, { test, consequent }) { 341 | return reducer.reduceSwitchCase(node, { test: test(), consequent: consequent.map(n => n()) }); 342 | }, 343 | 344 | reduceSwitchDefault(node, { consequent }) { 345 | return reducer.reduceSwitchDefault(node, { consequent: consequent.map(n => n()) }); 346 | }, 347 | 348 | reduceSwitchStatement(node, { discriminant, cases }) { 349 | return reducer.reduceSwitchStatement(node, { discriminant: discriminant(), cases: cases.map(n => n()) }); 350 | }, 351 | 352 | reduceSwitchStatementWithDefault(node, { discriminant, preDefaultCases, defaultCase, postDefaultCases }) { 353 | return reducer.reduceSwitchStatementWithDefault(node, { discriminant: discriminant(), preDefaultCases: preDefaultCases.map(n => n()), defaultCase: defaultCase(), postDefaultCases: postDefaultCases.map(n => n()) }); 354 | }, 355 | 356 | reduceTemplateElement(node) { 357 | return reducer.reduceTemplateElement(node); 358 | }, 359 | 360 | reduceTemplateExpression(node, { tag, elements }) { 361 | return reducer.reduceTemplateExpression(node, { tag: tag == null ? null : tag(), elements: elements.map(n => n()) }); 362 | }, 363 | 364 | reduceThisExpression(node) { 365 | return reducer.reduceThisExpression(node); 366 | }, 367 | 368 | reduceThrowStatement(node, { expression }) { 369 | return reducer.reduceThrowStatement(node, { expression: expression() }); 370 | }, 371 | 372 | reduceTryCatchStatement(node, { body, catchClause }) { 373 | return reducer.reduceTryCatchStatement(node, { body: body(), catchClause: catchClause() }); 374 | }, 375 | 376 | reduceTryFinallyStatement(node, { body, catchClause, finalizer }) { 377 | return reducer.reduceTryFinallyStatement(node, { body: body(), catchClause: catchClause == null ? null : catchClause(), finalizer: finalizer() }); 378 | }, 379 | 380 | reduceUnaryExpression(node, { operand }) { 381 | return reducer.reduceUnaryExpression(node, { operand: operand() }); 382 | }, 383 | 384 | reduceUpdateExpression(node, { operand }) { 385 | return reducer.reduceUpdateExpression(node, { operand: operand() }); 386 | }, 387 | 388 | reduceVariableDeclaration(node, { declarators }) { 389 | return reducer.reduceVariableDeclaration(node, { declarators: declarators.map(n => n()) }); 390 | }, 391 | 392 | reduceVariableDeclarationStatement(node, { declaration }) { 393 | return reducer.reduceVariableDeclarationStatement(node, { declaration: declaration() }); 394 | }, 395 | 396 | reduceVariableDeclarator(node, { binding, init }) { 397 | return reducer.reduceVariableDeclarator(node, { binding: binding(), init: init == null ? null : init() }); 398 | }, 399 | 400 | reduceWhileStatement(node, { test, body }) { 401 | return reducer.reduceWhileStatement(node, { test: test(), body: body() }); 402 | }, 403 | 404 | reduceWithStatement(node, { object, body }) { 405 | return reducer.reduceWithStatement(node, { object: object(), body: body() }); 406 | }, 407 | 408 | reduceYieldExpression(node, { expression }) { 409 | return reducer.reduceYieldExpression(node, { expression: expression == null ? null : expression() }); 410 | }, 411 | 412 | reduceYieldGeneratorExpression(node, { expression }) { 413 | return reducer.reduceYieldGeneratorExpression(node, { expression: expression() }); 414 | }, 415 | }; 416 | }; 417 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "shift-reducer", 3 | "version": "7.0.0", 4 | "description": "reducer for the Shift AST format", 5 | "author": "Shape Security", 6 | "homepage": "https://github.com/shapesecurity/shift-reducer-js", 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/shapesecurity/shift-reducer-js.git" 10 | }, 11 | "main": "src/index.js", 12 | "files": [ 13 | "gen", 14 | "src" 15 | ], 16 | "scripts": { 17 | "test": "mocha --inline-diffs --check-leaks --ui tdd --reporter dot test", 18 | "build": "mkdir -p gen && (for i in scripts/build/*; do node $i; done)", 19 | "prepare": "rm -rf gen/*.js && npm run build", 20 | "lint": "eslint src gen test examples" 21 | }, 22 | "dependencies": { 23 | "shift-ast": "7.0.0" 24 | }, 25 | "devDependencies": { 26 | "eslint": "5.6.1", 27 | "everything.js": "^1.0.3", 28 | "mocha": "^8.1.3", 29 | "shift-parser": "7.0.0", 30 | "shift-spec": "2019.0.0" 31 | }, 32 | "keywords": [ 33 | "Shift", 34 | "AST", 35 | "reducer", 36 | "reduce", 37 | "reducible", 38 | "monoidal", 39 | "monoid", 40 | "fold", 41 | "summary", 42 | "summarise", 43 | "abstract", 44 | "syntax", 45 | "tree" 46 | ], 47 | "bugs": { 48 | "url": "https://github.com/shapesecurity/shift-reducer-js/issues" 49 | }, 50 | "license": "Apache-2.0" 51 | } 52 | -------------------------------------------------------------------------------- /scripts/build/generate-adapt.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2018 Shape Security, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License") 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict'; 18 | 19 | const spec = require('shift-spec'); 20 | const { makeHeader } = require('../lib/utilities.js'); 21 | 22 | let content = `${makeHeader(__filename)} 23 | const Shift = require('shift-ast'); 24 | 25 | module.exports = (fn, reducer) => ({ 26 | __proto__: reducer, 27 | ${Object.keys(spec).map(typeName => ` 28 | reduce${typeName}(node, data) { 29 | return fn(super.reduce${typeName}(node, data), node); 30 | },`).join('\n')} 31 | }); 32 | `; 33 | 34 | require('fs').writeFileSync('gen/adapt.js', content, 'utf-8'); 35 | -------------------------------------------------------------------------------- /scripts/build/generate-clone-reducer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016 Shape Security, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License") 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict'; 18 | 19 | const spec = require('shift-spec'); 20 | const { makeHeader, parameterize, isStatefulType } = require('../lib/utilities.js'); 21 | 22 | let content = `${makeHeader(__filename)} 23 | const Shift = require('shift-ast'); 24 | 25 | module.exports = class CloneReducer {`; 26 | 27 | function cloneField(f) { 28 | if (!isStatefulType(f.type)) { 29 | return `${f.name}: node.${f.name}`; 30 | } 31 | return parameterize(f.name); 32 | } 33 | 34 | for (let typeName of Object.keys(spec)) { 35 | let type = spec[typeName]; 36 | let fields = type.fields.filter(f => f.name !== 'type'); 37 | if (fields.length === 0) { 38 | content += ` 39 | reduce${typeName}(node) { 40 | return new Shift.${typeName}; 41 | } 42 | `; 43 | } else { 44 | let statefulFields = fields.filter(f => isStatefulType(f.type)); 45 | let param = statefulFields.length > 0 ? `, { ${statefulFields.map(f => parameterize(f.name)).join(', ')} }` : ''; 46 | content += ` 47 | reduce${typeName}(node${param}) { 48 | return new Shift.${typeName}({ ${fields.map(cloneField).join(', ')} }); 49 | } 50 | `; 51 | } 52 | } 53 | 54 | content += `}; 55 | `; 56 | 57 | require('fs').writeFileSync('gen/clone-reducer.js', content, 'utf-8'); 58 | -------------------------------------------------------------------------------- /scripts/build/generate-director.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016 Shape Security, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License") 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict'; 18 | 19 | const spec = require('shift-spec'); 20 | const { makeHeader, isStatefulType } = require('../lib/utilities.js'); 21 | 22 | function buildContent(isThunked) { 23 | let content = `${makeHeader(__filename)} 24 | const director = {`; 25 | 26 | function reduce(name, type) { 27 | switch (type.typeName) { 28 | case 'Maybe': 29 | return `${name} && ${reduce(name, type.argument)}`; 30 | case 'List': 31 | return `${name}.map(v => ${reduce('v', type.argument)})`; 32 | case 'Union': 33 | return `${isThunked ? '(() => ' : ''}this[${name}.type](reducer, ${name})${isThunked ? ')' : ''}`; 34 | default: 35 | return `${isThunked ? '(() => ' : ''}this.${type.typeName}(reducer, ${name})${isThunked ? ')' : ''}`; 36 | } 37 | } 38 | 39 | for (let typeName of Object.keys(spec)) { 40 | let type = spec[typeName]; 41 | let fields = type.fields.filter(f => f.name !== 'type' && isStatefulType(f.type)); 42 | if (fields.length === 0) { 43 | content += ` 44 | ${typeName}(reducer, node) { 45 | return reducer.reduce${typeName}(node); 46 | }, 47 | `; 48 | 49 | } else { 50 | content += ` 51 | ${typeName}(reducer, node) { 52 | return reducer.reduce${typeName}(node, { ${fields.map(f => `${f.name}: ${reduce(`node.${f.name}`, f.type)}`).join(', ')} }); 53 | }, 54 | `; 55 | 56 | } 57 | } 58 | 59 | content += `}; 60 | 61 | module.exports = function ${isThunked ? 'thunkedReduce' : 'reduce'}(reducer, node) { 62 | return director[node.type](reducer, node); 63 | }; 64 | `; 65 | 66 | return content; 67 | } 68 | 69 | require('fs').writeFileSync('gen/director.js', buildContent(false), 'utf-8'); 70 | require('fs').writeFileSync('gen/thunked-director.js', buildContent(true), 'utf-8'); 71 | -------------------------------------------------------------------------------- /scripts/build/generate-lazy-clone-reducer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016 Shape Security, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License") 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict'; 18 | 19 | const spec = require('shift-spec'); 20 | const { makeHeader, sanitize, parameterize, isStatefulType, isNodeOrUnionOfNodes } = require('../lib/utilities.js'); 21 | 22 | function generateEquals(type, a, b) { 23 | switch (type.typeName) { 24 | case 'Enum': 25 | case 'String': 26 | case 'Number': 27 | case 'Boolean': 28 | throw new Error('not reached'); 29 | case 'List': 30 | switch (type.argument.typeName) { 31 | case 'Enum': 32 | case 'String': 33 | case 'Number': 34 | case 'Boolean': 35 | throw new Error('not reached'); 36 | case 'List': 37 | throw new Error('unimplemented: lists of lists'); 38 | case 'Maybe': 39 | if (isNodeOrUnionOfNodes(type.argument.argument)) { 40 | return `(${a}.length === ${b}.length && ${a}.every((v, i) => v === ${b}[i]))`; 41 | } 42 | throw new Error('unimplemented: list of maybe of ' + type.argument.argument); 43 | default: 44 | if (isNodeOrUnionOfNodes(type.argument)) { 45 | return `(${a}.length === ${b}.length && ${a}.every((v, i) => v === ${b}[i]))`; 46 | } 47 | throw new Error('unimplemented: list of ' + type.argument); 48 | } 49 | case 'Maybe': 50 | if (isNodeOrUnionOfNodes(type.argument)) { 51 | return a + ' === ' + b; 52 | } 53 | throw new Error('unimplemented: maybe of ' + type.argument); 54 | default: 55 | if (isNodeOrUnionOfNodes(type)) { 56 | return a + ' === ' + b; 57 | } 58 | throw new Error('unimplemented: ' + type); 59 | } 60 | } 61 | 62 | let content = `${makeHeader(__filename)} 63 | const Shift = require('shift-ast'); 64 | 65 | module.exports = class LazyCloneReducer {`; 66 | 67 | function cloneField(f) { 68 | if (!isStatefulType(f.type)) { 69 | return `${f.name}: node.${f.name}`; 70 | } 71 | return parameterize(f.name); 72 | } 73 | 74 | for (let typeName of Object.keys(spec)) { 75 | let type = spec[typeName]; 76 | let fields = type.fields.filter(f => f.name !== 'type'); 77 | let statefulFields = fields.filter(f => isStatefulType(f.type)); 78 | let param = statefulFields.length > 0 ? `, { ${statefulFields.map(f => parameterize(f.name)).join(', ')} }` : ''; 79 | content += ` 80 | reduce${typeName}(node${param}) {`; 81 | if (statefulFields.length === 0) { 82 | content += ` 83 | return node; 84 | } 85 | `; 86 | } else { 87 | content += ` 88 | if (${statefulFields.map(f => generateEquals(f.type, 'node.' + f.name, sanitize(f.name))).join(' && ')}) { 89 | return node; 90 | } 91 | return new Shift.${typeName}({ ${fields.map(cloneField).join(', ')} }); 92 | } 93 | `; 94 | } 95 | } 96 | 97 | content += `}; 98 | `; 99 | 100 | require('fs').writeFileSync('gen/lazy-clone-reducer.js', content, 'utf-8'); 101 | -------------------------------------------------------------------------------- /scripts/build/generate-memoize.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2018 Shape Security, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License") 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict'; 18 | 19 | const spec = require('shift-spec'); 20 | const { makeHeader, isStatefulType } = require('../lib/utilities.js'); 21 | 22 | let content = `${makeHeader(__filename)} 23 | const Shift = require('shift-ast'); 24 | 25 | module.exports = function memoize(reducer) { 26 | const cache = new WeakMap; 27 | return {`; 28 | 29 | for (let typeName of Object.keys(spec)) { 30 | let type = spec[typeName]; 31 | let fields = type.fields.filter(f => f.name !== 'type'); 32 | const hasArg = fields.some(f => isStatefulType(f.type)); 33 | const parameters = `node${hasArg ? ', arg' : ''}`; 34 | content += ` 35 | reduce${typeName}(${parameters}) { 36 | if (cache.has(node)) { 37 | return cache.get(node); 38 | } 39 | const res = reducer.reduce${typeName}(${parameters}); 40 | cache.set(node, res); 41 | return res; 42 | }, 43 | `; 44 | } 45 | 46 | content += ` }; 47 | }; 48 | `; 49 | 50 | require('fs').writeFileSync('gen/memoize.js', content, 'utf-8'); 51 | -------------------------------------------------------------------------------- /scripts/build/generate-monoidal-reducer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016 Shape Security, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License") 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict'; 18 | 19 | const spec = require('shift-spec'); 20 | const { makeHeader, sanitize, parameterize, isStatefulType } = require('../lib/utilities.js'); 21 | 22 | 23 | function toVal(isThunked, { name, type }) { 24 | switch (type.typeName) { 25 | case 'Maybe': 26 | return `${sanitize(name)} == null ? this.identity : ${sanitize(name)}${isThunked ? '()' : ''}`; 27 | case 'List': 28 | if (type.argument.typeName === 'Maybe') { 29 | return `this.append(...${sanitize(name)}.filter(n => n != null))`; 30 | } 31 | return `this.append(...${sanitize(name)})`; 32 | default: 33 | return sanitize(name) + (isThunked ? '()' : ''); 34 | } 35 | } 36 | 37 | function toArg(isThunked, { name, type }) { 38 | switch (type.typeName) { 39 | case 'Maybe': 40 | return `${sanitize(name)} == null ? ${isThunked ? '() => ' : ''}this.identity : ${sanitize(name)}`; 41 | case 'List': 42 | if (type.argument.typeName === 'Maybe') { 43 | return `...${sanitize(name)}.filter(n => n != null)`; 44 | } 45 | return `...${sanitize(name)}`; 46 | default: 47 | return sanitize(name); 48 | } 49 | } 50 | 51 | 52 | const regularPrefix = `${makeHeader(__filename)} 53 | const Shift = require('shift-ast'); 54 | 55 | module.exports = class MonoidalReducer { 56 | constructor(monoid) { 57 | let identity = monoid.empty(); 58 | this.identity = identity; 59 | let concat; 60 | if (monoid.prototype && typeof monoid.prototype.concat === 'function') { 61 | concat = Function.prototype.call.bind(monoid.prototype.concat); 62 | } else if (typeof monoid.concat === 'function') { 63 | concat = monoid.concat; 64 | } else { 65 | throw new TypeError('Monoid must provide a \`concat\` method'); 66 | } 67 | this.append = (...args) => args.reduce(concat, identity); 68 | } 69 | `; 70 | 71 | const thunkedPrefix = `${makeHeader(__filename)} 72 | const Shift = require('shift-ast'); 73 | 74 | module.exports = class MonoidalReducer { 75 | constructor(monoid) { 76 | let identity = monoid.empty(); 77 | this.identity = identity; 78 | 79 | let concatThunk; 80 | if (monoid.prototype && typeof monoid.prototype.concatThunk === 'function') { 81 | concatThunk = Function.prototype.call.bind(monoid.prototype.concatThunk); 82 | } else if (typeof monoid.concatThunk === 'function') { 83 | concatThunk = monoid.concatThunk; 84 | } else { 85 | let concat; 86 | if (monoid.prototype && typeof monoid.prototype.concat === 'function') { 87 | concat = Function.prototype.call.bind(monoid.prototype.concat); 88 | } else if (typeof monoid.concat === 'function') { 89 | concat = monoid.concat; 90 | } else { 91 | throw new TypeError('Monoid must provide a \`concatThunk\` or \`concat\` method'); 92 | } 93 | if (typeof monoid.isAbsorbing === 'function') { 94 | let isAbsorbing = monoid.isAbsorbing; 95 | concatThunk = (a, b) => isAbsorbing(a) ? a : concat(a, b()); 96 | } else { 97 | concatThunk = (a, b) => concat(a, b()); 98 | } 99 | } 100 | this.append = (...args) => args.reduce(concatThunk, identity); 101 | } 102 | `; 103 | 104 | 105 | function buildContent(isThunked) { 106 | let content = isThunked ? thunkedPrefix : regularPrefix; 107 | for (let typeName of Object.keys(spec)) { 108 | let type = spec[typeName]; 109 | let fields = type.fields.filter(f => f.name !== 'type' && isStatefulType(f.type)); 110 | if (fields.length === 0) { 111 | content += ` 112 | reduce${typeName}(node) { 113 | return this.identity; 114 | } 115 | `; 116 | } else { 117 | let param = `{ ${fields.map(f => parameterize(f.name)).join(', ')} }`; 118 | content += ` 119 | reduce${typeName}(node, ${param}) { 120 | `; 121 | if (fields.length === 1) { 122 | content += `return ${toVal(isThunked, fields[0])};`; 123 | } else { 124 | content += `return this.append(${fields.map(f => toArg(isThunked, f)).join(', ')});`; 125 | } 126 | content += ` 127 | } 128 | `; 129 | } 130 | } 131 | 132 | content += `}; 133 | `; 134 | 135 | return content; 136 | } 137 | require('fs').writeFileSync('gen/monoidal-reducer.js', buildContent(false), 'utf-8'); 138 | require('fs').writeFileSync('gen/thunked-monoidal-reducer.js', buildContent(true), 'utf-8'); 139 | -------------------------------------------------------------------------------- /scripts/build/generate-thunkify.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2018 Shape Security, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License") 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict'; 18 | 19 | const spec = require('shift-spec'); 20 | const { makeHeader, sanitize, parameterize, isStatefulType } = require('../lib/utilities.js'); 21 | 22 | function force({ name, type }) { 23 | switch (type.typeName) { 24 | case 'Maybe': 25 | return `${sanitize(name)} == null ? null : ${sanitize(name)}()`; 26 | case 'List': 27 | if (type.argument.typeName === 'Maybe') { 28 | return `${sanitize(name)}.map(n => n == null ? null : n())`; 29 | } 30 | return `${sanitize(name)}.map(n => n())`; 31 | default: 32 | return sanitize(name) + '()'; 33 | } 34 | } 35 | 36 | [true, false].forEach(isClass => { 37 | let content = `${makeHeader(__filename)} 38 | module.exports = function thunkify${isClass ? 'Class' : ''}(reducer${isClass ? 'Class' : ''}) { 39 | return ${isClass ? 'class extends reducerClass ' : ''}{`; 40 | 41 | for (let typeName of Object.keys(spec)) { 42 | let type = spec[typeName]; 43 | let fields = type.fields.filter(f => f.name !== 'type'); 44 | let statefulFields = fields.filter(f => isStatefulType(f.type)); 45 | let param = statefulFields.length > 0 ? `, { ${statefulFields.map(f => parameterize(f.name)).join(', ')} }` : ''; 46 | let base = isClass ? 'super' : 'reducer'; 47 | content += ` 48 | reduce${typeName}(node${param}) {`; 49 | if (statefulFields.length === 0) { 50 | content += ` 51 | return ${base}.reduce${typeName}(node);`; 52 | } else { 53 | content += ` 54 | return ${base}.reduce${typeName}(node, { ${statefulFields.map(f => f.name + ': ' + force(f)).join(', ')} });`; 55 | } 56 | content += ` 57 | }${isClass ? '' : ','} 58 | `; 59 | } 60 | 61 | content += ` }; 62 | }; 63 | `; 64 | 65 | require('fs').writeFileSync(`gen/thunkify${isClass ? '-class' : ''}.js`, content, 'utf-8'); 66 | }); 67 | -------------------------------------------------------------------------------- /scripts/lib/utilities.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const path = require('path'); 4 | const spec = require('shift-spec'); 5 | const { isRestrictedWord, isReservedWordES6 } = require('esutils').keyword; 6 | 7 | function sanitize(fieldName) { 8 | if (isRestrictedWord(fieldName) || isReservedWordES6(fieldName)) { 9 | return '_' + fieldName; 10 | } 11 | return fieldName; 12 | } 13 | 14 | function parameterize(fieldName) { 15 | if (isRestrictedWord(fieldName) || isReservedWordES6(fieldName)) { 16 | return fieldName + ': _' + fieldName; 17 | } 18 | return fieldName; 19 | } 20 | 21 | function isNodeOrUnionOfNodes(type) { 22 | return type.typeName === 'Union' && type.arguments.every(isNodeOrUnionOfNodes) || spec.hasOwnProperty(type.typeName); 23 | } 24 | 25 | function isStatefulType(type) { 26 | switch (type.typeName) { 27 | case 'Enum': 28 | case 'String': 29 | case 'Number': 30 | case 'Boolean': 31 | return false; 32 | case 'Maybe': 33 | case 'List': 34 | return isStatefulType(type.argument); 35 | case 'Union': 36 | return type.arguments.some(isStatefulType); 37 | default: 38 | if (isNodeOrUnionOfNodes(type)) { 39 | return true; 40 | } 41 | throw new Error('unimplemented: type ' + type); 42 | } 43 | } 44 | 45 | function makeHeader(filename) { 46 | return `// Generated by ${path.basename(filename)} 47 | /** 48 | * Copyright 2018 Shape Security, Inc. 49 | * 50 | * Licensed under the Apache License, Version 2.0 (the "License") 51 | * you may not use this file except in compliance with the License. 52 | * You may obtain a copy of the License at 53 | * 54 | * http://www.apache.org/licenses/LICENSE-2.0 55 | * 56 | * Unless required by applicable law or agreed to in writing, software 57 | * distributed under the License is distributed on an "AS IS" BASIS, 58 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 59 | * See the License for the specific language governing permissions and 60 | * limitations under the License. 61 | */ 62 | `; 63 | } 64 | 65 | module.exports = { 66 | sanitize, 67 | parameterize, 68 | isNodeOrUnionOfNodes, 69 | isStatefulType, 70 | makeHeader, 71 | }; 72 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Shape Security, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License") 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | const reduce = require('../gen/director.js'); 18 | const thunkedReduce = require('../gen/thunked-director.js'); 19 | const thunkify = require('../gen/thunkify.js'); 20 | const thunkifyClass = require('../gen/thunkify-class.js'); 21 | const memoize = require('../gen/memoize.js'); 22 | const CloneReducer = require('../gen/clone-reducer.js'); 23 | const LazyCloneReducer = require('../gen/lazy-clone-reducer.js'); 24 | const MonoidalReducer = require('../gen/monoidal-reducer.js'); 25 | const ThunkedMonoidalReducer = require('../gen/thunked-monoidal-reducer.js'); 26 | const adapt = require('../gen/adapt.js'); 27 | const { PlusReducer, ThunkedPlusReducer, ConcatReducer, ThunkedConcatReducer, AndReducer, ThunkedAndReducer, OrReducer, ThunkedOrReducer } = require('./reducers.js'); 28 | 29 | module.exports = { 30 | default: reduce, 31 | reduce, 32 | thunkedReduce, 33 | thunkify, 34 | thunkifyClass, 35 | memoize, 36 | CloneReducer, 37 | LazyCloneReducer, 38 | MonoidalReducer, 39 | ThunkedMonoidalReducer, 40 | adapt, 41 | PlusReducer, 42 | ThunkedPlusReducer, 43 | ConcatReducer, 44 | ThunkedConcatReducer, 45 | AndReducer, 46 | ThunkedAndReducer, 47 | OrReducer, 48 | ThunkedOrReducer, 49 | }; 50 | -------------------------------------------------------------------------------- /src/reducers.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Shape Security, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License") 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict'; 18 | 19 | const MonoidalReducer = require('../gen/monoidal-reducer.js'); 20 | const ThunkedMonoidalReducer = require('../gen/thunked-monoidal-reducer.js'); 21 | 22 | const PlusMonoid = { 23 | empty: () => 0, 24 | concat: (a, b) => a + b, 25 | }; 26 | 27 | const ConcatMonoid = { 28 | empty: () => [], 29 | concat: (a, b) => a.concat(b), 30 | }; 31 | 32 | const AndMonoid = { 33 | empty: () => true, 34 | concat: (a, b) => a && b, 35 | concatThunk: (a, b) => a && b(), 36 | }; 37 | 38 | const OrMonoid = { 39 | empty: () => false, 40 | concat: (a, b) => a || b, 41 | concatThunk: (a, b) => a || b(), 42 | }; 43 | 44 | 45 | exports.PlusReducer = class PlusReducer extends MonoidalReducer { 46 | constructor() { 47 | super(PlusMonoid); 48 | } 49 | }; 50 | 51 | exports.ThunkedPlusReducer = class ThunkedPlusReducer extends ThunkedMonoidalReducer { 52 | constructor() { 53 | super(PlusMonoid); 54 | } 55 | }; 56 | 57 | exports.ConcatReducer = class ConcatReducer extends MonoidalReducer { 58 | constructor() { 59 | super(ConcatMonoid); 60 | } 61 | }; 62 | 63 | exports.ThunkedConcatReducer = class ThunkedConcatReducer extends ThunkedMonoidalReducer { 64 | constructor() { 65 | super(ConcatMonoid); 66 | } 67 | }; 68 | 69 | exports.AndReducer = class AndReducer extends MonoidalReducer { 70 | constructor() { 71 | super(AndMonoid); 72 | } 73 | }; 74 | 75 | exports.ThunkedAndReducer = class ThunkedAndReducer extends ThunkedMonoidalReducer { 76 | constructor() { 77 | super(AndMonoid); 78 | } 79 | }; 80 | 81 | exports.OrReducer = class OrReducer extends MonoidalReducer { 82 | constructor() { 83 | super(OrMonoid); 84 | } 85 | }; 86 | 87 | exports.ThunkedOrReducer = class ThunkedOrReducer extends ThunkedMonoidalReducer { 88 | constructor() { 89 | super(OrMonoid); 90 | } 91 | }; 92 | -------------------------------------------------------------------------------- /test/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: "../.eslintrc.js", 3 | env: { 4 | mocha: true, 5 | node: true 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /test/adapt.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2018 Shape Security, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License") 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict'; 18 | 19 | const assert = require('assert'); 20 | 21 | const { reduce, PlusReducer, ConcatReducer, adapt } = require('../'); 22 | const { parseModule } = require('shift-parser'); 23 | 24 | suite('adapt', () => { 25 | test('adapt adapts', () => { 26 | const countNodes = adapt(d => d + 1, new PlusReducer); 27 | 28 | assert.equal(reduce(countNodes, parseModule('a + b')), 5); 29 | }); 30 | 31 | test('adapt has node available to it', () => { 32 | const listNodes = adapt((d, node) => d.concat([node.type]), new ConcatReducer); 33 | 34 | assert.deepStrictEqual(reduce(listNodes, parseModule('a + b')), [ 35 | 'IdentifierExpression', 36 | 'IdentifierExpression', 37 | 'BinaryExpression', 38 | 'ExpressionStatement', 39 | 'Module', 40 | ]); 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /test/clone-reducer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016 Shape Security, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the 'License') 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an 'AS IS' BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // const assert = require('assert'); 18 | 19 | // const { CloneReducer, default: reduce } = require('../'); 20 | // const { parseScript, parseModule } = require('shift-parser'); 21 | 22 | // const fs = require('fs'); 23 | 24 | // suite('clone', () => { 25 | // describe('everything.js', () => { 26 | // it('should clone to a thing which is equal to itself, but not itself', () => { 27 | // let tree, clonedTree; 28 | 29 | // tree = parseModule(fs.readFileSync(require.resolve('everything.js/es2015-module'), 'utf8')); 30 | // clonedTree = reduce(new CloneReducer, tree); 31 | // assert.deepEqual(tree, clonedTree); 32 | // assert.notEqual(tree, clonedTree); 33 | 34 | // tree = parseScript(fs.readFileSync(require.resolve('everything.js/es2015-script'), 'utf8')); 35 | // clonedTree = reduce(new CloneReducer, tree); 36 | // assert.deepEqual(tree, clonedTree); 37 | // assert.notEqual(tree, clonedTree); 38 | // }); 39 | // }); 40 | // }); 41 | -------------------------------------------------------------------------------- /test/lazy-clone-reducer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 Shape Security, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the 'License') 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an 'AS IS' BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | const assert = require('assert'); 18 | 19 | const { LazyCloneReducer, default: reduce } = require('../'); 20 | const { parseScript, parseModule } = require('shift-parser'); 21 | 22 | const fs = require('fs'); 23 | 24 | suite('lazy-clone', () => { 25 | test('everything.js should clone to itself', () => { 26 | test('should clone to itself', () => { 27 | let tree, clonedTree; 28 | 29 | tree = parseModule(fs.readFileSync(require.resolve('everything.js/es2015-module'), 'utf8')); 30 | clonedTree = reduce(new LazyCloneReducer, tree); 31 | assert.strictEqual(tree, clonedTree); 32 | 33 | tree = parseScript(fs.readFileSync(require.resolve('everything.js/es2015-script'), 'utf8')); 34 | clonedTree = reduce(new LazyCloneReducer, tree); 35 | assert.strictEqual(tree, clonedTree); 36 | }); 37 | }); 38 | 39 | test('simple override', () => { 40 | let unchangedProgram = 'let a = "b"; null;'; 41 | let changedProgram = 'let a = 0; null;'; 42 | 43 | class IncrementReducer extends LazyCloneReducer { 44 | reduceLiteralNumericExpression(node) { 45 | return { type: 'LiteralNumericExpression', value: node.value + 1 }; 46 | } 47 | } 48 | 49 | test('should not mutate a program not containing an overridden type', () => { 50 | let tree = parseScript(unchangedProgram); 51 | let newTree = reduce(new IncrementReducer, tree); 52 | assert.strictEqual(tree, newTree); 53 | }); 54 | 55 | test('should mutate a program containing an overridden type', () => { 56 | let tree = parseScript(changedProgram); 57 | let newTree = reduce(new IncrementReducer, tree); 58 | assert.notEqual(tree, newTree); 59 | assert.deepEqual(newTree, { 60 | type: 'Script', 61 | directives: [], 62 | statements: [{ 63 | type: 'VariableDeclarationStatement', 64 | declaration: { 65 | type: 'VariableDeclaration', 66 | kind: 'let', 67 | declarators: [{ 68 | type: 'VariableDeclarator', 69 | binding: { 70 | type: 'BindingIdentifier', 71 | name: 'a', 72 | }, 73 | init: { 74 | type: 'LiteralNumericExpression', 75 | value: 1, 76 | }, 77 | }], 78 | }, 79 | }, { 80 | type: 'ExpressionStatement', 81 | expression: { 82 | type: 'LiteralNullExpression', 83 | }, 84 | }], 85 | }); 86 | 87 | assert.strictEqual(tree.statements[1], newTree.statements[1]); 88 | }); 89 | }); 90 | }); 91 | -------------------------------------------------------------------------------- /test/monoidal-reducer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016 Shape Security, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License") 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | const assert = require('assert'); 18 | 19 | const { MonoidalReducer, default: reduce } = require('../'); 20 | const { parseModule } = require('shift-parser'); 21 | 22 | suite('MonoidalReducer', () => { 23 | 24 | test('simple IdentifierCounter example', () => { 25 | 26 | class IdentifierCounter extends MonoidalReducer { 27 | static count(program) { 28 | return reduce(new this, program); 29 | } 30 | 31 | constructor() { 32 | super(class Sum { 33 | static empty() { 34 | return 0; 35 | } 36 | concat(a) { 37 | return this + a; 38 | } 39 | }); 40 | } 41 | 42 | reduceIdentifierExpression() { 43 | return 1; 44 | } 45 | } 46 | 47 | assert.equal(IdentifierCounter.count(parseModule('f(a, b, 2e308)')), 3); 48 | assert.equal(IdentifierCounter.count(parseModule('[a, b]=0')), 0); 49 | assert.equal(IdentifierCounter.count(parseModule('[a, b]')), 2); 50 | assert.equal(IdentifierCounter.count(parseModule('[a, b, ...c]')), 3); 51 | assert.equal(IdentifierCounter.count(parseModule('[,a,,] = [,b,,]')), 1); 52 | assert.equal(IdentifierCounter.count(parseModule('export {a as b} from \'a\'; var a;')), 0); 53 | assert.equal(IdentifierCounter.count(parseModule('this')), 0); 54 | }); 55 | 56 | test('simple IdentifierCollector example', () => { 57 | 58 | let EMPTY; 59 | class Collector { 60 | constructor(x) { 61 | this.value = x; 62 | } 63 | static empty() { 64 | return EMPTY; 65 | } 66 | concat(a) { 67 | return new Collector(this.value.concat(a.value)); 68 | } 69 | } 70 | EMPTY = new Collector([]); 71 | 72 | class IdentifierCollector extends MonoidalReducer { 73 | static collect(program) { 74 | return reduce(new this, program).value; 75 | } 76 | 77 | constructor() { 78 | super(Collector); 79 | } 80 | 81 | reduceIdentifierExpression(node) { 82 | return new Collector([node.name]); 83 | } 84 | } 85 | 86 | assert.deepEqual(IdentifierCollector.collect(parseModule('f(a, b, 2e308)')).sort(), ['a', 'b', 'f']); 87 | assert.deepEqual(IdentifierCollector.collect(parseModule('[a, b]=0')), []); 88 | assert.deepEqual(IdentifierCollector.collect(parseModule('[a, b]')).sort(), ['a', 'b']); 89 | assert.deepEqual(IdentifierCollector.collect(parseModule('[a, b, ...c]')).sort(), ['a', 'b', 'c']); 90 | assert.deepEqual(IdentifierCollector.collect(parseModule('[,a,,] = [,b,,]')), ['b']); 91 | assert.deepEqual(IdentifierCollector.collect(parseModule('export {a as b} from \'a\'; var a;')), []); 92 | assert.deepEqual(IdentifierCollector.collect(parseModule('this')), []); 93 | }); 94 | 95 | }); 96 | -------------------------------------------------------------------------------- /test/thunk.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2018 Shape Security, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License") 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | const assert = require('assert'); 18 | 19 | const { default: reduce, thunkedReduce, MonoidalReducer, ThunkedMonoidalReducer, LazyCloneReducer, thunkify, thunkifyClass, memoize } = require('../'); 20 | const { parseScript } = require('shift-parser'); 21 | const spec = require('shift-spec'); 22 | 23 | 24 | function instrument(reducer, effects) { 25 | const out = {}; 26 | for (const type in spec) { 27 | if (!{}.hasOwnProperty.call(spec, type)) continue; 28 | const name = 'reduce' + type; 29 | out[name] = (...args) => { 30 | effects.push(type); 31 | return reducer[name](...args); 32 | }; 33 | } 34 | return out; 35 | } 36 | 37 | const sampleTree = parseScript(` 38 | 'a directive'; 39 | null; 40 | { 41 | debugger; 42 | } 43 | 0; 44 | f(1); 45 | `); 46 | 47 | const postorder = [ 48 | 'Directive', 49 | 'LiteralNullExpression', 50 | 'ExpressionStatement', 51 | 'DebuggerStatement', 52 | 'Block', 53 | 'BlockStatement', 54 | 'LiteralNumericExpression', 55 | 'ExpressionStatement', 56 | 'IdentifierExpression', 57 | 'LiteralNumericExpression', 58 | 'CallExpression', 59 | 'ExpressionStatement', 60 | 'Script', 61 | ]; 62 | 63 | const preorder = [ 64 | 'Script', 65 | 'Directive', 66 | 'ExpressionStatement', 67 | 'LiteralNullExpression', 68 | 'BlockStatement', 69 | 'Block', 70 | 'DebuggerStatement', 71 | 'ExpressionStatement', 72 | 'LiteralNumericExpression', 73 | 'ExpressionStatement', 74 | 'CallExpression', 75 | 'IdentifierExpression', 76 | 'LiteralNumericExpression', 77 | ]; 78 | 79 | suite('thunk', () => { 80 | test('regular monoidal reducer visits in postorder', () => { 81 | const reducer = new MonoidalReducer({ 82 | empty: () => false, 83 | concat: (a, b) => a || b, 84 | }); 85 | 86 | const effects = []; 87 | const reduced = reduce(instrument(reducer, effects), sampleTree); 88 | assert.strictEqual(reduced, false); 89 | assert.deepStrictEqual(effects, postorder); 90 | }); 91 | 92 | test('thunked monoidal reducer visits in preorder', () => { 93 | const reducer = new ThunkedMonoidalReducer({ 94 | empty: () => false, 95 | concatThunk: (a, b) => a || b(), 96 | }); 97 | 98 | const effects = []; 99 | const reduced = thunkedReduce(instrument(reducer, effects), sampleTree); 100 | assert.strictEqual(reduced, false); 101 | assert.deepStrictEqual(effects, preorder); 102 | }); 103 | 104 | test('thunked monoidal reducer short-circuits given concatThunk and does not use concat', () => { 105 | class HasNullReducer extends ThunkedMonoidalReducer { 106 | constructor() { 107 | super({ 108 | empty: () => false, 109 | concatThunk: (a, b) => a || b(), 110 | concat() { 111 | throw new Error('not reached'); 112 | }, 113 | }); 114 | } 115 | 116 | reduceLiteralNullExpression() { 117 | return true; 118 | } 119 | } 120 | const reducer = new HasNullReducer; 121 | 122 | const effects = []; 123 | const reduced = thunkedReduce(instrument(reducer, effects), sampleTree); 124 | assert.strictEqual(reduced, true); 125 | assert.deepStrictEqual(effects, preorder.slice(0, preorder.indexOf('LiteralNullExpression') + 1)); 126 | }); 127 | 128 | test('thunked monoidal reducer short-circuits given isAbsorbing', () => { 129 | class HasNullReducer extends ThunkedMonoidalReducer { 130 | constructor() { 131 | super({ 132 | empty: () => false, 133 | isAbsorbing: a => a, 134 | concat: (a, b) => a || b, 135 | }); 136 | } 137 | 138 | reduceLiteralNullExpression() { 139 | return true; 140 | } 141 | } 142 | const reducer = new HasNullReducer; 143 | 144 | const effects = []; 145 | const reduced = thunkedReduce(instrument(reducer, effects), sampleTree); 146 | assert.strictEqual(reduced, true); 147 | assert.deepStrictEqual(effects, preorder.slice(0, preorder.indexOf('LiteralNullExpression') + 1)); 148 | }); 149 | 150 | test('thunked monoidal reducer works with regular monoid', () => { 151 | class HasNullReducer extends ThunkedMonoidalReducer { 152 | constructor() { 153 | super({ 154 | empty: () => false, 155 | concat: (a, b) => a || b, 156 | }); 157 | } 158 | 159 | reduceLiteralNullExpression() { 160 | return true; 161 | } 162 | } 163 | const reducer = new HasNullReducer; 164 | 165 | const effects = []; 166 | const reduced = thunkedReduce(instrument(reducer, effects), sampleTree); 167 | assert.strictEqual(reduced, true); 168 | assert.deepStrictEqual(effects, preorder); 169 | }); 170 | 171 | test('thunked monoidal reducer avoids descending unnecessarily', () => { 172 | class ReducerAvoidingBlocks extends ThunkedMonoidalReducer { 173 | constructor() { 174 | super({ 175 | empty: () => false, 176 | concatThunk: (a, b) => a || b(), 177 | }); 178 | } 179 | 180 | reduceBlockStatement() { 181 | return false; 182 | } 183 | } 184 | const reducer = new ReducerAvoidingBlocks; 185 | 186 | const effects = []; 187 | const reduced = thunkedReduce(instrument(reducer, effects), sampleTree); 188 | assert.strictEqual(reduced, false); 189 | assert.deepStrictEqual(effects, [ 190 | 'Script', 191 | 'Directive', 192 | 'ExpressionStatement', 193 | 'LiteralNullExpression', 194 | 'BlockStatement', // Note: no 'Block' or 'DebuggerStatement' 195 | 'ExpressionStatement', 196 | 'LiteralNumericExpression', 197 | 'ExpressionStatement', 198 | 'CallExpression', 199 | 'IdentifierExpression', 200 | 'LiteralNumericExpression', 201 | ]); 202 | }); 203 | }); 204 | 205 | suite('memoize', () => { 206 | test('memoized thunkified LazyCloneReducer bails as early as possible with cached value on subsequent runs', () => { 207 | class IncrementingReducer extends LazyCloneReducer { 208 | reduceLiteralNumericExpression(node) { 209 | return { 210 | type: 'LiteralNumericExpression', 211 | value: node.value + 1, 212 | }; 213 | } 214 | } 215 | const thunkifiedFromObject = memoize(thunkify(new IncrementingReducer)); 216 | 217 | 218 | class ThunkedIncrementingReducer extends thunkifyClass(LazyCloneReducer) { 219 | reduceLiteralNumericExpression(node) { 220 | return { 221 | type: 'LiteralNumericExpression', 222 | value: node.value + 1, 223 | }; 224 | } 225 | } 226 | const thunkifiedFromClass = memoize(new ThunkedIncrementingReducer); 227 | 228 | [thunkifiedFromObject, thunkifiedFromClass].forEach(reducer => { 229 | const effects = []; 230 | const reduced = thunkedReduce(instrument(reducer, effects), sampleTree); 231 | assert.strictEqual(reduced.statements[2].expression.value, sampleTree.statements[2].expression.value + 1); 232 | assert.deepStrictEqual(effects, preorder); 233 | 234 | const effects2 = []; 235 | const reduced2 = thunkedReduce(instrument(reducer, effects2), sampleTree); 236 | assert.strictEqual(reduced2, reduced); // Note: ===, not just equivalent 237 | assert.deepStrictEqual(effects2, [ 238 | 'Script', 239 | ]); 240 | 241 | const effects3 = []; 242 | const reduced3 = thunkedReduce(instrument(reducer, effects3), reduced); 243 | assert.strictEqual(reduced3.statements[2].expression.value, sampleTree.statements[2].expression.value + 2); 244 | assert.deepStrictEqual(effects3, [ 245 | 'Script', 246 | 'Directive', 247 | 'ExpressionStatement', // Note: the LiteralNullExpression and the Block are not revisited 248 | 'BlockStatement', 249 | 'ExpressionStatement', 250 | 'LiteralNumericExpression', 251 | 'ExpressionStatement', 252 | 'CallExpression', 253 | 'IdentifierExpression', 254 | 'LiteralNumericExpression', 255 | ]); 256 | }); 257 | }); 258 | }); 259 | -------------------------------------------------------------------------------- /test/unit.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016 Shape Security, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License") 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | const assert = require('assert'); 18 | 19 | const { default: reduce } = require('../'); 20 | const { parseModule } = require('shift-parser'); 21 | 22 | suite('unit', () => { 23 | 24 | test('empty reducer throws', () => { 25 | assert.throws(() => reduce({}, parseModule('null;'))); 26 | }); 27 | 28 | test('nonempty reducer does not throw', () => { 29 | const literalNullReducer = { 30 | reduceExpressionStatement(node, state) { 31 | return state; 32 | }, 33 | reduceLiteralNullExpression(node, state) { 34 | return state; 35 | }, 36 | reduceModule(node, state) { 37 | return state; 38 | }, 39 | }; 40 | assert.doesNotThrow(() => reduce(literalNullReducer, parseModule('null;'))); 41 | }); 42 | 43 | }); 44 | --------------------------------------------------------------------------------