All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.helger.html.jscode.AbstractJSBlock Maven / Gradle / Ivy

The newest version!
/**
 * Copyright (C) 2014-2016 Philip Helger (www.helger.com)
 * philip[at]helger[dot]com
 *
 * 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.helger.html.jscode;

import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.helger.commons.ValueEnforcer;
import com.helger.commons.annotation.CodingStyleguideUnaware;
import com.helger.commons.annotation.Nonempty;
import com.helger.commons.annotation.OverrideOnDemand;
import com.helger.commons.annotation.ReturnsMutableCopy;
import com.helger.commons.annotation.ReturnsMutableObject;
import com.helger.commons.collection.CollectionHelper;
import com.helger.commons.collection.ext.CommonsArrayList;
import com.helger.commons.collection.ext.CommonsHashMap;
import com.helger.commons.collection.ext.ICommonsList;
import com.helger.commons.collection.ext.ICommonsMap;
import com.helger.commons.debug.GlobalDebug;
import com.helger.commons.equals.EqualsHelper;
import com.helger.commons.hashcode.HashCodeGenerator;
import com.helger.commons.lang.ClassHelper;
import com.helger.commons.math.MathHelper;
import com.helger.commons.state.EChange;
import com.helger.commons.string.ToStringGenerator;
import com.helger.html.js.CollectingJSCodeProvider;
import com.helger.html.js.IHasJSCode;
import com.helger.html.js.IHasJSCodeWithSettings;
import com.helger.json.IJson;

/**
 * A JS block. It contains a list of statements and declarations.
 *
 * @author Philip Helger
 */
@CodingStyleguideUnaware
public abstract class AbstractJSBlock implements IJSFunctionContainer
{
  private static final Logger s_aLogger = LoggerFactory.getLogger (AbstractJSBlock.class);

  /**
   * List of the content of this block
   */
  private final ICommonsList  m_aObjs = new CommonsArrayList <> ();

  /**
   * Named map of all declarations
   */
  private final ICommonsMap  m_aDecls = new CommonsHashMap <> ();

  /**
   * Current position. Must be ≥ 0.
   */
  private int m_nPos = 0;

  /**
   * Constructor
   */
  public AbstractJSBlock ()
  {}

  /**
   * Removes a declaration from this package.
   *
   * @param sName
   *        Name to remove
   * @return Never null.
   */
  @Nonnull
  public EChange removeByName (final String sName)
  {
    final IJSDeclaration aDecl = m_aDecls.remove (sName);
    if (aDecl == null)
      return EChange.UNCHANGED;
    m_aObjs.remove (aDecl);
    return EChange.CHANGED;
  }

  @Nonnull
  @ReturnsMutableCopy
  public ICommonsList  declarations ()
  {
    return m_aDecls.copyOfValues ();
  }

  /**
   * Gets a reference to the already created {@link JSDefinedClass}.
   *
   * @param sName
   *        Name to search
   * @return null If the object is not yet created.
   */
  @Nullable
  public IJSDeclaration getDeclaration (@Nullable final String sName)
  {
    return m_aDecls.get (sName);
  }

  /**
   * Checks if a given name is already defined as a class/interface
   *
   * @param sName
   *        Name to search
   * @return true if the passed variable is contained
   */
  public boolean isDeclared (@Nullable final String sName)
  {
    return m_aDecls.containsKey (sName);
  }

  /**
   * @return true if this block is empty and does not contain any
   *         statement.
   */
  public boolean isEmpty ()
  {
    return m_aObjs.isEmpty ();
  }

  @Nonnegative
  public int memberCount ()
  {
    return m_aObjs.size ();
  }

  @Nonnull
  @ReturnsMutableObject ("speed")
  final ICommonsList  directMembers ()
  {
    return m_aObjs;
  }

  @Nonnull
  @ReturnsMutableCopy
  public ICommonsList  members ()
  {
    return m_aObjs.getClone ();
  }

  /**
   * Remove all contents of the block. Sets the position to 0.
   *
   * @return this
   */
  @Nonnull
  public AbstractJSBlock clear ()
  {
    m_aObjs.clear ();
    m_aDecls.clear ();
    m_nPos = 0;
    return this;
  }

