diff --git a/src/Interp/ExpressionInterp.js b/src/Interp/ExpressionInterp.js index 7da78f8..526ac86 100644 --- a/src/Interp/ExpressionInterp.js +++ b/src/Interp/ExpressionInterp.js @@ -12,6 +12,8 @@ import { applyClosure, } from '../Closure'; +import Options from '../Options'; + import { interp as statementInterp } from './StatementInterp'; const interp = (exp, env) => { @@ -52,7 +54,7 @@ const interp = (exp, env) => { const closure = interp(callee, env); const vals = rawArgs.map((obj) => interp(obj, env)); - return applyClosure(interp, closure, vals, env); + return applyClosure(interp, closure, vals, env, Options.isLexical); } case 'UnaryExpression': { diff --git a/src/Interp/__tests__/ExpressionInterp-test.js b/src/Interp/__tests__/ExpressionInterp-test.js index 3cc0a06..efe9964 100644 --- a/src/Interp/__tests__/ExpressionInterp-test.js +++ b/src/Interp/__tests__/ExpressionInterp-test.js @@ -1,8 +1,11 @@ 'use strict'; jest.unmock('../../Parser') - .unmock('../ExpressionInterp').unmock('../StatementInterp') - .unmock('../../Environment').unmock('../../Closure'); + .unmock('../ExpressionInterp') + .unmock('../StatementInterp') + .unmock('../../Environment') + .unmock('../../Closure') + .unmock('../../Options'); const { interp } = require('../ExpressionInterp'); const { parse } = require('../../Parser'); @@ -11,7 +14,8 @@ const { extendEnv, } = require('../../Environment'); -import { makeClosure } from '../../Closure'; +const { makeClosure } = require('../../Closure'); +const Options = require('../../Options').default; const parseAndgetExp = (code) => parse(code).body[0].expression; @@ -205,6 +209,34 @@ describe('Interp', () => { })()); }); + it('should support dynamic scope', () => { + Options.isLexical = false; + + expect(interpExp(`(() => { + const adder = (x) => (y) => x + y; + const x = 100; + const add3ButActuallyAdd100 = adder(3); + return add3ButActuallyAdd100(5); + })()`)).toBe(100 + 5); + + expect(interpExp(`(() => { + const adder = (x) => (y) => x + y; + const x = 100; + const add3ButActuallyAdd100 = adder(3); + return add3ButActuallyAdd100(5); + })()`)).toBe(100 + 5); + + expect(interpExp(`(() => { + const x = 100; + const y = 200; + const adder = (x) => (y) => x + y; + const add3 = adder(3); + return add3(39); + })()`)).toBe(100 + 39); + + Options.isLexical = true; + }); + // it('IfStatement', () => { // expect(interpExp(`(() => { diff --git a/src/Options.js b/src/Options.js new file mode 100644 index 0000000..5a311b7 --- /dev/null +++ b/src/Options.js @@ -0,0 +1,9 @@ +/* + * This guy allows us to toggle the lexical/dynamic behavior at runtime. + */ + +const Options = { + isLexical: true, +}; + +export default Options;