import {
AST_Binary,
AST_Conditional,
AST_Chain,
AST_Dot,
AST_Object,
AST_Sequence,
AST_Statement,
AST_Sub,
AST_UnaryPostfix,
AST_PrefixedTemplateString
} from "../ast.js";
// return true if the node at the top of the stack (that means the
// innermost node in the current output) is lexically the first in
// a statement.
function first_in_statement(stack) {
let node = stack.parent(-1);
for (let i = 0, p; p = stack.parent(i); i++) {
if (p instanceof AST_Statement && p.body === node)
return true;
if ((p instanceof AST_Sequence && p.expressions[0] === node) ||
(p.TYPE === "Call" && p.expression === node) ||
(p instanceof AST_PrefixedTemplateString && p.prefix === node) ||
(p instanceof AST_Dot && p.expression === node) ||
(p instanceof AST_Sub && p.expression === node) ||
(p instanceof AST_Chain && p.expression === node) ||
(p instanceof AST_Conditional && p.condition === node) ||
(p instanceof AST_Binary && p.left === node) ||
(p instanceof AST_UnaryPostfix && p.expression === node)
) {
node = p;
} else {
return false;
}
}
}
// Returns whether the leftmost item in the expression is an object
function left_is_object(node) {
if (node instanceof AST_Object) return true;
if (node instanceof AST_Sequence) return left_is_object(node.expressions[0]);
if (node.TYPE === "Call") return left_is_object(node.expression);
if (node instanceof AST_PrefixedTemplateString) return left_is_object(node.prefix);
if (node instanceof AST_Dot || node instanceof AST_Sub) return left_is_object(node.expression);
if (node instanceof AST_Chain) return left_is_object(node.expression);
if (node instanceof AST_Conditional) return left_is_object(node.condition);
if (node instanceof AST_Binary) return left_is_object(node.left);
if (node instanceof AST_UnaryPostfix) return left_is_object(node.expression);
return false;
}
export { first_in_statement, left_is_object };