There is actually the reason for evals calls (for matched inner tuple only) - inline projection! Found it the hard way. The inner table in case of NLIJ is the inner node target table and not the output one.  The outer table tuple and non-matched inner one can be set by using getNValue method directly. The non-matched inner tuple should have the schema of the inner node output table and not the target one though.
I created ExpressionUtil::evalExpressions method to hide the eval loop. The other approach could be to properly initialize the projection node, factor-out ProjectionExecutor::p_execute while loop inner logic into a separate method, and call it from NLIJ loop as well.