  /**
   * Called when a declaration is added
   *
   * @param aDeclaration
   *        The added declaration. Never null.
   */
  @OverrideOnDemand
  protected void onAddDeclaration (@Nonnull final IJSDeclaration aDeclaration)
  {}

  @Nonnull
  public final  T addDeclaration (@Nonnull final T aDeclaration) throws JSNameAlreadyExistsException
  {
    ValueEnforcer.notNull (aDeclaration, "Declaration");

    final String sName = aDeclaration.name ();
    final IJSDeclaration aOldDecl = m_aDecls.get (sName);
    if (aOldDecl != null)
      throw new JSNameAlreadyExistsException (aOldDecl);
    m_aObjs.add (m_nPos, aDeclaration);
    m_aDecls.put (sName, aDeclaration);
    m_nPos++;
    onAddDeclaration (aDeclaration);
    return aDeclaration;
  }

  @Nonnull
  public final  T addStatement (@Nonnull final T aStatement)
  {
    ValueEnforcer.notNull (aStatement, "Statement");

    m_aObjs.add (m_nPos, aStatement);
    m_nPos++;
    return aStatement;
  }

  /**
   * Gets the current position to which new statements will be inserted. For
   * example if the value is 0, newly created instructions will be inserted at
   * the very beginning of the block.
   *
   * @return The current position
   * @see #pos(int)
   */
  @Nonnegative
  public int pos ()
  {
    return m_nPos;
  }

  /**
   * Sets the current position.
   *
   * @param nNewPos
   *        New position to use
   * @return the old value of the current position.
   * @throws IllegalArgumentException
   *         if the new position value is illegal.
   * @see #pos()
   */
  @Nonnegative
  public int pos (@Nonnegative final int nNewPos)
  {
    ValueEnforcer.isBetweenInclusive (nNewPos, "NewPos", 0, m_aObjs.size ());
    final int nOldPos = m_nPos;
    m_nPos = nNewPos;
    return nOldPos;
  }

  /**
   * Sets the current position to the end of the block.
   *
   * @return the old value of the current position.
   * @see #pos()
   */
  @Nonnegative
  public int posEnd ()
  {
    return pos (m_aObjs.size ());
  }

  /**
   * Add a class to this package.
   *
   * @param sName
   *        Name of class to be added to this package
   * @return Newly generated class
   * @exception JSNameAlreadyExistsException
   *            When the specified class/interface was already created.
   */
  @Nonnull
  public JSDefinedClass _class (@Nonnull @Nonempty final String sName) throws JSNameAlreadyExistsException
  {
    final JSDefinedClass aDefinedClass = new JSDefinedClass (sName);
    return addDeclaration (aDefinedClass);
  }

  /**
   * @param aType
   *        The type to be instantiated
   * @return A "new type" invocation object
   */
  @Nonnull
  public JSInvocation _new (@Nonnull final AbstractJSType aType)
  {
    ValueEnforcer.notNull (aType, "Type");

    return aType._new ();
  }

  @Nonnull
  public JSFunction function (@Nonnull final String sName) throws JSNameAlreadyExistsException
  {
    final JSFunction aFunction = new JSFunction (sName);
    return addDeclaration (aFunction);
  }

  /**
   * Adds a local variable declaration to this block
   *
   * @param sName
   *        Name of the variable
   * @return Newly generated {@link JSVar}
   * @throws JSNameAlreadyExistsException
   *         if the name is not unique
   */
  @Nonnull
  public JSVar var (@Nonnull @Nonempty final String sName) throws JSNameAlreadyExistsException
  {
    return var (sName, (IJSExpression) null);
  }

  /**
   * Adds a local variable declaration to this block
   *
   * @param sName
   *        Name of the variable
   * @param bInitValue
   *        Initialization value for this variable.
   * @return Newly generated {@link JSVar}
   * @throws JSNameAlreadyExistsException
   *         if the name is not unique
   */
  @Nonnull
  public JSVar var (@Nonnull @Nonempty final String sName, final boolean bInitValue) throws JSNameAlreadyExistsException
  {
    return var (sName, JSExpr.lit (bInitValue));
  }

  /**
   * Adds a local variable declaration to this block
   *
   * @param sName
   *        Name of the variable
   * @param cInitValue
   *        Initialization value for this variable.
   * @return Newly generated {@link JSVar}
   * @throws JSNameAlreadyExistsException
   *         if the name is not unique
   */
  @Nonnull
  public JSVar var (@Nonnull @Nonempty final String sName, final char cInitValue) throws JSNameAlreadyExistsException
  {
    return var (sName, JSExpr.lit (cInitValue));
  }

