├── .gitignore
├── .npmignore
├── README.md
├── lib
├── node
│ ├── bin.js
│ └── index.js
├── orchestrator
│ ├── index.js
│ ├── bin.js
│ ├── forked.js
│ ├── common.js
│ └── inline.js
├── reset-ca.js
├── virus.js
├── trap-hints.js
└── main.js
├── test
├── result.txt
├── base
│ ├── index.html
│ ├── generate-main.js
│ └── main.js
├── run.sh
└── meta
│ ├── empty-async.js
│ ├── empty-sync.js
│ ├── forward-async.js
│ ├── forward-sync.js
│ └── linvail.js
├── package.json
└── LICENSE
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | /node_modules/
3 | /ca/
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | /node_modules/
3 | /test/
4 | /ca/
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AranRemote
2 |
3 | Deploy Aran's analyses on distributed programs, for free.
4 |
--------------------------------------------------------------------------------
/lib/node/bin.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | const Minimist = require("minimist");
3 | const Index = require("./index.js");
4 | Index(Minimist(process.argv.slice(2)));
--------------------------------------------------------------------------------
/test/result.txt:
--------------------------------------------------------------------------------
1 |
2 | browser forward-sync devtools 273,560731358
3 | browser forward-async devtools 237,413035132
4 | browser linvail devtools 198,68847787
5 |
--------------------------------------------------------------------------------
/test/base/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Base
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/lib/node/index.js:
--------------------------------------------------------------------------------
1 | const Path = require("path");
2 | const OtilukeNode = require("otiluke/node");
3 | const Virus = require(Path.join(__dirname, "..", "virus.js"));
4 | module.exports = (options) => OtilukeNode(Virus, options);
--------------------------------------------------------------------------------
/lib/orchestrator/index.js:
--------------------------------------------------------------------------------
1 |
2 | const Inline = require("./inline.js");
3 | const Forked = require("./forked.js");
4 |
5 | module.exports = (options, callback) => {
6 | if (options["inline"]) Inline(options, callback);
7 | else Forked(options, callback);
8 | };
9 |
--------------------------------------------------------------------------------
/lib/reset-ca.js:
--------------------------------------------------------------------------------
1 | const Path = require("path");
2 | const cahome = process.argv.length > 2 ? Path.resolve(process.argv[2]) : Path.join(__dirname, "..", "ca");
3 | require("otiluke/browser/ca/index.js")({
4 | subj: "/CN=aran-remote/O=AranRemote",
5 | "ca-home": cahome
6 | });
7 | console.log("New self-signed certificate generated at: "+Path.join(cahome, "cert.pem"));
--------------------------------------------------------------------------------
/test/base/generate-main.js:
--------------------------------------------------------------------------------
1 | const Fs = require("fs");
2 | const Path = require("path");
3 | const dirname = Path.join(__dirname, "..", "..", "..", "aran", "test", "target", "atom");
4 | const content = Fs.readdirSync(dirname).filter((filname) => filname.endsWith(".js")).sort().map((filname) => {
5 | return "// "+filname+"\nconsole.log("+JSON.stringify(filname)+");\n(function () {\n"+Fs.readFileSync(Path.join(dirname, filname), "utf8")+"\n} ());\n\n";
6 | }).join("");
7 | Fs.writeFileSync(Path.join(__dirname, "main.js"), content, "utf8");
--------------------------------------------------------------------------------
/lib/orchestrator/bin.js:
--------------------------------------------------------------------------------
1 | const Common = require("./common.js");
2 | Common(JSON.parse(process.argv[2]), (location, hostname, message) => {
3 | console.error(location+" >> "+hostname+" >> "+message);
4 | // process.send({location, hostname, message});
5 | }, (error, result) => {
6 | if (error) {
7 | process.send(error.message);
8 | process.exit(0);
9 | } else {
10 | process.on("SIGTERM", () => {
11 | result.server.close();
12 | if (result.proxy) result.proxy.closeAll();
13 | });
14 | process.send(null);
15 | }
16 | });
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "aran-remote",
3 | "description": "Deploy local Aran advices on remote processes",
4 | "version": "0.3.9",
5 | "author": {
6 | "name": "Laurent Christophe",
7 | "email": "lachrist@vub.ac.be"
8 | },
9 | "devDependencies": {
10 | "linvail": "6.0.10"
11 | },
12 | "dependencies": {
13 | "acorn": "^6.1.0",
14 | "aran": "3.0.8",
15 | "astring": "^1.3.1",
16 | "melf": "2.2.14",
17 | "melf-share": "0.1.12",
18 | "otiluke": "5.4.3"
19 | },
20 | "bin": "lib/node/bin.js",
21 | "main": "lib/main.js",
22 | "repository": "lachrist/aran-remote",
23 | "homepage": "http://github.com/lachrist/aran-remote",
24 | "license": "MIT",
25 | "keywords": [
26 | "Remote",
27 | "Aran",
28 | "Instrumentation",
29 | "Distributed"
30 | ]
31 | }
32 |
--------------------------------------------------------------------------------
/test/run.sh:
--------------------------------------------------------------------------------
1 |
2 | # killall node ; clear && printf '\e[3J' ; node meta/linvail.js --node-port=9000 --alias=meta --log
3 | # clear && printf '\e[3J' ; node ../lib/node/bin.js --host=9000 --alias=base --meta-alias=meta -- base/main.js
4 |
5 | node $1 --node-port=9000 --alias=meta &
6 | sleep 2
7 | node ../lib/node/bin.js --host=9000 --alias=base --meta-alias=meta -- base/main.js
8 | wait $!
9 |
10 | # http-server base/ -p 8000 &
11 | # pid1=$!
12 | # node $1 --browser-port=8080 --alias=meta --argmpfx=META- --splitter=_META_ &
13 | # pid2=$!
14 | # sleep 2
15 | # /Applications/Firefox.app/Contents/MacOS/firefox-bin -private -devtools "http://localhost:8000?META-splitter=_META_&META-alias=base&META-meta-alias=meta" &
16 | # printf "\n\nPRESS ENTER WHEN DONE\n\n"
17 | # read -p "..."
18 | # kill $!
19 | # wait $pid2
20 | # kill $pid1
21 |
22 | # /bin/bash 1> /dev/null 2> /dev/null -c "/Applications/Firefox.app/Contents/MacOS/firefox-bin -private -devtools \"http://localhost:8000?META-splitter=_META_&META-alias=base&META-meta-alias=meta\"" &
23 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Laurent Christophe
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 |
--------------------------------------------------------------------------------
/test/meta/empty-async.js:
--------------------------------------------------------------------------------
1 |
2 | const Minimist = require("minimist");
3 | const Acorn = require("acorn");
4 | const AranRemote = require("../../lib/main.js");
5 | const Astring = require("astring");
6 |
7 | const options = Object.assign(Minimist(process.argv.slice(2)), {
8 | inline: true,
9 | synchronous: false,
10 | });
11 |
12 | AranRemote(options, (error, aran) => {
13 | if (error)
14 | throw error;
15 | const pointcut = (name, node) => name in advice;
16 | const transform = (script, source) => {
17 | const serial = typeof source === "number" ? source : null;
18 | const estree1 = Acorn.parse(script);
19 | const estree2 = aran.weave(estree1, pointcut, serial);
20 | return Astring.generate(estree2);
21 | };
22 | aran.then(() => { aran.orchestrator.terminate() }, (error) => { throw error });
23 | aran.orchestrator.then(() => { console.log("Success") }, (error) => { throw error });
24 | aran.onterminate = (alias) => { if (alias !== aran.alias) aran.terminate(aran.alias) };
25 | const advice = {
26 | __proto__: null,
27 | program: async function (serial) { aran.terminate(this.alias) },
28 | eval: async (script, serial) => transform(await aran.reflect.binary("+", "", script), serial)
29 | };
30 | return ({global, alias, argm}) => ({transform, advice: {__proto__:advice, alias}});
31 | });
32 |
--------------------------------------------------------------------------------
/test/meta/empty-sync.js:
--------------------------------------------------------------------------------
1 |
2 | const Minimist = require("minimist");
3 | const Acorn = require("acorn");
4 | const AranRemote = require("../../lib/main.js");
5 | const Astring = require("astring");
6 |
7 | const options = Object.assign(Minimist(process.argv.slice(2)), {
8 | inline: false,
9 | synchronous: true,
10 | });
11 |
12 | AranRemote(options, (error, aran) => {
13 | if (error)
14 | throw error;
15 | const pointcut = (name, node) => name in advice;
16 | const transform = (script, source) => {
17 | const serial = typeof source === "number" ? source : null;
18 | const estree1 = Acorn.parse(script);
19 | const estree2 = aran.weave(estree1, pointcut, serial);
20 | return Astring.generate(estree2);
21 | };
22 | aran.then(() => { aran.orchestrator.terminate() }, (error) => { throw error });
23 | aran.orchestrator.then(() => { console.log("Success") }, (error) => { throw error });
24 | aran.onterminate = (alias) => { if (alias !== aran.alias) aran.terminate(aran.alias) };
25 | const advice = {
26 | __proto__: null,
27 | program: function (serial) { aran.terminate(this.alias) },
28 | eval: (script, serial) => transform( aran.reflect.binary("+", "", script), serial)
29 | };
30 | return ({global, alias, argm}) => ({transform, advice: {__proto__:advice, alias}});
31 | });
32 |
--------------------------------------------------------------------------------
/lib/orchestrator/forked.js:
--------------------------------------------------------------------------------
1 |
2 | const ChildProcess = require("child_process");
3 | const Path = require("path");
4 |
5 | // const signal = (location, hostname, message) => {
6 | // console.error(location+" >> "+hostname+" >> "+message);
7 | // };
8 |
9 | module.exports = (options, callback) => {
10 | // , {execArgv:['--inspect-brk=9230']}
11 | const child = ChildProcess.fork(Path.join(__dirname, "bin.js"), [JSON.stringify(options)]);
12 | child.on("exit", (code) => { throw new Error("Orchestrator process exit ("+code+") before result message") });
13 | child.once("message", (message) => {
14 | if (message) return callback(new Error(message));
15 | child.removeAllListeners("exit");
16 | let resolve, reject;
17 | const promise = new Promise((closure1, closure2) => {
18 | resolve = closure1;
19 | reject = closure2;
20 | });
21 | // child.on("message", ({location, hostname, message}) => {
22 | // promise.onfailure(location, hostname, message);
23 | // });
24 | child.on("exit", (code) => {
25 | if (code !== 0 && code !== null) throw new Error("Orchestrator process exit ("+code+")");
26 | resolve(null);
27 | });
28 | promise.address = options["node-port"];
29 | promise.terminate = () => child.kill("SIGTERM");
30 | promise.destroy = () => {
31 | child.kill("SIGINT");
32 | reject(new Error("Destroyed by the user"));
33 | };
34 | // promise.onfailure = signal;
35 | callback(null, promise);
36 | });
37 | };
38 |
--------------------------------------------------------------------------------
/lib/orchestrator/common.js:
--------------------------------------------------------------------------------
1 |
2 | const Net = require("net");
3 | const Path = require("path");
4 | const Http = require("http");
5 | const Distributor = require("melf/lib/distributor");
6 | const OtilukeBrowser = require("otiluke/browser");
7 |
8 | module.exports = (options, onfailure, callback) => {
9 | const server = Net.createServer();
10 | server.on("error", callback);
11 | server.listen(options["node-port"], () => {
12 | server.removeListener("error", callback);
13 | const distributor = Distributor(options["log"]);
14 | server.on("connection", distributor.ConnectionListener());
15 | if (options.otiluke.port === undefined || options.otiluke.port === null) {
16 | callback(null, {distributor, server, proxy:null});
17 | } else {
18 | const proxy = OtilukeBrowser(Path.join(__dirname, "..", "virus.js"), Object.assign(options.otiluke, {
19 | onfailure,
20 | intercept: {
21 | request: distributor.RequestMiddleware(options.splitter),
22 | upgrade: distributor.UpgradeMiddleware(options.splitter)
23 | }
24 | }));
25 | const cleanup = (error) => {
26 | server.close();
27 | callback(error instanceof Error ? error : new Error("Early connection"));
28 | }
29 | server.on("connection", cleanup);
30 | proxy.on("error", cleanup);
31 | proxy.listen(options.otiluke.port, () => {
32 | server.removeListener("connection", cleanup);
33 | proxy.removeListener("error", cleanup);
34 | callback(null, {distributor, server, proxy});
35 | });
36 | }
37 | });
38 | };
39 |
--------------------------------------------------------------------------------
/lib/orchestrator/inline.js:
--------------------------------------------------------------------------------
1 |
2 | const Common = require("./common.js");
3 |
4 | // const signal = (location, hostname, message) => {
5 | // console.error(location+" >> "+hostname+" >> "+message);
6 | // };
7 |
8 | module.exports = (options, callback) => {
9 | const promise = new Promise((resolve, reject) => {
10 | Common(options, (location, hostname, message) => {
11 | console.error(location+" >> "+hostname+" >> "+message);
12 | // promise.onfailure(location, hostname, message);
13 | }, (error, {distributor, server, proxy}) => {
14 | if (error) return callback(error);
15 | const sockets = new Set();
16 | function onsocketclose () {
17 | sockets.delete(this);
18 | }
19 | server.on("connection", (socket) => {
20 | sockets.add(socket);
21 | socket.on("close", onsocketclose);
22 | });
23 | const failure = (error) => {
24 | server.close();
25 | for (let socket of sockets) socket.destroy();
26 | if (proxy) proxy.destroy();
27 | reject(error);
28 | };
29 | server.on("close", () => {
30 | if (!proxy || !proxy.listening) resolve(null)
31 | });
32 | if (proxy) proxy.on("close", () => {
33 | // Unlike for the forked orchestrator, it is not
34 | // guaranteed that all the servers/sockets closed
35 | // gracefully
36 | proxy.closeAll();
37 | proxy.destroyAll();
38 | if (!server.listening) resolve(null);
39 | });
40 | // promise.onfailure = signal;
41 | promise.address = distributor;
42 | promise.destroy = () => failure(new Error("Destroyed by the user"));
43 | promise.terminate = () => {
44 | server.close();
45 | if (proxy) proxy.closeAll();
46 | };
47 | callback(null, promise);
48 | });
49 | });
50 | };
51 |
--------------------------------------------------------------------------------
/lib/virus.js:
--------------------------------------------------------------------------------
1 | const Melf = require("melf");
2 | const MelfShare = require("melf-share");
3 | const TrapHints = require("./trap-hints.js");
4 |
5 | const process = (function () { return this } ()).process;
6 |
7 | // Inspired from: https://github.com/iliakan/detect-node
8 |
9 | const success = () => {
10 | if (Object.prototype.toString.call(process) === "[object process]") {
11 | process.exit(0);
12 | } else {
13 | alert("Success (this page will emit network errors)");
14 | }
15 | };
16 |
17 | const failure = (error) => {
18 | console.error(error.stack);
19 | if (Object.prototype.toString.call(process) === "[object process]") {
20 | process.exit(1);
21 | } else {
22 | alert("Failure (this page will emit network errors): "+error.message);
23 | }
24 | };
25 |
26 | module.exports = (argm, callback) => {
27 | Melf(argm.host || argm.splitter, argm.alias, (error, melf) => {
28 | if (error)
29 | return failure(error);
30 | const alias = argm["meta-alias"] || "aran";
31 | const share = MelfShare(melf, {synchronous:true});
32 | melf.then(success, failure);
33 | melf.onterminate = () => {
34 | melf.rpcall(alias, "onterminate", null);
35 | };
36 | melf.rprocedures.terminate = (alias, data, callback) => {
37 | callback(null, null);
38 | melf.terminate();
39 | };
40 | melf.rprocedures.destroy = (alias, data, callback) => {
41 | callback(null, null);
42 | melf.destroy();
43 | };
44 | const {namespace, setup} = melf.rpcall(alias, "initialize", {
45 | global: share.serialize(global),
46 | argm: argm
47 | });
48 | global[namespace] = {__proto__:null};
49 | Object.keys(TrapHints).forEach((name) => {
50 | const hints = TrapHints[name];
51 | global[namespace][name] = (...array) => {
52 | for (let index = 0, length = array.length - 1; index < length; index++)
53 | array[index] = share.serialize(array[index], hints[index]);
54 | return share.instantiate(melf.rpcall(alias, name, array));
55 | };
56 | });
57 | global.eval(setup);
58 | callback(null, (script, source) => melf.rpcall(alias, "transform", {script, source}));
59 | });
60 | };
61 |
--------------------------------------------------------------------------------
/test/meta/forward-async.js:
--------------------------------------------------------------------------------
1 |
2 | const Minimist = require("minimist");
3 | const Acorn = require("acorn");
4 | const AranRemote = require("../../lib/main.js");
5 | const Astring = require("astring");
6 |
7 | const options = Object.assign(Minimist(process.argv.slice(2)), {
8 | inline: true,
9 | synchronous: false,
10 | });
11 |
12 | AranRemote(options, (error, aran) => {
13 | if (error)
14 | throw error;
15 | const pointcut = (name, node) => true;
16 | const transform = (script, source) => {
17 | const serial = typeof source === "number" ? source : null;
18 | const estree1 = Acorn.parse(script);
19 | const estree2 = aran.weave(estree1, pointcut, serial);
20 | return Astring.generate(estree2);
21 | };
22 | let time = null;
23 | aran.then(() => { aran.orchestrator.terminate() }, (error) => { throw error });
24 | aran.orchestrator.then(() => { console.log("Success "+process.hrtime(time)) }, (error) => { throw error });
25 | aran.onterminate = (alias) => { if (alias !== aran.alias) aran.terminate(aran.alias) };
26 | const noop = async () => {};
27 | const identity = async (arg0) => arg0;
28 | const advice = {__proto__:null};
29 | // Informers //
30 | [
31 | "arrival",
32 | "enter",
33 | "leave",
34 | "continue",
35 | "break",
36 | "debugger"
37 | ].forEach((key) => { advice[key] = noop });
38 | advice.program = async function (serial) {
39 | time = process.hrtime();
40 | aran.terminate(this.alias);
41 | };
42 | // Transformers //
43 | [
44 | "error",
45 | "abrupt",
46 | "throw",
47 | "return",
48 | "closure",
49 | "builtin",
50 | "primitive",
51 | "read",
52 | "argument",
53 | "drop",
54 | "test",
55 | "write",
56 | "success",
57 | "failure"
58 | ].forEach((key) => { advice[key] = identity });
59 | advice.eval = async (script, serial) => transform(await aran.reflect.binary("+", "", script), serial);
60 | // Combiners //
61 | advice.construct = async (c, xs, s) => await aran.reflect.construct(c, xs);
62 | advice.apply = async (f, t, xs, s) => await aran.reflect.apply(f, t, xs);
63 | advice.unary = async (o, x) => await aran.reflect.unary(o, x);
64 | advice.binary = async (o, x1, x2) => await aran.reflect.binary(o, x1, x2);
65 | return ({global, alias, argm}) => ({transform, advice:{__proto__:advice, alias}});
66 | });
67 |
--------------------------------------------------------------------------------
/test/meta/forward-sync.js:
--------------------------------------------------------------------------------
1 |
2 | const Minimist = require("minimist");
3 | const Acorn = require("acorn");
4 | const AranRemote = require("../../lib/main.js");
5 | const Astring = require("astring");
6 |
7 | const options = Object.assign(Minimist(process.argv.slice(2)), {
8 | inline: false,
9 | synchronous: true,
10 | });
11 |
12 | AranRemote(options, (error, aran) => {
13 | if (error)
14 | throw error;
15 | const pointcut = (name, node) => true;
16 | const transform = (script, source) => {
17 | const serial = typeof source === "number" ? source : null;
18 | const estree1 = Acorn.parse(script);
19 | const estree2 = aran.weave(estree1, pointcut, serial);
20 | return Astring.generate(estree2);
21 | };
22 | let time = null;
23 | aran.then(() => { aran.orchestrator.terminate() }, (error) => { throw error });
24 | aran.orchestrator.then(() => { console.log("Success "+process.hrtime(time)) }, (error) => { throw error });
25 | aran.onterminate = (alias) => { if (alias !== aran.alias) aran.terminate(aran.alias) };
26 | const noop = () => {};
27 | const identity = (arg0) => arg0;
28 | const advice = {__proto__:null};
29 | // Informers //
30 | [
31 | "arrival",
32 | "enter",
33 | "leave",
34 | "continue",
35 | "break",
36 | "debugger"
37 | ].forEach((key) => { advice[key] = noop });
38 | advice.program = function (serial) {
39 | time = process.hrtime();
40 | aran.terminate(this.alias);
41 | };
42 | // Transformers //
43 | [
44 | "error",
45 | "abrupt",
46 | "throw",
47 | "return",
48 | "closure",
49 | "builtin",
50 | "primitive",
51 | "read",
52 | "argument",
53 | "drop",
54 | "test",
55 | "write",
56 | "success",
57 | "failure"
58 | ].forEach((key) => { advice[key] = identity });
59 | advice.eval = (script, serial) => transform( aran.reflect.binary("+", "", script), serial);
60 | // Combiners //
61 | advice.construct = (c, xs, s) => aran.reflect.construct(c, xs);
62 | advice.apply = (f, t, xs, s) => aran.reflect.apply(f, t, xs);
63 | advice.unary = (o, x) => aran.reflect.unary(o, x);
64 | advice.binary = (o, x1, x2) => aran.reflect.binary(o, x1, x2);
65 | return ({global, alias, argm}) => ({transform, advice:{__proto__:advice, alias}});
66 | });
67 |
--------------------------------------------------------------------------------
/lib/trap-hints.js:
--------------------------------------------------------------------------------
1 |
2 | ///////////////
3 | // Informers //
4 | ///////////////
5 | exports.arrival = ["function", "constructor|undefined", "value", "arguments"];
6 | exports.break = ["label|null"];
7 | exports.continue = ["label|null"];
8 | exports.debugger = [];
9 | exports.enter = ["tag", ["label"], ["indentifier"]];
10 | exports.leave = [];
11 | exports.program = ["object"];
12 |
13 | ///////////////
14 | // Modifiers //
15 | ///////////////
16 | exports.abrupt = ["value"];
17 | exports.argument = ["value", "argument-index"];
18 | exports.builtin = ["value", "builtin-name"];
19 | exports.closure = ["function"];
20 | exports.drop = ["value"];
21 | exports.error = ["value"];
22 | exports.failure = ["value"];
23 | exports.primitive = ["primitive"];
24 | exports.read = ["value", "identifier"];
25 | exports.return = ["value"];
26 | exports.success = ["value"];
27 | exports.test = ["value"];
28 | exports.throw = ["value"];
29 | exports.write = ["value", "identifier"];
30 | exports.eval = ["value"];
31 |
32 | ///////////////
33 | // Combiners //
34 | ///////////////
35 | exports.apply = ["value", "value", ["value"]];
36 | exports.binary = ["binary-operator", "value", "value"];
37 | exports.construct = ["value", ["value"]];
38 | exports.unary = ["unary-operator", "value"];
39 |
40 | //
41 | // ///////////////
42 | // // Producers //
43 | // ///////////////
44 | // exports.arrival = ["strict", {}];
45 | // exports.begin = ["strict", {}];
46 | // exports.catch = ["error"];
47 | // exports.closure = ["function"];
48 | // exports.discard = ["identifier", "success"];
49 | // exports.load = ["name", "builtin"];
50 | // exports.primitive = ["primitive"];
51 | // exports.read = ["identifier", "value"];
52 | // exports.regexp = ["regexp"];
53 | //
54 | // ///////////////
55 | // // Consumers //
56 | // ///////////////
57 | // exports.completion = ["value"];
58 | // exports.declare = ["kind", "identifier", "value"];
59 | // exports.eval = ["script"];
60 | // exports.failure = [{}, "error"];
61 | // exports.return = [{}, "result"];
62 | // exports.save = ["string", "any"];
63 | // exports.success = [{}, "value"];
64 | // exports.test = ["value"];
65 | // exports.throw = ["error"];
66 | // exports.with = ["environment"];
67 | // exports.write = ["identifier", "value"];
68 | //
69 | // ///////////////
70 | // // Informers //
71 | // ///////////////
72 | // exports.block = [];
73 | // exports.break = ["continue", "label"];
74 | // exports.copy = ["position"];
75 | // exports.drop = [];
76 | // exports.end = [{}];
77 | // exports.finally = [];
78 | // exports.label = ["continue", "label"];
79 | // exports.leave = ["type"];
80 | // exports.swap = ["position1", "position2"];
81 | // exports.try = [];
82 |
--------------------------------------------------------------------------------
/test/meta/linvail.js:
--------------------------------------------------------------------------------
1 |
2 | const Minimist = require("minimist");
3 | const Acorn = require("acorn");
4 | const AranRemote = require("../../lib/main.js");
5 | const Astring = require("astring");
6 | const Linvail = require("linvail");
7 |
8 | const options = Object.assign(Minimist(process.argv.slice(2)), {
9 | inline: false,
10 | synchronous: true,
11 | });
12 |
13 | AranRemote(options, (error, aran) => {
14 | if (error)
15 | throw error;
16 | const advice = {};
17 | const pointcut = (name, node) => name in advice;
18 | const transform = (script, source) => {
19 | const serial = typeof source === "number" ? source : null;
20 | const estree1 = Acorn.parse(script);
21 | const estree2 = aran.weave(estree1, pointcut, serial);
22 | return Astring.generate(estree2);
23 | };
24 | let time = null;
25 | aran.then(() => { aran.orchestrator.terminate() }, (error) => { throw error });
26 | aran.orchestrator.then(() => { console.log("Success "+process.hrtime(time)) }, (error) => { throw error });
27 | aran.onterminate = (alias) => { if (alias !== aran.alias) aran.terminate(aran.alias) };
28 | let counter = 0;
29 | const membrane = {
30 | taint: (value) => ({meta:"@"+(++counter), base:value}),
31 | clean: ($$value) => $$value.base
32 | };
33 | const {capture, release} = Linvail(membrane);
34 | // Informers //
35 | advice.program = function (serial) {
36 | time = process.hrtime();
37 | aran.terminate(this.alias);
38 | };
39 | // Consumers //
40 | advice.throw = ($$value, serial) => release(membrane.clean($$value));
41 | advice.test = ($$value, serial) => {
42 | console.log($$value.meta+" TEST");
43 | return membrane.clean($$value);
44 | };
45 | advice.success = ($$value, serial) => release(membrane.clean($$value));
46 | advice.eval = ($$value, serial) => {
47 | const script = release(membrane.clean($$value));
48 | return transform(script, serial);
49 | };
50 | // Producers //
51 | advice.error = (value, serial) => membrane.taint(capture(value));
52 | advice.primitive = (primitive, serial) => {
53 | const $$primitive = membrane.taint(primitive);
54 | console.log($$primitive.meta+" := "+JSON.stringify(primitive));
55 | return $$primitive;
56 | };
57 | advice.builtin = (value, name, serial) => membrane.taint(capture(value));
58 | advice.closure = ($closure, serial) => {
59 | Reflect.setPrototypeOf($closure, capture(Function.prototype));
60 | return membrane.taint($closure);
61 | };
62 | advice.argument = (_value, name) => {
63 | if (name === "length" || name === "new.target")
64 | return membrane.taint(_value);
65 | return _value;
66 | };
67 | // Combiners //
68 | advice.apply = ($$value1, $$value2, $$values, serial) => {
69 | return Reflect.apply(membrane.clean($$value1), $$value2, $$values);
70 | };
71 | advice.construct = ($$value, $$values, serial) => {
72 | return Reflect.construct(membrane.clean($$value), $$values);
73 | };
74 | advice.unary = (operator, $$value, serial) => {
75 | const value = release(membrane.clean($$value));
76 | const primitive = aran.reflect.unary(operator, value);
77 | const $$primitive = membrane.taint(primitive);
78 | console.log($$primitive.meta+" := "+operator+" "+$$value.meta);
79 | return $$primitive;
80 | };
81 | advice.binary = (operator, $$value1, $$value2, serial) => {
82 | const value1 = release(membrane.clean($$value1));
83 | const value2 = release(membrane.clean($$value2));
84 | const primitive = aran.reflect.binary(operator, value1, value2);
85 | const $$primitive = membrane.taint(primitive);
86 | console.log($$primitive.meta+" := "+$$value1.meta+" "+operator+" "+$$value2.meta);
87 | return $$primitive;
88 | };
89 | // Return
90 | return ({global, alias, argm}) => ({transform, advice:{__proto__:advice, alias}});
91 | });
92 |
--------------------------------------------------------------------------------
/lib/main.js:
--------------------------------------------------------------------------------
1 |
2 | const Os = require("os");
3 | const Fs = require("fs");
4 | const Path = require("path");
5 | const Aran = require("aran");
6 | const Melf = require("melf");
7 | const MelfShare = require("melf-share");
8 | const Astring = require("astring");
9 | const TrapHints = require("./trap-hints.js");
10 | const Orchestrator = require("./orchestrator");
11 |
12 | const identity = (argument) => argument;
13 |
14 | const noop = () => {};
15 |
16 | module.exports = (options={}, callback) => {
17 | options = {
18 | "node-port": options["node-port"] || Path.join(Os.tmpdir(), "aran-"+Date.now().toString(36)+"-"+Math.random().toString(36).substring(2)+".sock"),
19 | "inline": options["inline"] || false,
20 | "alias": options["alias"] || "aran",
21 | "log": options["log"] || false,
22 | "splitter": options["splitter"] || "ARAN",
23 | "melf-share": {
24 | "synchronous": options["synchronous"] || false,
25 | },
26 | aran: {
27 | "namespace": options["namespace"] || "_",
28 | "format": options["format"] || "estree",
29 | "root": options["roots"] || []
30 | },
31 | otiluke: {
32 | "port": options["browser-port"] || null,
33 | "argmpfx": options["argmpfx"] || "ARAN-",
34 | "cahome": options["cahome"] || Path.join(__dirname, "..", "ca"),
35 | "gvar": options["gvar"] || "__ARAN_TRANSFORM__",
36 | "sockdir": options["sockdir"] || null
37 | }
38 | };
39 | if (options["melf-share"]["synchronous"] && options["inline"]) {
40 | return callback(new Error("Cannot use the synchronous API and inline the orchestrator"));
41 | }
42 | Orchestrator(options, (error, orchestrator) => {
43 | if (error) return callback(error);
44 | Melf(orchestrator.address, options["alias"], (error, melf) => {
45 | if (error) {
46 | orchestrator.interrupt();
47 | callback(error);
48 | } else {
49 | const share = MelfShare(melf, options["melf-share"]);
50 | const analyses = {__proto__:null};
51 | const generate = options["aran"]["format"] === "estree" ? Astring.generate : identity;
52 | const aran = Aran(options["aran"]);
53 | const promise = new Promise((resolve, reject) => { melf.then(resolve, reject) });
54 | promise.orchestrator = orchestrator;
55 | promise._aran = aran;
56 | promise.weave = weave;
57 | promise.nodes = aran.nodes;
58 | promise.roots = aran.roots;
59 | promise.namespace = aran.namespace;
60 | promise.format = aran.format;
61 | promise._melf = melf;
62 | promise.alias = melf.alias;
63 | promise.onterminate = noop;
64 | promise.terminate = terminate;
65 | promise.destroy = destroy;
66 | promise._share = share;
67 | promise.ownerof = share.ownerof;
68 | promise.reflect = share.reflect;
69 | const Analysis = callback(null, promise);
70 | melf.rprocedures["onterminate"] = (origin, data, callback) => {
71 | callback(null, null);
72 | promise.onterminate(origin);
73 | };
74 | melf.onterminate = () => { promise.onterminate(melf.alias) };
75 | melf.rprocedures["initialize"] = (origin, data, callback) => {
76 | try {
77 | analyses[origin] = Analysis({
78 | alias: origin,
79 | argm: data.argm,
80 | global: share.instantiate(data.global)
81 | });
82 | callback(null, {
83 | namespace: aran.namespace,
84 | setup: generate(aran.setup()),
85 | });
86 | } catch (error) {
87 | callback(error);
88 | }
89 | };
90 | melf.rprocedures["transform"] = (origin, {script, source}, callback) => {
91 | try {
92 | callback(null, analyses[origin].transform(script, source));
93 | } catch (error) {
94 | callback(error);
95 | }
96 | };
97 | if (options["melf-share"]["synchronous"]) {
98 | Object.keys(TrapHints).forEach((name) => {
99 | const hints = TrapHints[name];
100 | const length = hints.length;
101 | melf.rprocedures[name] = (origin, data, callback) => {
102 | try {
103 | for (let index = 0; index < length; index++)
104 | data[index] = share.instantiate(data[index], hints[index]);
105 | callback(null, share.serialize(analyses[origin].advice[name](...data)));
106 | } catch (error) {
107 | callback(error);
108 | }
109 | };
110 | });
111 | } else {
112 | Object.keys(TrapHints).forEach((name) => {
113 | const hints = TrapHints[name];
114 | const length = hints.length;
115 | melf.rprocedures[name] = (origin, data, callback) => {
116 | for (let index = 0; index < length; index++)
117 | data[index] = share.instantiate(data[index], hints[index]);
118 | analyses[origin].advice[name](...data).then((result) => {
119 | callback(null, share.serialize(result), "value");
120 | }, callback);
121 | };
122 | });
123 | }
124 | }
125 | });
126 | });
127 | };
128 |
129 | function weave (root, pointcut, scope) {
130 | return this._aran.weave(root, pointcut, scope);
131 | }
132 |
133 | function terminate (alias, callback) {
134 | if (alias && alias !== this.alias) {
135 | this._melf.rpcall(alias, "terminate", null, (error, data) => { if (error) throw error });
136 | } else {
137 | this._melf.terminate();
138 | }
139 | }
140 |
141 | function destroy (alias) {
142 | if (alias && alias !== this.alias) {
143 | this._melf.rpcall(alias, "destroy", null, (error, data) => { if (error) throw error });
144 | } else {
145 | this._melf.destroy();
146 | }
147 | }
148 |
--------------------------------------------------------------------------------
/test/base/main.js:
--------------------------------------------------------------------------------
1 | // Arguments.js
2 | console.log("Arguments.js");
3 | (function () {
4 | let f = function () {
5 | if (arguments[0] !== "foo")
6 | throw new Error("Arguments1");
7 | if (arguments[1] !== "bar")
8 | throw new Error("Arguments2");
9 | if (arguments.length !== 2)
10 | throw new Error("Arguments3");
11 | };
12 | f("foo", "bar");
13 | } ());
14 |
15 | // Array.js
16 | console.log("Array.js");
17 | (function () {
18 | if ([1,2,3][0] !== 1)
19 | throw new Error("Array");
20 | } ());
21 |
22 | // Arrow.js
23 | console.log("Arrow.js");
24 | (function () {
25 | let a1 = () => "foo";
26 | let a2 = () => { return "bar" };
27 | if (a1() !== "foo")
28 | throw new Error("Arrow1");
29 | if (a2() !== "bar")
30 | throw new Error("Arrow2");
31 | let check = false;
32 | try {
33 | new a1();
34 | } catch (error) {
35 | check = true;
36 | }
37 | if (!check)
38 | throw new Error("Arrow3");
39 | } ());
40 |
41 | // Binary.js
42 | console.log("Binary.js");
43 | (function () {
44 | if (1+2 !== 3)
45 | throw new Error("Binary");
46 | } ());
47 |
48 | // Block.js
49 | console.log("Block.js");
50 | (function () {
51 | (function () {
52 | {let x = 1}
53 | if (typeof x !== "undefined")
54 | throw new Error("Block1");
55 | {var y = 1}
56 | if (y !== 1)
57 | throw new Error("Block2");
58 | } ());
59 | } ());
60 |
61 | // Break.js
62 | console.log("Break.js");
63 | (function () {
64 | a:{
65 | break a;
66 | throw new Error("Break1");
67 | }
68 | while (true) {
69 | break;
70 | throw new Error("Break2");
71 | }
72 | } ());
73 |
74 | // Call.js
75 | console.log("Call.js");
76 | (function () {
77 | if ((() => 1)() !== 1)
78 | throw new Error("Call");
79 | } ());
80 |
81 | // Conditional.js
82 | console.log("Conditional.js");
83 | (function () {
84 | if ((true?1:2) !== 1)
85 | throw new Error("Conditional1");
86 | if ((false?1:2) !== 2)
87 | throw new Error("Conditional2");
88 | } ());
89 |
90 | // Const.js
91 | console.log("Const.js");
92 | (function () {
93 | {
94 | const c = "foo";
95 | try {
96 | c = "bar";
97 | } catch (_) {
98 | }
99 | if (c !== "foo")
100 | throw new Error("Const1");
101 | }
102 | if (typeof c !== "undefined")
103 | throw new Error("Const2");
104 | } ());
105 |
106 | // Continue.js
107 | console.log("Continue.js");
108 | (function () {
109 | let x = true;
110 | while (x) {
111 | x = false;
112 | continue;
113 | throw new Error("Continue1");
114 | }
115 | let y = true;
116 | a : while (y) {
117 | y = false;
118 | continue a;
119 | throw new Error("Continue2");
120 | }
121 | } ());
122 |
123 | // Declaration.js
124 | console.log("Declaration.js");
125 | (function () {
126 | let x, y = 1;
127 | if (x !== undefined)
128 | throw new Error("Declaration1");
129 | if (y !== 1)
130 | throw new Error("Declaration2");
131 | } ());
132 |
133 | // DeclarationFor.js
134 | console.log("DeclarationFor.js");
135 | (function () {
136 | let sum = 0;
137 | for (let i=0; i<4; i++)
138 | sum = sum + i;
139 | if (sum !== 6)
140 | throw new Error("DeclarationFor");
141 | } ());
142 |
143 | // DeclarationForIn.js
144 | console.log("DeclarationForIn.js");
145 | (function () {
146 | let sum = "";
147 | for (let k in {a:1,b:2,c:3})
148 | sum = sum + k;
149 | if (sum !== "abc")
150 | throw new Error("DeclarationForIn");
151 | } ());
152 |
153 | // DeclarationForOf.js
154 | console.log("DeclarationForOf.js");
155 | (function () {
156 | let sum = "";
157 | for (let x of ["a", "b", "c"])
158 | sum = sum + x;
159 | if (sum !== "abc")
160 | throw new Error("ForOf");
161 | } ());
162 |
163 | // Definition.js
164 | console.log("Definition.js");
165 | (function () {
166 | (function () {
167 | f();
168 | function f () {}
169 | } ());
170 | } ());
171 |
172 | // DoWhile.js
173 | console.log("DoWhile.js");
174 | (function () {
175 | let i = 0;
176 | do {
177 | i++;
178 | } while (i < 3)
179 | if (i !== 3)
180 | throw new Error("DoWhile");
181 | } ());
182 |
183 | // Empty.js
184 | console.log("Empty.js");
185 | (function () {
186 | ;
187 | } ());
188 |
189 | // EvalCall.js
190 | console.log("EvalCall.js");
191 | (function () {
192 | let x = 1;
193 | if (eval("x") !== 1)
194 | throw new Error("EvalCall");
195 | } ());
196 |
197 | // Expression.js
198 | console.log("Expression.js");
199 | (function () {
200 | "foo";
201 | } ());
202 |
203 | // For.js
204 | console.log("For.js");
205 | (function () {
206 | let i;
207 | for (i=0; i<3; i++) {}
208 | if (i !== 3)
209 | throw new Error("For");
210 | } ());
211 |
212 | // ForIn.js
213 | console.log("ForIn.js");
214 | (function () {
215 | let k;
216 | for (k in {a:1}) {}
217 | if (k !== "a")
218 | throw new Error("DeclarationForIn");
219 | } ());
220 |
221 | // ForOf.js
222 | console.log("ForOf.js");
223 | (function () {
224 | let x;
225 | for (x of ["foo"]) {}
226 | if (x !== "foo")
227 | throw new Error("ForOf");
228 | } ());
229 |
230 | // Function.js
231 | console.log("Function.js");
232 | (function () {
233 | let f = function () { return 1 }
234 | if (f() !== 1)
235 | throw new Error("Function");
236 | } ());
237 |
238 | // Identifier.js
239 | console.log("Identifier.js");
240 | (function () {
241 | let x = 1;
242 | if (x !== 1)
243 | throw new Error("Identifier");
244 | } ());
245 |
246 | // IdentifierAssignment.js
247 | console.log("IdentifierAssignment.js");
248 | (function () {
249 | let x;
250 | x = 1;
251 | if (x !== 1)
252 | throw new Error("IdentifierAssignment1");
253 | x += 2;
254 | if (x !== 3)
255 | throw new Error("IdentifierAssignment2");
256 | } ());
257 |
258 | // IdentifierDelete.js
259 | console.log("IdentifierDelete.js");
260 | (function () {
261 | let o = {a:1};
262 | let x;
263 | with (o) {
264 | if (delete x)
265 | throw new Error("IdentifierDelete1");
266 | if (! delete a)
267 | throw new Error("IdentifierDelete2");
268 | if (! delete a$strange$id)
269 | throw new Error("IdentifierDelete3");
270 | }
271 | if ("a" in o)
272 | throw new Error("IdentifierDelete4");
273 | } ());
274 |
275 | // IdentifierForIn.js
276 | console.log("IdentifierForIn.js");
277 | (function () {
278 | let k;
279 | for (k in {a:1}) {}
280 | if (k !== "a")
281 | throw new Error("IdentifierForIn");
282 | } ());
283 |
284 | // IdentifierTypeof.js
285 | console.log("IdentifierTypeof.js");
286 | (function () {
287 | if (typeof 1 !== "number")
288 | throw new Error("Typeof2");
289 | if (typeof UndefinedVariable !== "undefined")
290 | throw new Error("Typeof1");
291 | } ());
292 |
293 | // IdentifierUpdate.js
294 | console.log("IdentifierUpdate.js");
295 | (function () {
296 | let x = 1;
297 | if (x++ !== 1)
298 | throw new Error("IdentifierUpdate1");
299 | if (++x !== 3)
300 | throw new Error("IdentifierUpdate2");
301 | } ());
302 |
303 | // If.js
304 | console.log("If.js");
305 | (function () {
306 | if (true) {} else {
307 | throw new Error("If1");
308 | }
309 | if (false) {
310 | throw new Error("If2");
311 | } else {}
312 | } ());
313 |
314 | // Label.js
315 | console.log("Label.js");
316 | (function () {
317 | a:{
318 | break a;
319 | throw new Error("Label");
320 | }
321 | } ());
322 |
323 | // Let.js
324 | console.log("Let.js");
325 | (function () {
326 | {
327 | let l = "foo";
328 | l = "bar"
329 | if (l !== "bar")
330 | throw new Error("Let1");
331 | }
332 | if (typeof l !== "undefined")
333 | throw new Error("Let2");
334 | } ());
335 |
336 | // Literal.js
337 | console.log("Literal.js");
338 | (function () {
339 | true;
340 | false;
341 | 1;
342 | -1;
343 | "a";
344 | /abc/g;
345 | } ());
346 |
347 | // Logical.js
348 | console.log("Logical.js");
349 | (function () {
350 | if ((false||1) !== 1)
351 | throw new Error("Logical1");
352 | if ((true&&1) !== 1)
353 | throw new Error("Logical2");
354 | } ());
355 |
356 | // LoopLabel.js
357 | console.log("LoopLabel.js");
358 | (function () {
359 | let i = 0;
360 | a: for (; i<10; i++) {
361 | if (i === 5)
362 | break a;
363 | }
364 | if (i !== 5)
365 | throw new Error("LoopLabel");
366 | } ());
367 |
368 | // Member.js
369 | console.log("Member.js");
370 | (function () {
371 | if ({a:1}.a !== 1)
372 | throw new Error("Member");
373 |
374 | } ());
375 |
376 | // MemberAssignment.js
377 | console.log("MemberAssignment.js");
378 | (function () {
379 | let o = {};
380 | o.a = 1;
381 | if (o.a !== 1)
382 | throw new Error("MemberAssignment1");
383 | o.a += 2;
384 | if (o.a !== 3)
385 | throw new Error("MemberAssignment2");
386 | } ());
387 |
388 | // MemberCall.js
389 | console.log("MemberCall.js");
390 | (function () {
391 | let o = {
392 | f: function () {
393 | if (this !== o)
394 | throw new Error("MemberCall");
395 | }
396 | }
397 | o.f();
398 | } ());
399 |
400 | // MemberDelete.js
401 | console.log("MemberDelete.js");
402 | (function () {
403 | let o = {a:1};
404 | delete o.a;
405 | if ("a" in o)
406 | throw new Error("MemberDelete");
407 | } ());
408 |
409 | // MemberForIn.js
410 | console.log("MemberForIn.js");
411 | (function () {
412 | let o = {};
413 | for (o.a in {a:1}) {}
414 | if (o.a !== "a")
415 | throw new Error("MemberForIn");
416 | } ());
417 |
418 | // MemberForOf.js
419 | console.log("MemberForOf.js");
420 | (function () {
421 | let o = {};
422 | for (o.a of ["foo"]) {}
423 | if (o.a !== "foo")
424 | throw new Error("ForOf");
425 | } ());
426 |
427 | // MemberUpdate.js
428 | console.log("MemberUpdate.js");
429 | (function () {
430 | let o = {a:1};
431 | if (o.a++ !== 1)
432 | throw new Error("MemberUpdate1");
433 | if (++o.a !== 3)
434 | throw new Error("MemberUpdate2");
435 | } ());
436 |
437 | // New.js
438 | console.log("New.js");
439 | (function () {
440 | let o = {};
441 | let F = function () { return o }
442 | if (new F() !== o)
443 | throw new Error("New");
444 |
445 | } ());
446 |
447 | // NewTarget.js
448 | console.log("NewTarget.js");
449 | (function () {
450 | let f1 = function () {
451 | if (new.target !== void 0)
452 | throw new Error("NewTarget1");
453 | }
454 | f1();
455 | let f2 = function () {
456 | if (new.target === void 0)
457 | throw new Error("NewTarget2");
458 | };
459 | new f2();
460 | } ());
461 |
462 | // Object.js
463 | console.log("Object.js");
464 | (function () {
465 | let b = "b";
466 | let o = {
467 | a: 1,
468 | [b]: 2,
469 | get c () { return 3 },
470 | set c (v) {}
471 | };
472 | if (o.a !== 1)
473 | throw new Error("Object1");
474 | if (o.b !== 2)
475 | throw new Error("Object2");
476 | o.c = 666;
477 | if (o.c !== 3)
478 | throw new Error("Object3");
479 | } ());
480 |
481 | // PatternArray.js
482 | console.log("PatternArray.js");
483 | (function () {
484 | let [x1,x2] = ["foo1", "bar1"];
485 | if (x1 !== "foo1")
486 | throw new Error("PatternArray1");
487 | if (x2 !== "bar1")
488 | throw new Error("PatternArray2");
489 | let [y1, y2, ... ys] = ["foo2", "bar2", "buz2", "qux2"];
490 | if (y1 !== "foo2")
491 | throw new Error("PatternArray3");
492 | if (y2 !== "bar2")
493 | throw new Error("PatternArray4");
494 | if (ys[0] !== "buz2")
495 | throw new Error("PatternArray5");
496 | if (ys[1] !== "qux2")
497 | throw new Error("PatternArray6");
498 | } ());
499 |
500 | // PatternDefault.js
501 | console.log("PatternDefault.js");
502 | (function () {
503 | let [x="foo", y="bar"] = [undefined, null];
504 | if (x !== "foo")
505 | throw new Error("PatternDefault1");
506 | if (y !== null)
507 | throw new Error("PatternDefault2");
508 | } ());
509 |
510 | // PatternObject.js
511 | console.log("PatternObject.js");
512 | (function () {
513 | let {x, y:z} = {x:"foo", y:"bar"};
514 | if (x !== "foo")
515 | throw new Error("PatternObject1");
516 | if (z !== "bar")
517 | throw new Error("PatternObject2");
518 | } ());
519 |
520 | // Rest.js
521 | console.log("Rest.js");
522 | (function () {
523 | let f = function (x, ...xs) {
524 | if (x !== "foo")
525 | throw new Error("Rest1");
526 | if (xs[0] !== "bar")
527 | throw new Error("Rest2");
528 | if (xs[1] !== "qux")
529 | throw new Error("Rest3");
530 | };
531 | f("foo", "bar", "qux");
532 | } ());
533 |
534 | // Return.js
535 | console.log("Return.js");
536 | (function () {
537 | let f = function () {
538 | return;
539 | throw new Error("Return1");
540 | }
541 | if (f() !== undefined)
542 | throw new Error("Return2");
543 | } ());
544 |
545 | // Sequence.js
546 | console.log("Sequence.js");
547 | (function () {
548 | if ((1,2) !== 2)
549 | throw new Error("Sequence");
550 | } ());
551 |
552 | // Spread.js
553 | console.log("Spread.js");
554 | (function () {
555 | let f = function (x, y, z, t) {
556 | if (x !== 1)
557 | throw new Error("Spread1");
558 | if (y !== 2)
559 | throw new Error("Spread2");
560 | if (z !== 3)
561 | throw new Error("Spread3");
562 | if (t !== 4)
563 | throw new Error("Spread4")
564 | if (arguments.length !== 4)
565 | throw new Error("Spread5");
566 | }
567 | f (1, ...[2,3], 4);
568 | } ());
569 |
570 | // StrictFunction.js
571 | console.log("StrictFunction.js");
572 | (function () {
573 | (function () {
574 | "use strict";
575 | let f = function () {
576 | if (this !== undefined)
577 | throw new Error("Strict");
578 | }
579 | f();
580 | } ());
581 | } ());
582 |
583 | // StrictProgram.js
584 | console.log("StrictProgram.js");
585 | (function () {
586 | "use strict";
587 | let f = function () {
588 | if (this !== undefined)
589 | throw new Error("Strict");
590 | }
591 | f();
592 | } ());
593 |
594 | // Switch.js
595 | console.log("Switch.js");
596 | (function () {
597 | let i=0;
598 | switch (2) {
599 | case 1: throw new Error("Switch1");
600 | case 2: i++;
601 | default:
602 | i++;
603 | break;
604 | case 2: throw new Error("Switch2");
605 | }
606 | if(i !== 2)
607 | throw new Error("Switch3");
608 | } ());
609 |
610 | // TaggedTemplateExpression.js
611 | console.log("TaggedTemplateExpression.js");
612 | (function () {
613 |
614 | function f () {
615 | "use strict";
616 | if (this !== void 0)
617 | throw new Error("TaggedTemplateExpression1");
618 | if (arguments.length !== 2)
619 | throw new Error("TaggedTemplateExpression2");
620 | if (!Array.isArray(arguments[0]))
621 | throw new Error("TaggedTemplateExpression3");
622 | if (Reflect.isExtensible(arguments[0]))
623 | throw new Error("TaggedTemplateExpression4");
624 | if (arguments[0].length !== 2)
625 | throw new Error("TaggedTemplateExpression5");
626 | if (arguments[0][0] !== "foo")
627 | throw new Error("TaggedTemplateExpression6");
628 | if (arguments[0][1] !== "bar")
629 | throw new Error("TaggedTemplateExpression7");
630 | if (!Array.isArray(arguments[0].raw))
631 | throw new Error("TaggedTemplateExpression8");
632 | if (Reflect.isExtensible(arguments[0].raw))
633 | throw new Error("TaggedTemplateExpression9");
634 | if (arguments[0].raw.length !== 2)
635 | throw new Error("TaggedTemplateExpression10");
636 | if (arguments[0].raw[0] !== "foo")
637 | throw new Error("TaggedTemplateExpression11");
638 | if (arguments[0].raw[1] !== "bar")
639 | throw new Error("TaggedTemplateExpression12");
640 | if (arguments[1] !== 123)
641 | throw new Error("TaggedTemplateExpression13");
642 | return "abc";
643 | };
644 |
645 | if (f `foo${123}bar` !== "abc")
646 | throw new Error("TaggedTemplateExpression14");
647 |
648 | } ());
649 |
650 | // TemplateLiteral.js
651 | console.log("TemplateLiteral.js");
652 | (function () {
653 | if (`foo${"bar"}qux` !== "foobarqux")
654 | throw new Error("Template1");
655 |
656 | } ());
657 |
658 | // This.js
659 | console.log("This.js");
660 | (function () {
661 | let o = {
662 | f:function () {
663 | if (this !== o)
664 | throw new Error("This");
665 | }
666 | }
667 | o.f();
668 | } ());
669 |
670 | // Throw.js
671 | console.log("Throw.js");
672 | (function () {
673 | let c = false;
674 | let f = false;
675 | try {
676 | throw "ok";
677 | throw "BOUM";
678 | } catch (e) {
679 | c = e;
680 | } finally {
681 | f = true;
682 | }
683 | if (c !== "ok")
684 | throw new Error("Throw1");
685 | if (!f)
686 | throw new Error("Throw2");
687 | } ());
688 |
689 | // Unary.js
690 | console.log("Unary.js");
691 | (function () {
692 | if (!true)
693 | throw new Error("Unary1");
694 | let o = {a:1,b:2};
695 | delete o.a;
696 | if ("a" in o)
697 | throw new Error("Unary2");
698 | delete o["b"]
699 | if ("b" in o)
700 | throw new Error("Unary3");
701 | } ());
702 |
703 | // While.js
704 | console.log("While.js");
705 | (function () {
706 | let i = 0;
707 | while (i < 3)
708 | i++;
709 | if (i !== 3)
710 | throw new Error("While");
711 | } ());
712 |
713 | // With.js
714 | console.log("With.js");
715 | (function () {
716 | let o = {a:1};
717 | with (o) {
718 | if (a !== 1)
719 | throw new Error("With1");
720 | a = 2;
721 | }
722 | if (o.a !== 2)
723 | throw new Error("With2");
724 | } ());
725 |
726 |
--------------------------------------------------------------------------------