% A boolean expression is
% BOOLEXPR  <- OPERAND ( OPERATOR OPERAND )*
% OPERATOR  <- "||" | "&&"
% OPERAND   <- "(" BOOLEXPR ")" | "!" OPERAND | PREDICATE
% PREDICATE ==[f-expands to]== "{" RETURN-TF "}"
% RETURN-TF ==[run  by  TeX]== "\use_i:nn" || "\use_ii:nn"
%
% In particular, booleans are the predicates "{\use_i:nn}" and "{\use_i:nn}".
%
% ===========================
% Code (see below to test it)
% ===========================
\RequirePackage{expl3}
\ExplSyntaxOn
\cs_set_protected:Npn \c_true_abool { { \use_i:nn } }
\cs_set_protected:Npn \c_false_abool { { \use_ii:nn } }
\prg_new_conditional:Npnn \abool_if:n #1 { TF , T , F }
  {
    \abool_eval_start:w #1 ) S )
  }

\cs_new:Npn \abool_marker: { M }
\cs_new:Npn \abool_eval_start:w #1 )
  {
    \group_align_safe_begin:
    \abool_eval_operand:N #1 \abool_marker: \use_i:nn )
  }
\cs_new:Npn \abool_eval_operand:N #1
  {
    \if_meaning:w ( #1 % )
      \exp_after:wN \abool_eval_group:w
    \else:
      \if_meaning:w ! #1
        \exp_after:wN \exp_after:wN
        \exp_after:wN \abool_eval_not_operand:w
      \else:
        \exp_after:wN \abool_eval_predicate:n
        \tex_romannumeral:D -`q
      \fi:
    \fi:
    #1
  }
\cs_new:Npn \abool_eval_not_operand:w ! #1
  {
    \if_meaning:w ( #1 % )
      \exp_after:wN \abool_eval_not_group:w
    \else:
      \if_meaning:w ! #1
        \exp_after:wN \exp_after:wN
        \exp_after:wN \abool_eval_operand:w
      \else:
        \exp_after:wN \abool_eval_not_predicate:n
        \tex_romannumeral:D -`q
      \fi:
    \fi:
    #1
  }
\cs_new:Npn \abool_eval_operand:w ! { \abool_eval_operand:N }
\cs_new:Npn \abool_eval_predicate:n #1
  {
    #1
      { \exp_after:wN \abool_eval_true_operator:w }
      { \exp_after:wN \abool_eval_false_operator:w }
    \tex_romannumeral:D -`q
  }
\cs_new:Npn \abool_eval_not_predicate:n #1
  {
    #1
      { \exp_after:wN \abool_eval_false_operator:w }
      { \exp_after:wN \abool_eval_true_operator:w }
    \tex_romannumeral:D -`q
  }
\cs_new:Npn \abool_eval_group:w ( #1 \abool_marker:
  {
    \abool_eval_operand:N #1
    \abool_marker: \use_i:nn
  }
\cs_new:Npn \abool_eval_not_group:w ( #1 \abool_marker:
  {
    \abool_eval_operand:N #1
    \abool_marker: \use_ii:nn
  }
\cs_new:Npn \abool_eval_true_operator:w #1
  { \use:c { abool_#1_T:w } }
\cs_new:Npn \abool_eval_false_operator:w #1
  { \use:c { abool_#1_F:w } }
\cs_new:cpn { abool_&_F:w } &
  { \abool_eval_skip_to_end:Nw \abool_M_F:w }
\cs_new:cpn { abool_|_F:w } | { \abool_eval_operand:N }
\cs_new:cpn { abool_&_T:w } & { \abool_eval_operand:N }
\cs_new:cpn { abool_|_T:w } |
  { \abool_eval_skip_to_end:Nw \abool_M_T:w }
\cs_new:Npn \abool_eval_skip_to_end:Nw #1 #2 \abool_marker: #3 )
  {
    \abool_eval_skip_loop:nwwNw
      { #1 #3 }
      #2
      \q_mark \abool_eval_skip_one:nw
      (
      \q_mark \abool_eval_skip_done:nw
      \q_stop
      )
  }
\cs_new:Npn \abool_eval_skip_loop:nwwNw #1 #2 ( #3 \q_mark #4 #5 \q_stop
  { #4 {#1} #3 }
\cs_new:Npn \abool_eval_skip_one:nw #1 #2 )
  {
    \abool_eval_skip_loop:nwwNw
      {#1}
      #2
      \q_mark \abool_eval_skip_one:nw
      (
      \q_mark \abool_eval_skip_done:nw
      \q_stop
  }
\cs_new:Npn \abool_eval_skip_done:nw #1 #2 ) { #1 ) }
\cs_new:cpn { abool_M_T:w } #1#2)#3)
  {
    #1
      \abool_eval_true_operator:w
      \abool_eval_false_operator:w
    #3
    \abool_marker: #2 )
  }
\cs_new:cpn { abool_M_F:w } #1#2)#3)
  {
    #1
      \abool_eval_false_operator:w
      \abool_eval_true_operator:w
    #3
    \abool_marker: #2 )
  }
\cs_new:cpn { abool_S_T:w } #1 )
  { \group_align_safe_end: \prg_return_true: }
\cs_new:cpn { abool_S_F:w } #1 )
  { \group_align_safe_end: \prg_return_false: }

% =============================================
% Tests (using the l3time package, newly on the
% svn, but you can test without if you want).
% =============================================

% Example of a definition of a "new" predicate,
% which would automatically be done by
% \prg_new_conditional, of course.
\cs_set:Npn \str_if_eq_ap:xx #1#2
  {
    {
      \if_int_compare:w \pdftex_strcmp:D {#1}{#2}=\c_zero
        \prg_return_true: \else: \prg_return_false: \fi:
      \c_zero
    }
  }

\RequirePackage{l3time}
\iow_term:x { Old~boolean~expressions: }
\time:n
  {
    \bool_if:nTF
      {
        \c_true_bool
        && ( \c_false_bool || !!!( !( \str_if_eq_p:xx {a} {a} ) ) )
        || \ERROR
      }
      { }
      { }
  }

\iow_term:x { New~boolean~expressions: }
\time:n
  {
    \abool_if:nTF
      {
        \c_true_abool
        && ( \c_false_abool || !!!( !( \str_if_eq_ap:xx {a} {a} ) ) )
        || \ERROR
      }
      { }
      { }
  }

% Something impossible with the old bool_if:nTF
\cs_set_protected:Npn \tl_if_in_ap:nn #1#2
  { { \tl_if_in:nnTF {#1}{#2} } }
\abool_if:nTF
  {
    \c_true_abool
    && \tl_if_in_ap:nn {abc} {ab}
    && \c_true_abool
  }
  { }
  { }

\tex_end:D
% Note to BLF: see Experiment268.tex