This commit is contained in:
Rolf Martin Glomsrud 2024-05-31 16:09:49 +02:00
parent cf200730f7
commit 3dd32df2c1
21 changed files with 109 additions and 597 deletions

View file

@ -1 +1,9 @@
# didactic-chainsaw
# JSTQL JavaScript Transform tool
This tool is created to transform JavaScript based on definitions written in a custom DSL called JSTQL
## JSTQL
This is a DSL created to define proposal transformations using templates. A transformation is defined by two templates, a template of what code snippets to search for **applicable to** and a template of how to transform those snippets **transform to**.
Examples of definitions for proposals can be found in [dsl_files](./dsl_files/)

View file

@ -1,19 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Page Title</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
body {
font-family: Arial, Helvetica, sans-serif;
}
</style>
</head>
<body>
<h1>Demo site</h1>
<p></p>
</body>
</html>

View file

@ -1,16 +0,0 @@
proposal MultiStmt{
case Smthn{
applicable to{
"let <<ident1:Identifier>> = <<funcIdent:Identifier | MemberExpression>>();
let <<ident2:Identifier>> = <<expr:Expression>>;
"
}
transform to {
"const ident2 = () => {
let <<ident1>> = <<funcIdent>>();
return <<expr>>;
}"
}
}
}

View file

@ -1,14 +0,0 @@
proposal Pipeline{
case SingleArgument {
applicable to {
"<<someFunctionIdent:Identifier || MemberExpression>>(<<otherFunctionIdent:Identifier || MemberExpression>>(<<arggg:Identifier>>));"
}
transform to {
"(<<arggg>> |> <<otherFunctionIdent>>(%)) |> <<someFunctionIdent>>(%);"
}
}
}

View file

@ -1,17 +0,0 @@
proposal Star{
case a {
applicable to {
"let <<ident:Identifier>> = () => {
<<statements: Statement>>
return <<returnVal : Expression>>;
}
"
}
transform to {
"let <<ident>> = do {
<<statements>>
<<returnVal>>
}"
}
}
}

View file

@ -1,10 +0,0 @@
proposal test_single_stmt{
pair one {
applicable to {
"let <<aaaa: Identifier >> = <<bbbb: Expression | Identifier>>"
}
transform to {
"let <<aaaa>> = 1 + <<bbbb>>;"
}
}
}

View file

@ -1,94 +0,0 @@
function parse() {
const input = ("input" |> document.getElementById(%)).value;
const data = 32 |> input.slice(%);
const compressedData = data |> decode_base64(%);
const uncompressed = pako.inflate(compressedData, {
to: "string"
});
const json = uncompressed |> JSON.parse(%);
json |> console.log(%);
json |> convertToDesktop(%);
}
function convertToDesktop(json) {
const newValues = {
crb: false,
newClanRaidClassId: 0,
newClanRaidClassLevel: 0,
pendingImmortalSouls: 0,
pendingRaidRubies: 0,
immortalSouls: 0,
lastPurchaseTime: 0,
lastRaidAttemptTimestamp: 0,
lastRaidRewardCheckTimestamp: 0,
shouldShowHZERoster: false,
lastBonusRewardCheckTimestamp: 0
};
const mappedValues = {
rubies: json.rubies / 10 |> Math.round(%)
};
const pcSpecificValues = {
readPatchNumber: "1.0e12",
saveOrigin: "pc"
};
const hash = "7a990d405d2c6fb93aa8fbb0ec1a3b23";
const newData = {
...newValues,
...json,
...mappedValues,
...pcSpecificValues
};
const compressed = pako.deflate(newData |> JSON.stringify(%), {
to: "string"
});
const base64 = compressed |> btoa(%);
const finalSaveString = hash + base64;
("output_output" |> document.getElementById(%)).innerText = finalSaveString;
showOutput();
}
function showOutput() {
("outputs" |> document.getElementById(%)).style.visibility = "visible";
}
function copyOutput() {
const output = "output_output" |> document.getElementById(%);
output.disabled = false;
output.focus();
output.select();
"copy" |> document.execCommand(%);
output.disabled = true;
const successElement = "copy_success_msg" |> document.getElementById(%);
successElement.style.visibility = "visible";
setTimeout(() => successElement.style.visibility = "hidden", 4000);
}
function decode_base64(s) {
let e = {},
i,
k,
v = [],
r = "",
w = String.fromCharCode;
let n = [[65, 91], [97, 123], [48, 58], [43, 44], [47, 48]];
for (z in n) {
for (i = n[z][0]; i < n[z][1]; i++) {
i |> w(%) |> v.push(%);
}
}
for (i = 0; i < 64; i++) {
e[v[i]] = i;
}
for (i = 0; i < s.length; i += 72) {
let b = 0,
c,
x,
l = 0,
o = s.substring(i, i + 72);
for (x = 0; x < o.length; x++) {
c = e[x |> o.charAt(%)];
b = (b << 6) + c;
l += 6;
while (l >= 8) {
r += (b >>> (l -= 8)) % 256 |> w(%);
}
}
}
return r;
}