  /**
   * Adds a local variable declaration to this block
   *
   * @param sName
   *        Name of the variable
   * @param dInitValue
   *        Initialization value for this variable.
   * @return Newly generated {@link JSVar}
   * @throws JSNameAlreadyExistsException
   *         if the name is not unique
   */
  @Nonnull
  public JSVar var (@Nonnull @Nonempty final String sName, final double dInitValue) throws JSNameAlreadyExistsException
  {
    return var (sName, JSExpr.lit (dInitValue));
  }

  /**
   * Adds a local variable declaration to this block
   *
   * @param sName
   *        Name of the variable
   * @param fInitValue
   *        Initialization value for this variable.
   * @return Newly generated {@link JSVar}
   * @throws JSNameAlreadyExistsException
   *         if the name is not unique
   */
  @Nonnull
  public JSVar var (@Nonnull @Nonempty final String sName, final float fInitValue) throws JSNameAlreadyExistsException
  {
    return var (sName, JSExpr.lit (fInitValue));
  }

  /**
   * Adds a local variable declaration to this block
   *
   * @param sName
   *        Name of the variable
   * @param nInitValue
   *        Initialization value for this variable.
   * @return Newly generated {@link JSVar}
   * @throws JSNameAlreadyExistsException
   *         if the name is not unique
   */
  @Nonnull
  public JSVar var (@Nonnull @Nonempty final String sName, final int nInitValue) throws JSNameAlreadyExistsException
  {
    return var (sName, JSExpr.lit (nInitValue));
  }

  /**
   * Adds a local variable declaration to this block
   *
   * @param sName
   *        Name of the variable
   * @param nInitValue
   *        Initialization value for this variable.
   * @return Newly generated {@link JSVar}
   * @throws JSNameAlreadyExistsException
   *         if the name is not unique
   */
  @Nonnull
  public JSVar var (@Nonnull @Nonempty final String sName, final long nInitValue) throws JSNameAlreadyExistsException
  {
    return var (sName, JSExpr.lit (nInitValue));
  }

  /**
   * Adds a local variable declaration to this block
   *
   * @param sName
   *        Name of the variable
   * @param sInitValue
   *        Initialization value for this variable.
   * @return Newly generated {@link JSVar}
   * @throws JSNameAlreadyExistsException
   *         if the name is not unique
   */
  @Nonnull
  public JSVar var (@Nonnull @Nonempty final String sName,
                    @Nullable final String sInitValue) throws JSNameAlreadyExistsException
  {
    return var (sName, sInitValue == null ? JSExpr.NULL : JSExpr.lit (sInitValue));
  }

  /**
   * Adds a local variable declaration to this block
   *
   * @param sName
   *        Name of the variable
   * @param aInitExpression
   *        Initialization expression for this variable. May be null.
   * @return Newly generated {@link JSVar}
   * @throws JSNameAlreadyExistsException
   *         if the name is not unique
   */
  @Nonnull
  public JSVar var (@Nonnull @Nonempty final String sName,
                    @Nullable final IJSExpression aInitExpression) throws JSNameAlreadyExistsException
  {
    final JSVar aVar = new JSVar (sName, aInitExpression);
    return addDeclaration (aVar);
  }

  @Nonnull
  public JSInvocation invoke (@Nonnull final JSAnonymousFunction aAnonFunction)
  {
    ValueEnforcer.notNull (aAnonFunction, "AnonFunction");

    return addStatement (aAnonFunction.invoke ());
  }

  @Nonnull
  public JSInvocation invoke (@Nonnull final JSFunction aFunction)
  {
    ValueEnforcer.notNull (aFunction, "Function");

    return addStatement (aFunction.invoke ());
  }

  @Nonnull
  public JSInvocation invoke (@Nonnull @Nonempty final String sFunctionName)
  {
    final JSInvocation aInvocation = new JSInvocation (sFunctionName);
    return addStatement (aInvocation);
  }

