idk dude, something is very bad with the transformation
This commit is contained in:
parent
3d3865d625
commit
bf3abd232c
15 changed files with 2733 additions and 2612 deletions
BIN
bun.lockb
BIN
bun.lockb
Binary file not shown.
16
dsl_files/multi_stmt_test.jstql
Normal file
16
dsl_files/multi_stmt_test.jstql
Normal 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>>;
|
||||||
|
}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
10
dsl_files/test_single_stmt.jstql
Normal file
10
dsl_files/test_single_stmt.jstql
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
proposal test_single_stmt{
|
||||||
|
pair one {
|
||||||
|
applicable to {
|
||||||
|
"let <<aaaa: Identifier >> = <<bbbb: Expression | Identifier>>"
|
||||||
|
}
|
||||||
|
transform to {
|
||||||
|
"let <<aaaa>> = () => <<bbbb>>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
2
output_files/output_multi.js
Normal file
2
output_files/output_multi.js
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
let ThisTest = LOOOOOOOOL();
|
||||||
|
let HAHHAHAH = 1 + 1;
|
5153
package-lock.json
generated
5153
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -9,6 +9,7 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/plugin-proposal-pipeline-operator": "^7.23.3",
|
"@babel/plugin-proposal-pipeline-operator": "^7.23.3",
|
||||||
"@swc/cli": "^0.1.62",
|
"@swc/cli": "^0.1.62",
|
||||||
|
"@types/babel__generator": "^7.6.8",
|
||||||
"@types/node": "^20.5.9",
|
"@types/node": "^20.5.9",
|
||||||
"bun-types": "latest",
|
"bun-types": "latest",
|
||||||
"typescript": "^5.2.2"
|
"typescript": "^5.2.2"
|
||||||
|
@ -18,8 +19,8 @@
|
||||||
"@babel/generator": "^7.23.0",
|
"@babel/generator": "^7.23.0",
|
||||||
"@babel/parser": "^7.23.0",
|
"@babel/parser": "^7.23.0",
|
||||||
"@babel/traverse": "^7.23.0",
|
"@babel/traverse": "^7.23.0",
|
||||||
"@types/babel-traverse": "^6.25.10",
|
|
||||||
"@types/babel__traverse": "^7.20.5",
|
"@types/babel__traverse": "^7.20.5",
|
||||||
|
"@types/babel-traverse": "^6.25.10",
|
||||||
"babel": "^6.23.0",
|
"babel": "^6.23.0",
|
||||||
"bun": "^1.0.4",
|
"bun": "^1.0.4",
|
||||||
"ts-node": "^10.9.1"
|
"ts-node": "^10.9.1"
|
||||||
|
|
|
@ -10,7 +10,7 @@ import {
|
||||||
|
|
||||||
import { parseDSLtoAST } from "../didactic-chainsaw-dsl/src/JSTQL_interface/fetchAST";
|
import { parseDSLtoAST } from "../didactic-chainsaw-dsl/src/JSTQL_interface/fetchAST";
|
||||||
import { parseJSTQL } from "./langium/langiumRunner";
|
import { parseJSTQL } from "./langium/langiumRunner";
|
||||||
const path = "test.js";
|
const path = "test_files/test.js";
|
||||||
const file = Bun.file(path);
|
const file = Bun.file(path);
|
||||||
const codeFromFile = await file.text();
|
const codeFromFile = await file.text();
|
||||||
const main = async () => {
|
const main = async () => {
|
||||||
|
@ -23,7 +23,7 @@ const main = async () => {
|
||||||
let proposals = await parseJSTQL(test_JSTQL);
|
let proposals = await parseJSTQL(test_JSTQL);
|
||||||
|
|
||||||
await Bun.write(
|
await Bun.write(
|
||||||
"output.js",
|
"output_files/output.js",
|
||||||
transform(proposals[0].pairs[0], codeFromFile)
|
transform(proposals[0].pairs[0], codeFromFile)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -22,17 +22,29 @@ export function runMatch(
|
||||||
internals: InternalDSLVariable
|
internals: InternalDSLVariable
|
||||||
): TreeNode<PairedNodes>[] {
|
): TreeNode<PairedNodes>[] {
|
||||||
// Special case for a single expression, we have to remove "ExpressionStatement" node.
|
// Special case for a single expression, we have to remove "ExpressionStatement" node.
|
||||||
if (
|
if (applicableTo.children.length === 1) {
|
||||||
applicableTo.children.length === 1 &&
|
if (applicableTo.children[0].element.type === "ExpressionStatement") {
|
||||||
applicableTo.children[0].element.type === "ExpressionStatement"
|
let matcher = new Matcher(
|
||||||
) {
|
internals,
|
||||||
let matcher = new Matcher(
|
applicableTo.children[0].children[0].element
|
||||||
internals,
|
);
|
||||||
applicableTo.children[0].children[0].element
|
matcher.singleExprMatcher(
|
||||||
);
|
code,
|
||||||
matcher.singleExprMatcher(code, applicableTo.children[0].children[0]);
|
applicableTo.children[0].children[0]
|
||||||
return matcher.matches;
|
);
|
||||||
|
return matcher.matches;
|
||||||
|
} else {
|
||||||
|
let matcher = new Matcher(
|
||||||
|
internals,
|
||||||
|
applicableTo.children[0].element
|
||||||
|
);
|
||||||
|
matcher.singleExprMatcher(code, applicableTo.children[0]);
|
||||||
|
return matcher.matches;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
showTree(code);
|
||||||
|
showTree(applicableTo);
|
||||||
|
|
||||||
let matcher = new Matcher(internals, applicableTo.element);
|
let matcher = new Matcher(internals, applicableTo.element);
|
||||||
matcher.multiStatementMatcher(code, applicableTo);
|
matcher.multiStatementMatcher(code, applicableTo);
|
||||||
return matcher.matches;
|
return matcher.matches;
|
||||||
|
@ -53,28 +65,30 @@ export class Matcher {
|
||||||
code: TreeNode<t.Node>,
|
code: TreeNode<t.Node>,
|
||||||
aplTo: TreeNode<t.Node>
|
aplTo: TreeNode<t.Node>
|
||||||
): TreeNode<PairedNodes> | undefined {
|
): 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);
|
let curMatches = this.checkCodeNode(code.element, aplTo.element);
|
||||||
curMatches =
|
curMatches =
|
||||||
curMatches && code.children.length >= aplTo.children.length;
|
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) {
|
if (!curMatches) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// At this point current does match
|
// 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, {
|
let pairedCurrent: TreeNode<PairedNodes> = new TreeNode(null, {
|
||||||
codeNode: code.element,
|
codeNode: code.element,
|
||||||
aplToNode: aplTo.element,
|
aplToNode: aplTo.element,
|
||||||
|
@ -85,7 +99,7 @@ export class Matcher {
|
||||||
aplTo.children[i]
|
aplTo.children[i]
|
||||||
);
|
);
|
||||||
if (childSearch === undefined) {
|
if (childSearch === undefined) {
|
||||||
// Failed to get a full match, so break here
|
// Failed to get a full match, so early return here
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
childSearch.parent = pairedCurrent;
|
childSearch.parent = pairedCurrent;
|
||||||
|
@ -96,10 +110,71 @@ export class Matcher {
|
||||||
return pairedCurrent;
|
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 {
|
private checkCodeNode(code_node: t.Node, aplTo: t.Node): boolean {
|
||||||
// First verify the internal DSL variables
|
// First verify the internal DSL variables
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { TransformRecipe, transform } from "../transform/transform";
|
||||||
|
|
||||||
const transformExample: TransformRecipe = {
|
const transformExample: TransformRecipe = {
|
||||||
applicableTo: `<<a>>(<<b:Identifier|Expression>>);`,
|
applicableTo: `<<a>>(<<b:Identifier|Expression>>);`,
|
||||||
transformTo: "b |> a(%)",
|
transformTo: "<<b>> |> <<a>>(%)",
|
||||||
};
|
};
|
||||||
const code =
|
const code =
|
||||||
"a(something);a(1+1);something(some_other_thing + 1 + 10 + 100); console.log(a)";
|
"a(something);a(1+1);something(some_other_thing + 1 + 10 + 100); console.log(a)";
|
||||||
|
|
|
@ -15,7 +15,7 @@ import {
|
||||||
import { runMatch } from "../matcher/matcher";
|
import { runMatch } from "../matcher/matcher";
|
||||||
import { transformMatch, transformer } from "./transformMatch";
|
import { transformMatch, transformer } from "./transformMatch";
|
||||||
import { preludeBuilder } from "../parser/preludeBuilder";
|
import { preludeBuilder } from "../parser/preludeBuilder";
|
||||||
|
import * as babelparser from "@babel/parser";
|
||||||
export interface Proposal {
|
export interface Proposal {
|
||||||
pairs: TransformRecipe[];
|
pairs: TransformRecipe[];
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ export interface TransformRecipe {
|
||||||
export interface SelfHostedRecipe extends TransformRecipe {
|
export interface SelfHostedRecipe extends TransformRecipe {
|
||||||
prelude: string;
|
prelude: string;
|
||||||
}
|
}
|
||||||
export function transform(recipe: TransformRecipe, code: string) {
|
export function transform(recipe: TransformRecipe, code: string): string {
|
||||||
if ((<SelfHostedRecipe>recipe).prelude !== undefined) {
|
if ((<SelfHostedRecipe>recipe).prelude !== undefined) {
|
||||||
// We are using the self hosted version
|
// We are using the self hosted version
|
||||||
return transformSelfHosted(
|
return transformSelfHosted(
|
||||||
|
@ -61,7 +61,7 @@ function transformSelfHosted(
|
||||||
recipe: TransformRecipe,
|
recipe: TransformRecipe,
|
||||||
internals: InternalDSLVariable,
|
internals: InternalDSLVariable,
|
||||||
code: string
|
code: string
|
||||||
) {
|
): string {
|
||||||
console.log(recipe);
|
console.log(recipe);
|
||||||
let codeAST = parse_with_plugins(code);
|
let codeAST = parse_with_plugins(code);
|
||||||
let codeTree = makeTree(codeAST);
|
let codeTree = makeTree(codeAST);
|
||||||
|
@ -81,25 +81,20 @@ function transformSelfHosted(
|
||||||
|
|
||||||
let matches = runMatch(codeTree, applicableToTree, internals);
|
let matches = runMatch(codeTree, applicableToTree, internals);
|
||||||
|
|
||||||
for (let match of matches) {
|
|
||||||
showTreePaired(match);
|
|
||||||
console.log(generate(match.element.codeNode).code);
|
|
||||||
}
|
|
||||||
console.log(matches.length);
|
console.log(matches.length);
|
||||||
for (let match of matches.reverse()) {
|
for (let match of matches.reverse()) {
|
||||||
//console.log(transformToTree.element);
|
//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 {
|
try {
|
||||||
transformer(match, transformToTree, output, codeAST);
|
transformer(match, transformToTree, output, codeAST);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("We failed to transform an element!");
|
console.log(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("Final generated code: \n");
|
console.log("Final generated code: \n");
|
||||||
|
|
||||||
let output = generate(codeAST, { topicToken: "%" }).code;
|
let output = generate(codeAST, { topicToken: "%" }).code;
|
||||||
//showTree(transformToTree);
|
//showTree(transformToTree);
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import {
|
||||||
import { InternalDSLVariable } from "../parser/parse";
|
import { InternalDSLVariable } from "../parser/parse";
|
||||||
import { MatchedTreeNode, PairedNodes } from "../matcher/matcher";
|
import { MatchedTreeNode, PairedNodes } from "../matcher/matcher";
|
||||||
import traverse from "@babel/traverse";
|
import traverse from "@babel/traverse";
|
||||||
|
import generate from "@babel/generator";
|
||||||
|
|
||||||
export function transformer(
|
export function transformer(
|
||||||
match: TreeNode<PairedNodes>,
|
match: TreeNode<PairedNodes>,
|
||||||
|
@ -48,7 +49,6 @@ export function transformMatch(
|
||||||
traverse(output, {
|
traverse(output, {
|
||||||
enter(path) {
|
enter(path) {
|
||||||
if (path.isIdentifier({ name: trnTo.element.name })) {
|
if (path.isIdentifier({ name: trnTo.element.name })) {
|
||||||
console.log(match.element.codeNode);
|
|
||||||
if (match.element.codeNode) {
|
if (match.element.codeNode) {
|
||||||
path.replaceWith(match.element.codeNode);
|
path.replaceWith(match.element.codeNode);
|
||||||
}
|
}
|
||||||
|
|
2
test_files/multi_stmt_test.js
Normal file
2
test_files/multi_stmt_test.js
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
let ThisTest = LOOOOOOOOL();
|
||||||
|
let HAHHAHAH = 1 + 1;
|
1
test_files/single_stmt.js
Normal file
1
test_files/single_stmt.js
Normal file
|
@ -0,0 +1 @@
|
||||||
|
let something = 1 + 1;
|
Loading…
Reference in a new issue