View file

@ -1,9 +0,0 @@
async function something() {
let a = 100;
a *= 100000;
return fetch("https://uib.no").then(uib => {
a += 100000;
a -= 1000;
return [a, uib];
});
}

View file

@ -1,12 +0,0 @@
let aaaa = do {
let g = 100;
let ff = 10;
let ggg = a(b);
100
};
var bbaaa = do {
let lllll = 1 + 1;
100 + 100;
const aaaaa = aaaa(bb);
lllll
};

View file

@ -1,2 +0,0 @@
let ThisTest = LOOOOOOOOL();
let HAHHAHAH = 1 + 1;

View file

@ -1,4 +0,0 @@
a |> w(%) |> w(%) |> w(%) |> w(%) |> w(%) |> w(%) |> w(%) |> w(%) |> w(%) |> w(%);
a |> b(%, a |> b(%, a |> b(%, a |> b(%, a |> b(%, a |> b(%, a |> b(%, b)))))));
a |> b(%, a) |> b(%, a) |> b(%, a) |> b(%, a) |> b(%, a) |> b(%, a) |> b(%, a) |> b(%, a) |> b(%, a) |> b(%, a) |> b(%, a) |> b(%, a);
b(b(b(b(a, a, a), a, a), a, a), a, a);

View file

@ -1,4 +0,0 @@
a |> w(%) |> w(%) |> w(%) |> w(%) |> w(%) |> w(%) |> w(%) |> w(%) |> w(%) |> w(%);
a |> b(%, a |> b(%, a |> b(%, a |> b(%, a |> b(%, a |> b(%, a |> b(%, b)))))));
a |> b(%, a) |> b(%, a) |> b(%, a) |> b(%, a) |> b(%, a) |> b(%, a) |> b(%, a) |> b(%, a) |> b(%, a) |> b(%, a) |> b(%, a) |> b(%, a);
b(b(b(b(a, a, a), a, a), a, a), a, a);

View file

@ -1,104 +0,0 @@
return awaitedExpr.then(async _geometry => {
const _intersectPoint = /*@__PURE__*/new Vector3();
const _worldScale = /*@__PURE__*/new Vector3();
const _mvPosition = /*@__PURE__*/new Vector3();
const _alignedPosition = /*@__PURE__*/new Vector2();
const _rotatedPosition = /*@__PURE__*/new Vector2();
const _viewWorldMatrix = /*@__PURE__*/new Matrix4();
const _vA = /*@__PURE__*/new Vector3();
const _vB = /*@__PURE__*/new Vector3();
const _vC = /*@__PURE__*/new Vector3();
const _uvA = /*@__PURE__*/new Vector2();
const _uvB = /*@__PURE__*/new Vector2();
const _uvC = /*@__PURE__*/new Vector2();
class Sprite extends Object3D {
constructor(material = new SpriteMaterial()) {
super();
this.isSprite = true;
this.type = "Sprite";
if (_geometry === undefined) {
_geometry = new BufferGeometry();
const float32Array = new Float32Array([-0.5, -0.5, 0, 0, 0, 0.5, -0.5, 0, 1, 0, 0.5, 0.5, 0, 1, 1, -0.5, 0.5, 0, 0, 1]);
const interleavedBuffer = new InterleavedBuffer(float32Array, 5);
_geometry.setIndex([0, 1, 2, 0, 2, 3]);
_geometry.setAttribute("position", new InterleavedBufferAttribute(interleavedBuffer, 3, 0, false));
_geometry.setAttribute("uv", new InterleavedBufferAttribute(interleavedBuffer, 2, 3, false));
}
this.geometry = _geometry;
this.material = material;
this.center = new Vector2(0.5, 0.5);
}
raycast(raycaster, intersects) {
if (raycaster.camera === null) {
console.error('THREE.Sprite: "Raycaster.camera" needs to be set in order to raycast against sprites.');
}
_worldScale.setFromMatrixScale(this.matrixWorld);
_viewWorldMatrix.copy(raycaster.camera.matrixWorld);
this.modelViewMatrix.multiplyMatrices(raycaster.camera.matrixWorldInverse, this.matrixWorld);
_mvPosition.setFromMatrixPosition(this.modelViewMatrix);
if (raycaster.camera.isPerspectiveCamera && this.material.sizeAttenuation === false) {
_worldScale.multiplyScalar(-_mvPosition.z);
}
const rotation = this.material.rotation;
let sin, cos;
if (rotation !== 0) {
cos = Math.cos(rotation);
sin = Math.sin(rotation);
}
const center = this.center;
transformVertex(_vA.set(-0.5, -0.5, 0), _mvPosition, center, _worldScale, sin, cos);
transformVertex(_vB.set(0.5, -0.5, 0), _mvPosition, center, _worldScale, sin, cos);
transformVertex(_vC.set(0.5, 0.5, 0), _mvPosition, center, _worldScale, sin, cos);
_uvA.set(0, 0);
_uvB.set(1, 0);
_uvC.set(1, 1);
// check first triangle
let intersect = raycaster.ray.intersectTriangle(_vA, _vB, _vC, false, _intersectPoint);
if (intersect === null) {
// check second triangle
transformVertex(_vB.set(-0.5, 0.5, 0), _mvPosition, center, _worldScale, sin, cos);
_uvB.set(0, 1);
intersect = raycaster.ray.intersectTriangle(_vA, _vC, _vB, false, _intersectPoint);
if (intersect === null) {
return;
}
}
const distance = raycaster.ray.origin.distanceTo(_intersectPoint);
if (distance < raycaster.near || distance > raycaster.far) return;
intersects.push({
distance: distance,
point: _intersectPoint.clone(),
uv: Triangle.getInterpolation(_intersectPoint, _vA, _vB, _vC, _uvA, _uvB, _uvC, new Vector2()),
face: null,
object: this
});
}
copy(source, recursive) {
super.copy(source, recursive);
if (source.center !== undefined) this.center.copy(source.center);
this.material = source.material;
return this;
}
}
function transformVertex(vertexPosition, mvPosition, center, scale, sin, cos) {
// compute position in camera space
_alignedPosition.subVectors(vertexPosition, center).addScalar(0.5).multiply(scale);
// to check if rotation is not zero
if (sin !== undefined) {
_rotatedPosition.x = cos * _alignedPosition.x - sin * _alignedPosition.y;
_rotatedPosition.y = sin * _alignedPosition.x + cos * _alignedPosition.y;
} else {
_rotatedPosition.copy(_alignedPosition);
}
vertexPosition.copy(mvPosition);
vertexPosition.x += _rotatedPosition.x;
vertexPosition.y += _rotatedPosition.y;
// transform to world space
vertexPosition.applyMatrix4(_viewWorldMatrix);
}
export { Sprite };
return returnExpr;
});

View file

@ -1,94 +0,0 @@
function parse() {
const input = ("input" |> document.getElementById(%)).value;
const data = 32 |> input.slice(%);
const compressedData = data |> decode_base64(%);
const uncompressed = compressedData |> pako.inflate(%, {
to: "string"
});
const json = uncompressed |> JSON.parse(%);
json |> console.log(%);
json |> convertToDesktop(%);
}
function convertToDesktop(json) {
const newValues = {
crb: false,
newClanRaidClassId: 0,
newClanRaidClassLevel: 0,
pendingImmortalSouls: 0,
pendingRaidRubies: 0,
immortalSouls: 0,
lastPurchaseTime: 0,
lastRaidAttemptTimestamp: 0,
lastRaidRewardCheckTimestamp: 0,
shouldShowHZERoster: false,
lastBonusRewardCheckTimestamp: 0
};
const mappedValues = {
rubies: json.rubies / 10 |> Math.round(%)
};
const pcSpecificValues = {
readPatchNumber: "1.0e12",
saveOrigin: "pc"
};
const hash = "7a990d405d2c6fb93aa8fbb0ec1a3b23";
const newData = {
...newValues,
...json,
...mappedValues,
...pcSpecificValues
};
const compressed = newData |> JSON.stringify(%) |> pako.deflate(%, {
to: "string"
});
const base64 = compressed |> btoa(%);
const finalSaveString = hash + base64;
("output_output" |> document.getElementById(%)).innerText = finalSaveString;
showOutput();
}
function showOutput() {
("outputs" |> document.getElementById(%)).style.visibility = "visible";
}
function copyOutput() {
const output = "output_output" |> document.getElementById(%);
output.disabled = false;
output.focus();
output.select();
"copy" |> document.execCommand(%);
output.disabled = true;
const successElement = "copy_success_msg" |> document.getElementById(%);
successElement.style.visibility = "visible";
(() => successElement.style.visibility = "hidden") |> setTimeout(%, 4000);
}
function decode_base64(s) {
let e = {},
i,
k,
v = [],
r = "",
w = String.fromCharCode;
let n = [[65, 91], [97, 123], [48, 58], [43, 44], [47, 48]];
for (z in n) {
for (i = n[z][0]; i < n[z][1]; i++) {
i |> w(%) |> v.push(%);
}
}
for (i = 0; i < 64; i++) {
e[v[i]] = i;
}
for (i = 0; i < s.length; i += 72) {
let b = 0,
c,
x,
l = 0,
o = i |> s.substring(%, i + 72);
for (x = 0; x < o.length; x++) {
c = e[x |> o.charAt(%)];
b = (b << 6) + c;
l += 6;
while (l >= 8) {
r += (b >>> (l -= 8)) % 256 |> w(%);
}
}
}
return r;
}

View file

@ -1,9 +0,0 @@
async function something() {
let a = 100;
a *= 100000;
return fetch("https://uib.no").then(uib => {
a += 100000;
a -= 1000;
return [a, uib];
});
}

View file

@ -1,98 +0,0 @@
// "fast-glob" and `createTwoFilesPatch` are bundled here since the API uses `micromatch` and `diff` too
import { createTwoFilesPatch } from "diff/lib/patch/create.js";
import fastGlob from "fast-glob";
import * as vnopts from "vnopts";
import * as errors from "./common/errors.js";
import getFileInfoWithoutPlugins from "./common/get-file-info.js";
import mockable from "./common/mockable.js";
import { clearCache as clearConfigCache, resolveConfig, resolveConfigFile } from "./config/resolve-config.js";
import * as core from "./main/core.js";
import { formatOptionsHiddenDefaults } from "./main/normalize-format-options.js";
import normalizeOptions from "./main/normalize-options.js";
import * as optionCategories from "./main/option-categories.js";
import { clearCache as clearPluginCache, loadBuiltinPlugins, loadPlugins } from "./main/plugins/index.js";
import { getSupportInfo as getSupportInfoWithoutPlugins, normalizeOptionSettings } from "./main/support.js";
import { createIsIgnoredFunction } from "./utils/ignore.js";
import isNonEmptyArray from "./utils/is-non-empty-array.js";
import omit from "./utils/object-omit.js";
import partition from "./utils/partition.js";
/**
* @param {*} fn
* @param {number} [optionsArgumentIndex]
* @returns {*}
*/
function withPlugins(fn, optionsArgumentIndex = 1 // Usually `options` is the 2nd argument
) {
return async (...args) => {
const options = args[optionsArgumentIndex] ?? {};
const {
plugins = []
} = options;
args[optionsArgumentIndex] = {
...options,
plugins: (await ([loadBuiltinPlugins(), plugins |> loadPlugins(%)] |> Promise.all(%))).flat()
};
return fn(...args);
};
}
const formatWithCursor = core.formatWithCursor |> withPlugins(%);
async function format(text, options) {
const {
formatted
} = await (text |> formatWithCursor(%, {
...options,
cursorOffset: -1
}));
return formatted;
}
async function check(text, options) {
return (await (text |> format(%, options))) === text;
}
// eslint-disable-next-line require-await
async function clearCache() {
clearConfigCache();
clearPluginCache();
}
/** @type {typeof getFileInfoWithoutPlugins} */
const getFileInfo = getFileInfoWithoutPlugins |> withPlugins(%);
/** @type {typeof getSupportInfoWithoutPlugins} */
const getSupportInfo = getSupportInfoWithoutPlugins |> withPlugins(%, 0);
// Internal shared with cli
const sharedWithCli = {
errors,
optionCategories,
createIsIgnoredFunction,
formatOptionsHiddenDefaults,
normalizeOptions,
getSupportInfoWithoutPlugins,
normalizeOptionSettings,
vnopts: {
ChoiceSchema: vnopts.ChoiceSchema,
apiDescriptor: vnopts.apiDescriptor
},
fastGlob,
createTwoFilesPatch,
utils: {
isNonEmptyArray,
partition,
omit
},
mockable
};
const debugApis = {
parse: core.parse |> withPlugins(%),
formatAST: core.formatAst |> withPlugins(%),
formatDoc: core.formatDoc |> withPlugins(%),
printToDoc: core.printToDoc |> withPlugins(%),
printDocToString: core.printDocToString |> withPlugins(%),
mockable
};
export { debugApis as __debug, sharedWithCli as __internal, check, clearCache as clearConfigCache, format, formatWithCursor, getFileInfo, getSupportInfo, resolveConfig, resolveConfigFile };
export * as doc from "./document/public.js";
export { default as version } from "./main/version.evaluate.cjs";
export * as util from "./utils/public.js";

66
src/evalRunner.ts Normal file
View file

@ -0,0 +1,66 @@
import { transform } from "./transform/transform";
import { readdir } from "node:fs/promises";
import { parseJSTQL } from "./langium/langiumRunner";
const main = async () => {
let basepathExamplesJSFiles = "../atom";
let examples = (await readdir(basepathExamplesJSFiles, { recursive: true }))
.filter((x) => x.endsWith(".js"))
.map((x) => basepathExamplesJSFiles + "/" + x);
console.log(examples);
let result = [];
for (let proposalFile of [
"pipeline.jstql",
"do.jstql",
"awaitToPromise.jstql",
]) {
const jstql_file = "dsl_files/" + proposalFile;
const test_file = Bun.file(jstql_file);
const test_JSTQL = await test_file.text();
let proposals = await parseJSTQL(test_JSTQL);
let sum = 0;
let failures = 0;
let filesSucceeded = 0;
console.log("Scripts found ", sum, "matches!");
let count = 0;
for (let examplesFile of examples) {
try {
if (examplesFile.split("/").includes("compiled")) {
//continue;
}
console.log(examplesFile);
let script = await Bun.file(examplesFile).text();
let [resultString, matches] = transform(
proposals[0].cases,
script
);
sum += matches;
console.log(matches);
if (matches > 0) {
await Bun.write(
"output_testing/" +
count +
examplesFile.split("/").join("_"),
resultString
);
count += 1;
}
filesSucceeded += 1;
} catch (e) {
failures += 1;
//console.log(e);
}
console.log("current sum", sum);
}
result.push(
proposalFile + ", " + sum + ", " + count + ", " + filesSucceeded
);
}
for (let res of result) {
console.log(res);
}
};
main();

