diff --git a/src/interpreter/Engine.cpp b/src/interpreter/Engine.cpp index 27b57854640..5f8758be3da 100644 --- a/src/interpreter/Engine.cpp +++ b/src/interpreter/Engine.cpp @@ -979,7 +979,12 @@ RamDomain Engine::execute(const Node* node, Context& ctxt) { ESAC(False) CASE(Conjunction) - return execute(shadow.getLhs(), ctxt) && execute(shadow.getRhs(), ctxt); + for (const auto& child : shadow.getChildren()) { + if (!execute(child.get(), ctxt)) { + return false; + } + } + return true; ESAC(Conjunction) CASE(Negation) diff --git a/src/interpreter/Generator.cpp b/src/interpreter/Generator.cpp index 3de7aeaf825..3844146c88a 100644 --- a/src/interpreter/Generator.cpp +++ b/src/interpreter/Generator.cpp @@ -200,7 +200,21 @@ NodePtr NodeGenerator::visit_(type_identity, const ram::False& lfals } NodePtr NodeGenerator::visit_(type_identity, const ram::Conjunction& conj) { - return mk(I_Conjunction, &conj, dispatch(conj.getLHS()), dispatch(conj.getRHS())); + NodePtrVec children; + std::stack dfs; + dfs.push(&conj.getRHS()); + dfs.push(&conj.getLHS()); + while (!dfs.empty()) { + const ram::Node* term = dfs.top(); + dfs.pop(); + if (const ram::Conjunction* subconj = as(term)) { + dfs.push(&subconj->getRHS()); + dfs.push(&subconj->getLHS()); + } else { + children.emplace_back(std::move(dispatch(*term))); + } + } + return mk(I_Conjunction, &conj, std::move(children)); } NodePtr NodeGenerator::visit_(type_identity, const ram::Negation& neg) { diff --git a/src/interpreter/Node.h b/src/interpreter/Node.h index 1e07aa7eed4..fd50f88c81f 100644 --- a/src/interpreter/Node.h +++ b/src/interpreter/Node.h @@ -578,9 +578,12 @@ class False : public Node { /** * @class Conjunction + * + * It's a compound node so that conjunctions with hundreds of terms + * do not overflow the engine stack with left/right recursion. */ -class Conjunction : public BinaryNode { - using BinaryNode::BinaryNode; +class Conjunction : public CompoundNode { + using CompoundNode::CompoundNode; }; /**