UNPKG

yzhanjsinterpreter

Version:

A JavaScript Interpreter Using JS itself. JavaScript 解释器,包含词法分析、语法解析和执行

350 lines (343 loc) 16.3 kB
const { evaluate, globalEnv } = require('../../../src/index') describe('Test Executor', () => { const map = new Map([ ['Literal', [['NumbericLiteral'], ['StringLiteral'], ['BooleanLiteral'], ['NullLiteral']]], ['Primary', [['(', 'Expression', ')'], ['Literal'], ['Identifier']]], ['MemberExpression', [['Primary'], ['MemberExpression', '.', 'Identifier'], ['MemberExpression', '[', 'Expression', ']']]], ['NewExpression', [['MemberExpression'], ['new', 'NewExpression']]], ['CallExpression', [ ['new', 'MemberExpression', '(', ')'], ['MemberExpression', '(', ')'], ['CallExpression', '.', 'Identifier'], ['CallExpression', '[', 'Expression', ']'], ['CallExpression', '(', 'Arguments', ')'] ]], ['LeftHandSideExpression', [['MemberExpression'], ['CallExpression'], ['NewExpression']]], ['MultiplicativeExpression', [['LeftHandSideExpression'], ['MultiplicativeExpression', '*', 'LeftHandSideExpression'], ['MultiplicativeExpression', '/', 'LeftHandSideExpression'], ['MultiplicativeExpression', '%', 'LeftHandSideExpression']]], ['AdditiveExpression', [['MultiplicativeExpression'], ['AdditiveExpression', '+', 'MultiplicativeExpression'], ['AdditiveExpression', '-', 'MultiplicativeExpression']]], ['AssignmentExpression', [['AdditiveExpression'], ['LeftHandSideExpression', '=', 'AssignmentExpression']]], ['Expression', [['AssignmentExpression']]], ['ExpressionStatement', [['Expression', ';']]], ['Declaration', [ ['var', 'Identifier', '=', 'Expression', ';'], ['let', 'Identifier', '=', 'Expression', ';'], ['const', 'Identifier', '=', 'Expression', ';'] ]], /** Added: Start */ ['Parameters', [['Identifier'], ['Parameters', ',', 'Identifier']]], ['FunctionDeclaration', [ ['function', 'Identifier', '(', ')', '{', 'StatementList', '}'], ['function', 'Identifier', '(', 'Parameters', ')', '{', 'StatementList', '}'] ]], /** Added: End */ ['Statement', [['ExpressionStatement'], ['IfStatement'], ['ForStatement'], ['Declaration']]], ['StatementListItem', [['Statement'], ['Declaration']]], ['StatementList', [['StatementListItem'], ['StatementList', 'StatementListItem']]], /** Added */ ['Program', [['StatementList']]], ]) const initialState = { Program: { EOF: { $end: true } } } it('1 + 1', () => { expect(evaluate('1 + 1', map, initialState)).toEqual({"type": "normal", "value": 2}) }) }) describe('Test Scope', () => { const map = new Map([ ['Literal', [['NumbericLiteral'], ['StringLiteral'], ['BooleanLiteral'], ['NullLiteral']]], ['Primary', [['(', 'Expression', ')'], ['Literal'], ['Identifier']]], ['MemberExpression', [['Primary'], ['MemberExpression', '.', 'Identifier'], ['MemberExpression', '[', 'Expression', ']']]], ['NewExpression', [['MemberExpression'], ['new', 'NewExpression']]], ['CallExpression', [ ['new', 'MemberExpression', '(', ')'], ['MemberExpression', '(', ')'], ['CallExpression', '.', 'Identifier'], ['CallExpression', '[', 'Expression', ']'], ['CallExpression', '(', 'Arguments', ')'] ]], ['LeftHandSideExpression', [['MemberExpression'], ['CallExpression'], ['NewExpression']]], ['MultiplicativeExpression', [['LeftHandSideExpression'], ['MultiplicativeExpression', '*', 'LeftHandSideExpression'], ['MultiplicativeExpression', '/', 'LeftHandSideExpression'], ['MultiplicativeExpression', '%', 'LeftHandSideExpression']]], ['AdditiveExpression', [['MultiplicativeExpression'], ['AdditiveExpression', '+', 'MultiplicativeExpression'], ['AdditiveExpression', '-', 'MultiplicativeExpression']]], ['AssignmentExpression', [['AdditiveExpression'], ['LeftHandSideExpression', '=', 'AssignmentExpression']]], ['Expression', [['AssignmentExpression'], ['Expression', ',', 'AssignmentExpression']]], ['ExpressionStatement', [['Expression', ';']]], ['Declaration', [ ['var', 'Identifier', '=', 'Expression', ';'], ['let', 'Identifier', '=', 'Expression', ';'], ['const', 'Identifier', '=', 'Expression', ';'] ]], ['Parameters', [['Identifier'], ['Parameters', ',', 'Identifier']]], ['FunctionDeclaration', [ ['function', 'Identifier', '(', ')', '{', 'StatementList', '}'], ['function', 'Identifier', '(', 'Parameters', ')', '{', 'StatementList', '}'] ]], /** Added: Start */ ['IfStatement', [ ['if', '(', 'Expression', ')', 'Statement'], ['if', '(', 'Expression', ')', 'else', 'Statement'] ]], ['BlockStatement', [ ['{', '}'], ['{', 'StatementList', '}'], ]], ['ForStatement', [ ['for', '(', 'Expression', ';', 'Expression', ';', 'Expression', ')', 'Statement'] ]], /** Added: End */ ['Statement', [['ExpressionStatement'], ['IfStatement'], ['ForStatement'], ['Declaration'], ['BlockStatement']]], ['StatementListItem', [['Statement'], ['Declaration']]], ['StatementList', [['StatementListItem'], ['StatementList', 'StatementListItem']]], /** Added */ ['Program', [['StatementList']]], ]) const initialState = { Program: { EOF: { $end: true } } } it('DelcarationStatement', () => { evaluate('let a = 1', map, initialState) expect(globalEnv.vars.get('a')).toBe(1) }) it('AdditiveStatement', () => { evaluate('let b = 1;b = b + 1', map, initialState) expect(globalEnv.vars.get('b')).toBe(2) }) it('Nested Blocks', () => { expect(evaluate(`{ let a= 1 { let b = a + 1 b + 1 } }`, map, initialState)).toEqual({"type": "normal", "value": 3}) }) }) describe('Test Statement Parser', () => { describe('Test IfStatement', () => { const map = new Map([ ['Literal', [['NumbericLiteral'], ['StringLiteral'], ['BooleanLiteral'], ['NullLiteral']]], ['Primary', [['(', 'Expression', ')'], ['Literal'], ['Identifier']]], ['MemberExpression', [['Primary'], ['MemberExpression', '.', 'Identifier'], ['MemberExpression', '[', 'Expression', ']']]], ['NewExpression', [['MemberExpression'], ['new', 'NewExpression']]], ['CallExpression', [ ['new', 'MemberExpression', '(', ')'], ['MemberExpression', '(', ')'], ['CallExpression', '.', 'Identifier'], ['CallExpression', '[', 'Expression', ']'], ['CallExpression', '(', 'Arguments', ')'] ]], ['LeftHandSideExpression', [['MemberExpression'], ['CallExpression'], ['NewExpression']]], ['MultiplicativeExpression', [['LeftHandSideExpression'], ['MultiplicativeExpression', '*', 'LeftHandSideExpression'], ['MultiplicativeExpression', '/', 'LeftHandSideExpression'], ['MultiplicativeExpression', '%', 'LeftHandSideExpression']]], ['AdditiveExpression', [['MultiplicativeExpression'], ['AdditiveExpression', '+', 'MultiplicativeExpression'], ['AdditiveExpression', '-', 'MultiplicativeExpression']]], ['AssignmentExpression', [['AdditiveExpression'], ['LeftHandSideExpression', '=', 'AssignmentExpression']]], ['Expression', [['AssignmentExpression'], ['Expression', ',', 'AssignmentExpression']]], ['ExpressionStatement', [['Expression', ';']]], ['Declaration', [ ['var', 'Identifier', '=', 'Expression', ';'], ['let', 'Identifier', '=', 'Expression', ';'], ['const', 'Identifier', '=', 'Expression', ';'] ]], ['Parameters', [['Identifier'], ['Parameters', ',', 'Identifier']]], ['FunctionDeclaration', [ ['function', 'Identifier', '(', ')', '{', 'StatementList', '}'], ['function', 'Identifier', '(', 'Parameters', ')', '{', 'StatementList', '}'] ]], /** Added: Start */ ['IfStatement', [ ['if', '(', 'Expression', ')', 'Statement'], ['if', '(', 'Expression', ')', 'else', 'Statement'] ]], ['BlockStatement', [ ['{', '}'], ['{', 'StatementList', '}'], ]], /** Added: End */ ['Statement', [['ExpressionStatement'], ['IfStatement'], ['ForStatement'], ['Declaration'], ['BlockStatement']]], ['StatementListItem', [['Statement'], ['Declaration']]], ['StatementList', [['StatementListItem'], ['StatementList', 'StatementListItem']]], /** Added */ ['Program', [['StatementList']]], ]) const initialState = { Program: { EOF: { $end: true } } } it('IfStatement', () => { expect(evaluate('if (ture) {const a = 1}', map, initialState)).toEqual({ type: 'normal', value: undefined }) }) }) describe('Test ForStatement', () => { const map = new Map([ ['Literal', [['NumbericLiteral'], ['StringLiteral'], ['BooleanLiteral'], ['NullLiteral']]], ['Primary', [['(', 'Expression', ')'], ['Literal'], ['Identifier']]], ['MemberExpression', [['Primary'], ['MemberExpression', '.', 'Identifier'], ['MemberExpression', '[', 'Expression', ']']]], ['NewExpression', [['MemberExpression'], ['new', 'NewExpression']]], ['CallExpression', [ ['new', 'MemberExpression', '(', ')'], ['MemberExpression', '(', ')'], ['CallExpression', '.', 'Identifier'], ['CallExpression', '[', 'Expression', ']'], ['CallExpression', '(', 'Arguments', ')'] ]], ['LeftHandSideExpression', [['MemberExpression'], ['CallExpression'], ['NewExpression']]], ['MultiplicativeExpression', [['UpdateExpression'], ['MultiplicativeExpression', '*', 'UpdateExpression'], ['MultiplicativeExpression', '/', 'UpdateExpression'], ['MultiplicativeExpression', '%', 'UpdateExpression']]], ['AdditiveExpression', [['MultiplicativeExpression'], ['AdditiveExpression', '+', 'MultiplicativeExpression'], ['AdditiveExpression', '-', 'MultiplicativeExpression']]], ['RelationalExpression', [['AdditiveExpression'], ['RelationalExpression', '>', 'AdditiveExpression'], ['RelationalExpression', '<', 'AdditiveExpression']]], ['AssignmentExpression', [['RelationalExpression'], ['LeftHandSideExpression', '=', 'RelationalExpression']]], ['Expression', [ ['AssignmentExpression'], ['Expression', ',', 'AssignmentExpression'], ]], ['UpdateExpression', [ ['LeftHandSideExpression'], ['LeftHandSideExpression', '++'], ['LeftHandSideExpression', '--'], ['++', 'LeftHandSideExpression'], ['--', 'LeftHandSideExpression'] ]], ['ExpressionStatement', [['Expression', ';']]], ['Declaration', [ ['var', 'Identifier', '=', 'Expression', ';'], ['let', 'Identifier', '=', 'Expression', ';'], ['const', 'Identifier', '=', 'Expression', ';'] ]], ['Parameters', [['Identifier'], ['Parameters', ',', 'Identifier']]], ['FunctionDeclaration', [ ['function', 'Identifier', '(', ')', '{', 'StatementList', '}'], ['function', 'Identifier', '(', 'Parameters', ')', '{', 'StatementList', '}'] ]], /** Added: Start */ ['IfStatement', [ ['if', '(', 'Expression', ')', 'Statement'], ['if', '(', 'Expression', ')', 'else', 'Statement'] ]], ['BlockStatement', [ ['{', '}'], ['{', 'StatementList', '}'], ]], ['ForStatement', [ ['for', '(', 'let', 'Expression', ';', 'Expression', ';', 'Expression', ')', 'Statement'], ['for', '(', 'var', 'Expression', ';', 'Expression', ';', 'Expression', ')', 'Statement'], ['for', '(', 'Expression', ';', 'Expression', ';', 'Expression', ')', 'Statement'] ]], /** Added: End */ ['Statement', [['ExpressionStatement'], ['IfStatement'], ['ForStatement'], ['Declaration'], ['BlockStatement']]], ['StatementListItem', [['Statement'], ['Declaration']]], ['StatementList', [['StatementListItem'], ['StatementList', 'StatementListItem']]], /** Added */ ['Program', [['StatementList']]], ]) const initialState = { Program: { EOF: { $end: true } } } it('ForStatement', () => { evaluate(` let a = 0 for(let i = 0; i < 10; i++) {a++} `, map, initialState) expect(globalEnv.get('a')).toBe(10) }) }) describe('Test BreakStatement', () => { const map = new Map([ ['Literal', [['NumbericLiteral'], ['StringLiteral'], ['BooleanLiteral'], ['NullLiteral']]], ['Primary', [['(', 'Expression', ')'], ['Literal'], ['Identifier']]], ['MemberExpression', [['Primary'], ['MemberExpression', '.', 'Identifier'], ['MemberExpression', '[', 'Expression', ']']]], ['NewExpression', [['MemberExpression'], ['new', 'NewExpression']]], ['CallExpression', [ ['new', 'MemberExpression', '(', ')'], ['MemberExpression', '(', ')'], ['CallExpression', '.', 'Identifier'], ['CallExpression', '[', 'Expression', ']'], ['CallExpression', '(', 'Arguments', ')'] ]], ['LeftHandSideExpression', [['MemberExpression'], ['CallExpression'], ['NewExpression']]], ['MultiplicativeExpression', [['UpdateExpression'], ['MultiplicativeExpression', '*', 'UpdateExpression'], ['MultiplicativeExpression', '/', 'UpdateExpression'], ['MultiplicativeExpression', '%', 'UpdateExpression']]], ['AdditiveExpression', [['MultiplicativeExpression'], ['AdditiveExpression', '+', 'MultiplicativeExpression'], ['AdditiveExpression', '-', 'MultiplicativeExpression']]], ['RelationalExpression', [['AdditiveExpression'], ['RelationalExpression', '>', 'AdditiveExpression'], ['RelationalExpression', '<', 'AdditiveExpression']]], ['EqualityExpression', [ ['RelationalExpression'], ['EqualityExpression', '==', 'RelationalExpression'], ['EqualityExpression', '!=', 'RelationalExpression'], ['EqualityExpression', '===', 'RelationalExpression'], ['EqualityExpression', '!==', 'RelationalExpression'], ]], ['AssignmentExpression', [['EqualityExpression'], ['LeftHandSideExpression', '=', 'EqualityExpression']]], ['Expression', [ ['AssignmentExpression'], ['Expression', ',', 'AssignmentExpression'], ]], ['UpdateExpression', [ ['LeftHandSideExpression'], ['LeftHandSideExpression', '++'], ['LeftHandSideExpression', '--'], ['++', 'LeftHandSideExpression'], ['--', 'LeftHandSideExpression'] ]], ['ExpressionStatement', [['Expression', ';']]], ['Declaration', [ ['var', 'Identifier', '=', 'Expression', ';'], ['let', 'Identifier', '=', 'Expression', ';'], ['const', 'Identifier', '=', 'Expression', ';'] ]], ['Parameters', [['Identifier'], ['Parameters', ',', 'Identifier']]], ['FunctionDeclaration', [ ['function', 'Identifier', '(', ')', '{', 'StatementList', '}'], ['function', 'Identifier', '(', 'Parameters', ')', '{', 'StatementList', '}'] ]], /** Added: Start */ ['IfStatement', [ ['if', '(', 'Expression', ')', 'Statement'], ['if', '(', 'Expression', ')', 'else', 'Statement'] ]], ['BlockStatement', [ ['{', '}'], ['{', 'StatementList', '}'], ]], ['ForStatement', [ ['for', '(', 'let', 'Expression', ';', 'Expression', ';', 'Expression', ')', 'Statement'], ['for', '(', 'var', 'Expression', ';', 'Expression', ';', 'Expression', ')', 'Statement'], ['for', '(', 'Expression', ';', 'Expression', ';', 'Expression', ')', 'Statement'] ]], ['BreakStatement', [ ['break', ';'] ]], /** Added: End */ ['Statement', [['ExpressionStatement'], ['IfStatement'], ['ForStatement'], ['Declaration'], ['BlockStatement'], ['BreakStatement']]], ['StatementListItem', [['Statement'], ['Declaration']]], ['StatementList', [['StatementListItem'], ['StatementList', 'StatementListItem']]], /** Added */ ['Program', [['StatementList']]], ]) const initialState = { Program: { EOF: { $end: true } } } it('Test BreakStatement', () => { evaluate(` for(let i = 1; i < 10; i++) { if (i === 5) break; } `, map, initialState) expect(globalEnv.get('i')).toBe(5) }) }) })