<commit_before>/**********************************************************************
 * Copyright (c) 2014 HubSpot Inc.
 *
 * 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.
 **********************************************************************/

package com.hubspot.jinjava.interpret;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
import java.util.stream.Collectors;

import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.SetMultimap;
import com.hubspot.jinjava.lib.Importable;
import com.hubspot.jinjava.lib.exptest.ExpTest;
import com.hubspot.jinjava.lib.exptest.ExpTestLibrary;
import com.hubspot.jinjava.lib.filter.Filter;
import com.hubspot.jinjava.lib.filter.FilterLibrary;
import com.hubspot.jinjava.lib.fn.ELFunctionDefinition;
import com.hubspot.jinjava.lib.fn.FunctionLibrary;
import com.hubspot.jinjava.lib.fn.MacroFunction;
import com.hubspot.jinjava.lib.tag.Tag;
import com.hubspot.jinjava.lib.tag.TagLibrary;
import com.hubspot.jinjava.tree.Node;
import com.hubspot.jinjava.util.ScopeMap;

public class Context extends ScopeMap<String, Object> {
  public static final String GLOBAL_MACROS_SCOPE_KEY = "__macros__";
  public static final String IMPORT_RESOURCE_PATH_KEY = "import_resource_path";

  private final SetMultimap<String, String> dependencies = HashMultimap.create();
  private Map<Library, Set<String>> disabled;

  public boolean isValidationMode() {
    return validationMode;
  }

  public Context setValidationMode(boolean validationMode) {
    this.validationMode = validationMode;
    return this;
  }

  public enum Library {
    EXP_TEST,
    FILTER,
    FUNCTION,
    TAG
  }

  private final CallStack extendPathStack;
  private final CallStack importPathStack;
  private final CallStack includePathStack;
  private final CallStack macroStack;
  private final CallStack fromStack;
  private final CallStack currentPathStack;

  private final Set<String> resolvedExpressions = new HashSet<>();
  private final Set<String> resolvedValues = new HashSet<>();
  private final Set<String> resolvedFunctions = new HashSet<>();

  private final ExpTestLibrary expTestLibrary;
  private final FilterLibrary filterLibrary;
  private final FunctionLibrary functionLibrary;
  private final TagLibrary tagLibrary;

  private final Context parent;

  private int renderDepth = -1;
  private Boolean autoEscape;
  private List<? extends Node> superBlock;

  private final Stack<String> renderStack = new Stack<>();

  private boolean validationMode = false;

  public Context() {
    this(null, null, null);
  }

  public Context(Context parent) {
    this(parent, null, null);
  }

  public Context(Context parent, Map<String, ?> bindings) {
    this(parent, bindings, null);
  }

  public Context(Context parent, Map<String, ?> bindings, Map<Library, Set<String>> disabled) {
    super(parent);
    this.disabled = disabled;

    if (bindings != null) {
      this.putAll(bindings);
    }

    this.parent = parent;

    this.extendPathStack = new CallStack(parent == null ? null : parent.getExtendPathStack(),
                                         ExtendsTagCycleException.class);
    this.importPathStack = new CallStack(parent == null ? null : parent.getImportPathStack(),
                                         ImportTagCycleException.class);
    this.includePathStack = new CallStack(parent == null ? null : parent.getIncludePathStack(),
                                          IncludeTagCycleException.class);
    this.macroStack = new CallStack(parent == null ? null : parent.getMacroStack(), MacroTagCycleException.class);
    this.fromStack = new CallStack(parent == null ? null : parent.getFromStack(),
        FromTagCycleException.class);
    this.currentPathStack = new CallStack(parent == null ? null : parent.getCurrentPathStack(), TagCycleException.class);

    if (disabled == null) {
      disabled = new HashMap<>();
    }

    this.expTestLibrary = new ExpTestLibrary(parent == null, disabled.get(Library.EXP_TEST));
    this.filterLibrary = new FilterLibrary(parent == null, disabled.get(Library.FILTER));
    this.tagLibrary = new TagLibrary(parent == null, disabled.get(Library.TAG));
    this.functionLibrary = new FunctionLibrary(parent == null, disabled.get(Library.FUNCTION));
  }

  public void reset() {
    // clear anything that pushes up to its parent's values
    resolvedExpressions.clear();
    resolvedValues.clear();
    resolvedFunctions.clear();
    dependencies.clear();
  }

  @Override
  public Context getParent() {
    return parent;
  }

  public Map<String, Object> getSessionBindings() {
    return this.getScope();
  }

