<commit_before>/*
 * Copyright 2006-2008 The FLWOR Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "stdafx.h"

#include "functions/function.h"
#include "functions/library.h"

#include "compiler/rewriter/rules/ruleset.h"
#include "compiler/rewriter/framework/rule_driver.h"
#include "compiler/rewriter/tools/expr_tools.h"

#include "compiler/expression/flwor_expr.h"
#include "compiler/expression/expr_iter.h"
#include "compiler/expression/expr.h"

#include "context/static_context.h"

#include "types/typeops.h"
#include "types/casting.h"

#include "diagnostics/xquery_warning.h"
#include "diagnostics/assert.h"

#include <memory>
#include <iterator>

namespace zorba
{

static void collect_flw_vars(const flwor_expr&, expr::FreeVars&);

static bool is_trivial_expr(const expr*);

static bool safe_to_fold_single_use(var_expr*, TypeConstants::quantifier_t, const flwor_expr&);

static bool var_in_try_block_or_in_loop(const var_expr*, const expr*, bool, bool, bool&);

static bool is_subseq_pred(RewriterContext&, const flwor_expr*, csize whereClausePos, const expr*, var_expr_t&, expr_t&);


#define MODIFY( expr ) do { modified = true; expr; } while (0)


/*******************************************************************************

********************************************************************************/
static void fix_if_annotations(if_expr* ifExpr)
{
  expr_tools::fix_annotations(ifExpr, ifExpr->get_cond_expr());
  expr_tools::fix_annotations(ifExpr, ifExpr->get_then_expr());
  expr_tools::fix_annotations(ifExpr, ifExpr->get_else_expr());
}


/*******************************************************************************

********************************************************************************/
class SubstVars : public PrePostRewriteRule
{
protected:
  const var_expr   * theVarExpr;
  expr             * theSubstExpr;

public:
  SubstVars(const var_expr* var, expr* subst)
    :
    PrePostRewriteRule(RewriteRule::SubstVars, "SubstVars"),
    theVarExpr(var),
    theSubstExpr(subst)
  {
  }

protected:
  expr_t rewritePre(expr* node, RewriterContext& rCtx);
  expr_t rewritePost(expr* node, RewriterContext& rCtx);
};


RULE_REWRITE_PRE(SubstVars)
{
  return (node == theVarExpr) ? theSubstExpr : NULL;
}


RULE_REWRITE_POST(SubstVars)
{
  return NULL;
}


/*******************************************************************************
  Replace all references to var "var" inside the expr "root" with expr "subst"
********************************************************************************/
expr_t subst_vars(
    const RewriterContext& rCtx0,
    expr* root,
    const var_expr* var,
    expr* subst)
{
  RewriterContext rCtx(rCtx0.getCompilerCB(),
                       root,
                       rCtx0.theUDF,
                       rCtx0.theMessage,
                       rCtx0.theIsInOrderedMode);

  SubstVars rule(var, subst);

  bool modified;

  rule.apply(rCtx, root, modified);

#if 0  // debug substitutions
  std::cout << rCtx.theMessage << std::endl
            << "After subst " << var << " :" << std::endl;
  rCtx.getRoot()->put(std::cout) << std::endl;
#endif

  return rCtx.getRoot();
}



