code: private void translate(IQ query, DatalogProgram pr) {
  		QueryNode root = query.getTree().getRootNode();
  		if(!(root instanceof ConstructionNode)){
  			throw new DatalogConversionException("the root is expected to be a Construction Node");
  		}
  
  		UnaryIQTree tree = (UnaryIQTree) query.getTree();
  
  		ConstructionNode rootCn = (ConstructionNode) root;
  		Queue<RuleHead> heads = new LinkedList<>();
  
  		ImmutableSubstitution<ImmutableTerm> topSubstitution = Optional.of(rootCn)
  			.map(ConstructionNode::getSubstitution)
  			.orElseGet(substitutionFactory::getSubstitution);
  
  		heads.add(new RuleHead(topSubstitution, query.getProjectionAtom(), Optional.of(tree.getChild())));
  
  		// Mutable (append-only)
  		Map<QueryNode, DataAtom> subQueryProjectionAtoms = new HashMap<>();
  		subQueryProjectionAtoms.put(root, query.getProjectionAtom());
  
  		//In heads we keep the heads of the sub-rules in the program, e.g. ans5() :- LeftJoin(....)
  		while(!heads.isEmpty()) {
  
  			RuleHead head = heads.poll();
  
  			//Applying substitutions in the head.
  			ImmutableList<? extends ImmutableTerm> substitutedHeadAtomArguments = head.substitution.apply(head.atom.getArguments());
  
  			List<Function> atoms = new LinkedList<>();
  
  			Function newHead = immutabilityTools.convertToMutableFunction(head.atom.getPredicate(),
  					substitutedHeadAtomArguments);
  
  			//Constructing the rule
  			CQIE newrule = datalogFactory.getCQIE(newHead, atoms);
  
  			pr.appendRule(newrule);
  
              head.optionalChildNode.ifPresent(t -> {
                  List<Function> uAtoms = getAtomFrom(t, heads, subQueryProjectionAtoms, false);
                  newrule.getBody().addAll(uAtoms);
              });
  
  		}
  	}
docs: Translate a given IntermediateQuery query object to datalog program.
  Note that (the object ref of the) datalog program is passed as argument
  
  Assumption: the root is a construction node
  
  @return Datalog program that represents the construction of the SPARQL
  query.