  @Nonnull
  public JSInvocation invoke (@Nonnull @Nonempty final String sField, @Nonnull @Nonempty final String sMethodName)
  {
    final JSInvocation aInvocation = JSExpr.ref (sField).invoke (sMethodName);
    return addStatement (aInvocation);
  }

  @Nonnull
  public JSInvocation invoke (@Nonnull @Nonempty final String sField, @Nonnull final JSMethod aMethod)
  {
    final JSInvocation aInvocation = JSExpr.ref (sField).invoke (aMethod);
    return addStatement (aInvocation);
  }

  /**
   * Creates an invocation statement and adds it to this block.
   *
   * @param aExpr
   *        JExpression evaluating to the class or object upon which the named
   *        method will be invoked
   * @param sMethod
   *        Name of method to invoke
   * @return Newly generated {@link JSInvocation}
   */
  @Nonnull
  public JSInvocation invoke (@Nullable final IJSExpression aExpr, @Nonnull @Nonempty final String sMethod)
  {
    final JSInvocation aInvocation = new JSInvocation (aExpr, sMethod);
    return addStatement (aInvocation);
  }

  /**
   * Creates an invocation statement and adds it to this block.
   *
   * @param aExpr
   *        JExpression evaluating to the class or object upon which the method
   *        will be invoked
   * @param aMethod
   *        JMethod to invoke
   * @return Newly generated {@link JSInvocation}
   */
  @Nonnull
  public JSInvocation invoke (@Nullable final IJSExpression aExpr, @Nonnull final JSMethod aMethod)
  {
    final JSInvocation aInvocation = new JSInvocation (aExpr, aMethod);
    return addStatement (aInvocation);
  }

  /**
   * Creates a static invocation statement.
   *
   * @param aType
   *        Type to use
   * @param sMethod
   *        Method name to invoke
   * @return Never null.
   */
  @Nonnull
  public JSInvocation staticInvoke (@Nullable final AbstractJSClass aType, @Nonnull final String sMethod)
  {
    final JSInvocation aInvocation = new JSInvocation (aType, sMethod);
    return addStatement (aInvocation);
  }

  /**
   * Creates a static invocation statement.
   *
   * @param aType
   *        Type to use
   * @param aMethod
   *        Method to invoke
   * @return Never null.
   */
  @Nonnull
  public JSInvocation staticInvoke (@Nullable final AbstractJSClass aType, @Nonnull final JSMethod aMethod)
  {
    final JSInvocation aInvocation = new JSInvocation (aType, aMethod);
    return addStatement (aInvocation);
  }

  @Nonnull
  public AbstractJSBlock assign (@Nonnull final IJSAssignmentTarget aLhs, final boolean bValue)
  {
    return assign (aLhs, JSExpr.lit (bValue));
  }

  @Nonnull
  public AbstractJSBlock assign (@Nonnull final IJSAssignmentTarget aLhs, final char cValue)
  {
    return assign (aLhs, JSExpr.lit (cValue));
  }

  @Nonnull
  public AbstractJSBlock assign (@Nonnull final IJSAssignmentTarget aLhs, final double dValue)
  {
    return assign (aLhs, JSExpr.lit (dValue));
  }

  @Nonnull
  public AbstractJSBlock assign (@Nonnull final IJSAssignmentTarget aLhs, final float fValue)
  {
    return assign (aLhs, JSExpr.lit (fValue));
  }

  @Nonnull
  public AbstractJSBlock assign (@Nonnull final IJSAssignmentTarget aLhs, final int nValue)
  {
    return assign (aLhs, JSExpr.lit (nValue));
  }

  @Nonnull
  public AbstractJSBlock assign (@Nonnull final IJSAssignmentTarget aLhs, final long nValue)
  {
    return assign (aLhs, JSExpr.lit (nValue));
  }

  @Nonnull
  public AbstractJSBlock assign (@Nonnull final IJSAssignmentTarget aLhs, @Nonnull final String sValue)
  {
    return assign (aLhs, sValue == null ? JSExpr.NULL : JSExpr.lit (sValue));
  }

  @Nonnull
  public AbstractJSBlock assign (@Nonnull final IJSAssignmentTarget aLhs, @Nullable final IJson aValue)
  {
    return assign (aLhs, aValue == null ? JSExpr.NULL : JSExpr.json (aValue));
  }