  @SuppressWarnings("unchecked")
  public Map<String, MacroFunction> getGlobalMacros() {
    Map<String, MacroFunction> macros = (Map<String, MacroFunction>) getScope().get(GLOBAL_MACROS_SCOPE_KEY);

    if (macros == null) {
      macros = new HashMap<>();
      getScope().put(GLOBAL_MACROS_SCOPE_KEY, macros);
    }
<commit_msg>Create a new one instead of clear.<commit_after>/**********************************************************************
 * Copyright (c) 2014 HubSpot Inc.
 *
 * 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.
 **********************************************************************/

package com.hubspot.jinjava.interpret;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
import java.util.stream.Collectors;

import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.SetMultimap;
import com.hubspot.jinjava.lib.Importable;
import com.hubspot.jinjava.lib.exptest.ExpTest;
import com.hubspot.jinjava.lib.exptest.ExpTestLibrary;
import com.hubspot.jinjava.lib.filter.Filter;
import com.hubspot.jinjava.lib.filter.FilterLibrary;
import com.hubspot.jinjava.lib.fn.ELFunctionDefinition;
import com.hubspot.jinjava.lib.fn.FunctionLibrary;
import com.hubspot.jinjava.lib.fn.MacroFunction;
import com.hubspot.jinjava.lib.tag.Tag;
import com.hubspot.jinjava.lib.tag.TagLibrary;
import com.hubspot.jinjava.tree.Node;
import com.hubspot.jinjava.util.ScopeMap;

public class Context extends ScopeMap<String, Object> {
  public static final String GLOBAL_MACROS_SCOPE_KEY = "__macros__";
  public static final String IMPORT_RESOURCE_PATH_KEY = "import_resource_path";

  private SetMultimap<String, String> dependencies = HashMultimap.create();
  private Map<Library, Set<String>> disabled;

  public boolean isValidationMode() {
    return validationMode;
  }

  public Context setValidationMode(boolean validationMode) {
    this.validationMode = validationMode;
    return this;
  }

  public enum Library {
    EXP_TEST,
    FILTER,
    FUNCTION,
    TAG
  }

  private final CallStack extendPathStack;
  private final CallStack importPathStack;
  private final CallStack includePathStack;
  private final CallStack macroStack;
  private final CallStack fromStack;
  private final CallStack currentPathStack;

  private final Set<String> resolvedExpressions = new HashSet<>();
  private final Set<String> resolvedValues = new HashSet<>();
  private final Set<String> resolvedFunctions = new HashSet<>();

  private final ExpTestLibrary expTestLibrary;
  private final FilterLibrary filterLibrary;
  private final FunctionLibrary functionLibrary;
  private final TagLibrary tagLibrary;

  private final Context parent;

  private int renderDepth = -1;
  private Boolean autoEscape;
  private List<? extends Node> superBlock;

  private final Stack<String> renderStack = new Stack<>();

  private boolean validationMode = false;

  public Context() {
    this(null, null, null);
  }

  public Context(Context parent) {
    this(parent, null, null);
  }

  public Context(Context parent, Map<String, ?> bindings) {
    this(parent, bindings, null);
  }

  public Context(Context parent, Map<String, ?> bindings, Map<Library, Set<String>> disabled) {
    super(parent);
    this.disabled = disabled;

    if (bindings != null) {
      this.putAll(bindings);
    }

    this.parent = parent;

    this.extendPathStack = new CallStack(parent == null ? null : parent.getExtendPathStack(),
                                         ExtendsTagCycleException.class);
    this.importPathStack = new CallStack(parent == null ? null : parent.getImportPathStack(),
                                         ImportTagCycleException.class);
    this.includePathStack = new CallStack(parent == null ? null : parent.getIncludePathStack(),
                                          IncludeTagCycleException.class);
    this.macroStack = new CallStack(parent == null ? null : parent.getMacroStack(), MacroTagCycleException.class);
    this.fromStack = new CallStack(parent == null ? null : parent.getFromStack(),
        FromTagCycleException.class);
    this.currentPathStack = new CallStack(parent == null ? null : parent.getCurrentPathStack(), TagCycleException.class);

    if (disabled == null) {
      disabled = new HashMap<>();
    }

    this.expTestLibrary = new ExpTestLibrary(parent == null, disabled.get(Library.EXP_TEST));
    this.filterLibrary = new FilterLibrary(parent == null, disabled.get(Library.FILTER));
    this.tagLibrary = new TagLibrary(parent == null, disabled.get(Library.TAG));
    this.functionLibrary = new FunctionLibrary(parent == null, disabled.get(Library.FUNCTION));
  }

  public void reset() {
    // clear anything that pushes up to its parent's values
    resolvedExpressions.clear();
    resolvedValues.clear();
    resolvedFunctions.clear();
    dependencies = HashMultimap.create();
  }

  @Override
  public Context getParent() {
    return parent;
  }

  public Map<String, Object> getSessionBindings() {
    return this.getScope();
  }

  @SuppressWarnings("unchecked")
  public Map<String, MacroFunction> getGlobalMacros() {
    Map<String, MacroFunction> macros = (Map<String, MacroFunction>) getScope().get(GLOBAL_MACROS_SCOPE_KEY);

    if (macros == null) {
      macros = new HashMap<>();
      getScope().put(GLOBAL_MACROS_SCOPE_KEY, macros);
    }

{'fraction_non_alphanumeric': 0.12216282534396634, 'fraction_numerical': 0.0015774252913855053, 'mean_word_length': 4.138226024313372, 'pattern_counts': {'":': 0, '<': 49, '<?xml version=': 0, '>': 49, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '133966', 'n_tokens_mistral': 3213, 'n_tokens_neox': 3096, 'n_words': 844}