├── .gitignore ├── .travis.yml ├── README.md ├── bin └── js2cpp ├── compile-and-run.sh ├── demo ├── demo1.cpp ├── demo1.js ├── demo2.cpp ├── demo2.js ├── demoargv.cpp ├── demoargv.js ├── demoarr.cpp ├── demoarr.js ├── demobeer.cpp ├── demobeer.js ├── demomath.cpp ├── demomath.js ├── demoqueue.cpp ├── demoqueue.js ├── demosettimeout.cpp └── demosettimeout.js ├── include ├── js2c.h └── js2c │ ├── console.h │ ├── process.h │ └── string.h ├── lib ├── cli.coffee ├── cpp-types.coffee ├── fake-classes.coffee ├── format.coffee ├── gen.coffee ├── index.coffee ├── standard-library-objects.json ├── tern-plugins.coffee ├── transforms │ ├── env.coffee │ └── index.coffee └── yell.js ├── package-lock.json ├── package.json ├── test ├── index.coffee ├── prepare.coffee └── some.js ├── test_compilee.js ├── transpile-and-compile-and-run.sh └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | deps 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | dist: trusty 3 | node_js: 4 | - 11 5 | cache: 6 | directories: 7 | - node_modules 8 | before_install: 9 | - export HOMEBREW_FORCE_VENDOR_RUBY=1 10 | - sh -c "$(curl -fsSL https://raw.githubusercontent.com/Linuxbrew/install/master/install.sh)" 11 | - brew install libuv-dev gcc 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/fabiosantoscode/js2cpp.svg?branch=master)](https://travis-ci.org/fabiosantoscode/js2cpp) 2 | 3 | # What's this? 4 | 5 | It's the product of the crazy idea of using the very excellent tern.js project to figure out the types of things and use them! 6 | 7 | js2cpp doesn't have a garbage collector yet. But it is usable and can run some JavaScript code as is! 8 | 9 | # How can I use it? 10 | 11 | Yeah, it actually does some things. This is how js2cpp handles strings: 12 | 13 | $ echo '"lol" + "lel"' | bin/js2cpp 14 | #include "js2c.h" 15 | #include 16 | 17 | String("lol") + String("lel"); 18 | 19 | And here's console.log! 20 | 21 | $ echo 'console.log(1, 2, "3")' | bin/js2cpp 22 | #include "js2c.h" 23 | #include 24 | 25 | console.log(1, 2, String("3")); 26 | 27 | It works because there's a "console" instance of a "Console" class with a variadic "log" function. 28 | 29 | Here is tern.js figuring out a couple of types. 30 | 31 | $ echo 'var aNumber = 1; var aString = "1";' | bin/js2cpp 32 | #include "js2c.h" 33 | #include 34 | 35 | double aNumber = 1; 36 | String aString = String("1"); 37 | 38 | # How do I run this? (Usage) 39 | 40 | ``` 41 | ~ ♥ bin/js2cpp -h 42 | Usage: js2cpp --run (run javascript from stdin) 43 | Usage: js2cpp --run filename.js 44 | Usage: js2cpp (compile from stdin) 45 | Usage: js2cpp filename.js (compile) 46 | 47 | environment variables: 48 | ~ $ RUN_VALGRIND=1 js2cpp --run ... - Run the compiled program with `valgrind` 49 | ~ $ GPP_BINARY=/path/to/g++ js2cpp ... - Select what g++ binary to use (defaults to `g++`) 50 | ``` 51 | 52 | * First, you need to update your compiler to a version that supports C++14. Your system probably already has this. If not, install linuxbrew or homebrew and just run `brew install gcc` 53 | * Then, clone this repo and run `npm install` 54 | * Optionally `npm test` just to make sure it works on your machine ;) If it doesn't please make an issue about it and I'll try to look into it. It tries to use the `g++` binary from your PATH. If you want to use another binary specify it with the `GPP_BINARY` environment variable, like so: `GPP_BINARY=g++-5 npm test`. 55 | * To compile some javascript, run `./bin/js2cpp < your-javascript.js > your-cee-plus-plus.cpp`. 56 | * To run it, run `./bin/js2cpp --run your-javascript.js`, or `./bin/js2cpp --run`, type in javascript, then press ^D when you're done. The `GPP_BINARY` variable also applies here. 57 | 58 | # Dumbjs 59 | 60 | js2cpp is kind of a frontend to fabiosantoscode/dumbjs, a javascript simplifier. It turns javascript that looks like this: 61 | 62 | ``` 63 | function foo(x) { 64 | x++ 65 | return function () { return x } 66 | } 67 | console.log(foo(0)()) 68 | ``` 69 | 70 | Into something like this: 71 | 72 | ``` 73 | var _flatten_0 = function (_closure) { 74 | return _closure.x 75 | } 76 | var foo = function (x) { 77 | var _closure_0 = {} 78 | _closure_0.x = x 79 | _closure_0.x++ 80 | return BIND(_flatten_0, _closure_0) 81 | } 82 | var main = function () { 83 | console.log(foo(0)()) 84 | } 85 | ``` 86 | (the BIND function must be defined elsewhere, in this case in js2cpp) 87 | 88 | Its features are closure simulation, main-ification (put stuff in a main() function), function de-nesting, and more will come. 89 | 90 | Since all of it is a much simpler form of javascript, it takes a huge weight off the shoulders of js2cpp and makes sure its code remains (somewhat) understandable by not mixing up concerns. 91 | 92 | This also means that you can use dumbjs to transpile javascript to other languages. Most of its features are switchable, because not every transpilation target language will need you to do things like wrapping things in a main() function or simulating closures. 93 | 94 | 95 | # Roadmap 96 | 97 | (unordered) 98 | 99 | The main objective of this project is to implement at least 80% of the parts of javascript you use every day. 100 | 101 | This means that, like a lot of npm modules which accidentally work in the browser when browserified, a lot of npm modules should accidentally work natively when js2cpp-ified. 102 | 103 | All of the following features may be implemented in dumbjs, in this project, or in both at the same time, depending on whether they apply to each project. 104 | 105 | - Plug in the [Boehm-Demers-Weiser conservative garbage collector](http://www.hboehm.info/gc/) (which works in C and C++, it seems!) 106 | - Rewrite this and dumbjs in pure javascript 107 | - Implement `arguments` and `this` 108 | - Import the most common modules from node core (mostly depends on the above), rewrite parts of them in C++ if necessary. 109 | - Implement promises 110 | - Implement boxed types, for those variables which can have 2 or more types 111 | - Implement `JSON.parse()` and `JSON.stringify()` (depends on the above) 112 | - Implement libuv bindings and shim, fake and steal node's IO APIs 113 | - Implement ES5-style classes (possibly by turning them into ES6-style classes first) 114 | - Implement or fake commonJS (`require()`, `module.exports`) modules. 115 | - Implement several javascript APIs such as Date, Symbol, and Array (which currently is simply a C++ `std::vector`). 116 | 117 | # Hey this is AMAZING I WANNA FORK IT SELL IT OR WHATEVER WHAT IS TEH LICENSSSS 118 | 119 | Just have fun with it! WTFPL 120 | 121 | -------------------------------------------------------------------------------- /bin/js2cpp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | require('coffee-script/register') 4 | var fs = require('fs') 5 | var cli = require('../lib/cli') 6 | var path = require('path') 7 | 8 | var input = process.stdin; 9 | var output = process.stdout; 10 | 11 | if (process.argv[2] == '-h' || process.argv[2] == '--help') { 12 | console.log('Usage: js2cpp --run (run javascript from stdin)') 13 | console.log('Usage: js2cpp --run filename.js') 14 | console.log('Usage: js2cpp (compile from stdin)') 15 | console.log('Usage: js2cpp filename.js (compile)') 16 | console.log('') 17 | console.log('environment variables:') 18 | console.log(' ~ $ RUN_VALGRIND=1 js2cpp --run ... - Run the compiled program with `valgrind`') 19 | console.log(' ~ $ GPP_BINARY=/path/to/g++ js2cpp ... - Select what g++ binary to use (defaults to `g++`)') 20 | } else if (process.argv[2] == '--run') { 21 | var args = process.argv.slice(3) 22 | if (process.argv[3] && process.argv[3] !== '--') { 23 | input = fs.createReadStream(process.argv[3]) 24 | args = process.argv.slice(4) 25 | } else if (process.argv[3] === '--') { 26 | input = process.stdin; 27 | args = process.argv.slice(4) 28 | } 29 | cli.run(input, args).then(function (programRun) { 30 | process.exit(programRun.status_code || 0) 31 | }, function (err) { 32 | if (err.status_code) { 33 | return process.exit(err.status_code) 34 | } 35 | console.error('Error compiling') 36 | onError(err) 37 | }) 38 | } else { 39 | if (process.argv[2]) 40 | input = fs.createReadStream(process.argv[2]) 41 | if (process.argv[3]) 42 | output = fs.createWriteStream(process.argv[3]) 43 | cli(input, output).catch(onError) 44 | } 45 | 46 | function onError (err) { 47 | if (err) { 48 | console.error(err.stack || err) 49 | process.exit(1) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /compile-and-run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | echo $1 3 | 4 | g++ -std=c++14 -Wall -Werror -O3 -I gc-7.2/include/ -I include/ -lrt -lpthread $1 && ./a.out 5 | 6 | -------------------------------------------------------------------------------- /demo/demo1.cpp: -------------------------------------------------------------------------------- 1 | #include "js2c.h" 2 | #include 3 | 4 | struct FakeClass_0 { 5 | double y; 6 | std::string z; 7 | FakeClass_0(){} 8 | }; 9 | 10 | 11 | 12 | int main () { 13 | js2cpp_init_libuv(); 14 | FakeClass_0 * x = new FakeClass_0(); 15 | x->y = -1; 16 | x->z = std::string("Hello c++!"); 17 | console.log(x->z, x->y); 18 | js2cpp_run_libuv(); 19 | } 20 | -------------------------------------------------------------------------------- /demo/demo1.js: -------------------------------------------------------------------------------- 1 | var x = {} 2 | x.y = -1 3 | x.z = "Hello c++!" 4 | console.log(x.z, x.y) 5 | -------------------------------------------------------------------------------- /demo/demo2.cpp: -------------------------------------------------------------------------------- 1 | #include "js2c.h" 2 | #include 3 | 4 | struct FakeClass_0 { 5 | double start; 6 | FakeClass_0(){} 7 | }; 8 | 9 | 10 | struct _flatten_incrementor { 11 | FakeClass_0 * _closure; 12 | _flatten_incrementor(FakeClass_0 * _closure):_closure(_closure) { } 13 | double operator() (); 14 | }; 15 | struct _flatten_incrementor; 16 | struct _flatten_demo; 17 | struct FakeClass_1 { 18 | _flatten_demo * demo; 19 | std::function<_flatten_incrementor * (double)> inc; 20 | FakeClass_1(){} 21 | }; 22 | 23 | 24 | struct _flatten_demo { 25 | FakeClass_1 * _closure; 26 | _flatten_demo(FakeClass_1 * _closure):_closure(_closure) { } 27 | void operator() (); 28 | }; 29 | _flatten_incrementor * _flatten_inc (double start); 30 | 31 | double _flatten_incrementor::operator() () { 32 | return _closure->start++; 33 | } 34 | void _flatten_demo::operator() () { 35 | _flatten_incrementor * inc0 = _closure->inc(0); 36 | console.log((*inc0)()); 37 | console.log((*inc0)()); 38 | console.log((*inc0)()); 39 | } 40 | _flatten_incrementor * _flatten_inc (double start) { 41 | FakeClass_0 * _closure_1 = new FakeClass_0(); 42 | _closure_1->start = start; 43 | return new _flatten_incrementor(_closure_1); 44 | } 45 | int main () { 46 | FakeClass_1 * _closure_0 = new FakeClass_1(); 47 | _closure_0->inc = _flatten_inc; 48 | _closure_0->demo = new _flatten_demo(_closure_0); 49 | js2cpp_init_libuv(); 50 | (*_closure_0->demo)(); 51 | js2cpp_run_libuv(); 52 | } 53 | -------------------------------------------------------------------------------- /demo/demo2.js: -------------------------------------------------------------------------------- 1 | 2 | function inc(start) { 3 | return function incrementor() { 4 | return start++ 5 | } 6 | } 7 | 8 | function demo() { 9 | var inc0 = inc(0) 10 | 11 | console.log(inc0()) 12 | console.log(inc0()) 13 | console.log(inc0()) 14 | } 15 | 16 | demo() 17 | -------------------------------------------------------------------------------- /demo/demoargv.cpp: -------------------------------------------------------------------------------- 1 | #include "js2c.h" 2 | #include 3 | 4 | 5 | 6 | int main (int argc, char* argv[]) { 7 | js2cpp_init_libuv(); 8 | js2cpp_init_argv(argc, argv); 9 | console.log(std::string("process.argv.length:"), process.argv->length); 10 | console.log(std::string("process.argv:"), process.argv); 11 | js2cpp_run_libuv(); 12 | } 13 | -------------------------------------------------------------------------------- /demo/demoargv.js: -------------------------------------------------------------------------------- 1 | 2 | console.log('process.argv.length:', process.argv.length) 3 | console.log('process.argv:', process.argv) 4 | 5 | -------------------------------------------------------------------------------- /demo/demoarr.cpp: -------------------------------------------------------------------------------- 1 | #include "js2c.h" 2 | #include 3 | 4 | 5 | 6 | 7 | 8 | int main (int argc, char* argv[]) { 9 | js2cpp_init_libuv(); 10 | js2cpp_init_argv(argc, argv); 11 | Array * x; 12 | x = (new Array({ 1.0f, 2.0f })); 13 | console.log(x, (new Array({ 1.0f, 2.0f })), (*x)[0.0f], (*(new Array({ 1.0f, 2.0f })))[0.0f]); 14 | Array * y = (new Array({ std::string("lel") })); 15 | console.log(y, (*y)[0.0f]); 16 | y->push(std::string("foo")); 17 | console.log(y); 18 | js2cpp_run_libuv(); 19 | } 20 | -------------------------------------------------------------------------------- /demo/demoarr.js: -------------------------------------------------------------------------------- 1 | 2 | var x 3 | 4 | x = [ 1, 2 ] 5 | 6 | console.log(x, [ 1, 2 ], x[0], [ 1, 2 ][0]) 7 | 8 | var y = [ 'lel' ]; 9 | 10 | console.log(y, y[0]); 11 | 12 | y.push('foo') 13 | 14 | console.log(y) 15 | 16 | -------------------------------------------------------------------------------- /demo/demobeer.cpp: -------------------------------------------------------------------------------- 1 | #include "js2c.h" 2 | #include 3 | 4 | 5 | 6 | int main () { 7 | js2cpp_init_libuv(); 8 | for (double i = 99; i > 0; i--) { 9 | double j = i - 1; 10 | std::string icase; 11 | std::string jcase; 12 | if (i != 1) { 13 | icase = std::string("bottles"); 14 | } else { 15 | icase = std::string("bottle"); 16 | } 17 | if (j != 1) { 18 | jcase = std::string("bottles"); 19 | } else { 20 | jcase = std::string("bottle"); 21 | } 22 | console.log(String(i) + std::string(" ") + icase + std::string(" of beer on the wall,")); 23 | console.log(String(i) + std::string(" ") + icase + std::string(" of beer,")); 24 | console.log(std::string("Take 1 down, pass it around,")); 25 | if (j != 0) { 26 | console.log(String(j) + std::string(" ") + jcase + std::string(" of beer on the wall.")); 27 | } else { 28 | console.log(std::string("No more bottles of beer on the wall!")); 29 | } 30 | } 31 | js2cpp_run_libuv(); 32 | } 33 | -------------------------------------------------------------------------------- /demo/demobeer.js: -------------------------------------------------------------------------------- 1 | for (var i = 99 ; i > 0 ; i--) { 2 | var j = i - 1; 3 | var icase 4 | var jcase 5 | if (i != 1) { 6 | icase = "bottles"; 7 | } else { 8 | icase = "bottle"; 9 | } 10 | if (j != 1) { 11 | jcase = "bottles"; 12 | } else { 13 | jcase = "bottle"; 14 | } 15 | console.log(String(i) + " " + icase + " of beer on the wall,"); 16 | console.log(String(i) + " " + icase + " of beer,"); 17 | console.log("Take 1 down, pass it around,"); 18 | if (j != 0) { 19 | console.log(String(j) + " " + jcase + " of beer on the wall."); 20 | } else { 21 | console.log("No more bottles of beer on the wall!"); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /demo/demomath.cpp: -------------------------------------------------------------------------------- 1 | #include "js2c.h" 2 | #include 3 | 4 | 5 | 6 | int main () { 7 | js2cpp_init_libuv(); 8 | console.log(std::string("Math.floor(Math.PI * 100) / 100:"), Math.floor(Math.PI * 100) / 100); 9 | console.log(std::string("Math.imul(3, 2):"), Math.imul(3, 2)); 10 | console.log(std::string("Math.pow(2, 10):"), Math.pow(2, 10)); 11 | console.log(std::string("Math.log(Math.E):"), Math.log(Math.E)); 12 | console.log(std::string("Math.ceil(Math.LOG10E):"), Math.ceil(Math.LOG10E)); 13 | console.log(std::string("Math.sin(90):"), Math.sin(90)); 14 | console.log(std::string("Math.sqrt(4):"), Math.sqrt(4)); 15 | console.log(std::string("Math.tan(45):"), Math.tan(45)); 16 | console.log(std::string("Math.trunc(2.000001):"), Math.trunc(2.000001)); 17 | console.log(std::string("Math.max(1):"), Math.max(1)); 18 | console.log(std::string("Math.max(1, 2):"), Math.max(1, 2)); 19 | console.log(std::string("Math.max(1, 2, -1):"), Math.max(1, 2, -1)); 20 | console.log(std::string("Math.max(1):"), Math.max(1)); 21 | console.log(std::string("Math.max(1, 2):"), Math.max(1, 2)); 22 | console.log(std::string("Math.max(1, 2, -1):"), Math.max(1, 2, -1)); 23 | console.log(std::string("Math.random() != Math.random()"), Math.random() != Math.random()); 24 | console.log(std::string("Math.random() <= 1 && Math.random() >= 0"), Math.random() <= 1 && Math.random() >= 0); 25 | console.log(std::string("NaN"), NaN); 26 | console.log(std::string("isNaN(NaN)"), isNaN(NaN)); 27 | js2cpp_run_libuv(); 28 | } 29 | -------------------------------------------------------------------------------- /demo/demomath.js: -------------------------------------------------------------------------------- 1 | console.log('Math.floor(Math.PI * 100) / 100:', Math.floor(Math.PI * 100) / 100) 2 | console.log('Math.imul(3, 2):', Math.imul(3, 2)) 3 | console.log('Math.pow(2, 10):', Math.pow(2, 10)) 4 | console.log('Math.log(Math.E):', Math.log(Math.E)) 5 | console.log('Math.ceil(Math.LOG10E):', Math.ceil(Math.LOG10E)) 6 | console.log('Math.sin(90):', Math.sin(90)) 7 | console.log('Math.sqrt(4):', Math.sqrt(4)) 8 | console.log('Math.tan(45):', Math.tan(45)) 9 | console.log('Math.trunc(2.000001):', Math.trunc(2.000001)) 10 | console.log('Math.max(1):', Math.max(1)) 11 | console.log('Math.max(1, 2):', Math.max(1, 2)) 12 | console.log('Math.max(1, 2, -1):', Math.max(1, 2, -1)) 13 | console.log('Math.max(1):', Math.max(1)) 14 | console.log('Math.max(1, 2):', Math.max(1, 2)) 15 | console.log('Math.max(1, 2, -1):', Math.max(1, 2, -1)) 16 | console.log('Math.random() != Math.random()', Math.random() != Math.random()) 17 | console.log('Math.random() <= 1 && Math.random() >= 0', Math.random() <= 1 && Math.random() >= 0) 18 | console.log('NaN', NaN) 19 | console.log('isNaN(NaN)', isNaN(NaN)) 20 | -------------------------------------------------------------------------------- /demo/demoqueue.cpp: -------------------------------------------------------------------------------- 1 | #include "js2c.h" 2 | #include 3 | 4 | struct FakeClass_0; 5 | 6 | void _flatten_3 (); 7 | void _flatten_2 (); 8 | void _flatten_1 (); 9 | void _flatten_0 (); 10 | struct FakeClass_0 { 11 | 12 | FakeClass_0(){} 13 | }; 14 | 15 | 16 | 17 | void _flatten_3 () { 18 | console.log(std::string("Called zeroth item in queue")); 19 | } 20 | void _flatten_2 () { 21 | console.log(std::string("Called second item in queue")); 22 | } 23 | void _flatten_1 () { 24 | console.log(std::string("Called first item in queue with")); 25 | } 26 | void _flatten_0 () { 27 | } 28 | int main (int argc, char* argv[]) { 29 | FakeClass_0 * _closure_0 = new FakeClass_0(); 30 | js2cpp_init_libuv(); 31 | js2cpp_init_argv(argc, argv); 32 | Array> * queue = (new Array>({ _flatten_0 })); 33 | queue->push(_flatten_1); 34 | queue->push(_flatten_2); 35 | queue->unshift(_flatten_3); 36 | while (queue->length) { 37 | queue->pop()(); 38 | } 39 | js2cpp_run_libuv(); 40 | } 41 | -------------------------------------------------------------------------------- /demo/demoqueue.js: -------------------------------------------------------------------------------- 1 | 2 | var queue = [ function() {} ]; 3 | 4 | queue.push(function () { 5 | console.log('Called first item in queue with') 6 | }) 7 | 8 | queue.push(function () { 9 | console.log('Called second item in queue') 10 | }) 11 | 12 | queue.unshift(function () { 13 | console.log('Called zeroth item in queue') 14 | }) 15 | 16 | while (queue.length) { 17 | queue.pop()() 18 | } 19 | 20 | -------------------------------------------------------------------------------- /demo/demosettimeout.cpp: -------------------------------------------------------------------------------- 1 | #include "js2c.h" 2 | #include 3 | 4 | struct FakeClass_0 { 5 | double count; 6 | double interval; 7 | FakeClass_0(){} 8 | }; 9 | 10 | 11 | struct _flatten_4 { 12 | FakeClass_0 * _closure; 13 | _flatten_4(FakeClass_0 * _closure):_closure(_closure) { } 14 | void operator() (); 15 | }; 16 | void _flatten_3 (); 17 | void _flatten_2 (); 18 | struct FakeClass_1 { 19 | std::function proceed; 20 | double thatWhichShallNotBeRun; 21 | double thatWhichShallNotBeRun2; 22 | FakeClass_1(){} 23 | }; 24 | 25 | 26 | struct FakeClass_2 { 27 | FakeClass_1 * _closure_0; 28 | FakeClass_2(){} 29 | }; 30 | 31 | 32 | struct _flatten_1 { 33 | FakeClass_1 * _closure; 34 | _flatten_1(FakeClass_1 * _closure):_closure(_closure) { } 35 | void operator() (); 36 | }; 37 | struct _flatten_0 { 38 | FakeClass_2 * _closure; 39 | _flatten_0(FakeClass_2 * _closure):_closure(_closure) { } 40 | void operator() (); 41 | }; 42 | void _flatten_proceed (); 43 | 44 | void _flatten_4::operator() () { 45 | console.log(_closure->count); 46 | if (!--_closure->count) 47 | clearInterval(_closure->interval); 48 | } 49 | void _flatten_3 () { 50 | console.log(std::string("fifteen!")); 51 | } 52 | void _flatten_2 () { 53 | console.log(std::string("fifteen!")); 54 | } 55 | void _flatten_1::operator() () { 56 | FakeClass_2 * _closure_1 = new FakeClass_2(); 57 | _closure_1->_closure_0 = _closure; 58 | console.log(std::string("two")); 59 | clearTimeout(_closure->thatWhichShallNotBeRun); 60 | clearImmediate(_closure->thatWhichShallNotBeRun2); 61 | setTimeout(new _flatten_0(_closure_1), 500); 62 | } 63 | void _flatten_0::operator() () { 64 | console.log(std::string("three")); 65 | _closure->_closure_0->proceed(); 66 | } 67 | void _flatten_proceed () { 68 | FakeClass_0 * _closure_2 = new FakeClass_0(); 69 | _closure_2->count = 3; 70 | _closure_2->interval = setInterval(new _flatten_4(_closure_2), 1000); 71 | console.log(std::string("counting down using interval number"), _closure_2->interval); 72 | } 73 | int main () { 74 | FakeClass_1 * _closure_0 = new FakeClass_1(); 75 | _closure_0->proceed = _flatten_proceed; 76 | js2cpp_init_libuv(); 77 | process.nextTick(new _flatten_1(_closure_0)); 78 | console.log(std::string("one")); 79 | _closure_0->thatWhichShallNotBeRun = setTimeout(_flatten_2); 80 | _closure_0->thatWhichShallNotBeRun2 = setImmediate(_flatten_3); 81 | js2cpp_run_libuv(); 82 | } 83 | -------------------------------------------------------------------------------- /demo/demosettimeout.js: -------------------------------------------------------------------------------- 1 | 2 | process.nextTick(function() { 3 | console.log('two'); 4 | clearTimeout(thatWhichShallNotBeRun); 5 | clearImmediate(thatWhichShallNotBeRun2); 6 | setTimeout(function () { 7 | console.log('three') 8 | proceed() 9 | }, 500) 10 | }) 11 | 12 | console.log('one') 13 | 14 | var thatWhichShallNotBeRun = setTimeout(function () { 15 | console.log('fifteen!') 16 | }); 17 | var thatWhichShallNotBeRun2 = setImmediate(function () { 18 | console.log('fifteen!') 19 | }); 20 | 21 | function proceed() { 22 | var count = 3; 23 | var interval = setInterval(function() { 24 | console.log(count) 25 | if (!--count) clearInterval(interval) 26 | }, 1000) 27 | console.log('counting down using interval number', interval) 28 | } 29 | 30 | -------------------------------------------------------------------------------- /include/js2c.h: -------------------------------------------------------------------------------- 1 | #include "stdio.h" 2 | #include "math.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "uv.h" 13 | #define Infinity INFINITY 14 | #define NaN NAN 15 | // Temporary fix for how dumbjs transpiles commonJS modules. 16 | // Should be done when there is an Undefinable type. 17 | #define undefined nullptr 18 | 19 | struct Console; 20 | 21 | namespace dumbjs_number_convert { 22 | double parse(std::string n, int base) { 23 | return (double) strtol(n.c_str(), NULL, base); 24 | } 25 | std::string stringify(double n, int base) { 26 | if (isnan(n)) { 27 | return std::string("NaN"); 28 | } 29 | if (n == (int) n) { 30 | return std::to_string((int) n); 31 | } 32 | std::ostringstream stream; 33 | stream << std::fixed << std::setprecision(15) << n; 34 | return stream.str(); 35 | } 36 | }; 37 | 38 | template 39 | struct Array { 40 | friend Console; 41 | private: 42 | std::vector vec; 43 | template 44 | void from_arg_pack(T first, Args... rest) { 45 | from_arg_pack(first); 46 | from_arg_pack(rest...); 47 | } 48 | void from_arg_pack(T only) { 49 | push(only); 50 | } 51 | void from_arg_pack() { } 52 | public: 53 | double length; 54 | Array() { 55 | vec = std::vector(); 56 | length = 0; 57 | } 58 | Array(std::initializer_list init) { 59 | vec = std::vector(); 60 | length = 0; 61 | for (auto iter = init.begin(); 62 | iter != init.end(); 63 | iter++) { 64 | push(*iter); 65 | } 66 | } 67 | Array(std::vector & some_vec) { 68 | vec = some_vec; 69 | length = vec.size(); 70 | } 71 | template 72 | Array(Args... args) { 73 | length = 0; 74 | vec = std::vector(); 75 | from_arg_pack(args...); 76 | } 77 | T operator[] (double index) { 78 | int ind = index; 79 | if (ind < 0 || ind >= vec.size()) { 80 | return T(); 81 | } 82 | return vec[ind]; 83 | } 84 | double push(T value) { 85 | vec.push_back(value); 86 | length += 1; 87 | return length; 88 | } 89 | T pop() { 90 | length -= 1; 91 | T last_value = vec[length]; 92 | vec.pop_back(); 93 | return last_value; 94 | } 95 | double unshift(T value) { 96 | length += 1; 97 | vec.insert(vec.begin(), value); 98 | return length; 99 | } 100 | Array * concat(Array * other) { 101 | Array *ret = new Array(); 102 | for (int i = 0; i < vec.size(); i++) { 103 | ret->push(vec[i]); 104 | } 105 | for (int i = 0; i < other->vec.size(); i++) { 106 | ret->push(other->vec[i]); 107 | } 108 | return ret; 109 | } 110 | double indexOf(T needle) { 111 | for (int i = 0; i < vec.size(); i++) { 112 | if (vec[i] == needle) { 113 | return i; 114 | } 115 | } 116 | return -1; 117 | } 118 | }; 119 | 120 | #include "js2c/string.h" 121 | 122 | template 123 | struct Map { 124 | friend Console; 125 | private: 126 | std::map map; 127 | public: 128 | auto set(TKey key, TVal val) { 129 | map[key] = val; 130 | return this; 131 | } 132 | auto get(TKey key) { 133 | return map.at(key); 134 | } 135 | bool has(TKey key) { 136 | return map.find(key) != map.end(); 137 | } 138 | }; 139 | 140 | double Number(std::string convert_from) { 141 | if (convert_from.length() == 0) { 142 | return 0; 143 | } 144 | if (convert_from == "Infinity") { 145 | return INFINITY; 146 | } 147 | if (convert_from == "-Infinity") { 148 | return -INFINITY; 149 | } 150 | std::string to_parse = convert_from; 151 | int radix = 10; 152 | if (convert_from[0] == '0' && convert_from.length() >= 2) { 153 | int prefix_length; 154 | switch (convert_from[1]) { 155 | case 'x': 156 | case 'X': 157 | radix = 16; 158 | prefix_length = 2; 159 | break; 160 | case 'o': 161 | case 'O': 162 | radix = 8; 163 | prefix_length = 2; 164 | break; 165 | case 'B': 166 | case 'b': 167 | radix = 2; 168 | prefix_length = 2; 169 | break; 170 | default: 171 | radix = 10; 172 | prefix_length = 1; 173 | break; 174 | } 175 | to_parse = convert_from.substr(prefix_length); 176 | } 177 | for (int i = 0; 178 | i < to_parse.length(); 179 | i++) { 180 | int c = to_parse[i]; 181 | if ( 182 | !( 183 | (radix >= 10 && c >= '0' && c <= '9') || 184 | (radix == 8 && c >= '0' && c <= '7') || 185 | (radix == 2 && c >= '0' && c <= '1') || 186 | (radix == 16 && c >= 'a' && c <= 'f') || 187 | (radix == 16 && c >= 'A' && c <= 'F') || 188 | (c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\f') 189 | ) 190 | ) { 191 | return NaN; 192 | } 193 | } 194 | if (radix != 10) { 195 | return dumbjs_number_convert::parse(to_parse, radix); 196 | } 197 | return strtod(to_parse.c_str(), NULL); 198 | } 199 | 200 | double Number(String convert_from) { 201 | return Number(String::get_std_string(convert_from)); 202 | } 203 | double Number(nullptr_t) { return 0; } 204 | double Number() { return 0; } 205 | double Number(double n) { return n; } 206 | 207 | bool isNaN(auto n) { return isnan(Number(n)); } 208 | bool isNaN(double n) { return isnan(n); } 209 | bool isNaN(nullptr_t) { return true; } 210 | bool isNaN() { return true; } 211 | 212 | struct Math_ { 213 | public: 214 | Math_() { 215 | struct timespec ts; 216 | clock_gettime(CLOCK_MONOTONIC, &ts); 217 | srand(ts.tv_sec + ts.tv_nsec); 218 | } 219 | double E = 2.718281828459045; 220 | double LN10 = 2.302585092994046; 221 | double LN2 = 0.6931471805599453; 222 | double LOG10E = 0.4342944819032518; 223 | double LOG2E = 1.4426950408889634; 224 | double PI = 3.141592653589793; 225 | double SQRT1_2 = 0.7071067811865476; 226 | double SQRT_2 = 1.4142135623730951; 227 | double abs(double n) { return ::abs(n); } 228 | double acos(double n) { return ::acos(n); } 229 | // double acosh(double n) { return } 230 | double asin(double n) { return ::asin(n); } 231 | // double asinh (double n) { return } 232 | double atan(double n) { return ::atan(n); } 233 | // double atan2(double n) { return } 234 | // double atanh(double n) { return } 235 | // double cbrt(double n) { return } 236 | double ceil(double n) { return ::ceil(n); } 237 | // double clz32(double n) { return } 238 | double cos(double n) { return ::cos(n); } 239 | // double cosh(double n) { return } 240 | double exp(double n) { return ::exp(n); } 241 | // double expm1(double n) { return } 242 | double floor(double n) { return ::floor(n); } 243 | // double fround(double n) { return } 244 | // double hypot(double n) { return } 245 | double imul(double a, double b) { return ((int)a) * ((int)b); } 246 | double log(double n) { return ::log(n); } 247 | // double log10(double n) { return } 248 | // double log1p(double n) { return } 249 | // double log2(double n) { return } 250 | double pow(double n, double power) { return ::pow(n, power); } 251 | double random() { return (double)rand() / RAND_MAX; } 252 | double round(double n) { return ::round(n); } 253 | // double sign(double n) { return } 254 | double sin(double n) { return ::sin(n); } 255 | // double sinh(double n) { return } 256 | double sqrt(double n) { return ::sqrt(n); } 257 | double tan(double n) { return ::tan(n); } 258 | // double tanh(double n) { return } 259 | double trunc(double n) { return (int) n; } 260 | template 261 | double max(double n, Args... rest) { 262 | double tmp = max(rest...); 263 | if (n > tmp) { 264 | return n; 265 | } else { 266 | return tmp; 267 | } 268 | } 269 | double max(double n) { 270 | return n; 271 | } 272 | template 273 | double min(double n, Args... rest) { 274 | double tmp = min(rest...); 275 | if (n < tmp) { 276 | return n; 277 | } else { 278 | return tmp; 279 | } 280 | } 281 | double min(double n) { 282 | return n; 283 | } 284 | }; 285 | 286 | Math_ Math; 287 | 288 | #include "js2c/console.h" 289 | 290 | Console console; 291 | 292 | #include "js2c/process.h" 293 | 294 | void js2cpp_init_argv(int argc, char* argv[]) { 295 | process.argv = new Array(); 296 | // Put something in process.argv[0], so that the user's application may be the second argument. 297 | // since node scripts expect their arguments to start with the node runtime and then just read arguments from argv[2] on 298 | // that means something has to be here. 299 | // 300 | // TODO in the future create js2cpp-node command so it may be the first argument, 301 | // and the javascript file that generated the program, the second argument. 302 | process.argv->push(String("/usr/bin/env")); 303 | for (int i = 0; i < argc; i++) { 304 | process.argv->push(String(argv[i])); 305 | } 306 | } 307 | -------------------------------------------------------------------------------- /include/js2c/console.h: -------------------------------------------------------------------------------- 1 | 2 | struct Console { 3 | private: 4 | template 5 | static std::string representation(Array *only) { 6 | return representation(*only); 7 | } 8 | template 9 | static std::string representation(Array only) { 10 | if (only.length == 0) { 11 | return "[]"; 12 | } 13 | std::string s("[ "); 14 | for (auto iter = only.vec.begin(); 15 | iter != only.vec.end(); 16 | iter++) { 17 | if (iter != only.vec.begin()) { s += ", "; } 18 | s += long_representation(*iter); 19 | } 20 | s += (" ]"); 21 | return s; 22 | } 23 | template 24 | static std::string representation(Map *only) { 25 | return representation(*only); 26 | } 27 | template 28 | static std::string representation(Map only) { 29 | std::string s("Map { "); 30 | for (auto iter = only.map.begin(); 31 | iter != only.map.end(); 32 | iter++) { 33 | if (iter != only.map.begin()) { s += ", "; } 34 | s += representation(iter->first); 35 | s += " => "; 36 | s += representation(iter->second); 37 | } 38 | s += " }"; 39 | return s; 40 | } 41 | static std::string representation(double n) { 42 | if (n == (int) n) 43 | return std::to_string((int) n); 44 | if (isnan(n)) 45 | return std::string("NaN"); 46 | if (n == Infinity) 47 | return std::string("Infinity"); 48 | if (n == -Infinity) 49 | return std::string("-Infinity"); 50 | return std::to_string(n); // Cuts to 6 zeroes, just like node does when printing to the console 51 | } 52 | static std::string representation(int boolean_value) { 53 | return std::string( 54 | boolean_value ? "true" : "false" 55 | ); 56 | } 57 | static std::string representation(std::string only) { 58 | return only; 59 | } 60 | static std::string representation(void* only) { 61 | if (only == undefined) { 62 | return "undefined"; 63 | } 64 | return std::string("[Object]"); 65 | } 66 | static std::string representation(std::functionany) { 67 | return std::string("[Function]"); 68 | } 69 | static std::string long_representation(std::string a_string) { 70 | std::string out = std::string("'"); 71 | for (auto iter = a_string.begin(); 72 | iter != a_string.end(); 73 | iter++) { 74 | bool should_escape = 75 | *iter == '\n' || 76 | *iter == '\r' || 77 | *iter == '\\' || 78 | *iter == '\'' || 79 | *iter == '\0'; 80 | 81 | if (should_escape) { 82 | out += std::string("\\"); 83 | } 84 | out.append(1, *iter); 85 | } 86 | out += std::string("'"); 87 | return out; 88 | } 89 | static std::string long_representation(String the_string) { 90 | return long_representation(std::string(the_string)); 91 | } 92 | static std::string long_representation(auto whatever) { 93 | return representation(whatever); 94 | } 95 | public: 96 | template 97 | static void log(T only) { 98 | std::cout << representation(only) << std::endl; 99 | } 100 | template 101 | static void log(T first, Args... rest) { 102 | std::cout << representation(first) << std::string(" "); 103 | log(rest...); 104 | } 105 | }; 106 | -------------------------------------------------------------------------------- /include/js2c/process.h: -------------------------------------------------------------------------------- 1 | 2 | // Node things 3 | struct Env { 4 | String operator [] (String variable) { 5 | try { 6 | return std::getenv(std::string(variable).c_str()); 7 | } catch (std::logic_error e) { 8 | return String(""); 9 | } 10 | } 11 | String setenv (std::string variable, std::string value) { 12 | ::setenv(variable.c_str(), value.c_str(), value.length()); 13 | return value; 14 | } 15 | }; 16 | 17 | struct Process { 18 | Env env; 19 | Array * argv; 20 | void nextTick(auto func) { 21 | setImmediate(func); /* Handle remains hidden */ 22 | } 23 | void exit(int exit_code = 0) { 24 | ::exit(exit_code); 25 | } 26 | }; 27 | 28 | Process process; 29 | -------------------------------------------------------------------------------- /include/js2c/string.h: -------------------------------------------------------------------------------- 1 | 2 | struct String { 3 | friend Console; 4 | private: 5 | std::string string_data; 6 | inline void set_string_data(std::string s) { 7 | string_data = s; 8 | length = s.length(); 9 | } 10 | public: 11 | double length; 12 | 13 | String (double convert_from) { 14 | set_string_data(dumbjs_number_convert::stringify(convert_from, 10)); 15 | } 16 | 17 | String (std::nullptr_t x) { 18 | // Temporary fix for how commonJS modules are transpiled 19 | set_string_data(String("undefined")); 20 | } 21 | 22 | String (const char *convert_from) { 23 | set_string_data(convert_from); 24 | } 25 | 26 | String (const std::string & convert_from) { 27 | set_string_data(convert_from); 28 | } 29 | 30 | String() { 31 | set_string_data(String("")); 32 | } 33 | 34 | operator std::string() { 35 | return string_data; 36 | } 37 | 38 | String operator[] (int index) const { 39 | return charAt(index); 40 | } 41 | 42 | String operator+ (const std::string &other) const { 43 | return this->string_data + other; 44 | } 45 | 46 | String operator+= (const std::string &other) { 47 | set_string_data(string_data + other); 48 | return string_data; 49 | } 50 | 51 | bool operator == (const std::string &other) const { 52 | return string_data == other; 53 | } 54 | 55 | bool operator != (const std::string &other) const { 56 | return string_data != other; 57 | } 58 | 59 | template 60 | String(Array *ary) { 61 | std::string s(""); 62 | size_t len = ary->length; 63 | for (size_t i = 0; i < len; i++) { 64 | s += String((*ary)[i]); 65 | if (i < len - 1) 66 | s += std::string(","); 67 | } 68 | set_string_data(s); 69 | } 70 | 71 | String charAt(int index) const { 72 | if (index < 0 || index >= length) { return String(""); } 73 | return substring(index, index + 1); 74 | } 75 | String substring(int indexStart, int indexEnd) const { 76 | std::string ret = ""; 77 | if (indexStart < 0) indexStart = 0; 78 | if (indexEnd < 0) indexEnd = 0; 79 | if (indexStart > length) indexStart = length; 80 | if (indexEnd > length) indexEnd = length; 81 | if (indexStart > indexEnd) { 82 | std::swap(indexStart, indexEnd); 83 | } 84 | for (int i = indexStart; i < indexEnd; i++) 85 | ret += string_data[i]; 86 | return ret; 87 | } 88 | String substring(int indexStart) const { 89 | return substring(indexStart, length); 90 | } 91 | String substr(int indexStart, int len) const { 92 | if (indexStart < 0) { indexStart += length; } 93 | if (len < 0) { return String(""); } 94 | return substring(indexStart, indexStart + len); 95 | } 96 | String substr(int indexStart) const { 97 | return substr(indexStart, length - indexStart); 98 | } 99 | String concat(const String &other) const { 100 | return string_data + other.string_data; 101 | } 102 | Array * split() const { 103 | return new Array({ String(*this) }); 104 | } 105 | Array * split(const String &split_by, int limit = -1) const { 106 | auto ret = new Array(); 107 | if (split_by.length > length) { 108 | if (limit == 0) { return ret; } 109 | ret->push(*this); 110 | return ret; 111 | } 112 | if (split_by.length == 0) { 113 | std::string this_string = ""; 114 | for (int i = 0; i < length; i++) { 115 | this_string += string_data[i]; 116 | if (limit >= 0 && ret->length >= limit) { return ret; } 117 | ret->push(this_string); 118 | this_string = ""; 119 | } 120 | return ret; 121 | } 122 | int match_i = 0; 123 | int i = 0; 124 | bool matching_substring = false; 125 | std::string this_split = ""; 126 | while (i < length) { 127 | if (matching_substring == false) { 128 | if (split_by.string_data[0] == string_data[i]) { 129 | matching_substring = true; 130 | match_i = 1; 131 | ret->push(this_split); 132 | if (limit >= 0 && ret->length >= limit) { return ret; } 133 | this_split = ""; 134 | } else { 135 | this_split += string_data[i]; 136 | } 137 | } else { 138 | if (split_by.string_data[match_i] != string_data[i]) { 139 | matching_substring = false; 140 | this_split = ""; 141 | this_split += string_data[i]; 142 | } else { 143 | ; // Consume string 144 | } 145 | match_i++; 146 | } 147 | i++; 148 | } 149 | ret->push(this_split); 150 | return ret; 151 | } 152 | 153 | static std::string get_std_string(const String& s) { 154 | return s.string_data; 155 | } 156 | }; 157 | 158 | 159 | String typeof(double _) { return "number"; } 160 | String typeof(int _) { return "number"; } 161 | String typeof(String _) { return "string"; } 162 | String typeof(std::function) { return "function"; } 163 | String typeof(void* ptr) { return ptr != undefined ? "object" : "undefined"; } 164 | -------------------------------------------------------------------------------- /lib/cli.coffee: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env coffee 2 | 3 | child_process = require 'child_process' 4 | path = require 'path' 5 | fs = require 'fs' 6 | 7 | js2cpp = require './index' 8 | 9 | cli = (inpt, outp = null, cb) -> 10 | read_string_or_stream(inpt) 11 | .then (js_code) -> 12 | cpp_code = js2cpp js_code 13 | if outp 14 | outp.write cpp_code + '\n' 15 | return cpp_code 16 | 17 | cli.sync = (inpt, options) -> 18 | return js2cpp inpt, options 19 | 20 | cli.run = (inpt, run_args) -> 21 | binary_path = process.cwd() + '/a.out' 22 | cli(inpt) 23 | .then (cpp_code) -> 24 | compile_command = process.env['GPP_BINARY'] or 'g++' 25 | 26 | relative = (pt) -> path.join(__dirname, '..', pt) 27 | args = [ 28 | '-std=c++14', 29 | '-x', 'c++', # Take an input c++ file as STDIN 30 | '-' 31 | '-x', 'none', # And the following files aren't c++, start autodetecting pls 32 | '-I', relative('include/'), 33 | '-lrt', 34 | '-lpthread', 35 | '-o', binary_path, 36 | ] 37 | 38 | return new Promise (resolve, reject) -> 39 | compiler = child_process.spawn(compile_command, args) 40 | compiler.stderr.pipe(process.stderr) 41 | compiler.stdin.write(cpp_code + '\n') 42 | compiler.stdin.end() 43 | compiler.on 'exit', (status_code) -> 44 | compiler.stderr.unpipe(process.stderr) 45 | if status_code is 0 46 | resolve() 47 | else 48 | reject({ status_code }) 49 | .then () -> 50 | return new Promise (resolve) -> 51 | if process.env['RUN_VALGRIND'] 52 | run_args = [binary_path].concat(run_args) 53 | binary_path = 'valgrind' 54 | program = child_process.spawn(binary_path, run_args or []) 55 | promiseForEndedStreams = new Promise (resolve) -> 56 | stdoutEnded = false 57 | stderrEnded = false 58 | tryFinish = () -> 59 | if stdoutEnded and stderrEnded 60 | resolve() 61 | program.stderr.on('end', () -> stderrEnded = true; tryFinish()) 62 | program.stdout.on('end', () -> stdoutEnded = true; tryFinish()) 63 | program.stderr.on('error', () -> stderrEnded = true; tryFinish()) 64 | program.stdout.on('error', () -> stdoutEnded = true; tryFinish()) 65 | program.stderr.pipe(process.stderr) 66 | program.stdout.pipe(process.stdout) 67 | process.stdin.pipe(program.stdin) 68 | program.on 'exit', (status_code) -> 69 | try 70 | fs.unlinkSync binary_path 71 | promiseForEndedStreams.then () -> 72 | resolve({ status_code }) 73 | 74 | module.exports = cli 75 | 76 | read_string_or_stream = (string_or_stream, cb) -> 77 | return new Promise (resolve, reject) -> 78 | if typeof string_or_stream == 'string' 79 | return resolve(string_or_stream) 80 | data = '' 81 | string_or_stream.on 'data', (d) -> 82 | data += d 83 | string_or_stream.on 'error', (err) -> 84 | reject(err) 85 | string_or_stream.on 'end', () -> 86 | resolve(data) 87 | 88 | -------------------------------------------------------------------------------- /lib/cpp-types.coffee: -------------------------------------------------------------------------------- 1 | yell = require './yell' 2 | assert = require 'assert' 3 | tern = require 'tern/lib/infer' 4 | estraverse = require 'estraverse' 5 | 6 | get_fn_type = (func) -> 7 | scope = func.scope or func.body.scope 8 | fnType = scope.fnType.getType(false) 9 | yell fnType, 'Couldn\'t find a type for function', func.originNode 10 | return fnType 11 | 12 | # Use c++ types 13 | # Places a "kind" property in nodes 14 | cpp_types = (ast) -> 15 | type_of = (node, name) -> 16 | node.scope_at.hasProp(name).getType(false) 17 | 18 | retype_decl = (node) -> 19 | decl = node.declarations[0] 20 | if decl.init && /^Function/.test decl.type 21 | node.kind = get_fn_type(node) 22 | else 23 | node.kind = type_of node, decl.id.name 24 | yell node.kind, 'couldn\'t find a type for node', node 25 | 26 | retype_fun = (node) -> 27 | node.kind = get_fn_type(node) 28 | yell node.kind, 'Couldn\'t find a type for function', node 29 | for param in node.params 30 | scope = node.scope or node.body.scope 31 | param.kind = scope.hasProp(param.name).getType(false) or tern.ANull 32 | yell param.kind, 'couldn\'t find a kind for function param', param 33 | 34 | estraverse.replace ast, 35 | enter: (node, parent) -> 36 | if node.type is 'VariableDeclaration' 37 | retype_decl node 38 | if node.type in ['FunctionDeclaration', 'FunctionExpression'] 39 | retype_fun node 40 | return node 41 | 42 | get_type = (node, abstract_val_ok = true) -> 43 | if node.kind 44 | # "kind" forced through a property in the object 45 | return node.kind 46 | assert node, 'pass a node to get_type!' 47 | assert node.scope_at, 'the node passed to get_type must have a scope!' 48 | type = tern.expressionType({ node: node, state: node.scope_at }) 49 | if abstract_val_ok 50 | return type 51 | return type.getType(false) 52 | 53 | module.exports = cpp_types 54 | module.exports.get_type = get_type 55 | 56 | -------------------------------------------------------------------------------- /lib/fake-classes.coffee: -------------------------------------------------------------------------------- 1 | assert = require 'assert' 2 | tern = require 'tern/lib/infer' 3 | 4 | { gen } = require './gen' 5 | 6 | _fake_classes = [] 7 | _find_fake_lass_with_decls = (decls) -> 8 | # avoiding duplicate classes 9 | for cls in _fake_classes 10 | all_equal = decls.length == cls.decls.length and 11 | decls.every (decl, i) -> 12 | decl[0] is cls.decls[i][0] and decl[1] is cls.decls[i][1] 13 | if all_equal 14 | return cls 15 | 16 | get_fake_classes = () -> Object.freeze _fake_classes 17 | 18 | clear_fake_classes = () -> 19 | _fake_classes = [] 20 | 21 | _make_decls = (type) -> 22 | decls = ([type.props[prop].getType(false), prop] for prop in Object.keys type.props) 23 | 24 | decls = decls.sort (a, b) -> 25 | if a[1] > b[1] 26 | return 1 27 | return -1 28 | 29 | return decls 30 | 31 | 32 | make_fake_class = (type, { origin_node } = {}) -> 33 | assert type instanceof tern.Obj 34 | 35 | decls = _make_decls(type) 36 | existing = _find_fake_lass_with_decls(decls) 37 | if existing 38 | return existing 39 | 40 | name = 'FakeClass_' + _fake_classes.length 41 | 42 | wip_fake_class = { decls, name } 43 | _fake_classes.push(wip_fake_class) # Avoids infinite recursion in cases where 2 classes reference each other's names. 44 | 45 | # resolve dependency loop 46 | { format_decl } = require './format' 47 | decl_strings = decls.map(([type, prop]) -> format_decl(type, prop, { origin_node })) 48 | 49 | class_body = decl_strings.join(';\n ') 50 | if decls.length 51 | class_body += ';' 52 | 53 | # TODO this is a global variable 54 | to_put_before.push """ 55 | struct #{name} { 56 | #{class_body} 57 | #{name}(){} 58 | };\n\n 59 | """ 60 | 61 | fake_class = { name: name, decls: decls } 62 | 63 | type.fake_class = fake_class 64 | 65 | _fake_classes.splice(_fake_classes.indexOf(wip_fake_class), 1) 66 | _fake_classes.push(fake_class) 67 | 68 | return fake_class 69 | 70 | 71 | 72 | module.exports = { make_fake_class, get_fake_classes, clear_fake_classes } 73 | 74 | -------------------------------------------------------------------------------- /lib/format.coffee: -------------------------------------------------------------------------------- 1 | yell = require './yell' 2 | assert = require 'assert' 3 | estraverse = require 'estraverse' 4 | tern = require 'tern/lib/infer' 5 | standard_library_objects = require('./standard-library-objects.json') 6 | { gen, RAW_C } = require './gen' 7 | { make_fake_class } = require './fake-classes' 8 | { get_type } = require('./cpp-types') 9 | 10 | ############# 11 | # Formatting (outputing) our C++! 12 | 13 | format = (ast) -> 14 | estraverse.replace ast, 15 | leave: (node, parent) -> 16 | if formatters.hasOwnProperty node.type 17 | formatters[node.type](node, parent) 18 | 19 | is_pointer_type = (name, type) -> 20 | if name in standard_library_objects 21 | return false 22 | if type instanceof tern.Arr 23 | return true 24 | if type is tern.cx().str 25 | return false 26 | return true 27 | 28 | # Some formatters 29 | formatters = 30 | UnaryExpression: (node) -> 31 | if node.operator is 'typeof' 32 | arg = node.argument 33 | if arg.type is 'Identifier' and 34 | not node.scope_at.hasProp(arg.name) 35 | # typical Javascript feature detection 36 | type_name = if arg.name not in standard_library_objects then 'undefined' else 'object' 37 | return RAW_C "String(\"#{type_name}\") 38 | /* was: typeof #{arg.name}*/", { original: node } 39 | 40 | return RAW_C "typeof(#{gen format arg})", { original: node } 41 | MemberExpression: (node) -> 42 | [obj, prop] = [gen(format(node.object)), gen(format(node.property))] 43 | if node.computed 44 | if is_pointer_type(obj, get_type(node.object, false)) 45 | obj = "(*#{obj})" 46 | return RAW_C "#{obj}[#{prop}]", { original: node } 47 | if not is_pointer_type(obj, get_type(node.object, false)) 48 | return RAW_C obj + '.' + prop, { original: node } 49 | return RAW_C obj + '->' + prop, { original: node } 50 | CallExpression: (node) -> 51 | if node.callee.name is 'BIND' 52 | function_type = get_type(node.arguments[0], false).getFunctionType() 53 | args = function_type.argNames.slice(node.arguments.length - 1) 54 | placeholders = args 55 | .map((_, i) -> "std::placeholders::_#{i+1}") 56 | .join(', ') 57 | 58 | if placeholders.length 59 | placeholders = ', ' + placeholders 60 | 61 | return RAW_C "std::bind(#{ 62 | node.arguments.map((arg) -> gen format arg).join(', ') 63 | }#{ 64 | placeholders 65 | })", { original: node } 66 | NewExpression: (node, parent) -> 67 | type = get_type(node, false) 68 | if type and type.name is 'Map' and type.origin is 'ecma6' 69 | wrap_membex = if parent.type is 'MemberExpression' then (s) -> "(#{s})" else (s) -> s 70 | return RAW_C wrap_membex("new #{ 71 | format_type(type, { pointer_if_necessary: false, origin_node: node }) 72 | }()"), { original: node } 73 | Literal: (node) -> 74 | if node.raw[0] in ['"', "'"] 75 | return RAW_C "String(#{gen node})", { original: node } 76 | if typeof node.value is 'number' 77 | if node.value == Math.floor(node.value) 78 | # All numbers are doubles. But since c++ can't tell between an int and a bool 79 | # the console.log representation of an "int" is "true" or "false" 80 | # To avoid console.log(0) yielding "true", specify the number's type here. 81 | return RAW_C "#{node.value}.0f", { original: node } 82 | ArrayExpression: (node, parent) -> 83 | items = ("#{gen format item}" for item in node.elements) 84 | types = (get_type(item, false) for item in node.elements) 85 | array_type = format_type(types[0], { origin_node: node }) 86 | if array_type is 'void' and parent.type is 'VariableDeclarator' 87 | array_type = format_type(get_type(parent.id, false), { origin_node: node }) 88 | yell array_type isnt 'void', 'Creating an array of an unknown type', node 89 | yell(types.every((type, i) -> format_type(type, { origin_node: node.elements[i] }) is array_type), 'array of mixed types!', node) 90 | return RAW_C "(new Array<#{ array_type }>({ #{items.join(', ')} }))", { original: node } 91 | ObjectExpression: (node) -> 92 | assert !node.properties.length 93 | fake_class = make_fake_class(get_type(node, false)) 94 | return RAW_C "new #{fake_class.name}()", { original: node } 95 | VariableDeclaration: (node) -> 96 | assert node.declarations.length is 1 97 | decl = node.declarations[0] 98 | sides = [ 99 | format_decl(get_type(node, false), decl.id.name, { origin_node: node }) 100 | ] 101 | semicolon = ';' 102 | semicolon = '' if node.parent.type is 'ForStatement' 103 | if decl.init 104 | sides.push "#{gen format decl.init}" 105 | RAW_C((sides.join(' = ') + semicolon), { original: node }) 106 | FunctionDeclaration: (node) -> 107 | if node.id.name is 'main' 108 | return RAW_C("int main (int argc, char* argv[]) 109 | #{gen format node.body}", { original: node }) 110 | 111 | return_type = format_type(get_type(node, false).retval.getType(false), { origin_node: node }) 112 | params = node.params 113 | 114 | to_put_before.push """ 115 | #{return_type} #{node.id.name} (#{format_params params}); 116 | """ 117 | return RAW_C(" 118 | #{return_type} #{node.id.name} (#{format_params params}) #{gen format node.body} 119 | ", { original: node }) 120 | 121 | format_params = (params) -> 122 | return params 123 | .map (param) -> format_decl(get_type(param, false), param.name, { is_param: true, origin_node: param }) 124 | .join ', ' 125 | 126 | all_equivalent_type = (param_list) -> 127 | if param_list.length is 1 128 | return true 129 | 130 | type_strings = param_list.map (t) -> format_type(t) 131 | 132 | return type_strings.every((type) -> type is type_strings[0]) 133 | 134 | # Takes a tern type and formats it as a c++ type 135 | format_type = (type, { pointer_if_necessary = true, is_param = false, origin_node } = {}) -> 136 | ptr = if pointer_if_necessary then (s) -> s + ' *' else (s) -> s 137 | if type instanceof tern.Fn 138 | ret_type = type.retval.getType(false) 139 | arg_types = type.args.map((arg) -> format_type(arg.getType(false), { is_param: true, origin_node })) 140 | return "std::function<#{format_type(ret_type, { origin_node })} 141 | (#{arg_types.join(', ')})>" 142 | return type.toString() 143 | if type instanceof tern.Arr 144 | arr_types = type.props[''].types 145 | if all_equivalent_type arr_types.map((t) -> t.getType(false)) 146 | return ptr "Array<#{format_type(arr_types[0].getType(false), { origin_node })}>" 147 | yell false, 'array contains multiple types of variables. This requires boxed types which are not supported yet.', origin_node 148 | 149 | if type?.origin == 'ecma6' 150 | assert type.name 151 | if type.name is 'Map' 152 | value_t = type.maybeProps?[':value'] 153 | key_t = type.maybeProps?[':key'] 154 | yell key_t and key_t.types.length isnt 0, 'Creating a map of unknown key type', origin_node 155 | yell key_t and value_t.types.length isnt 0, 'Creating a map of unknown value type', origin_node 156 | key_types_all_pointers = key_t.types.every (type) -> 157 | type instanceof tern.Obj and type not instanceof tern.Fn 158 | if not key_types_all_pointers 159 | yell key_t.types.length is 1, 'Creating a map of mixed key types', origin_node 160 | yell all_equivalent_type(value_t.types), 'Creating a map of mixed value types', origin_node 161 | formatted_type = if key_types_all_pointers then 'void*' else format_type(key_t.getType(false), { origin_node }) 162 | return ptr "Map<#{formatted_type}, 163 | #{format_type(value_t.getType(false), { origin_node })}>" 164 | yell false, 'Unsupported ES6 type ' + type.name, origin_node 165 | 166 | if type instanceof tern.Obj 167 | return ptr make_fake_class(type).name 168 | 169 | if type in [tern.ANull, null, undefined] and is_param 170 | return 'auto' 171 | 172 | type_name = type or 'undefined' 173 | 174 | return { 175 | string: 'String' 176 | number: 'double' 177 | undefined: 'void' 178 | bool: 'bool' 179 | }[type_name] or yell false, "unknown type #{type_name}", origin_node 180 | 181 | # Format a decl. 182 | # Examples: "int main", "(void)(func*)()", etc. 183 | format_decl = (type, name, { is_param = false, origin_node } = {}) -> 184 | assert type, 'format_decl called without a type!' 185 | assert name, 'format_decl called without a name!' 186 | return [format_type(type, { is_param, origin_node }), name].join(' ') 187 | 188 | # indent all but the first line by 4 spaces 189 | indent_tail = (s) -> 190 | indent_arr = ([first, rest...]) -> [first].concat(' ' + line for line in rest) 191 | indent_arr(s.split('\n')).join('\n') 192 | 193 | module.exports = { format_decl, formatters, format } 194 | -------------------------------------------------------------------------------- /lib/gen.coffee: -------------------------------------------------------------------------------- 1 | ############ 2 | # Deal with escodegen 3 | 4 | { get_type } = require './cpp-types' 5 | escodegen = require 'escodegen' 6 | assert = require 'assert' 7 | 8 | # We'll need to generate some code. escodegen_options and RAW_C() allow us to generate raw C with escodegen. 9 | gen = (ast) -> 10 | assert ast, 'No AST!' 11 | escodegen.generate(ast, escodegen_options) 12 | 13 | raw_c_sentinel = {} 14 | 15 | get_type = (args...) -> 16 | get_type = require('./cpp-types').get_type 17 | return get_type(args...) 18 | 19 | RAW_C = (raw_c, { original } = {}) -> 20 | assert original, 'call RAW_C with the original node, so as to propagate type information' 21 | kind = get_type original 22 | return { 23 | type: 'Literal', 24 | value: raw_c_sentinel, # Escodegen will check this against the value in escode 25 | raw: raw_c, 26 | kind: kind 27 | } 28 | 29 | 30 | # Using this function we cheat escodegen into giving us raw C code when we say it is "Literal" 31 | # This is because escodegen will parse Literals given to it, and if the raw option is set and the literal has a "raw" property, it will check the literal's "value" property against a parsed "value" property. We can pass it a fake parser that gives a dummy value which will always pass this check as long as we give it the same dummy value on the other end too. 32 | escodegen_fake_parser = () -> 33 | return { 34 | type: 'Program', 35 | body: [{ 36 | expression: { 37 | type: 'Literal', 38 | value: raw_c_sentinel # escodegen will think I'm legit because it's comparing against the value I gave it in in RAW_C 39 | } 40 | }] 41 | } 42 | 43 | ############## 44 | # Options for escodegen 45 | # This includes the fake parser hack to make it write raw C 46 | # And the option to always write double quotes in string constants. 47 | escodegen_options = { parse: escodegen_fake_parser, raw: true, format: { quotes: 'double' } } 48 | 49 | module.exports = { gen, RAW_C } 50 | 51 | -------------------------------------------------------------------------------- /lib/index.coffee: -------------------------------------------------------------------------------- 1 | 2 | util = require 'util' 3 | assert = require 'assert' 4 | dumbjs = require 'dumbjs/lib/index' 5 | 6 | underscore = require 'underscore' 7 | estraverse = require 'estraverse' 8 | 9 | { Server } = require 'tern' 10 | tern = require 'tern/lib/infer' 11 | # tern_defs_ecma5 = require 'tern/defs/ecma5' 12 | tern_defs_ecma6 = require 'tern/defs/ecma6' 13 | tern_add_comments = require 'tern/lib/comment' 14 | require 'tern/plugin/doc_comment' # adds the doc_comment plugin to tern modules 15 | 16 | yell = require './yell' 17 | { format } = require('./format') 18 | { gen } = require('./gen') 19 | run_transforms = require('./transforms/index') 20 | { clear_fake_classes, get_fake_classes } = require './fake-classes' 21 | cpp_types = require './cpp-types' 22 | register_tern_plugins = require './tern-plugins' 23 | 24 | # Annotate the AST with "func_at", "scope_at", "" properties which tell us what function a tree node belongs to 25 | annotate = (ast) -> 26 | fun_stack = [] 27 | scope_stack = [tern.cx().topScope] 28 | cur_fun = () -> fun_stack[fun_stack.length - 1] 29 | cur_scope = () -> scope_stack[scope_stack.length - 1] 30 | 31 | estraverse.traverse ast, 32 | enter: (node, parent) -> 33 | Object.defineProperty node, 'parent', 34 | enumerable: false, get: () -> parent 35 | node.scope_at = cur_scope() 36 | if node.type is 'FunctionDeclaration' or 37 | node.type is 'FunctionExpression' 38 | fun_stack.push node 39 | scope_stack.push(node.scope or node.body.scope or cur_scope()) 40 | 41 | if node.type is 'Identifier' and is_variable_reference(node, parent) 42 | prop = cur_scope().hasProp(node.name) 43 | if prop and !/Function/.test(prop?.originNode?.parent?.type) 44 | type = prop.getType(false) 45 | yell type, 'Couldn\'t statically determine the type of ' + node.name, node 46 | node.kind = type 47 | 48 | if node.type is 'MemberExpression' 49 | node.kind = cpp_types.get_type(node, false) 50 | 51 | return node 52 | leave: (node) -> 53 | if node.type in ['FunctionExpression', 'FunctionDeclaration'] 54 | fun_stack.pop() 55 | scope_stack.pop() 56 | return ast 57 | 58 | # Cleanup 59 | cleanup = (ast) -> 60 | estraverse.replace ast, enter: (node) -> 61 | # Gotta remove expression statements cos they be banned in C! 62 | if node.type is 'ExpressionStatement' and 63 | node.expression.type is 'Literal' 64 | return estraverse.VisitorOption.Remove 65 | 66 | if node.type is 'VariableDeclaration' 67 | assert node.declarations.length is 1 68 | if node.declarations[0].init?.type is 'FunctionExpression' 69 | return { 70 | type: 'FunctionDeclaration', 71 | id: node.declarations[0].id, 72 | body: node.declarations[0].init.body, 73 | params: node.declarations[0].init.params, 74 | } 75 | 76 | register_tern_plugins() 77 | 78 | global.to_put_before = undefined 79 | module.exports = (js, { customDumbJs = dumbjs, options = {}, dumbJsOptions = {} } = {}) -> 80 | dumbJsOptions = underscore.defaults(dumbJsOptions, { 81 | mainify: {}, 82 | typeConversions: {}, 83 | }) 84 | 85 | dumbJsOptions.typeConversions = underscore.defaults(dumbJsOptions.typeConversions, { 86 | avoidJSAdd: true, 87 | }) 88 | 89 | dumbJsOptions.mainify = underscore.defaults(dumbJsOptions.mainify, { 90 | prepend: [], 91 | append: [], 92 | }) 93 | 94 | make_global_call = (name, args = []) -> { 95 | type: 'ExpressionStatement', 96 | expression: { 97 | type: 'CallExpression', 98 | callee: { type: 'Identifier', name: name }, 99 | arguments: args.map((arg) -> { type: 'Identifier', name: arg }), 100 | } 101 | } 102 | dumbJsOptions.mainify.prepend.push(make_global_call('js2cpp_init_argv', [ 'argc', 'argv' ])) 103 | js = customDumbJs(js, dumbJsOptions) 104 | 105 | server = new Server({ 106 | defs: [ tern_defs_ecma6 ], 107 | plugins: { 108 | doc_comment: { strong: true }, 109 | js2cpp: {}, 110 | }, 111 | }) 112 | # server.addDefs(tern_defs_ecma5) TODO adding this makes everything fail. Bug? 113 | server.addFile('', js) 114 | server.reset() 115 | ctx = server.cx 116 | tern.withContext ctx, () -> 117 | global.to_put_before = [] 118 | clear_fake_classes() 119 | file = server.findFile('') 120 | file.inspect = () -> '' # This shows up when I log every node, so no pls. 121 | ast = file.ast 122 | global.currentFile = js 123 | ast = cleanup ast 124 | tern.analyze ast 125 | annotate ast 126 | ast = cpp_types ast 127 | run_transforms(ast) 128 | pseudo_c_ast = format ast 129 | before_c = """ 130 | #include "js2c.h" 131 | \n 132 | """ 133 | before_c += get_fake_classes().map(({ name }) -> 'struct ' + name + ';').join('\n') + '\n\n' 134 | before_c += (global.to_put_before.join '\n') + '\n\n' 135 | c = gen(pseudo_c_ast) 136 | return before_c + c 137 | 138 | # stolen from dumbjs/lib/declosurify 139 | is_variable_reference = (node, parent) -> 140 | assert node.type is 'Identifier' 141 | if /Function/.test parent.type 142 | # I'm the argument or name of a function 143 | return false 144 | if parent.type is 'MemberExpression' 145 | # Not all identifiers in MemberExpression s are variables, only when: 146 | return ( 147 | parent.object is node or # - identifier is the leftmost in the membex 148 | (parent.computed and parent.property is node) # - identifier is in square brackets ( foo[x] ) 149 | ) 150 | # Everything else is a variable reference. Probably. 151 | return true 152 | 153 | -------------------------------------------------------------------------------- /lib/standard-library-objects.json: -------------------------------------------------------------------------------- 1 | [ 2 | "console", 3 | "process", 4 | "process.env", 5 | "Math" 6 | ] 7 | -------------------------------------------------------------------------------- /lib/tern-plugins.coffee: -------------------------------------------------------------------------------- 1 | assert = require 'assert' 2 | tern = require 'tern/lib/infer' 3 | { registerPlugin } = require 'tern' 4 | 5 | timerFuncDefs = { 6 | "setTimeout": { 7 | "!type": "fn(f: fn(), ms: number) -> number", 8 | "!url": "https://developer.mozilla.org/en/docs/DOM/window.setTimeout", 9 | "!doc": "Calls a function or executes a code snippet after specified delay." 10 | }, 11 | "clearTimeout": { 12 | "!type": "fn(timeout: number)", 13 | "!url": "https://developer.mozilla.org/en/docs/DOM/window.clearTimeout", 14 | "!doc": "Clears the delay set by window.setTimeout()." 15 | }, 16 | "setInterval": { 17 | "!type": "fn(f: fn(), ms: number) -> number", 18 | "!url": "https://developer.mozilla.org/en/docs/DOM/window.setInterval", 19 | "!doc": "Calls a function or executes a code snippet repeatedly, with a fixed time delay between each call to that function." 20 | }, 21 | "clearInterval": { 22 | "!type": "fn(interval: number)", 23 | "!url": "https://developer.mozilla.org/en/docs/DOM/window.clearInterval", 24 | "!doc": "Cancels repeated action which was set up using setInterval." 25 | }, 26 | "setImmediate": { 27 | "!type": "fn(f: fn()) -> number", 28 | "!url": "https://developer.mozilla.org/en/docs/DOM/window.setImmediate", 29 | "!doc": "Calls a function or executes a code snippet repeatedly, with a fixed time delay between each call to that function." 30 | }, 31 | "clearImmediate": { 32 | "!type": "fn(interval: number)", 33 | "!url": "https://developer.mozilla.org/en/docs/DOM/window.clearInterval", 34 | "!doc": "Cancels repeated action which was set up using setInterval." 35 | }, 36 | } 37 | 38 | module.exports = () -> 39 | registerPlugin 'js2cpp', (server) -> 40 | server.addDefs(timerFuncDefs) 41 | IsBound = tern.constraint({ 42 | construct: (self, target) -> 43 | this.self = self 44 | this.target = target 45 | addType: (fn) -> 46 | assert fn instanceof tern.Fn 47 | assert fn.args.length 48 | boundFunctionType = new tern.Fn(fn.name, tern.ANull, fn.args.slice(1), fn.argNames.slice(1), fn.retval) 49 | this.target.addType(boundFunctionType) 50 | this.self.propagate(fn.args[0]) 51 | }) 52 | tern.registerFunction 'dumbjsbindfunc', (_self, args) -> 53 | assert args.length is 2, 'BIND called with ' + args.length + ' arguments!' 54 | bound_function = new tern.AVal 55 | args[0].propagate(new IsBound(args[1], bound_function)) 56 | return bound_function 57 | 58 | server.addDefs({ 59 | 'BIND': { 60 | '!type': 'fn(func: fn(), closure: ?) -> !custom:dumbjsbindfunc', 61 | } 62 | }) 63 | -------------------------------------------------------------------------------- /lib/transforms/env.coffee: -------------------------------------------------------------------------------- 1 | estraverse = require 'estraverse' 2 | { format } = require('../format') 3 | { gen, RAW_C } = require('../gen') 4 | 5 | module.exports = (ast) -> 6 | estraverse.replace ast, 7 | enter: (node, parent) -> 8 | if node.type is 'AssignmentExpression' and 9 | node.left.type is 'MemberExpression' and 10 | node.left.object.type is 'MemberExpression' and 11 | gen(node.left.object) == 'process.env' 12 | as_string = gen format node.left.property 13 | if node.left.property.type is 'Identifier' 14 | as_string = "String(#{JSON.stringify(node.left.property.name)})" 15 | return RAW_C("process.env.setenv(#{as_string}, String(#{gen format node.right}))", { original: node }) 16 | 17 | # Turns process.env.FOO into process.env['FOO'] 18 | if node.type is 'MemberExpression' and 19 | node.object.type is 'MemberExpression' and 20 | gen(node.object) == 'process.env' and 21 | node.property.type is 'Identifier' 22 | return RAW_C("process.env[String(#{JSON.stringify node.property.name})]", { original: node }) 23 | return ast 24 | 25 | -------------------------------------------------------------------------------- /lib/transforms/index.coffee: -------------------------------------------------------------------------------- 1 | 2 | module.exports = (ast) -> 3 | apply = (accum, func) -> func(accum) 4 | [ 5 | require('./env') 6 | ].reduce(apply, ast) 7 | -------------------------------------------------------------------------------- /lib/yell.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | module.exports = function (condition, message, node) { 4 | if (condition) { return } 5 | var err = new Error(message) 6 | // TODO use deep binding for this 7 | if (node.loc && global.currentFile) { 8 | var lineText = getLine(global.currentFile, node.loc.end.line) + '\n' 9 | var arrow = Array(node.loc.end.column).join(' ') + '^' + '\n' 10 | err.stack = lineText + arrow + err.stack; 11 | } 12 | throw err; 13 | } 14 | 15 | function getLine(source, line) { 16 | return source.split(/\r?\n/g)[line] 17 | } 18 | 19 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js2cpp", 3 | "version": "1.1.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "JSONStream": { 8 | "version": "1.3.4", 9 | "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.4.tgz", 10 | "integrity": "sha512-Y7vfi3I5oMOYIr+WxV8NZxDSwcbNgzdKYsTNInmycOq9bUYwGg9ryu57Wg5NLmCjqdFPNUmpMBo3kSJN9tCbXg==", 11 | "requires": { 12 | "jsonparse": "^1.2.0", 13 | "through": ">=2.2.7 <3" 14 | } 15 | }, 16 | "acorn": { 17 | "version": "5.7.3", 18 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", 19 | "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==" 20 | }, 21 | "amdefine": { 22 | "version": "1.0.1", 23 | "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", 24 | "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=" 25 | }, 26 | "browser-pack": { 27 | "version": "5.0.1", 28 | "resolved": "https://registry.npmjs.org/browser-pack/-/browser-pack-5.0.1.tgz", 29 | "integrity": "sha1-QZdxmyDG4KqglFHFER5T77b7wY0=", 30 | "requires": { 31 | "JSONStream": "^1.0.3", 32 | "combine-source-map": "~0.6.1", 33 | "defined": "^1.0.0", 34 | "through2": "^1.0.0", 35 | "umd": "^3.0.0" 36 | } 37 | }, 38 | "browser-resolve": { 39 | "version": "1.11.3", 40 | "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz", 41 | "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==", 42 | "requires": { 43 | "resolve": "1.1.7" 44 | }, 45 | "dependencies": { 46 | "resolve": { 47 | "version": "1.1.7", 48 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", 49 | "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=" 50 | } 51 | } 52 | }, 53 | "coffee-script": { 54 | "version": "1.12.7", 55 | "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.12.7.tgz", 56 | "integrity": "sha512-fLeEhqwymYat/MpTPUjSKHVYYl0ec2mOyALEMLmzr5i1isuG+6jfI2j2d5oBO3VIzgUXgBVIcOT9uH1TFxBckw==" 57 | }, 58 | "combine-source-map": { 59 | "version": "0.6.1", 60 | "resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.6.1.tgz", 61 | "integrity": "sha1-m0oJwxYDPXaODxHgKfonMOB5rZY=", 62 | "requires": { 63 | "convert-source-map": "~1.1.0", 64 | "inline-source-map": "~0.5.0", 65 | "lodash.memoize": "~3.0.3", 66 | "source-map": "~0.4.2" 67 | } 68 | }, 69 | "commander": { 70 | "version": "2.3.0", 71 | "resolved": "http://registry.npmjs.org/commander/-/commander-2.3.0.tgz", 72 | "integrity": "sha1-/UMOiJgy7DU7ms0d4hfBHLPu+HM=", 73 | "dev": true 74 | }, 75 | "concat-stream": { 76 | "version": "1.4.11", 77 | "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.4.11.tgz", 78 | "integrity": "sha512-X3JMh8+4je3U1cQpG87+f9lXHDrqcb2MVLg9L7o8b1UZ0DzhRrUpdn65ttzu10PpJPPI3MQNkis+oha6TSA9Mw==", 79 | "requires": { 80 | "inherits": "~2.0.1", 81 | "readable-stream": "~1.1.9", 82 | "typedarray": "~0.0.5" 83 | } 84 | }, 85 | "convert-source-map": { 86 | "version": "1.1.3", 87 | "resolved": "http://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz", 88 | "integrity": "sha1-SCnId+n+SbMWHzvzZziI4gRpmGA=" 89 | }, 90 | "core-util-is": { 91 | "version": "1.0.2", 92 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 93 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" 94 | }, 95 | "d": { 96 | "version": "1.0.0", 97 | "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", 98 | "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", 99 | "requires": { 100 | "es5-ext": "^0.10.9" 101 | } 102 | }, 103 | "debug": { 104 | "version": "2.2.0", 105 | "resolved": "http://registry.npmjs.org/debug/-/debug-2.2.0.tgz", 106 | "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", 107 | "dev": true, 108 | "requires": { 109 | "ms": "0.7.1" 110 | } 111 | }, 112 | "deep-is": { 113 | "version": "0.1.3", 114 | "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", 115 | "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=" 116 | }, 117 | "defined": { 118 | "version": "1.0.0", 119 | "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", 120 | "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=" 121 | }, 122 | "detective": { 123 | "version": "4.7.1", 124 | "resolved": "https://registry.npmjs.org/detective/-/detective-4.7.1.tgz", 125 | "integrity": "sha512-H6PmeeUcZloWtdt4DAkFyzFL94arpHr3NOwwmVILFiy+9Qd4JTxxXrzfyGk/lmct2qVGBwTSwSXagqu2BxmWig==", 126 | "requires": { 127 | "acorn": "^5.2.1", 128 | "defined": "^1.0.0" 129 | } 130 | }, 131 | "diff": { 132 | "version": "1.4.0", 133 | "resolved": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz", 134 | "integrity": "sha1-fyjS657nsVqX79ic5j3P2qPMur8=", 135 | "dev": true 136 | }, 137 | "dumbjs": { 138 | "version": "github:fabiosantoscode/dumbjs#0aac6b6ec22872ca0f6023e50606952135e607c6", 139 | "from": "github:fabiosantoscode/dumbjs", 140 | "requires": { 141 | "browser-pack": "^5.0.1", 142 | "coffee-script": "^1.10.0", 143 | "escodegen": "^1.8.0", 144 | "escope": "^3.2.0", 145 | "esprima": "^2.7.2", 146 | "estraverse": "^1.9.1", 147 | "event-stream": "^3.3.2", 148 | "jsonpretty": "^0.0.1", 149 | "lodash": "^4.17.4", 150 | "module-deps": "^3.9.1", 151 | "parse-error": "^0.2.0", 152 | "resolve": "^1.1.6", 153 | "tern": "^0.15.0", 154 | "underscore": "^1.8.3" 155 | }, 156 | "dependencies": { 157 | "acorn": { 158 | "version": "2.7.0", 159 | "resolved": "http://registry.npmjs.org/acorn/-/acorn-2.7.0.tgz", 160 | "integrity": "sha1-q259nYhqrKiwhbwzEreaGYQz8Oc=" 161 | }, 162 | "escope": { 163 | "version": "3.6.0", 164 | "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz", 165 | "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=", 166 | "requires": { 167 | "es6-map": "^0.1.3", 168 | "es6-weak-map": "^2.0.1", 169 | "esrecurse": "^4.1.0", 170 | "estraverse": "^4.1.1" 171 | }, 172 | "dependencies": { 173 | "estraverse": { 174 | "version": "4.2.0", 175 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", 176 | "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=" 177 | } 178 | } 179 | }, 180 | "tern": { 181 | "version": "0.15.0", 182 | "resolved": "http://registry.npmjs.org/tern/-/tern-0.15.0.tgz", 183 | "integrity": "sha1-aCdiOEwJsRBUWrkQHhl3/yjvfBU=", 184 | "requires": { 185 | "acorn": "^2.3.0", 186 | "glob": "3", 187 | "minimatch": "0.2", 188 | "typescript": "=1.0.1" 189 | } 190 | } 191 | } 192 | }, 193 | "duplexer": { 194 | "version": "0.1.1", 195 | "resolved": "http://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", 196 | "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=" 197 | }, 198 | "duplexer2": { 199 | "version": "0.0.2", 200 | "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", 201 | "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=", 202 | "requires": { 203 | "readable-stream": "~1.1.9" 204 | } 205 | }, 206 | "es5-ext": { 207 | "version": "0.10.46", 208 | "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.46.tgz", 209 | "integrity": "sha512-24XxRvJXNFwEMpJb3nOkiRJKRoupmjYmOPVlI65Qy2SrtxwOTB+g6ODjBKOtwEHbYrhWRty9xxOWLNdClT2djw==", 210 | "requires": { 211 | "es6-iterator": "~2.0.3", 212 | "es6-symbol": "~3.1.1", 213 | "next-tick": "1" 214 | } 215 | }, 216 | "es6-iterator": { 217 | "version": "2.0.3", 218 | "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", 219 | "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", 220 | "requires": { 221 | "d": "1", 222 | "es5-ext": "^0.10.35", 223 | "es6-symbol": "^3.1.1" 224 | } 225 | }, 226 | "es6-map": { 227 | "version": "0.1.5", 228 | "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", 229 | "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", 230 | "requires": { 231 | "d": "1", 232 | "es5-ext": "~0.10.14", 233 | "es6-iterator": "~2.0.1", 234 | "es6-set": "~0.1.5", 235 | "es6-symbol": "~3.1.1", 236 | "event-emitter": "~0.3.5" 237 | } 238 | }, 239 | "es6-set": { 240 | "version": "0.1.5", 241 | "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", 242 | "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", 243 | "requires": { 244 | "d": "1", 245 | "es5-ext": "~0.10.14", 246 | "es6-iterator": "~2.0.1", 247 | "es6-symbol": "3.1.1", 248 | "event-emitter": "~0.3.5" 249 | } 250 | }, 251 | "es6-symbol": { 252 | "version": "3.1.1", 253 | "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", 254 | "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", 255 | "requires": { 256 | "d": "1", 257 | "es5-ext": "~0.10.14" 258 | } 259 | }, 260 | "es6-weak-map": { 261 | "version": "2.0.2", 262 | "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz", 263 | "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=", 264 | "requires": { 265 | "d": "1", 266 | "es5-ext": "^0.10.14", 267 | "es6-iterator": "^2.0.1", 268 | "es6-symbol": "^3.1.1" 269 | } 270 | }, 271 | "escape-string-regexp": { 272 | "version": "1.0.2", 273 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz", 274 | "integrity": "sha1-Tbwv5nTnGUnK8/smlc5/LcHZqNE=", 275 | "dev": true 276 | }, 277 | "escodegen": { 278 | "version": "1.11.0", 279 | "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.11.0.tgz", 280 | "integrity": "sha512-IeMV45ReixHS53K/OmfKAIztN/igDHzTJUhZM3k1jMhIZWjk45SMwAtBsEXiJp3vSPmTcu6CXn7mDvFHRN66fw==", 281 | "requires": { 282 | "esprima": "^3.1.3", 283 | "estraverse": "^4.2.0", 284 | "esutils": "^2.0.2", 285 | "optionator": "^0.8.1", 286 | "source-map": "~0.6.1" 287 | }, 288 | "dependencies": { 289 | "esprima": { 290 | "version": "3.1.3", 291 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", 292 | "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=" 293 | }, 294 | "estraverse": { 295 | "version": "4.2.0", 296 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", 297 | "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=" 298 | }, 299 | "source-map": { 300 | "version": "0.6.1", 301 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 302 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 303 | "optional": true 304 | } 305 | } 306 | }, 307 | "escope": { 308 | "version": "2.0.7", 309 | "resolved": "https://registry.npmjs.org/escope/-/escope-2.0.7.tgz", 310 | "integrity": "sha1-s9yOYF7dzPHIPsjPfM5tBEJ+yOs=", 311 | "requires": { 312 | "es6-map": "^0.1.1", 313 | "es6-weak-map": "^0.1.2", 314 | "esrecurse": "^1.2.0", 315 | "estraverse": "^1.9.1", 316 | "util-extend": "^1.0.1" 317 | }, 318 | "dependencies": { 319 | "d": { 320 | "version": "0.1.1", 321 | "resolved": "https://registry.npmjs.org/d/-/d-0.1.1.tgz", 322 | "integrity": "sha1-2hhMU10Y2O57oqoim5FACfrhEwk=", 323 | "requires": { 324 | "es5-ext": "~0.10.2" 325 | } 326 | }, 327 | "es6-iterator": { 328 | "version": "0.1.3", 329 | "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-0.1.3.tgz", 330 | "integrity": "sha1-1vWLjE/EE8JJtLqhl2j45NfIlE4=", 331 | "requires": { 332 | "d": "~0.1.1", 333 | "es5-ext": "~0.10.5", 334 | "es6-symbol": "~2.0.1" 335 | } 336 | }, 337 | "es6-symbol": { 338 | "version": "2.0.1", 339 | "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-2.0.1.tgz", 340 | "integrity": "sha1-dhtcZ8/U8dGK+yNPaR1nhoLLO/M=", 341 | "requires": { 342 | "d": "~0.1.1", 343 | "es5-ext": "~0.10.5" 344 | } 345 | }, 346 | "es6-weak-map": { 347 | "version": "0.1.4", 348 | "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-0.1.4.tgz", 349 | "integrity": "sha1-cGzvnpmqI2undmwjnIueKG6n0ig=", 350 | "requires": { 351 | "d": "~0.1.1", 352 | "es5-ext": "~0.10.6", 353 | "es6-iterator": "~0.1.3", 354 | "es6-symbol": "~2.0.1" 355 | } 356 | }, 357 | "esrecurse": { 358 | "version": "1.2.0", 359 | "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-1.2.0.tgz", 360 | "integrity": "sha1-JeOzq3atih2i046Tk/12uEVqcG8=", 361 | "requires": { 362 | "estraverse": ">=1.9.0" 363 | } 364 | } 365 | } 366 | }, 367 | "esprima": { 368 | "version": "2.7.3", 369 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", 370 | "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=" 371 | }, 372 | "esrecurse": { 373 | "version": "4.2.1", 374 | "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", 375 | "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", 376 | "requires": { 377 | "estraverse": "^4.1.0" 378 | }, 379 | "dependencies": { 380 | "estraverse": { 381 | "version": "4.2.0", 382 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", 383 | "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=" 384 | } 385 | } 386 | }, 387 | "estraverse": { 388 | "version": "1.9.3", 389 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", 390 | "integrity": "sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q=" 391 | }, 392 | "esutils": { 393 | "version": "2.0.2", 394 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", 395 | "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" 396 | }, 397 | "event-emitter": { 398 | "version": "0.3.5", 399 | "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", 400 | "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", 401 | "requires": { 402 | "d": "1", 403 | "es5-ext": "~0.10.14" 404 | } 405 | }, 406 | "event-stream": { 407 | "version": "3.3.6", 408 | "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.6.tgz", 409 | "integrity": "sha512-dGXNg4F/FgVzlApjzItL+7naHutA3fDqbV/zAZqDDlXTjiMnQmZKu+prImWKszeBM5UQeGvAl3u1wBiKeDh61g==", 410 | "requires": { 411 | "duplexer": "^0.1.1", 412 | "flatmap-stream": "^0.1.0", 413 | "from": "^0.1.7", 414 | "map-stream": "0.0.7", 415 | "pause-stream": "^0.0.11", 416 | "split": "^1.0.1", 417 | "stream-combiner": "^0.2.2", 418 | "through": "^2.3.8" 419 | } 420 | }, 421 | "fast-levenshtein": { 422 | "version": "2.0.6", 423 | "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", 424 | "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" 425 | }, 426 | "flatmap-stream": { 427 | "version": "0.1.1", 428 | "resolved": "https://registry.npmjs.org/flatmap-stream/-/flatmap-stream-0.1.1.tgz", 429 | "integrity": "sha512-lAq4tLbm3sidmdCN8G3ExaxH7cUCtP5mgDvrYowsx84dcYkJJ4I28N7gkxA6+YlSXzaGLJYIDEi9WGfXzMiXdw==" 430 | }, 431 | "from": { 432 | "version": "0.1.7", 433 | "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", 434 | "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=" 435 | }, 436 | "glob": { 437 | "version": "3.2.11", 438 | "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz", 439 | "integrity": "sha1-Spc/Y1uRkPcV0QmH1cAP0oFevj0=", 440 | "requires": { 441 | "inherits": "2", 442 | "minimatch": "0.3" 443 | }, 444 | "dependencies": { 445 | "minimatch": { 446 | "version": "0.3.0", 447 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz", 448 | "integrity": "sha1-J12O2qxPG7MyZHIInnlJyDlGmd0=", 449 | "requires": { 450 | "lru-cache": "2", 451 | "sigmund": "~1.0.0" 452 | } 453 | } 454 | } 455 | }, 456 | "growl": { 457 | "version": "1.9.2", 458 | "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", 459 | "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=", 460 | "dev": true 461 | }, 462 | "inherits": { 463 | "version": "2.0.3", 464 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 465 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 466 | }, 467 | "inline-source-map": { 468 | "version": "0.5.0", 469 | "resolved": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.5.0.tgz", 470 | "integrity": "sha1-Skxd2OT7Xps82mDIIt+tyu5m4K8=", 471 | "requires": { 472 | "source-map": "~0.4.0" 473 | } 474 | }, 475 | "isarray": { 476 | "version": "0.0.1", 477 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", 478 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" 479 | }, 480 | "jade": { 481 | "version": "0.26.3", 482 | "resolved": "https://registry.npmjs.org/jade/-/jade-0.26.3.tgz", 483 | "integrity": "sha1-jxDXl32NefL2/4YqgbBRPMslaGw=", 484 | "dev": true, 485 | "requires": { 486 | "commander": "0.6.1", 487 | "mkdirp": "0.3.0" 488 | }, 489 | "dependencies": { 490 | "commander": { 491 | "version": "0.6.1", 492 | "resolved": "http://registry.npmjs.org/commander/-/commander-0.6.1.tgz", 493 | "integrity": "sha1-+mihT2qUXVTbvlDYzbMyDp47GgY=", 494 | "dev": true 495 | }, 496 | "mkdirp": { 497 | "version": "0.3.0", 498 | "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz", 499 | "integrity": "sha1-G79asbqCevI1dRQ0kEJkVfSB/h4=", 500 | "dev": true 501 | } 502 | } 503 | }, 504 | "jsonparse": { 505 | "version": "1.3.1", 506 | "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", 507 | "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=" 508 | }, 509 | "jsonpretty": { 510 | "version": "0.0.1", 511 | "resolved": "https://registry.npmjs.org/jsonpretty/-/jsonpretty-0.0.1.tgz", 512 | "integrity": "sha1-daA2khx0FF3k6PVEaP0eqa7GTn0=" 513 | }, 514 | "levn": { 515 | "version": "0.3.0", 516 | "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", 517 | "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", 518 | "requires": { 519 | "prelude-ls": "~1.1.2", 520 | "type-check": "~0.3.2" 521 | } 522 | }, 523 | "lodash": { 524 | "version": "4.17.11", 525 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", 526 | "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" 527 | }, 528 | "lodash.memoize": { 529 | "version": "3.0.4", 530 | "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz", 531 | "integrity": "sha1-LcvSwofLwKVcxCMovQxzYVDVPj8=" 532 | }, 533 | "lru-cache": { 534 | "version": "2.7.3", 535 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", 536 | "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=" 537 | }, 538 | "map-stream": { 539 | "version": "0.0.7", 540 | "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz", 541 | "integrity": "sha1-ih8HiW2CsQkmvTdEokIACfiJdKg=" 542 | }, 543 | "minimatch": { 544 | "version": "0.2.14", 545 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz", 546 | "integrity": "sha1-x054BXT2PG+aCQ6Q775u9TpqdWo=", 547 | "requires": { 548 | "lru-cache": "2", 549 | "sigmund": "~1.0.0" 550 | } 551 | }, 552 | "minimist": { 553 | "version": "1.2.0", 554 | "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", 555 | "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" 556 | }, 557 | "mkdirp": { 558 | "version": "0.5.1", 559 | "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 560 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 561 | "dev": true, 562 | "requires": { 563 | "minimist": "0.0.8" 564 | }, 565 | "dependencies": { 566 | "minimist": { 567 | "version": "0.0.8", 568 | "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", 569 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", 570 | "dev": true 571 | } 572 | } 573 | }, 574 | "mocha": { 575 | "version": "2.5.3", 576 | "resolved": "http://registry.npmjs.org/mocha/-/mocha-2.5.3.tgz", 577 | "integrity": "sha1-FhvlvetJZ3HrmzV0UFC2IrWu/Fg=", 578 | "dev": true, 579 | "requires": { 580 | "commander": "2.3.0", 581 | "debug": "2.2.0", 582 | "diff": "1.4.0", 583 | "escape-string-regexp": "1.0.2", 584 | "glob": "3.2.11", 585 | "growl": "1.9.2", 586 | "jade": "0.26.3", 587 | "mkdirp": "0.5.1", 588 | "supports-color": "1.2.0", 589 | "to-iso-string": "0.0.2" 590 | } 591 | }, 592 | "module-deps": { 593 | "version": "3.9.1", 594 | "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-3.9.1.tgz", 595 | "integrity": "sha1-6nXK+RmQkNJbDVUStaysuW5/h/M=", 596 | "requires": { 597 | "JSONStream": "^1.0.3", 598 | "browser-resolve": "^1.7.0", 599 | "concat-stream": "~1.4.5", 600 | "defined": "^1.0.0", 601 | "detective": "^4.0.0", 602 | "duplexer2": "0.0.2", 603 | "inherits": "^2.0.1", 604 | "parents": "^1.0.0", 605 | "readable-stream": "^1.1.13", 606 | "resolve": "^1.1.3", 607 | "stream-combiner2": "~1.0.0", 608 | "subarg": "^1.0.0", 609 | "through2": "^1.0.0", 610 | "xtend": "^4.0.0" 611 | } 612 | }, 613 | "ms": { 614 | "version": "0.7.1", 615 | "resolved": "http://registry.npmjs.org/ms/-/ms-0.7.1.tgz", 616 | "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", 617 | "dev": true 618 | }, 619 | "next-tick": { 620 | "version": "1.0.0", 621 | "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", 622 | "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" 623 | }, 624 | "optionator": { 625 | "version": "0.8.2", 626 | "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", 627 | "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", 628 | "requires": { 629 | "deep-is": "~0.1.3", 630 | "fast-levenshtein": "~2.0.4", 631 | "levn": "~0.3.0", 632 | "prelude-ls": "~1.1.2", 633 | "type-check": "~0.3.2", 634 | "wordwrap": "~1.0.0" 635 | } 636 | }, 637 | "parents": { 638 | "version": "1.0.1", 639 | "resolved": "https://registry.npmjs.org/parents/-/parents-1.0.1.tgz", 640 | "integrity": "sha1-/t1NK/GTp3dF/nHjcdc8MwfZx1E=", 641 | "requires": { 642 | "path-platform": "~0.11.15" 643 | } 644 | }, 645 | "parse-error": { 646 | "version": "0.2.0", 647 | "resolved": "https://registry.npmjs.org/parse-error/-/parse-error-0.2.0.tgz", 648 | "integrity": "sha1-ojbVB2y+GWwVeBuJKyDQtpdZ/1s=" 649 | }, 650 | "path-parse": { 651 | "version": "1.0.6", 652 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", 653 | "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" 654 | }, 655 | "path-platform": { 656 | "version": "0.11.15", 657 | "resolved": "https://registry.npmjs.org/path-platform/-/path-platform-0.11.15.tgz", 658 | "integrity": "sha1-6GQhf3TDaFDwhSt43Hv31KVyG/I=" 659 | }, 660 | "pause-stream": { 661 | "version": "0.0.11", 662 | "resolved": "http://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", 663 | "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", 664 | "requires": { 665 | "through": "~2.3" 666 | } 667 | }, 668 | "prelude-ls": { 669 | "version": "1.1.2", 670 | "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", 671 | "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" 672 | }, 673 | "readable-stream": { 674 | "version": "1.1.14", 675 | "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", 676 | "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", 677 | "requires": { 678 | "core-util-is": "~1.0.0", 679 | "inherits": "~2.0.1", 680 | "isarray": "0.0.1", 681 | "string_decoder": "~0.10.x" 682 | } 683 | }, 684 | "resolve": { 685 | "version": "1.8.1", 686 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", 687 | "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", 688 | "requires": { 689 | "path-parse": "^1.0.5" 690 | } 691 | }, 692 | "sigmund": { 693 | "version": "1.0.1", 694 | "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", 695 | "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=" 696 | }, 697 | "source-map": { 698 | "version": "0.4.4", 699 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", 700 | "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", 701 | "requires": { 702 | "amdefine": ">=0.0.4" 703 | } 704 | }, 705 | "split": { 706 | "version": "1.0.1", 707 | "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", 708 | "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", 709 | "requires": { 710 | "through": "2" 711 | } 712 | }, 713 | "stream-combiner": { 714 | "version": "0.2.2", 715 | "resolved": "http://registry.npmjs.org/stream-combiner/-/stream-combiner-0.2.2.tgz", 716 | "integrity": "sha1-rsjLrBd7Vrb0+kec7YwZEs7lKFg=", 717 | "requires": { 718 | "duplexer": "~0.1.1", 719 | "through": "~2.3.4" 720 | } 721 | }, 722 | "stream-combiner2": { 723 | "version": "1.0.2", 724 | "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.0.2.tgz", 725 | "integrity": "sha1-unKmtQy/q/qVD8i8h2BL0B62BnE=", 726 | "requires": { 727 | "duplexer2": "~0.0.2", 728 | "through2": "~0.5.1" 729 | }, 730 | "dependencies": { 731 | "readable-stream": { 732 | "version": "1.0.34", 733 | "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", 734 | "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", 735 | "requires": { 736 | "core-util-is": "~1.0.0", 737 | "inherits": "~2.0.1", 738 | "isarray": "0.0.1", 739 | "string_decoder": "~0.10.x" 740 | } 741 | }, 742 | "through2": { 743 | "version": "0.5.1", 744 | "resolved": "https://registry.npmjs.org/through2/-/through2-0.5.1.tgz", 745 | "integrity": "sha1-390BLrnHAOIyP9M084rGIqs3Lac=", 746 | "requires": { 747 | "readable-stream": "~1.0.17", 748 | "xtend": "~3.0.0" 749 | } 750 | }, 751 | "xtend": { 752 | "version": "3.0.0", 753 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-3.0.0.tgz", 754 | "integrity": "sha1-XM50B7r2Qsunvs2laBEcST9ZZlo=" 755 | } 756 | } 757 | }, 758 | "string_decoder": { 759 | "version": "0.10.31", 760 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", 761 | "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" 762 | }, 763 | "subarg": { 764 | "version": "1.0.0", 765 | "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz", 766 | "integrity": "sha1-9izxdYHplrSPyWVpn1TAauJouNI=", 767 | "requires": { 768 | "minimist": "^1.1.0" 769 | } 770 | }, 771 | "supports-color": { 772 | "version": "1.2.0", 773 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-1.2.0.tgz", 774 | "integrity": "sha1-/x7R5hFp0Gs88tWI4YixjYhH4X4=", 775 | "dev": true 776 | }, 777 | "tern": { 778 | "version": "0.16.0", 779 | "resolved": "http://registry.npmjs.org/tern/-/tern-0.16.0.tgz", 780 | "integrity": "sha1-xpW0CSpyS5XQm3XP+1B4CHZFKhY=", 781 | "requires": { 782 | "acorn": "^2.5.2", 783 | "glob": "3", 784 | "minimatch": "0.2", 785 | "typescript": "=1.0.1" 786 | }, 787 | "dependencies": { 788 | "acorn": { 789 | "version": "2.7.0", 790 | "resolved": "http://registry.npmjs.org/acorn/-/acorn-2.7.0.tgz", 791 | "integrity": "sha1-q259nYhqrKiwhbwzEreaGYQz8Oc=" 792 | } 793 | } 794 | }, 795 | "through": { 796 | "version": "2.3.8", 797 | "resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz", 798 | "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" 799 | }, 800 | "through2": { 801 | "version": "1.1.1", 802 | "resolved": "https://registry.npmjs.org/through2/-/through2-1.1.1.tgz", 803 | "integrity": "sha1-CEfLxESfNAVXTb3M2buEG4OsNUU=", 804 | "requires": { 805 | "readable-stream": ">=1.1.13-1 <1.2.0-0", 806 | "xtend": ">=4.0.0 <4.1.0-0" 807 | } 808 | }, 809 | "to-iso-string": { 810 | "version": "0.0.2", 811 | "resolved": "https://registry.npmjs.org/to-iso-string/-/to-iso-string-0.0.2.tgz", 812 | "integrity": "sha1-TcGeZk38y+Jb2NtQiwDG2hWCVdE=", 813 | "dev": true 814 | }, 815 | "type-check": { 816 | "version": "0.3.2", 817 | "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", 818 | "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", 819 | "requires": { 820 | "prelude-ls": "~1.1.2" 821 | } 822 | }, 823 | "typedarray": { 824 | "version": "0.0.6", 825 | "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", 826 | "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" 827 | }, 828 | "typescript": { 829 | "version": "1.0.1", 830 | "resolved": "http://registry.npmjs.org/typescript/-/typescript-1.0.1.tgz", 831 | "integrity": "sha1-6OrN4whKCR0/4ptgrFhiJSZiolo=" 832 | }, 833 | "umd": { 834 | "version": "3.0.3", 835 | "resolved": "https://registry.npmjs.org/umd/-/umd-3.0.3.tgz", 836 | "integrity": "sha512-4IcGSufhFshvLNcMCV80UnQVlZ5pMOC8mvNPForqwA4+lzYQuetTESLDQkeLmihq8bRcnpbQa48Wb8Lh16/xow==" 837 | }, 838 | "underscore": { 839 | "version": "1.9.1", 840 | "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.9.1.tgz", 841 | "integrity": "sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg==" 842 | }, 843 | "util-extend": { 844 | "version": "1.0.3", 845 | "resolved": "https://registry.npmjs.org/util-extend/-/util-extend-1.0.3.tgz", 846 | "integrity": "sha1-p8IW0mdUUWljeztu3GypEZ4v+T8=" 847 | }, 848 | "wordwrap": { 849 | "version": "1.0.0", 850 | "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", 851 | "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=" 852 | }, 853 | "xtend": { 854 | "version": "4.0.1", 855 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", 856 | "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" 857 | } 858 | } 859 | } 860 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js2cpp", 3 | "version": "1.1.0", 4 | "description": "", 5 | "main": "lib/index.js", 6 | "scripts": { 7 | "test": "mocha -t 20000 --compilers coffee:coffee-script/register --require test/prepare.coffee" 8 | }, 9 | "author": "", 10 | "license": "WTFPL", 11 | "dependencies": { 12 | "coffee-script": "^1.10.0", 13 | "dumbjs": "github:fabiosantoscode/dumbjs", 14 | "escodegen": "^1.6.1", 15 | "escope": "^2.0.4", 16 | "esprima": "^2.0.0", 17 | "estraverse": "^1.9.1", 18 | "tern": "^0.16.0", 19 | "underscore": "^1.8.3" 20 | }, 21 | "devDependencies": { 22 | "mocha": "^2.3.4" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /test/index.coffee: -------------------------------------------------------------------------------- 1 | 2 | describe 'js2cpp', () -> 3 | it 'Can run some functions', () -> 4 | javascript_code = ''' 5 | function fib(n) { 6 | return n == 0 ? 0 : 7 | n == 1 ? 1 : 8 | fib(n - 1) + fib(n - 2) 9 | } 10 | function repeat(s, n) { 11 | var out = '' 12 | while (n--) out += s 13 | return out 14 | } 15 | function inc(n) { 16 | return function() { 17 | return n++ 18 | } 19 | } 20 | console.log("fib(0)", fib(0)) 21 | console.log("fib(1)", fib(1)) 22 | console.log("fib(4)", fib(4)) 23 | console.log("'ba' + repeat('na', 2)", 'ba' + repeat('na', 2)) 24 | var incrementor = inc(0) 25 | console.log(incrementor()) 26 | console.log(incrementor()) 27 | console.log(incrementor()) 28 | var x = [1,2,3] 29 | console.log([1,2,3], x, x[0], [1,2,3][1]) 30 | console.log('Math.floor(Math.PI * 100) / 100:', Math.floor(Math.PI * 100) / 100) 31 | console.log('Math.imul(3, 2):', Math.imul(3, 2)) 32 | console.log('Math.pow(2, 10):', Math.pow(2, 10)) 33 | console.log('Math.log(Math.E):', Math.log(Math.E)) 34 | console.log('Math.ceil(Math.LOG10E):', Math.ceil(Math.LOG10E)) 35 | console.log('Math.round(0.1), Math.round(0.5), Math.round(0.6):', Math.round(0.1), Math.round(0.5), Math.round(0.6)) 36 | console.log('Math.sin(90):', Math.sin(90)) 37 | console.log('Math.sqrt(4):', Math.sqrt(4)) 38 | console.log('Math.tan(45):', Math.tan(45)) 39 | console.log('Math.trunc(2.000001):', Math.trunc(2.000001)) 40 | console.log('Math.max(1):', Math.max(1)) 41 | console.log('Math.max(1, 2):', Math.max(1, 2)) 42 | console.log('Math.max(1, 2, -1):', Math.max(1, 2, -1)) 43 | console.log('Math.max(1):', Math.max(1)) 44 | console.log('Math.max(1, 2):', Math.max(1, 2)) 45 | console.log('Math.max(1, 2, -1):', Math.max(1, 2, -1)) 46 | console.log('Math.random() != Math.random()', Math.random() != Math.random()) 47 | console.log('Math.random() <= 1 && Math.random() >= 0', Math.random() <= 1 && Math.random() >= 0) 48 | console.log('NaN', NaN) 49 | console.log('isNaN(NaN)', isNaN(NaN)) 50 | console.log('isNaN(10)', isNaN(10)) 51 | console.log('isNaN("10")', isNaN("10")) 52 | console.log('isNaN("10NaN")', isNaN("10NaN")) 53 | console.log('isNaN("lel")', isNaN("lel")) 54 | console.log('FOO=bar', process.env['FOO'] = 'bar') 55 | console.log('process.env[\\'FOO\\']', process.env['FOO']) 56 | console.log('process.env.FOO', process.env.FOO) 57 | function maker(start) { 58 | start = start + 2 59 | return { 60 | increment: function () { 61 | start++ 62 | }, 63 | getValue: function () { 64 | return start 65 | } 66 | } 67 | } 68 | var obj = maker(5) 69 | obj.increment() 70 | console.log('obj.getValue()', obj.getValue()) 71 | console.log('Number(3)', Number(3)) 72 | console.log('Number(NaN)', Number(NaN)) 73 | console.log('Number("NaN")', Number("NaN")) 74 | console.log('Number("32")', Number("32")) 75 | console.log('Number("0x32")', Number("0x32")) 76 | console.log('Number("010")', Number("010")) 77 | console.log('String("foo")', String("foo")) 78 | console.log('String(10)', String(10)) 79 | console.log('String(Math.PI)', String(Math.PI)) 80 | console.log('String(NaN)', String(NaN)) 81 | console.log('String(undefined)', String(undefined)) 82 | console.log('String([1,2,3])', String([1,2,3])) 83 | 84 | console.log('\\n---\\n') 85 | 86 | var arr = [ 1 ] 87 | arr.push(2) 88 | console.log('arr.indexOf(0)', arr.indexOf(0)) 89 | console.log('arr.indexOf(1)', arr.indexOf(1)) 90 | console.log('arr.indexOf(2)', arr.indexOf(2)) 91 | 92 | console.log('\\n--- typeof\\n') 93 | 94 | console.log('typeof "lel"', typeof "lel") 95 | console.log('typeof 4', typeof 4) 96 | console.log('typeof 0', typeof 0) 97 | console.log('typeof undefined', typeof undefined) 98 | console.log('typeof {}', typeof {}) 99 | console.log('typeof process', typeof process) 100 | console.log('typeof window', typeof window) 101 | console.log('typeof function () {}', typeof function () {}) 102 | console.log('typeof function () {arr;}', typeof function () {arr;}) 103 | 104 | console.log('\\n--- Map\\n') 105 | 106 | var mapObj = new Map() 107 | var key1 = {} 108 | var key2 = {} 109 | mapObj.set(key1, 5).set(key2, 4) 110 | console.log('mapObj.has(key1)', mapObj.has(key1)) 111 | console.log('mapObj.has(key2)', mapObj.has(key2)) 112 | console.log('mapObj.has({})', mapObj.has({})) 113 | console.log('mapObj.get(key2)', mapObj.get(key2)) 114 | 115 | console.log('\\n--- function equivalence\\n') 116 | 117 | var functions = [ 118 | function (x) { console.log('function one got', x) }, 119 | function (x) { console.log('function two got', x) }, 120 | ]; 121 | for (var i = 0; i < functions.length; i++) { 122 | functions[i](i + 1) 123 | } 124 | 125 | console.log('\\n--- immutable strings\\n') 126 | 127 | var ex = 'lel'; 128 | var why = ex; 129 | why += '1'; 130 | console.log('x, y', ex, why) 131 | console.log('"1".charAt(0)', "1".charAt(0)) 132 | console.log('"1".charAt(1)', "1".charAt(1)) 133 | console.log('"1".charAt(-1)', "1".charAt(-1)) 134 | console.log('"".split()', "".split()) 135 | console.log('"".split("")', "".split("")) 136 | console.log('"".split("a")', "".split("a")) 137 | console.log('"abc".split("")', "abc".split("")) 138 | console.log('"some thing".split(" ")', "some thing".split(" ")) 139 | console.log('"some thing".split(" thin")', "some thing".split(" thin")) 140 | console.log('"some thing".split(" thing")', "some thing".split(" thing")) 141 | console.log('"1".split(1)', "1".split(1)) 142 | console.log('"1 1 1".split(1, 2)', "1 1 1".split(1, 2)) 143 | console.log('"one".concat("two")', "one".concat("two")) 144 | console.log('"one".concat(2)', "one".concat(2)) 145 | console.log('"lel".substring(1)', "lel".substring(1)) 146 | console.log('"lel".substring(1, 2)', "lel".substring(1, 2)) 147 | console.log('"lel".substring(2, 1)', "lel".substring(2, 1)) 148 | console.log('"lel".substr(1)', "lel".substr(1)) 149 | console.log('"lel".substr(-1)', "lel".substr(-1)) 150 | console.log('"lel".substr(1, 1)', "lel".substr(1, 1)) 151 | console.log('"lel".substr(-1, 1)', "lel".substr(-1, 1)) 152 | ''' 153 | 154 | expected_result = 155 | ''' 156 | fib(0) 0 157 | fib(1) 1 158 | fib(4) 3 159 | 'ba' + repeat('na', 2) banana 160 | 0 161 | 1 162 | 2 163 | [ 1, 2, 3 ] [ 1, 2, 3 ] 1 2 164 | Math.floor(Math.PI * 100) / 100: 3.140000 165 | Math.imul(3, 2): 6 166 | Math.pow(2, 10): 1024 167 | Math.log(Math.E): 1 168 | Math.ceil(Math.LOG10E): 1 169 | Math.round(0.1), Math.round(0.5), Math.round(0.6): 0 1 1 170 | Math.sin(90): 0.893997 171 | Math.sqrt(4): 2 172 | Math.tan(45): 1.619775 173 | Math.trunc(2.000001): 2 174 | Math.max(1): 1 175 | Math.max(1, 2): 2 176 | Math.max(1, 2, -1): 2 177 | Math.max(1): 1 178 | Math.max(1, 2): 2 179 | Math.max(1, 2, -1): 2 180 | Math.random() != Math.random() true 181 | Math.random() <= 1 && Math.random() >= 0 true 182 | NaN NaN 183 | isNaN(NaN) true 184 | isNaN(10) false 185 | isNaN("10") false 186 | isNaN("10NaN") true 187 | isNaN("lel") true 188 | FOO=bar bar 189 | process.env['FOO'] bar 190 | process.env.FOO bar 191 | obj.getValue() 8 192 | Number(3) 3 193 | Number(NaN) NaN 194 | Number("NaN") NaN 195 | Number("32") 32 196 | Number("0x32") 50 197 | Number("010") 10 198 | String("foo") foo 199 | String(10) 10 200 | String(Math.PI) 3.141592653589793 201 | String(NaN) NaN 202 | String(undefined) undefined 203 | String([1,2,3]) 1,2,3 204 | 205 | --- 206 | 207 | arr.indexOf(0) -1 208 | arr.indexOf(1) 0 209 | arr.indexOf(2) 1 210 | 211 | --- typeof 212 | 213 | typeof "lel" string 214 | typeof 4 number 215 | typeof 0 number 216 | typeof undefined undefined 217 | typeof {} object 218 | typeof process object 219 | typeof window undefined 220 | typeof function () {} function 221 | typeof function () {arr;} function 222 | 223 | --- Map 224 | 225 | mapObj.has(key1) true 226 | mapObj.has(key2) true 227 | mapObj.has({}) false 228 | mapObj.get(key2) 4 229 | 230 | --- function equivalence 231 | 232 | function one got 1 233 | function two got 2 234 | 235 | --- immutable strings 236 | 237 | x, y lel lel1 238 | "1".charAt(0) 1 239 | "1".charAt(1) 240 | "1".charAt(-1) 241 | "".split() [ '' ] 242 | "".split("") [] 243 | "".split("a") [ '' ] 244 | "abc".split("") [ 'a', 'b', 'c' ] 245 | "some thing".split(" ") [ 'some', 'thing' ] 246 | "some thing".split(" thin") [ 'some', 'g' ] 247 | "some thing".split(" thing") [ 'some', '' ] 248 | "1".split(1) [ '', '' ] 249 | "1 1 1".split(1, 2) [ '', ' ' ] 250 | "one".concat("two") onetwo 251 | "one".concat(2) one2 252 | "lel".substring(1) el 253 | "lel".substring(1, 2) e 254 | "lel".substring(2, 1) e 255 | "lel".substr(1) el 256 | "lel".substr(-1) l 257 | "lel".substr(1, 1) e 258 | "lel".substr(-1, 1) l 259 | ''' + '\n' 260 | 261 | ok.equal(eval( 262 | bindifyPrelude + 263 | fakeConsole + 264 | dumbjs(javascript_code) + '\n' + 265 | 'main()' + '\n' + 266 | 'output' 267 | ), 268 | expected_result, 269 | 'sanity check: javascript runs in regular eval using util.inspect to log stuff and still has expected result.') 270 | 271 | ok.equal(output_of(javascript_code), expected_result) 272 | 273 | describe.skip 'functions that take `auto`', () -> 274 | it 'Can be generated', () -> 275 | javascript_code = """ 276 | function x(a) { 277 | return typeof a 278 | } 279 | console.log(x(1)); 280 | console.log(x("lel")); 281 | """ 282 | 283 | expected_result = """ 284 | number 285 | string 286 | 287 | """ 288 | 289 | ok.equal(eval( 290 | bindifyPrelude + 291 | fakeConsole + 292 | dumbjs(javascript_code) + '\n' + 293 | 'main()' + '\n' + 294 | 'output' 295 | ), 296 | expected_result, 297 | 'sanity check: javascript runs in regular eval using util.inspect to log stuff and still has expected result.') 298 | 299 | ok.equal(output_of(javascript_code), expected_result) 300 | 301 | it 'Can use closures and be called immediately', () -> 302 | javascript_code = """ 303 | var prefix = '-' 304 | function x(a) { 305 | return prefix + typeof a 306 | } 307 | console.log(x(1)); 308 | console.log(x("lel")); 309 | """ 310 | 311 | expected_result = """ 312 | -number 313 | -string 314 | 315 | """ 316 | 317 | ok.equal(eval( 318 | bindifyPrelude + 319 | fakeConsole + 320 | dumbjs(javascript_code) + '\n' + 321 | 'main()' + '\n' + 322 | 'output' 323 | ), 324 | expected_result, 325 | 'sanity check: javascript runs in regular eval using util.inspect to log stuff and still has expected result.') 326 | 327 | ok.equal(output_of(javascript_code), expected_result) 328 | 329 | it.skip 'TODO: Can use closures and be stored', () -> 330 | javascript_code = """ 331 | var prefix = '-' 332 | function x(a) { 333 | return prefix + typeof a 334 | } 335 | var y = x; 336 | console.log(y(1)); 337 | console.log(y("lel")); 338 | """ 339 | 340 | expected_result = """ 341 | -number 342 | -string 343 | 344 | """ 345 | 346 | ok.equal(eval( 347 | bindifyPrelude + 348 | fakeConsole + 349 | dumbjs(javascript_code) + '\n' + 350 | 'main()' + '\n' + 351 | 'output' 352 | ), 353 | expected_result, 354 | 'sanity check: javascript runs in regular eval using util.inspect to log stuff and still has expected result.') 355 | 356 | ok.equal(output_of(javascript_code), expected_result) 357 | 358 | describe 'jsdoc integration', () -> 359 | it 'allows you to create variables of unknown types', () -> 360 | javascript_code = cli.sync '/** @type {string} **/ var x;' 361 | ok /String x/.test(javascript_code), javascript_code 362 | 363 | it 'allows you to create arrays of unknown types', () -> 364 | javascript_code = cli.sync '/** @type {number[]} **/ var x = [];' 365 | ok /Array/.test(javascript_code), javascript_code 366 | 367 | it 'can use this (lite)', () -> 368 | javascript_code = """ 369 | var identity = function() { return this } 370 | console.log(typeof identity.call(function(){ return 6 })) 371 | var object = { 372 | foo: 6, 373 | method: function (bar) { return this.foo + bar }, 374 | }; 375 | console.log(object.method(1)) 376 | """ 377 | 378 | expected_result = """ 379 | function 380 | 7 381 | 382 | """ 383 | 384 | ok.equal(eval( 385 | bindifyPrelude + 386 | fakeConsole + 387 | dumbjs(javascript_code) + '\n' + 388 | 'main()' + '\n' + 389 | 'output' 390 | ), 391 | expected_result, 392 | 'sanity check: javascript runs in regular eval using util.inspect to log stuff and still has expected result.') 393 | 394 | ok.equal(output_of(javascript_code), expected_result) 395 | 396 | it.skip 'TODO: can use this', () -> 397 | javascript_code = """ 398 | var callMe = function() { return this() } 399 | var identity = function() { return this } 400 | console.log(callMe.call(function(){ return 6 })) 401 | console.log([identity][0]()) 402 | var x = { y: { zed: identity } } 403 | console.log(x, x.y.zed()) 404 | var foo = function (x) { 405 | return this + x; 406 | } 407 | console.log(foo.call(1, 4)); 408 | function bar() { 409 | return this 410 | } 411 | console.log(bar.call(50)) 412 | """ 413 | 414 | expected_result = """ 415 | 6 416 | [ [Function] ] 417 | { y: { zed: [Function] } } { zed: [Function] } 418 | 5 419 | 50 420 | 421 | """ 422 | 423 | ok.equal(eval( 424 | bindifyPrelude + 425 | fakeConsole + 426 | dumbjs(javascript_code) + '\n' + 427 | 'main()' + '\n' + 428 | 'output' 429 | ), 430 | expected_result, 431 | 'sanity check: javascript runs in regular eval using util.inspect to log stuff and still has expected result.') 432 | 433 | ok.equal(output_of(javascript_code), expected_result) 434 | 435 | it 'can transpile code that\'s been through the browserify machinery back in dumbjs', () -> 436 | javascript_code = """ 437 | console.log(require(#{JSON.stringify(__dirname + '/some.js')}).returnFoo()) 438 | """ 439 | 440 | expected_result = "xfoo\n" 441 | 442 | ok.equal(eval( 443 | bindifyPrelude + 444 | fakeConsole + 445 | dumbjs(javascript_code) + '\n' + 446 | 'main()' + '\n' + 447 | 'output' 448 | ), 449 | expected_result, 450 | 'sanity check: javascript runs in regular eval using util.inspect to log stuff and still has expected result.') 451 | 452 | ok.equal(output_of(javascript_code), expected_result) 453 | 454 | it 'regression: cannot transpile functions with arguments', () -> 455 | return cli.sync(""" 456 | function x() { 457 | return 6 458 | } 459 | 460 | x() 461 | """) 462 | 463 | -------------------------------------------------------------------------------- /test/prepare.coffee: -------------------------------------------------------------------------------- 1 | 2 | global.ok = require 'assert' 3 | global.fs = require 'fs' 4 | global.sh = require('child_process').execSync 5 | global.js2cpp = require '../lib/index' 6 | global.dumbjs = require 'dumbjs' 7 | global.cli = require '../lib/cli' 8 | global.bindifyPrelude = require 'dumbjs/lib/bindify-prelude' 9 | 10 | global.transpile = (program, options) -> 11 | return fs.writeFileSync('/tmp/js2ctests.cpp', cli.sync(program, options)) 12 | 13 | global.output_of = (program, options) -> 14 | transpile program, options 15 | sh([ 16 | process.env['GPP_BINARY'] or 'g++', 17 | '-std=c++14', 18 | '/tmp/js2ctests.cpp', 19 | '-I include/', 20 | '-lrt', 21 | '-lpthread', 22 | '-O0', 23 | '-g', 24 | '-o /tmp/js2ctests.out', 25 | ].join ' ') 26 | return ''+sh '/tmp/js2ctests.out' 27 | 28 | global.fakeConsole = '\n' + 29 | ''' 30 | var output = ''; 31 | var console = { 32 | log: function() { 33 | output += [].slice.call(arguments) 34 | .map(function (s) { 35 | return typeof s === 'string' ? 36 | s : 37 | typeof s === 'number' ? ( 38 | Math.floor(s) === s ? s : 39 | // TODO do this instead in Console::log 40 | String(s).split('.').length == 2 && String(s).split('.')[1].length < 6 ? (function addZero(s) { if (s.split('.')[1].length < 6) { return addZero(s + '0') } return s }(String(s))) : 41 | // TODO do this autorounding instead in Console::log 42 | Math.round(s * 1000000) / 1000000 43 | ) : 44 | require('util').inspect(s) 45 | }).join(' ') + '\\n' 46 | } 47 | }; 48 | ''' 49 | -------------------------------------------------------------------------------- /test/some.js: -------------------------------------------------------------------------------- 1 | module.exports.returnFoo = function returnFoo() { 2 | return 'xfoo' 3 | } 4 | -------------------------------------------------------------------------------- /test_compilee.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | function stringRepeat(str, num) { 4 | var result = ''; 5 | for (var i = 0; i < num; i++) { 6 | result += str; 7 | } 8 | return result; 9 | } 10 | 11 | // Call fn with a random number 12 | function withRand(fn) { 13 | return fn(4 /* chosen by fair dice roll. guaranteed to be random */) 14 | } 15 | 16 | function main() { 17 | console.log(stringRepeat('Beetlejuice, ', 2) + ' Beetlejuice!') 18 | console.log('lel', 'I said beetlejuice like', 3, 'times!') 19 | 20 | var object = { x: 1 } 21 | object.y = 6 22 | console.log('x', object.x, 'y', object.y) 23 | 24 | console.log('a func called with a random number', withRand(function(rand) { 25 | return rand 26 | })) 27 | return 0 28 | } 29 | 30 | -------------------------------------------------------------------------------- /transpile-and-compile-and-run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | echo $1.js \> $1.cpp 3 | 4 | bin/js2cpp < $1.js > $1.cpp && g++ -std=c++14 -Wall -O3 -I gc-7.2/include/ -I include/ -lrt -lpthread $1.cpp && ./a.out 5 | 6 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | JSONStream@^1.0.3: 6 | version "1.3.1" 7 | resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.1.tgz#707f761e01dae9e16f1bcf93703b78c70966579a" 8 | dependencies: 9 | jsonparse "^1.2.0" 10 | through ">=2.2.7 <3" 11 | 12 | acorn@^2.3.0, acorn@^2.5.2: 13 | version "2.7.0" 14 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-2.7.0.tgz#ab6e7d9d886aaca8b085bc3312b79a198433f0e7" 15 | 16 | acorn@^4.0.3: 17 | version "4.0.13" 18 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787" 19 | 20 | amdefine@>=0.0.4: 21 | version "1.0.1" 22 | resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" 23 | 24 | browser-pack@^5.0.1: 25 | version "5.0.1" 26 | resolved "https://registry.yarnpkg.com/browser-pack/-/browser-pack-5.0.1.tgz#4197719b20c6e0aaa09451c5111e53efb6fbc18d" 27 | dependencies: 28 | JSONStream "^1.0.3" 29 | combine-source-map "~0.6.1" 30 | defined "^1.0.0" 31 | through2 "^1.0.0" 32 | umd "^3.0.0" 33 | 34 | browser-resolve@^1.7.0: 35 | version "1.11.2" 36 | resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.2.tgz#8ff09b0a2c421718a1051c260b32e48f442938ce" 37 | dependencies: 38 | resolve "1.1.7" 39 | 40 | coffee-script@^1.10.0: 41 | version "1.12.7" 42 | resolved "https://registry.yarnpkg.com/coffee-script/-/coffee-script-1.12.7.tgz#c05dae0cb79591d05b3070a8433a98c9a89ccc53" 43 | 44 | combine-source-map@~0.6.1: 45 | version "0.6.1" 46 | resolved "https://registry.yarnpkg.com/combine-source-map/-/combine-source-map-0.6.1.tgz#9b4a09c316033d768e0f11e029fa2730e079ad96" 47 | dependencies: 48 | convert-source-map "~1.1.0" 49 | inline-source-map "~0.5.0" 50 | lodash.memoize "~3.0.3" 51 | source-map "~0.4.2" 52 | 53 | commander@0.6.1: 54 | version "0.6.1" 55 | resolved "https://registry.yarnpkg.com/commander/-/commander-0.6.1.tgz#fa68a14f6a945d54dbbe50d8cdb3320e9e3b1a06" 56 | 57 | commander@2.3.0: 58 | version "2.3.0" 59 | resolved "https://registry.yarnpkg.com/commander/-/commander-2.3.0.tgz#fd430e889832ec353b9acd1de217c11cb3eef873" 60 | 61 | concat-stream@~1.4.5: 62 | version "1.4.10" 63 | resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.4.10.tgz#acc3bbf5602cb8cc980c6ac840fa7d8603e3ef36" 64 | dependencies: 65 | inherits "~2.0.1" 66 | readable-stream "~1.1.9" 67 | typedarray "~0.0.5" 68 | 69 | convert-source-map@~1.1.0: 70 | version "1.1.3" 71 | resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.1.3.tgz#4829c877e9fe49b3161f3bf3673888e204699860" 72 | 73 | core-util-is@~1.0.0: 74 | version "1.0.2" 75 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" 76 | 77 | d@1: 78 | version "1.0.0" 79 | resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f" 80 | dependencies: 81 | es5-ext "^0.10.9" 82 | 83 | d@~0.1.1: 84 | version "0.1.1" 85 | resolved "https://registry.yarnpkg.com/d/-/d-0.1.1.tgz#da184c535d18d8ee7ba2aa229b914009fae11309" 86 | dependencies: 87 | es5-ext "~0.10.2" 88 | 89 | debug@2.2.0: 90 | version "2.2.0" 91 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" 92 | dependencies: 93 | ms "0.7.1" 94 | 95 | deep-is@~0.1.3: 96 | version "0.1.3" 97 | resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" 98 | 99 | defined@^1.0.0: 100 | version "1.0.0" 101 | resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" 102 | 103 | detective@^4.0.0: 104 | version "4.5.0" 105 | resolved "https://registry.yarnpkg.com/detective/-/detective-4.5.0.tgz#6e5a8c6b26e6c7a254b1c6b6d7490d98ec91edd1" 106 | dependencies: 107 | acorn "^4.0.3" 108 | defined "^1.0.0" 109 | 110 | diff@1.4.0: 111 | version "1.4.0" 112 | resolved "https://registry.yarnpkg.com/diff/-/diff-1.4.0.tgz#7f28d2eb9ee7b15a97efd89ce63dcfdaa3ccbabf" 113 | 114 | dumbjs@fabiosantoscode/dumbjs: 115 | version "1.5.0" 116 | resolved "https://codeload.github.com/fabiosantoscode/dumbjs/tar.gz/c23d151f99b69b0bd6afc1316f556e9d6dfdce5d" 117 | dependencies: 118 | browser-pack "^5.0.1" 119 | coffee-script "^1.10.0" 120 | escodegen "^1.8.0" 121 | escope "^3.2.0" 122 | esprima "^2.7.2" 123 | estraverse "^1.9.1" 124 | event-stream "^3.3.2" 125 | module-deps "^3.9.1" 126 | resolve "^1.1.6" 127 | tern "^0.15.0" 128 | underscore "^1.8.3" 129 | 130 | duplexer2@0.0.2, duplexer2@~0.0.2: 131 | version "0.0.2" 132 | resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.0.2.tgz#c614dcf67e2fb14995a91711e5a617e8a60a31db" 133 | dependencies: 134 | readable-stream "~1.1.9" 135 | 136 | duplexer@~0.1.1: 137 | version "0.1.1" 138 | resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1" 139 | 140 | es5-ext@^0.10.14, es5-ext@^0.10.9, es5-ext@~0.10.14, es5-ext@~0.10.2, es5-ext@~0.10.5, es5-ext@~0.10.6: 141 | version "0.10.24" 142 | resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.24.tgz#a55877c9924bc0c8d9bd3c2cbe17495ac1709b14" 143 | dependencies: 144 | es6-iterator "2" 145 | es6-symbol "~3.1" 146 | 147 | es6-iterator@2, es6-iterator@^2.0.1, es6-iterator@~2.0.1: 148 | version "2.0.1" 149 | resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.1.tgz#8e319c9f0453bf575d374940a655920e59ca5512" 150 | dependencies: 151 | d "1" 152 | es5-ext "^0.10.14" 153 | es6-symbol "^3.1" 154 | 155 | es6-iterator@~0.1.3: 156 | version "0.1.3" 157 | resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-0.1.3.tgz#d6f58b8c4fc413c249b4baa19768f8e4d7c8944e" 158 | dependencies: 159 | d "~0.1.1" 160 | es5-ext "~0.10.5" 161 | es6-symbol "~2.0.1" 162 | 163 | es6-map@^0.1.1, es6-map@^0.1.3: 164 | version "0.1.5" 165 | resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.5.tgz#9136e0503dcc06a301690f0bb14ff4e364e949f0" 166 | dependencies: 167 | d "1" 168 | es5-ext "~0.10.14" 169 | es6-iterator "~2.0.1" 170 | es6-set "~0.1.5" 171 | es6-symbol "~3.1.1" 172 | event-emitter "~0.3.5" 173 | 174 | es6-set@~0.1.5: 175 | version "0.1.5" 176 | resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1" 177 | dependencies: 178 | d "1" 179 | es5-ext "~0.10.14" 180 | es6-iterator "~2.0.1" 181 | es6-symbol "3.1.1" 182 | event-emitter "~0.3.5" 183 | 184 | es6-symbol@3.1.1, es6-symbol@^3.1, es6-symbol@^3.1.1, es6-symbol@~3.1, es6-symbol@~3.1.1: 185 | version "3.1.1" 186 | resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77" 187 | dependencies: 188 | d "1" 189 | es5-ext "~0.10.14" 190 | 191 | es6-symbol@~2.0.1: 192 | version "2.0.1" 193 | resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-2.0.1.tgz#761b5c67cfd4f1d18afb234f691d678682cb3bf3" 194 | dependencies: 195 | d "~0.1.1" 196 | es5-ext "~0.10.5" 197 | 198 | es6-weak-map@^0.1.2: 199 | version "0.1.4" 200 | resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-0.1.4.tgz#706cef9e99aa236ba7766c239c8b9e286ea7d228" 201 | dependencies: 202 | d "~0.1.1" 203 | es5-ext "~0.10.6" 204 | es6-iterator "~0.1.3" 205 | es6-symbol "~2.0.1" 206 | 207 | es6-weak-map@^2.0.1: 208 | version "2.0.2" 209 | resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.2.tgz#5e3ab32251ffd1538a1f8e5ffa1357772f92d96f" 210 | dependencies: 211 | d "1" 212 | es5-ext "^0.10.14" 213 | es6-iterator "^2.0.1" 214 | es6-symbol "^3.1.1" 215 | 216 | escape-string-regexp@1.0.2: 217 | version "1.0.2" 218 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz#4dbc2fe674e71949caf3fb2695ce7f2dc1d9a8d1" 219 | 220 | escodegen@^1.6.1, escodegen@^1.8.0: 221 | version "1.8.1" 222 | resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.8.1.tgz#5a5b53af4693110bebb0867aa3430dd3b70a1018" 223 | dependencies: 224 | esprima "^2.7.1" 225 | estraverse "^1.9.1" 226 | esutils "^2.0.2" 227 | optionator "^0.8.1" 228 | optionalDependencies: 229 | source-map "~0.2.0" 230 | 231 | escope@^2.0.4: 232 | version "2.0.7" 233 | resolved "https://registry.yarnpkg.com/escope/-/escope-2.0.7.tgz#b3dc8e605eddccf1c83ec8cf7cce6d04427ec8eb" 234 | dependencies: 235 | es6-map "^0.1.1" 236 | es6-weak-map "^0.1.2" 237 | esrecurse "^1.2.0" 238 | estraverse "^1.9.1" 239 | util-extend "^1.0.1" 240 | 241 | escope@^3.2.0: 242 | version "3.6.0" 243 | resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3" 244 | dependencies: 245 | es6-map "^0.1.3" 246 | es6-weak-map "^2.0.1" 247 | esrecurse "^4.1.0" 248 | estraverse "^4.1.1" 249 | 250 | esprima@^2.0.0, esprima@^2.7.1, esprima@^2.7.2: 251 | version "2.7.3" 252 | resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" 253 | 254 | esrecurse@^1.2.0: 255 | version "1.2.0" 256 | resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-1.2.0.tgz#25e3b3ab76ad8a1da2d38e9393fd76b8456a706f" 257 | dependencies: 258 | estraverse ">=1.9.0" 259 | 260 | esrecurse@^4.1.0: 261 | version "4.2.0" 262 | resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.0.tgz#fa9568d98d3823f9a41d91e902dcab9ea6e5b163" 263 | dependencies: 264 | estraverse "^4.1.0" 265 | object-assign "^4.0.1" 266 | 267 | estraverse@>=1.9.0, estraverse@^4.1.0, estraverse@^4.1.1: 268 | version "4.2.0" 269 | resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" 270 | 271 | estraverse@^1.9.1: 272 | version "1.9.3" 273 | resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-1.9.3.tgz#af67f2dc922582415950926091a4005d29c9bb44" 274 | 275 | esutils@^2.0.2: 276 | version "2.0.2" 277 | resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" 278 | 279 | event-emitter@~0.3.5: 280 | version "0.3.5" 281 | resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" 282 | dependencies: 283 | d "1" 284 | es5-ext "~0.10.14" 285 | 286 | event-stream@^3.3.2: 287 | version "3.3.4" 288 | resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571" 289 | dependencies: 290 | duplexer "~0.1.1" 291 | from "~0" 292 | map-stream "~0.1.0" 293 | pause-stream "0.0.11" 294 | split "0.3" 295 | stream-combiner "~0.0.4" 296 | through "~2.3.1" 297 | 298 | fast-levenshtein@~2.0.4: 299 | version "2.0.6" 300 | resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" 301 | 302 | from@~0: 303 | version "0.1.7" 304 | resolved "https://registry.yarnpkg.com/from/-/from-0.1.7.tgz#83c60afc58b9c56997007ed1a768b3ab303a44fe" 305 | 306 | glob@3, glob@3.2.11: 307 | version "3.2.11" 308 | resolved "https://registry.yarnpkg.com/glob/-/glob-3.2.11.tgz#4a973f635b9190f715d10987d5c00fd2815ebe3d" 309 | dependencies: 310 | inherits "2" 311 | minimatch "0.3" 312 | 313 | growl@1.9.2: 314 | version "1.9.2" 315 | resolved "https://registry.yarnpkg.com/growl/-/growl-1.9.2.tgz#0ea7743715db8d8de2c5ede1775e1b45ac85c02f" 316 | 317 | inherits@2, inherits@^2.0.1, inherits@~2.0.1: 318 | version "2.0.3" 319 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 320 | 321 | inline-source-map@~0.5.0: 322 | version "0.5.0" 323 | resolved "https://registry.yarnpkg.com/inline-source-map/-/inline-source-map-0.5.0.tgz#4a4c5dd8e4fb5e9b3cda60c822dfadcaee66e0af" 324 | dependencies: 325 | source-map "~0.4.0" 326 | 327 | isarray@0.0.1: 328 | version "0.0.1" 329 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" 330 | 331 | jade@0.26.3: 332 | version "0.26.3" 333 | resolved "https://registry.yarnpkg.com/jade/-/jade-0.26.3.tgz#8f10d7977d8d79f2f6ff862a81b0513ccb25686c" 334 | dependencies: 335 | commander "0.6.1" 336 | mkdirp "0.3.0" 337 | 338 | jsonparse@^1.2.0: 339 | version "1.3.1" 340 | resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" 341 | 342 | levn@~0.3.0: 343 | version "0.3.0" 344 | resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" 345 | dependencies: 346 | prelude-ls "~1.1.2" 347 | type-check "~0.3.2" 348 | 349 | lodash.memoize@~3.0.3: 350 | version "3.0.4" 351 | resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-3.0.4.tgz#2dcbd2c287cbc0a55cc42328bd0c736150d53e3f" 352 | 353 | lru-cache@2: 354 | version "2.7.3" 355 | resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" 356 | 357 | map-stream@~0.1.0: 358 | version "0.1.0" 359 | resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.1.0.tgz#e56aa94c4c8055a16404a0674b78f215f7c8e194" 360 | 361 | minimatch@0.2: 362 | version "0.2.14" 363 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-0.2.14.tgz#c74e780574f63c6f9a090e90efbe6ef53a6a756a" 364 | dependencies: 365 | lru-cache "2" 366 | sigmund "~1.0.0" 367 | 368 | minimatch@0.3: 369 | version "0.3.0" 370 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-0.3.0.tgz#275d8edaac4f1bb3326472089e7949c8394699dd" 371 | dependencies: 372 | lru-cache "2" 373 | sigmund "~1.0.0" 374 | 375 | minimist@0.0.8: 376 | version "0.0.8" 377 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" 378 | 379 | minimist@^1.1.0: 380 | version "1.2.0" 381 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" 382 | 383 | mkdirp@0.3.0: 384 | version "0.3.0" 385 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.0.tgz#1bbf5ab1ba827af23575143490426455f481fe1e" 386 | 387 | mkdirp@0.5.1: 388 | version "0.5.1" 389 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" 390 | dependencies: 391 | minimist "0.0.8" 392 | 393 | mocha@^2.3.4: 394 | version "2.5.3" 395 | resolved "https://registry.yarnpkg.com/mocha/-/mocha-2.5.3.tgz#161be5bdeb496771eb9b35745050b622b5aefc58" 396 | dependencies: 397 | commander "2.3.0" 398 | debug "2.2.0" 399 | diff "1.4.0" 400 | escape-string-regexp "1.0.2" 401 | glob "3.2.11" 402 | growl "1.9.2" 403 | jade "0.26.3" 404 | mkdirp "0.5.1" 405 | supports-color "1.2.0" 406 | to-iso-string "0.0.2" 407 | 408 | module-deps@^3.9.1: 409 | version "3.9.1" 410 | resolved "https://registry.yarnpkg.com/module-deps/-/module-deps-3.9.1.tgz#ea75caf9199090d25b0d5512b5acacb96e7f87f3" 411 | dependencies: 412 | JSONStream "^1.0.3" 413 | browser-resolve "^1.7.0" 414 | concat-stream "~1.4.5" 415 | defined "^1.0.0" 416 | detective "^4.0.0" 417 | duplexer2 "0.0.2" 418 | inherits "^2.0.1" 419 | parents "^1.0.0" 420 | readable-stream "^1.1.13" 421 | resolve "^1.1.3" 422 | stream-combiner2 "~1.0.0" 423 | subarg "^1.0.0" 424 | through2 "^1.0.0" 425 | xtend "^4.0.0" 426 | 427 | ms@0.7.1: 428 | version "0.7.1" 429 | resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" 430 | 431 | object-assign@^4.0.1: 432 | version "4.1.1" 433 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" 434 | 435 | optionator@^0.8.1: 436 | version "0.8.2" 437 | resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" 438 | dependencies: 439 | deep-is "~0.1.3" 440 | fast-levenshtein "~2.0.4" 441 | levn "~0.3.0" 442 | prelude-ls "~1.1.2" 443 | type-check "~0.3.2" 444 | wordwrap "~1.0.0" 445 | 446 | parents@^1.0.0: 447 | version "1.0.1" 448 | resolved "https://registry.yarnpkg.com/parents/-/parents-1.0.1.tgz#fedd4d2bf193a77745fe71e371d73c3307d9c751" 449 | dependencies: 450 | path-platform "~0.11.15" 451 | 452 | path-parse@^1.0.5: 453 | version "1.0.5" 454 | resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" 455 | 456 | path-platform@~0.11.15: 457 | version "0.11.15" 458 | resolved "https://registry.yarnpkg.com/path-platform/-/path-platform-0.11.15.tgz#e864217f74c36850f0852b78dc7bf7d4a5721bf2" 459 | 460 | pause-stream@0.0.11: 461 | version "0.0.11" 462 | resolved "https://registry.yarnpkg.com/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445" 463 | dependencies: 464 | through "~2.3" 465 | 466 | prelude-ls@~1.1.2: 467 | version "1.1.2" 468 | resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" 469 | 470 | "readable-stream@>=1.1.13-1 <1.2.0-0", readable-stream@^1.1.13, readable-stream@~1.1.9: 471 | version "1.1.14" 472 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" 473 | dependencies: 474 | core-util-is "~1.0.0" 475 | inherits "~2.0.1" 476 | isarray "0.0.1" 477 | string_decoder "~0.10.x" 478 | 479 | readable-stream@~1.0.17: 480 | version "1.0.34" 481 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" 482 | dependencies: 483 | core-util-is "~1.0.0" 484 | inherits "~2.0.1" 485 | isarray "0.0.1" 486 | string_decoder "~0.10.x" 487 | 488 | resolve@1.1.7: 489 | version "1.1.7" 490 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" 491 | 492 | resolve@^1.1.3, resolve@^1.1.6: 493 | version "1.4.0" 494 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.4.0.tgz#a75be01c53da25d934a98ebd0e4c4a7312f92a86" 495 | dependencies: 496 | path-parse "^1.0.5" 497 | 498 | sigmund@~1.0.0: 499 | version "1.0.1" 500 | resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" 501 | 502 | source-map@~0.2.0: 503 | version "0.2.0" 504 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.2.0.tgz#dab73fbcfc2ba819b4de03bd6f6eaa48164b3f9d" 505 | dependencies: 506 | amdefine ">=0.0.4" 507 | 508 | source-map@~0.4.0, source-map@~0.4.2: 509 | version "0.4.4" 510 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" 511 | dependencies: 512 | amdefine ">=0.0.4" 513 | 514 | split@0.3: 515 | version "0.3.3" 516 | resolved "https://registry.yarnpkg.com/split/-/split-0.3.3.tgz#cd0eea5e63a211dfff7eb0f091c4133e2d0dd28f" 517 | dependencies: 518 | through "2" 519 | 520 | stream-combiner2@~1.0.0: 521 | version "1.0.2" 522 | resolved "https://registry.yarnpkg.com/stream-combiner2/-/stream-combiner2-1.0.2.tgz#ba72a6b50cbfabfa950fc8bc87604bd01eb60671" 523 | dependencies: 524 | duplexer2 "~0.0.2" 525 | through2 "~0.5.1" 526 | 527 | stream-combiner@~0.0.4: 528 | version "0.0.4" 529 | resolved "https://registry.yarnpkg.com/stream-combiner/-/stream-combiner-0.0.4.tgz#4d5e433c185261dde623ca3f44c586bcf5c4ad14" 530 | dependencies: 531 | duplexer "~0.1.1" 532 | 533 | string_decoder@~0.10.x: 534 | version "0.10.31" 535 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" 536 | 537 | subarg@^1.0.0: 538 | version "1.0.0" 539 | resolved "https://registry.yarnpkg.com/subarg/-/subarg-1.0.0.tgz#f62cf17581e996b48fc965699f54c06ae268b8d2" 540 | dependencies: 541 | minimist "^1.1.0" 542 | 543 | supports-color@1.2.0: 544 | version "1.2.0" 545 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-1.2.0.tgz#ff1ed1e61169d06b3cf2d588e188b18d8847e17e" 546 | 547 | tern@^0.15.0: 548 | version "0.15.0" 549 | resolved "https://registry.yarnpkg.com/tern/-/tern-0.15.0.tgz#682762384c09b110545ab9101e1977ff28ef7c15" 550 | dependencies: 551 | acorn "^2.3.0" 552 | glob "3" 553 | minimatch "0.2" 554 | typescript "=1.0.1" 555 | 556 | tern@^0.16.0: 557 | version "0.16.0" 558 | resolved "https://registry.yarnpkg.com/tern/-/tern-0.16.0.tgz#c695b4092a724b95d09b75cffb50780876452a16" 559 | dependencies: 560 | acorn "^2.5.2" 561 | glob "3" 562 | minimatch "0.2" 563 | typescript "=1.0.1" 564 | 565 | through2@^1.0.0: 566 | version "1.1.1" 567 | resolved "https://registry.yarnpkg.com/through2/-/through2-1.1.1.tgz#0847cbc4449f3405574dbdccd9bb841b83ac3545" 568 | dependencies: 569 | readable-stream ">=1.1.13-1 <1.2.0-0" 570 | xtend ">=4.0.0 <4.1.0-0" 571 | 572 | through2@~0.5.1: 573 | version "0.5.1" 574 | resolved "https://registry.yarnpkg.com/through2/-/through2-0.5.1.tgz#dfdd012eb9c700e2323fd334f38ac622ab372da7" 575 | dependencies: 576 | readable-stream "~1.0.17" 577 | xtend "~3.0.0" 578 | 579 | through@2, "through@>=2.2.7 <3", through@~2.3, through@~2.3.1: 580 | version "2.3.8" 581 | resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" 582 | 583 | to-iso-string@0.0.2: 584 | version "0.0.2" 585 | resolved "https://registry.yarnpkg.com/to-iso-string/-/to-iso-string-0.0.2.tgz#4dc19e664dfccbe25bd8db508b00c6da158255d1" 586 | 587 | type-check@~0.3.2: 588 | version "0.3.2" 589 | resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" 590 | dependencies: 591 | prelude-ls "~1.1.2" 592 | 593 | typedarray@~0.0.5: 594 | version "0.0.6" 595 | resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" 596 | 597 | typescript@=1.0.1: 598 | version "1.0.1" 599 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-1.0.1.tgz#e8eacde3084a091d3fe29b60ac5862252662a25a" 600 | 601 | umd@^3.0.0: 602 | version "3.0.1" 603 | resolved "https://registry.yarnpkg.com/umd/-/umd-3.0.1.tgz#8ae556e11011f63c2596708a8837259f01b3d60e" 604 | 605 | underscore@^1.8.3: 606 | version "1.8.3" 607 | resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.8.3.tgz#4f3fb53b106e6097fcf9cb4109f2a5e9bdfa5022" 608 | 609 | util-extend@^1.0.1: 610 | version "1.0.3" 611 | resolved "https://registry.yarnpkg.com/util-extend/-/util-extend-1.0.3.tgz#a7c216d267545169637b3b6edc6ca9119e2ff93f" 612 | 613 | wordwrap@~1.0.0: 614 | version "1.0.0" 615 | resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" 616 | 617 | "xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0: 618 | version "4.0.1" 619 | resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" 620 | 621 | xtend@~3.0.0: 622 | version "3.0.0" 623 | resolved "https://registry.yarnpkg.com/xtend/-/xtend-3.0.0.tgz#5cce7407baf642cba7becda568111c493f59665a" 624 | --------------------------------------------------------------------------------