Skip to content

Instantly share code, notes, and snippets.

@IanSSenne
Created April 16, 2019 05:23
Show Gist options
  • Save IanSSenne/7f281123e4d74c0eca8196df849b4ab9 to your computer and use it in GitHub Desktop.
Save IanSSenne/7f281123e4d74c0eca8196df849b4ab9 to your computer and use it in GitHub Desktop.
const esprima = require("esprima");
const escodegen = require("escodegen");
const fs = require("fs");
const minify = require("terser");
const content = fs.readFileSync("./build.ts.js", "utf8");
const wrapper = fs.readFileSync("./builder/require.js", "utf8");
let ast = esprima.parseScript(content);
function walk(o, cb) {
if (o.type) {
o = cb(o);
}
for (let key in o) {
let v = o[key];
if (!v) continue;
if (v.constructor === Object || v.type) {
o[key] = walk(v, cb);
} else if (v.constructor === Array) {
for (let i = 0; i < v.length; i++) {
o[key][i] = walk(v[i], cb);
}
}
}
return o;
}
var names = {
'+': "PLUS",
'-': "MINUS",
'*': "MULTIPLY",
'/': "DIVIDE",
'%': "MOD",
'**': "EXPONENTIATION",
'^': "XOR",
'&': "AND",
'==': "EQUAL",
'!=': "NOTEQUAL",
'===': "STRICTEQUAL",
'!==': "STRICTNOTEQUAL",
'<': "LESSTHAN",
'>': "GREATERTHAN",
'<=': "LESSTHANEQUAL",
">=": "GREATERTHANEQUAL",
'<<': "LEFTSHIFT",
'>>': "RIGHTSHIFT",
'>>>': "UNSIGNEDRIGHTSHIFT",
"|": "OR"
};
let r = "";
for (let i in names) {
r += `${names[i]}(a,b){return a ${i} b;}\n`;
}
// fs.writeFileSync("overrides_template_autogenerated.js", r);
ast = walk(ast, function (node) {
if (node.type === "BinaryExpression") {
if (names[node.operator]) {
node.type = "CallExpression";
node.arguments = [node.left, node.right];
node.callee = {
"type": "MemberExpression",
"computed": false,
"object": {
"type": "MemberExpression",
"computed": false,
"object": {
"type": "Identifier",
"name": "_modules"
},
"property": {
"type": "Identifier",
"name": "overloads"
}
},
"property": {
"type": "Identifier",
"name": names[node.operator]
}
};
}
}
return node;
});
let intermediate = wrapper.replace("/*%overloads%*/", JSON.stringify(names)).replace("/*%content%*/", escodegen.generate(ast, {
parse: (...args) => JSON.parse(args[0]).constructor.name + "(" + args[0] + ")"
}));
fs.writeFileSync("build.temp.js", intermediate);
fs.writeFileSync("build.out.js", minify.minify(intermediate).code);
(function () {
function factory(name, op) {
let work = new Function("a", "b", "return a" + op + "b");
return (a, b) => {
let cons = a.constructor;
if (cons.overloads && cons.overloads[name]) {
return cons.overloads[name](a, b);
}
return work(a, b);
};
}
function make_overloads(o, r = {}) {
for (let i in o) {
r[o[i]] = factory(o[i], i);
}
return r;
}
let _modules = {
loaded: {},
unloaded: {},
_tryLoadUnloaded(name) {
const module = _modules.unloaded[name];
if (module) {
let exports = new Proxy({}, {
get(target, p, r) {
return target[p];
},
set(target, p, v) {
Object.defineProperty(target, p, {
value: v
});
return v;
}
});
let passin = [_modules.require, exports];
for (let i = 0; i < module.required.length; i++) {
if (module.required[i] == "require" || module.required[i] == "exports") {
continue;
}
_modules._tryLoadUnloaded(module.required[i]);
passin.push(_modules.loaded[module.required[i]]);
}
_modules.loaded[name] = module.definition(...passin) || exports;
delete _modules.unloaded[name];
}
},
require(thing) {
if (_modules.loaded[thing]) return _modules.loaded[thing];
if (_modules.unloaded[thing]) return _modules.unloaded[thing];
},
overloads: make_overloads( /*%overloads%*/ )
};
function define(name, required, definition) {
let module = {
required,
definition
};
_modules.unloaded[name] = module;
_modules._tryLoadUnloaded(name);
}
/*%content%*/
})()
(function () {
function factory(name, op) {
let work = new Function("a", "b", "return a" + op + "b");
return (a, b) => {
let cons = a.constructor;
if (cons.overloads && cons.overloads[name]) {
return cons.overloads[name](a, b);
}
return work(a, b);
};
}
function make_overloads(o, r = {}) {
for (let i in o) {
r[o[i]] = factory(o[i], i);
}
return r;
}
let _modules = {
loaded: {},
unloaded: {},
_tryLoadUnloaded(name) {
const module = _modules.unloaded[name];
if (module) {
let exports = new Proxy({}, {
get(target, p, r) {
return target[p];
},
set(target, p, v) {
Object.defineProperty(target, p, {
value: v
});
return v;
}
});
let passin = [_modules.require, exports];
for (let i = 0; i < module.required.length; i++) {
if (module.required[i] == "require" || module.required[i] == "exports") {
continue;
}
_modules._tryLoadUnloaded(module.required[i]);
passin.push(_modules.loaded[module.required[i]]);
}
_modules.loaded[name] = module.definition(...passin) || exports;
delete _modules.unloaded[name];
}
},
require(thing) {
if (_modules.loaded[thing]) return _modules.loaded[thing];
if (_modules.unloaded[thing]) return _modules.unloaded[thing];
},
overloads: make_overloads( {"+":"PLUS","-":"MINUS","*":"MULTIPLY","/":"DIVIDE","%":"MOD","**":"EXPONENTIATION","^":"XOR","&":"AND","==":"EQUAL","!=":"NOTEQUAL","===":"STRICTEQUAL","!==":"STRICTNOTEQUAL","<":"LESSTHAN",">":"GREATERTHAN","<=":"LESSTHANEQUAL",">=":"GREATERTHANEQUAL","<<":"LEFTSHIFT",">>":"RIGHTSHIFT",">>>":"UNSIGNEDRIGHTSHIFT","|":"OR"} )
};
function define(name, required, definition) {
let module = {
required,
definition
};
_modules.unloaded[name] = module;
_modules._tryLoadUnloaded(name);
}
define('types/Point', [
'require',
'exports'
], function (require, exports) {
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
add(o) {
return _modules.overloads.PLUS(this, o);
}
sub(o) {
return _modules.overloads.MINUS(this, o);
}
mult(o) {
return _modules.overloads.MULTIPLY(this, o);
}
div(o) {
return _modules.overloads.DIVIDE(this, o);
}
}
Point.overloads = {
PLUS(a, b) {
return new Point(_modules.overloads.PLUS(a.x, b.x), _modules.overloads.PLUS(a.y, b.y));
},
MINUS(a, b) {
return new Point(_modules.overloads.MINUS(a.x, b.x), _modules.overloads.MINUS(a.y, b.y));
},
MULTIPLY(a, b) {
return new Point(_modules.overloads.MULTIPLY(a.x, b.x), _modules.overloads.MULTIPLY(a.y, b.y));
},
DIVIDE(a, b) {
return new Point(_modules.overloads.DIVIDE(a.x, b.x), _modules.overloads.DIVIDE(a.y, b.y));
},
MOD(a, b) {
return new Point(_modules.overloads.MOD(a.x, b.x), _modules.overloads.MOD(a.y, b.y));
},
EXPONENTIATION(a, b) {
return new Point(_modules.overloads.EXPONENTIATION(a.x, b.x), _modules.overloads.EXPONENTIATION(a.y, b.y));
},
XOR(a, b) {
return new Point(_modules.overloads.XOR(a.x, b.x), _modules.overloads.XOR(a.y, b.y));
},
AND(a, b) {
return new Point(_modules.overloads.AND(a.x, b.x), _modules.overloads.AND(a.y, b.y));
},
LEFTSHIFT(a, b) {
return new Point(_modules.overloads.LEFTSHIFT(a.x, b.x), _modules.overloads.LEFTSHIFT(a.y, b.y));
},
RIGHTSHIFT(a, b) {
return new Point(_modules.overloads.RIGHTSHIFT(a.x, b.x), _modules.overloads.RIGHTSHIFT(a.y, b.y));
},
UNSIGNEDRIGHTSHIFT(a, b) {
return new Point(_modules.overloads.UNSIGNEDRIGHTSHIFT(a.x, b.x), _modules.overloads.UNSIGNEDRIGHTSHIFT(a.y, b.y));
},
OR(a, b) {
return new Point(_modules.overloads.OR(a.x, b.x), _modules.overloads.OR(a.y, b.y));
}
};
exports.default = Point;
});
define('index', [
'require',
'exports',
'types/Point'
], function (require, exports, Point_1) {
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
window['engine'] = { Point: Point_1.default };
let a = new Point_1.default(1, 2);
let b = new Point_1.default(3, 4);
console.log(_modules.overloads.PLUS(a, b));
});
})()
import Point from "./types/Point";
window["engine"] = {
Point
}
//example operation
let a = new Point(1,2);
let b = new Point(3,4);
console.log(a+b);
class Point {
x: number;
y: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
// @enumerable(false)
static overloads = {
PLUS(a, b) { return new Point(a.x + b.x, a.y + b.y); },
MINUS(a, b) { return new Point(a.x - b.x, a.y - b.y); },
MULTIPLY(a, b) { return new Point(a.x * b.x, a.y * b.y); },
DIVIDE(a, b) { return new Point(a.x / b.x, a.y / b.y); },
MOD(a, b) { return new Point(a.x % b.x, a.y % b.y); },
EXPONENTIATION(a, b) { return new Point(a.x ** b.x, a.y ** b.y); },
XOR(a, b) { return new Point(a.x ^ b.x, a.y ^ b.y); },
AND(a, b) { return new Point(a.x & b.x, a.y & b.y); },
LEFTSHIFT(a, b) { return new Point(a.x << b.x, a.y << b.y); },
RIGHTSHIFT(a, b) { return new Point(a.x >> b.x, a.y >> b.y); },
UNSIGNEDRIGHTSHIFT(a, b) { return new Point(a.x >>> b.x, a.y >>> b.y); },
OR(a, b) { return new Point(a.x | b.x, a.y | b.y); }
}
add(o) {
return (this as any) + o;
}
sub(o) {
return (this as any) - o;
}
mult(o) {
return (this as any) * o;
}
div(o) {
return (this as any) / o;
}
}
export default Point;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment