idk dude, something is very bad with the transformation

This commit is contained in:
Rolf Martin Glomsrud 2024-05-13 19:12:23 +02:00
parent b9cd5a1de9
commit b1a3ece8f1
15 changed files with 2733 additions and 2612 deletions

BIN
bun.lockb

Binary file not shown.

View file

@ -0,0 +1,16 @@
proposal MultiStmt{
pair Smthn{
applicable to{
"let <<something:Identifier>> = <<aiai:Identifier | MemberExpression>>();
let <<binaryExprLOL:Identifier>> = 1 + 1;
"
}
transform to {
"() => {
let <<something>> = <<aiai>>();
return <<binaryExprLOL>>;
}"
}
}
}

View file

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

View file

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

5153
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -9,6 +9,7 @@
"devDependencies": {
"@babel/plugin-proposal-pipeline-operator": "^7.23.3",
"@swc/cli": "^0.1.62",
"@types/babel__generator": "^7.6.8",
"@types/node": "^20.5.9",
"bun-types": "latest",
"typescript": "^5.2.2"
@ -18,8 +19,8 @@
"@babel/generator": "^7.23.0",
"@babel/parser": "^7.23.0",
"@babel/traverse": "^7.23.0",
"@types/babel-traverse": "^6.25.10",
"@types/babel__traverse": "^7.20.5",
"@types/babel-traverse": "^6.25.10",
"babel": "^6.23.0",
"bun": "^1.0.4",
"ts-node": "^10.9.1"

View file

@ -10,7 +10,7 @@ import {
import { parseDSLtoAST } from "../didactic-chainsaw-dsl/src/JSTQL_interface/fetchAST";
import { parseJSTQL } from "./langium/langiumRunner";
const path = "test.js";
const path = "test_files/test.js";
const file = Bun.file(path);
const codeFromFile = await file.text();
const main = async () => {
@ -23,7 +23,7 @@ const main = async () => {
let proposals = await parseJSTQL(test_JSTQL);
await Bun.write(
"output.js",
"output_files/output.js",
transform(proposals[0].pairs[0], codeFromFile)
);
};

View file

@ -22,17 +22,29 @@ export function runMatch(
internals: InternalDSLVariable
): TreeNode<PairedNodes>[] {
// Special case for a single expression, we have to remove "ExpressionStatement" node.
if (
applicableTo.children.length === 1 &&
applicableTo.children[0].element.type === "ExpressionStatement"
) {
let matcher = new Matcher(
internals,
applicableTo.children[0].children[0].element
);
matcher.singleExprMatcher(code, applicableTo.children[0].children[0]);
return matcher.matches;
if (applicableTo.children.length === 1) {
if (applicableTo.children[0].element.type === "ExpressionStatement") {
let matcher = new Matcher(
internals,
applicableTo.children[0].children[0].element
);
matcher.singleExprMatcher(
code,
applicableTo.children[0].children[0]
);
return matcher.matches;
} else {
let matcher = new Matcher(
internals,
applicableTo.children[0].element
);
matcher.singleExprMatcher(code, applicableTo.children[0]);
return matcher.matches;
}
} else {
showTree(code);
showTree(applicableTo);
let matcher = new Matcher(internals, applicableTo.element);
matcher.multiStatementMatcher(code, applicableTo);
return matcher.matches;
@ -53,28 +65,30 @@ export class Matcher {
code: TreeNode<t.Node>,
aplTo: TreeNode<t.Node>
): TreeNode<PairedNodes> | undefined {
// If we are at start of ApplicableTo, start a new search on each of the child nodes
if (aplTo.element === this.aplToFull) {
// Perform a new search on all child nodes before trying to verify current node
let temp = [];
// If any matches bubble up from child nodes, we have to store it
for (let code_child of code.children) {
let maybeChildMatch = this.singleExprMatcher(code_child, aplTo);
if (maybeChildMatch) {
temp.push(maybeChildMatch);
}
}
// Store all full matches
this.matches.push(...temp);
}
// Check if the current matches
let curMatches = this.checkCodeNode(code.element, aplTo.element);
curMatches =
curMatches && code.children.length >= aplTo.children.length;
// Current does not match and we have searched all the children, so just return early
// This ensures we only store the child search when we don't only have a partial match
let temp = [];
// If any matches bubble up from child nodes, we have to store it
for (let code_child of code.children) {
let maybeChildMatch = this.singleExprMatcher(code_child, aplTo);
if (maybeChildMatch) {
temp.push(maybeChildMatch);
}
}
// Filter the output for full matches :)
this.matches.push(
...temp.filter((x) => x.element.aplToNode === this.aplToFull)
);
if (!curMatches) {
return;
}
// At this point current does match
// Perform a search on each of the children of both AplTo and Code.
let pairedCurrent: TreeNode<PairedNodes> = new TreeNode(null, {
codeNode: code.element,
aplToNode: aplTo.element,
@ -85,7 +99,7 @@ export class Matcher {
aplTo.children[i]
);
if (childSearch === undefined) {
// Failed to get a full match, so break here
// Failed to get a full match, so early return here
return;
}
childSearch.parent = pairedCurrent;
@ -96,10 +110,71 @@ export class Matcher {
return pairedCurrent;
}
// This is broken
multiStatementMatcher(code: TreeNode<t.Node>, aplTo: TreeNode<t.Node>) {}
multiStatementMatcher(code: TreeNode<t.Node>, aplTo: TreeNode<t.Node>) {
if (
code.element.type === "Program" ||
code.element.type === "BlockStatement"
) {
this.matchMultiHead(code.children, aplTo.children);
}
for (let code_child of code.children) {
this.multiStatementMatcher(code_child, aplTo);
}
}
matchMultiHead(code: TreeNode<t.Node>[], aplTo: TreeNode<t.Node>[]) {
// Sliding window the size of aplTo
for (let y = 0; y <= code.length - aplTo.length; y++) {
let fullMatch = true;
let collection: TreeNode<PairedNodes>[] = [];
for (let i = 0; i < aplTo.length; i++) {
let res = this.exactExprMatcher(code[i + y], aplTo[i]);
if (!res) {
fullMatch = false;
break;
}
collection.push(res);
}
if (fullMatch) {
this.matches.push(...collection);
}
}
}
exactExprMatcher(
code: TreeNode<t.Node>,
aplTo: TreeNode<t.Node>
): TreeNode<PairedNodes> | undefined {
let curMatches =
this.checkCodeNode(code.element, aplTo.element) &&
code.children.length >= aplTo.children.length;
if (!curMatches) {
return undefined;
}
let paired: TreeNode<PairedNodes> = new TreeNode(null, {
aplToNode: aplTo.element,
codeNode: code.element,
});
for (let i = 0; i < aplTo.children.length; i++) {
let childRes = this.exactExprMatcher(
code.children[i],
aplTo.children[i]
);
if (!childRes) {
// If child is not match the entire thing is not a match;
return undefined;
}
// This is a match, so we store it
childRes.parent = paired;
paired.children.push(childRes);
}
return paired;
}
match(code: TreeNode<t.Node>, aplTo: TreeNode<t.Node>) {}
private checkCodeNode(code_node: t.Node, aplTo: t.Node): boolean {
// First verify the internal DSL variables

View file

@ -3,7 +3,7 @@ import { TransformRecipe, transform } from "../transform/transform";
const transformExample: TransformRecipe = {
applicableTo: `<<a>>(<<b:Identifier|Expression>>);`,
transformTo: "b |> a(%)",
transformTo: "<<b>> |> <<a>>(%)",
};
const code =
"a(something);a(1+1);something(some_other_thing + 1 + 10 + 100); console.log(a)";

View file

@ -15,7 +15,7 @@ import {
import { runMatch } from "../matcher/matcher";
import { transformMatch, transformer } from "./transformMatch";
import { preludeBuilder } from "../parser/preludeBuilder";
import * as babelparser from "@babel/parser";
export interface Proposal {
pairs: TransformRecipe[];
}
@ -27,7 +27,7 @@ export interface TransformRecipe {
export interface SelfHostedRecipe extends TransformRecipe {
prelude: string;
}
export function transform(recipe: TransformRecipe, code: string) {
export function transform(recipe: TransformRecipe, code: string): string {
if ((<SelfHostedRecipe>recipe).prelude !== undefined) {
// We are using the self hosted version
return transformSelfHosted(
@ -61,7 +61,7 @@ function transformSelfHosted(
recipe: TransformRecipe,
internals: InternalDSLVariable,
code: string
) {
): string {
console.log(recipe);
let codeAST = parse_with_plugins(code);
let codeTree = makeTree(codeAST);
@ -81,25 +81,20 @@ function transformSelfHosted(
let matches = runMatch(codeTree, applicableToTree, internals);
for (let match of matches) {
showTreePaired(match);
console.log(generate(match.element.codeNode).code);
}
console.log(matches.length);
for (let match of matches.reverse()) {
//console.log(transformToTree.element);
let output = structuredClone(transformToTree.element);
// There is a bug here, for some reason it works sometimes when Program and sometimes when File, no clue why?????
let output = parse_with_plugins(recipe.transformTo).program;
try {
transformer(match, transformToTree, output, codeAST);
} catch (error) {
console.log("We failed to transform an element!");
console.log(error);
}
}
console.log("Final generated code: \n");
let output = generate(codeAST, { topicToken: "%" }).code;
//showTree(transformToTree);
return output;
}

View file

@ -11,6 +11,7 @@ import {
import { InternalDSLVariable } from "../parser/parse";
import { MatchedTreeNode, PairedNodes } from "../matcher/matcher";
import traverse from "@babel/traverse";
import generate from "@babel/generator";
export function transformer(
match: TreeNode<PairedNodes>,
@ -48,7 +49,6 @@ export function transformMatch(
traverse(output, {
enter(path) {
if (path.isIdentifier({ name: trnTo.element.name })) {
console.log(match.element.codeNode);
if (match.element.codeNode) {
path.replaceWith(match.element.codeNode);
}

View file

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

View file

@ -0,0 +1 @@
let something = 1 + 1;