├── LICENSE ├── Makefile ├── README.md ├── example ├── closure.cpp ├── closure.js ├── dynamic.cpp ├── dynamic.js ├── exception.cpp ├── exception.js ├── fannkuch.cpp ├── fannkuch.js ├── function.cpp ├── function.js ├── iteration.cpp ├── iteration.js ├── json.cpp ├── json.js ├── prototype.cpp ├── prototype.js ├── reference.cpp ├── reference.js ├── scope.cpp ├── scope.js ├── this.cpp └── this.js └── src ├── constructors.h ├── javascript_end.h ├── javascript_start.h ├── object.h ├── operators.h ├── stdlib.h └── underscore.h /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Christopher Chedeau. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | CC = g++ 3 | CFLAGS = -Wall -std=gnu++0x 4 | FILES = $(wildcard example/*.cpp) 5 | TARGETS = $(FILES:.cpp=.jspp) 6 | 7 | all: $(TARGETS) 8 | 9 | %.jspp: %.cpp 10 | $(CC) -o $@ $< $(CFLAGS) 11 | 12 | clean: 13 | rm $(TARGETS) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | JSPP 2 | ===== 3 | 4 | C++ has a new standard called C++0x ([Wikipedia](http://en.wikipedia.org/wiki/C%2B%2B0x), [Bjarne Stroustrup](http://www2.research.att.com/~bs/C++0xFAQ.html)) that includes many interesting features such as Lambda, For Each, List Initialization ... Those features are so powerful that they allow to write C++ as if it was Javascript. 5 | 6 | The goal of this project is to transform C++ into Javascript. We want to be able to copy & paste Javascript into C++ and be able to run it. While this is not 100% feasible, the result is quite amazing. 7 | 8 | **This is only a prototype**. In about 600 lines of code we manage to make the core of the Javascript language. 9 | 10 | >> [Read the full description on my blog](http://blog.vjeux.com/2011/javascript/jspp-morph-cpp-into-javascript.html) 11 | ============== 12 | 13 | ChangeLog 14 | ------ 15 | 16 | * May 11 2011 - Removed `var` in `catch(var e)`. Removed `_()` in `throw _("e")`. `This` and `New` can be written in lowercase. 17 | * April 26 2011 - `for (var key : obj)` is now `for (var key in obj)`. Thanks [Rip-Rip](https://github.com/Rip-Rip/) -------------------------------------------------------------------------------- /example/closure.cpp: -------------------------------------------------------------------------------- 1 | #include "../src/javascript_start.h" 2 | 3 | var container = function (var data) { 4 | var secret = data; 5 | 6 | return { 7 | _["set"] = function (var x) { secret |= x; return undefined; }, 8 | _["get"] = function () { return secret; } 9 | }; 10 | }; 11 | 12 | var a = container("secret-a"); 13 | var b = container("secret-b"); 14 | 15 | a["set"]("override-a"); 16 | 17 | std::cout << a["get"]() << std::endl; 18 | std::cout << b["get"]() << std::endl; 19 | 20 | #include "../src/javascript_end.h" 21 | -------------------------------------------------------------------------------- /example/closure.js: -------------------------------------------------------------------------------- 1 | 2 | var container = function (data) { 3 | var secret = data; 4 | 5 | return { 6 | set: function (x) { secret = x; }, 7 | get: function () { return secret; } 8 | }; 9 | }; 10 | 11 | var a = container("secret-a"); 12 | var b = container("secret-b"); 13 | 14 | a.set("override-a"); 15 | 16 | console.log(a.get()); // override-a 17 | console.log(b.get()); // secret-b 18 | -------------------------------------------------------------------------------- /example/dynamic.cpp: -------------------------------------------------------------------------------- 1 | #include "../src/javascript_start.h" 2 | 3 | var repeat = function (var str, var times) { 4 | var ret = ""; 5 | for (var i = 0; i < times; ++i) { 6 | ret += str + i; 7 | } 8 | return ret; 9 | }; 10 | 11 | std::cout << repeat(" js++", 3) << std::endl; 12 | // " js++0 js++1 js++2" 13 | 14 | #include "../src/javascript_end.h" 15 | -------------------------------------------------------------------------------- /example/dynamic.js: -------------------------------------------------------------------------------- 1 | 2 | var repeat = function (str, times) { 3 | var ret = ""; 4 | for (var i = 0; i < times; ++i) { 5 | ret += str + i; 6 | } 7 | return ret; 8 | }; 9 | 10 | console.log(repeat(" js++", 3)); 11 | // " js++0 js++1 js++2" 12 | -------------------------------------------------------------------------------- /example/exception.cpp: -------------------------------------------------------------------------------- 1 | #include "../src/javascript_start.h" 2 | 3 | var go_die = function () { 4 | throw "Exception!"; 5 | }; 6 | 7 | try { 8 | go_die(); 9 | } catch (e) { 10 | std::cout << "Error: " << e << std::endl; 11 | } 12 | // Error: Exception! 13 | 14 | #include "../src/javascript_end.h" 15 | -------------------------------------------------------------------------------- /example/exception.js: -------------------------------------------------------------------------------- 1 | 2 | var go_die = function () { 3 | throw "Exception!"; 4 | }; 5 | 6 | try { 7 | go_die(); 8 | } catch (e) { 9 | console.log("Error:", e); 10 | } 11 | // Error: Exception! 12 | 13 | -------------------------------------------------------------------------------- /example/fannkuch.cpp: -------------------------------------------------------------------------------- 1 | #include "../src/javascript_start.h" 2 | 3 | // www.webkit.org/perf/sunspider-0.9/access-fannkuch.html 4 | 5 | var fannkuch = function (var n) { 6 | var check = 0; 7 | var perm = Array(n); 8 | var perm1 = Array(n); 9 | var count = Array(n); 10 | var maxPerm = Array(n); 11 | var maxFlipsCount = 0; 12 | var m = n - 1; 13 | 14 | for (var i = 0; i < n; i++) perm1[i] = i; 15 | var r = n; 16 | 17 | while (true) { 18 | while (r != 1) { count[r - 1] = r; r--; } 19 | if (!(perm1[0] == 0 || perm1[m] == m)) { 20 | for (var i = 0; i < n; i++) perm[i] = perm1[i]; 21 | 22 | var flipsCount = 0; 23 | var k; 24 | 25 | while (!((k = perm[0]) == 0)) { 26 | var k2 = (k + 1) >> 1; 27 | for (var i = 0; i < k2; i++) { 28 | var temp = perm[i]; perm[i] = perm[k - i]; perm[k - i] = temp; 29 | } 30 | flipsCount++; 31 | } 32 | 33 | if (flipsCount > maxFlipsCount) { 34 | maxFlipsCount = flipsCount; 35 | for (var i = 0; i < n; i++) maxPerm[i] = perm1[i]; 36 | } 37 | } 38 | 39 | while (true) { 40 | if (r == n) return maxFlipsCount; 41 | var perm0 = perm1[0]; 42 | var i = 0; 43 | while (i < r) { 44 | var j = i + 1; 45 | perm1[i] = perm1[j]; 46 | i = j; 47 | } 48 | perm1[r] = perm0; 49 | 50 | count[r] = count[r] - 1; 51 | if (count[r] > 0) break; 52 | r++; 53 | } 54 | } 55 | }; 56 | 57 | var n = 7; 58 | var ret = fannkuch(n); 59 | std::cout << fannkuch(n) << std::endl; 60 | 61 | #include "../src/javascript_end.h" 62 | -------------------------------------------------------------------------------- /example/fannkuch.js: -------------------------------------------------------------------------------- 1 | 2 | // www.webkit.org/perf/sunspider-0.9/access-fannkuch.html 3 | 4 | function fannkuch(n) { 5 | var check = 0; 6 | var perm = Array(n); 7 | var perm1 = Array(n); 8 | var count = Array(n); 9 | var maxPerm = Array(n); 10 | var maxFlipsCount = 0; 11 | var m = n - 1; 12 | 13 | for (var i = 0; i < n; i++) perm1[i] = i; 14 | var r = n; 15 | 16 | while (true) { 17 | while (r != 1) { count[r - 1] = r; r--; } 18 | if (!(perm1[0] == 0 || perm1[m] == m)) { 19 | for (var i = 0; i < n; i++) perm[i] = perm1[i]; 20 | 21 | var flipsCount = 0; 22 | var k; 23 | 24 | while (!((k = perm[0]) == 0)) { 25 | var k2 = (k + 1) >> 1; 26 | for (var i = 0; i < k2; i++) { 27 | var temp = perm[i]; perm[i] = perm[k - i]; perm[k - i] = temp; 28 | } 29 | flipsCount++; 30 | } 31 | 32 | if (flipsCount > maxFlipsCount) { 33 | maxFlipsCount = flipsCount; 34 | for (var i = 0; i < n; i++) maxPerm[i] = perm1[i]; 35 | } 36 | } 37 | 38 | while (true) { 39 | if (r == n) return maxFlipsCount; 40 | var perm0 = perm1[0]; 41 | var i = 0; 42 | while (i < r) { 43 | var j = i + 1; 44 | perm1[i] = perm1[j]; 45 | i = j; 46 | } 47 | perm1[r] = perm0; 48 | 49 | count[r] = count[r] - 1; 50 | if (count[r] > 0) break; 51 | r++; 52 | } 53 | } 54 | } 55 | 56 | var n = 7; 57 | var ret = fannkuch(n); 58 | console.log(ret); 59 | -------------------------------------------------------------------------------- /example/function.cpp: -------------------------------------------------------------------------------- 1 | #include "../src/javascript_start.h" 2 | 3 | var Utils = { 4 | _["map"] = function (var array, var func) { 5 | for (var i = 0; i < array["length"]; ++i) { 6 | array[i] = func(i, array[i]); 7 | } 8 | return undefined; 9 | } 10 | }; 11 | 12 | var a = {"a", "b", "c"}; 13 | std::cout << a << std::endl; 14 | // [a, b, c] 15 | 16 | Utils["map"](a, function (var key, var value) { 17 | return "(" + key + ":" + value + ")"; 18 | }); 19 | std::cout << a << std::endl; 20 | // [(0:a), (1:b), (2:c)] 21 | 22 | #include "../src/javascript_end.h" 23 | -------------------------------------------------------------------------------- /example/function.js: -------------------------------------------------------------------------------- 1 | 2 | var Utils = { 3 | "map": function (array, func) { 4 | for (var i = 0; i < array["length"]; ++i) { 5 | array[i] = func(i, array[i]); 6 | } 7 | } 8 | }; 9 | 10 | var a = ["a", "b", "c"]; 11 | console.log(a); 12 | // [a, b, c] 13 | 14 | Utils["map"](a, function (key, value) { 15 | return "(" + key + ":" + value + ")"; 16 | }); 17 | console.log(a); 18 | // [(0:a), (1:b), (2:c)] 19 | 20 | -------------------------------------------------------------------------------- /example/iteration.cpp: -------------------------------------------------------------------------------- 1 | #include "../src/javascript_start.h" 2 | 3 | var array = {10, 42, 30}; 4 | for (var i in array) { 5 | std::cout << i << " - " << array[i] << std::endl; 6 | } 7 | // 0 - 10 8 | // 1 - 42 9 | // 2 - 30 10 | // length - 3 11 | // prototype - undefined 12 | 13 | var object = { 14 | _["a"] = 1, 15 | _["b"] = 2, 16 | _["c"] = 3 17 | }; 18 | for (var i in object) { 19 | std::cout << i << " - " << object[i] << std::endl; 20 | } 21 | // a - 1 22 | // b - 2 23 | // c - 3 24 | // prototype - undefined 25 | 26 | #include "../src/javascript_end.h" 27 | -------------------------------------------------------------------------------- /example/iteration.js: -------------------------------------------------------------------------------- 1 | 2 | var array = [10, 42, 30]; 3 | for (var i in array) { 4 | console.log(i, array[i]); 5 | } 6 | // 0 - 10 7 | // 1 - 42 8 | // 2 - 30 9 | 10 | 11 | 12 | var object = { 13 | "a": 1, 14 | "b": 2, 15 | "c": 3 16 | }; 17 | for (var i in object) { 18 | console.log(i, object[i]); 19 | } 20 | // a - 1 21 | // b - 2 22 | // c - 3 23 | 24 | -------------------------------------------------------------------------------- /example/json.cpp: -------------------------------------------------------------------------------- 1 | #include "../src/javascript_start.h" 2 | 3 | var json = { 4 | _["number"] = 42, 5 | _["string"] = "vjeux", 6 | _["array"] = {1, 2, "three"}, 7 | 8 | _["nested"] = _({ 9 | _["first"] = 1 10 | }) 11 | }; 12 | 13 | std::cout << json << std::endl; 14 | // {array: [1, 2, three], nested: {first: 1}, number: 42, string: vjeux} 15 | 16 | #include "../src/javascript_end.h" 17 | -------------------------------------------------------------------------------- /example/json.js: -------------------------------------------------------------------------------- 1 | 2 | var json = { 3 | "number": 42, 4 | "string": "vjeux", 5 | "array": [1, 2, "three"], 6 | 7 | "nested": { 8 | "first": 1 9 | } 10 | }; 11 | 12 | console.log(json); 13 | // { number: 42, 14 | // string: 'vjeux', 15 | // array: [ 1, 2, 'three' ], 16 | // nested: { first: 1 } } 17 | -------------------------------------------------------------------------------- /example/prototype.cpp: -------------------------------------------------------------------------------- 1 | #include "../src/javascript_start.h" 2 | 3 | var createObject = function (var o) { 4 | var F = function () {return This;}; 5 | F["prototype"] = o; 6 | return New(F)(); 7 | }; 8 | 9 | var Person = { 10 | _["name"] = "Default", 11 | _["greet"] = function () { 12 | return "Hello world, my name is " + This["name"]; 13 | } 14 | }; 15 | 16 | var vjeux = createObject(Person); 17 | vjeux["name"] = "Vjeux"; 18 | 19 | var blog = createObject(Person); 20 | blog["name"] = "Blog"; 21 | 22 | var def = createObject(Person); 23 | 24 | std::cout << vjeux["greet"]() << std::endl; // Vjeux 25 | std::cout << blog["greet"]() << std::endl; // Blog 26 | std::cout << def["greet"]() << std::endl; // Default 27 | 28 | #include "../src/javascript_end.h" 29 | -------------------------------------------------------------------------------- /example/prototype.js: -------------------------------------------------------------------------------- 1 | 2 | var createObject = function (o) { 3 | var F = function () {}; 4 | F["prototype"] = o; 5 | return new F(); 6 | }; 7 | 8 | var Person = { 9 | name: "Default", 10 | greet: function () { 11 | return "Hello world, my name is " + this.name; 12 | } 13 | }; 14 | 15 | var vjeux = createObject(Person); 16 | vjeux.name = "Vjeux"; 17 | 18 | var blog = createObject(Person); 19 | blog.name = "Blog"; 20 | 21 | var def = createObject(Person); 22 | 23 | console.log(vjeux.greet()); // Vjeux 24 | console.log(blog.greet()); // Blog 25 | console.log(def.greet()); // Default 26 | -------------------------------------------------------------------------------- /example/reference.cpp: -------------------------------------------------------------------------------- 1 | #include "../src/javascript_start.h" 2 | 3 | 4 | var a = {}; 5 | a["key"] = "old"; 6 | 7 | var b = a; 8 | b["key"] = "new"; 9 | 10 | std::cout << a["key"] << " " << b["key"] << std::endl; 11 | // new new 12 | 13 | 14 | #include "../src/javascript_end.h" 15 | -------------------------------------------------------------------------------- /example/reference.js: -------------------------------------------------------------------------------- 1 | 2 | var a = {}; 3 | a["key"] = "old"; 4 | 5 | var b = a; 6 | b["key"] = "new"; 7 | 8 | console.log(a["key"], b["key"]); 9 | // new new 10 | -------------------------------------------------------------------------------- /example/scope.cpp: -------------------------------------------------------------------------------- 1 | #include "../src/javascript_start.h" 2 | 3 | var global = "global"; 4 | var $ = "prototype"; 5 | var jQuery = "jQuery"; 6 | 7 | _(function (var $) { 8 | var global = "local"; 9 | 10 | std::cout << "Inside: $ = " << $ << std::endl; 11 | std::cout << "Inside: global = " << global << std::endl; 12 | 13 | // Inside: $ = jQuery 14 | // Inside: global = local 15 | 16 | return undefined; 17 | })(jQuery); 18 | 19 | std::cout << "Outside: $ = " << $ << std::endl; 20 | std::cout << "Outside: global = " << global << std::endl; 21 | 22 | // Outside: $ = prototype 23 | // Outside: global = global 24 | 25 | #include "../src/javascript_end.h" 26 | -------------------------------------------------------------------------------- /example/scope.js: -------------------------------------------------------------------------------- 1 | 2 | var global = "global"; 3 | var $ = "prototype"; 4 | var jQuery = "jQuery"; 5 | 6 | (function ($) { 7 | var global = "local"; 8 | 9 | console.log("Inside: $ = ", $); 10 | console.log("Inside: global = ", global); 11 | 12 | // Inside: $ = jQuery 13 | // Inside: global = local 14 | 15 | return undefined; 16 | })(jQuery); 17 | 18 | console.log("Outside: $ = ", $); 19 | console.log("Outside: global = ", global); 20 | 21 | // Outside: $ = prototype 22 | // Outside: global = global 23 | 24 | -------------------------------------------------------------------------------- /example/this.cpp: -------------------------------------------------------------------------------- 1 | #include "../src/javascript_start.h" 2 | 3 | var f = function (var x, var y) { 4 | std::cout << "this: " << this << std::endl; 5 | this["x"] = x; 6 | this["y"] = y; 7 | 8 | return this; 9 | }; 10 | 11 | // new creates a new object this 12 | var a = new (f)(1, 2); // this: 13 | var b = new (f)(3, 4); // this: 14 | 15 | // Unbound call, 16 | var c = f(5, 6); // this: undefined 17 | 18 | // Bound call 19 | var obj = {42}; 20 | obj["f"] = f; 21 | 22 | var d = obj["f"](1, 2); // this: [42] 23 | 24 | // Call 25 | var e = f["call"](obj, 1, 2); // this: [42] 26 | 27 | #include "../src/javascript_end.h" 28 | -------------------------------------------------------------------------------- /example/this.js: -------------------------------------------------------------------------------- 1 | 2 | var f = function (x, y) { 3 | console.log("this:", this); 4 | this["x"] = x; 5 | this["y"] = y; 6 | }; 7 | 8 | // New creates a new object this 9 | var a = new f(1, 2); // this: 10 | var b = new f(3, 4); // this: 11 | 12 | // Unbound call, 13 | var c = f(5, 6); // this: global object 14 | 15 | // Bound call 16 | var obj = [42]; 17 | obj["f"] = f; 18 | 19 | var d = obj["f"](1, 2); // this: [42] 20 | 21 | // Call 22 | var e = f["call"](obj, 1, 2); // this: [42] 23 | 24 | -------------------------------------------------------------------------------- /src/constructors.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | Object& Object::operator= (Object o) { 4 | write->s = o.s; 5 | write->s->refcount += 1; 6 | return *write; 7 | } 8 | 9 | Object& Object::operator|= (Object o) { 10 | write->s->refcount += 1; 11 | 12 | write->s->type = o.s->type; 13 | write->s->s = o.s->s; 14 | write->s->n = o.s->n; 15 | write->s->map = o.s->map; 16 | write->s->kv = o.s->kv; 17 | 18 | write->s->f = o.s->f; 19 | write->s->f0 = o.s->f0; 20 | write->s->f1 = o.s->f1; 21 | write->s->f2 = o.s->f2; 22 | write->s->f3 = o.s->f3; 23 | write->s->f4 = o.s->f4; 24 | write->s->f5 = o.s->f5; 25 | 26 | return *write; 27 | } 28 | 29 | Object::Object(const Object& o) : self(o.self), write(this), s(o.s) { 30 | s->refcount += 1; 31 | } 32 | 33 | Object::Object() : self(&undefined), write(this), s(new State) { 34 | s->type = UNDEFINED; 35 | } 36 | 37 | Object::Object(double n) : self(&undefined), write(this), s(new State) { 38 | s->n = n; 39 | s->type = NUMBER; 40 | } 41 | 42 | Object::Object(int n) : self(&undefined), write(this), s(new State) { 43 | s->n = n; 44 | s->type = NUMBER; 45 | } 46 | 47 | Object::Object(bool b) : self(&undefined), write(this), s(new State) { 48 | s->n = b ? 1 : 0; 49 | s->type = NUMBER; 50 | } 51 | 52 | Object::Object(const char* str) : self(&undefined), write(this), s(new State) { 53 | s->s = str; 54 | s->type = STRING; 55 | } 56 | 57 | Object::Object(std::string str) : self(&undefined), write(this), s(new State) { 58 | s->s = str; 59 | s->type = STRING; 60 | } 61 | 62 | template // Function 63 | Object::Object(F f) : self(&undefined), write(this), s(new State) 64 | { 65 | set_func(f, &F::operator()); 66 | s->type = FUNCTION; 67 | s->map["prototype"] = global["Function"]; 68 | } 69 | 70 | 71 | Object::Object(std::pair, Object> it) : self(&undefined), write(this), s(new State) { 72 | s->s = it.first; 73 | s->type = STRING; 74 | } 75 | 76 | 77 | Object::Object(std::initializer_list list) : self(&undefined), write(this), s(new State) { 78 | int length = 0; 79 | 80 | for (auto elem : list) 81 | if (elem.s->type == KEYVALUE) { 82 | (*this)[elem.s->kv->key] = elem.s->kv->value; 83 | } else { 84 | (*this)[length++] = elem; 85 | } 86 | 87 | if (length > 0) { 88 | (*this)["length"] = length; 89 | s->type = ARRAY; 90 | } else { 91 | s->type = OBJECT; 92 | } 93 | } 94 | 95 | Object::Object(KeyValue& kv) : self(&undefined), write(this), s(new State) { 96 | s->type = KEYVALUE; 97 | s->kv = &kv; 98 | } 99 | 100 | Object New(Object o) { 101 | Object n; 102 | 103 | n.s->type = FUNCTION; 104 | n.s->f = o.s->f; 105 | n.s->f0 = o.s->f0; 106 | n.s->f1 = o.s->f1; 107 | n.s->f2 = o.s->f2; 108 | n.s->f3 = o.s->f3; 109 | n.s->f4 = o.s->f4; 110 | n.s->f5 = o.s->f5; 111 | 112 | n.self = &n; 113 | n["__proto__"] = o["prototype"]; 114 | 115 | return n; 116 | } 117 | -------------------------------------------------------------------------------- /src/javascript_end.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | } catch (e) { 4 | std::cout << "Uncatched error: " << e << std::endl; 5 | } 6 | 7 | #ifdef _WIN32 8 | system("pause"); 9 | #endif 10 | } 11 | -------------------------------------------------------------------------------- /src/javascript_start.h: -------------------------------------------------------------------------------- 1 | 2 | #include "object.h" 3 | #include "underscore.h" 4 | #include "operators.h" 5 | #include "constructors.h" 6 | 7 | #define catch(e) catch(var e) 8 | #define throw throw _= 9 | #define this This 10 | #define new New 11 | #define in : 12 | #define function(...) [=] (var This, ##__VA_ARGS__) mutable -> Object 13 | 14 | int main() 15 | { 16 | try { 17 | 18 | #include "stdlib.h" 19 | -------------------------------------------------------------------------------- /src/object.h: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | enum Types { 11 | NUMBER, 12 | STRING, 13 | FUNCTION, 14 | UNDEFINED, 15 | NULLL, 16 | OBJECT, 17 | ARRAY, 18 | KEYVALUE 19 | }; 20 | 21 | class Object; 22 | class KeyValue; 23 | 24 | class State 25 | { 26 | public: 27 | State() : refcount(1) {} 28 | int refcount; 29 | 30 | std::map map; 31 | int type; 32 | 33 | double n; 34 | std::string s; 35 | int f; 36 | std::function f0; 37 | std::function f1; 38 | std::function f2; 39 | std::function f3; 40 | std::function f4; 41 | std::function f5; 42 | KeyValue* kv; 43 | }; 44 | 45 | 46 | class Object { 47 | public: 48 | 49 | ~Object() { 50 | if (s->refcount == 1) { 51 | delete s; 52 | } else { 53 | s->refcount -= 1; 54 | } 55 | } 56 | 57 | // Constructors 58 | 59 | 60 | Object& operator= (Object o); 61 | Object& operator|= (Object o); 62 | Object(const Object& o); 63 | Object(); 64 | Object(double n); 65 | Object(int n); 66 | Object(bool b); 67 | Object(const char* str); 68 | Object(std::string str); 69 | Object(std::initializer_list list); 70 | Object(std::pair, Object> it); 71 | Object(KeyValue& kv); 72 | template Object(F f); 73 | 74 | 75 | // Methods 76 | 77 | Object operator()(); 78 | Object operator()(Object); 79 | Object operator()(Object, Object); 80 | Object operator()(Object, Object, Object); 81 | Object operator()(Object, Object, Object, Object); 82 | Object operator()(Object, Object, Object, Object, Object); 83 | 84 | std::string toString(); 85 | Object& get_key(std::string key); 86 | Object& operator[](Object key); 87 | 88 | Object* self; 89 | Object* write; 90 | State* s; 91 | 92 | 93 | std::map::iterator begin() { 94 | return s->map.begin(); 95 | } 96 | 97 | std::map::iterator end() { 98 | return s->map.end(); 99 | } 100 | 101 | protected: 102 | 103 | /* Functions */ 104 | // http://stackoverflow.com/questions/4170201/c0x-overloading-on-lambda-arity 105 | 106 | /* 0 param */ 107 | template 108 | void set_func(F& f, Object (F::*mf)(Object)) 109 | { s->f = 0; s->f0 = f; } 110 | 111 | /* 1 param */ 112 | template 113 | void set_func(F& f, Object (F::*mf)(Object, Object)) 114 | { s->f = 1; s->f1 = f; } 115 | 116 | /* 2 param */ 117 | template 118 | void set_func(F& f, Object (F::*mf)(Object, Object, Object)) 119 | { s->f = 2; s->f2 = f; } 120 | 121 | /* 3 param */ 122 | template 123 | void set_func(F& f, Object (F::*mf)(Object, Object, Object, Object)) 124 | { s->f = 3; s->f3 = f; } 125 | 126 | /* 4 param */ 127 | template 128 | void set_func(F& f, Object (F::*mf)(Object, Object, Object, Object, Object)) 129 | { s->f = 4; s->f4 = f; } 130 | 131 | /* 5 param */ 132 | template 133 | void set_func(F& f, Object (F::*mf)(Object, Object, Object, Object, Object, Object)) 134 | { s->f = 5; s->f5 = f; } 135 | }; 136 | 137 | std::ostream& operator<<(std::ostream& stream, Object o) { 138 | stream << o.toString(); 139 | return stream; 140 | } 141 | 142 | typedef Object var; 143 | 144 | Object undefined; 145 | Object global; 146 | -------------------------------------------------------------------------------- /src/operators.h: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | double NaN = std::numeric_limits::quiet_NaN(); 4 | 5 | Object Object::operator()() { 6 | if (s->type != FUNCTION) { throw _("Object is not a function"); } 7 | if (s->f == 0) return s->f0(*self); 8 | if (s->f == 1) return s->f1(*self, undefined); 9 | if (s->f == 2) return s->f2(*self, undefined, undefined); 10 | if (s->f == 3) return s->f3(*self, undefined, undefined, undefined); 11 | if (s->f == 4) return s->f4(*self, undefined, undefined, undefined, undefined); 12 | if (s->f == 5) return s->f5(*self, undefined, undefined, undefined, undefined, undefined); 13 | throw _("Too many arguments"); 14 | } 15 | 16 | Object Object::operator()(Object a) { 17 | if (s->type != FUNCTION) { throw _("Object is not a function"); } 18 | if (s->f == 0) return s->f0(*self); 19 | if (s->f == 1) return s->f1(*self, a); 20 | if (s->f == 2) return s->f2(*self, a, undefined); 21 | if (s->f == 3) return s->f3(*self, a, undefined, undefined); 22 | if (s->f == 4) return s->f4(*self, a, undefined, undefined, undefined); 23 | if (s->f == 5) return s->f5(*self, a, undefined, undefined, undefined, undefined); 24 | throw _("Too many arguments"); 25 | } 26 | 27 | Object Object::operator()(Object a, Object b) { 28 | if (s->type != FUNCTION) { throw _("Object is not a function"); } 29 | if (s->f == 0) return s->f0(*self); 30 | if (s->f == 1) return s->f1(*self, a); 31 | if (s->f == 2) return s->f2(*self, a, b); 32 | if (s->f == 3) return s->f3(*self, a, b, undefined); 33 | if (s->f == 4) return s->f4(*self, a, b, undefined, undefined); 34 | if (s->f == 5) return s->f5(*self, a, b, undefined, undefined, undefined); 35 | throw _("Too many arguments"); 36 | } 37 | 38 | Object Object::operator()(Object a, Object b, Object c) { 39 | if (s->type != FUNCTION) { throw _("Object is not a function"); } 40 | if (s->f == 0) return s->f0(*self); 41 | if (s->f == 1) return s->f1(*self, a); 42 | if (s->f == 2) return s->f2(*self, a, b); 43 | if (s->f == 3) return s->f3(*self, a, b, c); 44 | if (s->f == 4) return s->f4(*self, a, b, c, undefined); 45 | if (s->f == 5) return s->f5(*self, a, b, c, undefined, undefined); 46 | throw _("Too many arguments"); 47 | } 48 | 49 | Object Object::operator()(Object a, Object b, Object c, Object d) { 50 | if (s->type != FUNCTION) { throw _("Object is not a function"); } 51 | if (s->f == 0) return s->f0(*self); 52 | if (s->f == 1) return s->f1(*self, a); 53 | if (s->f == 2) return s->f2(*self, a, b); 54 | if (s->f == 3) return s->f3(*self, a, b, c); 55 | if (s->f == 4) return s->f4(*self, a, b, c, d); 56 | if (s->f == 5) return s->f5(*self, a, b, c, d, undefined); 57 | throw _("Too many arguments"); 58 | } 59 | 60 | Object Object::operator()(Object a, Object b, Object c, Object d, Object e) { 61 | if (s->type != FUNCTION) { throw _("Object is not a function"); } 62 | if (s->f == 0) return s->f0(*self); 63 | if (s->f == 1) return s->f1(*self, a); 64 | if (s->f == 2) return s->f2(*self, a, b); 65 | if (s->f == 3) return s->f3(*self, a, b, c); 66 | if (s->f == 4) return s->f4(*self, a, b, c, d); 67 | if (s->f == 5) return s->f5(*self, a, b, c, d, e); 68 | throw _("Too many arguments"); 69 | } 70 | 71 | 72 | Object operator >>(Object a, Object b) { 73 | if (a.s->type == NUMBER && b.s->type == NUMBER) { 74 | return (int)a.s->n >> (int)b.s->n; 75 | } 76 | throw Object("Unfinished operator>>"); 77 | } 78 | 79 | 80 | Object operator +(Object a, Object b) { 81 | if (a.s->type == NUMBER && b.s->type == NUMBER) { 82 | return a.s->n + b.s->n; 83 | } 84 | return a.toString() + b.toString(); 85 | } 86 | 87 | Object operator -(Object a, Object b) { 88 | if (a.s->type == NUMBER && b.s->type == NUMBER) { 89 | return a.s->n - b.s->n; 90 | } 91 | return NaN; 92 | } 93 | 94 | bool operator ==(Object a, Object b) { 95 | if (a.s->type == UNDEFINED && b.s->type == UNDEFINED) { 96 | return true; 97 | } 98 | if (a.s->type == NUMBER && b.s->type == NUMBER) { 99 | return a.s->n == b.s->n; 100 | } 101 | if (a.s->type == STRING && b.s->type == STRING) { 102 | return a.s->s == b.s->s; 103 | } 104 | return a.s == b.s; 105 | } 106 | 107 | bool operator !=(Object a, Object b) { 108 | return !(a == b); 109 | } 110 | 111 | Object operator *(Object a, Object b) { 112 | if (a.s->type == NUMBER && b.s->type == NUMBER) { 113 | return a.s->n * a.s->n; 114 | } 115 | return NaN; 116 | } 117 | 118 | Object operator /(Object a, Object b) { 119 | if (a.s->type == NUMBER && b.s->type == NUMBER) { 120 | return a.s->n / a.s->n; 121 | } 122 | return NaN; 123 | } 124 | 125 | Object& operator -=(Object& a, Object b) { 126 | a = a - b; 127 | return a; 128 | } 129 | 130 | Object& operator +=(Object& a, Object b) { 131 | a = a + b; 132 | return a; 133 | } 134 | 135 | Object& operator /=(Object& a, Object b) { 136 | a = a / b; 137 | return a; 138 | } 139 | 140 | Object& operator *=(Object& a, Object b) { 141 | a = a * b; 142 | return a; 143 | } 144 | 145 | Object& operator ++(Object& a) { 146 | a += 1; 147 | return a; 148 | } 149 | 150 | Object& operator --(Object& a) { 151 | a -= 1; 152 | return a; 153 | } 154 | 155 | Object& operator --(Object& a, int) { 156 | a -= 1; 157 | return a; 158 | } 159 | 160 | Object& operator ++(Object& a, int) { 161 | a += 1; 162 | return a; 163 | } 164 | /* 165 | bool operator !(Object a) { 166 | if (a.s->type == NUMBER) { 167 | return a.s->n == 0; 168 | } 169 | return a.toString() == ""; 170 | } 171 | */ 172 | 173 | bool operator <(Object a, Object b) { 174 | if (a.s->type == NUMBER && b.s->type == NUMBER) { 175 | return a.s->n < b.s->n; 176 | } 177 | return a.toString() < b.toString(); 178 | } 179 | 180 | bool operator <=(Object a, Object b) { 181 | if (a.s->type == NUMBER && b.s->type == NUMBER) { 182 | return a.s->n <= b.s->n; 183 | } 184 | return a.toString() <= b.toString(); 185 | } 186 | 187 | bool operator >(Object a, Object b) { 188 | return !(a <= b); 189 | } 190 | 191 | bool operator >=(Object a, Object b) { 192 | return !(a < b); 193 | } 194 | 195 | 196 | std::string Object::toString() { 197 | if (s->type == STRING) { 198 | return s->s; 199 | } 200 | 201 | if (s->type == NUMBER) { 202 | std::ostringstream stream; 203 | stream << s->n; 204 | return stream.str(); 205 | } 206 | 207 | if (s->type == UNDEFINED) { 208 | return "undefined"; 209 | } 210 | 211 | if (s->type == NULLL) { 212 | return "null"; 213 | } 214 | 215 | if (s->type == FUNCTION) { 216 | std::ostringstream stream; 217 | stream << ""; 218 | return stream.str(); 219 | } 220 | 221 | if (s->type == OBJECT) { 222 | std::ostringstream stream; 223 | stream << "{"; 224 | 225 | bool first = true; 226 | for (auto it = this->s->map.begin(); it != this->s->map.end(); ++it) { 227 | if (it->second != undefined) { 228 | if (!first) { 229 | stream << ", "; 230 | } 231 | first = false; 232 | stream << it->first << ": " << it->second; 233 | } 234 | } 235 | 236 | stream << "}"; 237 | return stream.str(); 238 | } 239 | 240 | if (s->type == ARRAY) { 241 | var length = (*this)["length"]; 242 | std::ostringstream stream; 243 | stream << "["; 244 | 245 | for (var i = 0; i < length; ++i) { 246 | stream << (*this)[i]; 247 | if (i != length - 1) { 248 | stream << ", "; 249 | } 250 | } 251 | 252 | stream << "]"; 253 | return stream.str(); 254 | } 255 | 256 | 257 | throw _("Unknown type"); 258 | } 259 | 260 | 261 | Object& Object::get_key(std::string key) { 262 | Object& ret = s->map[key]; 263 | if (ret == undefined && s->map["__proto__"] != undefined) { 264 | return s->map["__proto__"].get_key(key); 265 | } 266 | return ret; 267 | } 268 | 269 | Object& Object::operator[](Object key) { 270 | std::string key_str = key.toString(); 271 | Object& ret = get_key(key_str); 272 | ret.self = this; 273 | ret.write = &s->map[key_str]; 274 | return ret; 275 | } 276 | 277 | -------------------------------------------------------------------------------- /src/stdlib.h: -------------------------------------------------------------------------------- 1 | // Initialize with a dummy value first or it'll go into an infinite loop 2 | global["Function"] = "Function"; 3 | global["Function"] = function(var s) { 4 | throw _("Cannot eval in C++ sorry :("); 5 | }; 6 | global["Function"]["prototype"] = {}; 7 | global["Function"]["prototype"]["call"] = function (var self, var a, var b, var c, var d) { 8 | This.self = &self; 9 | return This(a, b, c, d); 10 | }; 11 | var Function = global["Function"]; 12 | 13 | global["typeof"] = function (Object o) { 14 | if (o.s->type == NUMBER) { 15 | return "number"; 16 | } 17 | if (o.s->type == STRING) { 18 | return "string"; 19 | } 20 | if (o.s->type == UNDEFINED) { 21 | return "undefined"; 22 | } 23 | if (o.s->type == NULLL) { 24 | return "null"; 25 | } 26 | if (o.s->type == OBJECT) { 27 | return "object"; 28 | } 29 | return undefined; 30 | }; 31 | var Typeof = global["typeof"]; 32 | 33 | global["Array"] = function () { 34 | return {}; 35 | }; 36 | var Array = global["Array"]; 37 | -------------------------------------------------------------------------------- /src/underscore.h: -------------------------------------------------------------------------------- 1 | 2 | struct KeyValue { 3 | KeyValue(std::string k) : key(k) { 4 | } 5 | 6 | KeyValue& operator=(Object v) { 7 | this->value = v; 8 | return *this; 9 | } 10 | 11 | Object key; 12 | Object value; 13 | }; 14 | 15 | class Underscore { 16 | public: 17 | Object operator() (Object a) { 18 | return a; 19 | } 20 | KeyValue& operator[] (Object key) { 21 | KeyValue* kv = new KeyValue(key.toString()); 22 | return *kv; 23 | } 24 | 25 | Object operator= (Object a) { 26 | return a; 27 | } 28 | }; 29 | Underscore _; 30 | 31 | --------------------------------------------------------------------------------