  @Nonnull
  public AbstractJSBlock assign (@Nonnull final IJSAssignmentTarget aLhs, @Nonnull final IJSExpression aExpr)
  {
    addStatement (aLhs.assign (aExpr));
    return this;
  }

  @Nonnull
  public AbstractJSBlock assignPlus (@Nonnull final IJSAssignmentTarget aLhs, final char cValue)
  {
    return assignPlus (aLhs, JSExpr.lit (cValue));
  }

  @Nonnull
  public AbstractJSBlock assignPlus (@Nonnull final IJSAssignmentTarget aLhs, final double dValue)
  {
    // No add with 0
    if (EqualsHelper.equals (dValue, 0))
      return this;
    if (dValue < 0)
      return assignMinus (aLhs, JSExpr.lit (MathHelper.abs (dValue)));
    return assignPlus (aLhs, JSExpr.lit (dValue));
  }

  @Nonnull
  public AbstractJSBlock assignPlus (@Nonnull final IJSAssignmentTarget aLhs, final float fValue)
  {
    // No add with 0
    if (EqualsHelper.equals (fValue, 0))
      return this;
    if (fValue < 0)
      return assignMinus (aLhs, JSExpr.lit (MathHelper.abs (fValue)));
    return assignPlus (aLhs, JSExpr.lit (fValue));
  }

  @Nonnull
  public AbstractJSBlock assignPlus (@Nonnull final IJSAssignmentTarget aLhs, final int nValue)
  {
    // No add with 0
    if (EqualsHelper.equals (nValue, 0))
      return this;
    if (nValue < 0)
      return assignMinus (aLhs, JSExpr.lit (MathHelper.abs (nValue)));
    return assignPlus (aLhs, JSExpr.lit (nValue));
  }

  @Nonnull
  public AbstractJSBlock assignPlus (@Nonnull final IJSAssignmentTarget aLhs, final long nValue)
  {
    // No add with 0
    if (EqualsHelper.equals (nValue, 0))
      return this;
    if (nValue < 0)
      return assignMinus (aLhs, JSExpr.lit (MathHelper.abs (nValue)));
    return assignPlus (aLhs, JSExpr.lit (nValue));
  }

  @Nonnull
  public AbstractJSBlock assignPlus (@Nonnull final IJSAssignmentTarget aLhs, @Nonnull final String sValue)
  {
    return assignPlus (aLhs, JSExpr.lit (sValue));
  }

  @Nonnull
  public AbstractJSBlock assignPlus (@Nonnull final IJSAssignmentTarget aLhs, @Nonnull final IJSExpression aExpr)
  {
    addStatement (JSExpr.assignPlus (aLhs, aExpr));
    return this;
  }

  @Nonnull
  public AbstractJSBlock assignMinus (@Nonnull final IJSAssignmentTarget aLhs, final double dValue)
  {
    // No subtract with 0
    if (EqualsHelper.equals (dValue, 0))
      return this;
    return assignMinus (aLhs, JSExpr.lit (dValue));
  }

  @Nonnull
  public AbstractJSBlock assignMinus (@Nonnull final IJSAssignmentTarget aLhs, final float fValue)
  {
    // No subtract with 0
    if (EqualsHelper.equals (fValue, 0))
      return this;
    return assignMinus (aLhs, JSExpr.lit (fValue));
  }

  @Nonnull
  public AbstractJSBlock assignMinus (@Nonnull final IJSAssignmentTarget aLhs, final int nValue)
  {
    // No subtract with 0
    if (EqualsHelper.equals (nValue, 0))
      return this;
    return assignMinus (aLhs, JSExpr.lit (nValue));
  }

  @Nonnull
  public AbstractJSBlock assignMinus (@Nonnull final IJSAssignmentTarget aLhs, final long nValue)
  {
    // No subtract with 0
    if (EqualsHelper.equals (nValue, 0))
      return this;
    return assignMinus (aLhs, JSExpr.lit (nValue));
  }

  @Nonnull
  public AbstractJSBlock assignMinus (@Nonnull final IJSAssignmentTarget aLhs, @Nonnull final IJSExpression aExpr)
  {
    addStatement (JSExpr.assignMinus (aLhs, aExpr));
    return this;
  }

