Input JavaScript Code
49 |let a = 1;
51 | let b = 1;
52 | a <<= b++;
53 | for (let i = 0; i < 10; i++) {
54 | if (i % 2 === 0) continue;
55 | if ((i | 2) == '11') break;
56 | a++;
57 | }
58 | undefined && 1 ?? (0 || a + b);
59 | ├── .gitignore ├── LICENSE ├── README.md ├── __test__ ├── classes │ └── JSObject.spec.js └── helpers │ ├── executor │ ├── 0-add-if-for.spec.js │ ├── 1-logical-break-continue.spec.js │ ├── 2-object-func-return-call.spec.js │ └── 3-new-promise.spec.js │ ├── lexical-analyer.spec.js │ └── syntax-parser.spec.js ├── docs ├── index.html ├── static │ ├── function.js │ ├── prism.css │ └── prism.js └── yzhanjsinterpreter.min.js ├── package-lock.json ├── package.json ├── src ├── classes │ ├── Completion.js │ ├── Environment.js │ ├── JSFunction.js │ ├── JSObject.js │ ├── Promise │ │ ├── PromiseFunction.js │ │ ├── RejectFunction.js │ │ ├── ResolveFunction.js │ │ └── ThenFunction.js │ ├── Reference.js │ └── Task.js ├── data │ └── conf.js ├── helpers │ ├── executor.js │ ├── lexical-analyzer.js │ └── syntax-parser.js └── index.js └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 馒头饭 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # yzhanJSInterpreter 2 | [](https://www.npmjs.com/package/yzhanjsinterpreter) 3 | [](https://www.npmjs.com/package/yzhanjsinterpreter) 4 | [](https://github.com/mantoufan/yzhanjsinterpreter/blob/main/LICENSE) 5 | A JavaScript Interpreter Using JS itself, implement `eval` 6 | JavaScript 解释器,包含词法分析、语法解析和执行。实现 `eval` 7 | ## Demo 8 | You could change JavaScript Code and view the result in realtime. 9 | [Online Demo](https://mantoufan.github.io/yzhanJSInterpreter) 10 |  11 | ## Setup 12 | ### Node.js 13 | ```javascript 14 | npm i yzhanjsinterpreter 15 | import yzhanJSInterpreter from 'yzhanjsinterpreter' 16 | ``` 17 | ### Browser 18 | ```html 19 | 20 | ``` 21 | ## Usage 22 | ### Declaration Code 23 | ```javascript 24 | const code = `let a = 1; 25 | let b = 1; 26 | a <<= b++; 27 | for (let i = 0; i < 10; i++) { 28 | if (i % 2 === 0) continue; 29 | if ((i | 2) == '11') break; 30 | a++; 31 | } 32 | undefined && 1 ?? (0 || a + b);` 33 | ``` 34 | ### Eval · Evaluate 35 | `eval` is a reserved keyword, so use `evaluate` instead 36 | ```javascript 37 | const evalResult = yzhanJSInterpreter.evaluate(code) 38 | ``` 39 | `evaluate` runs followed 3 steps: 40 | #### 1. Lexical Analyzer 41 | ```javascript 42 | const lexResult = yzhanJSInterpreter.lex(code) 43 | ``` 44 | #### 2. Syntax Parser 45 | ```javascript 46 | const parseResults = yzhanJSInterpreter.parse(lexResult) 47 | ``` 48 | #### 3. Executor 49 | ```javascript 50 | const executeResult = yzhanJSInterpreter.execute(parseResults[0]) 51 | const evalResult = executeResult 52 | ``` 53 | ## Development 54 | ### Unit Testing 55 | ```shell 56 | npm test 57 | ``` 58 | ### Build 59 | ```shell 60 | npm run build 61 | ``` 62 | ### Preview 63 | ```shell 64 | npm run dev 65 | ``` 66 | ## Todo 67 | 1. Travese AST, using child to replace the parent when there is only one parent Node. 68 | 2. Treeshaking: earse unseded declarations. -------------------------------------------------------------------------------- /__test__/classes/JSObject.spec.js: -------------------------------------------------------------------------------- 1 | const JSObject = require('../../src/classes/JSObject') 2 | describe('Test JSObject', () => { 3 | it('Test getProperty with value on itself', () => { 4 | const self = new JSObject() 5 | self.setProperty('a', { 6 | value: 1 7 | }) 8 | expect(self.getProperty('a')).toBe(1) 9 | }) 10 | it('Test getProperty with value on prototype', () => { 11 | const parent = new JSObject() 12 | parent.setProperty('a', { 13 | value: 1 14 | }) 15 | const child = new JSObject() 16 | child.prototype = parent 17 | expect(child.getProperty('a')).toBe(1) 18 | }) 19 | it('Test getProperty with getter on itself', () => { 20 | const self = new JSObject() 21 | self.setProperty('a', { 22 | get() { 23 | return 1 24 | } 25 | }) 26 | expect(self.getProperty('a')).toBe(1) 27 | }) 28 | it('Test getProperty with getter on prototype', () => { 29 | const parent = new JSObject() 30 | parent.setProperty('a', { 31 | get() { 32 | return 1 33 | } 34 | }) 35 | const child = new JSObject() 36 | child.prototype = parent 37 | expect(child.getProperty('a')).toBe(1) 38 | }) 39 | }) -------------------------------------------------------------------------------- /__test__/helpers/executor/0-add-if-for.spec.js: -------------------------------------------------------------------------------- 1 | const { evaluate, globalEnv } = require('../../../src/index') 2 | describe('Test Executor', () => { 3 | const map = new Map([ 4 | ['Literal', [['NumbericLiteral'], ['StringLiteral'], ['BooleanLiteral'], ['NullLiteral']]], 5 | ['Primary', [['(', 'Expression', ')'], ['Literal'], ['Identifier']]], 6 | ['MemberExpression', [['Primary'], ['MemberExpression', '.', 'Identifier'], ['MemberExpression', '[', 'Expression', ']']]], 7 | ['NewExpression', [['MemberExpression'], ['new', 'NewExpression']]], 8 | ['CallExpression', [ 9 | ['new', 'MemberExpression', '(', ')'], 10 | ['MemberExpression', '(', ')'], 11 | ['CallExpression', '.', 'Identifier'], 12 | ['CallExpression', '[', 'Expression', ']'], 13 | ['CallExpression', '(', 'Arguments', ')'] 14 | ]], 15 | ['LeftHandSideExpression', [['MemberExpression'], ['CallExpression'], ['NewExpression']]], 16 | ['MultiplicativeExpression', [['LeftHandSideExpression'], ['MultiplicativeExpression', '*', 'LeftHandSideExpression'], ['MultiplicativeExpression', '/', 'LeftHandSideExpression'], ['MultiplicativeExpression', '%', 'LeftHandSideExpression']]], 17 | ['AdditiveExpression', [['MultiplicativeExpression'], ['AdditiveExpression', '+', 'MultiplicativeExpression'], ['AdditiveExpression', '-', 'MultiplicativeExpression']]], 18 | ['AssignmentExpression', [['AdditiveExpression'], ['LeftHandSideExpression', '=', 'AssignmentExpression']]], 19 | ['Expression', [['AssignmentExpression']]], 20 | ['ExpressionStatement', [['Expression', ';']]], 21 | ['Declaration', [ 22 | ['var', 'Identifier', '=', 'Expression', ';'], 23 | ['let', 'Identifier', '=', 'Expression', ';'], 24 | ['const', 'Identifier', '=', 'Expression', ';'] 25 | ]], 26 | /** Added: Start */ 27 | ['Parameters', [['Identifier'], ['Parameters', ',', 'Identifier']]], 28 | ['FunctionDeclaration', [ 29 | ['function', 'Identifier', '(', ')', '{', 'StatementList', '}'], 30 | ['function', 'Identifier', '(', 'Parameters', ')', '{', 'StatementList', '}'] 31 | ]], 32 | /** Added: End */ 33 | ['Statement', [['ExpressionStatement'], ['IfStatement'], ['ForStatement'], ['Declaration']]], 34 | ['StatementListItem', [['Statement'], ['Declaration']]], 35 | ['StatementList', [['StatementListItem'], ['StatementList', 'StatementListItem']]], 36 | /** Added */ 37 | ['Program', [['StatementList']]], 38 | ]) 39 | const initialState = { 40 | Program: { 41 | EOF: { 42 | $end: true 43 | } 44 | } 45 | } 46 | it('1 + 1', () => { 47 | expect(evaluate('1 + 1', map, initialState)).toEqual({"type": "normal", "value": 2}) 48 | }) 49 | }) 50 | 51 | describe('Test Scope', () => { 52 | const map = new Map([ 53 | ['Literal', [['NumbericLiteral'], ['StringLiteral'], ['BooleanLiteral'], ['NullLiteral']]], 54 | ['Primary', [['(', 'Expression', ')'], ['Literal'], ['Identifier']]], 55 | ['MemberExpression', [['Primary'], ['MemberExpression', '.', 'Identifier'], ['MemberExpression', '[', 'Expression', ']']]], 56 | ['NewExpression', [['MemberExpression'], ['new', 'NewExpression']]], 57 | ['CallExpression', [ 58 | ['new', 'MemberExpression', '(', ')'], 59 | ['MemberExpression', '(', ')'], 60 | ['CallExpression', '.', 'Identifier'], 61 | ['CallExpression', '[', 'Expression', ']'], 62 | ['CallExpression', '(', 'Arguments', ')'] 63 | ]], 64 | ['LeftHandSideExpression', [['MemberExpression'], ['CallExpression'], ['NewExpression']]], 65 | ['MultiplicativeExpression', [['LeftHandSideExpression'], ['MultiplicativeExpression', '*', 'LeftHandSideExpression'], ['MultiplicativeExpression', '/', 'LeftHandSideExpression'], ['MultiplicativeExpression', '%', 'LeftHandSideExpression']]], 66 | ['AdditiveExpression', [['MultiplicativeExpression'], ['AdditiveExpression', '+', 'MultiplicativeExpression'], ['AdditiveExpression', '-', 'MultiplicativeExpression']]], 67 | ['AssignmentExpression', [['AdditiveExpression'], ['LeftHandSideExpression', '=', 'AssignmentExpression']]], 68 | ['Expression', [['AssignmentExpression'], ['Expression', ',', 'AssignmentExpression']]], 69 | ['ExpressionStatement', [['Expression', ';']]], 70 | ['Declaration', [ 71 | ['var', 'Identifier', '=', 'Expression', ';'], 72 | ['let', 'Identifier', '=', 'Expression', ';'], 73 | ['const', 'Identifier', '=', 'Expression', ';'] 74 | ]], 75 | ['Parameters', [['Identifier'], ['Parameters', ',', 'Identifier']]], 76 | ['FunctionDeclaration', [ 77 | ['function', 'Identifier', '(', ')', '{', 'StatementList', '}'], 78 | ['function', 'Identifier', '(', 'Parameters', ')', '{', 'StatementList', '}'] 79 | ]], 80 | /** Added: Start */ 81 | ['IfStatement', [ 82 | ['if', '(', 'Expression', ')', 'Statement'], 83 | ['if', '(', 'Expression', ')', 'else', 'Statement'] 84 | ]], 85 | ['BlockStatement', [ 86 | ['{', '}'], 87 | ['{', 'StatementList', '}'], 88 | ]], 89 | ['ForStatement', [ 90 | ['for', '(', 'Expression', ';', 'Expression', ';', 'Expression', ')', 'Statement'] 91 | ]], 92 | /** Added: End */ 93 | ['Statement', [['ExpressionStatement'], ['IfStatement'], ['ForStatement'], ['Declaration'], ['BlockStatement']]], 94 | ['StatementListItem', [['Statement'], ['Declaration']]], 95 | ['StatementList', [['StatementListItem'], ['StatementList', 'StatementListItem']]], 96 | /** Added */ 97 | ['Program', [['StatementList']]], 98 | ]) 99 | const initialState = { 100 | Program: { 101 | EOF: { 102 | $end: true 103 | } 104 | } 105 | } 106 | it('DelcarationStatement', () => { 107 | evaluate('let a = 1', map, initialState) 108 | expect(globalEnv.vars.get('a')).toBe(1) 109 | }) 110 | 111 | it('AdditiveStatement', () => { 112 | evaluate('let b = 1;b = b + 1', map, initialState) 113 | expect(globalEnv.vars.get('b')).toBe(2) 114 | }) 115 | it('Nested Blocks', () => { 116 | expect(evaluate(`{ 117 | let a= 1 118 | { 119 | let b = a + 1 120 | b + 1 121 | } 122 | }`, map, initialState)).toEqual({"type": "normal", "value": 3}) 123 | }) 124 | }) 125 | 126 | describe('Test Statement Parser', () => { 127 | describe('Test IfStatement', () => { 128 | const map = new Map([ 129 | ['Literal', [['NumbericLiteral'], ['StringLiteral'], ['BooleanLiteral'], ['NullLiteral']]], 130 | ['Primary', [['(', 'Expression', ')'], ['Literal'], ['Identifier']]], 131 | ['MemberExpression', [['Primary'], ['MemberExpression', '.', 'Identifier'], ['MemberExpression', '[', 'Expression', ']']]], 132 | ['NewExpression', [['MemberExpression'], ['new', 'NewExpression']]], 133 | ['CallExpression', [ 134 | ['new', 'MemberExpression', '(', ')'], 135 | ['MemberExpression', '(', ')'], 136 | ['CallExpression', '.', 'Identifier'], 137 | ['CallExpression', '[', 'Expression', ']'], 138 | ['CallExpression', '(', 'Arguments', ')'] 139 | ]], 140 | ['LeftHandSideExpression', [['MemberExpression'], ['CallExpression'], ['NewExpression']]], 141 | ['MultiplicativeExpression', [['LeftHandSideExpression'], ['MultiplicativeExpression', '*', 'LeftHandSideExpression'], ['MultiplicativeExpression', '/', 'LeftHandSideExpression'], ['MultiplicativeExpression', '%', 'LeftHandSideExpression']]], 142 | ['AdditiveExpression', [['MultiplicativeExpression'], ['AdditiveExpression', '+', 'MultiplicativeExpression'], ['AdditiveExpression', '-', 'MultiplicativeExpression']]], 143 | ['AssignmentExpression', [['AdditiveExpression'], ['LeftHandSideExpression', '=', 'AssignmentExpression']]], 144 | ['Expression', [['AssignmentExpression'], ['Expression', ',', 'AssignmentExpression']]], 145 | ['ExpressionStatement', [['Expression', ';']]], 146 | ['Declaration', [ 147 | ['var', 'Identifier', '=', 'Expression', ';'], 148 | ['let', 'Identifier', '=', 'Expression', ';'], 149 | ['const', 'Identifier', '=', 'Expression', ';'] 150 | ]], 151 | ['Parameters', [['Identifier'], ['Parameters', ',', 'Identifier']]], 152 | ['FunctionDeclaration', [ 153 | ['function', 'Identifier', '(', ')', '{', 'StatementList', '}'], 154 | ['function', 'Identifier', '(', 'Parameters', ')', '{', 'StatementList', '}'] 155 | ]], 156 | /** Added: Start */ 157 | ['IfStatement', [ 158 | ['if', '(', 'Expression', ')', 'Statement'], 159 | ['if', '(', 'Expression', ')', 'else', 'Statement'] 160 | ]], 161 | ['BlockStatement', [ 162 | ['{', '}'], 163 | ['{', 'StatementList', '}'], 164 | ]], 165 | /** Added: End */ 166 | ['Statement', [['ExpressionStatement'], ['IfStatement'], ['ForStatement'], ['Declaration'], ['BlockStatement']]], 167 | ['StatementListItem', [['Statement'], ['Declaration']]], 168 | ['StatementList', [['StatementListItem'], ['StatementList', 'StatementListItem']]], 169 | /** Added */ 170 | ['Program', [['StatementList']]], 171 | ]) 172 | const initialState = { 173 | Program: { 174 | EOF: { 175 | $end: true 176 | } 177 | } 178 | } 179 | it('IfStatement', () => { 180 | expect(evaluate('if (ture) {const a = 1}', map, initialState)).toEqual({ type: 'normal', value: undefined }) 181 | }) 182 | }) 183 | 184 | describe('Test ForStatement', () => { 185 | const map = new Map([ 186 | ['Literal', [['NumbericLiteral'], ['StringLiteral'], ['BooleanLiteral'], ['NullLiteral']]], 187 | ['Primary', [['(', 'Expression', ')'], ['Literal'], ['Identifier']]], 188 | ['MemberExpression', [['Primary'], ['MemberExpression', '.', 'Identifier'], ['MemberExpression', '[', 'Expression', ']']]], 189 | ['NewExpression', [['MemberExpression'], ['new', 'NewExpression']]], 190 | ['CallExpression', [ 191 | ['new', 'MemberExpression', '(', ')'], 192 | ['MemberExpression', '(', ')'], 193 | ['CallExpression', '.', 'Identifier'], 194 | ['CallExpression', '[', 'Expression', ']'], 195 | ['CallExpression', '(', 'Arguments', ')'] 196 | ]], 197 | ['LeftHandSideExpression', [['MemberExpression'], ['CallExpression'], ['NewExpression']]], 198 | ['MultiplicativeExpression', [['UpdateExpression'], ['MultiplicativeExpression', '*', 'UpdateExpression'], ['MultiplicativeExpression', '/', 'UpdateExpression'], ['MultiplicativeExpression', '%', 'UpdateExpression']]], 199 | ['AdditiveExpression', [['MultiplicativeExpression'], ['AdditiveExpression', '+', 'MultiplicativeExpression'], ['AdditiveExpression', '-', 'MultiplicativeExpression']]], 200 | ['RelationalExpression', [['AdditiveExpression'], ['RelationalExpression', '>', 'AdditiveExpression'], ['RelationalExpression', '<', 'AdditiveExpression']]], 201 | ['AssignmentExpression', [['RelationalExpression'], ['LeftHandSideExpression', '=', 'RelationalExpression']]], 202 | ['Expression', [ 203 | ['AssignmentExpression'], 204 | ['Expression', ',', 'AssignmentExpression'], 205 | ]], 206 | ['UpdateExpression', [ 207 | ['LeftHandSideExpression'], 208 | ['LeftHandSideExpression', '++'], 209 | ['LeftHandSideExpression', '--'], 210 | ['++', 'LeftHandSideExpression'], 211 | ['--', 'LeftHandSideExpression'] 212 | ]], 213 | ['ExpressionStatement', [['Expression', ';']]], 214 | ['Declaration', [ 215 | ['var', 'Identifier', '=', 'Expression', ';'], 216 | ['let', 'Identifier', '=', 'Expression', ';'], 217 | ['const', 'Identifier', '=', 'Expression', ';'] 218 | ]], 219 | ['Parameters', [['Identifier'], ['Parameters', ',', 'Identifier']]], 220 | ['FunctionDeclaration', [ 221 | ['function', 'Identifier', '(', ')', '{', 'StatementList', '}'], 222 | ['function', 'Identifier', '(', 'Parameters', ')', '{', 'StatementList', '}'] 223 | ]], 224 | /** Added: Start */ 225 | ['IfStatement', [ 226 | ['if', '(', 'Expression', ')', 'Statement'], 227 | ['if', '(', 'Expression', ')', 'else', 'Statement'] 228 | ]], 229 | ['BlockStatement', [ 230 | ['{', '}'], 231 | ['{', 'StatementList', '}'], 232 | ]], 233 | ['ForStatement', [ 234 | ['for', '(', 'let', 'Expression', ';', 'Expression', ';', 'Expression', ')', 'Statement'], 235 | ['for', '(', 'var', 'Expression', ';', 'Expression', ';', 'Expression', ')', 'Statement'], 236 | ['for', '(', 'Expression', ';', 'Expression', ';', 'Expression', ')', 'Statement'] 237 | ]], 238 | /** Added: End */ 239 | ['Statement', [['ExpressionStatement'], ['IfStatement'], ['ForStatement'], ['Declaration'], ['BlockStatement']]], 240 | ['StatementListItem', [['Statement'], ['Declaration']]], 241 | ['StatementList', [['StatementListItem'], ['StatementList', 'StatementListItem']]], 242 | /** Added */ 243 | ['Program', [['StatementList']]], 244 | ]) 245 | const initialState = { 246 | Program: { 247 | EOF: { 248 | $end: true 249 | } 250 | } 251 | } 252 | 253 | it('ForStatement', () => { 254 | evaluate(` 255 | let a = 0 256 | for(let i = 0; i < 10; i++) {a++} 257 | `, map, initialState) 258 | expect(globalEnv.get('a')).toBe(10) 259 | }) 260 | }) 261 | 262 | describe('Test BreakStatement', () => { 263 | const map = new Map([ 264 | ['Literal', [['NumbericLiteral'], ['StringLiteral'], ['BooleanLiteral'], ['NullLiteral']]], 265 | ['Primary', [['(', 'Expression', ')'], ['Literal'], ['Identifier']]], 266 | ['MemberExpression', [['Primary'], ['MemberExpression', '.', 'Identifier'], ['MemberExpression', '[', 'Expression', ']']]], 267 | ['NewExpression', [['MemberExpression'], ['new', 'NewExpression']]], 268 | ['CallExpression', [ 269 | ['new', 'MemberExpression', '(', ')'], 270 | ['MemberExpression', '(', ')'], 271 | ['CallExpression', '.', 'Identifier'], 272 | ['CallExpression', '[', 'Expression', ']'], 273 | ['CallExpression', '(', 'Arguments', ')'] 274 | ]], 275 | ['LeftHandSideExpression', [['MemberExpression'], ['CallExpression'], ['NewExpression']]], 276 | ['MultiplicativeExpression', [['UpdateExpression'], ['MultiplicativeExpression', '*', 'UpdateExpression'], ['MultiplicativeExpression', '/', 'UpdateExpression'], ['MultiplicativeExpression', '%', 'UpdateExpression']]], 277 | ['AdditiveExpression', [['MultiplicativeExpression'], ['AdditiveExpression', '+', 'MultiplicativeExpression'], ['AdditiveExpression', '-', 'MultiplicativeExpression']]], 278 | ['RelationalExpression', [['AdditiveExpression'], ['RelationalExpression', '>', 'AdditiveExpression'], ['RelationalExpression', '<', 'AdditiveExpression']]], 279 | ['EqualityExpression', [ 280 | ['RelationalExpression'], 281 | ['EqualityExpression', '==', 'RelationalExpression'], 282 | ['EqualityExpression', '!=', 'RelationalExpression'], 283 | ['EqualityExpression', '===', 'RelationalExpression'], 284 | ['EqualityExpression', '!==', 'RelationalExpression'], 285 | ]], 286 | ['AssignmentExpression', [['EqualityExpression'], ['LeftHandSideExpression', '=', 'EqualityExpression']]], 287 | ['Expression', [ 288 | ['AssignmentExpression'], 289 | ['Expression', ',', 'AssignmentExpression'], 290 | ]], 291 | ['UpdateExpression', [ 292 | ['LeftHandSideExpression'], 293 | ['LeftHandSideExpression', '++'], 294 | ['LeftHandSideExpression', '--'], 295 | ['++', 'LeftHandSideExpression'], 296 | ['--', 'LeftHandSideExpression'] 297 | ]], 298 | ['ExpressionStatement', [['Expression', ';']]], 299 | ['Declaration', [ 300 | ['var', 'Identifier', '=', 'Expression', ';'], 301 | ['let', 'Identifier', '=', 'Expression', ';'], 302 | ['const', 'Identifier', '=', 'Expression', ';'] 303 | ]], 304 | ['Parameters', [['Identifier'], ['Parameters', ',', 'Identifier']]], 305 | ['FunctionDeclaration', [ 306 | ['function', 'Identifier', '(', ')', '{', 'StatementList', '}'], 307 | ['function', 'Identifier', '(', 'Parameters', ')', '{', 'StatementList', '}'] 308 | ]], 309 | /** Added: Start */ 310 | ['IfStatement', [ 311 | ['if', '(', 'Expression', ')', 'Statement'], 312 | ['if', '(', 'Expression', ')', 'else', 'Statement'] 313 | ]], 314 | ['BlockStatement', [ 315 | ['{', '}'], 316 | ['{', 'StatementList', '}'], 317 | ]], 318 | ['ForStatement', [ 319 | ['for', '(', 'let', 'Expression', ';', 'Expression', ';', 'Expression', ')', 'Statement'], 320 | ['for', '(', 'var', 'Expression', ';', 'Expression', ';', 'Expression', ')', 'Statement'], 321 | ['for', '(', 'Expression', ';', 'Expression', ';', 'Expression', ')', 'Statement'] 322 | ]], 323 | ['BreakStatement', [ 324 | ['break', ';'] 325 | ]], 326 | /** Added: End */ 327 | ['Statement', [['ExpressionStatement'], ['IfStatement'], ['ForStatement'], ['Declaration'], ['BlockStatement'], ['BreakStatement']]], 328 | ['StatementListItem', [['Statement'], ['Declaration']]], 329 | ['StatementList', [['StatementListItem'], ['StatementList', 'StatementListItem']]], 330 | /** Added */ 331 | ['Program', [['StatementList']]], 332 | ]) 333 | const initialState = { 334 | Program: { 335 | EOF: { 336 | $end: true 337 | } 338 | } 339 | } 340 | 341 | it('Test BreakStatement', () => { 342 | evaluate(` 343 | for(let i = 1; i < 10; i++) { 344 | if (i === 5) break; 345 | } 346 | `, map, initialState) 347 | expect(globalEnv.get('i')).toBe(5) 348 | }) 349 | }) 350 | }) -------------------------------------------------------------------------------- /__test__/helpers/executor/1-logical-break-continue.spec.js: -------------------------------------------------------------------------------- 1 | const { evaluate, globalEnv } = require('../../../src/index') 2 | describe('Test Homework', () => { 3 | const map = new Map([ 4 | ['Parameters', [ 5 | ['Identifier'], 6 | ['Parameters', ',', 'Identifier'] 7 | ]], 8 | ['FunctionDeclaration', [ 9 | ['function', 'Identifier', '(', ')', '{', 'StatementList', '}'], 10 | ['function', 'Identifier', '(', 'Parameters', ')', '{', 'StatementList', '}'] 11 | ]], 12 | ['Declaration', [ 13 | ['FunctionDeclaration'], 14 | ['var', 'Identifier', '=', 'Expression', ';'], 15 | ['let', 'Identifier', '=', 'Expression', ';'], 16 | ['const', 'Identifier', '=', 'Expression', ';'] 17 | ]], 18 | ['Literal', [ 19 | ['NumbericLiteral'], 20 | ['StringLiteral'], 21 | ['BooleanLiteral'], 22 | ['NullLiteral'] 23 | ]], 24 | ['Primary', [ 25 | ['(', 'Expression', ')'], 26 | ['Literal'], 27 | ['Identifier'] 28 | ]], 29 | ['MemberExpression', [ 30 | ['Primary'], 31 | ['MemberExpression', '.', 'Identifier'], 32 | ['MemberExpression', '[', 'Expression', ']'] 33 | ]], 34 | ['NewExpression', [ 35 | ['MemberExpression'], 36 | ['new', 'NewExpression'] 37 | ]], 38 | ['CallExpression', [ 39 | ['new', 'MemberExpression', '(', ')'], 40 | ['MemberExpression', '(', ')'], 41 | ['CallExpression', '.', 'Identifier'], 42 | ['CallExpression', '[', 'Expression', ']'], 43 | ['CallExpression', '(', 'Arguments', ')'] 44 | ]], 45 | ['LeftHandSideExpression', [ 46 | ['MemberExpression'], 47 | ['CallExpression'], 48 | ['NewExpression'] 49 | ]], 50 | ['UpdateExpression', [ 51 | ['LeftHandSideExpression'], 52 | ['LeftHandSideExpression', '++'], 53 | ['LeftHandSideExpression', '--'], 54 | ['++', 'LeftHandSideExpression'], 55 | ['--', 'LeftHandSideExpression'] 56 | ]], 57 | ['MultiplicativeExpression', [ 58 | ['UpdateExpression'], 59 | ['MultiplicativeExpression', '*', 'UpdateExpression'], 60 | ['MultiplicativeExpression', '/', 'UpdateExpression'], 61 | ['MultiplicativeExpression', '%', 'UpdateExpression'] 62 | ]], 63 | ['AdditiveExpression', [ 64 | ['MultiplicativeExpression'], 65 | ['AdditiveExpression', '+', 'MultiplicativeExpression'], 66 | ['AdditiveExpression', '-', 'MultiplicativeExpression'] 67 | ]], 68 | ['RelationalExpression', [ 69 | ['AdditiveExpression'], 70 | ['RelationalExpression', '>', 'AdditiveExpression'], 71 | ['RelationalExpression', '<', 'AdditiveExpression'] 72 | ]], 73 | ['EqualityExpression', [ 74 | ['RelationalExpression'], 75 | ['EqualityExpression', '==', 'RelationalExpression'], 76 | ['EqualityExpression', '!=', 'RelationalExpression'], 77 | ['EqualityExpression', '===', 'RelationalExpression'], 78 | ['EqualityExpression', '!==', 'RelationalExpression'], 79 | ]], 80 | ['BitwiseANDExpression', [ 81 | ['EqualityExpression'], 82 | ['BitwiseANDExpression', '&', 'EqualityExpression'] 83 | ]], 84 | ['BitwiseXORExpression', [ 85 | ['BitwiseANDExpression'], 86 | ['BitwiseXORExpression', '^', 'BitwiseANDExpression'] 87 | ]], 88 | ['BitwiseORExpression', [ 89 | ['BitwiseXORExpression'], 90 | ['BitwiseORExpression', '|', 'BitwiseXORExpression'] 91 | ]], 92 | ['LogicalANDExpression', [ 93 | ['BitwiseORExpression'], 94 | ['LogicalANDExpression', '&&', 'BitwiseORExpression'] 95 | ]], 96 | ['LogicalORExpression', [ 97 | ['LogicalANDExpression'], 98 | ['LogicalORExpression', '||', 'LogicalANDExpression'] 99 | ]], 100 | ['CoalesceExpression', [ 101 | ['ShortCircuitExpression', '??', 'BitwiseORExpression'] 102 | ]], 103 | // ['CoalesceExpressionHead', [ 104 | // ['CoalesceExpression'], 105 | // ['BitwiseORExpression'] 106 | // ]], 107 | ['ShortCircuitExpression', [ 108 | ['LogicalORExpression'], 109 | ['CoalesceExpression'] 110 | ]], 111 | ['ConditionalExpression', [ 112 | ['ShortCircuitExpression'], 113 | ['ShortCircuitExpression', '?', 'AssignmentExpression', ':', 'AssignmentExpression'] 114 | ]], 115 | ['AssignmentOperator', [ 116 | ['*='],['/='], ['%='], ['+='], ['-='], 117 | ['<<='], ['>>='], ['>>>='], 118 | ['&='], ['^='], ['|='], ['**='] 119 | ]], 120 | ['AssignmentExpression', [ 121 | ['ConditionalExpression'], 122 | ['LeftHandSideExpression', '=', 'AssignmentExpression'], 123 | ['LeftHandSideExpression', 'AssignmentOperator', 'AssignmentExpression'], 124 | ['LeftHandSideExpression', '&&=', 'AssignmentExpression'], 125 | ['LeftHandSideExpression', '||=', 'AssignmentExpression'], 126 | ['LeftHandSideExpression', '??=', 'AssignmentExpression'], 127 | ]], 128 | ['Expression', [ 129 | ['AssignmentExpression'], 130 | ['Expression', ',', 'AssignmentExpression'], 131 | ]], 132 | ['ExpressionStatement', [ 133 | ['Expression', ';'] 134 | ]], 135 | ['BlockStatement', [ 136 | ['{', '}'], 137 | ['{', 'StatementList', '}'], 138 | ]], 139 | ['IfStatement', [ 140 | ['if', '(', 'Expression', ')', 'Statement'], 141 | ['if', '(', 'Expression', ')', 'else', 'Statement'] 142 | ]], 143 | ['ForStatement', [ 144 | ['for', '(', 'let', 'Expression', ';', 'Expression', ';', 'Expression', ')', 'Statement'], 145 | ['for', '(', 'var', 'Expression', ';', 'Expression', ';', 'Expression', ')', 'Statement'], 146 | ['for', '(', 'Expression', ';', 'Expression', ';', 'Expression', ')', 'Statement'] 147 | ]], 148 | ['BreakableStatement', [ 149 | ['ForStatement'] 150 | ]], 151 | ['BreakStatement', [ 152 | ['break', ';'], 153 | ['break', 'Identifier', ';'] 154 | ]], 155 | ['ContinueStatement', [ 156 | ['continue', ';'], 157 | ['continue', 'Identifier', ';'] 158 | ]], 159 | ['Statement', [ 160 | ['BlockStatement'], 161 | ['ExpressionStatement'], 162 | ['IfStatement'], 163 | ['ForStatement'], 164 | ['BreakableStatement'], 165 | ['BreakStatement'], 166 | ['ContinueStatement'], 167 | ['Declaration'], 168 | ]], 169 | ['StatementListItem', [ 170 | ['Statement'], 171 | ['Declaration'] 172 | ]], 173 | ['StatementList', [ 174 | ['StatementListItem'], 175 | ['StatementList', 'StatementListItem'] 176 | ]], 177 | ['Program', [['StatementList']]], 178 | ]) 179 | const initialState = { 180 | Program: { 181 | EOF: { 182 | $end: true 183 | } 184 | } 185 | } 186 | 187 | it('Test EqualityExpression', () => { 188 | expect(evaluate(`'1' == 1 === (1 != '0');`, map, initialState)).toEqual({ 189 | type: 'normal', 190 | value: true 191 | }) 192 | }) 193 | 194 | it('Test BitwiseExpression', () => { 195 | expect(evaluate(`1 | 2 ^ 2 & 1;`, map, initialState)).toEqual({ 196 | type: 'normal', 197 | value: 3 198 | }) 199 | }) 200 | 201 | it('Test LogicalExpression', () => { 202 | expect(evaluate(`(0 ?? 2) || 1 && 2`, map, initialState)).toEqual({ 203 | type: 'normal', 204 | value: 2 205 | }) 206 | }) 207 | 208 | it('Test LogicalExpression with let a = 1 || 2', () => { 209 | evaluate('let a = 1 || 2', map, initialState) 210 | expect(globalEnv.get('a')).toEqual(1) 211 | }) 212 | 213 | it('Test AssignmentOperator', () => { 214 | expect(evaluate(` 215 | let ans = 0 216 | ans += 1 217 | ans *= 2 218 | ans /= 2 219 | ans <<= 2 220 | ans >>= 1 221 | ans >>>= 1 222 | `, map, initialState)).toEqual({ 223 | type: 'normal', 224 | value: 1 225 | }) 226 | }) 227 | 228 | it('Test BreakStatement', () => { 229 | expect(evaluate(` 230 | let ans = 0 231 | for(let i = 0; i < 10; i++) { 232 | if (i === 5) break; 233 | ans++ 234 | } 235 | ans + 0; 236 | `, map, initialState)).toEqual({ 237 | type: 'normal', 238 | value: 5 239 | }) 240 | }) 241 | 242 | it('Test ContinueStatement', () => { 243 | expect(evaluate(` 244 | let ans = 0 245 | for(let i = 0; i < 10; i++) { 246 | if (i % 2 === 0) continue; 247 | ans++; 248 | } 249 | ans + 0; 250 | `)).toEqual({ 251 | type: 'normal', 252 | value: 5 253 | }) 254 | }) 255 | }) -------------------------------------------------------------------------------- /__test__/helpers/executor/2-object-func-return-call.spec.js: -------------------------------------------------------------------------------- 1 | 2 | const { globalEnv, evaluate } = require('../../../src/index') 3 | describe('Test Object And Function', () => { 4 | const map = new Map([ 5 | ['PropertyDefinition', [ 6 | ['StringLiteral', ':', 'Expression'], 7 | ['NumbericLiteral', ':', 'Expression'] 8 | ]], 9 | ['PropertyDefinitionList', [ 10 | ['PropertyDefinition'], 11 | ['PropertyDefinitionList', ':', 'PropertyDefinition'] 12 | ]], 13 | ['ObjectLiteral', [ 14 | ['{', '}'], 15 | ['{', 'PropertyDefinitionList', '}'], 16 | ['{', 'PropertyDefinitionList', ',', '}'], 17 | ]], 18 | ['Literal', [ 19 | ['NumbericLiteral'], 20 | ['StringLiteral'], 21 | ['BooleanLiteral'], 22 | ['NullLiteral'], 23 | ['ObjectLiteral'], 24 | ]], 25 | ['Primary', [ 26 | ['(', 'Expression', ')'], 27 | ['Literal'], 28 | ['Identifier'] 29 | ]], 30 | ['Arguments', [ 31 | ['AssignmentExpression'], 32 | ['Arguments', ',', 'AssignmentExpression'] 33 | ]], 34 | ['MemberExpression', [ 35 | ['Primary'], 36 | ['MemberExpression', '.', 'Identifier'], 37 | ['MemberExpression', '[', 'Expression', ']'], 38 | ['new', 'MemberExpression', '(', 'Arguments', ')'], 39 | ['MemberExpression', '(', ')'], 40 | ]], 41 | ['NewExpression', [ 42 | ['MemberExpression'], 43 | ['new', 'NewExpression'] 44 | ]], 45 | ['CallExpression', [ 46 | ['CallExpression', '.', 'Identifier'], 47 | ['CallExpression', '[', 'Expression', ']'], 48 | ['CallExpression', '(', 'Arguments', ')'] 49 | ]], 50 | ['LeftHandSideExpression', [ 51 | ['MemberExpression'], 52 | ['CallExpression'], 53 | ['NewExpression'] 54 | ]], 55 | ['UpdateExpression', [ 56 | ['LeftHandSideExpression'], 57 | ['LeftHandSideExpression', '++'], 58 | ['LeftHandSideExpression', '--'], 59 | ['++', 'LeftHandSideExpression'], 60 | ['--', 'LeftHandSideExpression'] 61 | ]], 62 | ['MultiplicativeExpression', [ 63 | ['UpdateExpression'], 64 | ['MultiplicativeExpression', '*', 'UpdateExpression'], 65 | ['MultiplicativeExpression', '/', 'UpdateExpression'], 66 | ['MultiplicativeExpression', '%', 'UpdateExpression'] 67 | ]], 68 | ['AdditiveExpression', [ 69 | ['MultiplicativeExpression'], 70 | ['AdditiveExpression', '+', 'MultiplicativeExpression'], 71 | ['AdditiveExpression', '-', 'MultiplicativeExpression'] 72 | ]], 73 | ['RelationalExpression', [ 74 | ['AdditiveExpression'], 75 | ['RelationalExpression', '>', 'AdditiveExpression'], 76 | ['RelationalExpression', '<', 'AdditiveExpression'] 77 | ]], 78 | ['EqualityExpression', [ 79 | ['RelationalExpression'], 80 | ['EqualityExpression', '==', 'RelationalExpression'], 81 | ['EqualityExpression', '!=', 'RelationalExpression'], 82 | ['EqualityExpression', '===', 'RelationalExpression'], 83 | ['EqualityExpression', '!==', 'RelationalExpression'], 84 | ]], 85 | ['BitwiseANDExpression', [ 86 | ['EqualityExpression'], 87 | ['BitwiseANDExpression', '&', 'EqualityExpression'] 88 | ]], 89 | ['BitwiseXORExpression', [ 90 | ['BitwiseANDExpression'], 91 | ['BitwiseXORExpression', '^', 'BitwiseANDExpression'] 92 | ]], 93 | ['BitwiseORExpression', [ 94 | ['BitwiseXORExpression'], 95 | ['BitwiseORExpression', '|', 'BitwiseXORExpression'] 96 | ]], 97 | ['LogicalANDExpression', [ 98 | ['BitwiseORExpression'], 99 | ['LogicalANDExpression', '&&', 'BitwiseORExpression'] 100 | ]], 101 | ['LogicalORExpression', [ 102 | ['LogicalANDExpression'], 103 | ['LogicalORExpression', '||', 'LogicalANDExpression'] 104 | ]], 105 | ['CoalesceExpression', [ 106 | ['ShortCircuitExpression', '??', 'BitwiseORExpression'] 107 | ]], 108 | // ['CoalesceExpressionHead', [ 109 | // ['CoalesceExpression'], 110 | // ['BitwiseORExpression'] 111 | // ]], 112 | ['ShortCircuitExpression', [ 113 | ['LogicalORExpression'], 114 | ['CoalesceExpression'] 115 | ]], 116 | ['ConditionalExpression', [ 117 | ['ShortCircuitExpression'], 118 | ['ShortCircuitExpression', '?', 'AssignmentExpression', ':', 'AssignmentExpression'] 119 | ]], 120 | ['AssignmentOperator', [ 121 | ['*='],['/='], ['%='], ['+='], ['-='], 122 | ['<<='], ['>>='], ['>>>='], 123 | ['&='], ['^='], ['|='], ['**='] 124 | ]], 125 | ['AssignmentExpression', [ 126 | ['ConditionalExpression'], 127 | ['LeftHandSideExpression', '=', 'AssignmentExpression'], 128 | ['LeftHandSideExpression', 'AssignmentOperator', 'AssignmentExpression'], 129 | ['LeftHandSideExpression', '&&=', 'AssignmentExpression'], 130 | ['LeftHandSideExpression', '||=', 'AssignmentExpression'], 131 | ['LeftHandSideExpression', '??=', 'AssignmentExpression'], 132 | ]], 133 | ['Expression', [ 134 | ['AssignmentExpression'], 135 | ['Expression', ',', 'AssignmentExpression'], 136 | ]], 137 | ['Parameters', [ 138 | ['Identifier'], 139 | ['Parameters', ',', 'Identifier'] 140 | ]], 141 | ['FunctionDeclaration', [ 142 | ['function', 'Identifier', '(', ')', 'BlockStatement'], 143 | ['function', 'Identifier', '(', 'Parameters', ')', 'BlockStatement'] 144 | ]], 145 | ['Declaration', [ 146 | ['FunctionDeclaration'], 147 | ['var', 'Identifier', '=', 'Expression', ';'], 148 | ['let', 'Identifier', '=', 'Expression', ';'], 149 | ['const', 'Identifier', '=', 'Expression', ';'] 150 | ]], 151 | ['ExpressionStatement', [ 152 | ['Expression', ';'] 153 | ]], 154 | ['BlockStatement', [ 155 | ['{', '}'], 156 | ['{', 'StatementList', '}'], 157 | ]], 158 | ['IfStatement', [ 159 | ['if', '(', 'Expression', ')', 'Statement'], 160 | ['if', '(', 'Expression', ')', 'else', 'Statement'] 161 | ]], 162 | ['ForStatement', [ 163 | ['for', '(', 'let', 'Expression', ';', 'Expression', ';', 'Expression', ')', 'Statement'], 164 | ['for', '(', 'var', 'Expression', ';', 'Expression', ';', 'Expression', ')', 'Statement'], 165 | ['for', '(', 'Expression', ';', 'Expression', ';', 'Expression', ')', 'Statement'] 166 | ]], 167 | ['BreakableStatement', [ 168 | ['ForStatement'] 169 | ]], 170 | ['BreakStatement', [ 171 | ['break', ';'], 172 | ['break', 'Identifier', ';'] 173 | ]], 174 | ['ContinueStatement', [ 175 | ['continue', ';'], 176 | ['continue', 'Identifier', ';'] 177 | ]], 178 | ['Statement', [ 179 | ['BlockStatement'], 180 | ['ExpressionStatement'], 181 | ['IfStatement'], 182 | ['ForStatement'], 183 | ['BreakableStatement'], 184 | ['BreakStatement'], 185 | ['ContinueStatement'], 186 | ['Declaration'], 187 | ]], 188 | ['StatementListItem', [ 189 | ['Statement'], 190 | ['Declaration'] 191 | ]], 192 | ['StatementList', [ 193 | ['StatementListItem'], 194 | ['StatementList', 'StatementListItem'] 195 | ]], 196 | ['Program', [['StatementList']]], 197 | ]) 198 | const initialState = { 199 | Program: { 200 | EOF: { 201 | $end: true 202 | } 203 | } 204 | } 205 | 206 | it('Test JSObject', () => { 207 | evaluate(`let a = {'b' : 1}`, map, initialState) 208 | expect(globalEnv.get('a').getProperty('b')).toBe(1) 209 | }) 210 | 211 | it('Test JSFunction', () => { 212 | evaluate(`function a() { 213 | const b = 1; 214 | }`, map, initialState) 215 | expect(globalEnv.get('a').functionBody.type).toBe('BlockStatement') 216 | }) 217 | }) 218 | 219 | 220 | describe('Test Return Statement', () => { 221 | const map = new Map([ 222 | ['PropertyDefinition', [ 223 | ['StringLiteral', ':', 'Expression'], 224 | ['NumbericLiteral', ':', 'Expression'] 225 | ]], 226 | ['PropertyDefinitionList', [ 227 | ['PropertyDefinition'], 228 | ['PropertyDefinitionList', ':', 'PropertyDefinition'] 229 | ]], 230 | ['ObjectLiteral', [ 231 | ['{', '}'], 232 | ['{', 'PropertyDefinitionList', '}'], 233 | ['{', 'PropertyDefinitionList', ',', '}'], 234 | ]], 235 | ['Literal', [ 236 | ['NumbericLiteral'], 237 | ['StringLiteral'], 238 | ['BooleanLiteral'], 239 | ['NullLiteral'], 240 | ['ObjectLiteral'], 241 | ]], 242 | ['Primary', [ 243 | ['(', 'Expression', ')'], 244 | ['Literal'], 245 | ['Identifier'] 246 | ]], 247 | ['Arguments', [ 248 | ['(', ')'], 249 | ['(', 'ArgumentList', ')'], 250 | ['(', 'ArgumentList', ',', ')'] 251 | ]], 252 | ['ArgumentList', [ 253 | ['AssignmentExpression'], 254 | ['ArgumentList', ',', 'AssignmentExpression'] 255 | ]], 256 | ['MemberExpression', [ 257 | ['Primary'], 258 | ['MemberExpression', '.', 'Identifier'], 259 | ['MemberExpression', '[', 'Expression', ']'], 260 | ['new', 'MemberExpression', 'Arguments'] 261 | ]], 262 | ['NewExpression', [ 263 | ['MemberExpression'], 264 | ['new', 'NewExpression'] 265 | ]], 266 | ['CallExpression', [ 267 | ['CoverCallExpressionAndAsyncArrowHead'], 268 | ['CallExpression', 'Arguments'], 269 | ['CallExpression', '[', 'Expression', ']'], 270 | ['CallExpression', '.', 'Identifier'], 271 | ]], 272 | ['CoverCallExpressionAndAsyncArrowHead', [ 273 | ['MemberExpression', 'Arguments'] 274 | ]], 275 | ['LeftHandSideExpression', [ 276 | ['MemberExpression'], 277 | ['CallExpression'], 278 | ['NewExpression'] 279 | ]], 280 | ['UpdateExpression', [ 281 | ['LeftHandSideExpression'], 282 | ['LeftHandSideExpression', '++'], 283 | ['LeftHandSideExpression', '--'], 284 | ['++', 'LeftHandSideExpression'], 285 | ['--', 'LeftHandSideExpression'] 286 | ]], 287 | ['MultiplicativeExpression', [ 288 | ['UpdateExpression'], 289 | ['MultiplicativeExpression', '*', 'UpdateExpression'], 290 | ['MultiplicativeExpression', '/', 'UpdateExpression'], 291 | ['MultiplicativeExpression', '%', 'UpdateExpression'] 292 | ]], 293 | ['AdditiveExpression', [ 294 | ['MultiplicativeExpression'], 295 | ['AdditiveExpression', '+', 'MultiplicativeExpression'], 296 | ['AdditiveExpression', '-', 'MultiplicativeExpression'] 297 | ]], 298 | ['RelationalExpression', [ 299 | ['AdditiveExpression'], 300 | ['RelationalExpression', '>', 'AdditiveExpression'], 301 | ['RelationalExpression', '<', 'AdditiveExpression'] 302 | ]], 303 | ['EqualityExpression', [ 304 | ['RelationalExpression'], 305 | ['EqualityExpression', '==', 'RelationalExpression'], 306 | ['EqualityExpression', '!=', 'RelationalExpression'], 307 | ['EqualityExpression', '===', 'RelationalExpression'], 308 | ['EqualityExpression', '!==', 'RelationalExpression'], 309 | ]], 310 | ['BitwiseANDExpression', [ 311 | ['EqualityExpression'], 312 | ['BitwiseANDExpression', '&', 'EqualityExpression'] 313 | ]], 314 | ['BitwiseXORExpression', [ 315 | ['BitwiseANDExpression'], 316 | ['BitwiseXORExpression', '^', 'BitwiseANDExpression'] 317 | ]], 318 | ['BitwiseORExpression', [ 319 | ['BitwiseXORExpression'], 320 | ['BitwiseORExpression', '|', 'BitwiseXORExpression'] 321 | ]], 322 | ['LogicalANDExpression', [ 323 | ['BitwiseORExpression'], 324 | ['LogicalANDExpression', '&&', 'BitwiseORExpression'] 325 | ]], 326 | ['LogicalORExpression', [ 327 | ['LogicalANDExpression'], 328 | ['LogicalORExpression', '||', 'LogicalANDExpression'] 329 | ]], 330 | ['CoalesceExpression', [ 331 | ['ShortCircuitExpression', '??', 'BitwiseORExpression'] 332 | ]], 333 | // ['CoalesceExpressionHead', [ 334 | // ['CoalesceExpression'], 335 | // ['BitwiseORExpression'] 336 | // ]], 337 | ['ShortCircuitExpression', [ 338 | ['LogicalORExpression'], 339 | ['CoalesceExpression'] 340 | ]], 341 | ['ConditionalExpression', [ 342 | ['ShortCircuitExpression'], 343 | ['ShortCircuitExpression', '?', 'AssignmentExpression', ':', 'AssignmentExpression'] 344 | ]], 345 | ['AssignmentOperator', [ 346 | ['*='],['/='], ['%='], ['+='], ['-='], 347 | ['<<='], ['>>='], ['>>>='], 348 | ['&='], ['^='], ['|='], ['**='] 349 | ]], 350 | ['AssignmentExpression', [ 351 | ['ConditionalExpression'], 352 | ['LeftHandSideExpression', '=', 'AssignmentExpression'], 353 | ['LeftHandSideExpression', 'AssignmentOperator', 'AssignmentExpression'], 354 | ['LeftHandSideExpression', '&&=', 'AssignmentExpression'], 355 | ['LeftHandSideExpression', '||=', 'AssignmentExpression'], 356 | ['LeftHandSideExpression', '??=', 'AssignmentExpression'], 357 | ]], 358 | ['Expression', [ 359 | ['AssignmentExpression'], 360 | ['Expression', ',', 'AssignmentExpression'], 361 | ]], 362 | ['Parameters', [ 363 | ['Identifier'], 364 | ['Parameters', ',', 'Identifier'] 365 | ]], 366 | ['FunctionDeclaration', [ 367 | ['function', 'Identifier', '(', ')', 'BlockStatement'], 368 | ['function', 'Identifier', '(', 'Parameters', ')', 'BlockStatement'] 369 | ]], 370 | ['Declaration', [ 371 | ['FunctionDeclaration'], 372 | ['var', 'Identifier', '=', 'Expression', ';'], 373 | ['let', 'Identifier', '=', 'Expression', ';'], 374 | ['const', 'Identifier', '=', 'Expression', ';'] 375 | ]], 376 | ['ExpressionStatement', [ 377 | ['Expression', ';'] 378 | ]], 379 | ['BlockStatement', [ 380 | ['{', '}'], 381 | ['{', 'StatementList', '}'], 382 | ]], 383 | ['IfStatement', [ 384 | ['if', '(', 'Expression', ')', 'Statement'], 385 | ['if', '(', 'Expression', ')', 'else', 'Statement'] 386 | ]], 387 | ['ForStatement', [ 388 | ['for', '(', 'let', 'Expression', ';', 'Expression', ';', 'Expression', ')', 'Statement'], 389 | ['for', '(', 'var', 'Expression', ';', 'Expression', ';', 'Expression', ')', 'Statement'], 390 | ['for', '(', 'Expression', ';', 'Expression', ';', 'Expression', ')', 'Statement'] 391 | ]], 392 | ['BreakableStatement', [ 393 | ['ForStatement'] 394 | ]], 395 | ['BreakStatement', [ 396 | ['break', ';'], 397 | ['break', 'Identifier', ';'] 398 | ]], 399 | ['ContinueStatement', [ 400 | ['continue', ';'], 401 | ['continue', 'Identifier', ';'] 402 | ]], 403 | ['ReturnStatement', [ 404 | ['return', ';'], 405 | ['return', 'Expression', ';'], 406 | ]], 407 | ['Statement', [ 408 | ['BlockStatement'], 409 | ['ExpressionStatement'], 410 | ['IfStatement'], 411 | ['ForStatement'], 412 | ['BreakableStatement'], 413 | ['BreakStatement'], 414 | ['ContinueStatement'], 415 | ['ReturnStatement'], 416 | ['Declaration'], 417 | ]], 418 | ['StatementListItem', [ 419 | ['Statement'], 420 | ['Declaration'] 421 | ]], 422 | ['StatementList', [ 423 | ['StatementListItem'], 424 | ['StatementList', 'StatementListItem'] 425 | ]], 426 | ['Program', [['StatementList']]], 427 | ]) 428 | const initialState = { 429 | Program: { 430 | EOF: { 431 | $end: true 432 | } 433 | } 434 | } 435 | it('Test CallExpression With ReturnStatement', () => { 436 | expect(evaluate(` 437 | let a = 1 438 | function f(){ 439 | return ++a 440 | } 441 | f() 442 | `, map, initialState)).toEqual({ 443 | type: 'normal', 444 | value: { 445 | type: 'return', 446 | value: 2 447 | } 448 | }) 449 | expect(globalEnv.get('a')).toBe(2) 450 | }) 451 | it('Test CallExpression With ReturnStatement And Scope', () => { 452 | expect(evaluate(` 453 | let a = 1 454 | function f() { 455 | let a = 0 456 | a += 2 457 | return a 458 | } 459 | f() 460 | `, map, initialState)).toEqual({ 461 | type: 'normal', 462 | value: { 463 | type: 'return', 464 | value: 2 465 | } 466 | }) 467 | expect(globalEnv.get('a')).toBe(1) 468 | }) 469 | it('Test CallExpression With ReturnStatement, Scope And Parameters', () => { 470 | expect(evaluate(` 471 | let a = 1 472 | function f(b) { 473 | a += b 474 | return a 475 | } 476 | f(2) 477 | `, map, initialState)).toEqual({ 478 | type: 'normal', 479 | value: { 480 | type: 'return', 481 | value: 3 482 | } 483 | }) 484 | expect(globalEnv.get('a')).toBe(3) 485 | }) 486 | }) -------------------------------------------------------------------------------- /__test__/helpers/executor/3-new-promise.spec.js: -------------------------------------------------------------------------------- 1 | const { globalEnv, evaluate } = require('../../../src/index') 2 | describe('Test Promise', () => { 3 | const map = new Map([ 4 | ['PropertyDefinition', [ 5 | ['StringLiteral', ':', 'Expression'], 6 | ['NumbericLiteral', ':', 'Expression'] 7 | ]], 8 | ['PropertyDefinitionList', [ 9 | ['PropertyDefinition'], 10 | ['PropertyDefinitionList', ':', 'PropertyDefinition'] 11 | ]], 12 | ['ObjectLiteral', [ 13 | ['{', '}'], 14 | ['{', 'PropertyDefinitionList', '}'], 15 | ['{', 'PropertyDefinitionList', ',', '}'], 16 | ]], 17 | ['Literal', [ 18 | ['NumbericLiteral'], 19 | ['StringLiteral'], 20 | ['BooleanLiteral'], 21 | ['NullLiteral'], 22 | ['ObjectLiteral'], 23 | ]], 24 | ['Primary', [ 25 | ['(', 'Expression', ')'], 26 | ['Literal'], 27 | ['Identifier'] 28 | ]], 29 | ['Arguments', [ 30 | ['(', ')'], 31 | ['(', 'ArgumentList', ')'], 32 | ['(', 'ArgumentList', ',', ')'] 33 | ]], 34 | ['ArgumentList', [ 35 | ['AssignmentExpression'], 36 | ['ArgumentList', ',', 'AssignmentExpression'] 37 | ]], 38 | ['MemberExpression', [ 39 | ['Primary'], 40 | ['MemberExpression', '.', 'Identifier'], 41 | ['MemberExpression', '[', 'Expression', ']'], 42 | ['new', 'MemberExpression', 'Arguments'] 43 | ]], 44 | ['NewExpression', [ 45 | ['MemberExpression'], 46 | ['new', 'NewExpression'] 47 | ]], 48 | ['CallExpression', [ 49 | ['CoverCallExpressionAndAsyncArrowHead'], 50 | ['CallExpression', 'Arguments'], 51 | ['CallExpression', '[', 'Expression', ']'], 52 | ['CallExpression', '.', 'Identifier'], 53 | ]], 54 | ['CoverCallExpressionAndAsyncArrowHead', [ 55 | ['MemberExpression', 'Arguments'] 56 | ]], 57 | ['LeftHandSideExpression', [ 58 | ['MemberExpression'], 59 | ['CallExpression'], 60 | ['NewExpression'] 61 | ]], 62 | ['UpdateExpression', [ 63 | ['LeftHandSideExpression'], 64 | ['LeftHandSideExpression', '++'], 65 | ['LeftHandSideExpression', '--'], 66 | ['++', 'LeftHandSideExpression'], 67 | ['--', 'LeftHandSideExpression'] 68 | ]], 69 | ['MultiplicativeExpression', [ 70 | ['UpdateExpression'], 71 | ['MultiplicativeExpression', '*', 'UpdateExpression'], 72 | ['MultiplicativeExpression', '/', 'UpdateExpression'], 73 | ['MultiplicativeExpression', '%', 'UpdateExpression'] 74 | ]], 75 | ['AdditiveExpression', [ 76 | ['MultiplicativeExpression'], 77 | ['AdditiveExpression', '+', 'MultiplicativeExpression'], 78 | ['AdditiveExpression', '-', 'MultiplicativeExpression'] 79 | ]], 80 | ['RelationalExpression', [ 81 | ['AdditiveExpression'], 82 | ['RelationalExpression', '>', 'AdditiveExpression'], 83 | ['RelationalExpression', '<', 'AdditiveExpression'] 84 | ]], 85 | ['EqualityExpression', [ 86 | ['RelationalExpression'], 87 | ['EqualityExpression', '==', 'RelationalExpression'], 88 | ['EqualityExpression', '!=', 'RelationalExpression'], 89 | ['EqualityExpression', '===', 'RelationalExpression'], 90 | ['EqualityExpression', '!==', 'RelationalExpression'], 91 | ]], 92 | ['BitwiseANDExpression', [ 93 | ['EqualityExpression'], 94 | ['BitwiseANDExpression', '&', 'EqualityExpression'] 95 | ]], 96 | ['BitwiseXORExpression', [ 97 | ['BitwiseANDExpression'], 98 | ['BitwiseXORExpression', '^', 'BitwiseANDExpression'] 99 | ]], 100 | ['BitwiseORExpression', [ 101 | ['BitwiseXORExpression'], 102 | ['BitwiseORExpression', '|', 'BitwiseXORExpression'] 103 | ]], 104 | ['LogicalANDExpression', [ 105 | ['BitwiseORExpression'], 106 | ['LogicalANDExpression', '&&', 'BitwiseORExpression'] 107 | ]], 108 | ['LogicalORExpression', [ 109 | ['LogicalANDExpression'], 110 | ['LogicalORExpression', '||', 'LogicalANDExpression'] 111 | ]], 112 | ['CoalesceExpression', [ 113 | ['ShortCircuitExpression', '??', 'BitwiseORExpression'] 114 | ]], 115 | // ['CoalesceExpressionHead', [ 116 | // ['CoalesceExpression'], 117 | // ['BitwiseORExpression'] 118 | // ]], 119 | ['ShortCircuitExpression', [ 120 | ['LogicalORExpression'], 121 | ['CoalesceExpression'] 122 | ]], 123 | ['ConditionalExpression', [ 124 | ['ShortCircuitExpression'], 125 | ['ShortCircuitExpression', '?', 'AssignmentExpression', ':', 'AssignmentExpression'] 126 | ]], 127 | ['AssignmentOperator', [ 128 | ['*='],['/='], ['%='], ['+='], ['-='], 129 | ['<<='], ['>>='], ['>>>='], 130 | ['&='], ['^='], ['|='], ['**='] 131 | ]], 132 | ['AssignmentExpression', [ 133 | ['ConditionalExpression'], 134 | ['LeftHandSideExpression', '=', 'AssignmentExpression'], 135 | ['LeftHandSideExpression', 'AssignmentOperator', 'AssignmentExpression'], 136 | ['LeftHandSideExpression', '&&=', 'AssignmentExpression'], 137 | ['LeftHandSideExpression', '||=', 'AssignmentExpression'], 138 | ['LeftHandSideExpression', '??=', 'AssignmentExpression'], 139 | ]], 140 | ['Expression', [ 141 | ['AssignmentExpression'], 142 | ['Expression', ',', 'AssignmentExpression'], 143 | ]], 144 | ['Parameters', [ 145 | ['Identifier'], 146 | ['Parameters', ',', 'Identifier'] 147 | ]], 148 | ['FunctionDeclaration', [ 149 | ['function', 'Identifier', '(', ')', 'BlockStatement'], 150 | ['function', 'Identifier', '(', 'Parameters', ')', 'BlockStatement'] 151 | ]], 152 | ['Declaration', [ 153 | ['FunctionDeclaration'], 154 | ['var', 'Identifier', '=', 'Expression', ';'], 155 | ['let', 'Identifier', '=', 'Expression', ';'], 156 | ['const', 'Identifier', '=', 'Expression', ';'] 157 | ]], 158 | ['ExpressionStatement', [ 159 | ['Expression', ';'] 160 | ]], 161 | ['BlockStatement', [ 162 | ['{', '}'], 163 | ['{', 'StatementList', '}'], 164 | ]], 165 | ['IfStatement', [ 166 | ['if', '(', 'Expression', ')', 'Statement'], 167 | ['if', '(', 'Expression', ')', 'else', 'Statement'] 168 | ]], 169 | ['ForStatement', [ 170 | ['for', '(', 'let', 'Expression', ';', 'Expression', ';', 'Expression', ')', 'Statement'], 171 | ['for', '(', 'var', 'Expression', ';', 'Expression', ';', 'Expression', ')', 'Statement'], 172 | ['for', '(', 'Expression', ';', 'Expression', ';', 'Expression', ')', 'Statement'] 173 | ]], 174 | ['BreakableStatement', [ 175 | ['ForStatement'] 176 | ]], 177 | ['BreakStatement', [ 178 | ['break', ';'], 179 | ['break', 'Identifier', ';'] 180 | ]], 181 | ['ContinueStatement', [ 182 | ['continue', ';'], 183 | ['continue', 'Identifier', ';'] 184 | ]], 185 | ['ReturnStatement', [ 186 | ['return', ';'], 187 | ['return', 'Expression', ';'], 188 | ]], 189 | ['Statement', [ 190 | ['BlockStatement'], 191 | ['ExpressionStatement'], 192 | ['IfStatement'], 193 | ['ForStatement'], 194 | ['BreakableStatement'], 195 | ['BreakStatement'], 196 | ['ContinueStatement'], 197 | ['ReturnStatement'], 198 | ['Declaration'], 199 | ]], 200 | ['StatementListItem', [ 201 | ['Statement'], 202 | ['Declaration'] 203 | ]], 204 | ['StatementList', [ 205 | ['StatementListItem'], 206 | ['StatementList', 'StatementListItem'] 207 | ]], 208 | ['Program', [['StatementList']]], 209 | ]) 210 | const initialState = { 211 | Program: { 212 | EOF: { 213 | $end: true 214 | } 215 | } 216 | } 217 | 218 | it('Test New Promise', () => { 219 | evaluate(` 220 | function callback (resolve){resolve()} 221 | const p = new Promise(callback) 222 | `, map, initialState) 223 | expect(globalEnv.get('p')).toBeTruthy() 224 | }) 225 | 226 | it('Test then function of promise instance using resolve', () => { 227 | evaluate(` 228 | let b = 1 229 | function fn(resolve){ 230 | resolve(1) 231 | } 232 | function then(resolveValue){ 233 | b = b + resolveValue 234 | } 235 | const p = new Promise(fn) 236 | p.then(then) 237 | `, map, initialState) 238 | expect(globalEnv.get('b')).toBe(2) 239 | }) 240 | it('Test then function of promise instance using reject', () => { 241 | evaluate(` 242 | let b = 1 243 | function fn(resolve, reject){ 244 | reject(1) 245 | } 246 | function then(rejectReason){ 247 | b = b + rejectReason 248 | } 249 | const p = new Promise(fn) 250 | p.then(then) 251 | `, map, initialState) 252 | expect(globalEnv.get('b')).toBe(2) 253 | }) 254 | }) -------------------------------------------------------------------------------- /__test__/helpers/lexical-analyer.spec.js: -------------------------------------------------------------------------------- 1 | const { lex } = require('../../src/index') 2 | 3 | describe('Test LR Parser', () => { 4 | test('let a = null + 1 + "str"', () => { 5 | expect(JSON.stringify(lex('let a = null + 1 + "str"'))).toEqual(JSON.stringify([{"type": "let", "value": "let"}, {"type": "Identifier", "value": "a"}, {"type": "=", "value": "="}, {"type": "NulLiteral", "value": "null"}, {"type": "+", "value": "+"}, {"type": "NumbericLiteral", "value": "1"}, {"type": "+", "value": "+"}, {"type": "StringLiteral", "value": "\"str\""}, {"type": "EOF"}])) 6 | }) 7 | }) -------------------------------------------------------------------------------- /__test__/helpers/syntax-parser.spec.js: -------------------------------------------------------------------------------- 1 | const { lex, parse } = require('../../src/index') 2 | 3 | describe('Test Expression Parser', () => { 4 | it('literal', () => { 5 | const map = new Map([ 6 | ['Literal', [['NumbericLiteral'], ['StringLiteral'], ['BooleanLiteral'], ['NullLiteral']]] 7 | ]) 8 | const initialState = { 9 | Literal: { 10 | EOF: { 11 | $end: true 12 | } 13 | } 14 | } 15 | const expression = parse(lex("'fanfan'"), map, initialState) 16 | expect(JSON.stringify(expression)).toBe(JSON.stringify([{"type":"Literal","children":[{"type":"StringLiteral","value":"'fanfan'"}]},{"type":"EOF"}])) 17 | }) 18 | 19 | it('Primary', () => { 20 | const map = new Map([ 21 | ['Literal', [['NumbericLiteral'], ['StringLiteral'], ['BooleanLiteral'], ['NullLiteral']]], 22 | ['Primary', [['(', 'Expression', ')'], ['Literal'], ['Identifier']]] 23 | ]) 24 | const initialState = { 25 | Primary: { 26 | EOF: { 27 | $end: true 28 | } 29 | } 30 | } 31 | const expression = parse(lex("'fanfan'"), map, initialState) 32 | expect(JSON.stringify(expression)).toBe(JSON.stringify([{"type":"Primary","children":[{"type":"Literal","children":[{"type":"StringLiteral","value":"'fanfan'"}]}]},{"type":"EOF"}])) 33 | }) 34 | it('MemberExpression', () => { 35 | const map = new Map([ 36 | ['Literal', [['NumbericLiteral'], ['StringLiteral'], ['BooleanLiteral'], ['NullLiteral']]], 37 | ['Primary', [['(', 'Expression', ')'], ['Literal'], ['Identifier']]], 38 | ['MemberExpression', [['Primary'], ['MemberExpression', '.', 'Identifier'], ['MemberExpression', '[', 'Expression', ']']]], 39 | ]) 40 | const initialState = { 41 | MemberExpression: { 42 | EOF: { 43 | $end: true 44 | } 45 | } 46 | } 47 | const expression = parse(lex("a.b"), map, initialState) 48 | expect(JSON.stringify(expression)).toBe(JSON.stringify([{"type":"MemberExpression","children":[{"type":"MemberExpression","children":[{"type":"Primary","children":[{"type":"Identifier","value":"a"}]}]},{"type":".","value":"."},{"type":"Identifier","value":"b"}]},{"type":"EOF"}])) 49 | }) 50 | it('AdditiveExpression', () => { 51 | const map = new Map([ 52 | ['Literal', [['NumbericLiteral'], ['StringLiteral'], ['BooleanLiteral'], ['NullLiteral']]], 53 | ['Primary', [['(', 'Expression', ')'], ['Literal'], ['Identifier']]], 54 | ['MemberExpression', [['Primary'], ['MemberExpression', '.', 'Identifier'], ['MemberExpression', '[', 'Expression', ']']]], 55 | ['MultiplicativeExpression', [['MemberExpression'], ['MultiplicativeExpression', '*', 'MemberExpression'], ['MultiplicativeExpression', '/', 'MemberExpression'], ['MultiplicativeExpression', '%', 'MemberExpression']]], 56 | ['AdditiveExpression', [['MultiplicativeExpression'], ['AdditiveExpression', '+', 'MultiplicativeExpression'], ['AdditiveExpression', '-', 'MultiplicativeExpression']]], 57 | ]) 58 | const initialState = { 59 | AdditiveExpression: { 60 | EOF: { 61 | $end: true 62 | } 63 | } 64 | } 65 | const expression = parse(lex("a.b + 2 * 3"), map, initialState) 66 | expect(JSON.stringify(expression)).toBe(JSON.stringify([{"type":"AdditiveExpression","children":[{"type":"AdditiveExpression","children":[{"type":"MultiplicativeExpression","children":[{"type":"MemberExpression","children":[{"type":"MemberExpression","children":[{"type":"Primary","children":[{"type":"Identifier","value":"a"}]}]},{"type":".","value":"."},{"type":"Identifier","value":"b"}]}]}]},{"type":"+","value":"+"},{"type":"MultiplicativeExpression","children":[{"type":"MultiplicativeExpression","children":[{"type":"MemberExpression","children":[{"type":"Primary","children":[{"type":"Literal","children":[{"type":"NumbericLiteral","value":"2"}]}]}]}]},{"type":"*","value":"*"},{"type":"MemberExpression","children":[{"type":"Primary","children":[{"type":"Literal","children":[{"type":"NumbericLiteral","value":"3"}]}]}]}]}]},{"type":"EOF"}])) 67 | }) 68 | it('AssignmentExpression', () => { 69 | const map = new Map([ 70 | ['Literal', [['NumbericLiteral'], ['StringLiteral'], ['BooleanLiteral'], ['NullLiteral']]], 71 | ['Primary', [['(', 'Expression', ')'], ['Literal'], ['Identifier']]], 72 | ['MemberExpression', [['Primary'], ['MemberExpression', '.', 'Identifier'], ['MemberExpression', '[', 'Expression', ']']]], 73 | ['LeftHandSideExpression', [['MemberExpression']]], 74 | ['MultiplicativeExpression', [['LeftHandSideExpression'], ['MultiplicativeExpression', '*', 'LeftHandSideExpression'], ['MultiplicativeExpression', '/', 'LeftHandSideExpression'], ['MultiplicativeExpression', '%', 'LeftHandSideExpression']]], 75 | ['AdditiveExpression', [['MultiplicativeExpression'], ['AdditiveExpression', '+', 'MultiplicativeExpression'], ['AdditiveExpression', '-', 'MultiplicativeExpression']]], 76 | ['AssignmentExpression', [['AdditiveExpression'], ['LeftHandSideExpression', '=', 'AssignmentExpression']]] 77 | ]) 78 | const initialState = { 79 | AssignmentExpression: { 80 | EOF: { 81 | $end: true 82 | } 83 | } 84 | } 85 | const expression = parse(lex("a = 20"), map, initialState) 86 | expect(JSON.stringify(expression)).toBe(JSON.stringify([{"type":"AssignmentExpression","children":[{"type":"LeftHandSideExpression","children":[{"type":"MemberExpression","children":[{"type":"Primary","children":[{"type":"Identifier","value":"a"}]}]}]},{"type":"=","value":"="},{"type":"AssignmentExpression","children":[{"type":"AdditiveExpression","children":[{"type":"MultiplicativeExpression","children":[{"type":"LeftHandSideExpression","children":[{"type":"MemberExpression","children":[{"type":"Primary","children":[{"type":"Literal","children":[{"type":"NumbericLiteral","value":"20"}]}]}]}]}]}]}]}]},{"type":"EOF"}])) 87 | }) 88 | it('Statement', () => { 89 | const map = new Map([ 90 | ['Literal', [['NumbericLiteral'], ['StringLiteral'], ['BooleanLiteral'], ['NullLiteral']]], 91 | ['Primary', [['(', 'Expression', ')'], ['Literal'], ['Identifier']]], 92 | ['MemberExpression', [['Primary'], ['MemberExpression', '.', 'Identifier'], ['MemberExpression', '[', 'Expression', ']']]], 93 | ['LeftHandSideExpression', [['MemberExpression']]], 94 | ['MultiplicativeExpression', [['LeftHandSideExpression'], ['MultiplicativeExpression', '*', 'LeftHandSideExpression'], ['MultiplicativeExpression', '/', 'LeftHandSideExpression'], ['MultiplicativeExpression', '%', 'LeftHandSideExpression']]], 95 | ['AdditiveExpression', [['MultiplicativeExpression'], ['AdditiveExpression', '+', 'MultiplicativeExpression'], ['AdditiveExpression', '-', 'MultiplicativeExpression']]], 96 | ['AssignmentExpression', [['AdditiveExpression'], ['LeftHandSideExpression', '=', 'AssignmentExpression']]], 97 | ['Expression', [['AssignmentExpression']]], 98 | ['ExpressionStatement', [['Expression', ';']]], 99 | ['Declaration', [ 100 | ['var', 'Identifier', '=', 'Expression', ';'], 101 | ['let', 'Identifier', '=', 'Expression', ';'], 102 | ['const', 'Identifier', '=', 'Expression', ';'] 103 | ]], 104 | // ['IfStatement', [ 105 | // ['if', '(', 'Expression', ')', 'Statement'], 106 | // ['if', '(', 'Expression', ')', 'else', 'Statement'] 107 | // ]], 108 | // ['forStatement', [ 109 | // ['for', '(', 'Expression', ';', 'Expression', ';', 'Expression', ')', 'Statement'] 110 | // ]], 111 | ['Statement', [['ExpressionStatement'], ['IfStatement'], ['ForStatement'], ['Declaration']]], 112 | ]) 113 | const initialState = { 114 | Statement: { 115 | EOF: { 116 | $end: true 117 | } 118 | } 119 | } 120 | const expression = parse(lex("let a = 1;"), map, initialState) 121 | expect(JSON.stringify(expression)).toBe(JSON.stringify([{"type":"Statement","children":[{"type":"Declaration","children":[{"type":"let","value":"let"},{"type":"Identifier","value":"a"},{"type":"=","value":"="},{"type":"Expression","children":[{"type":"AssignmentExpression","children":[{"type":"AdditiveExpression","children":[{"type":"MultiplicativeExpression","children":[{"type":"LeftHandSideExpression","children":[{"type":"MemberExpression","children":[{"type":"Primary","children":[{"type":"Literal","children":[{"type":"NumbericLiteral","value":"1"}]}]}]}]}]}]}]}]},{"type":";","value":";"}]}]},{"type":"EOF"}])) 122 | }) 123 | it('Test StatementList', () => { 124 | const map = new Map([ 125 | ['Literal', [['NumbericLiteral'], ['StringLiteral'], ['BooleanLiteral'], ['NullLiteral']]], 126 | ['Primary', [['(', 'Expression', ')'], ['Literal'], ['Identifier']]], 127 | ['MemberExpression', [['Primary'], ['MemberExpression', '.', 'Identifier'], ['MemberExpression', '[', 'Expression', ']']]], 128 | ['LeftHandSideExpression', [['MemberExpression']]], 129 | ['MultiplicativeExpression', [['LeftHandSideExpression'], ['MultiplicativeExpression', '*', 'LeftHandSideExpression'], ['MultiplicativeExpression', '/', 'LeftHandSideExpression'], ['MultiplicativeExpression', '%', 'LeftHandSideExpression']]], 130 | ['AdditiveExpression', [['MultiplicativeExpression'], ['AdditiveExpression', '+', 'MultiplicativeExpression'], ['AdditiveExpression', '-', 'MultiplicativeExpression']]], 131 | ['AssignmentExpression', [['AdditiveExpression'], ['LeftHandSideExpression', '=', 'AssignmentExpression']]], 132 | ['Expression', [['AssignmentExpression']]], 133 | ['ExpressionStatement', [['Expression', ';']]], 134 | ['Declaration', [ 135 | ['var', 'Identifier', '=', 'Expression', ';'], 136 | ['let', 'Identifier', '=', 'Expression', ';'], 137 | ['const', 'Identifier', '=', 'Expression', ';'] 138 | ]], 139 | ['Statement', [['ExpressionStatement'], ['IfStatement'], ['ForStatement'], ['Declaration']]], 140 | ['StatementListItem', [['Statement'], ['Declaration']]], 141 | ['StatementList', [['StatementListItem'], ['StatementList', 'StatementListItem']]] 142 | ]) 143 | const initialState = { 144 | StatementList: { 145 | EOF: { 146 | $end: true 147 | } 148 | } 149 | } 150 | const expression = parse(lex(` 151 | let a = 1; 152 | const b = 1; 153 | `), map, initialState) 154 | expect(JSON.stringify(expression)).toBe(JSON.stringify([{"type":"StatementList","children":[{"type":"StatementList","children":[{"type":"StatementListItem","children":[{"type":"Statement","children":[{"type":"Declaration","children":[{"type":"let","value":"let"},{"type":"Identifier","value":"a"},{"type":"=","value":"="},{"type":"Expression","children":[{"type":"AssignmentExpression","children":[{"type":"AdditiveExpression","children":[{"type":"MultiplicativeExpression","children":[{"type":"LeftHandSideExpression","children":[{"type":"MemberExpression","children":[{"type":"Primary","children":[{"type":"Literal","children":[{"type":"NumbericLiteral","value":"1"}]}]}]}]}]}]}]}]},{"type":";","value":";"}]}]}]}]},{"type":"StatementListItem","children":[{"type":"Statement","children":[{"type":"Declaration","children":[{"type":"const","value":"const"},{"type":"Identifier","value":"b"},{"type":"=","value":"="},{"type":"Expression","children":[{"type":"AssignmentExpression","children":[{"type":"AdditiveExpression","children":[{"type":"MultiplicativeExpression","children":[{"type":"LeftHandSideExpression","children":[{"type":"MemberExpression","children":[{"type":"Primary","children":[{"type":"Literal","children":[{"type":"NumbericLiteral","value":"1"}]}]}]}]}]}]}]}]},{"type":";","value":";"}]}]}]}]},{"type":"EOF"}])) 155 | }) 156 | 157 | it('ASI followed EOF and }', () => { 158 | const map = new Map([ 159 | ['Literal', [['NumbericLiteral'], ['StringLiteral'], ['BooleanLiteral'], ['NullLiteral']]], 160 | ['Primary', [['(', 'Expression', ')'], ['Literal'], ['Identifier']]], 161 | ['MemberExpression', [['Primary'], ['MemberExpression', '.', 'Identifier'], ['MemberExpression', '[', 'Expression', ']']]], 162 | ['LeftHandSideExpression', [['MemberExpression']]], 163 | ['MultiplicativeExpression', [['LeftHandSideExpression'], ['MultiplicativeExpression', '*', 'LeftHandSideExpression'], ['MultiplicativeExpression', '/', 'LeftHandSideExpression'], ['MultiplicativeExpression', '%', 'LeftHandSideExpression']]], 164 | ['AdditiveExpression', [['MultiplicativeExpression'], ['AdditiveExpression', '+', 'MultiplicativeExpression'], ['AdditiveExpression', '-', 'MultiplicativeExpression']]], 165 | ['AssignmentExpression', [['AdditiveExpression'], ['LeftHandSideExpression', '=', 'AssignmentExpression']]], 166 | ['Expression', [['AssignmentExpression']]], 167 | ['ExpressionStatement', [['Expression', ';']]], 168 | ['Declaration', [ 169 | ['var', 'Identifier', '=', 'Expression', ';'], 170 | ['let', 'Identifier', '=', 'Expression', ';'], 171 | ['const', 'Identifier', '=', 'Expression', ';'] 172 | ]], 173 | ['Statement', [['ExpressionStatement'], ['IfStatement'], ['ForStatement'], ['Declaration']]], 174 | ['StatementListItem', [['Statement'], ['Declaration']]], 175 | ['StatementList', [['StatementListItem'], ['StatementList', 'StatementListItem']]] 176 | ]) 177 | const initialState = { 178 | StatementList: { 179 | EOF: { 180 | $end: true 181 | } 182 | } 183 | } 184 | const expression = parse(lex('let a = 1 + 2 + 3'), map, initialState) 185 | expect(JSON.stringify(expression)).toBe(JSON.stringify([{"type":"StatementList","children":[{"type":"StatementListItem","children":[{"type":"Statement","children":[{"type":"Declaration","children":[{"type":"let","value":"let"},{"type":"Identifier","value":"a"},{"type":"=","value":"="},{"type":"Expression","children":[{"type":"AssignmentExpression","children":[{"type":"AdditiveExpression","children":[{"type":"AdditiveExpression","children":[{"type":"AdditiveExpression","children":[{"type":"MultiplicativeExpression","children":[{"type":"LeftHandSideExpression","children":[{"type":"MemberExpression","children":[{"type":"Primary","children":[{"type":"Literal","children":[{"type":"NumbericLiteral","value":"1"}]}]}]}]}]}]},{"type":"+","value":"+"},{"type":"MultiplicativeExpression","children":[{"type":"LeftHandSideExpression","children":[{"type":"MemberExpression","children":[{"type":"Primary","children":[{"type":"Literal","children":[{"type":"NumbericLiteral","value":"2"}]}]}]}]}]}]},{"type":"+","value":"+"},{"type":"MultiplicativeExpression","children":[{"type":"LeftHandSideExpression","children":[{"type":"MemberExpression","children":[{"type":"Primary","children":[{"type":"Literal","children":[{"type":"NumbericLiteral","value":"3"}]}]}]}]}]}]}]}]},{"type":";","value":";"}]}]}]}]},{"type":"EOF"}])) 186 | }) 187 | 188 | it('ASI followed Enter', () => { 189 | const map = new Map([ 190 | ['Literal', [['NumbericLiteral'], ['StringLiteral'], ['BooleanLiteral'], ['NullLiteral']]], 191 | ['Primary', [['(', 'Expression', ')'], ['Literal'], ['Identifier']]], 192 | ['MemberExpression', [['Primary'], ['MemberExpression', '.', 'Identifier'], ['MemberExpression', '[', 'Expression', ']']]], 193 | ['LeftHandSideExpression', [['MemberExpression']]], 194 | ['MultiplicativeExpression', [['LeftHandSideExpression'], ['MultiplicativeExpression', '*', 'LeftHandSideExpression'], ['MultiplicativeExpression', '/', 'LeftHandSideExpression'], ['MultiplicativeExpression', '%', 'LeftHandSideExpression']]], 195 | ['AdditiveExpression', [['MultiplicativeExpression'], ['AdditiveExpression', '+', 'MultiplicativeExpression'], ['AdditiveExpression', '-', 'MultiplicativeExpression']]], 196 | ['AssignmentExpression', [['AdditiveExpression'], ['LeftHandSideExpression', '=', 'AssignmentExpression']]], 197 | ['Expression', [['AssignmentExpression']]], 198 | ['ExpressionStatement', [['Expression', ';']]], 199 | ['Declaration', [ 200 | ['var', 'Identifier', '=', 'Expression', ';'], 201 | ['let', 'Identifier', '=', 'Expression', ';'], 202 | ['const', 'Identifier', '=', 'Expression', ';'] 203 | ]], 204 | ['Statement', [['ExpressionStatement'], ['IfStatement'], ['ForStatement'], ['Declaration']]], 205 | ['StatementListItem', [['Statement'], ['Declaration']]], 206 | ['StatementList', [['StatementListItem'], ['StatementList', 'StatementListItem']]] 207 | ]) 208 | const initialState = { 209 | StatementList: { 210 | EOF: { 211 | $end: true 212 | } 213 | } 214 | } 215 | const expression = parse(lex("let a = 1 + 2 + 3\nlet b = 1"), map, initialState) 216 | expect(JSON.stringify(expression)).toBe(JSON.stringify([{"type":"StatementList","children":[{"type":"StatementList","children":[{"type":"StatementListItem","children":[{"type":"Statement","children":[{"type":"Declaration","children":[{"type":"let","value":"let"},{"type":"Identifier","value":"a"},{"type":"=","value":"="},{"type":"Expression","children":[{"type":"AssignmentExpression","children":[{"type":"AdditiveExpression","children":[{"type":"AdditiveExpression","children":[{"type":"AdditiveExpression","children":[{"type":"MultiplicativeExpression","children":[{"type":"LeftHandSideExpression","children":[{"type":"MemberExpression","children":[{"type":"Primary","children":[{"type":"Literal","children":[{"type":"NumbericLiteral","value":"1"}]}]}]}]}]}]},{"type":"+","value":"+"},{"type":"MultiplicativeExpression","children":[{"type":"LeftHandSideExpression","children":[{"type":"MemberExpression","children":[{"type":"Primary","children":[{"type":"Literal","children":[{"type":"NumbericLiteral","value":"2"}]}]}]}]}]}]},{"type":"+","value":"+"},{"type":"MultiplicativeExpression","children":[{"type":"LeftHandSideExpression","children":[{"type":"MemberExpression","children":[{"type":"Primary","children":[{"type":"Literal","children":[{"type":"NumbericLiteral","value":"3"}]}]}]}]}]}]}]}]},{"type":";","value":";"}]}]}]}]},{"type":"StatementListItem","children":[{"type":"Statement","children":[{"type":"Declaration","children":[{"type":"let","value":"let"},{"type":"Identifier","value":"b"},{"type":"=","value":"="},{"type":"Expression","children":[{"type":"AssignmentExpression","children":[{"type":"AdditiveExpression","children":[{"type":"MultiplicativeExpression","children":[{"type":"LeftHandSideExpression","children":[{"type":"MemberExpression","children":[{"type":"Primary","children":[{"type":"Literal","children":[{"type":"NumbericLiteral","value":"1"}]}]}]}]}]}]}]}]},{"type":";","value":";"}]}]}]}]},{"type":"EOF"}])) 217 | }) 218 | 219 | it('New Expression / Call Expression', () => { 220 | const map = new Map([ 221 | ['Literal', [['NumbericLiteral'], ['StringLiteral'], ['BooleanLiteral'], ['NullLiteral']]], 222 | ['Primary', [['(', 'Expression', ')'], ['Literal'], ['Identifier']]], 223 | ['MemberExpression', [['Primary'], ['MemberExpression', '.', 'Identifier'], ['MemberExpression', '[', 'Expression', ']']]], 224 | ['NewExpression', [['MemberExpression'], ['new', 'NewExpression']]], 225 | ['CallExpression', [ 226 | ['new', 'MemberExpression', '(', ')'], 227 | ['MemberExpression', '(', ')'], 228 | ['CallExpression', '.', 'Identifier'], 229 | ['CallExpression', '[', 'Expression', ']'], 230 | ['CallExpression', '(', 'Arguments', ')'] 231 | ]], 232 | ['LeftHandSideExpression', [['MemberExpression'], ['CallExpression'], ['NewExpression']]], 233 | ['MultiplicativeExpression', [['LeftHandSideExpression'], ['MultiplicativeExpression', '*', 'LeftHandSideExpression'], ['MultiplicativeExpression', '/', 'LeftHandSideExpression'], ['MultiplicativeExpression', '%', 'LeftHandSideExpression']]], 234 | ['AdditiveExpression', [['MultiplicativeExpression'], ['AdditiveExpression', '+', 'MultiplicativeExpression'], ['AdditiveExpression', '-', 'MultiplicativeExpression']]], 235 | ['AssignmentExpression', [['AdditiveExpression'], ['LeftHandSideExpression', '=', 'AssignmentExpression']]], 236 | ['Expression', [['AssignmentExpression']]], 237 | ['ExpressionStatement', [['Expression', ';']]], 238 | ['Declaration', [ 239 | ['var', 'Identifier', '=', 'Expression', ';'], 240 | ['let', 'Identifier', '=', 'Expression', ';'], 241 | ['const', 'Identifier', '=', 'Expression', ';'] 242 | ]], 243 | ['Statement', [['ExpressionStatement'], ['IfStatement'], ['ForStatement'], ['Declaration']]], 244 | ['StatementListItem', [['Statement'], ['Declaration']]], 245 | ['StatementList', [['StatementListItem'], ['StatementList', 'StatementListItem']]] 246 | ]) 247 | const initialState = { 248 | StatementList: { 249 | EOF: { 250 | $end: true 251 | } 252 | } 253 | } 254 | const expression = parse(lex("new Class1()"), map, initialState) 255 | expect(JSON.stringify(expression)).toBe(JSON.stringify([{"type":"StatementList","children":[{"type":"StatementListItem","children":[{"type":"Statement","children":[{"type":"ExpressionStatement","children":[{"type":"Expression","children":[{"type":"AssignmentExpression","children":[{"type":"AdditiveExpression","children":[{"type":"MultiplicativeExpression","children":[{"type":"LeftHandSideExpression","children":[{"type":"CallExpression","children":[{"type":"new","value":"new"},{"type":"MemberExpression","children":[{"type":"Primary","children":[{"type":"Identifier","value":"Class1"}]}]},{"type":"(","value":"("},{"type":")","value":")"}]}]}]}]}]}]},{"type":";","value":";"}]}]}]}]},{"type":"EOF"}])) 256 | }) 257 | it('Function Declaration', () => { 258 | const map = new Map([ 259 | ['Literal', [['NumbericLiteral'], ['StringLiteral'], ['BooleanLiteral'], ['NullLiteral']]], 260 | ['Primary', [['(', 'Expression', ')'], ['Literal'], ['Identifier']]], 261 | ['MemberExpression', [['Primary'], ['MemberExpression', '.', 'Identifier'], ['MemberExpression', '[', 'Expression', ']']]], 262 | ['NewExpression', [['MemberExpression'], ['new', 'NewExpression']]], 263 | ['CallExpression', [ 264 | ['new', 'MemberExpression', '(', ')'], 265 | ['MemberExpression', '(', ')'], 266 | ['CallExpression', '.', 'Identifier'], 267 | ['CallExpression', '[', 'Expression', ']'], 268 | ['CallExpression', '(', 'Arguments', ')'] 269 | ]], 270 | ['LeftHandSideExpression', [['MemberExpression'], ['CallExpression'], ['NewExpression']]], 271 | ['MultiplicativeExpression', [['LeftHandSideExpression'], ['MultiplicativeExpression', '*', 'LeftHandSideExpression'], ['MultiplicativeExpression', '/', 'LeftHandSideExpression'], ['MultiplicativeExpression', '%', 'LeftHandSideExpression']]], 272 | ['AdditiveExpression', [['MultiplicativeExpression'], ['AdditiveExpression', '+', 'MultiplicativeExpression'], ['AdditiveExpression', '-', 'MultiplicativeExpression']]], 273 | ['AssignmentExpression', [['AdditiveExpression'], ['LeftHandSideExpression', '=', 'AssignmentExpression']]], 274 | ['Expression', [['AssignmentExpression']]], 275 | ['ExpressionStatement', [['Expression', ';']]], 276 | ['Declaration', [ 277 | ['var', 'Identifier', '=', 'Expression', ';'], 278 | ['let', 'Identifier', '=', 'Expression', ';'], 279 | ['const', 'Identifier', '=', 'Expression', ';'] 280 | ]], 281 | /** Added: Start */ 282 | ['FunctionDeclaration', [ 283 | ['function', 'Identifier', '(', ')', '{', 'StatementList', '}'], 284 | ['function', 'Identifier', '(', 'Parameters', ')', '{', 'StatementList', '}'] 285 | ]], 286 | ['Parameters', [['Identifier'], ['Parameters', ',', 'Identifier']]], 287 | /** Added: End */ 288 | ['Statement', [['ExpressionStatement'], ['IfStatement'], ['ForStatement'], ['Declaration']]], 289 | ['StatementListItem', [['Statement'], ['Declaration']]], 290 | ['StatementList', [['StatementListItem'], ['StatementList', 'StatementListItem']]], 291 | /** Added */ 292 | ['Program', [['StatementList']]] 293 | ]) 294 | const initialState = { 295 | StatementList: { 296 | EOF: { 297 | $end: true 298 | } 299 | } 300 | } 301 | const expression = parse(lex("new Class1()"), map, initialState) 302 | expect(JSON.stringify(expression)).toBe(JSON.stringify([{"type":"StatementList","children":[{"type":"StatementListItem","children":[{"type":"Statement","children":[{"type":"ExpressionStatement","children":[{"type":"Expression","children":[{"type":"AssignmentExpression","children":[{"type":"AdditiveExpression","children":[{"type":"MultiplicativeExpression","children":[{"type":"LeftHandSideExpression","children":[{"type":"CallExpression","children":[{"type":"new","value":"new"},{"type":"MemberExpression","children":[{"type":"Primary","children":[{"type":"Identifier","value":"Class1"}]}]},{"type":"(","value":"("},{"type":")","value":")"}]}]}]}]}]}]},{"type":";","value":";"}]}]}]}]},{"type":"EOF"}])) 303 | }) 304 | }) -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 | 7 |let a = 1;
51 | let b = 1;
52 | a <<= b++;
53 | for (let i = 0; i < 10; i++) {
54 | if (i % 2 === 0) continue;
55 | if ((i | 2) == '11') break;
56 | a++;
57 | }
58 | undefined && 1 ?? (0 || a + b);
59 |