/*******************************************************************************

********************************************************************************/
RULE_REWRITE_PRE(EliminateUnusedLetVars)
{
  const QueryLoc& loc = LOC(node);
  static_context* sctx = node->get_sctx();
  TypeManager* tm = sctx->get_typemanager();

  if (node->get_expr_kind() != flwor_expr_kind)
    return NULL;

  flwor_expr* flworp = static_cast<flwor_expr *>(node);
  flwor_expr& flwor = *flworp;

  expr::FreeVars myVars;
  collect_flw_vars(flwor, myVars);

  const forletwin_clause& flwc = *reinterpret_cast<const forletwin_clause *>(flwor[0]);

  csize numClauses = flwor.num_clauses();
  csize numForLetClauses = 0;

  // "for $x in E return $x"  --> "E"
  // "let $x := E return $x"  --> "E"
  if (numClauses == 1 &&
      myVars.size() == 1 &&
      flwor.get_return_expr()->get_expr_kind() == wrapper_expr_kind)
  {
    const wrapper_expr* w = static_cast<const wrapper_expr*>(flwor.get_return_expr());
    if (w->get_expr() == flwc.get_var())
      return flwc.get_expr();
  }

  // "for $x in ... where E ... return ...", and E doesn't depend on FLWOR vars -->
  // "if E then flwor else ()", where flwor is the original flwor expr without the
  // where clause.
  expr* whereExpr;
  if ((whereExpr = flwor.get_where()) != NULL && !flwor.has_sequential_clauses())
  {
    const expr::FreeVars& whereVars = whereExpr->getFreeVars();

    expr::FreeVars diff;
    std::set_intersection(myVars.begin(),
                          myVars.end(),
                          whereVars.begin(),
                          whereVars.end(),
                          std::inserter(diff, diff.begin()));
    if (diff.empty())
    {
      expr_t oldWhere = whereExpr;
      flwor.remove_where_clause();

      rchandle<if_expr> ifExpr = new if_expr(sctx,
                                             loc,
                                             oldWhere,
                                             &flwor,
                                             fo_expr::create_seq(sctx, loc));

      fix_if_annotations(ifExpr);

      return ifExpr.getp();
    }
  }

  bool modified = false;
  group_clause* gc = NULL;

  // (a) Remove, if possible, FOR/LET vars that are not referenced anywhere
  // (b) Replace, if possible, FOR/LET vars that are referenced only once, with
  //     their domain expr.
  // (c) Change a LET var into a FOR var, if its domain expr consists of
  //     exactly one item.
  for (ulong i = 0; i < numClauses; ++i)
  {
    bool substitute = false;

    flwor_clause& c = *flwor.get_clause(i);

    if (c.get_kind() == flwor_clause::group_clause)
    {<commit_msg>Changed a piece of code to be applicable to either general or simple flwor expressions.<commit_after>/*
 * Copyright 2006-2008 The FLWOR Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "stdafx.h"

#include "functions/function.h"
#include "functions/library.h"

#include "compiler/rewriter/rules/ruleset.h"
#include "compiler/rewriter/framework/rule_driver.h"
#include "compiler/rewriter/tools/expr_tools.h"

#include "compiler/expression/flwor_expr.h"
#include "compiler/expression/expr_iter.h"
#include "compiler/expression/expr.h"

#include "context/static_context.h"

#include "types/typeops.h"
#include "types/casting.h"

#include "diagnostics/xquery_warning.h"
#include "diagnostics/assert.h"

#include <memory>
#include <iterator>

namespace zorba
{

static void collect_flw_vars(const flwor_expr&, expr::FreeVars&);

static bool is_trivial_expr(const expr*);

static bool safe_to_fold_single_use(var_expr*, TypeConstants::quantifier_t, const flwor_expr&);

static bool var_in_try_block_or_in_loop(const var_expr*, const expr*, bool, bool, bool&);

static bool is_subseq_pred(RewriterContext&, const flwor_expr*, csize whereClausePos, const expr*, var_expr_t&, expr_t&);


#define MODIFY( expr ) do { modified = true; expr; } while (0)


/*******************************************************************************

********************************************************************************/
static void fix_if_annotations(if_expr* ifExpr)
{
  expr_tools::fix_annotations(ifExpr, ifExpr->get_cond_expr());
  expr_tools::fix_annotations(ifExpr, ifExpr->get_then_expr());
  expr_tools::fix_annotations(ifExpr, ifExpr->get_else_expr());
}


/*******************************************************************************

********************************************************************************/
class SubstVars : public PrePostRewriteRule
{
protected:
  const var_expr   * theVarExpr;
  expr             * theSubstExpr;

public:
  SubstVars(const var_expr* var, expr* subst)
    :
    PrePostRewriteRule(RewriteRule::SubstVars, "SubstVars"),
    theVarExpr(var),
    theSubstExpr(subst)
  {
  }

protected:
  expr_t rewritePre(expr* node, RewriterContext& rCtx);
  expr_t rewritePost(expr* node, RewriterContext& rCtx);
};


RULE_REWRITE_PRE(SubstVars)
{
  return (node == theVarExpr) ? theSubstExpr : NULL;
}


RULE_REWRITE_POST(SubstVars)
{
  return NULL;
}


/*******************************************************************************
  Replace all references to var "var" inside the expr "root" with expr "subst"
********************************************************************************/
expr_t subst_vars(
    const RewriterContext& rCtx0,
    expr* root,
    const var_expr* var,
    expr* subst)
{
  RewriterContext rCtx(rCtx0.getCompilerCB(),
                       root,
                       rCtx0.theUDF,
                       rCtx0.theMessage,
                       rCtx0.theIsInOrderedMode);

  SubstVars rule(var, subst);

  bool modified;

  rule.apply(rCtx, root, modified);

#if 0  // debug substitutions
  std::cout << rCtx.theMessage << std::endl
            << "After subst " << var << " :" << std::endl;
  rCtx.getRoot()->put(std::cout) << std::endl;
#endif

  return rCtx.getRoot();
}



/*******************************************************************************

********************************************************************************/
RULE_REWRITE_PRE(EliminateUnusedLetVars)
{
  const QueryLoc& loc = LOC(node);
  static_context* sctx = node->get_sctx();
  TypeManager* tm = sctx->get_typemanager();

  if (node->get_expr_kind() != flwor_expr_kind)
    return NULL;

  flwor_expr* flworp = static_cast<flwor_expr *>(node);
  flwor_expr& flwor = *flworp;

  expr::FreeVars myVars;
  collect_flw_vars(flwor, myVars);

  const forletwin_clause& flwc = *reinterpret_cast<const forletwin_clause *>(flwor[0]);

  csize numClauses = flwor.num_clauses();
  csize numForLetClauses = 0;

  // "for $x in E return $x"  --> "E"
  // "let $x := E return $x"  --> "E"
  if (numClauses == 1 &&
      myVars.size() == 1 &&
      flwor.get_return_expr()->get_expr_kind() == wrapper_expr_kind)
  {
    const wrapper_expr* w = static_cast<const wrapper_expr*>(flwor.get_return_expr());
    if (w->get_expr() == flwc.get_var())
      return flwc.get_expr();
  }

  // "for $x in ... where E ... return ...", and E doesn't depend on FLWOR vars -->
  // "if E then flwor else ()", where flwor is the original flwor expr without the
  // where clause.
  expr* whereExpr;
  for(int i = 0; i < numClauses; ++i)
  {

    flwor_clause *clause = flwor.get_clause(i);

    if (clause->get_kind() == flwor_clause::where_clause &&
        !flwor.has_sequential_clauses())
    {
      whereExpr = clause->get_expr();
      const expr::FreeVars& whereVars = whereExpr->getFreeVars();

      expr::FreeVars diff;
      std::set_intersection(myVars.begin(),
                            myVars.end(),
                            whereVars.begin(),
                            whereVars.end(),
                            std::inserter(diff, diff.begin()));
      if (diff.empty())
      {
        expr_t oldWhere = whereExpr;
        flwor.remove_where_clause();

        rchandle<if_expr> ifExpr = new if_expr(sctx,
                                               loc,
                                               oldWhere,
                                               &flwor,
                                               fo_expr::create_seq(sctx, loc));

        fix_if_annotations(ifExpr);

        return ifExpr.getp();
      }
    }

  }

  bool modified = false;
  group_clause* gc = NULL;

  // (a) Remove, if possible, FOR/LET vars that are not referenced anywhere
  // (b) Replace, if possible, FOR/LET vars that are referenced only once, with
  //     their domain expr.
  // (c) Change a LET var into a FOR var, if its domain expr consists of
  //     exactly one item.
  for (ulong i = 0; i < numClauses; ++i)
  {
    bool substitute = false;

    flwor_clause& c = *flwor.get_clause(i);

    if (c.get_kind() == flwor_clause::group_clause)
    {
{'fraction_non_alphanumeric': 0.20773727118904783, 'fraction_numerical': 0.0037686509767728043, 'mean_word_length': 3.3751682368775238, 'pattern_counts': {'":': 0, '<': 46, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 16, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6603301', 'n_tokens_mistral': 4050, 'n_tokens_neox': 3931, 'n_words': 960}