  @Nonnull
  public AbstractJSBlock assignMultiply (@Nonnull final IJSAssignmentTarget aLhs, final double dValue)
  {
    // No multiply with 1
    if (EqualsHelper.equals (dValue, 1))
      return this;
    return assignMultiply (aLhs, JSExpr.lit (dValue));
  }

  @Nonnull
  public AbstractJSBlock assignMultiply (@Nonnull final IJSAssignmentTarget aLhs, final float fValue)
  {
    // No multiply with 1
    if (EqualsHelper.equals (fValue, 1))
      return this;
    return assignMultiply (aLhs, JSExpr.lit (fValue));
  }

  @Nonnull
  public AbstractJSBlock assignMultiply (@Nonnull final IJSAssignmentTarget aLhs, final int nValue)
  {
    // No multiply with 1
    if (EqualsHelper.equals (nValue, 1))
      return this;
    return assignMultiply (aLhs, JSExpr.lit (nValue));
  }

  @Nonnull
  public AbstractJSBlock assignMultiply (@Nonnull final IJSAssignmentTarget aLhs, final long nValue)
  {
    // No multiply with 1
    if (EqualsHelper.equals (nValue, 1))
      return this;
    return assignMultiply (aLhs, JSExpr.lit (nValue));
  }

  @Nonnull
  public AbstractJSBlock assignMultiply (@Nonnull final IJSAssignmentTarget aLhs, @Nonnull final IJSExpression aExpr)
  {
    addStatement (JSExpr.assignMultiply (aLhs, aExpr));
    return this;
  }

  @Nonnull
  public AbstractJSBlock assignDivide (@Nonnull final IJSAssignmentTarget aLhs, final double dValue)
  {
    // No divide by 1
    if (EqualsHelper.equals (dValue, 1))
      return this;
    return assignDivide (aLhs, JSExpr.lit (dValue));
  }

  @Nonnull
  public AbstractJSBlock assignDivide (@Nonnull final IJSAssignmentTarget aLhs, final float fValue)
  {
    // No divide by 1
    if (EqualsHelper.equals (fValue, 1))
      return this;
    return assignDivide (aLhs, JSExpr.lit (fValue));
  }

  @Nonnull
  public AbstractJSBlock assignDivide (@Nonnull final IJSAssignmentTarget aLhs, final int nValue)
  {
    // No divide by 1
    if (EqualsHelper.equals (nValue, 1))
      return this;
    return assignDivide (aLhs, JSExpr.lit (nValue));
  }

  @Nonnull
  public AbstractJSBlock assignDivide (@Nonnull final IJSAssignmentTarget aLhs, final long nValue)
  {
    // No divide by 1
    if (EqualsHelper.equals (nValue, 1))
      return this;
    return assignDivide (aLhs, JSExpr.lit (nValue));
  }

  @Nonnull
  public AbstractJSBlock assignDivide (@Nonnull final IJSAssignmentTarget aLhs, @Nonnull final IJSExpression aExpr)
  {
    addStatement (JSExpr.assignDivide (aLhs, aExpr));
    return this;
  }

  @Nonnull
  public AbstractJSBlock assignModulo (@Nonnull final IJSAssignmentTarget aLhs, final int nValue)
  {
    return assignModulo (aLhs, JSExpr.lit (nValue));
  }

  @Nonnull
  public AbstractJSBlock assignModulo (@Nonnull final IJSAssignmentTarget aLhs, final long nValue)
  {
    return assignModulo (aLhs, JSExpr.lit (nValue));
  }

  @Nonnull
  public AbstractJSBlock assignModulo (@Nonnull final IJSAssignmentTarget aLhs, @Nonnull final IJSExpression aExpr)
  {
    addStatement (JSExpr.assignModulo (aLhs, aExpr));
    return this;
  }

  @Nonnull
  public AbstractJSBlock incrPostfix (@Nonnull final IJSAssignmentTarget aLhs)
  {
    addStatement (new JSIncrPostfix (aLhs));
    return this;
  }

  @Nonnull
  public AbstractJSBlock incrPrefix (@Nonnull final IJSAssignmentTarget aLhs)
  {
    addStatement (new JSIncrPrefix (aLhs));
    return this;
  }

  @Nonnull
  public AbstractJSBlock decrPostfix (@Nonnull final IJSAssignmentTarget aLhs)
  {
    addStatement (new JSDecrPostfix (aLhs));
    return this;
  }

