@abaplint/transpiler
Version:
111 lines • 3.9 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Rearranger = void 0;
const core_1 = require("@abaplint/core");
// this rearranges the AST to take precedence into account
class Rearranger {
run(type, node) {
if (!node) {
return undefined;
}
if (type === "INTF") {
// no arithmethic expressions in global interfaces
return node;
}
const flattened = this.flatten(node);
const rebuilt = this.rebuild(flattened);
return rebuilt;
}
/////////////////
rebuild(node) {
if (node instanceof core_1.Nodes.TokenNode) {
return node;
}
const children = node.getChildren();
children.forEach(this.rebuild.bind(this));
if (node instanceof core_1.Nodes.ExpressionNode) {
this.precedence(node);
}
return node;
}
// this takes a single flattened node, and splits into binary nodes according to precedence and left to right processing
precedence(node) {
const children = node.getChildren();
const arith = node.findDirectExpressions(core_1.Expressions.ArithOperator);
// after flattening it might have multiple operators under the samenode
if (arith.length <= 1) {
return;
}
let splitAt;
// multiplication/division and left to right
for (let i = arith.length - 1; i >= 0; i--) {
const a = arith[i];
const concat = a.concatTokens().toUpperCase();
if (concat === "*"
|| concat === "/"
|| concat === "**"
|| concat === "MOD"
|| concat === "DIV") {
continue;
}
splitAt = a;
break;
}
// fallback
if (splitAt === undefined) {
splitAt = arith[arith.length - 1];
}
const index = children.indexOf(splitAt);
let left = [];
{
const lhs = children.slice(0, index);
if (lhs.length > 1) {
const temp = new core_1.Nodes.ExpressionNode(node.get());
temp.setChildren(lhs);
this.precedence(temp);
left.push(temp);
}
else {
left = lhs;
}
}
let right = [];
{
const rhs = children.slice(index + 1);
if (rhs.length > 1) {
const temp = new core_1.Nodes.ExpressionNode(node.get());
temp.setChildren(rhs);
this.precedence(temp);
right.push(temp);
}
else {
right = rhs;
}
}
node.setChildren(left.concat([splitAt]).concat(right));
}
// this flattens the arithmethic expressions so all related is under the same node
flatten(node) {
if (node instanceof core_1.Nodes.TokenNode) {
return node;
}
const children = node.getChildren();
children.forEach(this.flatten.bind(this));
const last = children[children.length - 1];
const secondLast = children[children.length - 2];
if (last === undefined
|| secondLast === undefined
|| !(last instanceof core_1.Nodes.ExpressionNode)
|| !(last.get() instanceof core_1.Expressions.Source)
|| !(secondLast instanceof core_1.Nodes.ExpressionNode)
|| !(secondLast.get() instanceof core_1.Expressions.ArithOperator)) {
return node;
}
const withoutLast = node.getChildren().slice(0, children.length - 1);
const flat = withoutLast.concat(last.getChildren());
node.setChildren(flat);
return node;
}
}
exports.Rearranger = Rearranger;
//# sourceMappingURL=rearranger.js.map