默认来说,ECMAScript是HTML的唯一标准脚本语言。因此,当你使用的别的脚本语言时,你可能会期望大部分浏览器不会识别这个语言。 另外,对于某些语言来说(比如C),当它的环境并不像通常那样对资源有完全的权限时,该语言的某些语义也变得难以定义——例如考虑在HTML页面中C指针的意义! 虽然如此,通过结合现代浏览器不断提升的计算能力和ECMAScript推出的typed arrays,理论上我们可以在纯ECMAScript中建立完整的虚拟机。因此,理论上我们同样也可以用ECMAScript来实现一个小任务:解析其他编程语言(即创建编译器)。
在ECMAScript之外
这里并不是展示一个完整的ECMAScript编译器的地方。但是我们可以展示如何开始这项工作。下面的代码是一个扩展编译器的基础,但是默认没有加载任何编译器。它的工作原理是:不能被识别的MIME类型代码会被忽略——这使我们可以手动解析他们。
想要概览这里的代码,请git clone https://github.com/madmurphy/rosetta.js,或直接下载.zip文件.
rosetta.js:
库
"use strict"; /*\ |*| |*| :: rosetta.js :: |*| |*| A possible, extensible collection of compilers to native ECMAScript. |*| |*| November 12, 2014 |*| |*| https://developer.mozilla.org/en-US/Add-ons/Code_snippets/Rosetta |*| https://developer.mozilla.org/User:fusionchess |*| |*| This framework is released under the GNU Public License, version 3 or later. |*| https://www.gnu.org/licenses/gpl-3.0.html |*| |*| Syntax: |*| |*| rosetta.appendCompiler([ "text/x-csrc", "text/x-c" ], yourCompiler); |*| \*/ var rosetta = new (function () { function createScript (oScript, oXHR200) { var sMimeType = oScript.getAttribute("type").toLowerCase(), oBaton = document.createComment(" The previous code has been automatically translated from \"" + sMimeType + "\" to \"text/ecmascript\". "); if (!oDicts.hasOwnProperty(sMimeType)) { alert("rosetta.translateScript() \u2013 Unknown mime-type \"" + sMimeType + "\": script ignored."); return; } var oCompiled = document.createElement("script"); oScript.parentNode.insertBefore(oBaton, oScript); oScript.parentNode.removeChild(oScript); for (var aAttrs = oScript.attributes, nAttr = 0; nAttr < aAttrs.length; nAttr++) { oCompiled.setAttribute(aAttrs[nAttr].name, aAttrs[nAttr].value); } oCompiled.type = "text\/ecmascript"; if (oXHR200) { oCompiled.src = "data:text\/javascript," + encodeURIComponent(oDicts[sMimeType](oXHR200.responseText)); } oCompiled.text = oXHR200 ? "" : oDicts[sMimeType](oScript.text); oBaton.parentNode.insertBefore(oCompiled, oBaton); } function reqError (oError) { throw new URIError("The script " + oError.target.src + " is not accessible."); } function reqSuccess () { createScript(this.refScript, this); } function getSource (oScript) { var oReq = new XMLHttpRequest(); oReq.onload = reqSuccess; oReq.onerror = reqError; oReq.refScript = oScript; oReq.open("GET", oScript.src, true); oReq.send(null); } function parseScript (oScript) { if (oScript.hasAttribute("type") && !rIgnoreMimes.test(oScript.getAttribute("type").toLowerCase())) { oScript.hasAttribute("src") ? getSource(oScript) : createScript(oScript); } } function parseDocument () { for ( var aScripts = document.getElementsByTagName("script"), nIdx = 0; nIdx < aScripts.length; parseScript(aScripts[nIdx++]) ); } var oDicts = {}, rIgnoreMimes = /^\s*(?:text\/javascript|text\/ecmascript)\s*$/; this.translateScript = parseScript; this.translateAll = parseDocument; this.appendCompiler = function (vMimeTypes, fCompiler) { if (arguments.length < 2) { throw new TypeError("rosetta.appendCompiler() \u2013 not enough arguments"); } if (typeof fCompiler !== "function") { throw new TypeError("rosetta.appendCompiler() \u2013 second argument must be a function"); } if (!Array.isArray(vMimeTypes)) { oDicts[(vMimeTypes).toString()] = fCompiler; return true; } for (var nIdx = 0; nIdx < vMimeTypes.length; nIdx++) { oDicts[(vMimeTypes[nIdx]).toString()] = fCompiler; } return true; }; })();
现在,想象你需要一个C (MIME类型:text/x-c
)脚本的编译器。首先,你需要声明一个函数,这个函数会把传入的纯文本C转换为并输出纯文本的ECMAScript。让我们调用这个createECMASrc()函数并把它和
C MIME类型关联:
rosetta_c.js:
一个C编译器
/* C Compiler for Rosetta */ (function () { if (!window.rosetta) { return; } /* This function takes as argument a plain text (in this case, a code written in C) and returns another plain text written in ECMAScript */ function createECMASrc (sCSrc) { /* This is just an empty example... Enjoy in creating your C compiler! */ return "alert(\"Here you have the C code to be compiled to ECMAScript:\\n\\n\" + " + JSON.stringify(sCSrc) + ");"; } rosetta.appendCompiler([ "text/x-csrc", "text/x-c" ], createECMASrc); })();
现在,你仅仅需要在你的HTML页面中引用rosetta.js,就可以把你的C脚本和ECMAScript脚本一起执行了。
example.html:
HTML示例
<!doctype html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>Rosetta C Example</title> <script type="text/javascript" src="rosetta.js"></script> <script type="text/javascript" src="rosetta_c.js"></script> <script type="text/x-csrc"> #include <stdio.h> int main () { printf("Hello world number 1!\n"); return 0; } </script> <script type="text/x-c" src="example.c"></script> </head> <body> <p>Lorem ipsum</p> <script type="text/javascript"> rosetta.translateAll(); </script> </body> </html>
example.c:
C示例
#include <stdio.h> int main () { printf("Hello world number 2!\n"); return 0; }
如果觉得创建一个C语言的编译器看起来是一项非常庞大的任务,这里有一些ECMAScript的近亲可以很容易转译为ECMAScript。上面的例子展示了可用来转换这些语言(不管简单还是困难)的可行的解决方案。
MIME类型
这里是一些关联其他编程语言的类型types:
Language | MIME type |
---|---|
Bash | text/x-shellscript |
Java | text/x-java-source |
C | text/x-c, text/x-csrc |
C++ | text/x-c++, text/x-c++src |
Python | text/x-python |
<script>
元素的type属性对可用的MIME类型没有限制。