  @Nonnull
  public AbstractJSBlock decrPrefix (@Nonnull final IJSAssignmentTarget aLhs)
  {
    addStatement (new JSDecrPrefix (aLhs));
    return this;
  }

  /**
   * Create a For statement and add it to this block
   *
   * @return Newly generated For statement
   */
  @Nonnull
  public JSForLoop _for ()
  {
    return addStatement (new JSForLoop ());
  }

  @Nonnull
  public JSForIn forIn (@Nonnull final JSVar aVar, @Nonnull final IJSExpression aCollection)
  {
    return addStatement (new JSForIn (aVar, aCollection));
  }

  @Nonnull
  public JSForIn forIn (@Nonnull @Nonempty final String sVarName, @Nonnull final IJSExpression aCollection)
  {
    return addStatement (new JSForIn (sVarName, aCollection));
  }

  /**
   * Create a While statement and add it to this block
   *
   * @param aTest
   *        The while condition to use
   * @return Newly generated While statement
   */
  @Nonnull
  public JSWhileLoop _while (@Nonnull final IJSExpression aTest)
  {
    return addStatement (new JSWhileLoop (aTest));
  }

  /**
   * Create a Do statement and add it to this block
   *
   * @param aTest
   *        Do test
   * @return Newly generated Do statement
   */
  @Nonnull
  public JSDoLoop _do (@Nonnull final IJSExpression aTest)
  {
    return addStatement (new JSDoLoop (aTest));
  }

  /**
   * Create a switch/case statement and add it to this block
   *
   * @param aTest
   *        test expression
   * @return Created switch statement
   */
  @Nonnull
  public JSSwitch _switch (@Nonnull final IJSExpression aTest)
  {
    return addStatement (new JSSwitch (aTest));
  }

  /**
   * Create a Try statement and add it to this block
   *
   * @return Newly generated Try statement
   */
  @Nonnull
  public JSTryBlock _try ()
  {
    return addStatement (new JSTryBlock ());
  }

  /**
   * Insert a delete aExpr; statement
   *
   * @param aExpr
   *        the expression to be deleted. May not be null.
   * @return this
   */
  @Nonnull
  public AbstractJSBlock delete (@Nonnull final IJSExpression aExpr)
  {
    addStatement (new JSDelete (aExpr));
    return this;
  }

  /**
   * Create a throw statement and add it to this block
   *
   * @param aExpr
   *        Throwing expression
   * @return this
   */
  @Nonnull
  public AbstractJSBlock _throw (@Nonnull final IJSExpression aExpr)
  {
    addStatement (new JSThrow (aExpr));
    return this;
  }

  /**
   * @return this
   */
  @Nonnull
  public AbstractJSBlock debugger ()
  {
    addStatement (new JSDebugger ());
    return this;
  }

  /**
   * Create a label, which can be referenced from continue and
   * break statements.
   *
   * @param sName
   *        name
   * @return this
   */
  @Nonnull
  public JSLabel label (@Nonnull @Nonempty final String sName)
  {
    return addStatement (new JSLabel (sName));
  }

  /**
   * Create an If statement and add it to this block
   *
   * @param aTest
   *        {@link IJSExpression} to be tested to determine branching
   * @return Newly generated conditional statement
   */
  @Nonnull
  public JSConditional _if (@Nonnull final IJSExpression aTest)
  {
    return addStatement (new JSConditional (aTest));
  }

  /**
   * Create an If statement and add it to this block
   *
   * @param aTest
   *        {@link IJSExpression} to be tested to determine branching
   * @param aThen
   *        "then" block content. May be null.
   * @return Newly generated conditional statement
   */
  @Nonnull
  public JSConditional _if (@Nonnull final IJSExpression aTest, @Nullable final IHasJSCode aThen)
  {
    return addStatement (new JSConditional (aTest, aThen));
  }

  /**
   * Create an If statement and add it to this block
   *
   * @param aTest
   *        {@link IJSExpression} to be tested to determine branching
   * @param aThen
   *        "then" block content. May be null.
   * @param aElse
   *        "else" block content. May be null.
   * @return Newly generated conditional statement
   */
  @Nonnull
  public JSConditional _if (@Nonnull final IJSExpression aTest,
                            @Nullable final IHasJSCode aThen,
                            @Nullable final IHasJSCode aElse)
  {
    return addStatement (new JSConditional (aTest, aThen, aElse));
  }

