Skip to content

Commit

Permalink
WIP build tools
Browse files Browse the repository at this point in the history
  • Loading branch information
keyz committed Apr 17, 2016
1 parent 03763c4 commit 105ae56
Show file tree
Hide file tree
Showing 9 changed files with 57 additions and 26 deletions.
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,5 @@ node_modules
.node_repl_history

.DS_Store
lib
dist

.nyc_output
20 changes: 20 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
language: node_js

node_js:
- 5.10.1

compiler: clang-3.6

env:
- CXX=clang-3.6

addons:
apt:
sources:
- llvm-toolchain-precise-3.6
- ubuntu-toolchain-r-test
packages:
- clang-3.6
- g++-4.8

after_success: npm run coveralls
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# trivial-js-interpreter
# The Super Tiny _Interpreter_
Let's explain what a **closure** is by writing a JavaScript interpreter in JavaScript.
30 changes: 20 additions & 10 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,32 +1,39 @@
{
"name": "trivial-js-interpreter",
"name": "the-super-tiny-interpreter",
"version": "1.0.0",
"description": "",
"main": "index.js",
"description": "Explain what a closure is by writing a JavaScript interpreter in JavaScript",
"main": "lib/index.js",
"scripts": {
"clean": "rimraf lib coverage",
"build:babel": "babel src --out-dir lib --ignore __tests__",
"test": "jest",
"lint": "eslint src"
"coverage": "jest --coverage",
"coveralls": "npm run coverage && cat ./coverage/lcov.info | coveralls",
"lint": "eslint src",
"postinstall": "npm run clean && npm run lint && npm test && npm run coveralls && npm run build:babel"
},
"repository": {
"type": "git",
"url": "git+https://github.com/keyanzhang/trivial-js-interpreter.git"
"url": "git+https://github.com/keyanzhang/the-super-tiny-interpreter.git"
},
"keywords": [],
"author": "Keyan Zhang <[email protected]> (http:https://keya.nz)",
"license": "MIT",
"bugs": {
"url": "https://github.com/keyanzhang/trivial-js-interpreter/issues"
"url": "https://github.com/keyanzhang/the-super-tiny-interpreter/issues"
},
"homepage": "https://github.com/keyanzhang/trivial-js-interpreter#readme",
"homepage": "https://github.com/keyanzhang/the-super-tiny-interpreter#readme",
"devDependencies": {
"babel-cli": "^6.7.5",
"babel-core": "^6.7.6",
"babel-eslint": "^6.0.2",
"babel-jest": "^11.0.0",
"babel-jest": "^11.0.1",
"babel-plugin-transform-flow-strip-types": "^6.7.0",
"babel-polyfill": "^6.7.4",
"babel-preset-es2015": "^6.6.0",
"babel-preset-stage-0": "^6.5.0",
"eslint": "^2.7.0",
"coveralls": "^2.11.9",
"eslint": "^2.8.0",
"eslint-config-airbnb": "^7.0.0",
"eslint-plugin-babel": "^3.2.0",
"jest": "^0.1.40",
Expand All @@ -35,14 +42,17 @@
"dependencies": {
"babylon": "^6.7.0",
"fbjs": "^0.8.0",
"immutable": "^3.7.6"
"immutable": "^3.8.0"
},
"jest": {
"unmockedModulePathPatterns": [
"<rootDir>/node_modules/babylon",
"<rootDir>/node_modules/immutable",
"<rootDir>/node_modules/fbjs",
"<rootDir>/src/utils"
],
"testPathDirs": [
"<rootDir>/src"
]
}
}
8 changes: 5 additions & 3 deletions samples/adder.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
const adder = (x) => (y) => x + y;
const add3 = adder(3);
add3(39);
(() => {
const adder = (x) => (y) => x + y;
const add3 = adder(3);
return add3(39);
})();
10 changes: 5 additions & 5 deletions src/Closure.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ const makeClosure = (params, body, defineTimeEnv) => ({
* This is a little bit tricky and please feel free to ignore this part.
*
* Our arrow functions can be recursively defined. For instance,
* in `const fact = (x) => (x < 2 ? 1 : x * fact(x - 1));`:
* in `const fact = (x) => (x < 2 ? 1 : x * fact(x - 1));`
* we need to reference `fact` in the body of `fact` itself.
*
* If we create a "normal" closure for the function above, the `fact` in the body
* will be unbound.
* If we create a "normal" closure for the function above, the `fact` (pun intended)
* in the body will be unbound.
*
* A quick fix is to update the environment with a reference to the closure itself.
* For more information, check http:https://www.cs.indiana.edu/~dyb/papers/fixing-letrec.pdf
Expand Down Expand Up @@ -54,13 +54,13 @@ const applyClosure = (evaluator, closure, vals, callTimeEnv, isLexical = true) =
if (!isLexical) {
// Dynamic scope.
// `callTimeEnv` is the latest binding information.
const envForTheEvaluator = batchExtendEnv(params, vals, callTimeEnv);
const envForTheEvaluator = batchExtendEnv(params, vals, /* HEY LOOK AT ME → */ callTimeEnv);
return evaluator(body, envForTheEvaluator);
}

// Lexical closure yo.
// `defineTimeEnv` is the one that got extracted from the closure.
const envForTheEvaluator = batchExtendEnv(params, vals, defineTimeEnv);
const envForTheEvaluator = batchExtendEnv(params, vals, /* HEY LOOK AT ME → */ defineTimeEnv);
return evaluator(body, envForTheEvaluator);
};

Expand Down
4 changes: 2 additions & 2 deletions src/Interp/StatementInterp.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ const interp = (exp, env) => {

if (init.type === 'ArrowFunctionExpression') {
/*
* TL;DR: it could be a letrec!
* TL;DR: it could be a `letrec`!
*
* A better way is to do a static analysis and to see whether the RHS
* actually contains recursive definitions.
Expand All @@ -68,7 +68,7 @@ const interp = (exp, env) => {
// case 'IfStatement': {
// const { alternate, consequent, test } = currentExp;
// const testVal = expInterp(test, currentEnv);
// return currentExp;
//
// if (testVal) {
//
// }
Expand Down
4 changes: 2 additions & 2 deletions src/Parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Writing a parser is way beyond the scope of this interpreter.
* Let's just borrow it from babel.
*/
import { parse as bParse } from 'babylon';
import { parse as babylonParse } from 'babylon';
import { isObject, mapFilterObject } from './utils';

const defaultOptions = {
Expand Down Expand Up @@ -44,7 +44,7 @@ const cleanupAst = (target) => {
};

const parse = (code, options = defaultOptions) => {
const originalAst = bParse(code, options);
const originalAst = babylonParse(code, options);
return cleanupAst(originalAst).program; // we don't care about `File` type, too
};

Expand Down
2 changes: 1 addition & 1 deletion src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const mapFilterObject = (obj, fn) => {

keys.forEach((key) => {
const val = obj[key];
const fnResult = fn(val, key); // `fn` return `false` for removal, or a tuple of `[ key, val ]`
const fnResult = fn(val, key); // `fn` returns `false` for removal, or a tuple of `[ key, val ]`
if (fnResult) {
const [ newKey, newVal ] = fnResult;
result[newKey] = newVal;
Expand Down

0 comments on commit 105ae56

Please sign in to comment.