View file

@ -10,83 +10,46 @@ import {
import { readdir } from "node:fs/promises";
import { parseJSTQL } from "./langium/langiumRunner";
const dir = "../prettier/src";
import { parseArgs } from "util";
const path = "test_files/test2.js";
const file = Bun.file(path);
const codeFromFile = await file.text();
const options = {
o: {
type: "string",
},
};
const { values: argVals, tokens: positional } = parseArgs({
options,
tokens: true,
allowPositionals: true,
});
const main = async () => {
//transform(selfHostedTransformExampleMultiStmt, codeFromFile);
/*
console.log(codeFromFile);
const jstql_file =
"/home/rolfmg/Coding/Master/didactic-chainsaw/dsl_files/awaitToPromise.jstql";
const test_file = Bun.file(jstql_file);
const test_JSTQL = await test_file.text();
let proposals = await parseJSTQL(test_JSTQL);
let [code, count] = transform(proposals[0].cases, codeFromFile);
await Bun.write("output_files/test2.js", code);
return;
*/
let basepathExamplesJSFiles = "../next.js";
let examples = (await readdir(basepathExamplesJSFiles, { recursive: true }))
.filter((x) => x.endsWith(".js"))
.map((x) => basepathExamplesJSFiles + "/" + x);
console.log(examples);
let result = [];
for (let proposalFile of [
"pipeline.jstql",
"do.jstql",
"awaitToPromise.jstql",
]) {
const jstql_file = "dsl_files/" + proposalFile;
const test_file = Bun.file(jstql_file);
const test_JSTQL = await test_file.text();
let proposals = await parseJSTQL(test_JSTQL);
let sum = 0;
let failures = 0;
let filesSucceeded = 0;
console.log("Scripts found ", sum, "matches!");
let count = 0;
for (let examplesFile of examples) {
try {
if (examplesFile.split("/").includes("compiled")) {
//continue;
}
console.log(examplesFile);
let script = await Bun.file(examplesFile).text();
let [resultString, matches] = transform(
proposals[0].cases,
script
);
sum += matches;
console.log(matches);
if (matches > 0) {
await Bun.write(
"output_testing/" +
count +
examplesFile.split("/").join("_"),
resultString
);
count += 1;
}
filesSucceeded += 1;
} catch (e) {
failures += 1;
//console.log(e);
}
console.log("current sum", sum);
}
result.push(
proposalFile + ", " + sum + ", " + count + ", " + filesSucceeded
console.log(positional);
if (!positional[0] || !positional[0].value.endsWith(".jstql")) {
throw new Error("First positional argument is current JSTQL file");
}
if (!positional[1] || !positional[1].value.endsWith(".js")) {
throw new Error(
"Second positional argument is JS code to be transformed"
);
}
const jstql_file = positional[0].value;
const code_file = positional[1].value;
for (let res of result) {
console.log(res);
let jstqlString = await Bun.file(jstql_file).text();
let codeString = await Bun.file(code_file).text();
let parsedJSTQL = await parseJSTQL(jstqlString);
for (let proposal of parsedJSTQL) {
let [resultString, matches] = transform(proposal.cases, codeString);
let path = "./";
if (argVals["o"]) {
path = argVals["o"];
}
Bun.write(path, resultString);
}
};

View file

@ -1,7 +0,0 @@
let a = LOOOOOOOOL();
let b = (999 * 128) / 12;
const haha = () => {
let a = LOOOOOOOOL();
let b = (999 * 128) / 12;
};

View file

@ -1,8 +0,0 @@
let something = 1 + 1;
let yikers = hahahah;
let lol = () => 100 + 100;
function haha() {
let fhdsjkfhdsjkfhds = fjhdkslfjhdsklfjdskl;
}

View file

@ -1,4 +0,0 @@
let x = () => {
let b = 0;
return b;
};