  /**
   * Create a return statement and add it to this block
   *
   * @return this
   */
  @Nonnull
  public AbstractJSBlock _return ()
  {
    return _return ((IJSExpression) null);
  }

  @Nonnull
  public AbstractJSBlock _return (final boolean bValue)
  {
    return _return (JSExpr.lit (bValue));
  }

  @Nonnull
  public AbstractJSBlock _return (final char cValue)
  {
    return _return (JSExpr.lit (cValue));
  }

  @Nonnull
  public AbstractJSBlock _return (final double dValue)
  {
    return _return (JSExpr.lit (dValue));
  }

  @Nonnull
  public AbstractJSBlock _return (final float fValue)
  {
    return _return (JSExpr.lit (fValue));
  }

  @Nonnull
  public AbstractJSBlock _return (final int nValue)
  {
    return _return (JSExpr.lit (nValue));
  }

  @Nonnull
  public AbstractJSBlock _return (final long nValue)
  {
    return _return (JSExpr.lit (nValue));
  }

  @Nonnull
  public AbstractJSBlock _return (@Nullable final String sValue)
  {
    return _return (sValue == null ? JSExpr.NULL : JSExpr.lit (sValue));
  }

  @Nonnull
  public AbstractJSBlock _return (@Nullable final IJson aValue)
  {
    return _return (aValue == null ? JSExpr.NULL : JSExpr.json (aValue));
  }

  /**
   * Create a return statement and add it to this block
   *
   * @param aExpr
   *        Expression to return
   * @return this
   */
  @Nonnull
  public AbstractJSBlock _return (@Nullable final IJSExpression aExpr)
  {
    addStatement (new JSReturn (aExpr));
    return this;
  }

  /**
   * Create a sub-block and add it to this block
   *
   * @return The newly created block
   */
  @Nonnull
  public JSBlock block ()
  {
    return addStatement (new JSBlock (false, false));
  }

  @Nonnull
  public AbstractJSBlock comment (@Nonnull final String sComment)
  {
    addStatement (new JSCommentSingleLine (sComment));
    return this;
  }

  @Nonnull
  public AbstractJSBlock add (@Nonnull final IHasJSCode aJSCode)
  {
    if (aJSCode instanceof JSPackage)
    {
      // Avoid nested JSPackage
      for (final IHasJSCode aNestedJSCode : ((JSPackage) aJSCode).members ())
        add (aNestedJSCode);
    }
    else
      if (aJSCode instanceof CollectingJSCodeProvider)
      {
        // Flatten CollectingJSCodeProvider
        for (final IHasJSCode aNestedJSCode : ((CollectingJSCodeProvider) aJSCode).getAll ())
          add (aNestedJSCode);
      }
      else
      {
        if (GlobalDebug.isDebugMode ())
          if (!(aJSCode instanceof IHasJSCodeWithSettings))
            s_aLogger.warn ("Adding unspecified IHasJSCode of type " +
                            aJSCode.getClass ().getName () +
                            " to " +
                            ClassHelper.getClassLocalName (this));

        m_aObjs.add (m_nPos, aJSCode);
        m_nPos++;
      }
    return this;
  }

  @Nonnull
  public AbstractJSBlock add (@Nonnull final IJSStatement aStatement)
  {
    addStatement (aStatement);
    return this;
  }

  @Override
  public boolean equals (final Object o)
  {
    if (o == this)
      return true;
    if (o == null || !getClass ().equals (o.getClass ()))
      return false;
    final AbstractJSBlock rhs = (AbstractJSBlock) o;
    return m_aObjs.equals (rhs.m_aObjs) && m_aDecls.equals (rhs.m_aDecls) && m_nPos == rhs.m_nPos;
  }

  @Override
  public int hashCode ()
  {
    return new HashCodeGenerator (this).append (m_aObjs).append (m_aDecls).append (m_nPos).getHashCode ();
  }

  @Override
  public String toString ()
  {
    return new ToStringGenerator (this).appendIf ("objs", m_aObjs, CollectionHelper::isNotEmpty)
                                       .appendIf ("decls", m_aDecls, CollectionHelper::isNotEmpty)
                                       .append ("pos", m_nPos)
                                       .toString ();
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy