diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 5a70a253..f6b0a0d9 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -136,7 +136,8 @@ jobs: matrix: #node-version: ['latest', '22.x', '20.x'] node-version: ['22.x', '20.x'] - os: [ubuntu-latest, windows-latest, macos-latest] + # node-gyp not working on the lastest windows (2025), needs to be updated + os: [ubuntu-latest, windows-2022, macos-latest] runs-on: ${{ matrix.os }} diff --git a/Fortran-JS/src-api/FortranJoinPoints.ts b/Fortran-JS/src-api/FortranJoinPoints.ts index ea779c03..7722dd33 100644 --- a/Fortran-JS/src-api/FortranJoinPoints.ts +++ b/Fortran-JS/src-api/FortranJoinPoints.ts @@ -97,4 +97,8 @@ export default class FortranJoinPoints { name, args.map(unwrapJoinPoint) )); } + + static parenExpr(expr: Joinpoints.Expr): Joinpoints.Expr { + return wrapJoinPoint(FortranJavaTypes.AstFactory.parenExpr(unwrapJoinPoint(expr))); + } } \ No newline at end of file diff --git a/Fortran-JS/src-api/Joinpoints.ts b/Fortran-JS/src-api/Joinpoints.ts index ce6e1070..f0306e0c 100644 --- a/Fortran-JS/src-api/Joinpoints.ts +++ b/Fortran-JS/src-api/Joinpoints.ts @@ -738,6 +738,19 @@ const JoinpointMapper = { ifStatement: IfStatement, ompBlockConstruct: OmpBlockConstruct, arraySubscriptExpr: ArraySubscriptExpr, + // Declaration/specification node types present in the Java weaverspecs but + // without dedicated TypeScript classes. Mapped to Statement so that + // Query.search and $jp.descendants traversals do not crash when encountering + // variable type declarations (e.g. `integer :: i, j`). + typeDeclarationStatement: Statement, + specificationStatement: Statement, + entityDecl: Statement, + fortranDecl: Statement, + exprInitialization: Statement, + initialization: Statement, + attributeSpecifier: Statement, + keywordAttributeSpecifier: Statement, + parameterKeyword: Statement, }; let registered = false; diff --git a/Fortran-JS/src-api/code/LoopFission.ts b/Fortran-JS/src-api/code/LoopFission.ts index 2dbf9b2a..a7b5593a 100644 --- a/Fortran-JS/src-api/code/LoopFission.ts +++ b/Fortran-JS/src-api/code/LoopFission.ts @@ -1,4 +1,6 @@ -import { DoStatement, RangeLoopControl } from "../Joinpoints.js"; +import Query from "@specs-feup/lara/api/weaver/Query.js"; +import { ArraySubscriptExpr, AssignmentStatement, DoStatement, Joinpoint, + RangeLoopControl } from "../Joinpoints.js"; /** * Splits a do-loop with multiple body statements into one loop per statement. @@ -44,7 +46,63 @@ export default function loopFission($loop: DoStatement): DoStatement[] { return result } +function stmtArrayWrites(stmt: Joinpoint): Set { + const result = new Set(); + for (const assign of Query.searchFromInclusive(stmt, AssignmentStatement)) { + const lhs = assign.variable; + if (lhs instanceof ArraySubscriptExpr) result.add(lhs.var.name); + } + return result; +} + +function stmtArrayReads(stmt: Joinpoint): Set { + const result = new Set(); + for (const assign of Query.searchFromInclusive(stmt, AssignmentStatement)) { + for (const expr of Query.searchFromInclusive(assign.expr, ArraySubscriptExpr)) { + result.add(expr.var.name); + } + } + return result; +} + +function stmtScalarWrites(stmt: Joinpoint): string[] { + const result: string[] = []; + for (const assign of Query.searchFromInclusive(stmt, AssignmentStatement)) { + const lhs = assign.variable; + if (!(lhs instanceof ArraySubscriptExpr)) result.push(lhs.name); + } + return result; +} + export function canFission($loop: DoStatement): boolean { - return $loop.control instanceof RangeLoopControl - && $loop.body.executableStmts.length > 1; + if (!($loop.control instanceof RangeLoopControl)) return false; + const stmts = [...$loop.body.executableStmts]; + if (stmts.length <= 1) return false; + + const arrayReads = stmts.map(s => stmtArrayReads(s)); + const arrayWrites = stmts.map(s => stmtArrayWrites(s)); + const scalarWrites = stmts.map(s => stmtScalarWrites(s)); + + for (let j = 1; j < stmts.length; j++) { + // Check 1: scalar written in an earlier stmt appears in a later stmt's code. + // After fission, the later loop sees only the scalar value from its own + // iteration — it cannot observe the value threaded from the earlier loop. + for (let i = 0; i < j; i++) { + for (const sv of scalarWrites[i]) { + if (new RegExp(`\\b${sv}\\b`).test(stmts[j].code)) return false; + } + } + + // Check 2: a later stmt writes an array that an earlier stmt reads. + // After fission, the earlier loop (for ALL iterations) runs before the + // later loop, so the earlier loop reads stale values for every iteration + // after the first one that the later loop would have updated. + for (const wName of arrayWrites[j]) { + for (let i = 0; i < j; i++) { + if (arrayReads[i].has(wName)) return false; + } + } + } + + return true; } diff --git a/Fortran-JS/src-api/code/LoopInterchange.ts b/Fortran-JS/src-api/code/LoopInterchange.ts new file mode 100644 index 00000000..8996716e --- /dev/null +++ b/Fortran-JS/src-api/code/LoopInterchange.ts @@ -0,0 +1,74 @@ +import Query from "@specs-feup/lara/api/weaver/Query.js"; +import FortranJoinPoints from "../FortranJoinPoints.js"; +import { DataRef, DoStatement, ExecutableStatement, RangeLoopControl } from "../Joinpoints.js"; + +/** + * Swaps the outer and inner loop of a perfect 2-deep nest. + * + * Transforms: + * ```fortran + * do i = lo_i, hi_i + * do j = lo_j, hi_j + * body + * end do + * end do + * ``` + * Into: + * ```fortran + * do j = lo_j, hi_j + * do i = lo_i, hi_i + * body + * end do + * end do + * ``` + * + * Returns unchanged [outer] if canInterchange() fails. + */ +export default function loopInterchange(outer: DoStatement, inner: DoStatement): DoStatement[] { + if (!canInterchange(outer, inner)) return [outer]; + const oc = outer.control as RangeLoopControl; + const ic = inner.control as RangeLoopControl; + + // New outer uses inner's control (deep-copied) + const newOuterCtrl = FortranJoinPoints.rangeLoopControl( + ic.var.deepCopy() as DataRef, + ic.lower.deepCopy(), + ic.upper.deepCopy() + ); + if (ic.step !== undefined) newOuterCtrl.setStep(ic.step.deepCopy()); + const newOuterDo = FortranJoinPoints.doStatement(newOuterCtrl); + + // New inner uses outer's control (deep-copied) + const newInnerCtrl = FortranJoinPoints.rangeLoopControl( + oc.var.deepCopy() as DataRef, + oc.lower.deepCopy(), + oc.upper.deepCopy() + ); + if (oc.step !== undefined) newInnerCtrl.setStep(oc.step.deepCopy()); + const newInnerDo = FortranJoinPoints.doStatement(newInnerCtrl); + + // Deep-copy body statements into new inner loop + for (const stmt of inner.body.executableStmts) { + newInnerDo.body.insertEnd(stmt.deepCopy() as ExecutableStatement); + } + newOuterDo.body.insertEnd(newInnerDo); + outer.replaceWith(newOuterDo); + return [newOuterDo]; +} + +export function canInterchange(outer: DoStatement, inner: DoStatement): boolean { + const oc = outer.control, ic = inner.control; + if (!(oc instanceof RangeLoopControl && ic instanceof RangeLoopControl)) return false; + const outerVar = oc.var.name; + + // Check 1: triangular inner bounds — inner bound references outer variable + if (ic.lower.code.includes(outerVar) || ic.upper.code.includes(outerVar)) return false; + + // Check 2: nested DO inside body uses outer variable in its bounds + for (const nested of Query.searchFrom(inner.body, DoStatement)) { + const nc = nested.control; + if (!(nc instanceof RangeLoopControl)) continue; + if (nc.lower.code.includes(outerVar) || nc.upper.code.includes(outerVar)) return false; + } + return true; +} diff --git a/Fortran-JS/src-api/code/LoopTiling.ts b/Fortran-JS/src-api/code/LoopTiling.ts index b8763b56..4ba8c349 100644 --- a/Fortran-JS/src-api/code/LoopTiling.ts +++ b/Fortran-JS/src-api/code/LoopTiling.ts @@ -1,3 +1,4 @@ +import Query from "@specs-feup/lara/api/weaver/Query.js"; import FortranJoinPoints from "../FortranJoinPoints.js"; import { DataRef, DoStatement, ExecutableStatement, RangeLoopControl } from "../Joinpoints.js"; @@ -85,8 +86,26 @@ export default function loopTile(outer: DoStatement, inner: DoStatement, tileSiz return [outerTileDo]; } +function containsVar(code: string, varName: string): boolean { + return new RegExp(`\\b${varName}\\b`).test(code); +} + export function canTile(outer: DoStatement, inner: DoStatement): boolean { const oc = outer.control, ic = inner.control; - return oc instanceof RangeLoopControl && ic instanceof RangeLoopControl - && oc.step === undefined && ic.step === undefined; + if (!(oc instanceof RangeLoopControl && ic instanceof RangeLoopControl)) return false; + if (oc.step !== undefined || ic.step !== undefined) return false; + + const outerVar = oc.var.name; + + // Check 1: triangular inner bounds — inner bound references outer variable + if (containsVar(ic.lower.code, outerVar) || containsVar(ic.upper.code, outerVar)) return false; + + // Check 2: nested DO inside inner body uses outer variable in its bounds + for (const nested of Query.searchFrom(inner.body, DoStatement)) { + const nc = nested.control; + if (!(nc instanceof RangeLoopControl)) continue; + if (containsVar(nc.lower.code, outerVar) || containsVar(nc.upper.code, outerVar)) return false; + } + + return true; } \ No newline at end of file diff --git a/Fortran-JS/src-api/code/LoopUnroll.ts b/Fortran-JS/src-api/code/LoopUnroll.ts index b1fe9442..c12b7d61 100644 --- a/Fortran-JS/src-api/code/LoopUnroll.ts +++ b/Fortran-JS/src-api/code/LoopUnroll.ts @@ -4,14 +4,21 @@ import { DataRef, DoStatement, ExecutableStatement, RangeLoopControl } from "../ /** * Deep-copies a body statement and replaces every reference to `varName` with - * `varName+offset` using AST-level substitution (only real variable references + * `(varName+offset)` using AST-level substitution (only real variable references * are affected, not occurrences inside string literals or comments). + * + * The replacement is wrapped in parenExpr() so that when it appears as the + * right operand of a surrounding subtraction (e.g. `n - i`) the emitted code + * is `n - (i + 1)` rather than `n - i + 1` (which Fortran evaluates as + * `n - i + 1`, flipping the sign of the offset). */ function substituteVar(stmt: ExecutableStatement, varName: string, offset: number): ExecutableStatement { const copy = stmt.deepCopy() as ExecutableStatement; if (offset === 0) return copy; for (const ref of Query.searchFrom(copy, DataRef, { name: varName })) { - const binOp = FortranJoinPoints.binaryOperatorAdd(ref.deepCopy(), FortranJoinPoints.intLiteral(offset)); + const binOp = FortranJoinPoints.parenExpr( + FortranJoinPoints.binaryOperatorAdd(ref.deepCopy(), FortranJoinPoints.intLiteral(offset)) + ); ref.replaceWith(binOp) } return copy; @@ -22,7 +29,7 @@ function substituteVar(stmt: ExecutableStatement, varName: string, offset: numbe * * Two loops replace the original: * - A **main loop** that steps by `factor`, with the body replicated `factor` - * times (each copy substitutes `var` with `var+offset` for offset 0..factor-1). + * times (each copy substitutes `var` with `(var+offset)` for offset 0..factor-1). * - A **cleanup loop** that handles the remaining < `factor` iterations with the * original body. When `factor` exactly divides the trip count, the cleanup * loop's bounds produce a no-op and it generates no iterations. @@ -37,10 +44,10 @@ function substituteVar(stmt: ExecutableStatement, varName: string, offset: numbe * // end do * * // After: - * // do i = 1, (n) - 3, 4 - * // a(i) = b(i); a(i+1) = b(i+1); a(i+2) = b(i+2); a(i+3) = b(i+3) + * // do i = 1, n - 3, 4 + * // a(i) = b(i); a((i+1)) = b((i+1)); a((i+2)) = b((i+2)); a((i+3)) = b((i+3)) * // end do - * // do i = (1) + (((n) - (1) + 1) / 4) * 4, n + * // do i = n + 1 - MOD(n - (1) + 1, 4), n * // a(i) = b(i) * // end do * @@ -59,7 +66,7 @@ export default function loopUnroll($loop: DoStatement, factor: number): DoStatem const mainCtrl = mainDo.control as RangeLoopControl; mainCtrl.setUpper(FortranJoinPoints.binaryOperatorSubtract( - ctrl.upper.deepCopy(), + ctrl.upper.deepCopy(), FortranJoinPoints.intLiteral(factor - 1)) ); mainCtrl.setStep(FortranJoinPoints.intLiteral(factor)); @@ -70,21 +77,28 @@ export default function loopUnroll($loop: DoStatement, factor: number): DoStatem } } - // Cleanup loop: lo + ((hi - lo + 1) / factor) * factor .. hi - // Integer division makes this a no-op when factor exactly divides the trip count. - const cleanupLower = FortranJoinPoints.binaryOperatorAdd( - ctrl.lower.deepCopy(), - FortranJoinPoints.binaryOperatorMultiply( - FortranJoinPoints.binaryOperatorDivide( - FortranJoinPoints.binaryOperatorAdd( - FortranJoinPoints.binaryOperatorSubtract(ctrl.upper.deepCopy(), ctrl.lower.deepCopy()), - FortranJoinPoints.intLiteral(1) - ), - FortranJoinPoints.intLiteral(factor) - ), - FortranJoinPoints.intLiteral(factor) - ) + // Cleanup loop: hi + 1 - MOD(hi - (lo) + 1, factor) .. hi + // + // lo is wrapped in parenExpr() so compound lower bounds like (k+1) or (i+1) + // emit as `hi - (k+1) + 1 = hi - k` instead of `hi - k + 1 + 1 = hi - k + 2`. + // MOD's argument list is syntactically parenthesized, so the full tripCount + // expression inside it is evaluated correctly regardless of complexity. + const tripCount = FortranJoinPoints.binaryOperatorAdd( + FortranJoinPoints.binaryOperatorSubtract( + ctrl.upper.deepCopy(), + FortranJoinPoints.parenExpr(ctrl.lower.deepCopy()) + ), + FortranJoinPoints.intLiteral(1) + ); + const remainder = FortranJoinPoints.intrinsicCall("MOD", [ + tripCount, + FortranJoinPoints.intLiteral(factor) + ]); + const cleanupLower = FortranJoinPoints.binaryOperatorSubtract( + FortranJoinPoints.binaryOperatorAdd(ctrl.upper.deepCopy(), FortranJoinPoints.intLiteral(1)), + remainder ); + const cleanupCtrl = FortranJoinPoints.rangeLoopControl(ctrl.var.deepCopy() as DataRef, cleanupLower, ctrl.upper.deepCopy()); const cleanupDo = FortranJoinPoints.doStatement(cleanupCtrl); for (const stmt of bodyStmts) { @@ -99,4 +113,4 @@ export function canUnroll($loop: DoStatement, factor: number = 2): boolean { if (!($loop.control instanceof RangeLoopControl)) return false; if (factor <= 1) return false; return ($loop.control as RangeLoopControl).step === undefined; -} \ No newline at end of file +} diff --git a/Fortran-JS/src-api/examples/fissionGeneric.ts b/Fortran-JS/src-api/examples/fissionGeneric.ts new file mode 100644 index 00000000..417d0a9a --- /dev/null +++ b/Fortran-JS/src-api/examples/fissionGeneric.ts @@ -0,0 +1,18 @@ +import Query from "@specs-feup/lara/api/weaver/Query.js"; +import LoopFissionPass from "../pass/LoopFissionPass.js"; +import { Subroutine } from "../Joinpoints.js"; + +const subroutines = Query.search(Subroutine, ($jp) => $jp.moduleName.startsWith('kernel_')).get(); + +if (subroutines.length === 0) { + console.log('No kernel_* subroutine found — skipping'); +} else { + for (const sub of subroutines) { + const result = new LoopFissionPass().apply(sub); + if (result.appliedPass) { + console.log(`[fissionGeneric] FISSIONED: ${sub.moduleName}`); + } else { + console.log(`[fissionGeneric] SKIPPED (no eligible multi-statement loops): ${sub.moduleName}`); + } + } +} diff --git a/Fortran-JS/src-api/examples/fusionGeneric.ts b/Fortran-JS/src-api/examples/fusionGeneric.ts new file mode 100644 index 00000000..ae6b8b29 --- /dev/null +++ b/Fortran-JS/src-api/examples/fusionGeneric.ts @@ -0,0 +1,18 @@ +import Query from "@specs-feup/lara/api/weaver/Query.js"; +import LoopFusionPass from "../pass/LoopFusionPass.js"; +import { Subroutine } from "../Joinpoints.js"; + +const subroutines = Query.search(Subroutine, ($jp) => $jp.moduleName.startsWith('kernel_')).get(); + +if (subroutines.length === 0) { + console.log('No kernel_* subroutine found — skipping'); +} else { + for (const sub of subroutines) { + const result = new LoopFusionPass().apply(sub); + if (result.appliedPass) { + console.log(`[fusionGeneric] FUSED: ${sub.moduleName}`); + } else { + console.log(`[fusionGeneric] SKIPPED (no fusable consecutive loops): ${sub.moduleName}`); + } + } +} diff --git a/Fortran-JS/src-api/examples/interchangeGeneric.ts b/Fortran-JS/src-api/examples/interchangeGeneric.ts new file mode 100644 index 00000000..0ac632f1 --- /dev/null +++ b/Fortran-JS/src-api/examples/interchangeGeneric.ts @@ -0,0 +1,18 @@ +import Query from "@specs-feup/lara/api/weaver/Query.js"; +import LoopInterchangePass from "../pass/LoopInterchangePass.js"; +import { Subroutine } from "../Joinpoints.js"; + +const subroutines = Query.search(Subroutine, ($jp) => $jp.moduleName.startsWith('kernel_')).get(); + +if (subroutines.length === 0) { + console.log('No kernel_* subroutine found — skipping'); +} else { + for (const sub of subroutines) { + const result = new LoopInterchangePass().apply(sub); + if (result.appliedPass) { + console.log(`[interchangeGeneric] INTERCHANGED: ${sub.moduleName}`); + } else { + console.log(`[interchangeGeneric] SKIPPED (no eligible/legal 2-deep perfect nest): ${sub.moduleName}`); + } + } +} diff --git a/Fortran-JS/src-api/examples/tilingGeneric.ts b/Fortran-JS/src-api/examples/tilingGeneric.ts new file mode 100644 index 00000000..98dd07b4 --- /dev/null +++ b/Fortran-JS/src-api/examples/tilingGeneric.ts @@ -0,0 +1,20 @@ +import Query from "@specs-feup/lara/api/weaver/Query.js"; +import LoopTilingPass from "../pass/LoopTilingPass.js"; +import { Subroutine } from "../Joinpoints.js"; + +const TILE_SIZE = 32; + +const subroutines = Query.search(Subroutine, ($jp) => $jp.moduleName.startsWith('kernel_')).get(); + +if (subroutines.length === 0) { + console.log('No kernel_* subroutine found — skipping'); +} else { + for (const sub of subroutines) { + const result = new LoopTilingPass(TILE_SIZE).apply(sub); + if (result.appliedPass) { + console.log(`[tilingGeneric] TILED (tile=${TILE_SIZE}): ${sub.moduleName}`); + } else { + console.log(`[tilingGeneric] SKIPPED (no eligible 2-deep perfect nest): ${sub.moduleName}`); + } + } +} diff --git a/Fortran-JS/src-api/examples/unrollGeneric.ts b/Fortran-JS/src-api/examples/unrollGeneric.ts new file mode 100644 index 00000000..5bb5ae57 --- /dev/null +++ b/Fortran-JS/src-api/examples/unrollGeneric.ts @@ -0,0 +1,20 @@ +import Query from "@specs-feup/lara/api/weaver/Query.js"; +import LoopUnrollPass from "../pass/LoopUnrollPass.js"; +import { Subroutine } from "../Joinpoints.js"; + +const FACTOR = 4; + +const subroutines = Query.search(Subroutine, ($jp) => $jp.moduleName.startsWith('kernel_')).get(); + +if (subroutines.length === 0) { + console.log('No kernel_* subroutine found — skipping'); +} else { + for (const sub of subroutines) { + const result = new LoopUnrollPass(FACTOR).apply(sub); + if (result.appliedPass) { + console.log(`[unrollGeneric] UNROLLED (factor=${FACTOR}): ${sub.moduleName}`); + } else { + console.log(`[unrollGeneric] SKIPPED (no unrollable innermost loops): ${sub.moduleName}`); + } + } +} diff --git a/Fortran-JS/src-api/pass/LoopFissionPass.ts b/Fortran-JS/src-api/pass/LoopFissionPass.ts index 8b5d4cca..59b5daa9 100644 --- a/Fortran-JS/src-api/pass/LoopFissionPass.ts +++ b/Fortran-JS/src-api/pass/LoopFissionPass.ts @@ -30,7 +30,9 @@ export default class LoopFissionPass extends Pass { /** Yields every eligible do-loop in the subtree: range loops with more than one body statement. */ protected *_findLoops($jp: Joinpoint): Generator { - for (const child of $jp.children) { + let children: Joinpoint[]; + try { children = [...$jp.children]; } catch (_) { return; } + for (const child of children) { yield* this._findLoops(child); } if ($jp instanceof DoStatement && canFission($jp)) { diff --git a/Fortran-JS/src-api/pass/LoopFusionPass.ts b/Fortran-JS/src-api/pass/LoopFusionPass.ts index be5e568c..e5502e3e 100644 --- a/Fortran-JS/src-api/pass/LoopFusionPass.ts +++ b/Fortran-JS/src-api/pass/LoopFusionPass.ts @@ -1,14 +1,73 @@ import Pass from "@specs-feup/lara/api/lara/pass/Pass.js"; import PassResult from "@specs-feup/lara/api/lara/pass/results/PassResult.js"; -import { DoStatement, Joinpoint, RangeLoopControl } from "../Joinpoints.js"; +import Query from "@specs-feup/lara/api/weaver/Query.js"; +import { ArraySubscriptExpr, AssignmentStatement, DoStatement, Joinpoint, RangeLoopControl } from "../Joinpoints.js"; import loopFusion from "../code/LoopFusion.js"; +type ArrayAccess = { arrayName: string; subCodes: string[] }; + +function loopWrites(loop: DoStatement): ArrayAccess[] { + const result: ArrayAccess[] = []; + for (const stmt of Query.searchFrom(loop.body, AssignmentStatement)) { + const lhs = stmt.variable; + if (lhs instanceof ArraySubscriptExpr) { + // .name on ArraySubscriptExpr is ""; the array identifier is at .var.name + result.push({ arrayName: lhs.var.name, subCodes: lhs.subscripts.map(s => s.code) }); + } + } + return result; +} + +function loopReads(loop: DoStatement): ArrayAccess[] { + const result: ArrayAccess[] = []; + for (const stmt of Query.searchFrom(loop.body, AssignmentStatement)) { + for (const expr of Query.searchFromInclusive(stmt.expr, ArraySubscriptExpr)) { + result.push({ arrayName: expr.var.name, subCodes: expr.subscripts.map(s => s.code) }); + } + } + return result; +} + +function innerLoopVars(loop: DoStatement): Set { + const vars = new Set(); + for (const nested of Query.searchFrom(loop.body, DoStatement)) { + if (nested.kind === 'range') { + const ctl = nested.control; + if (ctl instanceof RangeLoopControl) vars.add(ctl.var.name); + } + } + return vars; +} + +function hasVar(code: string, varName: string): boolean { + return new RegExp(`\\b${varName}\\b`).test(code); +} + +function hasAnyVar(code: string, vars: Set): boolean { + return [...vars].some(v => hasVar(code, v)); +} + /** * Pass that fuses consecutive range do-loops with identical boundaries into a * single loop (loop fusion), applied recursively across the subtree. * * At each scope level, adjacent do-loops that share the same range control are - * grouped and fused into the first loop of each group. + * grouped and fused into the first loop of each group. Groups are split at any + * pair that fails a legality check: + * + * - Check A: a write in loop A has a subscript that does not contain the fusion + * variable (the same element is written/accumulated on every iteration) and the + * same array is read in loop B — the reader would see a partial value. + * + * - Check B: array X is written in loop A as `X(inner, fusion_var)` (column-major) + * and read in loop B as `X(fusion_var, inner)` (row-major) — a cross-iteration + * transposed dependency. + * + * - Check C: array X is written in one loop with a subscript that contains the + * fusion variable but no inner loop variable (one element per fusion iteration), + * and read in the other loop with a subscript that contains an inner loop + * variable (reads across the full range) — a forward or backward cross-iteration + * dependency. * * @example * const pass = new LoopFusionPass(); @@ -32,7 +91,9 @@ export default class LoopFusionPass extends Pass { * inner loops are fused before their containing scope is inspected. */ protected *_findAllFusableSets($jp: Joinpoint): Generator { - for (const child of [...$jp.children]) { + let children: Joinpoint[]; + try { children = [...$jp.children]; } catch (_) { children = []; } + for (const child of children) { yield* this._findAllFusableSets(child); } for (const set of this._findFusableSets($jp)) { @@ -41,22 +102,29 @@ export default class LoopFusionPass extends Pass { } /** - * Returns groups of consecutive range do-loops among the **direct children** - * of `$jp` that share identical loop boundaries and can therefore be fused. - * - * Any non-do-loop child (or a do-loop with different boundaries) breaks an - * ongoing group. Only groups of length ≥ 2 are returned. - * - * @param $jp - The joinpoint whose direct children are inspected. + * Returns groups of consecutive range do-loops among the direct children of + * `$jp` that share identical loop boundaries and pass all three legality + * checks. Groups are split whenever a consecutive pair is illegal; only + * groups of length ≥ 2 are returned. */ protected _findFusableSets($jp: Joinpoint): DoStatement[][] { const result: DoStatement[][] = []; let group: DoStatement[] = []; - for (const child of $jp.children) { + let children: Joinpoint[]; + try { children = [...$jp.children]; } catch (_) { return result; } + + for (const child of children) { if (child instanceof DoStatement && child.kind === 'range') { - if (group.length === 0 || group[0].sameScope(child)) { - group.push(child); + if (group.length === 0) { + group = [child]; + } else if (group[0].sameScope(child)) { + if (this._canFusePair(group[group.length - 1], child)) { + group.push(child); + } else { + if (group.length >= 2) result.push(group); + group = [child]; + } } else { if (group.length >= 2) result.push(group); group = [child]; @@ -69,4 +137,76 @@ export default class LoopFusionPass extends Pass { if (group.length >= 2) result.push(group); return result; } + + /** + * Returns false if fusing `a` immediately before `b` would violate one of + * three dependency patterns detectable from the AST. + */ + protected _canFusePair(a: DoStatement, b: DoStatement): boolean { + const fv = (a.control as RangeLoopControl).var.name; + const ivA = innerLoopVars(a); + const ivB = innerLoopVars(b); + + const writesA = loopWrites(a); + const writesB = loopWrites(b); + const readsA = loopReads(a); + const readsB = loopReads(b); + + const readNamesA = new Set(readsA.map(r => r.arrayName)); + const readNamesB = new Set(readsB.map(r => r.arrayName)); + + // Check A: write subscript contains no instance of the fusion variable → + // the same array element is modified on every fusion iteration. + // If the other loop reads that element, it will see an incomplete value. + for (const w of writesA) { + if (!w.subCodes.some(sc => hasVar(sc, fv)) && readNamesB.has(w.arrayName)) return false; + } + for (const w of writesB) { + if (!w.subCodes.some(sc => hasVar(sc, fv)) && readNamesA.has(w.arrayName)) return false; + } + + // Check B: array X written as X(inner_var, fv) in one loop and read as + // X(fv, inner_var) in the other — transposed cross-iteration dependency. + const checkTransposed = ( + writes: ArrayAccess[], reads: ArrayAccess[], + writeIV: Set, readIV: Set + ) => { + for (const w of writes) { + if (w.subCodes.length !== 2) continue; + const [ws0, ws1] = w.subCodes; + if (!hasAnyVar(ws0, writeIV) || !hasVar(ws1, fv)) continue; + for (const r of reads) { + if (r.arrayName !== w.arrayName || r.subCodes.length !== 2) continue; + const [rs0, rs1] = r.subCodes; + if (hasVar(rs0, fv) && hasAnyVar(rs1, readIV)) return true; + } + } + return false; + }; + if (checkTransposed(writesA, readsB, ivA, ivB)) return false; + if (checkTransposed(writesB, readsA, ivB, ivA)) return false; + + // Check C: array X written with a subscript that contains the fusion + // variable but no inner loop variable (one element per fusion iteration), + // and read by the other loop with a subscript that contains an inner loop + // variable (reads across the full range within one fusion iteration). + const checkOnePerIter = ( + writes: ArrayAccess[], reads: ArrayAccess[], + writeIV: Set, readIV: Set + ) => { + for (const w of writes) { + const allSubs = w.subCodes.join(' '); + if (!hasVar(allSubs, fv) || hasAnyVar(allSubs, writeIV)) continue; + for (const r of reads) { + if (r.arrayName !== w.arrayName) continue; + if (hasAnyVar(r.subCodes.join(' '), readIV)) return true; + } + } + return false; + }; + if (checkOnePerIter(writesA, readsB, ivA, ivB)) return false; + if (checkOnePerIter(writesB, readsA, ivB, ivA)) return false; + + return true; + } } diff --git a/Fortran-JS/src-api/pass/LoopInterchangePass.ts b/Fortran-JS/src-api/pass/LoopInterchangePass.ts new file mode 100644 index 00000000..1be344a5 --- /dev/null +++ b/Fortran-JS/src-api/pass/LoopInterchangePass.ts @@ -0,0 +1,66 @@ +import Pass from "@specs-feup/lara/api/lara/pass/Pass.js"; +import PassResult from "@specs-feup/lara/api/lara/pass/results/PassResult.js"; +import Query from "@specs-feup/lara/api/weaver/Query.js"; +import { DoStatement, Joinpoint, RangeLoopControl } from "../Joinpoints.js"; +import loopInterchange, { canInterchange } from "../code/LoopInterchange.js"; + +/** + * Pass that interchanges every legal top-level 2-deep perfect loop nest in the subtree. + * + * A pair is eligible when: + * 1. Both loops are range loops. + * 2. The inner loop's bounds do not reference the outer loop variable (Check 1: no triangular bounds). + * 3. No nested DO loop inside the inner body has bounds referencing the outer variable (Check 2). + * + * All eligible pairs are collected before any transformation so that AST mutations + * do not interfere with the traversal. In nests deeper than 2, only the outermost + * 2-level pair is interchanged. + * + * @example + * const pass = new LoopInterchangePass(); + * pass.apply(Query.root()); + */ +export default class LoopInterchangePass extends Pass { + protected _name = "LoopInterchangePass"; + + protected _apply_impl($jp: Joinpoint): PassResult { + const pairs = this._findInterchangeablePairs($jp); + let appliedPass = false; + for (const { outer, inner } of pairs) { + loopInterchange(outer, inner); + appliedPass = true; + } + return new PassResult(this, $jp, { appliedPass, insertedLiteralCode: false }); + } + + protected _findInterchangeablePairs($jp: Joinpoint): { outer: DoStatement; inner: DoStatement }[] { + // Collect all structural 2-deep perfect nests regardless of legality. + // innerSet must be built from ALL pairs so that nests deeper than 2 are + // handled correctly: an inner pair nested inside an illegal outer pair must + // not be interchanged either (its "outer" loop is still the inner of an + // unprocessed pair and evaluation-order constraints may still apply). + const allPairs: { outer: DoStatement; inner: DoStatement }[] = []; + for (const loop of Query.searchFrom($jp, DoStatement)) { + const stmts = loop.body.executableStmts; + if (stmts.length === 1 && stmts[0] instanceof DoStatement) { + allPairs.push({ outer: loop, inner: stmts[0] as DoStatement }); + } + } + // LARA wraps each AST node in a new JS proxy on every access, so JS object + // identity cannot be used to detect that the same loop appears as both an + // outer in one pair and an inner in another. Key by loop variable name + // instead — unique per subroutine for PolyBench's affine loops. + const innerVarNames = new Set( + allPairs + .map(p => p.inner.control) + .filter((c): c is RangeLoopControl => c instanceof RangeLoopControl) + .map(c => c.var.name) + ); + return allPairs + .filter(({ outer }) => { + const oc = outer.control; + return !(oc instanceof RangeLoopControl && innerVarNames.has(oc.var.name)); + }) + .filter(({ outer, inner }) => canInterchange(outer, inner)); + } +} diff --git a/Fortran-JS/src-api/pass/LoopUnrollPass.ts b/Fortran-JS/src-api/pass/LoopUnrollPass.ts index 5d5333a8..304b97e2 100644 --- a/Fortran-JS/src-api/pass/LoopUnrollPass.ts +++ b/Fortran-JS/src-api/pass/LoopUnrollPass.ts @@ -37,16 +37,29 @@ export default class LoopUnrollPass extends Pass { * * A loop is innermost when none of its descendants is a do-loop. * Recursion does not descend into innermost loops. + * + * The try/catch around children access guards against staging-branch AST + * nodes (e.g. attributeSpecifier) whose underlying Java joinpoint has a null + * node, causing a NullPointerException when `.children` is accessed. */ protected *_findInnermostLoops($jp: Joinpoint): Generator { if ($jp instanceof DoStatement) { - const hasNestedLoop = $jp.descendants.some(d => d instanceof DoStatement); + let hasNestedLoop = false; + try { + hasNestedLoop = $jp.descendants.some(d => d instanceof DoStatement); + } catch (_) { /* unmapped descendant — treat as no nested loop */ } if (!hasNestedLoop && canUnroll($jp, this.factor)) { yield $jp; return; } } - for (const child of [...$jp.children]) { + let children: Joinpoint[]; + try { + children = [...$jp.children]; + } catch (_) { + return; // skip nodes whose children cannot be accessed + } + for (const child of children) { yield* this._findInnermostLoops(child); } } diff --git a/FortranAst/src/pt/up/fe/specs/fortran/ast/FortranNodeFactory.java b/FortranAst/src/pt/up/fe/specs/fortran/ast/FortranNodeFactory.java index 4b0e0a93..915bf48e 100644 --- a/FortranAst/src/pt/up/fe/specs/fortran/ast/FortranNodeFactory.java +++ b/FortranAst/src/pt/up/fe/specs/fortran/ast/FortranNodeFactory.java @@ -13,6 +13,7 @@ import pt.up.fe.specs.fortran.ast.nodes.expr.Expr; import pt.up.fe.specs.fortran.ast.nodes.expr.IntLiteral; import pt.up.fe.specs.fortran.ast.nodes.expr.Literal; +import pt.up.fe.specs.fortran.ast.nodes.expr.ParenExpr; import pt.up.fe.specs.fortran.ast.nodes.expr.StringLiteral; import pt.up.fe.specs.fortran.ast.nodes.expr.enums.BinaryOperatorKind; import pt.up.fe.specs.fortran.ast.nodes.loops.LoopControl; @@ -331,6 +332,11 @@ public BinaryOperator binaryOperator(BinaryOperatorKind kind, Expr lhs, Expr rhs return node; } + public ParenExpr parenExpr(Expr expr) { + DataStore data = newDataStore(ParenExpr.class); + return new ParenExpr(data, Collections.singletonList(expr)); + } + public OmpOrderedClause ompOrderedClause(int value) { DataStore data = newDataStore(OmpOrderedClause.class); diff --git a/FortranWeaver/src/pt/up/fe/specs/fortran/weaver/FortranWeaver.json b/FortranWeaver/src/pt/up/fe/specs/fortran/weaver/FortranWeaver.json index 86c57729..1940bdb1 100644 --- a/FortranWeaver/src/pt/up/fe/specs/fortran/weaver/FortranWeaver.json +++ b/FortranWeaver/src/pt/up/fe/specs/fortran/weaver/FortranWeaver.json @@ -981,6 +981,232 @@ }] }] }, + { + "type": "joinpoint", + "name": "attributeSpecifier", + "extends": "joinpoint" , + "children": [ + { + "type": "attribute", + "tooltip": "Returns an array with the children of the node", + "children": [ + { + "type": "joinpoint[]", + "name": "children" + }] + }, + { + "type": "attribute", + "tooltip": "String with the code represented by this node", + "children": [ + { + "type": "String", + "name": "code" + }] + }, + { + "type": "attribute", + "tooltip": "true if the given node is a descendant of this node", + "children": [ + { + "type": "Boolean", + "name": "contains" + }, + { + "type": "joinpoint", + "name": "jp", + "defaultValue": "" + }] + }, + { + "type": "attribute", + "tooltip": "Returns an array with the descendants of the node", + "children": [ + { + "type": "joinpoint[]", + "name": "descendants" + }] + }, + { + "type": "attribute", + "tooltip": "Looks for an ancestor joinpoint name, walking back on the AST", + "children": [ + { + "type": "joinpoint", + "name": "getAncestor" + }, + { + "type": "String", + "name": "type", + "defaultValue": "" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the index of this join point in relation to its parent", + "children": [ + { + "type": "int", + "name": "indexOfSelf" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the node that came before this node, or undefined if there is none", + "children": [ + { + "type": "joinpoint", + "name": "leftJp" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the parent node in the AST, or undefined if it is the root node", + "children": [ + { + "type": "joinpoint", + "name": "parent" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the node that comes after this node, or undefined if there is none", + "children": [ + { + "type": "joinpoint", + "name": "rightJp" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the 'program' join point", + "children": [ + { + "type": "program", + "name": "root" + }] + }, + { + "type": "attribute", + "tooltip": "the nodes of the scope of the current join point. If this node has a body (e.g., loop, function) corresponds to the children of the body. Otherwise, returns an empty array", + "children": [ + { + "type": "joinpoint[]", + "name": "scopeNodes" + }] + }, + { + "type": "action", + "tooltip": "Performs a copy of the node and its children, but not of the nodes in its fields", + "children": [ + { + "type": "joinpoint", + "name": "copy" + }] + }, + { + "type": "action", + "tooltip": "Performs a copy of the node and its children, including the nodes in their fields (only the first level of field nodes, this function is not recursive)", + "children": [ + { + "type": "joinpoint", + "name": "deepCopy" + }] + }, + { + "type": "action", + "tooltip": "Removes node associated to the joinpoint from the AST", + "children": [ + { + "type": "joinpoint", + "name": "detach" + }] + }, + { + "type": "action", + "tooltip": "Inserts the given join point after this join point", + "children": [ + { + "type": "joinpoint", + "name": "insertAfter" + }, + { + "type": "joinpoint", + "name": "node", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Overload which accepts a string", + "children": [ + { + "type": "joinpoint", + "name": "insertAfter" + }, + { + "type": "String", + "name": "code", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Inserts the given join point before this join point", + "children": [ + { + "type": "joinpoint", + "name": "insertBefore" + }, + { + "type": "joinpoint", + "name": "node", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Overload which accepts a string", + "children": [ + { + "type": "joinpoint", + "name": "insertBefore" + }, + { + "type": "String", + "name": "node", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Replaces this node with the given node", + "children": [ + { + "type": "joinpoint", + "name": "replaceWith" + }, + { + "type": "joinpoint", + "name": "node", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Overload which accepts a list of join points", + "children": [ + { + "type": "joinpoint", + "name": "replaceWith" + }, + { + "type": "joinpoint[]", + "name": "node", + "defaultValue": "" + }] + }] + }, { "type": "joinpoint", "name": "binaryOperator", @@ -2394,6 +2620,24 @@ "name": "scopeNodes" }] }, + { + "type": "action", + "tooltip": "Performs a copy of the node and its children, but not of the nodes in its fields", + "children": [ + { + "type": "joinpoint", + "name": "copy" + }] + }, + { + "type": "action", + "tooltip": "Performs a copy of the node and its children, including the nodes in their fields (only the first level of field nodes, this function is not recursive)", + "children": [ + { + "type": "joinpoint", + "name": "deepCopy" + }] + }, { "type": "action", "tooltip": "Removes node associated to the joinpoint from the AST", @@ -2405,25 +2649,95 @@ }, { "type": "action", - "tooltip": "Replaces this node with the given node", + "tooltip": "Inserts the given join point after this join point", "children": [ { "type": "joinpoint", - "name": "replaceWith" + "name": "insertAfter" }, { "type": "joinpoint", "name": "node", "defaultValue": "" }] - }] - }, - { - "type": "joinpoint", - "name": "elseIfBlock", - "extends": "joinpoint" , - "tooltip": "Represents the optional 'else if' blocks of an if construct", - "children": [ + }, + { + "type": "action", + "tooltip": "Overload which accepts a string", + "children": [ + { + "type": "joinpoint", + "name": "insertAfter" + }, + { + "type": "String", + "name": "code", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Inserts the given join point before this join point", + "children": [ + { + "type": "joinpoint", + "name": "insertBefore" + }, + { + "type": "joinpoint", + "name": "node", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Overload which accepts a string", + "children": [ + { + "type": "joinpoint", + "name": "insertBefore" + }, + { + "type": "String", + "name": "node", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Replaces this node with the given node", + "children": [ + { + "type": "joinpoint", + "name": "replaceWith" + }, + { + "type": "joinpoint", + "name": "node", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Overload which accepts a list of join points", + "children": [ + { + "type": "joinpoint", + "name": "replaceWith" + }, + { + "type": "joinpoint[]", + "name": "node", + "defaultValue": "" + }] + }] + }, + { + "type": "joinpoint", + "name": "elseIfBlock", + "extends": "joinpoint" , + "tooltip": "Represents the optional 'else if' blocks of an if construct", + "children": [ { "type": "attribute", "children": [ @@ -2551,170 +2865,111 @@ }, { "type": "action", - "tooltip": "Removes node associated to the joinpoint from the AST", + "tooltip": "Performs a copy of the node and its children, but not of the nodes in its fields", "children": [ { "type": "joinpoint", - "name": "detach" + "name": "copy" }] }, { "type": "action", - "tooltip": "Replaces this node with the given node", + "tooltip": "Performs a copy of the node and its children, including the nodes in their fields (only the first level of field nodes, this function is not recursive)", "children": [ { "type": "joinpoint", - "name": "replaceWith" - }, - { - "type": "joinpoint", - "name": "node", - "defaultValue": "" - }] - }] - }, - { - "type": "joinpoint", - "name": "elseIfStatement", - "extends": "joinpoint" , - "tooltip": "Represents the header of an 'else if' block", - "children": [ - { - "type": "attribute", - "children": [ - { - "type": "expr", - "name": "condition" - }] - }, - { - "type": "attribute", - "tooltip": "Returns an array with the children of the node", - "children": [ - { - "type": "joinpoint[]", - "name": "children" + "name": "deepCopy" }] }, { - "type": "attribute", - "tooltip": "String with the code represented by this node", + "type": "action", + "tooltip": "Removes node associated to the joinpoint from the AST", "children": [ { - "type": "String", - "name": "code" + "type": "joinpoint", + "name": "detach" }] }, { - "type": "attribute", - "tooltip": "true if the given node is a descendant of this node", + "type": "action", + "tooltip": "Inserts the given join point after this join point", "children": [ { - "type": "Boolean", - "name": "contains" + "type": "joinpoint", + "name": "insertAfter" }, { "type": "joinpoint", - "name": "jp", + "name": "node", "defaultValue": "" }] }, { - "type": "attribute", - "tooltip": "Returns an array with the descendants of the node", - "children": [ - { - "type": "joinpoint[]", - "name": "descendants" - }] - }, - { - "type": "attribute", - "tooltip": "Looks for an ancestor joinpoint name, walking back on the AST", + "type": "action", + "tooltip": "Overload which accepts a string", "children": [ { "type": "joinpoint", - "name": "getAncestor" + "name": "insertAfter" }, { "type": "String", - "name": "type", + "name": "code", "defaultValue": "" }] }, { - "type": "attribute", - "tooltip": "Returns the index of this join point in relation to its parent", - "children": [ - { - "type": "int", - "name": "indexOfSelf" - }] - }, - { - "type": "attribute", - "tooltip": "Returns the node that came before this node, or undefined if there is none", + "type": "action", + "tooltip": "Inserts the given join point before this join point", "children": [ { "type": "joinpoint", - "name": "leftJp" - }] - }, - { - "type": "attribute", - "tooltip": "Returns the parent node in the AST, or undefined if it is the root node", - "children": [ + "name": "insertBefore" + }, { "type": "joinpoint", - "name": "parent" + "name": "node", + "defaultValue": "" }] }, { - "type": "attribute", - "tooltip": "Returns the node that comes after this node, or undefined if there is none", + "type": "action", + "tooltip": "Overload which accepts a string", "children": [ { "type": "joinpoint", - "name": "rightJp" - }] - }, - { - "type": "attribute", - "tooltip": "Returns the 'program' join point", - "children": [ - { - "type": "program", - "name": "root" - }] - }, - { - "type": "attribute", - "tooltip": "the nodes of the scope of the current join point. If this node has a body (e.g., loop, function) corresponds to the children of the body. Otherwise, returns an empty array", - "children": [ + "name": "insertBefore" + }, { - "type": "joinpoint[]", - "name": "scopeNodes" + "type": "String", + "name": "node", + "defaultValue": "" }] }, { "type": "action", - "tooltip": "Removes node associated to the joinpoint from the AST", + "tooltip": "Replaces this node with the given node", "children": [ { "type": "joinpoint", - "name": "detach" + "name": "replaceWith" + }, + { + "type": "joinpoint", + "name": "node", + "defaultValue": "" }] }, { "type": "action", - "tooltip": "Replaces this node with the given node", + "tooltip": "Overload which accepts a list of join points", "children": [ { "type": "joinpoint", "name": "replaceWith" }, { - "type": "joinpoint", + "type": "joinpoint[]", "name": "node", "defaultValue": "" }] @@ -2722,24 +2977,16 @@ }, { "type": "joinpoint", - "name": "executableStatement", - "extends": "statement" , - "tooltip": "Represents an executable statement", + "name": "elseIfStatement", + "extends": "joinpoint" , + "tooltip": "Represents the header of an 'else if' block", "children": [ { "type": "attribute", "children": [ { - "type": "Boolean", - "name": "isFirst" - }] - }, - { - "type": "attribute", - "children": [ - { - "type": "Boolean", - "name": "isLast" + "type": "expr", + "name": "condition" }] }, { @@ -2965,23 +3212,15 @@ }, { "type": "joinpoint", - "name": "execution", - "extends": "statementBlock" , + "name": "entityDecl", + "extends": "fortranDecl" , "children": [ { "type": "attribute", "children": [ { - "type": "executableStatement[]", - "name": "executableStmts" - }] - }, - { - "type": "attribute", - "children": [ - { - "type": "statement[]", - "name": "stmts" + "type": "String", + "name": "name" }] }, { @@ -3095,37 +3334,11 @@ }, { "type": "action", + "tooltip": "Performs a copy of the node and its children, but not of the nodes in its fields", "children": [ { - "type": "void", - "name": "insertBegin" - }, - { - "type": "executableStatement", - "name": "stmt", - "defaultValue": "" - }] - }, - { - "type": "action", - "children": [ - { - "type": "void", - "name": "insertEnd" - }, - { - "type": "executableStatement", - "name": "stmt", - "defaultValue": "" - }] - }, - { - "type": "action", - "tooltip": "Performs a copy of the node and its children, but not of the nodes in its fields", - "children": [ - { - "type": "joinpoint", - "name": "copy" + "type": "joinpoint", + "name": "copy" }] }, { @@ -3233,10 +3446,26 @@ }, { "type": "joinpoint", - "name": "expr", - "extends": "joinpoint" , - "tooltip": "Represents an expression", + "name": "executableStatement", + "extends": "statement" , + "tooltip": "Represents an executable statement", "children": [ + { + "type": "attribute", + "children": [ + { + "type": "Boolean", + "name": "isFirst" + }] + }, + { + "type": "attribute", + "children": [ + { + "type": "Boolean", + "name": "isLast" + }] + }, { "type": "attribute", "tooltip": "Returns an array with the children of the node", @@ -3460,27 +3689,23 @@ }, { "type": "joinpoint", - "name": "file", - "defaultAttr": "name", - "extends": "joinpoint" , - "tooltip": "Represents a source file (e.g., .f90)", + "name": "execution", + "extends": "statementBlock" , "children": [ { "type": "attribute", - "tooltip": "the name of the folder", "children": [ { - "type": "String", - "name": "foldername" + "type": "executableStatement[]", + "name": "executableStmts" }] }, { "type": "attribute", - "tooltip": "the name of the file", "children": [ { - "type": "String", - "name": "name" + "type": "statement[]", + "name": "stmts" }] }, { @@ -3592,6 +3817,32 @@ "name": "scopeNodes" }] }, + { + "type": "action", + "children": [ + { + "type": "void", + "name": "insertBegin" + }, + { + "type": "executableStatement", + "name": "stmt", + "defaultValue": "" + }] + }, + { + "type": "action", + "children": [ + { + "type": "void", + "name": "insertEnd" + }, + { + "type": "executableStatement", + "name": "stmt", + "defaultValue": "" + }] + }, { "type": "action", "tooltip": "Performs a copy of the node and its children, but not of the nodes in its fields", @@ -3706,50 +3957,10 @@ }, { "type": "joinpoint", - "name": "ifConstruct", - "extends": "executableStatement" , - "tooltip": "Represents the root of an if construct", + "name": "expr", + "extends": "joinpoint" , + "tooltip": "Represents an expression", "children": [ - { - "type": "attribute", - "children": [ - { - "type": "elseBlock", - "name": "elseBlock" - }] - }, - { - "type": "attribute", - "children": [ - { - "type": "elseIfBlock[]", - "name": "elseIfBlocks" - }] - }, - { - "type": "attribute", - "children": [ - { - "type": "ifThenBlock", - "name": "ifThenBlock" - }] - }, - { - "type": "attribute", - "children": [ - { - "type": "Boolean", - "name": "isFirst" - }] - }, - { - "type": "attribute", - "children": [ - { - "type": "Boolean", - "name": "isLast" - }] - }, { "type": "attribute", "tooltip": "Returns an array with the children of the node", @@ -3859,6 +4070,24 @@ "name": "scopeNodes" }] }, + { + "type": "action", + "tooltip": "Performs a copy of the node and its children, but not of the nodes in its fields", + "children": [ + { + "type": "joinpoint", + "name": "copy" + }] + }, + { + "type": "action", + "tooltip": "Performs a copy of the node and its children, including the nodes in their fields (only the first level of field nodes, this function is not recursive)", + "children": [ + { + "type": "joinpoint", + "name": "deepCopy" + }] + }, { "type": "action", "tooltip": "Removes node associated to the joinpoint from the AST", @@ -3870,54 +4099,100 @@ }, { "type": "action", - "tooltip": "Replaces this node with the given node", + "tooltip": "Inserts the given join point after this join point", "children": [ { "type": "joinpoint", - "name": "replaceWith" + "name": "insertAfter" }, { "type": "joinpoint", "name": "node", "defaultValue": "" }] - }] - }, - { - "type": "joinpoint", - "name": "ifStatement", - "extends": "actionStatement" , - "children": [ + }, { - "type": "attribute", + "type": "action", + "tooltip": "Overload which accepts a string", "children": [ { - "type": "expr", - "name": "condition" + "type": "joinpoint", + "name": "insertAfter" + }, + { + "type": "String", + "name": "code", + "defaultValue": "" }] }, { - "type": "attribute", + "type": "action", + "tooltip": "Inserts the given join point before this join point", "children": [ { - "type": "actionStatement", - "name": "statement" + "type": "joinpoint", + "name": "insertBefore" + }, + { + "type": "joinpoint", + "name": "node", + "defaultValue": "" }] }, { - "type": "attribute", + "type": "action", + "tooltip": "Overload which accepts a string", "children": [ { - "type": "Boolean", - "name": "isFirst" + "type": "joinpoint", + "name": "insertBefore" + }, + { + "type": "String", + "name": "node", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Replaces this node with the given node", + "children": [ + { + "type": "joinpoint", + "name": "replaceWith" + }, + { + "type": "joinpoint", + "name": "node", + "defaultValue": "" }] }, + { + "type": "action", + "tooltip": "Overload which accepts a list of join points", + "children": [ + { + "type": "joinpoint", + "name": "replaceWith" + }, + { + "type": "joinpoint[]", + "name": "node", + "defaultValue": "" + }] + }] + }, + { + "type": "joinpoint", + "name": "exprInitialization", + "extends": "initialization" , + "children": [ { "type": "attribute", "children": [ { - "type": "Boolean", - "name": "isLast" + "type": "expr", + "name": "expr" }] }, { @@ -4029,6 +4304,24 @@ "name": "scopeNodes" }] }, + { + "type": "action", + "tooltip": "Performs a copy of the node and its children, but not of the nodes in its fields", + "children": [ + { + "type": "joinpoint", + "name": "copy" + }] + }, + { + "type": "action", + "tooltip": "Performs a copy of the node and its children, including the nodes in their fields (only the first level of field nodes, this function is not recursive)", + "children": [ + { + "type": "joinpoint", + "name": "deepCopy" + }] + }, { "type": "action", "tooltip": "Removes node associated to the joinpoint from the AST", @@ -4040,39 +4333,112 @@ }, { "type": "action", - "tooltip": "Replaces this node with the given node", + "tooltip": "Inserts the given join point after this join point", "children": [ { "type": "joinpoint", - "name": "replaceWith" + "name": "insertAfter" }, { "type": "joinpoint", "name": "node", "defaultValue": "" }] + }, + { + "type": "action", + "tooltip": "Overload which accepts a string", + "children": [ + { + "type": "joinpoint", + "name": "insertAfter" + }, + { + "type": "String", + "name": "code", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Inserts the given join point before this join point", + "children": [ + { + "type": "joinpoint", + "name": "insertBefore" + }, + { + "type": "joinpoint", + "name": "node", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Overload which accepts a string", + "children": [ + { + "type": "joinpoint", + "name": "insertBefore" + }, + { + "type": "String", + "name": "node", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Replaces this node with the given node", + "children": [ + { + "type": "joinpoint", + "name": "replaceWith" + }, + { + "type": "joinpoint", + "name": "node", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Overload which accepts a list of join points", + "children": [ + { + "type": "joinpoint", + "name": "replaceWith" + }, + { + "type": "joinpoint[]", + "name": "node", + "defaultValue": "" + }] }] }, { "type": "joinpoint", - "name": "ifThenBlock", + "name": "file", + "defaultAttr": "name", "extends": "joinpoint" , - "tooltip": "Represents the first block of an if construct", + "tooltip": "Represents a source file (e.g., .f90)", "children": [ { "type": "attribute", + "tooltip": "the name of the folder", "children": [ { - "type": "statementBlock", - "name": "body" + "type": "String", + "name": "foldername" }] }, { "type": "attribute", + "tooltip": "the name of the file", "children": [ { - "type": "ifThenStatement", - "name": "header" + "type": "String", + "name": "name" }] }, { @@ -4184,6 +4550,24 @@ "name": "scopeNodes" }] }, + { + "type": "action", + "tooltip": "Performs a copy of the node and its children, but not of the nodes in its fields", + "children": [ + { + "type": "joinpoint", + "name": "copy" + }] + }, + { + "type": "action", + "tooltip": "Performs a copy of the node and its children, including the nodes in their fields (only the first level of field nodes, this function is not recursive)", + "children": [ + { + "type": "joinpoint", + "name": "deepCopy" + }] + }, { "type": "action", "tooltip": "Removes node associated to the joinpoint from the AST", @@ -4193,6 +4577,62 @@ "name": "detach" }] }, + { + "type": "action", + "tooltip": "Inserts the given join point after this join point", + "children": [ + { + "type": "joinpoint", + "name": "insertAfter" + }, + { + "type": "joinpoint", + "name": "node", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Overload which accepts a string", + "children": [ + { + "type": "joinpoint", + "name": "insertAfter" + }, + { + "type": "String", + "name": "code", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Inserts the given join point before this join point", + "children": [ + { + "type": "joinpoint", + "name": "insertBefore" + }, + { + "type": "joinpoint", + "name": "node", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Overload which accepts a string", + "children": [ + { + "type": "joinpoint", + "name": "insertBefore" + }, + { + "type": "String", + "name": "node", + "defaultValue": "" + }] + }, { "type": "action", "tooltip": "Replaces this node with the given node", @@ -4206,22 +4646,27 @@ "name": "node", "defaultValue": "" }] + }, + { + "type": "action", + "tooltip": "Overload which accepts a list of join points", + "children": [ + { + "type": "joinpoint", + "name": "replaceWith" + }, + { + "type": "joinpoint[]", + "name": "node", + "defaultValue": "" + }] }] }, { "type": "joinpoint", - "name": "ifThenStatement", + "name": "fortranDecl", "extends": "joinpoint" , - "tooltip": "Represents the header of an 'if then' block", "children": [ - { - "type": "attribute", - "children": [ - { - "type": "expr", - "name": "condition" - }] - }, { "type": "attribute", "tooltip": "Returns an array with the children of the node", @@ -4292,64 +4737,2303 @@ "children": [ { "type": "joinpoint", - "name": "leftJp" + "name": "leftJp" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the parent node in the AST, or undefined if it is the root node", + "children": [ + { + "type": "joinpoint", + "name": "parent" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the node that comes after this node, or undefined if there is none", + "children": [ + { + "type": "joinpoint", + "name": "rightJp" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the 'program' join point", + "children": [ + { + "type": "program", + "name": "root" + }] + }, + { + "type": "attribute", + "tooltip": "the nodes of the scope of the current join point. If this node has a body (e.g., loop, function) corresponds to the children of the body. Otherwise, returns an empty array", + "children": [ + { + "type": "joinpoint[]", + "name": "scopeNodes" + }] + }, + { + "type": "action", + "tooltip": "Performs a copy of the node and its children, but not of the nodes in its fields", + "children": [ + { + "type": "joinpoint", + "name": "copy" + }] + }, + { + "type": "action", + "tooltip": "Performs a copy of the node and its children, including the nodes in their fields (only the first level of field nodes, this function is not recursive)", + "children": [ + { + "type": "joinpoint", + "name": "deepCopy" + }] + }, + { + "type": "action", + "tooltip": "Removes node associated to the joinpoint from the AST", + "children": [ + { + "type": "joinpoint", + "name": "detach" + }] + }, + { + "type": "action", + "tooltip": "Inserts the given join point after this join point", + "children": [ + { + "type": "joinpoint", + "name": "insertAfter" + }, + { + "type": "joinpoint", + "name": "node", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Overload which accepts a string", + "children": [ + { + "type": "joinpoint", + "name": "insertAfter" + }, + { + "type": "String", + "name": "code", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Inserts the given join point before this join point", + "children": [ + { + "type": "joinpoint", + "name": "insertBefore" + }, + { + "type": "joinpoint", + "name": "node", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Overload which accepts a string", + "children": [ + { + "type": "joinpoint", + "name": "insertBefore" + }, + { + "type": "String", + "name": "node", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Replaces this node with the given node", + "children": [ + { + "type": "joinpoint", + "name": "replaceWith" + }, + { + "type": "joinpoint", + "name": "node", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Overload which accepts a list of join points", + "children": [ + { + "type": "joinpoint", + "name": "replaceWith" + }, + { + "type": "joinpoint[]", + "name": "node", + "defaultValue": "" + }] + }] + }, + { + "type": "joinpoint", + "name": "ifConstruct", + "extends": "executableStatement" , + "tooltip": "Represents the root of an if construct", + "children": [ + { + "type": "attribute", + "children": [ + { + "type": "elseBlock", + "name": "elseBlock" + }] + }, + { + "type": "attribute", + "children": [ + { + "type": "elseIfBlock[]", + "name": "elseIfBlocks" + }] + }, + { + "type": "attribute", + "children": [ + { + "type": "ifThenBlock", + "name": "ifThenBlock" + }] + }, + { + "type": "attribute", + "children": [ + { + "type": "Boolean", + "name": "isFirst" + }] + }, + { + "type": "attribute", + "children": [ + { + "type": "Boolean", + "name": "isLast" + }] + }, + { + "type": "attribute", + "tooltip": "Returns an array with the children of the node", + "children": [ + { + "type": "joinpoint[]", + "name": "children" + }] + }, + { + "type": "attribute", + "tooltip": "String with the code represented by this node", + "children": [ + { + "type": "String", + "name": "code" + }] + }, + { + "type": "attribute", + "tooltip": "true if the given node is a descendant of this node", + "children": [ + { + "type": "Boolean", + "name": "contains" + }, + { + "type": "joinpoint", + "name": "jp", + "defaultValue": "" + }] + }, + { + "type": "attribute", + "tooltip": "Returns an array with the descendants of the node", + "children": [ + { + "type": "joinpoint[]", + "name": "descendants" + }] + }, + { + "type": "attribute", + "tooltip": "Looks for an ancestor joinpoint name, walking back on the AST", + "children": [ + { + "type": "joinpoint", + "name": "getAncestor" + }, + { + "type": "String", + "name": "type", + "defaultValue": "" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the index of this join point in relation to its parent", + "children": [ + { + "type": "int", + "name": "indexOfSelf" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the node that came before this node, or undefined if there is none", + "children": [ + { + "type": "joinpoint", + "name": "leftJp" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the parent node in the AST, or undefined if it is the root node", + "children": [ + { + "type": "joinpoint", + "name": "parent" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the node that comes after this node, or undefined if there is none", + "children": [ + { + "type": "joinpoint", + "name": "rightJp" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the 'program' join point", + "children": [ + { + "type": "program", + "name": "root" + }] + }, + { + "type": "attribute", + "tooltip": "the nodes of the scope of the current join point. If this node has a body (e.g., loop, function) corresponds to the children of the body. Otherwise, returns an empty array", + "children": [ + { + "type": "joinpoint[]", + "name": "scopeNodes" + }] + }, + { + "type": "action", + "tooltip": "Performs a copy of the node and its children, but not of the nodes in its fields", + "children": [ + { + "type": "joinpoint", + "name": "copy" + }] + }, + { + "type": "action", + "tooltip": "Performs a copy of the node and its children, including the nodes in their fields (only the first level of field nodes, this function is not recursive)", + "children": [ + { + "type": "joinpoint", + "name": "deepCopy" + }] + }, + { + "type": "action", + "tooltip": "Removes node associated to the joinpoint from the AST", + "children": [ + { + "type": "joinpoint", + "name": "detach" + }] + }, + { + "type": "action", + "tooltip": "Inserts the given join point after this join point", + "children": [ + { + "type": "joinpoint", + "name": "insertAfter" + }, + { + "type": "joinpoint", + "name": "node", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Overload which accepts a string", + "children": [ + { + "type": "joinpoint", + "name": "insertAfter" + }, + { + "type": "String", + "name": "code", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Inserts the given join point before this join point", + "children": [ + { + "type": "joinpoint", + "name": "insertBefore" + }, + { + "type": "joinpoint", + "name": "node", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Overload which accepts a string", + "children": [ + { + "type": "joinpoint", + "name": "insertBefore" + }, + { + "type": "String", + "name": "node", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Replaces this node with the given node", + "children": [ + { + "type": "joinpoint", + "name": "replaceWith" + }, + { + "type": "joinpoint", + "name": "node", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Overload which accepts a list of join points", + "children": [ + { + "type": "joinpoint", + "name": "replaceWith" + }, + { + "type": "joinpoint[]", + "name": "node", + "defaultValue": "" + }] + }] + }, + { + "type": "joinpoint", + "name": "ifStatement", + "extends": "actionStatement" , + "children": [ + { + "type": "attribute", + "children": [ + { + "type": "expr", + "name": "condition" + }] + }, + { + "type": "attribute", + "children": [ + { + "type": "actionStatement", + "name": "statement" + }] + }, + { + "type": "attribute", + "children": [ + { + "type": "Boolean", + "name": "isFirst" + }] + }, + { + "type": "attribute", + "children": [ + { + "type": "Boolean", + "name": "isLast" + }] + }, + { + "type": "attribute", + "tooltip": "Returns an array with the children of the node", + "children": [ + { + "type": "joinpoint[]", + "name": "children" + }] + }, + { + "type": "attribute", + "tooltip": "String with the code represented by this node", + "children": [ + { + "type": "String", + "name": "code" + }] + }, + { + "type": "attribute", + "tooltip": "true if the given node is a descendant of this node", + "children": [ + { + "type": "Boolean", + "name": "contains" + }, + { + "type": "joinpoint", + "name": "jp", + "defaultValue": "" + }] + }, + { + "type": "attribute", + "tooltip": "Returns an array with the descendants of the node", + "children": [ + { + "type": "joinpoint[]", + "name": "descendants" + }] + }, + { + "type": "attribute", + "tooltip": "Looks for an ancestor joinpoint name, walking back on the AST", + "children": [ + { + "type": "joinpoint", + "name": "getAncestor" + }, + { + "type": "String", + "name": "type", + "defaultValue": "" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the index of this join point in relation to its parent", + "children": [ + { + "type": "int", + "name": "indexOfSelf" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the node that came before this node, or undefined if there is none", + "children": [ + { + "type": "joinpoint", + "name": "leftJp" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the parent node in the AST, or undefined if it is the root node", + "children": [ + { + "type": "joinpoint", + "name": "parent" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the node that comes after this node, or undefined if there is none", + "children": [ + { + "type": "joinpoint", + "name": "rightJp" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the 'program' join point", + "children": [ + { + "type": "program", + "name": "root" + }] + }, + { + "type": "attribute", + "tooltip": "the nodes of the scope of the current join point. If this node has a body (e.g., loop, function) corresponds to the children of the body. Otherwise, returns an empty array", + "children": [ + { + "type": "joinpoint[]", + "name": "scopeNodes" + }] + }, + { + "type": "action", + "tooltip": "Performs a copy of the node and its children, but not of the nodes in its fields", + "children": [ + { + "type": "joinpoint", + "name": "copy" + }] + }, + { + "type": "action", + "tooltip": "Performs a copy of the node and its children, including the nodes in their fields (only the first level of field nodes, this function is not recursive)", + "children": [ + { + "type": "joinpoint", + "name": "deepCopy" + }] + }, + { + "type": "action", + "tooltip": "Removes node associated to the joinpoint from the AST", + "children": [ + { + "type": "joinpoint", + "name": "detach" + }] + }, + { + "type": "action", + "tooltip": "Inserts the given join point after this join point", + "children": [ + { + "type": "joinpoint", + "name": "insertAfter" + }, + { + "type": "joinpoint", + "name": "node", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Overload which accepts a string", + "children": [ + { + "type": "joinpoint", + "name": "insertAfter" + }, + { + "type": "String", + "name": "code", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Inserts the given join point before this join point", + "children": [ + { + "type": "joinpoint", + "name": "insertBefore" + }, + { + "type": "joinpoint", + "name": "node", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Overload which accepts a string", + "children": [ + { + "type": "joinpoint", + "name": "insertBefore" + }, + { + "type": "String", + "name": "node", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Replaces this node with the given node", + "children": [ + { + "type": "joinpoint", + "name": "replaceWith" + }, + { + "type": "joinpoint", + "name": "node", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Overload which accepts a list of join points", + "children": [ + { + "type": "joinpoint", + "name": "replaceWith" + }, + { + "type": "joinpoint[]", + "name": "node", + "defaultValue": "" + }] + }] + }, + { + "type": "joinpoint", + "name": "ifThenBlock", + "extends": "joinpoint" , + "tooltip": "Represents the first block of an if construct", + "children": [ + { + "type": "attribute", + "children": [ + { + "type": "statementBlock", + "name": "body" + }] + }, + { + "type": "attribute", + "children": [ + { + "type": "ifThenStatement", + "name": "header" + }] + }, + { + "type": "attribute", + "tooltip": "Returns an array with the children of the node", + "children": [ + { + "type": "joinpoint[]", + "name": "children" + }] + }, + { + "type": "attribute", + "tooltip": "String with the code represented by this node", + "children": [ + { + "type": "String", + "name": "code" + }] + }, + { + "type": "attribute", + "tooltip": "true if the given node is a descendant of this node", + "children": [ + { + "type": "Boolean", + "name": "contains" + }, + { + "type": "joinpoint", + "name": "jp", + "defaultValue": "" + }] + }, + { + "type": "attribute", + "tooltip": "Returns an array with the descendants of the node", + "children": [ + { + "type": "joinpoint[]", + "name": "descendants" + }] + }, + { + "type": "attribute", + "tooltip": "Looks for an ancestor joinpoint name, walking back on the AST", + "children": [ + { + "type": "joinpoint", + "name": "getAncestor" + }, + { + "type": "String", + "name": "type", + "defaultValue": "" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the index of this join point in relation to its parent", + "children": [ + { + "type": "int", + "name": "indexOfSelf" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the node that came before this node, or undefined if there is none", + "children": [ + { + "type": "joinpoint", + "name": "leftJp" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the parent node in the AST, or undefined if it is the root node", + "children": [ + { + "type": "joinpoint", + "name": "parent" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the node that comes after this node, or undefined if there is none", + "children": [ + { + "type": "joinpoint", + "name": "rightJp" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the 'program' join point", + "children": [ + { + "type": "program", + "name": "root" + }] + }, + { + "type": "attribute", + "tooltip": "the nodes of the scope of the current join point. If this node has a body (e.g., loop, function) corresponds to the children of the body. Otherwise, returns an empty array", + "children": [ + { + "type": "joinpoint[]", + "name": "scopeNodes" + }] + }, + { + "type": "action", + "tooltip": "Performs a copy of the node and its children, but not of the nodes in its fields", + "children": [ + { + "type": "joinpoint", + "name": "copy" + }] + }, + { + "type": "action", + "tooltip": "Performs a copy of the node and its children, including the nodes in their fields (only the first level of field nodes, this function is not recursive)", + "children": [ + { + "type": "joinpoint", + "name": "deepCopy" + }] + }, + { + "type": "action", + "tooltip": "Removes node associated to the joinpoint from the AST", + "children": [ + { + "type": "joinpoint", + "name": "detach" + }] + }, + { + "type": "action", + "tooltip": "Inserts the given join point after this join point", + "children": [ + { + "type": "joinpoint", + "name": "insertAfter" + }, + { + "type": "joinpoint", + "name": "node", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Overload which accepts a string", + "children": [ + { + "type": "joinpoint", + "name": "insertAfter" + }, + { + "type": "String", + "name": "code", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Inserts the given join point before this join point", + "children": [ + { + "type": "joinpoint", + "name": "insertBefore" + }, + { + "type": "joinpoint", + "name": "node", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Overload which accepts a string", + "children": [ + { + "type": "joinpoint", + "name": "insertBefore" + }, + { + "type": "String", + "name": "node", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Replaces this node with the given node", + "children": [ + { + "type": "joinpoint", + "name": "replaceWith" + }, + { + "type": "joinpoint", + "name": "node", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Overload which accepts a list of join points", + "children": [ + { + "type": "joinpoint", + "name": "replaceWith" + }, + { + "type": "joinpoint[]", + "name": "node", + "defaultValue": "" + }] + }] + }, + { + "type": "joinpoint", + "name": "ifThenStatement", + "extends": "joinpoint" , + "tooltip": "Represents the header of an 'if then' block", + "children": [ + { + "type": "attribute", + "children": [ + { + "type": "expr", + "name": "condition" + }] + }, + { + "type": "attribute", + "tooltip": "Returns an array with the children of the node", + "children": [ + { + "type": "joinpoint[]", + "name": "children" + }] + }, + { + "type": "attribute", + "tooltip": "String with the code represented by this node", + "children": [ + { + "type": "String", + "name": "code" + }] + }, + { + "type": "attribute", + "tooltip": "true if the given node is a descendant of this node", + "children": [ + { + "type": "Boolean", + "name": "contains" + }, + { + "type": "joinpoint", + "name": "jp", + "defaultValue": "" + }] + }, + { + "type": "attribute", + "tooltip": "Returns an array with the descendants of the node", + "children": [ + { + "type": "joinpoint[]", + "name": "descendants" + }] + }, + { + "type": "attribute", + "tooltip": "Looks for an ancestor joinpoint name, walking back on the AST", + "children": [ + { + "type": "joinpoint", + "name": "getAncestor" + }, + { + "type": "String", + "name": "type", + "defaultValue": "" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the index of this join point in relation to its parent", + "children": [ + { + "type": "int", + "name": "indexOfSelf" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the node that came before this node, or undefined if there is none", + "children": [ + { + "type": "joinpoint", + "name": "leftJp" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the parent node in the AST, or undefined if it is the root node", + "children": [ + { + "type": "joinpoint", + "name": "parent" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the node that comes after this node, or undefined if there is none", + "children": [ + { + "type": "joinpoint", + "name": "rightJp" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the 'program' join point", + "children": [ + { + "type": "program", + "name": "root" + }] + }, + { + "type": "attribute", + "tooltip": "the nodes of the scope of the current join point. If this node has a body (e.g., loop, function) corresponds to the children of the body. Otherwise, returns an empty array", + "children": [ + { + "type": "joinpoint[]", + "name": "scopeNodes" + }] + }, + { + "type": "action", + "tooltip": "Performs a copy of the node and its children, but not of the nodes in its fields", + "children": [ + { + "type": "joinpoint", + "name": "copy" + }] + }, + { + "type": "action", + "tooltip": "Performs a copy of the node and its children, including the nodes in their fields (only the first level of field nodes, this function is not recursive)", + "children": [ + { + "type": "joinpoint", + "name": "deepCopy" + }] + }, + { + "type": "action", + "tooltip": "Removes node associated to the joinpoint from the AST", + "children": [ + { + "type": "joinpoint", + "name": "detach" + }] + }, + { + "type": "action", + "tooltip": "Inserts the given join point after this join point", + "children": [ + { + "type": "joinpoint", + "name": "insertAfter" + }, + { + "type": "joinpoint", + "name": "node", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Overload which accepts a string", + "children": [ + { + "type": "joinpoint", + "name": "insertAfter" + }, + { + "type": "String", + "name": "code", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Inserts the given join point before this join point", + "children": [ + { + "type": "joinpoint", + "name": "insertBefore" + }, + { + "type": "joinpoint", + "name": "node", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Overload which accepts a string", + "children": [ + { + "type": "joinpoint", + "name": "insertBefore" + }, + { + "type": "String", + "name": "node", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Replaces this node with the given node", + "children": [ + { + "type": "joinpoint", + "name": "replaceWith" + }, + { + "type": "joinpoint", + "name": "node", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Overload which accepts a list of join points", + "children": [ + { + "type": "joinpoint", + "name": "replaceWith" + }, + { + "type": "joinpoint[]", + "name": "node", + "defaultValue": "" + }] + }] + }, + { + "type": "joinpoint", + "name": "initialization", + "extends": "joinpoint" , + "children": [ + { + "type": "attribute", + "tooltip": "Returns an array with the children of the node", + "children": [ + { + "type": "joinpoint[]", + "name": "children" + }] + }, + { + "type": "attribute", + "tooltip": "String with the code represented by this node", + "children": [ + { + "type": "String", + "name": "code" + }] + }, + { + "type": "attribute", + "tooltip": "true if the given node is a descendant of this node", + "children": [ + { + "type": "Boolean", + "name": "contains" + }, + { + "type": "joinpoint", + "name": "jp", + "defaultValue": "" + }] + }, + { + "type": "attribute", + "tooltip": "Returns an array with the descendants of the node", + "children": [ + { + "type": "joinpoint[]", + "name": "descendants" + }] + }, + { + "type": "attribute", + "tooltip": "Looks for an ancestor joinpoint name, walking back on the AST", + "children": [ + { + "type": "joinpoint", + "name": "getAncestor" + }, + { + "type": "String", + "name": "type", + "defaultValue": "" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the index of this join point in relation to its parent", + "children": [ + { + "type": "int", + "name": "indexOfSelf" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the node that came before this node, or undefined if there is none", + "children": [ + { + "type": "joinpoint", + "name": "leftJp" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the parent node in the AST, or undefined if it is the root node", + "children": [ + { + "type": "joinpoint", + "name": "parent" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the node that comes after this node, or undefined if there is none", + "children": [ + { + "type": "joinpoint", + "name": "rightJp" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the 'program' join point", + "children": [ + { + "type": "program", + "name": "root" + }] + }, + { + "type": "attribute", + "tooltip": "the nodes of the scope of the current join point. If this node has a body (e.g., loop, function) corresponds to the children of the body. Otherwise, returns an empty array", + "children": [ + { + "type": "joinpoint[]", + "name": "scopeNodes" + }] + }, + { + "type": "action", + "tooltip": "Performs a copy of the node and its children, but not of the nodes in its fields", + "children": [ + { + "type": "joinpoint", + "name": "copy" + }] + }, + { + "type": "action", + "tooltip": "Performs a copy of the node and its children, including the nodes in their fields (only the first level of field nodes, this function is not recursive)", + "children": [ + { + "type": "joinpoint", + "name": "deepCopy" + }] + }, + { + "type": "action", + "tooltip": "Removes node associated to the joinpoint from the AST", + "children": [ + { + "type": "joinpoint", + "name": "detach" + }] + }, + { + "type": "action", + "tooltip": "Inserts the given join point after this join point", + "children": [ + { + "type": "joinpoint", + "name": "insertAfter" + }, + { + "type": "joinpoint", + "name": "node", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Overload which accepts a string", + "children": [ + { + "type": "joinpoint", + "name": "insertAfter" + }, + { + "type": "String", + "name": "code", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Inserts the given join point before this join point", + "children": [ + { + "type": "joinpoint", + "name": "insertBefore" + }, + { + "type": "joinpoint", + "name": "node", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Overload which accepts a string", + "children": [ + { + "type": "joinpoint", + "name": "insertBefore" + }, + { + "type": "String", + "name": "node", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Replaces this node with the given node", + "children": [ + { + "type": "joinpoint", + "name": "replaceWith" + }, + { + "type": "joinpoint", + "name": "node", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Overload which accepts a list of join points", + "children": [ + { + "type": "joinpoint", + "name": "replaceWith" + }, + { + "type": "joinpoint[]", + "name": "node", + "defaultValue": "" + }] + }] + }, + { + "type": "joinpoint", + "name": "intLiteral", + "extends": "literal" , + "children": [ + { + "type": "attribute", + "children": [ + { + "type": "String", + "name": "literal" + }] + }, + { + "type": "attribute", + "tooltip": "Returns an array with the children of the node", + "children": [ + { + "type": "joinpoint[]", + "name": "children" + }] + }, + { + "type": "attribute", + "tooltip": "String with the code represented by this node", + "children": [ + { + "type": "String", + "name": "code" + }] + }, + { + "type": "attribute", + "tooltip": "true if the given node is a descendant of this node", + "children": [ + { + "type": "Boolean", + "name": "contains" + }, + { + "type": "joinpoint", + "name": "jp", + "defaultValue": "" + }] + }, + { + "type": "attribute", + "tooltip": "Returns an array with the descendants of the node", + "children": [ + { + "type": "joinpoint[]", + "name": "descendants" + }] + }, + { + "type": "attribute", + "tooltip": "Looks for an ancestor joinpoint name, walking back on the AST", + "children": [ + { + "type": "joinpoint", + "name": "getAncestor" + }, + { + "type": "String", + "name": "type", + "defaultValue": "" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the index of this join point in relation to its parent", + "children": [ + { + "type": "int", + "name": "indexOfSelf" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the node that came before this node, or undefined if there is none", + "children": [ + { + "type": "joinpoint", + "name": "leftJp" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the parent node in the AST, or undefined if it is the root node", + "children": [ + { + "type": "joinpoint", + "name": "parent" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the node that comes after this node, or undefined if there is none", + "children": [ + { + "type": "joinpoint", + "name": "rightJp" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the 'program' join point", + "children": [ + { + "type": "program", + "name": "root" + }] + }, + { + "type": "attribute", + "tooltip": "the nodes of the scope of the current join point. If this node has a body (e.g., loop, function) corresponds to the children of the body. Otherwise, returns an empty array", + "children": [ + { + "type": "joinpoint[]", + "name": "scopeNodes" + }] + }, + { + "type": "action", + "tooltip": "Performs a copy of the node and its children, but not of the nodes in its fields", + "children": [ + { + "type": "joinpoint", + "name": "copy" + }] + }, + { + "type": "action", + "tooltip": "Performs a copy of the node and its children, including the nodes in their fields (only the first level of field nodes, this function is not recursive)", + "children": [ + { + "type": "joinpoint", + "name": "deepCopy" + }] + }, + { + "type": "action", + "tooltip": "Removes node associated to the joinpoint from the AST", + "children": [ + { + "type": "joinpoint", + "name": "detach" + }] + }, + { + "type": "action", + "tooltip": "Inserts the given join point after this join point", + "children": [ + { + "type": "joinpoint", + "name": "insertAfter" + }, + { + "type": "joinpoint", + "name": "node", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Overload which accepts a string", + "children": [ + { + "type": "joinpoint", + "name": "insertAfter" + }, + { + "type": "String", + "name": "code", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Inserts the given join point before this join point", + "children": [ + { + "type": "joinpoint", + "name": "insertBefore" + }, + { + "type": "joinpoint", + "name": "node", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Overload which accepts a string", + "children": [ + { + "type": "joinpoint", + "name": "insertBefore" + }, + { + "type": "String", + "name": "node", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Replaces this node with the given node", + "children": [ + { + "type": "joinpoint", + "name": "replaceWith" + }, + { + "type": "joinpoint", + "name": "node", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Overload which accepts a list of join points", + "children": [ + { + "type": "joinpoint", + "name": "replaceWith" + }, + { + "type": "joinpoint[]", + "name": "node", + "defaultValue": "" + }] + }] + }, + { + "type": "joinpoint", + "name": "keywordAttributeSpecifier", + "extends": "attributeSpecifier" , + "children": [ + { + "type": "attribute", + "tooltip": "Returns an array with the children of the node", + "children": [ + { + "type": "joinpoint[]", + "name": "children" + }] + }, + { + "type": "attribute", + "tooltip": "String with the code represented by this node", + "children": [ + { + "type": "String", + "name": "code" + }] + }, + { + "type": "attribute", + "tooltip": "true if the given node is a descendant of this node", + "children": [ + { + "type": "Boolean", + "name": "contains" + }, + { + "type": "joinpoint", + "name": "jp", + "defaultValue": "" + }] + }, + { + "type": "attribute", + "tooltip": "Returns an array with the descendants of the node", + "children": [ + { + "type": "joinpoint[]", + "name": "descendants" + }] + }, + { + "type": "attribute", + "tooltip": "Looks for an ancestor joinpoint name, walking back on the AST", + "children": [ + { + "type": "joinpoint", + "name": "getAncestor" + }, + { + "type": "String", + "name": "type", + "defaultValue": "" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the index of this join point in relation to its parent", + "children": [ + { + "type": "int", + "name": "indexOfSelf" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the node that came before this node, or undefined if there is none", + "children": [ + { + "type": "joinpoint", + "name": "leftJp" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the parent node in the AST, or undefined if it is the root node", + "children": [ + { + "type": "joinpoint", + "name": "parent" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the node that comes after this node, or undefined if there is none", + "children": [ + { + "type": "joinpoint", + "name": "rightJp" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the 'program' join point", + "children": [ + { + "type": "program", + "name": "root" + }] + }, + { + "type": "attribute", + "tooltip": "the nodes of the scope of the current join point. If this node has a body (e.g., loop, function) corresponds to the children of the body. Otherwise, returns an empty array", + "children": [ + { + "type": "joinpoint[]", + "name": "scopeNodes" + }] + }, + { + "type": "action", + "tooltip": "Performs a copy of the node and its children, but not of the nodes in its fields", + "children": [ + { + "type": "joinpoint", + "name": "copy" + }] + }, + { + "type": "action", + "tooltip": "Performs a copy of the node and its children, including the nodes in their fields (only the first level of field nodes, this function is not recursive)", + "children": [ + { + "type": "joinpoint", + "name": "deepCopy" + }] + }, + { + "type": "action", + "tooltip": "Removes node associated to the joinpoint from the AST", + "children": [ + { + "type": "joinpoint", + "name": "detach" + }] + }, + { + "type": "action", + "tooltip": "Inserts the given join point after this join point", + "children": [ + { + "type": "joinpoint", + "name": "insertAfter" + }, + { + "type": "joinpoint", + "name": "node", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Overload which accepts a string", + "children": [ + { + "type": "joinpoint", + "name": "insertAfter" + }, + { + "type": "String", + "name": "code", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Inserts the given join point before this join point", + "children": [ + { + "type": "joinpoint", + "name": "insertBefore" + }, + { + "type": "joinpoint", + "name": "node", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Overload which accepts a string", + "children": [ + { + "type": "joinpoint", + "name": "insertBefore" + }, + { + "type": "String", + "name": "node", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Replaces this node with the given node", + "children": [ + { + "type": "joinpoint", + "name": "replaceWith" + }, + { + "type": "joinpoint", + "name": "node", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Overload which accepts a list of join points", + "children": [ + { + "type": "joinpoint", + "name": "replaceWith" + }, + { + "type": "joinpoint[]", + "name": "node", + "defaultValue": "" + }] + }] + }, + { + "type": "joinpoint", + "name": "literal", + "extends": "expr" , + "tooltip": "Represents a literal", + "children": [ + { + "type": "attribute", + "children": [ + { + "type": "String", + "name": "literal" + }] + }, + { + "type": "attribute", + "tooltip": "Returns an array with the children of the node", + "children": [ + { + "type": "joinpoint[]", + "name": "children" + }] + }, + { + "type": "attribute", + "tooltip": "String with the code represented by this node", + "children": [ + { + "type": "String", + "name": "code" + }] + }, + { + "type": "attribute", + "tooltip": "true if the given node is a descendant of this node", + "children": [ + { + "type": "Boolean", + "name": "contains" + }, + { + "type": "joinpoint", + "name": "jp", + "defaultValue": "" + }] + }, + { + "type": "attribute", + "tooltip": "Returns an array with the descendants of the node", + "children": [ + { + "type": "joinpoint[]", + "name": "descendants" + }] + }, + { + "type": "attribute", + "tooltip": "Looks for an ancestor joinpoint name, walking back on the AST", + "children": [ + { + "type": "joinpoint", + "name": "getAncestor" + }, + { + "type": "String", + "name": "type", + "defaultValue": "" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the index of this join point in relation to its parent", + "children": [ + { + "type": "int", + "name": "indexOfSelf" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the node that came before this node, or undefined if there is none", + "children": [ + { + "type": "joinpoint", + "name": "leftJp" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the parent node in the AST, or undefined if it is the root node", + "children": [ + { + "type": "joinpoint", + "name": "parent" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the node that comes after this node, or undefined if there is none", + "children": [ + { + "type": "joinpoint", + "name": "rightJp" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the 'program' join point", + "children": [ + { + "type": "program", + "name": "root" + }] + }, + { + "type": "attribute", + "tooltip": "the nodes of the scope of the current join point. If this node has a body (e.g., loop, function) corresponds to the children of the body. Otherwise, returns an empty array", + "children": [ + { + "type": "joinpoint[]", + "name": "scopeNodes" + }] + }, + { + "type": "action", + "tooltip": "Performs a copy of the node and its children, but not of the nodes in its fields", + "children": [ + { + "type": "joinpoint", + "name": "copy" + }] + }, + { + "type": "action", + "tooltip": "Performs a copy of the node and its children, including the nodes in their fields (only the first level of field nodes, this function is not recursive)", + "children": [ + { + "type": "joinpoint", + "name": "deepCopy" + }] + }, + { + "type": "action", + "tooltip": "Removes node associated to the joinpoint from the AST", + "children": [ + { + "type": "joinpoint", + "name": "detach" + }] + }, + { + "type": "action", + "tooltip": "Inserts the given join point after this join point", + "children": [ + { + "type": "joinpoint", + "name": "insertAfter" + }, + { + "type": "joinpoint", + "name": "node", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Overload which accepts a string", + "children": [ + { + "type": "joinpoint", + "name": "insertAfter" + }, + { + "type": "String", + "name": "code", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Inserts the given join point before this join point", + "children": [ + { + "type": "joinpoint", + "name": "insertBefore" + }, + { + "type": "joinpoint", + "name": "node", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Overload which accepts a string", + "children": [ + { + "type": "joinpoint", + "name": "insertBefore" + }, + { + "type": "String", + "name": "node", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Replaces this node with the given node", + "children": [ + { + "type": "joinpoint", + "name": "replaceWith" + }, + { + "type": "joinpoint", + "name": "node", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Overload which accepts a list of join points", + "children": [ + { + "type": "joinpoint", + "name": "replaceWith" + }, + { + "type": "joinpoint[]", + "name": "node", + "defaultValue": "" + }] + }] + }, + { + "type": "joinpoint", + "name": "loopControl", + "extends": "joinpoint" , + "tooltip": "Represents the loop control structure, with specialized subclasses for different loop kinds", + "children": [ + { + "type": "attribute", + "tooltip": "Returns an array with the children of the node", + "children": [ + { + "type": "joinpoint[]", + "name": "children" + }] + }, + { + "type": "attribute", + "tooltip": "String with the code represented by this node", + "children": [ + { + "type": "String", + "name": "code" + }] + }, + { + "type": "attribute", + "tooltip": "true if the given node is a descendant of this node", + "children": [ + { + "type": "Boolean", + "name": "contains" + }, + { + "type": "joinpoint", + "name": "jp", + "defaultValue": "" + }] + }, + { + "type": "attribute", + "tooltip": "Returns an array with the descendants of the node", + "children": [ + { + "type": "joinpoint[]", + "name": "descendants" + }] + }, + { + "type": "attribute", + "tooltip": "Looks for an ancestor joinpoint name, walking back on the AST", + "children": [ + { + "type": "joinpoint", + "name": "getAncestor" + }, + { + "type": "String", + "name": "type", + "defaultValue": "" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the index of this join point in relation to its parent", + "children": [ + { + "type": "int", + "name": "indexOfSelf" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the node that came before this node, or undefined if there is none", + "children": [ + { + "type": "joinpoint", + "name": "leftJp" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the parent node in the AST, or undefined if it is the root node", + "children": [ + { + "type": "joinpoint", + "name": "parent" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the node that comes after this node, or undefined if there is none", + "children": [ + { + "type": "joinpoint", + "name": "rightJp" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the 'program' join point", + "children": [ + { + "type": "program", + "name": "root" + }] + }, + { + "type": "attribute", + "tooltip": "the nodes of the scope of the current join point. If this node has a body (e.g., loop, function) corresponds to the children of the body. Otherwise, returns an empty array", + "children": [ + { + "type": "joinpoint[]", + "name": "scopeNodes" + }] + }, + { + "type": "action", + "tooltip": "Performs a copy of the node and its children, but not of the nodes in its fields", + "children": [ + { + "type": "joinpoint", + "name": "copy" + }] + }, + { + "type": "action", + "tooltip": "Performs a copy of the node and its children, including the nodes in their fields (only the first level of field nodes, this function is not recursive)", + "children": [ + { + "type": "joinpoint", + "name": "deepCopy" + }] + }, + { + "type": "action", + "tooltip": "Removes node associated to the joinpoint from the AST", + "children": [ + { + "type": "joinpoint", + "name": "detach" }] }, { - "type": "attribute", - "tooltip": "Returns the parent node in the AST, or undefined if it is the root node", + "type": "action", + "tooltip": "Inserts the given join point after this join point", "children": [ { "type": "joinpoint", - "name": "parent" + "name": "insertAfter" + }, + { + "type": "joinpoint", + "name": "node", + "defaultValue": "" }] }, { - "type": "attribute", - "tooltip": "Returns the node that comes after this node, or undefined if there is none", + "type": "action", + "tooltip": "Overload which accepts a string", "children": [ { "type": "joinpoint", - "name": "rightJp" + "name": "insertAfter" + }, + { + "type": "String", + "name": "code", + "defaultValue": "" }] }, { - "type": "attribute", - "tooltip": "Returns the 'program' join point", + "type": "action", + "tooltip": "Inserts the given join point before this join point", "children": [ { - "type": "program", - "name": "root" + "type": "joinpoint", + "name": "insertBefore" + }, + { + "type": "joinpoint", + "name": "node", + "defaultValue": "" }] }, { - "type": "attribute", - "tooltip": "the nodes of the scope of the current join point. If this node has a body (e.g., loop, function) corresponds to the children of the body. Otherwise, returns an empty array", + "type": "action", + "tooltip": "Overload which accepts a string", "children": [ { - "type": "joinpoint[]", - "name": "scopeNodes" + "type": "joinpoint", + "name": "insertBefore" + }, + { + "type": "String", + "name": "node", + "defaultValue": "" }] }, { "type": "action", - "tooltip": "Removes node associated to the joinpoint from the AST", + "tooltip": "Replaces this node with the given node", "children": [ { "type": "joinpoint", - "name": "detach" + "name": "replaceWith" + }, + { + "type": "joinpoint", + "name": "node", + "defaultValue": "" }] }, { "type": "action", - "tooltip": "Replaces this node with the given node", + "tooltip": "Overload which accepts a list of join points", "children": [ { "type": "joinpoint", "name": "replaceWith" }, { - "type": "joinpoint", + "type": "joinpoint[]", "name": "node", "defaultValue": "" }] @@ -4357,15 +7041,16 @@ }, { "type": "joinpoint", - "name": "intLiteral", - "extends": "literal" , + "name": "mainProgram", + "extends": "programUnit" , "children": [ { "type": "attribute", + "tooltip": "Returns the unit's specification part", "children": [ { - "type": "String", - "name": "literal" + "type": "specification", + "name": "specification" }] }, { @@ -4591,16 +7276,16 @@ }, { "type": "joinpoint", - "name": "literal", - "extends": "expr" , - "tooltip": "Represents a literal", + "name": "nameValue", + "extends": "joinpoint" , + "tooltip": "Represents a name/value pair in a compiler directive", "children": [ { "type": "attribute", "children": [ { "type": "String", - "name": "literal" + "name": "name" }] }, { @@ -4826,10 +7511,34 @@ }, { "type": "joinpoint", - "name": "loopControl", - "extends": "joinpoint" , - "tooltip": "Represents the loop control structure, with specialized subclasses for different loop kinds", + "name": "ompBlockConstruct", + "extends": "ompConstruct" , + "tooltip": "Represents an OpenMP block construct (such as parallel or task)", "children": [ + { + "type": "attribute", + "children": [ + { + "type": "ompClause[]", + "name": "clauses" + }] + }, + { + "type": "attribute", + "children": [ + { + "type": "Boolean", + "name": "isFirst" + }] + }, + { + "type": "attribute", + "children": [ + { + "type": "Boolean", + "name": "isLast" + }] + }, { "type": "attribute", "tooltip": "Returns an array with the children of the node", @@ -4939,6 +7648,46 @@ "name": "scopeNodes" }] }, + { + "type": "action", + "children": [ + { + "type": "void", + "name": "setBody" + }, + { + "type": "execution", + "name": "body", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Sets the construct's clauses", + "children": [ + { + "type": "void", + "name": "setClauses" + }, + { + "type": "ompClause[]", + "name": "clauses", + "defaultValue": "" + }] + }, + { + "type": "action", + "children": [ + { + "type": "void", + "name": "setDirective" + }, + { + "type": "String", + "name": "directive", + "defaultValue": "" + }] + }, { "type": "action", "tooltip": "Performs a copy of the node and its children, but not of the nodes in its fields", @@ -5053,18 +7802,10 @@ }, { "type": "joinpoint", - "name": "mainProgram", - "extends": "programUnit" , + "name": "ompClause", + "extends": "joinpoint" , + "tooltip": "Represents an OpenMP clause", "children": [ - { - "type": "attribute", - "tooltip": "Returns the unit's specification part", - "children": [ - { - "type": "specification", - "name": "specification" - }] - }, { "type": "attribute", "tooltip": "Returns an array with the children of the node", @@ -5288,16 +8029,32 @@ }, { "type": "joinpoint", - "name": "nameValue", - "extends": "joinpoint" , - "tooltip": "Represents a name/value pair in a compiler directive", + "name": "ompConstruct", + "extends": "executableStatement" , + "tooltip": "Represents a generic OpenMP construct", "children": [ { "type": "attribute", "children": [ { - "type": "String", - "name": "name" + "type": "ompClause[]", + "name": "clauses" + }] + }, + { + "type": "attribute", + "children": [ + { + "type": "Boolean", + "name": "isFirst" + }] + }, + { + "type": "attribute", + "children": [ + { + "type": "Boolean", + "name": "isLast" }] }, { @@ -5409,6 +8166,33 @@ "name": "scopeNodes" }] }, + { + "type": "action", + "tooltip": "Sets the construct's clauses", + "children": [ + { + "type": "void", + "name": "setClauses" + }, + { + "type": "ompClause[]", + "name": "clauses", + "defaultValue": "" + }] + }, + { + "type": "action", + "children": [ + { + "type": "void", + "name": "setDirective" + }, + { + "type": "String", + "name": "directive", + "defaultValue": "" + }] + }, { "type": "action", "tooltip": "Performs a copy of the node and its children, but not of the nodes in its fields", @@ -5502,55 +8286,31 @@ }, { "type": "joinpoint", - "name": "node", - "defaultValue": "" - }] - }, - { - "type": "action", - "tooltip": "Overload which accepts a list of join points", - "children": [ - { - "type": "joinpoint", - "name": "replaceWith" - }, - { - "type": "joinpoint[]", - "name": "node", - "defaultValue": "" - }] - }] - }, - { - "type": "joinpoint", - "name": "ompBlockConstruct", - "extends": "ompConstruct" , - "tooltip": "Represents an OpenMP block construct (such as parallel or task)", - "children": [ - { - "type": "attribute", - "children": [ - { - "type": "ompClause[]", - "name": "clauses" - }] - }, - { - "type": "attribute", - "children": [ - { - "type": "Boolean", - "name": "isFirst" + "name": "node", + "defaultValue": "" }] }, { - "type": "attribute", + "type": "action", + "tooltip": "Overload which accepts a list of join points", "children": [ { - "type": "Boolean", - "name": "isLast" + "type": "joinpoint", + "name": "replaceWith" + }, + { + "type": "joinpoint[]", + "name": "node", + "defaultValue": "" }] - }, + }] + }, + { + "type": "joinpoint", + "name": "ompDataSharingClause", + "extends": "ompClause" , + "tooltip": "Represents an OpenMP datasharing clause (public, private, ...)", + "children": [ { "type": "attribute", "tooltip": "Returns an array with the children of the node", @@ -5660,46 +8420,6 @@ "name": "scopeNodes" }] }, - { - "type": "action", - "children": [ - { - "type": "void", - "name": "setBody" - }, - { - "type": "execution", - "name": "body", - "defaultValue": "" - }] - }, - { - "type": "action", - "tooltip": "Sets the construct's clauses", - "children": [ - { - "type": "void", - "name": "setClauses" - }, - { - "type": "ompClause[]", - "name": "clauses", - "defaultValue": "" - }] - }, - { - "type": "action", - "children": [ - { - "type": "void", - "name": "setDirective" - }, - { - "type": "String", - "name": "directive", - "defaultValue": "" - }] - }, { "type": "action", "tooltip": "Performs a copy of the node and its children, but not of the nodes in its fields", @@ -5814,10 +8534,34 @@ }, { "type": "joinpoint", - "name": "ompClause", - "extends": "joinpoint" , - "tooltip": "Represents an OpenMP clause", + "name": "ompLoopConstruct", + "extends": "ompConstruct" , + "tooltip": "Represents an OpenMP loop construct (such as do or do parallel)", "children": [ + { + "type": "attribute", + "children": [ + { + "type": "ompClause[]", + "name": "clauses" + }] + }, + { + "type": "attribute", + "children": [ + { + "type": "Boolean", + "name": "isFirst" + }] + }, + { + "type": "attribute", + "children": [ + { + "type": "Boolean", + "name": "isLast" + }] + }, { "type": "attribute", "tooltip": "Returns an array with the children of the node", @@ -5927,6 +8671,46 @@ "name": "scopeNodes" }] }, + { + "type": "action", + "children": [ + { + "type": "void", + "name": "setLoop" + }, + { + "type": "doStatement", + "name": "loop", + "defaultValue": "" + }] + }, + { + "type": "action", + "tooltip": "Sets the construct's clauses", + "children": [ + { + "type": "void", + "name": "setClauses" + }, + { + "type": "ompClause[]", + "name": "clauses", + "defaultValue": "" + }] + }, + { + "type": "action", + "children": [ + { + "type": "void", + "name": "setDirective" + }, + { + "type": "String", + "name": "directive", + "defaultValue": "" + }] + }, { "type": "action", "tooltip": "Performs a copy of the node and its children, but not of the nodes in its fields", @@ -6041,34 +8825,9 @@ }, { "type": "joinpoint", - "name": "ompConstruct", - "extends": "executableStatement" , - "tooltip": "Represents a generic OpenMP construct", + "name": "ompOrderedClause", + "extends": "ompClause" , "children": [ - { - "type": "attribute", - "children": [ - { - "type": "ompClause[]", - "name": "clauses" - }] - }, - { - "type": "attribute", - "children": [ - { - "type": "Boolean", - "name": "isFirst" - }] - }, - { - "type": "attribute", - "children": [ - { - "type": "Boolean", - "name": "isLast" - }] - }, { "type": "attribute", "tooltip": "Returns an array with the children of the node", @@ -6178,33 +8937,6 @@ "name": "scopeNodes" }] }, - { - "type": "action", - "tooltip": "Sets the construct's clauses", - "children": [ - { - "type": "void", - "name": "setClauses" - }, - { - "type": "ompClause[]", - "name": "clauses", - "defaultValue": "" - }] - }, - { - "type": "action", - "children": [ - { - "type": "void", - "name": "setDirective" - }, - { - "type": "String", - "name": "directive", - "defaultValue": "" - }] - }, { "type": "action", "tooltip": "Performs a copy of the node and its children, but not of the nodes in its fields", @@ -6319,9 +9051,8 @@ }, { "type": "joinpoint", - "name": "ompDataSharingClause", + "name": "ompReductionClause", "extends": "ompClause" , - "tooltip": "Represents an OpenMP datasharing clause (public, private, ...)", "children": [ { "type": "attribute", @@ -6546,34 +9277,9 @@ }, { "type": "joinpoint", - "name": "ompLoopConstruct", - "extends": "ompConstruct" , - "tooltip": "Represents an OpenMP loop construct (such as do or do parallel)", + "name": "parameterKeyword", + "extends": "keywordAttributeSpecifier" , "children": [ - { - "type": "attribute", - "children": [ - { - "type": "ompClause[]", - "name": "clauses" - }] - }, - { - "type": "attribute", - "children": [ - { - "type": "Boolean", - "name": "isFirst" - }] - }, - { - "type": "attribute", - "children": [ - { - "type": "Boolean", - "name": "isLast" - }] - }, { "type": "attribute", "tooltip": "Returns an array with the children of the node", @@ -6671,56 +9377,16 @@ "children": [ { "type": "program", - "name": "root" - }] - }, - { - "type": "attribute", - "tooltip": "the nodes of the scope of the current join point. If this node has a body (e.g., loop, function) corresponds to the children of the body. Otherwise, returns an empty array", - "children": [ - { - "type": "joinpoint[]", - "name": "scopeNodes" - }] - }, - { - "type": "action", - "children": [ - { - "type": "void", - "name": "setLoop" - }, - { - "type": "doStatement", - "name": "loop", - "defaultValue": "" - }] - }, - { - "type": "action", - "tooltip": "Sets the construct's clauses", - "children": [ - { - "type": "void", - "name": "setClauses" - }, - { - "type": "ompClause[]", - "name": "clauses", - "defaultValue": "" + "name": "root" }] }, { - "type": "action", + "type": "attribute", + "tooltip": "the nodes of the scope of the current join point. If this node has a body (e.g., loop, function) corresponds to the children of the body. Otherwise, returns an empty array", "children": [ { - "type": "void", - "name": "setDirective" - }, - { - "type": "String", - "name": "directive", - "defaultValue": "" + "type": "joinpoint[]", + "name": "scopeNodes" }] }, { @@ -6837,8 +9503,9 @@ }, { "type": "joinpoint", - "name": "ompOrderedClause", - "extends": "ompClause" , + "name": "program", + "extends": "joinpoint" , + "tooltip": "Represents the complete program and is the top-most join point in the hierarchy", "children": [ { "type": "attribute", @@ -7063,9 +9730,18 @@ }, { "type": "joinpoint", - "name": "ompReductionClause", - "extends": "ompClause" , + "name": "programUnit", + "extends": "joinpoint" , "children": [ + { + "type": "attribute", + "tooltip": "Returns the unit's specification part", + "children": [ + { + "type": "specification", + "name": "specification" + }] + }, { "type": "attribute", "tooltip": "Returns an array with the children of the node", @@ -7289,10 +9965,41 @@ }, { "type": "joinpoint", - "name": "program", - "extends": "joinpoint" , - "tooltip": "Represents the complete program and is the top-most join point in the hierarchy", + "name": "rangeLoopControl", + "extends": "loopControl" , "children": [ + { + "type": "attribute", + "children": [ + { + "type": "expr", + "name": "lower" + }] + }, + { + "type": "attribute", + "children": [ + { + "type": "expr", + "name": "step" + }] + }, + { + "type": "attribute", + "children": [ + { + "type": "expr", + "name": "upper" + }] + }, + { + "type": "attribute", + "children": [ + { + "type": "dataRef", + "name": "var" + }] + }, { "type": "attribute", "tooltip": "Returns an array with the children of the node", @@ -7402,6 +10109,32 @@ "name": "scopeNodes" }] }, + { + "type": "action", + "children": [ + { + "type": "void", + "name": "setStep" + }, + { + "type": "expr", + "name": "step", + "defaultValue": "" + }] + }, + { + "type": "action", + "children": [ + { + "type": "void", + "name": "setUpper" + }, + { + "type": "expr", + "name": "upper", + "defaultValue": "" + }] + }, { "type": "action", "tooltip": "Performs a copy of the node and its children, but not of the nodes in its fields", @@ -7516,16 +10249,15 @@ }, { "type": "joinpoint", - "name": "programUnit", - "extends": "joinpoint" , + "name": "realLiteral", + "extends": "literal" , "children": [ { "type": "attribute", - "tooltip": "Returns the unit's specification part", "children": [ { - "type": "specification", - "name": "specification" + "type": "String", + "name": "literal" }] }, { @@ -7751,39 +10483,23 @@ }, { "type": "joinpoint", - "name": "rangeLoopControl", - "extends": "loopControl" , + "name": "specification", + "extends": "statementBlock" , "children": [ { "type": "attribute", "children": [ { - "type": "expr", - "name": "lower" - }] - }, - { - "type": "attribute", - "children": [ - { - "type": "expr", - "name": "step" - }] - }, - { - "type": "attribute", - "children": [ - { - "type": "expr", - "name": "upper" + "type": "specificationStatement[]", + "name": "specificationStmts" }] }, { "type": "attribute", "children": [ { - "type": "dataRef", - "name": "var" + "type": "statement[]", + "name": "stmts" }] }, { @@ -7897,27 +10613,15 @@ }, { "type": "action", + "tooltip": "Adds a UseStmt to a specification part. The statement is inserted at the beginning.", "children": [ { "type": "void", - "name": "setStep" - }, - { - "type": "expr", - "name": "step", - "defaultValue": "" - }] - }, - { - "type": "action", - "children": [ - { - "type": "void", - "name": "setUpper" + "name": "addUseStmt" }, { - "type": "expr", - "name": "upper", + "type": "useStatement", + "name": "stmt", "defaultValue": "" }] }, @@ -8035,15 +10739,23 @@ }, { "type": "joinpoint", - "name": "realLiteral", - "extends": "literal" , + "name": "specificationStatement", + "extends": "statement" , "children": [ { "type": "attribute", "children": [ { - "type": "String", - "name": "literal" + "type": "Boolean", + "name": "isFirst" + }] + }, + { + "type": "attribute", + "children": [ + { + "type": "Boolean", + "name": "isLast" }] }, { @@ -8269,15 +10981,24 @@ }, { "type": "joinpoint", - "name": "specification", - "extends": "statementBlock" , + "name": "statement", + "extends": "joinpoint" , + "tooltip": "Represents a Fortran statement", "children": [ { "type": "attribute", "children": [ { - "type": "statement[]", - "name": "stmts" + "type": "Boolean", + "name": "isFirst" + }] + }, + { + "type": "attribute", + "children": [ + { + "type": "Boolean", + "name": "isLast" }] }, { @@ -8389,20 +11110,6 @@ "name": "scopeNodes" }] }, - { - "type": "action", - "tooltip": "Adds a UseStmt to a specification part. The statement is inserted at the beginning.", - "children": [ - { - "type": "void", - "name": "addUseStmt" - }, - { - "type": "useStatement", - "name": "stmt", - "defaultValue": "" - }] - }, { "type": "action", "tooltip": "Performs a copy of the node and its children, but not of the nodes in its fields", @@ -8517,24 +11224,15 @@ }, { "type": "joinpoint", - "name": "statement", + "name": "statementBlock", "extends": "joinpoint" , - "tooltip": "Represents a Fortran statement", "children": [ { "type": "attribute", "children": [ { - "type": "Boolean", - "name": "isFirst" - }] - }, - { - "type": "attribute", - "children": [ - { - "type": "Boolean", - "name": "isLast" + "type": "statement[]", + "name": "stmts" }] }, { @@ -8760,15 +11458,15 @@ }, { "type": "joinpoint", - "name": "statementBlock", - "extends": "joinpoint" , + "name": "stringLiteral", + "extends": "literal" , "children": [ { "type": "attribute", "children": [ { - "type": "statement[]", - "name": "stmts" + "type": "String", + "name": "literal" }] }, { @@ -8994,15 +11692,24 @@ }, { "type": "joinpoint", - "name": "stringLiteral", - "extends": "literal" , + "name": "subroutine", + "extends": "programUnit" , "children": [ { "type": "attribute", "children": [ { "type": "String", - "name": "literal" + "name": "moduleName" + }] + }, + { + "type": "attribute", + "tooltip": "Returns the unit's specification part", + "children": [ + { + "type": "specification", + "name": "specification" }] }, { @@ -9228,24 +11935,39 @@ }, { "type": "joinpoint", - "name": "subroutine", - "extends": "programUnit" , + "name": "typeDeclarationStatement", + "extends": "specificationStatement" , "children": [ { "type": "attribute", "children": [ { - "type": "String", - "name": "moduleName" + "type": "attributeSpecifier[]", + "name": "attrs" }] }, { "type": "attribute", - "tooltip": "Returns the unit's specification part", "children": [ { - "type": "specification", - "name": "specification" + "type": "entityDecl[]", + "name": "decls" + }] + }, + { + "type": "attribute", + "children": [ + { + "type": "Boolean", + "name": "isFirst" + }] + }, + { + "type": "attribute", + "children": [ + { + "type": "Boolean", + "name": "isLast" }] }, { diff --git a/FortranWeaver/src/pt/up/fe/specs/fortran/weaver/importable/AstFactory.java b/FortranWeaver/src/pt/up/fe/specs/fortran/weaver/importable/AstFactory.java index 5c1d014c..e92d75c8 100644 --- a/FortranWeaver/src/pt/up/fe/specs/fortran/weaver/importable/AstFactory.java +++ b/FortranWeaver/src/pt/up/fe/specs/fortran/weaver/importable/AstFactory.java @@ -120,6 +120,13 @@ public static ADoStatement doStatement(ARangeLoopControl control) { ); } + public static AExpr parenExpr(AExpr expr) { + return FortranJoinpoints.create( + FortranWeaver.getFactory().parenExpr((Expr) expr.getNode()), + AExpr.class + ); + } + public static AExpr intrinsicCall(String name, Object[] args) { DataRef callee = FortranWeaver.getFactory().dataRef(name); List argNodes = SpecsCollections.asListT(AExpr.class, args)