`
javayestome
  • 浏览: 1041165 次
  • 性别: Icon_minigender_2
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

JSPP – Morph C++ Into Javascript

阅读更多

C++ has a new standard called C++0x (Wikipedia,Bjarne Stroustrup) 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.

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.

This is only a prototype. In about 600 lines of code we manage to make the core of the Javascript language.

You can view the source and compile examples at theJSPP Github Repository.

JSON

The Javascript Object notation can be emulated thanks to C++0x initialization lists and a bit of operator overload hackery._has an operator[]that returns aKeyValueobject, that has an operator=overload that fills both keys and values. For each value of the initialization listL If that's an objet, it is treated like anArray(add one to the lenght and use the length as key). If that's aKeyValue, both key and value are set.

There is an ambiguity with nested initialization lists, we use_()to cast the list into an Object. It is probably possible to fix it.

C++
var json = {
    _["number"] = 42,
    _["string"] = "vjeux",
    _["array"] = {1, 2, "three"},

    _["nested"] = _({
        _["first"] = 1
    })
};

std::cout < < json;
// {array: [1, 2, three], nested: {first: 1},
//  number: 42, string: vjeux}
Javascript
var json = {
    "number": 42,
    "string": "vjeux",
    "array": [1, 2, "three"],

    "nested": {
        "first": 1
    }
};

console.log(json);
// {number: 42, string: 'vjeux',
//  array: [1, 2, three], nested: {first: 1}}

Function

C++0x added lambda to the language with the following syntax:[capture] (arguments) -> returnType { body }.functionis a macro that transformsfunction (var i)into[=] (Object This, Object arguments, var i) -> Object. This allows to use the Javascript syntax and let us sneakily add thethisandargumentsmagic variables.

C++ is strongly typed and even lambdas have types. We can overload the Object constructor on
lambda arityand have a typed container for each one. Then, we overload the() operatorthat will call the stored lambda. We we carefully addundefinedvalues for unspecified arguments and fill theThisandargumentsvariables.

In Javascript, when a function does not return a value, it returns undefined. Sadly, we cannot have a default return value in C++, you have to write it yourself.

Since everything must be typed in C++, we have to addvarbefore the argument name.

C++
var Utils = {
  _["map"] = function (var array, var func) {
    for (var i = 0; i < array["length"]; ++i) {
      array[i] = func(i, array[i]);
    }
    return undefined;
  }
};

var a = {"a", "b", "c"};
std::cout << a;
// [a, b, c]

Utils["map"](a, function (var key, var value) {
  return "(" + key + ":" + value + ")";
});
std::cout << a;
// [(0:a), (1:b), (2:c)]
Javascript
var Utils = {
  "map": function (array, func) {
    for (var i = 0; i < array["length"]; ++i) {
      array[i] = func(i, array[i]);
    }

  }
};

var a = ["a", "b", "c"];
console.log(a);
// [a, b, c]

Utils["map"](a, function (key, value) {
  return "(" + key + ":" + value + ")";
});
console.log(a);
// [(0:a), (1:b), (2:c)]

Closure

There are two ways to capture variables with lambda in C++: either by reference or by value. What we would like is to capture by reference in order for all the variables to be bound to the same object. However, when the initial variable gets out of scope it is destroyed, and any attempt to read it results in a Segmentation Fault!

Instead, we have to capture it by value. It means that a new object is created for each lambda capturing the variable. Our objects are manipulated by reference, meaning that assigning a new value to the object will just update it and not all the other copies. We introduce a new assignement operatorobj |= valuethat updates all the copies.

C++
var container = function (var data) { 
  var secret = data;

  return {
    _["set"] = function (var x) {
        secret |= x;
        return undefined;
    },
    _["get"] = function () { return secret; }
  };
};

var a = container("secret-a");
var b = container("secret-b");

a["set"]("override-a");

std::cout < < a["get"](); // override-a
std::cout << b["get"](); // secret-b
Javascript
var container = function (data) {
  var secret = data;

  return {
    set: function (x) {
        secret = x;

    },
    get: function () { return secret; }
  };
};

var a = container("secret-a");
var b = container("secret-b");

a.set("override-a");

console.log(a.get()); // override-a
console.log(b.get()); // secret-b

This

There arefour waysto set thethisvalue:

  • Function call:foo().thisis set to the global object. As this is not a proper way to do things, I set it to undefined.
  • Method call:object.foo().thisis set toobject.
  • Constructor:new foo().foois called with a new instance ofthis.
  • Explicit:foo.call(this, arguments...). We explicitely set the this value.

All four ways are implemented in jspp but in a different way than Javascript. In Javascript, the language knows the construction and therefore can deduce whatthisis going to be. In C++, on the other hand, have a local view of what is going on. We have to develop another strategy for settingthisthat works for usual usage patterns.

We associate athisvalue for every object, by default beingundefined. If we obtain the object through another object(test.foo),thisis set to be the base object.

Newcreates a new function object withthisset to itself. Therefore it can be called to initialize the object. Contrary to Javascript, the constructor function has to returnthis.

C++
var f = function (var x, var y) {
    std::cout < < "this: " << This;
    This["x"] = x;
    This["y"] = y;
    return This;
};

// New creates a new object this
var a = New(f)(1, 2); // this: [function 40d0]
var b = New(f)(3, 4); // this: [function 48e0]

// Unbound call, 
var c = f(5, 6); // this: undefined

// Bound call
var obj = {42};
obj["f"] = f;

var d = obj["f"](1, 2); // this: [42]

// Call
var e = f["call"](obj, 1, 2); // this: [42]
Javascript
var f = function (x, y) {
    console.log("this:", this);
    this["x"] = x;
    this["y"] = y;

};

// New creates a new object this
var a = new f(1, 2); // this: [object]
var b = new f(3, 4); // this: [object]

// Unbound call, 
var c = f(5, 6); // this: global object

// Bound call
var obj = [42];
obj["f"] = f;

var d = obj["f"](1, 2); // this: [42]

// Call
var e = f["call"](obj, 1, 2); // this: [42]

Prototypal Inheritance

In order to use prototypal inheritance, we can useDouglas Crockford Object.Create.

When reading a property, we try to read it on the current object, and if it does not exist we try again on the prototype. However, when writing a property we want to write it on the object itself. Therefore the returned object contains in fact two objects, one used for reading and one for writing.

C++
var createObject = function (var o) {
    var F = function () {return This;};
    F["prototype"] = o;
    return New(F)();
};

var Person = {
    _["name"] = "Default",
    _["greet"] = function () {
        return "My name is " + This["name"];
    }
};

var vjeux = createObject(Person);
vjeux["name"] = "Vjeux";

var blog = createObject(Person);
blog["name"] = "Blog";

var def = createObject(Person);

std::cout < < vjeux["greet"](); // Vjeux
std::cout << blog["greet"]();  // Blog
std::cout << def["greet"]();   // Default
Javascript
var createObject = function (o) {
    var F = function () {};
    F.prototype = o;
    return new F();
};

var Person = {
    name: "Default",
    greet: function () {
        return "My name is " + this.name;
    }
};

var vjeux = createObject(Person);
vjeux.name = "Vjeux";

var blog = createObject(Person);
blog.name = "Blog";

var def = createObject(Person);

console.log(vjeux.greet()); // Vjeux
console.log(blog.greet());  // Blog
console.log(def.greet());   // Default

Iteration

We use the new iteration facility of C++0x to deal withfor(var in)Javascript syntax. As this is a prototype, it currently loops over all the keys of the object. However, it is possible to implement theisEnumerablefunctionnality.

C++
var array = {10, 42, 30};
for (var i : array) {
    std::cout < < i << " - " << array[i];
}
// 0 - 10
// 1 - 42
// 2 - 30
// length - 3
// prototype - undefined

var object = {
    _["a"] = 1,
    _["b"] = 2,
    _["c"] = 3
};
for (var i : object) {
    std::cout << i << " - " << object[i];
}
// a - 1
// b - 2
// c - 3
// prototype - undefined
Javascript
var array = [10, 42, 30];
for (var i in array) {
    console.log(i, array[i]);
}
// 0 - 10
// 1 - 42
// 2 - 30



var object = {
    "a": 1,
    "b": 2,
    "c": 3
};
for (var i in object) {
    console.log(i, object[i]);
}
// a - 1
// b - 2
// c - 3
//

Dynamic Typing

There is only one class calledvar. All the operators+,+=,++,<,*... are overloaded in order to make the right behavior. Since this is only a prototype, all of them are not working properly nor following the ECMAScript standard.

C++
var repeat = function (var str, var times) {
    var ret = "";
    for (var i = 0; i < times; ++i) {
        ret += str + i;
    }
    return ret;
};

std::cout << repeat(" js++", 3);
// " js++0 js++1 js++2"
Javascript
var repeat = function (str, times) {
    var ret = "";
    for (var i = 0; i < times; ++i) {
        ret += str + i;
    }
    return ret;
};

console.log(repeat(" js++", 3));
// " js++0 js++1 js++2"

Scope

Scope management is done with lambdas. Since they are implemented in C++0x, it works without pain.

C++
var global = "global";
var $ = "prototype";
var jQuery = "jQuery";

_(function (var $) {
    var global = "local";

    std::cout < < "Inside:      $ = " << $;
    std::cout << "Inside: global = " << global;

    // Inside:      $ = jQuery
    // Inside: global = local

    return undefined;
})(jQuery);

std::cout << "Outside:      $ = " << $;
std::cout << "Outside: global = " << global;

// Outside:      $ = prototype
// Outside: global = global
Javascript
var global = "global";
var $ = "prototype";
var jQuery = "jQuery";

(function ($) {
    var global = "local";

    console.log("Inside:      $ = ", $);
    console.log("Inside: global = ", global);

    // Inside:      $ = jQuery
    // Inside: global = local

    return undefined;
})(jQuery);

console.log("Outside:      $ = ", $);
console.log("Outside: global = ", global);

// Outside:      $ = prototype
// Outside: global = global

Reference

As in Javascript, everything is passed by reference. The current implementation uses a simple reference count to handle garbage collection.

C++
var a = {};
a["key"] = "old";

var b = a;
b["key"] = "new";

std::cout < < a["key"] << " " << b["key"];
// new new
Javascript
var a = {};
a["key"] = "old";

var b = a;
b["key"] = "new";

console.log(a["key"], b["key"]);
// new new

Exception

Javascript exception mechanism is directly borrowed from C++, therefore we can use the native one.

We need to throw a Javascript object. We can either throw a new instance of a Javascript function or use_()to cast a string into an object.

C++
var go_die = function () {
    throw _("Exception!");
};

try {
    go_die();
} catch (var e) {
    std::cout < < "Error: " << e;
}
// Error: Exception!
Javascript
var go_die = function () {
    throw "Exception!";
};

try {
    go_die();
} catch (e) {
    console.log("Error:", e);
}
// Error: Exception!

How to use

Note: Only the strict minimum of code able to run the examples has been written. It is a prototype, do not try to use it for any serious development.

The library can be compiled underg++ 4.6,Visual Studio 2010and the latest version ofICC. However Visual Studio and ICC do not support the initialization lists, so you cannot use the JSON syntax. But all the other examples will compile.

All the examples of this page are available in theexample/folder. The following execution will let you run the examples.

> make
g++ -o example/dynamic.jspp example/dynamic.cpp -Wall -std=gnu++0x
g++ -o example/exception.jspp example/exception.cpp -Wall -std=gnu++0x
...
> cd example
> ./json.jspp
{array: [1, 2, three], nested: {first: 1}, number: 42, string: vjeux}
> node json.js
{ number: 42,
  string: 'vjeux',
  array: [ 1, 2, 'three' ],
  nested: { first: 1 } }

Pro / Cons

The awesome part is the fact that it is possible to develop nearly all the concepts of Javascript in C++.

Pros

  • Write C++ in a dynamic fashion!
  • Extremely easy to integrate all the existing C++ code base.
  • Fun:)

Cons

  • Not possible to optimize as much as the latest Javascript engines.
  • Some features are impossible to write such aseval,with, named functions ...
  • NoREPL.
  • A bit more verbose than Javascript.

How to Improve

  • Code theargumentsmanagement.
  • Develop the Javascript standard library (operators, Array, Regex ...).
  • Find ways to minimize the C++ overhead (remove the use of_()).
  • Find concepts that I did not introduce.
分享到:
评论

相关推荐

    MORPH数据集下载-part01

    "MORPH数据集"是一个广泛使用的年龄进展与退行的人脸图像数据库,它在人脸识别、年龄估计、面部特征分析等领域有着重要的应用。该数据集包含了大量不同年龄、性别和种族的人脸图像,旨在促进计算机视觉和模式识别...

    morph数据库(2)

    "morph数据库(2)"是一个关于人脸年龄变化的大型数据集,它主要被广泛应用于计算机视觉、人工智能和机器学习领域,尤其是面部识别和年龄估计的研究。morph数据库因其详尽且全面的特性而备受赞誉,它包含了大量个体在...

    morph.part1.rar

    morph 年龄性别数据集 13673个人,共55608张。属性主打年龄,人种,性别。非受限条件采集图片。额外的还包括头发颜色(人种特征)眼镜

    人脸图像数据集MORPH-II

    MORPH-II数据集由16至77岁人群的照片组成,每个人平均有4张照片。这是公开的最大的纵向人脸图像数据集。学术版包含了大约55000张5年拍摄的图像。MORPH-II数据集收集了55134张头像,其中提供了有价值的纵向数据。

    morph数据库(2)【2-11】

    比较完整的morph数据库,太大了分成了11份,童叟无欺,大家可以放心的下!

    morph数据库(4)

    "morph数据库(4)"是一个关于图像处理和计算机视觉领域的资源,特别关注于年龄相关的面部变化研究。这个数据库因其详尽和全面性而被广泛使用,它包含了大量的面部图像,用于研究人脸的形状、表情和年龄变化。由于其...

    包含morph-1.1.1.jar

    《morph-1.1.1.jar:深入了解Java库与软件构建》 在IT行业中,Java是一种广泛应用的编程语言,而jar(Java Archive)文件是Java平台特有的归档格式,用于集合多个类文件、资源文件以及元数据,形成一个可执行的组件...

    morph-1.1.1.jar 开发jar包

    morph-1.1.1.jar 开发jar包 morph-1.1.1.jar 开发jar包

    15-变脸Morph folder

    在本教程中,我们将深入探讨After Effects中的"变脸Morph"技术,这是一个在影视特效领域广泛应用的创新手法。"15-变脸Morph folder"这个标题暗示了这是一个关于第15个教学主题,专注于如何在After Effects中实现人物...

    morph数据库(10)【10-11】

    morph数据库(10)

    DS_Morph-IC-II.pdf

    FTDI公司的Morph-IC-II是一款紧凑但功能强大的FPGA模块,它内置了Altera的Cyclone-II FPGA,可用于综合大型规模集成(LSI)设计。这款模块通过FTDI的FT2232H,即USB 2.0高速(480Mbit/s)USB桥,实现了FPGA与PC机...

    morph-1.1.1.jar

    jso所需要的jar包,包含commons-beanutils.jar、commons-httpclient.jar、commons-lang.jar、ezmorph-1.0.5.jar、json-lib-2.2-jdk15.jar、morph-1.1.1.jar

    图形图像处理 合成 MORPH31E

    本主题聚焦于“图形图像处理 合成 MORPH31E”,这显然是一个关于图像变形或过渡效果的专题,可能是某种软件、工具或者算法的应用。下面将详细讨论这个知识点。 首先,"合成"在图形图像处理中指的是将两个或多个图像...

    morph数据库(4)【4-11】

    比较完整的morph数据库,太大了分成了11份,童叟无欺,大家可以放心的下!!!

    matlab开发-Morph

    在MATLAB中,“Morph”通常指的是图像处理中的形态学操作,它是一种处理二值图像(黑和白像素)的方法,广泛应用于图像分割、噪声去除、物体形状分析等领域。在这个“matlab开发-Morph”项目中,我们可能涉及到对数...

    Morph-DSK:javascript 画布 HTML 动画

    **JavaScript 画布动画技术详解** 在Web开发中,JavaScript是一种强大的脚本语言,它能够为...通过学习和实践"Morph-DSK"项目,开发者可以提升自己在JavaScript动画领域的技能,更好地理解和掌握动态图形的创建技巧。

    morph export

    3ds max导出morph 的插件,做表情、物体形变动画的时候一般会用到。

    Morph和关节动画概述,骨骼蒙皮动画详解+代码

    ### Morph和关节动画概述,骨骼蒙皮动画详解 #### 一、3D模型动画基本原理与分类 3D模型动画的核心在于使模型中的顶点随时间动态变化,从而展现出生动的运动效果。根据不同的实现方式和技术特点,3D模型动画可以...

    morph数据库(8)【8-11】

    比较完整的morph数据库,太大了分成了11份,童叟无欺,大家可以放心的下!!!

    json必用包括morph-1.1.1.jar

    4. **与JS、JSP交互**:由于JSON格式与JavaScript语法紧密相关,`morph-1.1.1.jar`很可能支持与JavaScript的无缝交互,使得在JSP(JavaServer Pages)中使用JSON数据变得简单。在JSP中,你可以直接将JSON对象嵌入到...

Global site tag (gtag.js) - Google Analytics