idk dude, something is very bad with the transformation
This commit is contained in:
parent
b9cd5a1de9
commit
b1a3ece8f1
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": {
|
||||
"@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"
|
||||
|
|
|
@ -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)
|
||||
);
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)";
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
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