/* -*- coding: utf-8 -*-
 *
 * Copyright 2023 IBM RESEARCH. All Rights Reserved.
 *
 * 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 <qasm/AST/ASTAngleContextControl.h>
#include <qasm/AST/ASTAngleNodeBuilder.h>
#include <qasm/AST/ASTAngleNodeList.h>
#include <qasm/AST/ASTAnnotationContextBuilder.h>
#include <qasm/AST/ASTAnyTypeList.h>
#include <qasm/AST/ASTArgumentNodeBuilder.h>
#include <qasm/AST/ASTArray.h>
#include <qasm/AST/ASTArraySubscript.h>
#include <qasm/AST/ASTBuilder.h>
#include <qasm/AST/ASTCBitNodeMap.h>
#include <qasm/AST/ASTDeclarationBuilder.h>
#include <qasm/AST/ASTDefcalBuilder.h>
#include <qasm/AST/ASTDirectiveStatementNode.h>
#include <qasm/AST/ASTDoWhileStatementBuilder.h>
#include <qasm/AST/ASTExpressionBuilder.h>
#include <qasm/AST/ASTExpressionEvaluator.h>
#include <qasm/AST/ASTExpressionValidator.h>
#include <qasm/AST/ASTForStatementBuilder.h>
#include <qasm/AST/ASTFunctionDefinitionBuilder.h>
#include <qasm/AST/ASTGateControl.h>
#include <qasm/AST/ASTGateNodeBuilder.h>
#include <qasm/AST/ASTGateOpBuilder.h>
#include <qasm/AST/ASTGateQubitParamBuilder.h>
#include <qasm/AST/ASTGateQubitTracker.h>
#include <qasm/AST/ASTIdentifier.h>
#include <qasm/AST/ASTIfConditionalsGraphController.h>
#include <qasm/AST/ASTIfStatementTracker.h>
#include <qasm/AST/ASTKernelBuilder.h>
#include <qasm/AST/ASTLoops.h>
#include <qasm/AST/ASTMangler.h>
#include <qasm/AST/ASTObjectTracker.h>
#include <qasm/AST/ASTOpenQASMVersionTracker.h>
#include <qasm/AST/ASTOperatorPrecedenceController.h>
#include <qasm/AST/ASTParameterBuilder.h>
#include <qasm/AST/ASTPragmaContextBuilder.h>
#include <qasm/AST/ASTProductionFactory.h>
#include <qasm/AST/ASTRedeclarationController.h>
#include <qasm/AST/ASTScopeController.h>
#include <qasm/AST/ASTStringUtils.h>
#include <qasm/AST/ASTSwitchStatementBuilder.h>
#include <qasm/AST/ASTSymbolTable.h>
#include <qasm/AST/ASTTypeDiscovery.h>
#include <qasm/AST/ASTTypeEnums.h>
#include <qasm/AST/ASTUtils.h>
#include <qasm/AST/ASTWhileStatementBuilder.h>
#include <qasm/AST/OpenPulse/ASTOpenPulseCalibration.h>
#include <qasm/AST/OpenPulse/ASTOpenPulseController.h>
#include <qasm/Frontend/QasmDiagnosticEmitter.h>
#include <qasm/Frontend/QasmFeatureTester.h>

#include <cassert>
#include <iomanip>
#include <iostream>
#include <string>

namespace QASM {

ASTProductionFactory ASTProductionFactory::APF;

const std::variant<const ASTIntNode *, const ASTIdentifierNode *>
    ASTProductionFactory::EVX;

using DiagLevel = QASM::QasmDiagnosticEmitter::DiagLevel;

unsigned ASTProductionFactory::GetVariantBits(
    const std::variant<const ASTIntNode *, const ASTIdentifierNode *> &V) {
  switch (V.index()) {
  case 0:
    if (const ASTIntNode *II = std::get<0>(V))
      return ASTUtils::Instance().GetUnsignedValue(II);

    return 0U;
    break;
  case 1:
    if (const ASTIdentifierNode *IId = std::get<1>(V)) {
      ASTScopeController::Instance().CheckIdentifier(IId);
      return ASTUtils::Instance().GetUnsignedValue(IId);
    }

    return 0U;
    break;
  default:
    break;
  }

  return static_cast<unsigned>(~0x0);
}

ASTDeclarationNode *
ASTProductionFactory::ProductionRule_1000(const ASTToken *TK,
                                          const ASTIdentifierNode *QId) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(QId && "Invalid ASTIdentifierNode argument!");

  if (ASTOpenQASMVersionTracker::Instance().GetVersion() >= 3.0) {
    std::stringstream M;
    M << "The 'qreg' type designator is deprecated and may be removed in a "
      << "future release.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(QId), M.str(),
        DiagLevel::Warning);
  }

  if (QId->IsReference()) {
    QId = const_cast<ASTIdentifierNode *>(QId->GetIdentifier());
    assert(QId && "Could not obtain a valid ASTIdentifierNode!");
    assert(!QId->IsReference() &&
           "Identifier is still an Identifier Reference!");

    ASTSymbolTableEntry *QSTE =
        new ASTSymbolTableEntry(QId, QId->GetSymbolType());
    assert(QSTE && "Could not create a valid ASTSymbolTableEntry!");

    const_cast<ASTIdentifierNode *>(QId)->SetSymbolTableEntry(QSTE);
    ASTSymbolTable::Instance().SwapQSTMSymbolTableEntry(QId, QSTE);
  }

  unsigned Bits = QId->GetBits();
  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(QId)) {
    std::stringstream M;
    M << "Declaration " << QId->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(QId), M.str(),
        DiagLevel::Error);
  }

  ASTQubitContainerNode *QBN =
      ASTBuilder::Instance().CreateASTQubitContainerNode(QId, Bits);
  assert(QBN && "Could not create an ASTQRegNode!");

  QBN->SetLocation(TK->GetLocation());
  QBN->Mangle();

  ASTDeclarationNode *DN = new ASTDeclarationNode(QId, QBN, ASTTypeQReg, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *
ASTProductionFactory::ProductionRule_1001(const ASTToken *TK,
                                          const ASTIdentifierNode *Id) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");

  if (ASTOpenQASMVersionTracker::Instance().GetVersion() >= 3.0) {
    std::stringstream M;
    M << "The 'creg' type designator is deprecated and may be removed in a "
      << "future release.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(),
        DiagLevel::Warning);
  }

  unsigned Bits = Id->GetBits();
  if (ASTStringUtils::Instance().IsIndexed(Id->GetName())) {
    Bits = ASTStringUtils::Instance().GetIdentifierIndex(Id->GetName());
    std::string BID =
        ASTStringUtils::Instance().GetIdentifierBase(Id->GetName());
    ASTSymbolTable::Instance().Erase(Id, Id->GetSymbolType());
    ASTSymbolTable::Instance().Erase(BID, Bits, Id->GetSymbolType());
    Id = ASTBuilder::Instance().CreateASTIdentifierNode(BID, Bits,
                                                        ASTTypeBitset);
    assert(Id && "Could not create a valid ASTIdentifierNode!");
  } else {
    Bits = ASTUtils::Instance().AdjustZeroBitWidth(Id, 1U);
    if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(Id, Bits,
                                                            ASTTypeBitset)) {
      std::stringstream M;
      M << "Could not transfer Symbol Table Entry for ASTTypeQubitContainer.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
      return ASTDeclarationNode::DeclarationError(Id, M.str());
    }
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
    std::stringstream M;
    M << "Declaration " << Id->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
  }

  ASTCBitNode *CBN = ASTBuilder::Instance().CreateASTCBitNode(Id, Bits, 0UL);
  assert(CBN && "Could not create a valid ASTCBitNode!");

  CBN->SetLocation(TK->GetLocation());
  CBN->Mangle();
  ASTDeclarationNode *DN =
      new ASTDeclarationNode(Id, CBN, ASTTypeBitset, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *
ASTProductionFactory::ProductionRule_1002(const ASTToken *TK,
                                          const ASTIdentifierNode *Id,
                                          const ASTIntNode *I) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(I && "Invalid ASTIntNode argument!");

  if (ASTOpenQASMVersionTracker::Instance().GetVersion() >= 3.0) {
    std::stringstream M;
    M << "The 'creg' type designator is deprecated and may be removed in a "
      << "future release.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(),
        DiagLevel::Warning);
  }

  unsigned BM = ASTUtils::Instance().GetUnsignedValue(I);
  unsigned Bits = Id->GetBits();

  if (ASTStringUtils::Instance().IsIndexed(Id->GetName())) {
    Bits = ASTStringUtils::Instance().GetIdentifierIndex(Id->GetName());
    std::string BID =
        ASTStringUtils::Instance().GetIdentifierBase(Id->GetName());
    ASTSymbolTable::Instance().Erase(Id, Id->GetSymbolType());
    ASTSymbolTable::Instance().Erase(BID, Bits, Id->GetSymbolType());
    Id = ASTBuilder::Instance().CreateASTIdentifierNode(BID, Bits,
                                                        ASTTypeBitset);
    assert(Id && "Could not create a valid ASTIdentifierNode!");
  } else {
    Bits = ASTUtils::Instance().AdjustZeroBitWidth(Id, 1U);
    if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(Id, Bits,
                                                            ASTTypeBitset)) {
      std::stringstream M;
      M << "Could not transfer Symbol Table Entry for ASTTypeQubitContainer.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
      return ASTDeclarationNode::DeclarationError(Id, M.str());
    }
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
    std::stringstream M;
    M << "Declaration " << Id->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
  }

  ASTCBitNode *CBN = ASTBuilder::Instance().CreateASTCBitNode(Id, Bits, BM);
  assert(CBN && "Could not create a valid ASTCBitNode!");

  CBN->SetLocation(TK->GetLocation());
  CBN->SetConstantFolded();
  CBN->Mangle();

  ASTDeclarationNode *DN =
      new ASTDeclarationNode(Id, CBN, ASTTypeBitset, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *
ASTProductionFactory::ProductionRule_1003(const ASTToken *TK,
                                          const ASTIdentifierNode *Id,
                                          const ASTIntNode *I) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(I && "Invalid ASTIntNode Bit Width argument!");

  if (ASTOpenQASMVersionTracker::Instance().GetVersion() >= 3.0) {
    std::stringstream M;
    M << "The 'creg' type designator is deprecated and may be removed in a "
      << "future release.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(),
        DiagLevel::Warning);
  }

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(I);
  if (ASTIdentifierNode::InvalidBits(Bits)) {
    std::stringstream M;
    M << "Invalid number of bits for ASTBitsetNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(Id, Bits,
                                                          ASTTypeBitset)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeQubitContainer.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
    std::stringstream M;
    M << "Declaration " << Id->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  std::size_t BM = 0UL;
  ASTCBitNode *CBN = ASTBuilder::Instance().CreateASTCBitNode(Id, Bits, BM);
  assert(CBN && "Could not create a valid ASTCBitNode!");

  CBN->SetLocation(TK->GetLocation());
  CBN->SetConstantFolded();
  CBN->Mangle();

  ASTDeclarationNode *DN =
      new ASTDeclarationNode(Id, CBN, ASTTypeBitset, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *ASTProductionFactory::ProductionRule_1004(
    const ASTToken *TK, const ASTIdentifierNode *Id, const ASTIntNode *BI,
    const ASTIntNode *I) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(BI && "Invalid ASTIntNode Bit Width argument!");
  assert(I && "Invalid ASTIntNode Bit Value argument!");

  if (ASTOpenQASMVersionTracker::Instance().GetVersion() >= 3.0) {
    std::stringstream M;
    M << "The 'creg' type designator is deprecated and may be removed in a "
      << "future release.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(),
        DiagLevel::Warning);
  }

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(BI);
  if (ASTIdentifierNode::InvalidBits(Bits)) {
    std::stringstream M;
    M << "Invalid number of bits for ASTBitsetNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(Id, Bits,
                                                          ASTTypeBitset)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeBitset.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
    std::stringstream M;
    M << "Declaration " << Id->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  unsigned BV = ASTUtils::Instance().GetUnsignedValue(I);
  ASTCBitNode *CBN = ASTBuilder::Instance().CreateASTCBitNode(Id, Bits, BV);
  assert(CBN && "Could not create a valid ASTCBitNode!");

  CBN->SetLocation(TK->GetLocation());
  CBN->SetConstantFolded();
  CBN->Mangle();

  ASTDeclarationNode *DN =
      new ASTDeclarationNode(Id, CBN, ASTTypeBitset, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *ASTProductionFactory::ProductionRule_1005(
    const ASTToken *TK, const ASTIdentifierNode *Id, const ASTIntNode *I,
    const std::string &SBM) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(I && "Invalid ASTIntNode Bit Width argument!");

  if (ASTOpenQASMVersionTracker::Instance().GetVersion() >= 3.0) {
    std::stringstream M;
    M << "The 'creg' type designator is deprecated and may be removed in a "
      << "future release.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(),
        DiagLevel::Warning);
  }

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(I);
  if (ASTIdentifierNode::InvalidBits(Bits)) {
    std::stringstream M;
    M << "Invalid number of bits for ASTBitsetNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  std::string SSBM = SBM;
  if (ASTStringUtils::Instance().IsQuoted(SBM))
    SSBM = ASTStringUtils::Instance().Sanitize(SBM);

  if (ASTStringUtils::Instance().IsHex(SSBM)) {
    try {
      uint64_t HXV = std::stoull(SBM, nullptr, 16);
      SSBM = ASTStringUtils::Instance().ToBinary(HXV);
    } catch (const std::invalid_argument &E) {
      std::stringstream M;
      M << "Exception caught during hex conversion: " << E.what() << '.';
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(), M.str(), DiagLevel::Error);
      return ASTDeclarationNode::DeclarationError(Id, M.str());
    } catch (const std::out_of_range &E) {
      std::stringstream M;
      M << "Exception caught during hex conversion: " << E.what() << '.';
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(), M.str(), DiagLevel::Error);
      return ASTDeclarationNode::DeclarationError(Id, M.str());
    } catch (...) {
      std::stringstream M;
      M << "Exception caught during hex conversion.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(), M.str(), DiagLevel::Error);
      return ASTDeclarationNode::DeclarationError(Id, M.str());
    }
  }

  if (!ASTStringUtils::Instance().ValidateBinary(SSBM)) {
    std::stringstream M;
    M << "Invalid string bitmask representation " << SSBM.c_str() << '.';
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(Id, Bits,
                                                          ASTTypeBitset)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeBitset.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
    std::stringstream M;
    M << "Declaration " << Id->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  ASTCBitNode *CBN = ASTBuilder::Instance().CreateASTCBitNode(Id, Bits, SSBM);
  assert(CBN && "Could not create a valid ASTCBitNode!");

  CBN->SetLocation(TK->GetLocation());
  CBN->SetConstantFolded();
  CBN->Mangle();

  ASTDeclarationNode *DN =
      new ASTDeclarationNode(Id, CBN, ASTTypeBitset, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *
ASTProductionFactory::ProductionRule_100(const ASTToken *TK,
                                         const ASTIdentifierNode *DId) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DId && "Invalid ASTIdentifierNode argument!");

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
          DId, ASTBoolNode::BoolBits, ASTTypeBool)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeBool.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(DId)) {
    std::stringstream M;
    M << "Declaration " << DId->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  ASTBoolNode *BN = ASTBuilder::Instance().CreateASTBoolNode(DId, false);
  assert(BN && "Failed to create an ASTBoolNode!");

  BN->SetLocation(TK->GetLocation());
  BN->Mangle();

  ASTDeclarationNode *DN = new ASTDeclarationNode(DId, BN, ASTTypeBool, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *
ASTProductionFactory::ProductionRule_101(const ASTToken *TK,
                                         const ASTIdentifierNode *DId,
                                         const std::string &BSV) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DId && "Invalid ASTIdentifierNode! argument!");

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
          DId, ASTBoolNode::BoolBits, ASTTypeBool)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeBool.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(DId)) {
    std::stringstream M;
    M << "Declaration " << DId->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  if (BSV != "true" && BSV != "false") {
    std::stringstream M;
    M << "Booleans can only be initialized with 'true' or "
      << "'false' string literals.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  ASTBoolNode *BN =
      ASTBuilder::Instance().CreateASTBoolNode(DId, BSV == "true");
  assert(BN && "Failed to create an ASTBoolNode!");

  BN->SetLocation(TK->GetLocation());
  BN->SetConstantFolded();
  BN->Mangle();

  ASTDeclarationNode *DN = new ASTDeclarationNode(DId, BN, ASTTypeBool, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *
ASTProductionFactory::ProductionRule_102(const ASTToken *TK,
                                         const ASTIdentifierNode *DId,
                                         const std::string &ISV) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DId && "Invalid ASTIdentifierNode! argument!");

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
          DId, ASTBoolNode::BoolBits, ASTTypeBool)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeBool.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(DId)) {
    std::stringstream M;
    M << "Declaration " << DId->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  int64_t BI = 0;
  try {
    BI = std::stol(ISV);
  } catch (const std::invalid_argument &E) {
    std::stringstream M;
    M << "Exception caught during string-to-integer conversion: " << E.what()
      << '.';
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  } catch (const std::out_of_range &E) {
    std::stringstream M;
    M << "Exception caught during string-to-integer conversion: " << E.what()
      << '.';
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  } catch (...) {
    std::stringstream M;
    M << "Unknown exception caught during string-to-integer conversion.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  ASTBoolNode *BN = ASTBuilder::Instance().CreateASTBoolNode(DId, BI != 0);
  assert(BN && "Failed to create an ASTBoolNode!");

  BN->SetLocation(TK->GetLocation());
  BN->SetConstantFolded();
  BN->Mangle();

  ASTDeclarationNode *DN = new ASTDeclarationNode(DId, BN, ASTTypeBool, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *
ASTProductionFactory::ProductionRule_103(const ASTToken *TK,
                                         const ASTIdentifierNode *DId,
                                         const ASTBinaryOpNode *BOP) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DId && "Invalid ASTIdentifierNode! argument!");
  assert(BOP && "Invalid BinaryOp Expression argument!");

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
          DId, ASTBoolNode::BoolBits, ASTTypeBool)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeBool.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(DId)) {
    std::stringstream M;
    M << "Declaration " << DId->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  ASTBoolNode *BN = ASTBuilder::Instance().CreateASTBoolNode(DId, BOP);
  assert(BN && "Failed to create an ASTBoolNode!");

  BN->SetLocation(TK->GetLocation());
  BN->Mangle();

  ASTDeclarationNode *DN = new ASTDeclarationNode(DId, BN, ASTTypeBool, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *
ASTProductionFactory::ProductionRule_104(const ASTToken *TK,
                                         const ASTIdentifierNode *DId,
                                         const ASTUnaryOpNode *UOP) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DId && "Invalid ASTIdentifierNode! argument!");
  assert(UOP && "Invalid UnaryOp Expression argument!");

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
          DId, ASTBoolNode::BoolBits, ASTTypeBool)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeBool.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(DId)) {
    std::stringstream M;
    M << "Declaration " << DId->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  ASTBoolNode *BN = ASTBuilder::Instance().CreateASTBoolNode(DId, UOP);
  assert(BN && "Failed to create an ASTBoolNode!");

  BN->SetLocation(TK->GetLocation());
  BN->Mangle();

  ASTDeclarationNode *DN = new ASTDeclarationNode(DId, BN, ASTTypeBool, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *
ASTProductionFactory::ProductionRule_105(const ASTToken *TK,
                                         const ASTIdentifierNode *DId,
                                         const ASTIdentifierNode *Id) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DId && "Invalid ASTIdentifierNode! argument!");
  assert(Id && "Invalid ASTIdentifierNode! argument!");

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
          DId, ASTBoolNode::BoolBits, ASTTypeBool)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeBool.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(DId)) {
    std::stringstream M;
    M << "Declaration " << DId->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  bool BV = false;
  unsigned Index = Id->GetBits();
  ASTType ETy = ASTTypeUndefined;
  ASTSymbolTableEntry *STE = nullptr;

  if (const ASTIdentifierRefNode *IdR =
          dynamic_cast<const ASTIdentifierRefNode *>(Id)) {
    STE = ASTSymbolTable::Instance().Lookup(IdR, IdR->GetBits(),
                                            IdR->GetReferenceType());
    assert(STE && "ASTIdentifierRefNode has no SymbolTable Entry!");

    if (IdR->IsIndexed()) {
      ETy = STE->GetValueType();
      switch (ETy) {
      case ASTTypeInt:
      case ASTTypeMPInteger:
      case ASTTypeBool:
      case ASTTypeFloat:
      case ASTTypeBitset:
        Index = IdR->GetIndex();
        break;
      default: {
        std::stringstream M;
        M << "Impossible ASTBoolNode Initialization from an "
          << PrintTypeEnum(ETy) << ".";
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(), M.str(),
            DiagLevel::Error);
        return ASTDeclarationNode::DeclarationError(Id, M.str());
      } break;
      }
    }
  } else {
    STE = ASTSymbolTable::Instance().Lookup(Id);
    assert(STE && "ASTIdentifierNode has no SymbolTable Entry!");

    ETy = STE->GetValueType();
    switch (ETy) {
    case ASTTypeInt:
    case ASTTypeMPInteger:
    case ASTTypeBool:
    case ASTTypeBitset:
    case ASTTypeIntArray:
    case ASTTypeMPIntegerArray:
    case ASTTypeBoolArray:
    case ASTTypeCBitArray:
    case ASTTypeCBitNArray:
      break;
    default: {
      std::stringstream M;
      M << "Impossible ASTBoolNode Initialization from an "
        << PrintTypeEnum(ETy) << ".";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(), M.str(), DiagLevel::Error);
      return ASTDeclarationNode::DeclarationError(Id, M.str());
    } break;
    }
  }

  if (!STE) {
    std::stringstream M;
    M << "Impossible ASTBoolNode Initialization from an " << PrintTypeEnum(ETy)
      << ".";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  switch (ETy) {
  case ASTTypeInt: {
    ASTIntNode *IN = STE->GetValue()->GetValue<ASTIntNode *>();
    assert(IN && "Invalid Value obtained from the SymbolTable Entry!");
    BV = ASTUtils::Instance().GetBooleanValue(IN);
  } break;
  case ASTTypeFloat: {
    ASTFloatNode *FN = STE->GetValue()->GetValue<ASTFloatNode *>();
    assert(FN && "Invalid Value obtained from the SymbolTable Entry!");
    BV = FN->GetValue() != 0.0f;
  } break;
  case ASTTypeDouble: {
    ASTDoubleNode *DN = STE->GetValue()->GetValue<ASTDoubleNode *>();
    assert(DN && "Invalid Value obtained from the SymbolTable Entry!");
    BV = DN->GetValue() != 0.0;
  } break;
  case ASTTypeMPInteger: {
    ASTMPIntegerNode *MPI = STE->GetValue()->GetValue<ASTMPIntegerNode *>();
    assert(MPI && "Invalid Value obtained from the SymbolTable Entry!");
    BV = ASTUtils::Instance().GetBooleanValue(MPI);
  } break;
  case ASTTypeMPDecimal: {
    ASTMPDecimalNode *MPD = STE->GetValue()->GetValue<ASTMPDecimalNode *>();
    assert(MPD && "Invalid Value obtained from the SymbolTable Entry!");
    BV = !MPD->IsZero();
  } break;
  case ASTTypeAngle: {
    ASTAngleNode *AN = STE->GetValue()->GetValue<ASTAngleNode *>();
    assert(AN && "Invalid Value obtained from the SymbolTable Entry!");
    BV = !AN->IsZero();
  } break;
  case ASTTypeBool: {
    ASTBoolNode *BN = STE->GetValue()->GetValue<ASTBoolNode *>();
    assert(BN && "Invalid Value obtained from the SymbolTable Entry!");
    BV = BN->GetValue();
  } break;
  case ASTTypeBitset: {
    ASTCBitNode *CBN = STE->GetValue()->GetValue<ASTCBitNode *>();
    assert(CBN && "Invalid Value obtained from the SymbolTable Entry!");
    BV = CBN->AsBool();
  } break;
  case ASTTypeIntArray: {
    ASTIntArrayNode *IAN = dynamic_cast<ASTIntArrayNode *>(
        STE->GetValue()->GetValue<ASTArrayNode *>());
    assert(IAN && "Invalid Value obtained from the SymbolTable Entry!");
    IAN->ValidateIndex(Index, Id->GetLocation());
    ASTIntNode *IN = IAN->GetElement(Index);
    assert(IN && "Invalid ASTIntNode obtained from the SymbolTable Entry!");
    BV = ASTUtils::Instance().GetBooleanValue(IN);
  } break;
  case ASTTypeMPIntegerArray: {
    ASTMPIntegerArrayNode *MPIA = dynamic_cast<ASTMPIntegerArrayNode *>(
        STE->GetValue()->GetValue<ASTArrayNode *>());
    assert(MPIA && "Invalid Value obtained from the SymbolTable Entry!");
    MPIA->ValidateIndex(Index, Id->GetLocation());
    ASTMPIntegerNode *MPI = MPIA->GetElement(Index);
    assert(MPI &&
           "Invalid ASTMPIntegerNode obtained from the SymbolTable Entry!");
    BV = ASTUtils::Instance().GetBooleanValue(MPI);
  } break;
  case ASTTypeBoolArray: {
    ASTBoolArrayNode *BAN = dynamic_cast<ASTBoolArrayNode *>(
        STE->GetValue()->GetValue<ASTArrayNode *>());
    assert(BAN && "Invalid Value obtained from the SymbolTable Entry!");
    BAN->ValidateIndex(Index, Id->GetLocation());
    ASTBoolNode *BN = BAN->GetElement(Index);
    assert(BN && "Invalid ASTBoolNode obtained from the SymbolTable Entry!");
    BV = BN->GetValue();
  } break;
  case ASTTypeCBitArray: {
    ASTCBitArrayNode *CBA = dynamic_cast<ASTCBitArrayNode *>(
        STE->GetValue()->GetValue<ASTArrayNode *>());
    assert(CBA && "Invalid Value obtained from the SymbolTable Entry!");
    CBA->ValidateIndex(Index, Id->GetLocation());
    ASTCBitNode *CBN = CBA->GetElement(Index);
    assert(CBN && "Invalid ASTCBitNode obtained from the SymbolTable Entry!");
    BV = CBN->AsBool();
  } break;
  case ASTTypeCBitNArray: {
    ASTCBitNArrayNode *CBNA = dynamic_cast<ASTCBitNArrayNode *>(
        STE->GetValue()->GetValue<ASTArrayNode *>());
    assert(CBNA && "Invalid Value obtained from the SymbolTable Entry!");
    CBNA->ValidateIndex(Index, Id->GetLocation());
    ASTCBitNode *CBN = CBNA->GetElement(Index);
    assert(CBN && "Invalid ASTCBitNode obtained from the SymbolTable Entry!");
    BV = CBN->AsBool();
  } break;
  default: {
    std::stringstream M;
    M << "Impossible ASTBoolNode Initialization from an " << PrintTypeEnum(ETy)
      << ".";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  } break;
  }

  ASTBoolNode *BN = ASTBuilder::Instance().CreateASTBoolNode(DId, BV);
  assert(BN && "Could not create a valid ASTBoolNode!");

  BN->SetLocation(TK->GetLocation());
  BN->Mangle();

  ASTDeclarationNode *DN = new ASTDeclarationNode(DId, BN, ASTTypeBool, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *ASTProductionFactory::ProductionRule_106(
    const ASTToken *TK, const ASTIdentifierNode *DId,
    const ASTFunctionCallStatementNode *FC) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DId && "Invalid ASTIdentifierNode! argument!");
  assert(FC && "Invalid ASTFunctionCallStatementNode argument!");

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
          DId, ASTBoolNode::BoolBits, ASTTypeBool)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeBool.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(DId)) {
    std::stringstream M;
    M << "Declaration " << DId->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  const ASTFunctionCallNode *EN = FC->GetFunctionCall();
  assert(EN && "Could not obtain a valid ASTFunctionCallNode!");

  if (!EN->ReturnsResult()) {
    std::stringstream M;
    M << "Assignment requires a non-void return type.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  ASTBoolNode *BN = ASTBuilder::Instance().CreateASTBoolNode(DId, EN);
  assert(BN && "Could not create a valid ASTBoolNode!");

  BN->SetLocation(TK->GetLocation());
  BN->Mangle();

  ASTDeclarationNode *DN = new ASTDeclarationNode(DId, BN, ASTTypeBool, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *
ASTProductionFactory::ProductionRule_107(const ASTToken *TK,
                                         const ASTIdentifierNode *Id) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");

  unsigned Bits = 1U;
  Id->SetBits(Bits);

  if (ASTStringUtils::Instance().IsIndexed(Id->GetName())) {
    Bits = ASTStringUtils::Instance().GetIdentifierIndex(Id->GetName());
    std::string BID =
        ASTStringUtils::Instance().GetIdentifierBase(Id->GetName());
    ASTSymbolTable::Instance().Erase(Id, Id->GetSymbolType());
    ASTSymbolTable::Instance().Erase(BID, Bits, Id->GetSymbolType());
    Id = ASTBuilder::Instance().CreateASTIdentifierNode(BID, Bits,
                                                        ASTTypeBitset);
    assert(Id && "Could not create a valid ASTIdentifierNode!");
  } else {
    Bits = ASTUtils::Instance().AdjustZeroBitWidth(Id, 1U);
    if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(Id, Bits,
                                                            ASTTypeBitset)) {
      std::stringstream M;
      M << "Could not transfer Symbol Table Entry for ASTTypeBitset.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
      return ASTDeclarationNode::DeclarationError(Id, M.str());
    }
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
    std::stringstream M;
    M << "Declaration " << Id->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  ASTCBitNode *CBN = ASTBuilder::Instance().CreateASTCBitNode(Id, Bits, 0UL);
  assert(CBN && "Could not create an ASTCBitNode!");

  CBN->SetLocation(TK->GetLocation());
  CBN->Mangle();

  ASTSymbolTableEntry *STE =
      ASTSymbolTable::Instance().Lookup(Id, Bits, ASTTypeBitset);
  assert(STE && "CBitNode Identifier has no SymbolTableEntry!");
  assert(STE->HasValue() && "CBitNode SymbolTable Entry has no Value!");

  ASTCBitNodeMap::Instance().Insert(Id, CBN);
  ASTDeclarationNode *DN =
      new ASTDeclarationNode(Id, CBN, ASTTypeBitset, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *
ASTProductionFactory::ProductionRule_108(const ASTToken *TK,
                                         const ASTIdentifierNode *Id,
                                         const std::string &IS) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(!IS.empty() && "Invalid Numeric String Literal argument!");

  unsigned Bits = 1U;
  Id->SetBits(Bits);

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  if (ASTStringUtils::Instance().IsIndexed(Id->GetName())) {
    Bits = ASTStringUtils::Instance().GetIdentifierIndex(Id->GetName());
    std::string BID =
        ASTStringUtils::Instance().GetIdentifierBase(Id->GetName());
    ASTSymbolTable::Instance().Erase(Id, Id->GetSymbolType());
    ASTSymbolTable::Instance().Erase(BID, Bits, Id->GetSymbolType());
    Id = ASTBuilder::Instance().CreateASTIdentifierNode(BID, Bits,
                                                        ASTTypeBitset);
    assert(Id && "Could not create a valid ASTIdentifierNode!");
  } else {
    Bits = ASTUtils::Instance().AdjustZeroBitWidth(Id, 1U);
    if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(Id, Bits,
                                                            ASTTypeBitset)) {
      std::stringstream M;
      M << "Could not transfer Symbol Table Entry for ASTTypeBitset.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
      return ASTDeclarationNode::DeclarationError(Id, M.str());
    }
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
    std::stringstream M;
    M << "Declaration " << Id->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  std::size_t Bitmask = static_cast<std::size_t>(std::stoul(IS));
  Bitmask = !(!Bitmask);

  ASTCBitNode *CBN =
      ASTBuilder::Instance().CreateASTCBitNode(Id, Bits, Bitmask);
  assert(CBN && "Could not create an ASTCBitNode!");

  CBN->SetDeclarationContext(CTX);
  CBN->SetLocation(TK->GetLocation());
  CBN->SetConstantFolded();
  CBN->Mangle();

  assert(CBN->GetDeclarationContext() == Id->GetDeclarationContext() &&
         "Inconsistent DeclarationContext Identifier <-> ASTCBitNode!");

  ASTSymbolTableEntry *STE =
      ASTSymbolTable::Instance().Lookup(Id, Bits, ASTTypeBitset);
  assert(STE && "CBit Identifier has no SymbolTableEntry!");
  assert(STE->HasValue() && "CBitNode SymbolTable Entry has no Value!");

  STE->SetContext(CTX);
  ASTCBitNodeMap::Instance().Insert(Id, CBN);

  ASTDeclarationNode *DN =
      new ASTDeclarationNode(Id, CBN, ASTTypeBitset, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  DN->SetDeclarationContext(CTX);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *
ASTProductionFactory::ProductionRule_109(const ASTToken *TK,
                                         const ASTIdentifierNode *Id,
                                         const std::string &NS) const {
  assert(Id && "Could not create an ASTIdentifierNode!");
  assert(!NS.empty() && "Invalid Numeric String Literal argument!");

  unsigned Bits = 1U;
  Id->SetBits(Bits);

  if (ASTStringUtils::Instance().IsIndexed(Id->GetName())) {
    Bits = ASTStringUtils::Instance().GetIdentifierIndex(Id->GetName());
    std::string BID =
        ASTStringUtils::Instance().GetIdentifierBase(Id->GetName());
    ASTSymbolTable::Instance().Erase(Id, Id->GetSymbolType());
    ASTSymbolTable::Instance().Erase(BID, Bits, Id->GetSymbolType());
    Id = ASTBuilder::Instance().CreateASTIdentifierNode(BID, Bits,
                                                        ASTTypeBitset);
    assert(Id && "Could not create a valid ASTIdentifierNode!");
  } else {
    Bits = ASTUtils::Instance().AdjustZeroBitWidth(Id, 1U);
    if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(Id, Bits,
                                                            ASTTypeBitset)) {
      std::stringstream M;
      M << "Could not transfer Symbol Table Entry for ASTTypeBitset.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
      return ASTDeclarationNode::DeclarationError(Id, M.str());
    }
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
    std::stringstream M;
    M << "Declaration " << Id->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  std::string SNS = ASTStringUtils::Instance().Sanitize(NS);
  ASTCBitNode *CBN = ASTBuilder::Instance().CreateASTCBitNode(Id, Bits, SNS);
  assert(CBN && "Could not create an ASTCBitNode!");

  CBN->SetLocation(TK->GetLocation());
  CBN->SetConstantFolded();
  CBN->Mangle();

  ASTSymbolTableEntry *STE =
      ASTSymbolTable::Instance().Lookup(Id, Bits, ASTTypeBitset);
  assert(STE && "CBit Identifier has no SymbolTableEntry!");
  assert(STE->HasValue() && "CBitNode SymbolTable Entry has no Value!");

  ASTCBitNodeMap::Instance().Insert(Id, CBN);
  ASTDeclarationNode *DN =
      new ASTDeclarationNode(Id, CBN, ASTTypeBitset, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *
ASTProductionFactory::ProductionRule_110(const ASTToken *TK,
                                         const ASTIdentifierNode *Id,
                                         const ASTIdentifierNode *IDV) const {
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(IDV && "Invalid ASTIdentifierNode argument!");

  ASTScopeController::Instance().CheckUndefined(IDV);
  ASTScopeController::Instance().CheckOutOfScope(IDV);

  unsigned Bits = 1U;
  Id->SetBits(Bits);

  if (ASTStringUtils::Instance().IsIndexed(Id->GetName())) {
    Bits = ASTStringUtils::Instance().GetIdentifierIndex(Id->GetName());
    std::string BID =
        ASTStringUtils::Instance().GetIdentifierBase(Id->GetName());
    ASTSymbolTable::Instance().Erase(Id, Id->GetSymbolType());
    ASTSymbolTable::Instance().Erase(BID, Bits, Id->GetSymbolType());
    Id = ASTBuilder::Instance().CreateASTIdentifierNode(BID, Bits,
                                                        ASTTypeBitset);
    assert(Id && "Could not create a valid ASTIdentifierNode!");
  } else {
    Bits = ASTUtils::Instance().AdjustZeroBitWidth(Id, 1U);
    if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(Id, Bits,
                                                            ASTTypeBitset)) {
      std::stringstream M;
      M << "Could not transfer Symbol Table Entry for ASTTypeBitset.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
      return ASTDeclarationNode::DeclarationError(Id, M.str());
    }
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
    std::stringstream M;
    M << "Declaration " << Id->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  ASTSymbolTableEntry *VSTE = ASTSymbolTable::Instance().Lookup(
      IDV, IDV->GetBits(), IDV->GetSymbolType());
  assert(VSTE && "Invalid SymbolTable Entry for ASTIdentifierNode!");

  ASTSymbolTableEntry *ISTE =
      ASTSymbolTable::Instance().Lookup(Id, Bits, ASTTypeBitset);
  assert(ISTE && "Invalid SymbolTable Entry for ASTIdentifierNode!");

  std::size_t BM;
  std::string BMS;
  ASTCBitNode *CBN = nullptr;
  bool FromArray = false;
  bool FromBM = false;
  bool FromBMS = false;
  bool FromBitset = false;

  ASTType VTy = VSTE->GetValueType();

  switch (VTy) {
  case ASTTypeBool: {
    ASTBoolNode *BN = VSTE->GetValue()->GetValue<ASTBoolNode *>();
    assert(BN && "Could not retrieve a valid ASTBoolNode!");
    BM = static_cast<unsigned>(BN->GetValue());
    FromBM = true;
  } break;
  case ASTTypeInt: {
    BM = ASTUtils::Instance().GetUnsignedValue(IDV);
    FromBM = true;
  } break;
  case ASTTypeFloat: {
    ASTFloatNode *FN = VSTE->GetValue()->GetValue<ASTFloatNode *>();
    assert(FN && "Could not retrieve a valid ASTFloatNode!");

    BMS = FN->GetValue() == 0.0f ? "0" : "1";
    FromBMS = true;
  } break;
  case ASTTypeMPInteger: {
    ASTMPIntegerNode *MPI = VSTE->GetValue()->GetValue<ASTMPIntegerNode *>();
    assert(MPI && "Could not retrieve a valid ASTMPIntegerNode!");

    BMS = MPI->GetValue(2);
    FromBMS = true;
  } break;
  case ASTTypeMPDecimal: {
    ASTMPDecimalNode *MPD = VSTE->GetValue()->GetValue<ASTMPDecimalNode *>();
    assert(MPD && "Could not retrieve a valid ASTMPDecimalNode!");

    BMS = MPD->IsZero() ? "0" : "1";
    FromBMS = true;
  } break;
  case ASTTypeAngle: {
    ASTAngleNode *ANG = VSTE->GetValue()->GetValue<ASTAngleNode *>();
    assert(ANG && "Could not retrieve a valid ASTAngleNode!");

    BMS = ANG->IsZero() ? "0" : "1";
    FromBMS = true;
  } break;
  case ASTTypeCBitArray:
  case ASTTypeCBitNArray:
  case ASTTypeIdentifier: {
    const ASTIdentifierRefNode *IdR =
        dynamic_cast<const ASTIdentifierRefNode *>(IDV);
    if (IdR) {
      ASTSymbolTableEntry *STE = ASTSymbolTable::Instance().Lookup(IdR);
      assert(STE && "ASTIdentifierRefNode has no SymbolTable Entry!");

      if (STE->GetValueType() == ASTTypeCBitArray) {
        ASTCBitArrayNode *CRN = dynamic_cast<ASTCBitArrayNode *>(
            STE->GetValue()->GetValue<ASTArrayNode *>());
        assert(CRN && "Could not obtain a valid ASTCBitArrayNode from "
                      "the SymbolTable!");

        auto Index = IdR->GetIndex();
        CRN->ValidateIndex(Index, IdR->GetLocation());
        CBN = CRN->GetElement(Index);
        assert(CBN && "Could not obtain a valid ASTCBitNode from "
                      "the ASTCBitArrayNode!");
        FromArray = true;
        BMS = CBN->AsString();
        FromBMS = true;
      } else if (STE->GetValueType() == ASTTypeCBitNArray) {
        ASTCBitNArrayNode *CRN = dynamic_cast<ASTCBitNArrayNode *>(
            STE->GetValue()->GetValue<ASTArrayNode *>());
        assert(CRN && "Could not obtain a valid ASTCBitNArrayNode from "
                      "the SymbolTable!");

        auto Index = IdR->GetIndex();
        CRN->ValidateIndex(Index, IdR->GetLocation());
        CBN = CRN->GetElement(Index);
        assert(CBN && "Could not obtain a valid ASTCBitNode from "
                      "the ASTCBitNArrayNode!");
        FromArray = true;
        BMS = CBN->AsString();
        FromBMS = true;
      } else if (STE->GetValueType() == ASTTypeBitset) {
        ASTCBitNode *BN = dynamic_cast<ASTCBitNode *>(
            STE->GetValue()->GetValue<ASTCBitNode *>());
        assert(BN && "Could not obtain a valid ASTCBitNode from "
                     "the SymbolTable!");
        FromBitset = true;
        BM = (*BN)[IdR->GetBits()];
      } else {
        std::stringstream M;
        M << "Impossible ASTCBitNode Initialization from an "
          << PrintTypeEnum(VTy) << ".";
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(IDV), M.str(),
            DiagLevel::Error);
        return ASTDeclarationNode::DeclarationError(Id, M.str());
      }
    }
  } break;
  case ASTTypeBitset: {
    ISTE->ResetValue();
    const ASTIdentifierRefNode *IdR =
        dynamic_cast<const ASTIdentifierRefNode *>(IDV);
    if (IdR) {
      ASTSymbolTableEntry *STE = ASTSymbolTable::Instance().Lookup(IdR);
      assert(STE && "ASTIdentifierRefNode has no SymbolTable Entry!");

      const ASTIdentifierNode *RId = IdR->GetIdentifier();
      assert(RId && "Could not obtain a valid ASTIdentifierNode from the "
                    "ASTIdentifierRefNode!");

      CBN = dynamic_cast<ASTCBitNode *>(
          STE->GetValue()->GetValue<ASTCBitNode *>());
      assert(CBN && "Could not obtain a valid ASTCBitNode from "
                    "the SymbolTable!");

      if (IdR->GetBits() >= RId->GetBits()) {
        std::stringstream M;
        M << "Attempt to read past the end of the array!";
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(IDV), M.str(),
            DiagLevel::Error);
        return ASTDeclarationNode::DeclarationError(Id, M.str());
      }

      FromBitset = true;
      BM = Id->GetBits();
      BMS = std::string(BM, CBN->AsString()[IdR->GetBits()]);
    } else {
      ASTSymbolTableEntry *STE = ASTSymbolTable::Instance().Lookup(IDV);
      assert(STE && "ASTIdentifierRefNode has no SymbolTable Entry!");

      CBN = dynamic_cast<ASTCBitNode *>(
          STE->GetValue()->GetValue<ASTCBitNode *>());
      assert(CBN && "Could not obtain a valid ASTCBitNode from "
                    "the SymbolTable!");

      FromBitset = true;
      BM = Id->GetBits();
      BMS = CBN->AsString();
      BMS = BMS.substr(0, std::min(BM, BMS.length()));
    }
  } break;
  default: {
    std::stringstream M;
    M << "Impossible ASTCBitNode Initialization from an " << PrintTypeEnum(VTy)
      << ".";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(IDV), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  } break;
  }

  ASTCBitNode *DCBN = nullptr;

  if (FromBM) {
    DCBN = ASTBuilder::Instance().CreateASTCBitNode(Id, Bits, !(BM == 0));
  } else if (FromBMS || FromArray) {
    BM = std::stoul(BMS);
    DCBN = ASTBuilder::Instance().CreateASTCBitNode(Id, Bits, !(BM == 0));
  } else if (FromBitset) {
    BM = std::stoul(BMS);
    DCBN = ASTBuilder::Instance().CreateASTCBitNode(Id, Bits, !(BM == 0));
  } else {
    std::stringstream M;
    M << "Impossible ASTCBitNode Initialization from an " << PrintTypeEnum(VTy)
      << ".";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(IDV), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  assert(DCBN && "Could not create a valid ASTCBitNode!");

  DCBN->SetLocation(TK->GetLocation());
  DCBN->Mangle();
  ISTE->ResetValue();
  ISTE->SetValue(new ASTValue<>(DCBN, ASTTypeBitset), ASTTypeBitset);
  assert(ISTE->HasValue() && "ASTSymbolTable Entry has no Value!");

  ASTCBitNodeMap::Instance().Insert(Id, DCBN);
  ASTDeclarationNode *DN =
      new ASTDeclarationNode(Id, DCBN, ASTTypeBitset, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *
ASTProductionFactory::ProductionRule_111(const ASTToken *TK,
                                         const ASTIdentifierNode *Id,
                                         const ASTGateQOpNode *GQO) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(GQO && "Invalid ASTGateQOpNode argument!");

  unsigned Bits = 1U;
  Id->SetBits(Bits);

  if (ASTStringUtils::Instance().IsIndexed(Id->GetName())) {
    Bits = ASTStringUtils::Instance().GetIdentifierIndex(Id->GetName());
    std::string BID =
        ASTStringUtils::Instance().GetIdentifierBase(Id->GetName());
    ASTSymbolTable::Instance().Erase(Id, Id->GetSymbolType());
    ASTSymbolTable::Instance().Erase(BID, Bits, Id->GetSymbolType());
    Id = ASTBuilder::Instance().CreateASTIdentifierNode(BID, Bits,
                                                        ASTTypeBitset);
    assert(Id && "Could not create a valid ASTIdentifierNode!");
  } else {
    Bits = ASTUtils::Instance().AdjustZeroBitWidth(Id, 1U);
    if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(Id, Bits,
                                                            ASTTypeBitset)) {
      std::stringstream M;
      M << "Could not transfer Symbol Table Entry for ASTTypeBitset.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
      return ASTDeclarationNode::DeclarationError(Id, M.str());
    }
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
    std::stringstream M;
    M << "Declaration " << Id->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  ASTSymbolTableEntry *STE =
      ASTSymbolTable::Instance().Lookup(Id, Bits, ASTTypeBitset);
  assert(STE && "Bitset Identifier has no SymbolTableEntry!");
  assert(STE->GetValueType() == ASTTypeBitset &&
         "Invalid ASTType for ASTCBitNode SymbolTableEntry!");

  ASTCBitNode *CBN = ASTBuilder::Instance().CreateASTCBitNode(Id, Bits, 1U);
  assert(CBN && "Could not create an ASTCBitNode!");

  CBN->SetLocation(TK->GetLocation());
  CBN->SetGateQOp(GQO);
  CBN->Mangle();

  ASTCBitNodeMap::Instance().Insert(Id, CBN);
  ASTDeclarationNode *DN =
      new ASTDeclarationNode(Id, CBN, ASTTypeBitset, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *ASTProductionFactory::ProductionRule_112(
    const ASTToken *TK, const ASTIdentifierNode *Id,
    const ASTFunctionCallStatementNode *FC) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(FC && "Invalid ASTFunctionCallStatementNode argument!");

  unsigned Bits = 1U;
  Id->SetBits(Bits);

  if (ASTStringUtils::Instance().IsIndexed(Id->GetName())) {
    Bits = ASTStringUtils::Instance().GetIdentifierIndex(Id->GetName());
    std::string BID =
        ASTStringUtils::Instance().GetIdentifierBase(Id->GetName());
    ASTSymbolTable::Instance().Erase(Id, Id->GetSymbolType());
    ASTSymbolTable::Instance().Erase(BID, Bits, Id->GetSymbolType());
    Id = ASTBuilder::Instance().CreateASTIdentifierNode(BID, Bits,
                                                        ASTTypeBitset);
    assert(Id && "Could not create a valid ASTIdentifierNode!");
  } else {
    Bits = ASTUtils::Instance().AdjustZeroBitWidth(Id, 1U);
    if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(Id, Bits,
                                                            ASTTypeBitset)) {
      std::stringstream M;
      M << "Could not transfer Symbol Table Entry for ASTTypeBitset.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
      return ASTDeclarationNode::DeclarationError(Id, M.str());
    }
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
    std::stringstream M;
    M << "Error: Declaration " << Id->GetName() << " already exists";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  ASTSymbolTableEntry *STE =
      ASTSymbolTable::Instance().Lookup(Id, Bits, ASTTypeBitset);
  assert(STE && "Could not obtain a valid SymbolTable Entry!");

  const ASTFunctionCallNode *EN = FC->GetFunctionCall();
  assert(EN && "Could not obtain a valid ASTFunctionCallNode!");

  if (!EN->ReturnsResult()) {
    std::stringstream M;
    M << "Assignment requires a non-void return type.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  unsigned BM = 0U;
  ASTType RTy = EN->GetResult()->GetResultType();

  switch (RTy) {
  case ASTTypeBool:
  case ASTTypeInt:
  case ASTTypeMPInteger:
  case ASTTypeBitset:
    break;
  default: {
    std::stringstream M;
    M << "Impossible initialization of an ASTCBitNode from "
      << "Type " << PrintTypeEnum(RTy) << ".";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  } break;
  }

  ASTCBitNode *CBN = ASTBuilder::Instance().CreateASTCBitNode(Id, Bits, BM);
  assert(CBN && "Could not create a valid ASTCBitNode!");

  ASTBinaryOpNode *BOP = new ASTBinaryOpNode(
      ASTIdentifierNode::BinaryOp.Clone(), CBN, EN, ASTOpTypeAssign);
  assert(BOP && "Could not create a valid ASTBinaryOpNode!");

  CBN->SetBinaryOp(BOP);
  CBN->SetLocation(TK->GetLocation());
  CBN->Mangle();

  ASTDeclarationNode *DN =
      new ASTDeclarationNode(Id, CBN, ASTTypeBitset, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);

  ASTStatementNode *STN = new ASTStatementNode(Id, BOP);
  assert(STN && "Could not create a valid ASTStatementNode!");

  ASTStatementBuilder::Instance().Append(STN);
  return DN;
}

ASTDeclarationNode *ASTProductionFactory::ProductionRule_120(
    const ASTToken *TK, const ASTIdentifierNode *DId, bool Unsigned) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DId && "Invalid ASTIdentifierNode! argument!");

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
          DId, ASTIntNode::IntBits, ASTTypeInt)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeInt.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(DId)) {
    std::stringstream M;
    M << "Declaration " << DId->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  DId->SetBits(ASTIntNode::IntBits);
  ASTIntNode *INT =
      Unsigned ? ASTBuilder::Instance().CreateASTIntNode(DId, uint32_t(0))
               : ASTBuilder::Instance().CreateASTIntNode(DId, int32_t(0));
  assert(INT && "Could not create a valid ASTIntNode!");

  INT->SetLocation(TK->GetLocation());
  INT->Mangle();

  ASTDeclarationNode *DN = new ASTDeclarationNode(DId, INT, ASTTypeInt, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *
ASTProductionFactory::ProductionRule_121(const ASTToken *TK,
                                         const ASTIdentifierNode *DId,
                                         const ASTExpressionNode *EN) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DId && "Invalid ASTIdentifierNode! argument!");
  assert(EN && "Invalid ASTExpressionNode argument!");

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
          DId, ASTIntNode::IntBits, ASTTypeInt)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeInt.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(DId)) {
    std::stringstream M;
    M << "Declaration " << DId->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  bool FromValue = false;
  bool FromExpr = false;
  const ASTCastExpressionNode *CX = nullptr;
  bool ITW = false;
  int32_t ISV;

  ASTType ETy = EN->GetASTType();

  switch (ETy) {
  case ASTTypeInt:
    if (const ASTIntNode *I = dynamic_cast<const ASTIntNode *>(EN)) {
      FromValue = true;
      if (I->IsSigned())
        ISV = I->GetSignedValue();
      else
        ISV = static_cast<int32_t>(I->GetUnsignedValue());
    }
    break;
  case ASTTypeBool:
    if (const ASTBoolNode *B = dynamic_cast<const ASTBoolNode *>(EN)) {
      FromValue = true;
      ISV = static_cast<int32_t>(B->GetValue());
      CX = new ASTCastExpressionNode(B, ASTTypeInt, ASTIntNode::IntBits);
      assert(CX && "Could not create a valid ASTCastExpressionNode!");
    }
    break;
  case ASTTypeFloat:
    if (const ASTFloatNode *F = dynamic_cast<const ASTFloatNode *>(EN)) {
      FromValue = true;
      ISV = static_cast<int32_t>(F->GetValue());
      CX = new ASTCastExpressionNode(F, ASTTypeInt, ASTIntNode::IntBits);
      assert(CX && "Could not create a valid ASTCastExpressionNode!");
    }
    break;
  case ASTTypeDouble:
    if (const ASTDoubleNode *D = dynamic_cast<const ASTDoubleNode *>(EN)) {
      FromValue = true;
      ISV = static_cast<int32_t>(D->GetValue());
      CX = new ASTCastExpressionNode(D, ASTTypeInt, ASTIntNode::IntBits);
      assert(CX && "Could not create a valid ASTCastExpressionNode!");
    }
    break;
  case ASTTypeLongDouble:
    if (const ASTLongDoubleNode *LD =
            dynamic_cast<const ASTLongDoubleNode *>(EN)) {
      FromValue = true;
      ISV = static_cast<int32_t>(LD->GetValue());
    }
    break;
  case ASTTypeMPInteger:
    if (const ASTMPIntegerNode *MPI =
            dynamic_cast<const ASTMPIntegerNode *>(EN)) {
      FromValue = true;
      ISV = MPI->ToSignedInt();
      CX = new ASTCastExpressionNode(MPI, ASTTypeInt, ASTIntNode::IntBits);
      assert(CX && "Could not create a valid ASTCastExpressionNode!");
    }
    break;
  case ASTTypeMPDecimal:
    if (const ASTMPDecimalNode *MPD =
            dynamic_cast<const ASTMPDecimalNode *>(EN)) {
      FromValue = true;
      ISV = static_cast<int32_t>(MPD->ToDouble());
      CX = new ASTCastExpressionNode(MPD, ASTTypeInt, ASTIntNode::IntBits);
      assert(CX && "Could not create a valid ASTCastExpressionNode!");
    }
    break;
  case ASTTypeBinaryOp:
  case ASTTypeUnaryOp:
  case ASTTypeExpression:
  case ASTTypeCast:
    FromExpr = true;
    break;
  case ASTTypeCBitArray:
  case ASTTypeCBitNArray:
  case ASTTypeQubitArray:
  case ASTTypeQubitNArray:
  case ASTTypeAngleArray:
  case ASTTypeBoolArray:
  case ASTTypeMPIntegerArray:
  case ASTTypeMPDecimalArray:
  case ASTTypeLengthArray:
  case ASTTypeDurationArray:
  case ASTTypeFloatArray:
  case ASTTypeIntArray: {
    std::stringstream M;
    M << "An array cannot be assigned to a scalar.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  } break;
  case ASTTypeQubit: {
    std::stringstream M;
    M << "A Qubit cannot be assigned to a scalar.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  } break;
  case ASTTypeBitset:
    if (const ASTCBitNode *CB = dynamic_cast<const ASTCBitNode *>(EN)) {
      FromValue = true;

      if (CB->Size() > 32U) {
        std::stringstream M;
        M << "Bitset size exceeds 32 bits. This will result in truncation.";
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(EN), M.str(),
            DiagLevel::Warning);
      }

      try {
        ISV = static_cast<int32_t>(std::stol(CB->AsString(), nullptr, 2));
      } catch (const std::invalid_argument &E) {
        FromValue = false;
        std::stringstream M;
        M << "Conversion failure from bitset to signed int.";
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(EN), M.str(),
            DiagLevel::ICE);
        return ASTDeclarationNode::DeclarationError(DId, M.str());
      } catch (...) {
        FromValue = false;
        std::stringstream M;
        M << "Run-time exception during conversion from bitset to signed int.";
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(EN), M.str(),
            DiagLevel::ICE);
        return ASTDeclarationNode::DeclarationError(DId, M.str());
      }
    }
    break;
  case ASTTypeIdentifier: {
    const ASTIdentifierNode *IId = EN->GetIdentifier();
    assert(IId && "Could not obtain a valid ASTIdentifierNode!");

    ASTScopeController::Instance().CheckUndefined(IId);
    ASTScopeController::Instance().CheckOutOfScope(IId);

    const ASTIdentifierRefNode *IdR =
        dynamic_cast<const ASTIdentifierRefNode *>(IId);
    if (!IdR) {
      if (ASTTypeCastController::Instance().CanCast(IId->GetSymbolType(),
                                                    ASTTypeInt)) {
        ASTSymbolTableEntry *STE = ASTSymbolTable::Instance().Lookup(IId);
        assert(STE && "ASTIdentifierNode has no SymbolTable Entry!");

        switch (STE->GetValueType()) {
        case ASTTypeBool: {
          if (ASTBoolNode *BN = dynamic_cast<ASTBoolNode *>(
                  STE->GetValue()->GetValue<ASTBoolNode *>())) {
            FromValue = true;
            ISV = BN->GetValue();
            CX = new ASTCastExpressionNode(BN, ASTTypeInt, ASTIntNode::IntBits);
            assert(CX && "Could not create a valid ASTCastExpressionNode!");
          }
        } break;
        case ASTTypeInt: {
          if (ASTIntNode *IN = STE->GetValue()->GetValue<ASTIntNode *>()) {
            FromValue = true;
            ISV = IN->IsSigned() ? IN->GetSignedValue()
                                 : static_cast<int32_t>(IN->GetUnsignedValue());
          }
        } break;
        case ASTTypeFloat: {
          if (ASTFloatNode *FN = STE->GetValue()->GetValue<ASTFloatNode *>()) {
            FromValue = true;
            ISV = static_cast<int32_t>(FN->GetValue());
            CX = new ASTCastExpressionNode(FN, ASTTypeInt, ASTIntNode::IntBits);
            assert(CX && "Could not create a valid ASTCastExpressionNode!");
          }
        } break;
        case ASTTypeDouble: {
          if (ASTDoubleNode *DN =
                  STE->GetValue()->GetValue<ASTDoubleNode *>()) {
            FromValue = true;
            ISV = static_cast<int32_t>(DN->GetValue());
            ITW = true;
            CX = new ASTCastExpressionNode(DN, ASTTypeInt, ASTIntNode::IntBits);
            assert(CX && "Could not create a valid ASTCastExpressionNode!");
          }
        } break;
        case ASTTypeMPInteger: {
          if (ASTMPIntegerNode *MPI =
                  STE->GetValue()->GetValue<ASTMPIntegerNode *>()) {
            FromValue = true;
            ISV = MPI->ToSignedInt();
            CX =
                new ASTCastExpressionNode(MPI, ASTTypeInt, ASTIntNode::IntBits);
            assert(CX && "Could not create a valid ASTCastExpressionNode!");
            if (MPI->GetBits() > ASTIntNode::IntBits)
              ITW = true;
          }
        } break;
        case ASTTypeMPDecimal: {
          if (ASTMPDecimalNode *MPD =
                  STE->GetValue()->GetValue<ASTMPDecimalNode *>()) {
            FromValue = true;
            ISV = static_cast<int32_t>(MPD->ToDouble());
            CX =
                new ASTCastExpressionNode(MPD, ASTTypeInt, ASTIntNode::IntBits);
            assert(CX && "Could not create a valid ASTCastExpressionNode!");
            if (MPD->GetBits() > ASTIntNode::IntBits)
              ITW = true;
          }
        } break;
        case ASTTypeBitset: {
          if (ASTCBitNode *CBN = STE->GetValue()->GetValue<ASTCBitNode *>()) {
            FromValue = true;
            ISV = ASTMathUtils::Instance().BoolVectorToIntegral<int32_t>(
                CBN->AsVector());
            CX =
                new ASTCastExpressionNode(CBN, ASTTypeInt, ASTIntNode::IntBits);
            assert(CX && "Could not create a valid ASTCastExpressionNode!");
            if (CBN->Size() > ASTIntNode::IntBits)
              ITW = true;
          }
        } break;
        case ASTTypeAngle: {
          if (ASTAngleNode *AN = STE->GetValue()->GetValue<ASTAngleNode *>()) {
            FromValue = true;
            ISV = static_cast<int32_t>(AN->AsDouble());
            CX = new ASTCastExpressionNode(AN, ASTTypeInt, ASTIntNode::IntBits);
            assert(CX && "Could not create a valid ASTCastExpressionNode!");
            if (AN->GetBits() > ASTIntNode::IntBits)
              ITW = true;
          }
        } break;
        default: {
          std::stringstream M;
          M << "Impossible ASTIntNode Initialization from an "
            << PrintTypeEnum(ETy) << ".";
          QasmDiagnosticEmitter::Instance().EmitDiagnostic(
              DIAGLineCounter::Instance().GetLocation(IId), M.str(),
              DiagLevel::Error);
        } break;
        }
      } else {
        std::stringstream M;
        M << "Impossible cast from " << PrintTypeEnum(IId->GetSymbolType())
          << " to " << PrintTypeEnum(ASTTypeInt) << '.';
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(DId), M.str(),
            DiagLevel::Error);
        return ASTDeclarationNode::DeclarationError(DId, M.str());
      }
    } else if (ASTTypeCastController::Instance().CanCast(IdR->GetSymbolType(),
                                                         ASTTypeInt)) {
      ASTSymbolTableEntry *STE = ASTSymbolTable::Instance().Lookup(IdR);
      assert(STE && "ASTIdentifierRefNode has no SymbolTable Entry!");

      switch (STE->GetValueType()) {
      case ASTTypeBool: {
        if (ASTBoolNode *BN = dynamic_cast<ASTBoolNode *>(
                STE->GetValue()->GetValue<ASTBoolNode *>())) {
          FromValue = true;
          CX = new ASTCastExpressionNode(BN, ASTTypeInt, ASTIntNode::IntBits);
          assert(CX && "Could not create a valid ASTCastExpressionNode!");
          ISV = BN->GetValue();
        }
      } break;
      case ASTTypeUInt:
      case ASTTypeInt: {
        if (ASTIntNode *IN = STE->GetValue()->GetValue<ASTIntNode *>()) {
          FromValue = true;
          ISV = IN->IsSigned() ? IN->GetSignedValue()
                               : static_cast<int32_t>(IN->GetUnsignedValue());
        }
      } break;
      case ASTTypeFloat: {
        if (ASTFloatNode *FN = STE->GetValue()->GetValue<ASTFloatNode *>()) {
          FromValue = true;
          ISV = static_cast<int32_t>(FN->GetValue());
          CX = new ASTCastExpressionNode(FN, ASTTypeInt, ASTIntNode::IntBits);
          assert(CX && "Could not create a valid ASTCastExpressionNode!");
        }
      } break;
      case ASTTypeDouble: {
        if (ASTDoubleNode *DN = STE->GetValue()->GetValue<ASTDoubleNode *>()) {
          FromValue = true;
          ISV = static_cast<int32_t>(DN->GetValue());
          CX = new ASTCastExpressionNode(DN, ASTTypeInt, ASTIntNode::IntBits);
          assert(CX && "Could not create a valid ASTCastExpressionNode!");
          ITW = true;
        }
      } break;
      case ASTTypeMPUInteger:
      case ASTTypeMPInteger: {
        if (ASTMPIntegerNode *MPI =
                STE->GetValue()->GetValue<ASTMPIntegerNode *>()) {
          FromValue = true;
          ISV = MPI->ToSignedInt();
          CX = new ASTCastExpressionNode(MPI, ASTTypeInt, ASTIntNode::IntBits);
          assert(CX && "Could not create a valid ASTCastExpressionNode!");
          if (MPI->GetBits() > ASTIntNode::IntBits)
            ITW = true;
        }
      } break;
      case ASTTypeMPDecimal: {
        if (ASTMPDecimalNode *MPD =
                STE->GetValue()->GetValue<ASTMPDecimalNode *>()) {
          FromValue = true;
          ISV = static_cast<int32_t>(MPD->ToDouble());
          CX = new ASTCastExpressionNode(MPD, ASTTypeInt, ASTIntNode::IntBits);
          assert(CX && "Could not create a valid ASTCastExpressionNode!");
          if (MPD->GetBits() > ASTIntNode::IntBits)
            ITW = true;
        }
      } break;
      case ASTTypeBitset: {
        if (ASTCBitNode *CBN = STE->GetValue()->GetValue<ASTCBitNode *>()) {
          FromValue = true;
          ISV = ASTMathUtils::Instance().BoolVectorToIntegral<int32_t>(
              CBN->AsVector());
          CX = new ASTCastExpressionNode(CBN, ASTTypeInt, ASTIntNode::IntBits);
          assert(CX && "Could not create a valid ASTCastExpressionNode!");
          if (CBN->Size() > ASTIntNode::IntBits)
            ITW = true;
        }
      } break;
      case ASTTypeAngle: {
        if (ASTAngleNode *AN = STE->GetValue()->GetValue<ASTAngleNode *>()) {
          FromValue = true;
          ISV = static_cast<int32_t>(AN->AsDouble());
          CX = new ASTCastExpressionNode(AN, ASTTypeInt, ASTIntNode::IntBits);
          assert(CX && "Could not create a valid ASTCastExpressionNode!");
          if (AN->GetBits() > ASTIntNode::IntBits)
            ITW = true;
        }
      } break;
      default: {
        std::stringstream M;
        M << "Impossible cast to " << PrintTypeEnum(ASTTypeInt) << " from "
          << PrintTypeEnum(IdR->GetSymbolType()) << '.';
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(IId), M.str(),
            DiagLevel::Error);
        return ASTDeclarationNode::DeclarationError(DId, M.str());
      } break;
      }
    }
  } break;
  default: {
    std::stringstream M;
    M << "Impossible ASTIntNode Initialization from an " << PrintTypeEnum(ETy)
      << ".";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  } break;
  }

  ASTIntNode *IN = nullptr;

  if (ITW) {
    std::stringstream M;
    M << "Assignment may result in truncation.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(),
        DiagLevel::Warning);
  }

  if (FromValue) {
    if (CX) {
      IN = ASTBuilder::Instance().CreateASTIntNode(DId, CX, false);
      assert(IN && "Could not create a valid ASTIntNode!");
      IN->SetValue(ISV);
      IN->SetConstantFolded(true);
    } else {
      IN = ASTBuilder::Instance().CreateASTIntNode(DId, ISV);
      IN->SetConstantFolded(true);
    }
  } else if (FromExpr) {
    if (EN->GetASTType() == ASTTypeCast) {
      CX = dynamic_cast<const ASTCastExpressionNode *>(EN);
      assert(CX && "Could not dynamic_cast to an ASTCastExpressionNode!");
      IN = ASTBuilder::Instance().CreateASTIntNode(DId, CX, false);
    } else {
      IN = ASTBuilder::Instance().CreateASTIntNode(DId, EN, false);
    }

    ASTSymbolTableEntry *STE =
        ASTSymbolTable::Instance().Lookup(DId, ASTIntNode::IntBits, ASTTypeInt);
    assert(STE && "Could not obtain a valid SymbolTable Entry!");

    STE->SetValue(new ASTValue<>(IN, ASTTypeInt), ASTTypeInt);
    assert(STE->HasValue() && "SymbolTable Entry has no Value!");
    const_cast<ASTIdentifierNode *>(DId)->SetSymbolTableEntry(STE);
  } else {
    IN = ASTBuilder::Instance().CreateASTIntNode(DId, EN, false);
    ASTSymbolTableEntry *STE =
        ASTSymbolTable::Instance().Lookup(DId, ASTIntNode::IntBits, ASTTypeInt);
    assert(STE && "Could not obtain a valid SymbolTable Entry!");

    STE->SetValue(new ASTValue<>(IN, ASTTypeInt), ASTTypeInt);
    assert(STE->HasValue() && "SymbolTable Entry has no Value!");

    const_cast<ASTIdentifierNode *>(DId)->SetSymbolTableEntry(STE);
  }

  assert(IN && "Could not create a valid ASTIntNode!");

  IN->SetLocation(TK->GetLocation());
  IN->Mangle();

  ASTDeclarationNode *DN = new ASTDeclarationNode(DId, IN, ASTTypeInt, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *
ASTProductionFactory::ProductionRule_122(const ASTToken *TK,
                                         const ASTIdentifierNode *DId,
                                         const ASTStatementNode *SN) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DId && "Invalid ASTIdentifierNode! argument!");
  assert(SN && "Invalid ASTStatementNode argument!");

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
          DId, ASTIntNode::IntBits, ASTTypeInt)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeInt.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(DId)) {
    std::stringstream M;
    M << "Declaration " << DId->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  ASTIntNode *IN = nullptr;

  const ASTExpressionNode *EN = nullptr;
  if (SN->GetASTType() == ASTTypeFunctionCallStatement) {
    const ASTFunctionCallStatementNode *FSN =
        dynamic_cast<const ASTFunctionCallStatementNode *>(SN);
    assert(FSN && "Could not dynamic_cast to an ASTFunctionCallStatementNode!");
    EN = FSN->GetFunctionCall();
  } else {
    EN = SN->GetExpression();
  }

  assert(EN && "Could not obtain an ASTExpressionNode from the "
               "ASTStatementNode!");

  if (EN->GetASTType() == ASTTypeInt) {
    const ASTIntNode *EI = dynamic_cast<const ASTIntNode *>(EN);
    assert(EI && "Could not dynamic_cast to an ASTIntNode!");

    int32_t V = EI->IsSigned() ? EI->GetSignedValue()
                               : static_cast<int32_t>(EI->GetUnsignedValue());
    IN = ASTBuilder::Instance().CreateASTIntNode(DId, V);
  } else {
    IN = ASTBuilder::Instance().CreateASTIntNode(DId, EN, false);
    assert(IN && "Could not create an ASTIntNode!");
    ASTSymbolTableEntry *STE =
        ASTSymbolTable::Instance().Lookup(DId, ASTIntNode::IntBits, ASTTypeInt);
    assert(STE && "Invalid SymbolTable Entry!");

    STE->ResetValue();
    STE->SetValue(new ASTValue<>(IN, ASTTypeInt), ASTTypeInt);
    const_cast<ASTIdentifierNode *>(DId)->SetSymbolTableEntry(STE);
  }

  assert(IN && "Could not create an ASTIntNode!");

  IN->SetLocation(TK->GetLocation());
  IN->Mangle();

  ASTDeclarationNode *DN = new ASTDeclarationNode(DId, IN, ASTTypeInt, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *
ASTProductionFactory::ProductionRule_170(ASTDeclarationNode *DN) const {
  assert(DN && "Invalid ASTDeclarationNode argument!");

  if (!ASTExpressionValidator::Instance().CanBeConst(DN->GetASTType())) {
    std::stringstream M;
    M << "A Declaration of type " << PrintTypeEnum(DN->GetASTType())
      << " cannot be const.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DN), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(DN->GetIdentifier(), M.str());
  }

  DN->SetConst(true);
  ASTDeclarationBuilder::Instance().ConstAppend(DN);
  return DN;
}

ASTDeclarationNode *
ASTProductionFactory::ProductionRule_200(const ASTToken *TK,
                                         const ASTIdentifierNode *DId,
                                         const ASTIntNode *II) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DId && "Invalid ASTIdentifierNode argument!");
  assert(II && "Invalid ASTIntNode argument!");

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(II);
  assert(!ASTIdentifierNode::InvalidBits(Bits) && "Invalid number of Bits!");

  DId->SetBits(Bits);
  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(DId, Bits,
                                                          ASTTypeBitset)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeBitset.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(DId)) {
    std::stringstream M;
    M << "Declaration " << DId->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  ASTCBitNode *CBN = ASTBuilder::Instance().CreateASTCBitNode(DId, Bits, 0UL);
  assert(CBN && "Could not create an ASTCBitNode!");

  CBN->SetLocation(TK->GetLocation());
  CBN->Mangle();
  ASTCBitNodeMap::Instance().Insert(DId, CBN);

  ASTDeclarationNode *DN =
      new ASTDeclarationNode(DId, CBN, ASTTypeBitset, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *
ASTProductionFactory::ProductionRule_201(const ASTToken *TK,
                                         const ASTIdentifierNode *Id,
                                         const ASTIdentifierNode *IId) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(IId && "Invalid ASTIdentifierNode Index argument!");

  ASTScopeController::Instance().CheckUndefined(IId);
  ASTScopeController::Instance().CheckOutOfScope(IId);

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(IId);
  assert(!ASTIdentifierNode::InvalidBits(Bits) && "Invalid number of Bits!");

  Id->SetBits(Bits);
  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(Id, Bits,
                                                          ASTTypeBitset)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeBitset.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
    std::stringstream M;
    M << "Declaration " << Id->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  ASTCBitNode *CBN = ASTBuilder::Instance().CreateASTCBitNode(Id, Bits, 0UL);
  assert(CBN && "Could not create an ASTCBitNode!");

  CBN->SetLocation(TK->GetLocation());
  CBN->Mangle();
  ASTCBitNodeMap::Instance().Insert(Id, CBN);

  ASTDeclarationNode *DN =
      new ASTDeclarationNode(Id, CBN, ASTTypeBitset, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *ASTProductionFactory::ProductionRule_202(
    const ASTToken *TK, const ASTIdentifierNode *Id, const ASTIntNode *II,
    const ASTExpressionNode *EN) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(II && "Invalid ASTIntNode argument!");
  assert(EN && "Invalid ASTExpressionNode argument!");

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(II);
  assert(!ASTIdentifierNode::InvalidBits(Bits) && "Invalid number of Bits!");

  Id->SetBits(Bits);
  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(Id, Bits,
                                                          ASTTypeBitset)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeBitset.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
    std::stringstream M;
    M << "Declaration " << Id->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  bool FromBitset = false;
  bool FromValue = false;
  bool FromExpr = false;
  bool ITW = false;
  const ASTImplicitConversionNode *ICX = nullptr;
  std::string BMS = "0";

  ASTType ETy = EN->GetASTType();

  switch (ETy) {
  case ASTTypeBool:
    if (const ASTBoolNode *BN = dynamic_cast<const ASTBoolNode *>(EN)) {
      FromValue = true;
      BMS = BN->GetValue() ? "1" : "0";
      ICX = new ASTImplicitConversionNode(BN, ASTTypeBitset, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeInt:
    if (const ASTIntNode *IN = dynamic_cast<const ASTIntNode *>(EN)) {
      FromValue = true;
      if (IN->IsMP() && IN->IsMPInteger()) {
        const ASTMPIntegerNode *MPI = IN->GetMPInteger();
        assert(MPI && "Could not obtain a valid ASTMPIntegerNode!");
        BMS = MPI->GetValue(2);
        ICX = new ASTImplicitConversionNode(MPI, ASTTypeBitset, Bits);
        assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
      } else {
        std::bitset<32> B(ASTUtils::Instance().GetUnsignedValue(IN));
        BMS = B.to_string();
        if (Bits < ASTIntNode::IntBits) {
          ITW = true;
          BMS = BMS.substr(0, Bits);
        }

        ICX = new ASTImplicitConversionNode(IN, ASTTypeBitset, Bits);
        assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
      }
    }
    break;
  case ASTTypeFloat:
    if (const ASTFloatNode *FN = dynamic_cast<const ASTFloatNode *>(EN)) {
      FromValue = true;
      float F = FN->GetValue();
      uint32_t *I = reinterpret_cast<uint32_t *>(&F);
      std::bitset<32> B(*I);
      BMS = B.to_string();
      if (Bits < ASTFloatNode::FloatBits) {
        ITW = true;
        BMS = BMS.substr(0, Bits);
      }

      ICX = new ASTImplicitConversionNode(FN, ASTTypeBitset, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeDouble:
    if (const ASTDoubleNode *DN = dynamic_cast<const ASTDoubleNode *>(EN)) {
      FromValue = true;
      double D = DN->GetValue();
      uint64_t *I = reinterpret_cast<uint64_t *>(&D);
      std::bitset<64> B(*I);
      BMS = B.to_string();
      if (Bits < ASTDoubleNode::DoubleBits) {
        ITW = true;
        BMS = BMS.substr(0, Bits);
      }

      ICX = new ASTImplicitConversionNode(DN, ASTTypeBitset, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeLongDouble:
    if (const ASTLongDoubleNode *LDN =
            dynamic_cast<const ASTLongDoubleNode *>(EN)) {
      FromValue = true;
      long double LD = LDN->GetValue();
      const unsigned char *C = reinterpret_cast<const unsigned char *>(&LD);
      std::stringstream LS;
      for (unsigned I = 0; I < sizeof(LD); ++I)
        LS << std::bitset<CHAR_BIT>(*C++).to_string();

      BMS = LS.str();
      if (Bits < ASTLongDoubleNode::LongDoubleBits) {
        ITW = true;
        BMS = BMS.substr(0, Bits);
      }

      ICX = new ASTImplicitConversionNode(LDN, ASTTypeBitset, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeMPInteger:
    if (const ASTMPIntegerNode *MPI =
            dynamic_cast<const ASTMPIntegerNode *>(EN)) {
      FromValue = true;
      BMS = MPI->GetValue(2);
      if (Bits < MPI->GetBits()) {
        ITW = true;
        BMS = BMS.substr(0, Bits);
      }

      ICX = new ASTImplicitConversionNode(MPI, ASTTypeBitset, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeMPDecimal:
    if (const ASTMPDecimalNode *MPD =
            dynamic_cast<const ASTMPDecimalNode *>(EN)) {
      FromValue = true;
      BMS = MPD->GetValue(2);
      if (Bits < MPD->GetBits()) {
        ITW = true;
        BMS = BMS.substr(0, Bits);
      }

      ICX = new ASTImplicitConversionNode(MPD, ASTTypeBitset, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeBinaryOp:
  case ASTTypeUnaryOp:
  case ASTTypeExpression:
  case ASTTypeImplicitConversion:
    FromExpr = true;
    ICX = new ASTImplicitConversionNode(EN, ASTTypeBitset, Bits);
    assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    break;
  case ASTTypeCast:
    FromExpr = true;
    break;
  case ASTTypeCBitArray:
  case ASTTypeCBitNArray:
  case ASTTypeQubitArray:
  case ASTTypeQubitNArray:
  case ASTTypeAngleArray:
  case ASTTypeBoolArray:
  case ASTTypeMPIntegerArray:
  case ASTTypeMPDecimalArray:
  case ASTTypeMPComplexArray:
  case ASTTypeDurationArray:
  case ASTTypeFloatArray:
  case ASTTypeIntArray: {
    std::stringstream M;
    M << "An array cannot be assigned to a bitset.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  } break;
  case ASTTypeStringLiteral: {
    const ASTStringNode *STN = dynamic_cast<const ASTStringNode *>(EN);
    assert(STN && "Could not dynamic_cast to a valid ASTStringNode!");
    BMS = STN->GetValue();
    ICX = new ASTImplicitConversionNode(STN, ASTTypeBitset, Bits);
    assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
  } break;
  case ASTTypeIdentifier: {
    const ASTIdentifierNode *IId = EN->GetIdentifier();
    assert(IId && "Could not obtain an unindexed ASTIdentifierNode!");

    ASTScopeController::Instance().CheckUndefined(IId);
    ASTScopeController::Instance().CheckOutOfScope(IId);

    const ASTIdentifierRefNode *IdR =
        dynamic_cast<const ASTIdentifierRefNode *>(IId);
    if (!IdR) {
      const ASTSymbolTableEntry *STE = IId->GetSymbolTableEntry();
      assert(STE && "Could not obtain a valid ASTSymbolTableEntry!");
      assert(STE->GetValueType() == IId->GetSymbolType() &&
             "Type mismatch ASTIdentifierNode <-> ASTSymbolTableEntry!");

      switch (IId->GetSymbolType()) {
      case ASTTypeBool: {
        if (ASTBoolNode *BN = STE->GetValue()->GetValue<ASTBoolNode *>()) {
          FromValue = true;
          BMS = BN->GetValue() ? "1" : "0";
          ICX = new ASTImplicitConversionNode(BN, ASTTypeBitset, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeInt: {
        if (ASTIntNode *IN = STE->GetValue()->GetValue<ASTIntNode *>()) {
          FromValue = true;
          std::bitset<32> B(ASTUtils::Instance().GetUnsignedValue(IN));
          BMS = B.to_string();
          if (Bits < ASTIntNode::IntBits) {
            ITW = true;
            BMS = BMS.substr(0, Bits);
          }

          ICX = new ASTImplicitConversionNode(IN, ASTTypeBitset, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeFloat: {
        if (ASTFloatNode *FN = STE->GetValue()->GetValue<ASTFloatNode *>()) {
          FromValue = true;
          float F = FN->GetValue();
          uint32_t *I = reinterpret_cast<uint32_t *>(&F);
          std::bitset<32> B(*I);
          BMS = B.to_string();
          if (Bits < ASTFloatNode::FloatBits) {
            ITW = true;
            BMS = BMS.substr(0, Bits);
          }

          ICX = new ASTImplicitConversionNode(FN, ASTTypeBitset, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeDouble: {
        if (ASTDoubleNode *DN = STE->GetValue()->GetValue<ASTDoubleNode *>()) {
          FromValue = true;
          double D = DN->GetValue();
          uint64_t *I = reinterpret_cast<uint64_t *>(&D);
          std::bitset<64> B(*I);
          BMS = B.to_string();
          if (Bits < ASTDoubleNode::DoubleBits) {
            ITW = true;
            BMS = BMS.substr(0, Bits);
          }

          ICX = new ASTImplicitConversionNode(DN, ASTTypeBitset, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeLongDouble: {
        if (ASTLongDoubleNode *LDN =
                STE->GetValue()->GetValue<ASTLongDoubleNode *>()) {
          FromValue = true;
          long double LD = LDN->GetValue();
          const unsigned char *C = reinterpret_cast<const unsigned char *>(&LD);
          std::stringstream LS;
          for (unsigned I = 0; I < sizeof(LD); ++I)
            LS << std::bitset<CHAR_BIT>(*C++).to_string();

          BMS = LS.str();
          if (Bits < ASTLongDoubleNode::LongDoubleBits) {
            ITW = true;
            BMS = BMS.substr(0, Bits);
          }

          ICX = new ASTImplicitConversionNode(LDN, ASTTypeBitset, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeAngle: {
        if (ASTAngleNode *AN = STE->GetValue()->GetValue<ASTAngleNode *>()) {
          FromValue = true;
          BMS = AN->AsMPDecimal()->GetValue(2);
          if (Bits < AN->GetBits()) {
            ITW = true;
            BMS = BMS.substr(0, Bits);
          }

          ICX = new ASTImplicitConversionNode(AN, ASTTypeBitset, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeMPInteger: {
        if (ASTMPIntegerNode *MPI =
                STE->GetValue()->GetValue<ASTMPIntegerNode *>()) {
          FromValue = true;
          BMS = MPI->GetValue(2);
          if (Bits < MPI->GetBits()) {
            ITW = true;
            BMS = BMS.substr(0, Bits);
          }

          ICX = new ASTImplicitConversionNode(MPI, ASTTypeBitset, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeMPDecimal: {
        if (ASTMPDecimalNode *MPD =
                STE->GetValue()->GetValue<ASTMPDecimalNode *>()) {
          FromValue = true;
          BMS = MPD->GetValue(2);
          if (Bits < MPD->GetBits()) {
            ITW = true;
            BMS = BMS.substr(0, Bits);
          }

          ICX = new ASTImplicitConversionNode(MPD, ASTTypeBitset, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeBitset: {
        if (ASTCBitNode *CB = STE->GetValue()->GetValue<ASTCBitNode *>()) {
          FromBitset = true;
          BMS = CB->AsString();
        }
      } break;
      default: {
      } break;
      }
    } else {
      assert(IdR && "Could not dynamic_cast to an ASTIdentifierNode!");

      const ASTIdentifierNode *LIId = IdR->GetIdentifier();
      assert(LIId && "Could not obtain an unindexed ASTIdentifierNode!");

      ASTScopeController::Instance().CheckUndefined(LIId);
      ASTScopeController::Instance().CheckOutOfScope(LIId);

      if (IdR->IsIndexed()) {
        const ASTSymbolTableEntry *STE = ASTSymbolTable::Instance().Lookup(
            IdR, IdR->GetBits(), IdR->GetReferenceType());
        assert(STE && "ASTIdentifierRefNode has no SymbolTable Entry!");

        switch (STE->GetValueType()) {
        case ASTTypeBool:
          if (ASTBoolNode *BN = STE->GetValue()->GetValue<ASTBoolNode *>()) {
            FromValue = true;
            BMS = BN->GetValue() ? "1" : "0";
            ICX = new ASTImplicitConversionNode(BN, ASTTypeBitset, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
          break;
        case ASTTypeInt:
          if (ASTIntNode *IN = STE->GetValue()->GetValue<ASTIntNode *>()) {
            FromValue = true;
            std::bitset<32> B(ASTUtils::Instance().GetUnsignedValue(IN));
            BMS = B.to_string();
            if (Bits < ASTIntNode::IntBits) {
              ITW = true;
              BMS = BMS.substr(0, Bits);
            }

            ICX = new ASTImplicitConversionNode(IN, ASTTypeBitset, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
          break;
        case ASTTypeFloat:
          if (ASTFloatNode *FN = STE->GetValue()->GetValue<ASTFloatNode *>()) {
            FromValue = true;
            float F = FN->GetValue();
            uint32_t *I = reinterpret_cast<uint32_t *>(&F);
            std::bitset<32> B(*I);
            BMS = B.to_string();
            if (Bits < ASTFloatNode::FloatBits) {
              ITW = true;
              BMS = BMS.substr(0, Bits);
            }

            ICX = new ASTImplicitConversionNode(FN, ASTTypeBitset, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
          break;
        case ASTTypeDouble:
          if (ASTDoubleNode *DN =
                  STE->GetValue()->GetValue<ASTDoubleNode *>()) {
            FromValue = true;
            double D = DN->GetValue();
            uint64_t *I = reinterpret_cast<uint64_t *>(&D);
            std::bitset<64> B(*I);
            BMS = B.to_string();
            if (Bits < ASTDoubleNode::DoubleBits) {
              ITW = true;
              BMS = BMS.substr(0, Bits);
            }

            ICX = new ASTImplicitConversionNode(DN, ASTTypeBitset, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
          break;
        case ASTTypeLongDouble:
          if (ASTLongDoubleNode *LDN =
                  STE->GetValue()->GetValue<ASTLongDoubleNode *>()) {
            FromValue = true;
            long double LD = LDN->GetValue();
            const unsigned char *C =
                reinterpret_cast<const unsigned char *>(&LD);
            std::stringstream LS;
            for (unsigned I = 0; I < sizeof(LD); ++I)
              LS << std::bitset<CHAR_BIT>(*C++).to_string();

            BMS = LS.str();
            if (Bits < ASTLongDoubleNode::LongDoubleBits) {
              ITW = true;
              BMS = BMS.substr(0, Bits);
            }

            ICX = new ASTImplicitConversionNode(LDN, ASTTypeBitset, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
          break;
        case ASTTypeMPInteger:
          if (ASTMPIntegerNode *MPI =
                  STE->GetValue()->GetValue<ASTMPIntegerNode *>()) {
            FromValue = true;
            BMS = MPI->GetValue(2);
            if (Bits < MPI->GetBits()) {
              ITW = true;
              BMS = BMS.substr(0, Bits);
            }

            ICX = new ASTImplicitConversionNode(MPI, ASTTypeBitset, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
          break;
        case ASTTypeMPDecimal:
          if (ASTMPDecimalNode *MPD =
                  STE->GetValue()->GetValue<ASTMPDecimalNode *>()) {
            FromValue = true;
            BMS = MPD->GetValue(2);
            if (Bits < MPD->GetBits()) {
              ITW = true;
              BMS = BMS.substr(0, Bits);
            }

            ICX = new ASTImplicitConversionNode(MPD, ASTTypeBitset, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
          break;
        case ASTTypeAngle:
          if (ASTAngleNode *AN = STE->GetValue()->GetValue<ASTAngleNode *>()) {
            FromValue = true;
            BMS = AN->AsMPDecimal()->GetValue(2);
            if (Bits < AN->GetBits()) {
              ITW = true;
              BMS = BMS.substr(0, Bits);
            }

            ICX = new ASTImplicitConversionNode(AN, ASTTypeBitset, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
          break;
        case ASTTypeBitset:
          if (ASTCBitNode *CB = STE->GetValue()->GetValue<ASTCBitNode *>()) {
            FromBitset = true;
            BMS = CB->AsString();
          }
          break;
        default: {
          std::stringstream M;
          M << "Impossible assignment to an ASTCBitNode from an "
            << PrintTypeEnum(STE->GetValueType()) << '.';
          QasmDiagnosticEmitter::Instance().EmitDiagnostic(
              DIAGLineCounter::Instance().GetLocation(Id), M.str(),
              DiagLevel::Error);
          return ASTDeclarationNode::DeclarationError(Id, M.str());
        } break;
        }
      }
    }
  } break;
  case ASTTypeBitset: {
    if (const ASTCBitNode *CB =
            dynamic_cast<const ASTCBitNode *>(EN->GetExpression())) {
      FromBitset = true;
      BMS = CB->AsString();
    }
  } break;
  default: {
    std::stringstream M;
    M << "Impossible assignment to an ASTCBitNode from an "
      << PrintTypeEnum(ETy) << ".";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  } break;
  }

  ASTCBitNode *DCBN = nullptr;

  if (ITW) {
    std::stringstream M;
    M << "Assignment may result in truncation.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(),
        DiagLevel::Warning);
  }

  if (FromExpr) {
    switch (EN->GetASTType()) {
    case ASTTypeCast: {
      const ASTCastExpressionNode *CX =
          dynamic_cast<const ASTCastExpressionNode *>(EN);
      assert(CX && "Could not dynamic_cast to an ASTCastExpressionNode!");
      DCBN = ASTBuilder::Instance().CreateASTCBitNode(Id, Bits, CX);
    } break;
    case ASTTypeBinaryOp: {
      const ASTBinaryOpNode *BOP = dynamic_cast<const ASTBinaryOpNode *>(EN);
      assert(BOP && "Could not dynamic_cast to an ASTBinaryOpNode!");
      ICX = new ASTImplicitConversionNode(BOP, ASTTypeBitset, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
      DCBN = ASTBuilder::Instance().CreateASTCBitNode(Id, Bits, ICX);
    } break;
    case ASTTypeUnaryOp: {
      const ASTUnaryOpNode *UOP = dynamic_cast<const ASTUnaryOpNode *>(EN);
      assert(UOP && "Could not dynamic_cast to an ASTBinaryOpNode!");
      ICX = new ASTImplicitConversionNode(UOP, ASTTypeBitset, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
      DCBN = ASTBuilder::Instance().CreateASTCBitNode(Id, Bits, ICX);
    } break;
    default: {
      std::stringstream M;
      M << "Impossible cast to an " << PrintTypeEnum(ASTTypeBitset)
        << " from an " << PrintTypeEnum(EN->GetASTType()) << '.';
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(Id), M.str(),
          DiagLevel::Error);
      return ASTDeclarationNode::DeclarationError(Id, M.str());
    } break;
    }
  } else if (EN->GetASTType() == ASTTypeInt) {
    const ASTIntNode *EI = dynamic_cast<const ASTIntNode *>(EN);
    assert(EI && "Could not dynamic_cast to an ASTIntNode!");

    if (EI->IsMP() && EI->IsMPInteger()) {
      const ASTMPIntegerNode *MPI = EI->GetMPInteger();
      assert(MPI && "Could not obtain a valid ASTMPInteger!");

      BMS = MPI->GetValue(2);
      DCBN = ASTBuilder::Instance().CreateASTCBitNode(Id, Bits, BMS);
    } else {
      std::size_t BM = ASTUtils::Instance().GetUnsignedValue(EI);
      DCBN = ASTBuilder::Instance().CreateASTCBitNode(Id, Bits, BM);
    }
  } else if (EN->GetASTType() == ASTTypeMPInteger) {
    const ASTMPIntegerNode *MPI = dynamic_cast<const ASTMPIntegerNode *>(EN);
    assert(MPI && "Could not dynamic_cast to an ASTMPIntegerNode!");

    BMS = MPI->GetValue(2);
    if (Bits < BMS.length()) {
      std::stringstream M;
      M << "Conversion to binary format will result in truncation";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(EN), M.str(),
          DiagLevel::Warning);
    }

    DCBN = ASTBuilder::Instance().CreateASTCBitNode(Id, Bits, BMS);
  } else if (EN->GetASTType() == ASTTypeStringLiteral) {
    const ASTStringNode *STN = dynamic_cast<const ASTStringNode *>(EN);
    assert(STN && "Could not dynamic_cast to a valid ASTStringNode!");

    std::string VS = ASTStringUtils::Instance().Sanitize(STN->GetValue());
    if (VS.length() != Bits && VS.length() != 1U) {
      std::stringstream M;
      M << "Bitset initializer length does not match the bitset width.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(EN), M.str(),
          DiagLevel::Error);
      return ASTDeclarationNode::DeclarationError(Id, M.str());
    }

    DCBN = ASTBuilder::Instance().CreateASTCBitNode(Id, Bits, STN->GetValue());
  } else if (FromBitset || FromValue) {
    DCBN = ASTBuilder::Instance().CreateASTCBitNode(Id, Bits, BMS);
  } else {
    DCBN = ASTBuilder::Instance().CreateASTCBitNode(Id, Bits, 0UL);
  }

  assert(DCBN && "Could not create a valid ASTCBitNode!");

  if (FromValue) {
    DCBN->SetConstantFolded(true);
    if (ICX)
      DCBN->SetImplicitConversion(ICX);
  }

  DCBN->SetLocation(TK->GetLocation());
  DCBN->Mangle();

  ASTCBitNodeMap::Instance().Insert(Id, DCBN);
  ASTDeclarationNode *DN =
      new ASTDeclarationNode(Id, DCBN, ASTTypeBitset, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *ASTProductionFactory::ProductionRule_203(
    const ASTToken *TK, const ASTIdentifierNode *DId, const ASTIntNode *IIX,
    const ASTFunctionCallStatementNode *FC) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DId && "Invalid ASTIdentifierList argument!");
  assert(IIX && "Invalid Index ASTIntNode argument!");
  assert(FC && "Invalid ASTFunctionCallStatementNode argument!");

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(IIX);
  assert(!ASTIdentifierNode::InvalidBits(Bits) &&
         "Invalid number of bitset bits!");

  DId->SetBits(Bits);
  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(DId, Bits,
                                                          ASTTypeBitset)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeBitset.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(DId)) {
    std::stringstream M;
    M << "Declaration " << DId->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  const ASTFunctionCallNode *EN = FC->GetFunctionCall();
  assert(EN && "Could not obtain a valid ASTFunctionCallNode!");

  if (!EN->ReturnsResult()) {
    std::stringstream M;
    M << "Assignment requires a non-void return type.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  const ASTResultNode *RN = EN->GetResult();
  assert(RN && "Could not obtain a valid Function ASTResultNode!");

  ASTType RTy = RN->GetResultType();
  const ASTImplicitConversionNode *ICX = nullptr;

  switch (RTy) {
  case ASTTypeBool:
  case ASTTypeInt:
  case ASTTypeFloat:
  case ASTTypeDouble:
  case ASTTypeLongDouble:
  case ASTTypeMPInteger:
  case ASTTypeMPDecimal:
  case ASTTypeAngle:
  case ASTTypeBitset:
    ICX = new ASTImplicitConversionNode(RN, ASTTypeBitset, Bits);
    assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    break;
  default: {
    std::stringstream M;
    M << "Impossible initialization of an ASTCBitNode from "
      << "Type " << PrintTypeEnum(RTy) << ".";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  } break;
  }

  ASTCBitNode *DCBN = ASTBuilder::Instance().CreateASTCBitNode(DId, Bits, 0UL);
  assert(DCBN && "Could not create a valid ASTCBitNode!");

  ASTBinaryOpNode *BOP = nullptr;
  if (ICX)
    BOP = new ASTBinaryOpNode(ASTIdentifierNode::BinaryOp.Clone(), DCBN, ICX,
                              ASTOpTypeAssign);
  else
    BOP = new ASTBinaryOpNode(ASTIdentifierNode::BinaryOp.Clone(), DCBN, EN,
                              ASTOpTypeAssign);
  assert(BOP && "Could not create a valid ASTBinaryOpNode!");

  BOP->SetLocation(TK->GetLocation());
  DCBN->SetLocation(TK->GetLocation());
  DCBN->SetBinaryOp(BOP);
  DCBN->Mangle();

  ASTCBitNodeMap::Instance().Insert(DId, DCBN);
  ASTDeclarationNode *DN =
      new ASTDeclarationNode(DId, DCBN, ASTTypeBitset, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *ASTProductionFactory::ProductionRule_204(
    const ASTToken *TK, const ASTIdentifierNode *Id,
    const ASTIdentifierNode *IXd, const ASTExpressionNode *EN) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierList argument!");
  assert(IXd && "Invalid ASTIdentifierNode Index argument!");
  assert(EN && "Invalid ASTExpressionNode argument!");

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(IXd);
  assert(!ASTIdentifierNode::InvalidBits(Bits) && "Invalid number of Bits!");

  Id->SetBits(Bits);
  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(Id, Bits,
                                                          ASTTypeBitset)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeBitset.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
    std::stringstream M;
    M << "Declaration " << Id->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  bool FromBitset = false;
  bool FromValue = false;
  bool FromExpr = false;
  bool ITW = false;
  const ASTImplicitConversionNode *ICX = nullptr;
  std::string BMS = "0";

  ASTType ETy = EN->GetASTType();

  switch (ETy) {
  case ASTTypeBool:
    if (const ASTBoolNode *BN = dynamic_cast<const ASTBoolNode *>(EN)) {
      FromValue = true;
      BMS = BN->GetValue() ? "1" : "0";
      ICX = new ASTImplicitConversionNode(BN, ASTTypeBitset, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeInt:
    if (const ASTIntNode *IN = dynamic_cast<const ASTIntNode *>(EN)) {
      FromValue = true;
      std::bitset<32> B(ASTUtils::Instance().GetUnsignedValue(IN));
      BMS = B.to_string();
      if (Bits < ASTIntNode::IntBits) {
        ITW = true;
        BMS = BMS.substr(0, Bits);
      }

      ICX = new ASTImplicitConversionNode(IN, ASTTypeBitset, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeFloat:
    if (const ASTFloatNode *FN = dynamic_cast<const ASTFloatNode *>(EN)) {
      FromValue = true;
      float F = FN->GetValue();
      uint32_t *I = reinterpret_cast<uint32_t *>(&F);
      std::bitset<32> B(*I);
      BMS = B.to_string();
      if (Bits < ASTFloatNode::FloatBits) {
        ITW = true;
        BMS = BMS.substr(0, Bits);
      }

      ICX = new ASTImplicitConversionNode(FN, ASTTypeBitset, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeDouble:
    if (const ASTDoubleNode *DN = dynamic_cast<const ASTDoubleNode *>(EN)) {
      FromValue = true;
      double D = DN->GetValue();
      uint64_t *I = reinterpret_cast<uint64_t *>(&D);
      std::bitset<64> B(*I);
      BMS = B.to_string();
      if (Bits < ASTDoubleNode::DoubleBits) {
        ITW = true;
        BMS = BMS.substr(0, Bits);
      }

      ICX = new ASTImplicitConversionNode(DN, ASTTypeBitset, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeLongDouble:
    if (const ASTLongDoubleNode *LDN =
            dynamic_cast<const ASTLongDoubleNode *>(EN)) {
      FromValue = true;
      long double LD = LDN->GetValue();
      const unsigned char *C = reinterpret_cast<const unsigned char *>(&LD);
      std::stringstream LS;
      for (unsigned I = 0; I < sizeof(LD); ++I)
        LS << std::bitset<CHAR_BIT>(*C++).to_string();

      BMS = LS.str();
      if (Bits < ASTLongDoubleNode::LongDoubleBits) {
        ITW = true;
        BMS = BMS.substr(0, Bits);
      }

      ICX = new ASTImplicitConversionNode(LDN, ASTTypeBitset, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeMPInteger:
    if (const ASTMPIntegerNode *MPI =
            dynamic_cast<const ASTMPIntegerNode *>(EN)) {
      FromValue = true;
      BMS = MPI->GetValue(2);
      if (Bits < MPI->GetBits()) {
        ITW = true;
        BMS = BMS.substr(0, Bits);
      }

      ICX = new ASTImplicitConversionNode(MPI, ASTTypeBitset, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeMPDecimal:
    if (const ASTMPDecimalNode *MPD =
            dynamic_cast<const ASTMPDecimalNode *>(EN)) {
      FromValue = true;
      BMS = MPD->GetValue(2);
      if (Bits < MPD->GetBits()) {
        ITW = true;
        BMS = BMS.substr(0, Bits);
      }

      ICX = new ASTImplicitConversionNode(MPD, ASTTypeBitset, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeBinaryOp:
  case ASTTypeUnaryOp:
  case ASTTypeExpression:
  case ASTTypeImplicitConversion:
    FromExpr = true;
    ICX = new ASTImplicitConversionNode(EN, ASTTypeBitset, Bits);
    assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    break;
  case ASTTypeCast:
    FromExpr = true;
    break;
  case ASTTypeCBitArray:
  case ASTTypeCBitNArray:
  case ASTTypeQubitArray:
  case ASTTypeQubitNArray:
  case ASTTypeAngleArray:
  case ASTTypeBoolArray:
  case ASTTypeMPIntegerArray:
  case ASTTypeMPDecimalArray:
  case ASTTypeMPComplexArray:
  case ASTTypeDurationArray:
  case ASTTypeFloatArray:
  case ASTTypeIntArray: {
    std::stringstream M;
    M << "An array cannot be assigned to a bitset.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  } break;
  case ASTTypeStringLiteral: {
    const ASTStringNode *STN = dynamic_cast<const ASTStringNode *>(EN);
    assert(STN && "Could not dynamic_cast to a valid ASTStringNode!");
    BMS = STN->GetValue();
    ICX = new ASTImplicitConversionNode(STN, ASTTypeBitset, Bits);
    assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
  } break;
  case ASTTypeIdentifier: {
    const ASTIdentifierNode *IId = EN->GetIdentifier();
    assert(IId && "Could not obtain an unindexed ASTIdentifierNode!");

    ASTScopeController::Instance().CheckUndefined(IId);
    ASTScopeController::Instance().CheckOutOfScope(IId);

    const ASTIdentifierRefNode *IdR =
        dynamic_cast<const ASTIdentifierRefNode *>(IId);
    if (!IdR) {
      const ASTSymbolTableEntry *STE = IId->GetSymbolTableEntry();
      assert(STE && "Could not obtain a valid ASTSymbolTableEntry!");
      assert(STE->GetValueType() == IId->GetSymbolType() &&
             "Type mismatch ASTIdentifierNode <-> ASTSymbolTableEntry!");

      switch (IId->GetSymbolType()) {
      case ASTTypeBool: {
        if (ASTBoolNode *BN = STE->GetValue()->GetValue<ASTBoolNode *>()) {
          FromValue = true;
          BMS = BN->GetValue() ? "1" : "0";
          ICX = new ASTImplicitConversionNode(BN, ASTTypeBitset, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeInt: {
        if (ASTIntNode *IN = STE->GetValue()->GetValue<ASTIntNode *>()) {
          FromValue = true;
          std::bitset<32> B(ASTUtils::Instance().GetUnsignedValue(IN));
          BMS = B.to_string();
          if (Bits < ASTIntNode::IntBits) {
            ITW = true;
            BMS = BMS.substr(0, Bits);
          }

          ICX = new ASTImplicitConversionNode(IN, ASTTypeBitset, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeFloat: {
        if (ASTFloatNode *FN = STE->GetValue()->GetValue<ASTFloatNode *>()) {
          FromValue = true;
          float F = FN->GetValue();
          uint32_t *I = reinterpret_cast<uint32_t *>(&F);
          std::bitset<32> B(*I);
          BMS = B.to_string();
          if (Bits < ASTFloatNode::FloatBits) {
            ITW = true;
            BMS = BMS.substr(0, Bits);
          }

          ICX = new ASTImplicitConversionNode(FN, ASTTypeBitset, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeDouble: {
        if (ASTDoubleNode *DN = STE->GetValue()->GetValue<ASTDoubleNode *>()) {
          FromValue = true;
          double D = DN->GetValue();
          uint64_t *I = reinterpret_cast<uint64_t *>(&D);
          std::bitset<64> B(*I);
          BMS = B.to_string();
          if (Bits < ASTDoubleNode::DoubleBits) {
            ITW = true;
            BMS = BMS.substr(0, Bits);
          }

          ICX = new ASTImplicitConversionNode(DN, ASTTypeBitset, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeLongDouble: {
        if (ASTLongDoubleNode *LDN =
                STE->GetValue()->GetValue<ASTLongDoubleNode *>()) {
          FromValue = true;
          long double LD = LDN->GetValue();
          const unsigned char *C = reinterpret_cast<const unsigned char *>(&LD);
          std::stringstream LS;
          for (unsigned I = 0; I < sizeof(LD); ++I)
            LS << std::bitset<CHAR_BIT>(*C++).to_string();

          BMS = LS.str();
          if (Bits < ASTLongDoubleNode::LongDoubleBits) {
            ITW = true;
            BMS = BMS.substr(0, Bits);
          }

          ICX = new ASTImplicitConversionNode(LDN, ASTTypeBitset, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeAngle: {
        if (ASTAngleNode *AN = STE->GetValue()->GetValue<ASTAngleNode *>()) {
          FromValue = true;
          BMS = AN->AsMPDecimal()->GetValue(2);
          if (Bits < AN->GetBits()) {
            ITW = true;
            BMS = BMS.substr(0, Bits);
          }

          ICX = new ASTImplicitConversionNode(AN, ASTTypeBitset, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeMPInteger: {
        if (ASTMPIntegerNode *MPI =
                STE->GetValue()->GetValue<ASTMPIntegerNode *>()) {
          FromValue = true;
          BMS = MPI->GetValue(2);
          if (Bits < MPI->GetBits()) {
            ITW = true;
            BMS = BMS.substr(0, Bits);
          }

          ICX = new ASTImplicitConversionNode(MPI, ASTTypeBitset, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeMPDecimal: {
        if (ASTMPDecimalNode *MPD =
                STE->GetValue()->GetValue<ASTMPDecimalNode *>()) {
          FromValue = true;
          BMS = MPD->GetValue(2);
          if (Bits < MPD->GetBits()) {
            ITW = true;
            BMS = BMS.substr(0, Bits);
          }

          ICX = new ASTImplicitConversionNode(MPD, ASTTypeBitset, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeBitset: {
        if (ASTCBitNode *CB = STE->GetValue()->GetValue<ASTCBitNode *>()) {
          FromBitset = true;
          BMS = CB->AsString();
        }
      } break;
      default: {
      } break;
      }
    } else {
      assert(IdR && "Could not dynamic_cast to an ASTIdentifierNode!");

      const ASTIdentifierNode *LIId = IdR->GetIdentifier();
      assert(LIId && "Could not obtain an unindexed ASTIdentifierNode!");

      ASTScopeController::Instance().CheckUndefined(LIId);
      ASTScopeController::Instance().CheckOutOfScope(LIId);

      if (IdR->IsIndexed()) {
        const ASTSymbolTableEntry *STE = ASTSymbolTable::Instance().Lookup(
            IdR, IdR->GetBits(), IdR->GetReferenceType());
        assert(STE && "ASTIdentifierRefNode has no SymbolTable Entry!");

        switch (STE->GetValueType()) {
        case ASTTypeBool:
          if (ASTBoolNode *BN = STE->GetValue()->GetValue<ASTBoolNode *>()) {
            FromValue = true;
            BMS = BN->GetValue() ? "1" : "0";
            ICX = new ASTImplicitConversionNode(BN, ASTTypeBitset, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
          break;
        case ASTTypeInt:
          if (ASTIntNode *IN = STE->GetValue()->GetValue<ASTIntNode *>()) {
            FromValue = true;
            std::bitset<32> B(ASTUtils::Instance().GetUnsignedValue(IN));
            BMS = B.to_string();
            if (Bits < ASTIntNode::IntBits) {
              ITW = true;
              BMS = BMS.substr(0, Bits);
            }

            ICX = new ASTImplicitConversionNode(IN, ASTTypeBitset, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
          break;
        case ASTTypeFloat:
          if (ASTFloatNode *FN = STE->GetValue()->GetValue<ASTFloatNode *>()) {
            FromValue = true;
            float F = FN->GetValue();
            uint32_t *I = reinterpret_cast<uint32_t *>(&F);
            std::bitset<32> B(*I);
            BMS = B.to_string();
            if (Bits < ASTFloatNode::FloatBits) {
              ITW = true;
              BMS = BMS.substr(0, Bits);
            }

            ICX = new ASTImplicitConversionNode(FN, ASTTypeBitset, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
          break;
        case ASTTypeDouble:
          if (ASTDoubleNode *DN =
                  STE->GetValue()->GetValue<ASTDoubleNode *>()) {
            FromValue = true;
            double D = DN->GetValue();
            uint64_t *I = reinterpret_cast<uint64_t *>(&D);
            std::bitset<64> B(*I);
            BMS = B.to_string();
            if (Bits < ASTDoubleNode::DoubleBits) {
              ITW = true;
              BMS = BMS.substr(0, Bits);
            }

            ICX = new ASTImplicitConversionNode(DN, ASTTypeBitset, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
          break;
        case ASTTypeLongDouble:
          if (ASTLongDoubleNode *LDN =
                  STE->GetValue()->GetValue<ASTLongDoubleNode *>()) {
            FromValue = true;
            long double LD = LDN->GetValue();
            const unsigned char *C =
                reinterpret_cast<const unsigned char *>(&LD);
            std::stringstream LS;
            for (unsigned I = 0; I < sizeof(LD); ++I)
              LS << std::bitset<CHAR_BIT>(*C++).to_string();

            BMS = LS.str();
            if (Bits < ASTLongDoubleNode::LongDoubleBits) {
              ITW = true;
              BMS = BMS.substr(0, Bits);
            }

            ICX = new ASTImplicitConversionNode(LDN, ASTTypeBitset, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
          break;
        case ASTTypeMPInteger:
          if (ASTMPIntegerNode *MPI =
                  STE->GetValue()->GetValue<ASTMPIntegerNode *>()) {
            FromValue = true;
            BMS = MPI->GetValue(2);
            if (Bits < MPI->GetBits()) {
              ITW = true;
              BMS = BMS.substr(0, Bits);
            }

            ICX = new ASTImplicitConversionNode(MPI, ASTTypeBitset, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
          break;
        case ASTTypeMPDecimal:
          if (ASTMPDecimalNode *MPD =
                  STE->GetValue()->GetValue<ASTMPDecimalNode *>()) {
            FromValue = true;
            BMS = MPD->GetValue(2);
            if (Bits < MPD->GetBits()) {
              ITW = true;
              BMS = BMS.substr(0, Bits);
            }

            ICX = new ASTImplicitConversionNode(MPD, ASTTypeBitset, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
          break;
        case ASTTypeAngle:
          if (ASTAngleNode *AN = STE->GetValue()->GetValue<ASTAngleNode *>()) {
            FromValue = true;
            BMS = AN->AsMPDecimal()->GetValue(2);
            if (Bits < AN->GetBits()) {
              ITW = true;
              BMS = BMS.substr(0, Bits);
            }

            ICX = new ASTImplicitConversionNode(AN, ASTTypeBitset, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
          break;
        case ASTTypeBitset:
          if (ASTCBitNode *CB = STE->GetValue()->GetValue<ASTCBitNode *>()) {
            FromBitset = true;
            BMS = CB->AsString();
          }
          break;
        default: {
          std::stringstream M;
          M << "Impossible assignment to an ASTCBitNode from an "
            << PrintTypeEnum(STE->GetValueType()) << '.';
          QasmDiagnosticEmitter::Instance().EmitDiagnostic(
              DIAGLineCounter::Instance().GetLocation(Id), M.str(),
              DiagLevel::Error);
          return ASTDeclarationNode::DeclarationError(Id, M.str());
        } break;
        }
      }
    }
  } break;
  case ASTTypeBitset: {
    if (const ASTCBitNode *CB =
            dynamic_cast<const ASTCBitNode *>(EN->GetExpression())) {
      FromBitset = true;
      BMS = CB->AsString();
    }
  } break;
  default: {
    std::stringstream M;
    M << "Impossible assignment to an ASTCBitNode from an "
      << PrintTypeEnum(ETy) << ".";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  } break;
  }

  ASTCBitNode *DCBN = nullptr;

  if (ITW) {
    std::stringstream M;
    M << "Assignment may result in truncation.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(),
        DiagLevel::Warning);
  }

  if (FromExpr) {
    switch (EN->GetASTType()) {
    case ASTTypeCast: {
      const ASTCastExpressionNode *CX =
          dynamic_cast<const ASTCastExpressionNode *>(EN);
      assert(CX && "Could not dynamic_cast to an ASTCastExpressionNode!");
      DCBN = ASTBuilder::Instance().CreateASTCBitNode(Id, Bits, CX);
    } break;
    case ASTTypeBinaryOp: {
      const ASTBinaryOpNode *BOP = dynamic_cast<const ASTBinaryOpNode *>(EN);
      assert(BOP && "Could not dynamic_cast to an ASTBinaryOpNode!");
      ICX = new ASTImplicitConversionNode(BOP, ASTTypeBitset, Bits);
      assert(ICX && "Could not create a valid ASTImpicitConversionNode!");
      DCBN = ASTBuilder::Instance().CreateASTCBitNode(Id, Bits, ICX);
    } break;
    case ASTTypeUnaryOp: {
      const ASTUnaryOpNode *UOP = dynamic_cast<const ASTUnaryOpNode *>(EN);
      assert(UOP && "Could not dynamic_cast to an ASTBinaryOpNode!");
      ICX = new ASTImplicitConversionNode(UOP, ASTTypeBitset, Bits);
      assert(ICX && "Could not create a valid ASTImpicitConversionNode!");
      DCBN = ASTBuilder::Instance().CreateASTCBitNode(Id, Bits, ICX);
    } break;
    default: {
      std::stringstream M;
      M << "Impossible cast to an " << PrintTypeEnum(ASTTypeBitset)
        << " from an " << PrintTypeEnum(EN->GetASTType()) << '.';
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(Id), M.str(),
          DiagLevel::Error);
      return ASTDeclarationNode::DeclarationError(Id, M.str());
    } break;
    }
  } else if (EN->GetASTType() == ASTTypeInt) {
    const ASTIntNode *EI = dynamic_cast<const ASTIntNode *>(EN);
    assert(EI && "Could not dynamic_cast to an ASTIntNode!");

    std::size_t BM = ASTUtils::Instance().GetUnsignedValue(EI);
    DCBN = ASTBuilder::Instance().CreateASTCBitNode(Id, Bits, BM);
  } else if (EN->GetASTType() == ASTTypeMPInteger) {
    const ASTMPIntegerNode *MPI = dynamic_cast<const ASTMPIntegerNode *>(EN);
    assert(MPI && "Could not dynamic_cast to an ASTMPIntegerNode!");

    BMS = MPI->GetValue(2);
    if (Bits < BMS.length()) {
      std::stringstream M;
      M << "Conversion to binary format will result in truncation";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(Id), M.str(),
          DiagLevel::Warning);
    }

    DCBN = ASTBuilder::Instance().CreateASTCBitNode(Id, Bits, BMS);
  } else if (EN->GetASTType() == ASTTypeStringLiteral) {
    const ASTStringNode *STN = dynamic_cast<const ASTStringNode *>(EN);
    assert(STN && "Could not dynamic_cast to a valid ASTStringNode!");

    DCBN = ASTBuilder::Instance().CreateASTCBitNode(Id, Bits, STN->GetValue());
  } else if (FromBitset || FromValue) {
    DCBN = ASTBuilder::Instance().CreateASTCBitNode(Id, Bits, BMS);
  } else {
    DCBN = ASTBuilder::Instance().CreateASTCBitNode(Id, Bits, 0UL);
  }

  assert(DCBN && "Could not create a valid ASTCBitNode!");

  if (FromValue) {
    DCBN->SetConstantFolded(true);
    if (ICX)
      DCBN->SetImplicitConversion(ICX);
  }

  DCBN->SetLocation(TK->GetLocation());
  DCBN->Mangle();

  ASTCBitNodeMap::Instance().Insert(Id, DCBN);
  ASTDeclarationNode *DN =
      new ASTDeclarationNode(Id, DCBN, ASTTypeBitset, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *ASTProductionFactory::ProductionRule_205(
    const ASTToken *TK, const ASTIdentifierNode *DId,
    const ASTIdentifierNode *IXd,
    const ASTFunctionCallStatementNode *FC) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DId && "Invalid ASTIdentifierNode argument!");
  assert(IXd && "Invalid ASTIdentifierNode Index argument!");
  assert(FC && "Invalid ASTFunctionCallStatementNode argument!");

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(IXd);
  assert(!ASTIdentifierNode::InvalidBits(Bits) && "Invalid number of Bits!");

  DId->SetBits(Bits);
  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(DId, Bits,
                                                          ASTTypeBitset)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeBitset.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(DId)) {
    std::stringstream M;
    M << "Declaration " << DId->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  const ASTFunctionCallNode *EN = FC->GetFunctionCall();
  assert(EN && "Could not obtain a valid ASTFunctionCallNode!");

  if (!EN->ReturnsResult()) {
    std::stringstream M;
    M << "Assignment requires a non-void return type.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  const ASTResultNode *RN = EN->GetResult();
  assert(RN && "Could not obtain a valid Function ASTResultNode!");

  ASTType RTy = RN->GetResultType();
  const ASTImplicitConversionNode *ICX = nullptr;

  switch (RTy) {
  case ASTTypeBool:
  case ASTTypeInt:
  case ASTTypeFloat:
  case ASTTypeDouble:
  case ASTTypeLongDouble:
  case ASTTypeMPInteger:
  case ASTTypeMPDecimal:
  case ASTTypeAngle:
  case ASTTypeBitset:
    ICX = new ASTImplicitConversionNode(RN, ASTTypeBitset, Bits);
    assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    break;
  default: {
    std::stringstream M;
    M << "Impossible initialization of an ASTCBitNode from "
      << "Type " << PrintTypeEnum(RTy) << ".";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  } break;
  }

  ASTCBitNode *DCBN = ASTBuilder::Instance().CreateASTCBitNode(DId, Bits, 0UL);
  assert(DCBN && "Could not create a valid ASTCBitNode!");

  ASTBinaryOpNode *BOP = nullptr;
  if (ICX)
    BOP = new ASTBinaryOpNode(ASTIdentifierNode::BinaryOp.Clone(), DCBN, ICX,
                              ASTOpTypeAssign);
  else
    BOP = new ASTBinaryOpNode(ASTIdentifierNode::BinaryOp.Clone(), DCBN, EN,
                              ASTOpTypeAssign);
  assert(BOP && "Could not create a valid ASTBinaryOpNode!");

  BOP->SetLocation(TK->GetLocation());
  DCBN->SetLocation(TK->GetLocation());
  DCBN->SetBinaryOp(BOP);
  DCBN->Mangle();

  ASTCBitNodeMap::Instance().Insert(DId, DCBN);
  ASTDeclarationNode *DN =
      new ASTDeclarationNode(DId, DCBN, ASTTypeBitset, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *ASTProductionFactory::ProductionRule_220(
    const ASTToken *TK, const ASTIdentifierNode *DId, const ASTIntNode *I,
    bool Unsigned) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DId && "Invalid ASTIdentifierNode! argument!");
  assert(I && "Invalid ASTIntNode argument!");

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(I);
  assert(!ASTIdentifierNode::InvalidBits(Bits) &&
         "Invalid number of Bits for Index Identifier!");

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(DId, Bits,
                                                          ASTTypeMPInteger)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeMPInteger.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(DId)) {
    std::stringstream M;
    M << "Declaration " << DId->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  ASTMPIntegerNode *MPI =
      ASTBuilder::Instance().CreateASTMPIntegerNode(DId, Bits, Unsigned);
  assert(MPI && "Could not create an ASTMPIntegerNode!");

  MPI->SetLocation(TK->GetLocation());
  MPI->Mangle();

  ASTDeclarationNode *DN =
      new ASTDeclarationNode(DId, MPI, ASTTypeMPInteger, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *ASTProductionFactory::ProductionRule_221(
    const ASTToken *TK, const ASTIdentifierNode *DId,
    const ASTIdentifierNode *IId, bool Unsigned) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DId && "Invalid ASTIdentifierNode argument!");
  assert(IId && "Invalid ASTIdentifierNode argument!");

  ASTScopeController::Instance().CheckUndefined(IId);
  ASTScopeController::Instance().CheckOutOfScope(IId);

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(IId);
  assert(!ASTIdentifierNode::InvalidBits(Bits) &&
         "Invalid number of Bits for Index Identifier!");

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(DId, Bits,
                                                          ASTTypeMPInteger)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeMPInteger.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(DId)) {
    std::stringstream M;
    M << "Error: Declaration " << DId->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  ASTMPIntegerNode *MPI =
      ASTBuilder::Instance().CreateASTMPIntegerNode(DId, Bits, Unsigned);
  assert(MPI && "Could not create an ASTMPIntegerNode!");

  MPI->SetLocation(TK->GetLocation());
  MPI->Mangle();

  ASTDeclarationNode *DN =
      new ASTDeclarationNode(DId, MPI, ASTTypeMPInteger, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *ASTProductionFactory::ProductionRule_222(
    const ASTToken *TK, const ASTIdentifierNode *DId, const ASTIntNode *I,
    const ASTExpressionNode *EN, bool Unsigned) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DId && "Invalid ASTIdentifierNode! argument!");
  assert(I && "Invalid ASTMPIntegerNode BitIndex argument!");
  assert(EN && "Invalid ASTExpressionNode argument!");

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(I);
  assert(!ASTIdentifierNode::InvalidBits(Bits) &&
         "Invalid number of Bits for ASTMPIntegerNode!");

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(DId, Bits,
                                                          ASTTypeMPInteger)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeMPInteger.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(DId)) {
    std::stringstream M;
    M << "Declaration " << DId->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  std::string MPIVS;
  bool FromArray = false;
  bool FromValue = false;
  bool FromExpr = false;
  const ASTImplicitConversionNode *ICX = nullptr;
  bool ITW = false;
  mpz_t MPV;

  ASTType ETy = EN->GetASTType();
  ASTSignbit SB = Unsigned ? ASTSignbit::Unsigned : ASTSignbit::Signed;

  switch (ETy) {
  case ASTTypeInt:
    if (const ASTIntNode *IN = dynamic_cast<const ASTIntNode *>(EN)) {
      FromValue = true;
      mpz_init2(MPV, Bits);

      if (IN->IsString()) {
        if (ASTMPIntegerNode::InitMPZFromString(MPV, IN->GetString().c_str(),
                                                SB) != 0) {
          std::stringstream M;
          M << "Failed conversion from String to ASTMPInteger.";
          QasmDiagnosticEmitter::Instance().EmitDiagnostic(
              DIAGLineCounter::Instance().GetLocation(EN), M.str(),
              DiagLevel::Error);
          return ASTDeclarationNode::DeclarationError(DId, M.str());
        }
      } else {
        if (IN->IsSigned())
          mpz_set_si(MPV, IN->GetSignedValue());
        else
          mpz_set_si(MPV, static_cast<int32_t>(IN->GetUnsignedValue()));
      }

      ICX = new ASTImplicitConversionNode(IN, ASTTypeMPInteger, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeBool:
    if (const ASTBoolNode *BN = dynamic_cast<const ASTBoolNode *>(EN)) {
      FromValue = true;
      mpz_init2(MPV, Bits);
      mpz_set_si(MPV, static_cast<int32_t>(BN->GetValue()));
      ICX = new ASTImplicitConversionNode(BN, ASTTypeMPInteger, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeFloat:
    if (const ASTFloatNode *FN = dynamic_cast<const ASTFloatNode *>(EN)) {
      FromValue = true;
      mpz_init2(MPV, Bits);
      mpz_set_d(MPV, FN->GetValue());
      ICX = new ASTImplicitConversionNode(FN, ASTTypeMPInteger, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeDouble:
    if (const ASTDoubleNode *DN = dynamic_cast<const ASTDoubleNode *>(EN)) {
      FromValue = true;
      mpz_init2(MPV, Bits);
      mpz_set_d(MPV, DN->GetValue());
      if (Bits < 64)
        ITW = true;
      ICX = new ASTImplicitConversionNode(DN, ASTTypeMPInteger, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeLongDouble:
    if (const ASTLongDoubleNode *LD =
            dynamic_cast<const ASTLongDoubleNode *>(EN)) {
      FromValue = true;
      mpz_init2(MPV, Bits);
      mpz_set_d(MPV, LD->GetValue());
      if (Bits < 128)
        ITW = true;
      ICX = new ASTImplicitConversionNode(LD, ASTTypeMPInteger, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeMPInteger:
    if (const ASTMPIntegerNode *MPII =
            dynamic_cast<const ASTMPIntegerNode *>(EN)) {
      FromValue = true;
      mpz_init2(MPV, Bits);
      mpz_set(MPV, MPII->GetMPValue());
      if (Bits < MPII->GetIdentifier()->GetBits())
        ITW = true;
    }
    break;
  case ASTTypeMPDecimal:
    if (const ASTMPDecimalNode *MPD =
            dynamic_cast<const ASTMPDecimalNode *>(EN)) {
      FromValue = true;
      mpz_init2(MPV, Bits);
      mpfr_get_z(MPV, MPD->GetMPValue(), MPFR_RNDN);
      if (Bits < MPD->GetIdentifier()->GetBits())
        ITW = true;
      ICX = new ASTImplicitConversionNode(MPD, ASTTypeMPInteger, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeAngle:
    if (const ASTAngleNode *AN = dynamic_cast<const ASTAngleNode *>(EN)) {
      FromValue = true;
      mpz_init2(MPV, Bits);
      mpfr_get_z(MPV, AN->GetMPValue(), MPFR_RNDN);
      if (AN->GetIdentifier()->GetBits() > Bits)
        ITW = true;
      ICX = new ASTImplicitConversionNode(AN, ASTTypeMPInteger, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeBitset:
    if (const ASTCBitNode *CB = dynamic_cast<const ASTCBitNode *>(EN)) {
      FromValue = true;
      mpz_init2(MPV, Bits);
      if (mpz_set_str(MPV, CB->AsString().c_str(), 2) != 0)
        mpz_set_si(MPV, static_cast<int64_t>(~0x0));
      if (CB->Size() > Bits)
        ITW = true;
      ICX = new ASTImplicitConversionNode(CB, ASTTypeMPInteger, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeQubit: {
    std::stringstream M;
    M << "A Qubit cannot be assigned to a scalar.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  } break;
  case ASTTypeStringLiteral: {
    if (const ASTStringNode *S = dynamic_cast<const ASTStringNode *>(EN)) {
      FromValue = true;
      mpz_init2(MPV, Bits);
      std::string MPS = ASTStringUtils::Instance().Sanitize(S->GetValue());
      if (ASTMPIntegerNode::InitMPZFromString(MPV, MPS.c_str(), SB) != 0) {
        std::stringstream M;
        M << "Failed conversion from String to ASTMPInteger.";
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(EN), M.str(),
            DiagLevel::Error);
        return ASTDeclarationNode::DeclarationError(DId, M.str());
      }
    }
  } break;
  case ASTTypeBinaryOp:
  case ASTTypeUnaryOp:
  case ASTTypeExpression:
  case ASTTypeCast:
    FromExpr = true;
    break;
  case ASTTypeImplicitConversion:
    ICX = new ASTImplicitConversionNode(EN, ASTTypeMPInteger, Bits);
    assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    FromExpr = true;
    break;
  case ASTTypeCBitArray:
  case ASTTypeCBitNArray:
  case ASTTypeQubitArray:
  case ASTTypeQubitNArray:
  case ASTTypeAngleArray:
  case ASTTypeBoolArray:
  case ASTTypeMPIntegerArray:
  case ASTTypeMPDecimalArray:
  case ASTTypeLengthArray:
  case ASTTypeDurationArray:
  case ASTTypeFloatArray:
  case ASTTypeIntArray: {
    std::stringstream M;
    M << "An array cannot be assigned to a multiple-precision integer.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  } break;
  case ASTTypeIdentifier: {
    const ASTIdentifierNode *Id = EN->GetIdentifier();
    assert(Id && "Could not obtain a valid ASTIdentifierNode!");

    const ASTIdentifierRefNode *IdR =
        dynamic_cast<const ASTIdentifierRefNode *>(Id);
    if (!IdR) {
      const ASTSymbolTableEntry *STE = Id->GetSymbolTableEntry();
      assert(STE && "Could not obtain a valid ASTSymbolTableEntry!");
      assert(
          STE->GetValueType() == Id->GetSymbolType() &&
          "Type mismatch between ASTIdentifierNode and ASTSymbolTableEntry!");

      switch (Id->GetSymbolType()) {
      case ASTTypeBool: {
        if (ASTBoolNode *BN = STE->GetValue()->GetValue<ASTBoolNode *>()) {
          FromValue = true;
          mpz_init2(MPV, Bits);
          mpz_set_si(MPV, static_cast<int32_t>(BN->GetValue()));
          ICX = new ASTImplicitConversionNode(BN, ASTTypeMPInteger, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeInt: {
        if (ASTIntNode *IN = STE->GetValue()->GetValue<ASTIntNode *>()) {
          FromValue = true;
          mpz_init2(MPV, Bits);
          if (IN->IsSigned())
            mpz_set_si(MPV, IN->GetSignedValue());
          else
            mpz_set_si(MPV, static_cast<int32_t>(IN->GetUnsignedValue()));

          ICX = new ASTImplicitConversionNode(IN, ASTTypeMPInteger, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeFloat: {
        if (ASTFloatNode *FN = STE->GetValue()->GetValue<ASTFloatNode *>()) {
          FromValue = true;
          mpz_init2(MPV, Bits);
          mpz_set_d(MPV, FN->GetValue());
          ICX = new ASTImplicitConversionNode(FN, ASTTypeMPInteger, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeDouble: {
        if (ASTDoubleNode *DN = STE->GetValue()->GetValue<ASTDoubleNode *>()) {
          FromValue = true;
          mpz_init2(MPV, Bits);
          mpz_set_d(MPV, DN->GetValue());
          ICX = new ASTImplicitConversionNode(DN, ASTTypeMPInteger, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeLongDouble: {
        if (ASTLongDoubleNode *LN =
                STE->GetValue()->GetValue<ASTLongDoubleNode *>()) {
          FromValue = true;
          mpz_init2(MPV, Bits);
          mpz_set_d(MPV, LN->GetValue());
          ICX = new ASTImplicitConversionNode(LN, ASTTypeMPInteger, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeAngle: {
        if (ASTAngleNode *AN = STE->GetValue()->GetValue<ASTAngleNode *>()) {
          FromValue = true;
          mpz_init2(MPV, Bits);
          ITW = true;
          mpfr_get_z(MPV, AN->GetMPValue(), MPFR_RNDN);
          ICX = new ASTImplicitConversionNode(AN, ASTTypeMPInteger, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeMPInteger: {
        if (ASTMPIntegerNode *MPI =
                STE->GetValue()->GetValue<ASTMPIntegerNode *>()) {
          FromValue = true;
          mpz_init2(MPV, Bits);
          mpz_set(MPV, MPI->GetMPValue());
          if (Bits < MPI->GetBits())
            ITW = true;
        }
      } break;
      case ASTTypeMPDecimal: {
        if (ASTMPDecimalNode *MPD =
                STE->GetValue()->GetValue<ASTMPDecimalNode *>()) {
          FromValue = true;
          mpz_init2(MPV, Bits);
          mpfr_get_z(MPV, MPD->GetMPValue(), MPFR_RNDN);
          if (Bits < MPD->GetIdentifier()->GetBits())
            ITW = true;
          ICX = new ASTImplicitConversionNode(MPD, ASTTypeMPInteger, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeBitset: {
        if (ASTCBitNode *CBN = STE->GetValue()->GetValue<ASTCBitNode *>()) {
          FromValue = true;
          mpz_init2(MPV, Bits);
          mpz_set_str(MPV, CBN->AsString().c_str(), 2);
          if (Bits < CBN->Size())
            ITW = true;
          ICX = new ASTImplicitConversionNode(CBN, ASTTypeMPInteger, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      default: {
        std::stringstream M;
        M << "Impossible assignment from an "
          << PrintTypeEnum(Id->GetSymbolType()) << " to an ASTMPIntegerNode.";
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(TK), M.str(),
            DiagLevel::Error);
        return ASTDeclarationNode::DeclarationError(DId, M.str());
      } break;
      }
    } else {
      assert(IdR && "Could not dynamic_cast to an ASTIdentifierNode!");

      const ASTIdentifierNode *IId = IdR->GetIdentifier();
      assert(IId && "Could not obtain an unindexed ASTIdentifierNode!");

      ASTScopeController::Instance().CheckUndefined(IId);
      ASTScopeController::Instance().CheckOutOfScope(IId);

      if (IdR->IsIndexed()) {
        ASTSymbolTableEntry *STE = ASTSymbolTable::Instance().Lookup(
            IdR, IdR->GetBits(), IdR->GetReferenceType());
        assert(STE && "ASTIdentifierRefNode has no SymbolTable Entry!");

        switch (STE->GetValueType()) {
        case ASTTypeMPUInteger:
        case ASTTypeMPInteger:
          if (ASTMPIntegerNode *MPI =
                  STE->GetValue()->GetValue<ASTMPIntegerNode *>()) {
            FromValue = true;
            mpz_init2(MPV, Bits);
            mpz_set(MPV, MPI->GetMPValue());
            if (Bits < MPI->GetBits())
              ITW = true;
          }
          break;
        case ASTTypeBool:
          if (ASTBoolNode *BN = STE->GetValue()->GetValue<ASTBoolNode *>()) {
            FromValue = true;
            mpz_init2(MPV, Bits);
            mpz_set_si(MPV, static_cast<int32_t>(BN->GetValue()));
            ICX = new ASTImplicitConversionNode(BN, ASTTypeMPInteger, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
          break;
        case ASTTypeInt:
        case ASTTypeUInt:
          if (ASTIntNode *IN = STE->GetValue()->GetValue<ASTIntNode *>()) {
            FromValue = true;
            mpz_init2(MPV, Bits);
            if (IN->IsSigned())
              mpz_set_si(MPV, IN->GetSignedValue());
            else
              mpz_set_si(MPV, static_cast<int32_t>(IN->GetUnsignedValue()));

            ICX = new ASTImplicitConversionNode(IN, ASTTypeMPInteger, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
          break;
        case ASTTypeFloat:
          if (ASTFloatNode *FN = STE->GetValue()->GetValue<ASTFloatNode *>()) {
            FromValue = true;
            mpz_init2(MPV, Bits);
            mpz_set_d(MPV, FN->GetValue());
            ICX = new ASTImplicitConversionNode(FN, ASTTypeMPInteger, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
          break;
        case ASTTypeMPDecimal:
          if (ASTMPDecimalNode *MPD =
                  STE->GetValue()->GetValue<ASTMPDecimalNode *>()) {
            FromValue = true;
            mpz_init2(MPV, Bits);
            mpfr_get_z(MPV, MPD->GetMPValue(), MPFR_RNDN);
            if (Bits < MPD->GetIdentifier()->GetBits())
              ITW = true;
            ICX = new ASTImplicitConversionNode(MPD, ASTTypeMPInteger, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
          break;
        case ASTTypeBitset:
          if (ASTCBitNode *CBN = STE->GetValue()->GetValue<ASTCBitNode *>()) {
            FromValue = true;
            mpz_init2(MPV, Bits);
            mpz_set_str(MPV, CBN->AsString().c_str(), 2);
            if (Bits < CBN->Size())
              ITW = true;
            ICX = new ASTImplicitConversionNode(CBN, ASTTypeMPInteger, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
          break;
        case ASTTypeAngle: {
          if (ASTAngleNode *AN = STE->GetValue()->GetValue<ASTAngleNode *>()) {
            FromValue = true;
            mpz_init2(MPV, Bits);
            ITW = true;
            mpfr_get_z(MPV, AN->GetMPValue(), MPFR_RNDN);
            ICX = new ASTImplicitConversionNode(AN, ASTTypeMPInteger, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
        } break;
        default: {
          std::stringstream M;
          M << "Impossible ASTMPIntegerNode Initialization from an "
            << PrintTypeEnum(ETy) << ".";
          QasmDiagnosticEmitter::Instance().EmitDiagnostic(
              DIAGLineCounter::Instance().GetLocation(IId), M.str(),
              DiagLevel::Error);
          return ASTDeclarationNode::DeclarationError(DId, M.str());
        } break;
        }
      }
    }
  } break;
  default: {
    std::stringstream M;
    M << "Impossible ASTMPIntegerNode Initialization from an "
      << PrintTypeEnum(ETy) << ".";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  } break;
  }

  ASTMPIntegerNode *DMPI = nullptr;

  if (ITW) {
    std::stringstream M;
    M << "Assignment may result in truncation.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(),
        DiagLevel::Warning);
  }

  if (FromArray) {
    DMPI = ASTBuilder::Instance().CreateASTMPIntegerNode(
        DId, Bits, MPIVS.c_str(), Unsigned);
  } else if (FromValue) {
    DMPI =
        ASTBuilder::Instance().CreateASTMPIntegerNode(DId, Bits, MPV, Unsigned);
    mpz_clear(MPV);
  } else if (FromExpr) {
    if (EN->GetASTType() == ASTTypeCast) {
      const ASTCastExpressionNode *CX =
          dynamic_cast<const ASTCastExpressionNode *>(EN);
      assert(CX && "Could not dynamic_cast to an ASTCastExpressionNode!");
      DMPI = ASTBuilder::Instance().CreateASTMPIntegerNode(DId, Bits, CX,
                                                           Unsigned);
    } else {
      DMPI = ASTBuilder::Instance().CreateASTMPIntegerNode(DId, Bits, EN,
                                                           Unsigned);
    }
  } else {
    DMPI =
        ASTBuilder::Instance().CreateASTMPIntegerNode(DId, Bits, EN, Unsigned);
  }

  assert(DMPI && "Could not create an ASTMPIntegerNode!");

  if (FromValue) {
    DMPI->SetConstantFolded(true);
    if (ICX)
      DMPI->SetImplicitConversion(ICX);
  }

  DMPI->SetLocation(TK->GetLocation());
  DMPI->Mangle();
  ASTDeclarationNode *DN =
      new ASTDeclarationNode(DId, DMPI, ASTTypeMPInteger, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *ASTProductionFactory::ProductionRule_223(
    const ASTToken *TK, const ASTIdentifierNode *DId, const ASTIntNode *I,
    const ASTFunctionCallStatementNode *FC, bool Unsigned) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DId && "Invalid ASTIdentifierNode argument!");
  assert(I && "Invalid ASTMPIntegerNode BitIndex argument!");
  assert(FC && "Invalid ASTFunctionCallStatementNode argument!");

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(I);
  assert(!ASTIdentifierNode::InvalidBits(Bits) &&
         "Invalid number of Bits for ASTMPIntegerNode!");

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(DId, Bits,
                                                          ASTTypeMPInteger)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeMPInteger.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(DId)) {
    std::stringstream M;
    M << "Declaration " << DId->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  const ASTFunctionCallNode *EN = FC->GetFunctionCall();
  assert(EN && "Could not obtain a valid ASTFunctionCallNode!");

  if (!EN->ReturnsResult()) {
    std::stringstream M;
    M << "Assignment requires a non-void return type.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  ASTMPIntegerNode *DMPI =
      ASTBuilder::Instance().CreateASTMPIntegerNode(DId, Bits, EN, Unsigned);
  assert(DMPI && "Could not create a valid ASTMPIntegerNode!");

  DMPI->SetLocation(TK->GetLocation());
  DMPI->Mangle();

  ASTDeclarationNode *DN =
      new ASTDeclarationNode(DId, DMPI, ASTTypeMPInteger, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *ASTProductionFactory::ProductionRule_224(
    const ASTToken *TK, const ASTIdentifierNode *DId,
    const ASTIdentifierNode *BId, const ASTExpressionNode *EN,
    bool Unsigned) const {
  assert(DId && "Invalid ASTIdentifierNode! argument!");
  assert(BId && "Invalid ASTIntNode BitIndex argument!");
  assert(EN && "Invalid ASTExpressionNode argument!");

  ASTScopeController::Instance().CheckUndefined(BId);
  ASTScopeController::Instance().CheckOutOfScope(BId);

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(BId);
  assert(!ASTIdentifierNode::InvalidBits(Bits) &&
         "Invalid number of Bits for Index Identifier!");

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(DId, Bits,
                                                          ASTTypeMPInteger)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeMPInteger.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(DId)) {
    std::stringstream M;
    M << "Declaration " << DId->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  std::string MPIVS;
  bool FromArray = false;
  bool FromValue = false;
  bool FromExpr = false;
  bool ITW = false;
  const ASTImplicitConversionNode *ICX = nullptr;
  mpz_t MPV;

  ASTType ETy = EN->GetASTType();
  ASTSignbit SB = Unsigned ? ASTSignbit::Unsigned : ASTSignbit::Signed;

  switch (ETy) {
  case ASTTypeInt:
    if (const ASTIntNode *IN = dynamic_cast<const ASTIntNode *>(EN)) {
      mpz_init2(MPV, Bits);
      FromValue = true;
      if (IN->IsString()) {
        if (ASTMPIntegerNode::InitMPZFromString(MPV, IN->GetString().c_str(),
                                                SB) != 0) {
          std::stringstream M;
          M << "Failed conversion from String to ASTMPInteger.";
          QasmDiagnosticEmitter::Instance().EmitDiagnostic(
              DIAGLineCounter::Instance().GetLocation(), M.str(),
              DiagLevel::Error);
        }
      } else {
        if (IN->IsSigned())
          mpz_set_si(MPV, IN->GetSignedValue());
        else
          mpz_set_si(MPV, static_cast<int32_t>(IN->GetUnsignedValue()));
      }

      ICX = new ASTImplicitConversionNode(IN, ASTTypeMPInteger, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeBool:
    if (const ASTBoolNode *BN = dynamic_cast<const ASTBoolNode *>(EN)) {
      mpz_init2(MPV, Bits);
      FromValue = true;
      mpz_set_si(MPV, static_cast<int32_t>(BN->GetValue()));
      ICX = new ASTImplicitConversionNode(BN, ASTTypeMPInteger, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeFloat:
    if (const ASTFloatNode *FN = dynamic_cast<const ASTFloatNode *>(EN)) {
      mpz_init2(MPV, Bits);
      FromValue = true;
      mpz_set_d(MPV, FN->GetValue());
      ICX = new ASTImplicitConversionNode(FN, ASTTypeMPInteger, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeDouble:
    if (const ASTDoubleNode *DN = dynamic_cast<const ASTDoubleNode *>(EN)) {
      mpz_init2(MPV, Bits);
      FromValue = true;
      mpz_set_d(MPV, DN->GetValue());
      if (Bits < 64)
        ITW = true;
      ICX = new ASTImplicitConversionNode(DN, ASTTypeMPInteger, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeLongDouble:
    if (const ASTLongDoubleNode *LD =
            dynamic_cast<const ASTLongDoubleNode *>(EN)) {
      mpz_init2(MPV, Bits);
      FromValue = true;
      mpz_set_d(MPV, LD->GetValue());
      if (Bits < 128)
        ITW = true;
      ICX = new ASTImplicitConversionNode(LD, ASTTypeMPInteger, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeMPInteger:
    if (const ASTMPIntegerNode *MPII =
            dynamic_cast<const ASTMPIntegerNode *>(EN)) {
      mpz_init2(MPV, Bits);
      FromValue = true;
      mpz_set(MPV, MPII->GetMPValue());
      if (Bits < MPII->GetIdentifier()->GetBits())
        ITW = true;
    }
    break;
  case ASTTypeMPDecimal:
    if (const ASTMPDecimalNode *MPD =
            dynamic_cast<const ASTMPDecimalNode *>(EN)) {
      mpz_init2(MPV, Bits);
      FromValue = true;
      mpfr_get_z(MPV, MPD->GetMPValue(), MPFR_RNDN);
      if (Bits < MPD->GetIdentifier()->GetBits())
        ITW = true;
      ICX = new ASTImplicitConversionNode(MPD, ASTTypeMPInteger, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeBitset:
    if (const ASTCBitNode *CB = dynamic_cast<const ASTCBitNode *>(EN)) {
      mpz_init2(MPV, Bits);
      FromValue = true;
      if (mpz_set_str(MPV, CB->AsString().c_str(), 2) != 0)
        mpz_set_si(MPV, static_cast<int64_t>(~0x0));
      if (CB->Size() > Bits)
        ITW = true;
      ICX = new ASTImplicitConversionNode(CB, ASTTypeMPInteger, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeAngle:
    if (const ASTAngleNode *AN = dynamic_cast<const ASTAngleNode *>(EN)) {
      mpz_init2(MPV, Bits);
      FromValue = true;
      mpfr_get_z(MPV, AN->GetMPValue(), MPFR_RNDN);
      if (AN->GetIdentifier()->GetBits() > Bits)
        ITW = true;
      ICX = new ASTImplicitConversionNode(AN, ASTTypeMPInteger, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeStringLiteral: {
    if (const ASTStringNode *S = dynamic_cast<const ASTStringNode *>(EN)) {
      FromValue = true;
      mpz_init2(MPV, Bits);
      std::string MPS = ASTStringUtils::Instance().Sanitize(S->GetValue());
      if (ASTMPIntegerNode::InitMPZFromString(MPV, MPS.c_str(), SB) != 0) {
        std::stringstream M;
        M << "Failed conversion from String to ASTMPInteger.";
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(EN), M.str(),
            DiagLevel::Error);
        return ASTDeclarationNode::DeclarationError(DId, M.str());
      }
    }
  } break;
  case ASTTypeBinaryOp:
  case ASTTypeUnaryOp:
  case ASTTypeExpression:
  case ASTTypeCast:
    FromExpr = true;
    break;
  case ASTTypeCBitArray:
  case ASTTypeCBitNArray:
  case ASTTypeQubitArray:
  case ASTTypeQubitNArray:
  case ASTTypeAngleArray:
  case ASTTypeBoolArray:
  case ASTTypeMPIntegerArray:
  case ASTTypeMPDecimalArray:
  case ASTTypeLengthArray:
  case ASTTypeDurationArray:
  case ASTTypeFloatArray:
  case ASTTypeIntArray: {
    std::stringstream M;
    M << "An array cannot be assigned to a multiple-precision integer.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  } break;
  case ASTTypeQubit: {
    std::stringstream M;
    M << "A Qubit cannot be assigned to a scalar.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  } break;
  case ASTTypeIdentifier: {
    const ASTIdentifierNode *Id = EN->GetIdentifier();
    assert(Id && "Could not obtain a valid ASTIdentifierNode!");

    const ASTIdentifierRefNode *IdR =
        dynamic_cast<const ASTIdentifierRefNode *>(Id);
    if (!IdR) {
      const ASTSymbolTableEntry *STE = Id->GetSymbolTableEntry();
      assert(STE && "Could not obtain a valid ASTSymbolTableEntry!");
      assert(
          STE->GetValueType() == Id->GetSymbolType() &&
          "Type mismatch between ASTIdentifierNode and ASTSymbolTableEntry!");

      switch (Id->GetSymbolType()) {
      case ASTTypeBool: {
        if (ASTBoolNode *BN = STE->GetValue()->GetValue<ASTBoolNode *>()) {
          FromValue = true;
          mpz_init2(MPV, Bits);
          mpz_set_si(MPV, static_cast<int32_t>(BN->GetValue()));
          ICX = new ASTImplicitConversionNode(BN, ASTTypeMPInteger, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeInt: {
        if (ASTIntNode *IN = STE->GetValue()->GetValue<ASTIntNode *>()) {
          FromValue = true;
          mpz_init2(MPV, Bits);
          if (IN->IsSigned())
            mpz_set_si(MPV, IN->GetSignedValue());
          else
            mpz_set_si(MPV, static_cast<int32_t>(IN->GetUnsignedValue()));

          ICX = new ASTImplicitConversionNode(IN, ASTTypeMPInteger, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeFloat: {
        if (ASTFloatNode *FN = STE->GetValue()->GetValue<ASTFloatNode *>()) {
          FromValue = true;
          mpz_init2(MPV, Bits);
          mpz_set_d(MPV, FN->GetValue());
          ICX = new ASTImplicitConversionNode(FN, ASTTypeMPInteger, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeDouble: {
        if (ASTDoubleNode *DN = STE->GetValue()->GetValue<ASTDoubleNode *>()) {
          FromValue = true;
          mpz_init2(MPV, Bits);
          mpz_set_d(MPV, DN->GetValue());
          ICX = new ASTImplicitConversionNode(DN, ASTTypeMPInteger, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeLongDouble: {
        if (ASTLongDoubleNode *LN =
                STE->GetValue()->GetValue<ASTLongDoubleNode *>()) {
          FromValue = true;
          mpz_init2(MPV, Bits);
          mpz_set_d(MPV, LN->GetValue());
          ICX = new ASTImplicitConversionNode(LN, ASTTypeMPInteger, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeAngle: {
        if (ASTAngleNode *AN = STE->GetValue()->GetValue<ASTAngleNode *>()) {
          FromValue = true;
          mpz_init2(MPV, Bits);
          ITW = true;
          mpfr_get_z(MPV, AN->GetMPValue(), MPFR_RNDN);
          ICX = new ASTImplicitConversionNode(AN, ASTTypeMPInteger, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeMPInteger: {
        if (ASTMPIntegerNode *MPI =
                STE->GetValue()->GetValue<ASTMPIntegerNode *>()) {
          FromValue = true;
          mpz_init2(MPV, Bits);
          mpz_set(MPV, MPI->GetMPValue());
          if (Bits < MPI->GetBits())
            ITW = true;
        }
      } break;
      case ASTTypeMPDecimal: {
        if (ASTMPDecimalNode *MPD =
                STE->GetValue()->GetValue<ASTMPDecimalNode *>()) {
          FromValue = true;
          mpz_init2(MPV, Bits);
          mpfr_get_z(MPV, MPD->GetMPValue(), MPFR_RNDN);
          if (Bits < MPD->GetIdentifier()->GetBits())
            ITW = true;
          ICX = new ASTImplicitConversionNode(MPD, ASTTypeMPInteger, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeBitset: {
        if (ASTCBitNode *CBN = STE->GetValue()->GetValue<ASTCBitNode *>()) {
          FromValue = true;
          mpz_init2(MPV, Bits);
          mpz_set_str(MPV, CBN->AsString().c_str(), 2);
          if (Bits < CBN->Size())
            ITW = true;
          ICX = new ASTImplicitConversionNode(CBN, ASTTypeMPInteger, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      default: {
        std::stringstream M;
        M << "Impossible assignment from an "
          << PrintTypeEnum(Id->GetSymbolType()) << " to an ASTMPIntegerNode.";
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(TK), M.str(),
            DiagLevel::Error);
        return ASTDeclarationNode::DeclarationError(DId, M.str());
      } break;
      }
    } else {
      assert(IdR && "Could not dynamic_cast to an ASTIdentifierNode!");

      const ASTIdentifierNode *IId = IdR->GetIdentifier();
      assert(IId && "Could not obtain an unindexed ASTIdentifierNode!");

      ASTScopeController::Instance().CheckUndefined(IId);
      ASTScopeController::Instance().CheckOutOfScope(IId);

      if (IdR->IsIndexed()) {
        ASTSymbolTableEntry *STE = ASTSymbolTable::Instance().Lookup(
            IdR, IdR->GetBits(), IdR->GetReferenceType());
        assert(STE && "ASTIdentifierRefNode has no SymbolTable Entry!");

        switch (STE->GetValueType()) {
        case ASTTypeMPInteger:
          if (ASTMPIntegerNode *MPI =
                  STE->GetValue()->GetValue<ASTMPIntegerNode *>()) {
            FromValue = true;
            mpz_init2(MPV, Bits);
            mpz_set(MPV, MPI->GetMPValue());
            if (Bits < MPI->GetBits())
              ITW = true;
          }
          break;
        case ASTTypeBool:
          if (ASTBoolNode *BN = STE->GetValue()->GetValue<ASTBoolNode *>()) {
            FromValue = true;
            mpz_init2(MPV, Bits);
            mpz_set_ui(MPV, BN->GetValue());
            ICX = new ASTImplicitConversionNode(BN, ASTTypeMPInteger, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
          break;
        case ASTTypeInt:
          if (ASTIntNode *IN = STE->GetValue()->GetValue<ASTIntNode *>()) {
            FromValue = true;
            mpz_init2(MPV, Bits);
            if (IN->IsSigned())
              mpz_set_ui(MPV, static_cast<uint32_t>(IN->GetSignedValue()));
            else
              mpz_set_ui(MPV, IN->GetUnsignedValue());

            ICX = new ASTImplicitConversionNode(IN, ASTTypeMPInteger, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
          break;
        case ASTTypeFloat:
          if (ASTFloatNode *FN = STE->GetValue()->GetValue<ASTFloatNode *>()) {
            FromValue = true;
            mpz_init2(MPV, Bits);
            mpz_set_d(MPV, FN->GetValue());
            ICX = new ASTImplicitConversionNode(FN, ASTTypeMPInteger, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
          break;
        case ASTTypeMPDecimal:
          if (ASTMPDecimalNode *MPD =
                  STE->GetValue()->GetValue<ASTMPDecimalNode *>()) {
            FromValue = true;
            mpz_init2(MPV, Bits);
            mpfr_get_z(MPV, MPD->GetMPValue(), MPFR_RNDN);
            if (Bits < MPD->GetIdentifier()->GetBits())
              ITW = true;
            ICX = new ASTImplicitConversionNode(MPD, ASTTypeMPInteger, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
          break;
        case ASTTypeBitset:
          if (ASTCBitNode *CBN = STE->GetValue()->GetValue<ASTCBitNode *>()) {
            FromValue = true;
            mpz_init2(MPV, Bits);
            mpz_set_str(MPV, CBN->AsString().c_str(), 2);
            if (Bits < CBN->Size())
              ITW = true;
            ICX = new ASTImplicitConversionNode(CBN, ASTTypeMPInteger, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
          break;
        case ASTTypeAngle: {
          if (ASTAngleNode *AN = STE->GetValue()->GetValue<ASTAngleNode *>()) {
            FromValue = true;
            mpz_init2(MPV, Bits);
            ITW = true;
            mpfr_get_z(MPV, AN->GetMPValue(), MPFR_RNDN);
            ICX = new ASTImplicitConversionNode(AN, ASTTypeMPInteger, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
        } break;
        default: {
          std::stringstream M;
          M << "Impossible ASTMPIntegerNode Initialization from an "
            << PrintTypeEnum(ETy) << ".";
          QasmDiagnosticEmitter::Instance().EmitDiagnostic(
              DIAGLineCounter::Instance().GetLocation(IId), M.str(),
              DiagLevel::Error);
          return ASTDeclarationNode::DeclarationError(DId, M.str());
        } break;
        }
      }
    }
  } break;
  default: {
    std::stringstream M;
    M << "Impossible ASTMPIntegerNode Initialization from an "
      << PrintTypeEnum(ETy) << ".";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  } break;
  }

  ASTMPIntegerNode *DMPI = nullptr;

  if (ITW) {
    std::stringstream M;
    M << "Assignment may result in truncation.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(),
        DiagLevel::Warning);
  }

  if (FromArray) {
    DMPI = ASTBuilder::Instance().CreateASTMPIntegerNode(
        DId, Bits, MPIVS.c_str(), Unsigned);
  } else if (FromValue) {
    DMPI =
        ASTBuilder::Instance().CreateASTMPIntegerNode(DId, Bits, MPV, Unsigned);
    mpz_clear(MPV);
  } else if (FromExpr) {
    if (EN->GetASTType() == ASTTypeCast) {
      const ASTCastExpressionNode *CX =
          dynamic_cast<const ASTCastExpressionNode *>(EN);
      assert(CX && "Could not dynamic_cast to an ASTCastExpressionNode!");
      DMPI = ASTBuilder::Instance().CreateASTMPIntegerNode(DId, Bits, CX,
                                                           Unsigned);
    } else {
      DMPI = ASTBuilder::Instance().CreateASTMPIntegerNode(DId, Bits, EN,
                                                           Unsigned);
    }
  } else {
    DMPI =
        ASTBuilder::Instance().CreateASTMPIntegerNode(DId, Bits, EN, Unsigned);
  }

  assert(DMPI && "Could not create an ASTMPIntegerNode!");

  if (FromValue) {
    DMPI->SetConstantFolded(true);
    if (ICX)
      DMPI->SetImplicitConversion(ICX);
  }

  DMPI->SetLocation(TK->GetLocation());
  DMPI->Mangle();

  ASTDeclarationNode *DN =
      new ASTDeclarationNode(DId, DMPI, ASTTypeMPInteger, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *ASTProductionFactory::ProductionRule_225(
    const ASTToken *TK, const ASTIdentifierNode *DId,
    const ASTIdentifierNode *BId, const ASTFunctionCallStatementNode *FC,
    bool Unsigned) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DId && "Invalid ASTIdentifierNode argument!");
  assert(BId && "Invalid ASTIntNode BitIndex argument!");
  assert(FC && "Invalid ASTFunctionCallStatementNode argument!");

  ASTScopeController::Instance().CheckUndefined(BId);
  ASTScopeController::Instance().CheckOutOfScope(BId);

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(BId);
  assert(!ASTIdentifierNode::InvalidBits(Bits) &&
         "Invalid number of Bits for Index Identifier!");

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(DId, Bits,
                                                          ASTTypeMPInteger)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeMPInteger.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(DId)) {
    std::stringstream M;
    M << "Declaration " << DId->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  const ASTFunctionCallNode *EN = FC->GetFunctionCall();
  assert(EN && "Could not obtain a valid ASTFunctionCallNode!");

  ASTScopeController::Instance().CheckOutOfScope(BId);

  if (!EN->ReturnsResult()) {
    std::stringstream M;
    M << "Assignment requires a non-void return type.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  ASTMPIntegerNode *DMPI =
      ASTBuilder::Instance().CreateASTMPIntegerNode(DId, Bits, EN, Unsigned);
  assert(DMPI && "Could not create a valid ASTMPIntegerNode!");

  DMPI->SetLocation(TK->GetLocation());
  DMPI->Mangle();

  ASTDeclarationNode *DN =
      new ASTDeclarationNode(DId, DMPI, ASTTypeMPInteger, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *
ASTProductionFactory::ProductionRule_226(const ASTToken *TK,
                                         const ASTIdentifierNode *DId,
                                         const ASTExpressionNode *EN) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DId && "Invalid ASTIdentifierNode! argument!");
  assert(EN && "Invalid ASTExpressionNode argument!");

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  DId->SetDeclarationContext(CTX);

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
          DId, ASTIntNode::IntBits, ASTTypeInt)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeInt.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(DId)) {
    std::stringstream M;
    M << "Declaration " << DId->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  ASTIntNode *IIN = nullptr;
  const ASTCastExpressionNode *CX = nullptr;
  bool FromArray = false;
  bool FromValue = false;
  bool FromExpr = false;
  bool ITW = false;
  uint32_t USV;

  ASTType ETy = EN->GetASTType();

  switch (ETy) {
  case ASTTypeInt:
    if (const ASTIntNode *I = dynamic_cast<const ASTIntNode *>(EN)) {
      FromValue = true;
      if (I->IsSigned())
        USV = static_cast<uint32_t>(I->GetSignedValue());
      else
        USV = I->GetUnsignedValue();
    }
    break;
  case ASTTypeBool:
    if (const ASTBoolNode *B = dynamic_cast<const ASTBoolNode *>(EN)) {
      FromValue = true;
      USV = static_cast<uint32_t>(B->GetValue());
      CX = new ASTCastExpressionNode(B, ASTTypeInt, ASTIntNode::IntBits);
      assert(CX && "Could not create a valid ASTCastExpressionNode!");
    }
    break;
  case ASTTypeFloat:
    if (const ASTFloatNode *F = dynamic_cast<const ASTFloatNode *>(EN)) {
      USV = static_cast<uint32_t>(F->GetValue());
      FromValue = true;
      CX = new ASTCastExpressionNode(F, ASTTypeInt, ASTIntNode::IntBits);
      assert(CX && "Could not create a valid ASTCastExpressionNode!");
    }
    break;
  case ASTTypeDouble:
    if (const ASTDoubleNode *D = dynamic_cast<const ASTDoubleNode *>(EN)) {
      USV = static_cast<uint32_t>(D->GetValue());
      FromValue = true;
      ITW = true;
      CX = new ASTCastExpressionNode(D, ASTTypeInt, ASTIntNode::IntBits);
      assert(CX && "Could not create a valid ASTCastExpressionNode!");
    }
    break;
  case ASTTypeLongDouble:
    if (const ASTLongDoubleNode *LD =
            dynamic_cast<const ASTLongDoubleNode *>(EN)) {
      FromValue = true;
      ITW = true;
      USV = static_cast<uint32_t>(LD->GetValue());
    }
    break;
  case ASTTypeMPInteger:
    if (const ASTMPIntegerNode *MPI =
            dynamic_cast<const ASTMPIntegerNode *>(EN)) {
      USV = MPI->ToUnsignedInt();
      FromValue = true;
      CX = new ASTCastExpressionNode(MPI, ASTTypeInt, ASTIntNode::IntBits);
      assert(CX && "Could not create a valid ASTCastExpressionNode!");
      if (MPI->GetIdentifier()->GetBits() > ASTIntNode::IntBits)
        ITW = true;
    }
    break;
  case ASTTypeMPDecimal:
    if (const ASTMPDecimalNode *MPD =
            dynamic_cast<const ASTMPDecimalNode *>(EN)) {
      USV = static_cast<uint32_t>(MPD->ToDouble());
      FromValue = true;
      CX = new ASTCastExpressionNode(MPD, ASTTypeInt, ASTIntNode::IntBits);
      assert(CX && "Could not create a valid ASTCastExpressionNode!");
      if (MPD->GetIdentifier()->GetBits() > ASTIntNode::IntBits)
        ITW = true;
    }
    break;
  case ASTTypeAngle:
    if (const ASTAngleNode *AN = dynamic_cast<const ASTAngleNode *>(EN)) {
      USV = static_cast<uint32_t>(AN->AsDouble());
      FromValue = true;
      CX = new ASTCastExpressionNode(AN, ASTTypeInt, ASTIntNode::IntBits);
      assert(CX && "Could not create a valid ASTCastExpressionNode!");
      if (AN->GetBits() > ASTIntNode::IntBits)
        ITW = true;
    }
    break;
  case ASTTypeBitset:
    if (const ASTCBitNode *CB = dynamic_cast<const ASTCBitNode *>(EN)) {
      FromValue = true;
      CX = new ASTCastExpressionNode(CB, ASTTypeInt, ASTIntNode::IntBits);
      assert(CX && "Could not create a valid ASTCastExpressionNode!");

      if (CB->Size() > ASTIntNode::IntBits)
        ITW = true;
      try {
        USV = static_cast<unsigned>(std::stoul(CB->AsString(), nullptr, 2));
      } catch (const std::out_of_range &E) {
        std::stringstream M;
        M << "Conversion failure from bitset to unsigned int.";
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(EN), M.str(),
            DiagLevel::ICE);
        return ASTDeclarationNode::DeclarationError(DId, M.str());
      } catch (const std::invalid_argument &E) {
        std::stringstream M;
        M << "Conversion failure from bitset to unsigned int.";
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(EN), M.str(),
            DiagLevel::ICE);
        return ASTDeclarationNode::DeclarationError(DId, M.str());
      } catch (...) {
        std::stringstream M;
        M << "Run-time exception during conversion from bitset to unsigned "
             "int.";
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(EN), M.str(),
            DiagLevel::ICE);
        return ASTDeclarationNode::DeclarationError(DId, M.str());
      }
    }
    break;
  case ASTTypeBinaryOp:
  case ASTTypeUnaryOp:
  case ASTTypeExpression:
  case ASTTypeCast:
    FromExpr = true;
    break;
  case ASTTypeCBitArray:
  case ASTTypeCBitNArray:
  case ASTTypeQubitArray:
  case ASTTypeQubitNArray:
  case ASTTypeAngleArray:
  case ASTTypeBoolArray:
  case ASTTypeMPIntegerArray:
  case ASTTypeMPDecimalArray:
  case ASTTypeLengthArray:
  case ASTTypeDurationArray:
  case ASTTypeFloatArray:
  case ASTTypeIntArray: {
    std::stringstream M;
    M << "An array cannot be assigned to a scalar.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  } break;
  case ASTTypeQubit: {
    std::stringstream M;
    M << "A Qubit cannot be assigned to a scalar.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  } break;
  case ASTTypeIdentifier: {
    const ASTIdentifierNode *IId = EN->GetIdentifier();
    assert(IId && "Could not obtain a valid ASTIdentifierNode!");

    ASTScopeController::Instance().CheckUndefined(IId);
    ASTScopeController::Instance().CheckOutOfScope(IId);

    const ASTIdentifierRefNode *IdR =
        dynamic_cast<const ASTIdentifierRefNode *>(IId);
    if (!IdR) {
      if (ASTTypeCastController::Instance().CanCast(IId->GetSymbolType(),
                                                    ASTTypeInt)) {
        ASTSymbolTableEntry *STE = ASTSymbolTable::Instance().Lookup(IId);
        assert(STE && "ASTIdentifierNode has no SymbolTable Entry!");

        switch (STE->GetValueType()) {
        case ASTTypeBool: {
          if (ASTBoolNode *BN = dynamic_cast<ASTBoolNode *>(
                  STE->GetValue()->GetValue<ASTBoolNode *>())) {
            FromValue = true;
            USV = BN->GetValue();
            CX = new ASTCastExpressionNode(BN, ASTTypeInt, ASTIntNode::IntBits);
            assert(CX && "Could not create a valid ASTCastExpressionNode!");
          }
        } break;
        case ASTTypeInt: {
          if (ASTIntNode *IN = STE->GetValue()->GetValue<ASTIntNode *>()) {
            FromValue = true;
            USV = IN->IsSigned() ? static_cast<uint32_t>(IN->GetSignedValue())
                                 : IN->GetUnsignedValue();
          }
        } break;
        case ASTTypeFloat: {
          if (ASTFloatNode *FN = STE->GetValue()->GetValue<ASTFloatNode *>()) {
            FromValue = true;
            USV = static_cast<uint32_t>(FN->GetValue());
            CX = new ASTCastExpressionNode(FN, ASTTypeInt, ASTIntNode::IntBits);
            assert(CX && "Could not create a valid ASTCastExpressionNode!");
          }
        } break;
        case ASTTypeDouble: {
          if (ASTDoubleNode *DN =
                  STE->GetValue()->GetValue<ASTDoubleNode *>()) {
            FromValue = true;
            USV = static_cast<uint32_t>(DN->GetValue());
            ITW = true;
            CX = new ASTCastExpressionNode(DN, ASTTypeInt, ASTIntNode::IntBits);
            assert(CX && "Could not create a valid ASTCastExpressionNode!");
          }
        } break;
        case ASTTypeMPInteger: {
          if (ASTMPIntegerNode *MPI =
                  STE->GetValue()->GetValue<ASTMPIntegerNode *>()) {
            FromValue = true;
            USV = MPI->ToUnsignedInt();
            CX =
                new ASTCastExpressionNode(MPI, ASTTypeInt, ASTIntNode::IntBits);
            assert(CX && "Could not create a valid ASTCastExpressionNode!");
            if (MPI->GetBits() > ASTIntNode::IntBits)
              ITW = true;
          }
        } break;
        case ASTTypeMPDecimal: {
          if (ASTMPDecimalNode *MPD =
                  STE->GetValue()->GetValue<ASTMPDecimalNode *>()) {
            FromValue = true;
            USV = static_cast<uint32_t>(MPD->ToDouble());
            CX =
                new ASTCastExpressionNode(MPD, ASTTypeInt, ASTIntNode::IntBits);
            assert(CX && "Could not create a valid ASTCastExpressionNode!");
            if (MPD->GetBits() > ASTIntNode::IntBits)
              ITW = true;
          }
        } break;
        case ASTTypeBitset: {
          if (ASTCBitNode *CBN = STE->GetValue()->GetValue<ASTCBitNode *>()) {
            FromValue = true;
            USV = ASTMathUtils::Instance().BoolVectorToIntegral<uint32_t>(
                CBN->AsVector());
            CX =
                new ASTCastExpressionNode(CBN, ASTTypeInt, ASTIntNode::IntBits);
            assert(CX && "Could not create a valid ASTCastExpressionNode!");
            if (CBN->Size() > ASTIntNode::IntBits)
              ITW = true;
          }
        } break;
        case ASTTypeAngle: {
          if (ASTAngleNode *AN = STE->GetValue()->GetValue<ASTAngleNode *>()) {
            FromValue = true;
            USV = static_cast<uint32_t>(AN->AsDouble());
            CX = new ASTCastExpressionNode(AN, ASTTypeInt, ASTIntNode::IntBits);
            assert(CX && "Could not create a valid ASTCastExpressionNode!");
            if (AN->GetBits() > ASTIntNode::IntBits)
              ITW = true;
          }
        } break;
        default: {
          std::stringstream M;
          M << "Impossible ASTIntNode Initialization from an "
            << PrintTypeEnum(ETy) << ".";
          QasmDiagnosticEmitter::Instance().EmitDiagnostic(
              DIAGLineCounter::Instance().GetLocation(IId), M.str(),
              DiagLevel::Error);
        } break;
        }
      } else {
        std::stringstream M;
        M << "Impossible cast from " << PrintTypeEnum(IId->GetSymbolType())
          << " to " << PrintTypeEnum(ASTTypeInt) << '.';
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(DId), M.str(),
            DiagLevel::Error);
        return ASTDeclarationNode::DeclarationError(DId, M.str());
      }
    } else if (ASTTypeCastController::Instance().CanCast(IdR->GetSymbolType(),
                                                         ASTTypeInt)) {
      ASTSymbolTableEntry *STE = ASTSymbolTable::Instance().Lookup(IdR);
      assert(STE && "ASTIdentifierRefNode has no SymbolTable Entry!");

      switch (STE->GetValueType()) {
      case ASTTypeBool: {
        if (ASTBoolNode *BN = dynamic_cast<ASTBoolNode *>(
                STE->GetValue()->GetValue<ASTBoolNode *>())) {
          USV = BN->GetValue();
          FromValue = true;
          CX = new ASTCastExpressionNode(BN, ASTTypeInt, ASTIntNode::IntBits);
          assert(CX && "Could not create a valid ASTCastExpressionNode!");
        }
      } break;
      case ASTTypeInt:
      case ASTTypeUInt: {
        if (ASTIntNode *IN = STE->GetValue()->GetValue<ASTIntNode *>()) {
          FromValue = true;
          USV = IN->IsSigned() ? static_cast<uint32_t>(IN->GetSignedValue())
                               : IN->GetUnsignedValue();
        }
      } break;
      case ASTTypeFloat: {
        if (ASTFloatNode *FN = STE->GetValue()->GetValue<ASTFloatNode *>()) {
          FromValue = true;
          USV = static_cast<uint32_t>(FN->GetValue());
          CX = new ASTCastExpressionNode(FN, ASTTypeInt, ASTIntNode::IntBits);
          assert(CX && "Could not create a valid ASTCastExpressionNode!");
        }
      } break;
      case ASTTypeDouble: {
        if (ASTDoubleNode *DN = STE->GetValue()->GetValue<ASTDoubleNode *>()) {
          FromValue = true;
          USV = static_cast<uint32_t>(DN->GetValue());
          CX = new ASTCastExpressionNode(DN, ASTTypeInt, ASTIntNode::IntBits);
          assert(CX && "Could not create a valid ASTCastExpressionNode!");
          ITW = true;
        }
      } break;
      case ASTTypeMPInteger:
      case ASTTypeMPUInteger: {
        if (ASTMPIntegerNode *MPI =
                STE->GetValue()->GetValue<ASTMPIntegerNode *>()) {
          FromValue = true;
          USV = MPI->ToUnsignedInt();
          CX = new ASTCastExpressionNode(MPI, ASTTypeInt, ASTIntNode::IntBits);
          assert(CX && "Could not create a valid ASTCastExpressionNode!");
          if (MPI->GetBits() > ASTIntNode::IntBits)
            ITW = true;
        }
      } break;
      case ASTTypeMPDecimal: {
        if (ASTMPDecimalNode *MPD =
                STE->GetValue()->GetValue<ASTMPDecimalNode *>()) {
          FromValue = true;
          USV = static_cast<uint32_t>(MPD->ToDouble());
          CX = new ASTCastExpressionNode(MPD, ASTTypeInt, ASTIntNode::IntBits);
          assert(CX && "Could not create a valid ASTCastExpressionNode!");
          if (MPD->GetBits() > ASTIntNode::IntBits)
            ITW = true;
        }
      } break;
      case ASTTypeBitset: {
        if (ASTCBitNode *CBN = STE->GetValue()->GetValue<ASTCBitNode *>()) {
          FromValue = true;
          USV = ASTMathUtils::Instance().BoolVectorToIntegral<uint32_t>(
              CBN->AsVector());
          CX = new ASTCastExpressionNode(CBN, ASTTypeInt, ASTIntNode::IntBits);
          assert(CX && "Could not create a valid ASTCastExpressionNode!");
          if (CBN->Size() > ASTIntNode::IntBits)
            ITW = true;
        }
      } break;
      case ASTTypeAngle: {
        if (ASTAngleNode *AN = STE->GetValue()->GetValue<ASTAngleNode *>()) {
          FromValue = true;
          USV = static_cast<uint32_t>(AN->AsDouble());
          CX = new ASTCastExpressionNode(AN, ASTTypeInt, ASTIntNode::IntBits);
          assert(CX && "Could not create a valid ASTCastExpressionNode!");
          if (AN->GetBits() > ASTIntNode::IntBits)
            ITW = true;
        }
      } break;
      default: {
        std::stringstream M;
        M << "Impossible cast to " << PrintTypeEnum(ASTTypeInt) << " from "
          << PrintTypeEnum(IdR->GetSymbolType()) << '.';
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(IId), M.str(),
            DiagLevel::Error);
        return ASTDeclarationNode::DeclarationError(DId, M.str());
      } break;
      }
    }
  } break;
  default: {
    std::stringstream M;
    M << "Impossible ASTIntNode Initialization from an " << PrintTypeEnum(ETy)
      << ".";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  } break;
  }

  ASTIntNode *IN = nullptr;

  if (ITW) {
    std::stringstream M;
    M << "Assignment may result in truncation.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(),
        DiagLevel::Warning);
  }

  if (FromArray) {
    IN = ASTBuilder::Instance().CreateASTIntNode(DId, IIN->GetUnsignedValue());
  } else if (FromValue) {
    if (CX) {
      IN = ASTBuilder::Instance().CreateASTIntNode(DId, CX, true);
      assert(IN && "Could not create a valid ASTIntNode!");
      IN->SetValue(USV);
      IN->SetConstantFolded(true);
    } else {
      IN = ASTBuilder::Instance().CreateASTIntNode(DId, USV);
      IN->SetConstantFolded(true);
    }
  } else if (FromExpr) {
    if (EN->GetASTType() == ASTTypeCast) {
      CX = dynamic_cast<const ASTCastExpressionNode *>(EN);
      assert(CX && "Could not dynamic_cast to an ASTCastExpressionNode!");
      IN = ASTBuilder::Instance().CreateASTIntNode(DId, CX, true);
    } else {
      IN = ASTBuilder::Instance().CreateASTIntNode(DId, EN, true);
    }
  } else {
    IN = ASTBuilder::Instance().CreateASTIntNode(DId, EN, true);
  }

  assert(IN && "Could not create an ASTIntNode!");

  IN->SetLocation(TK->GetLocation());
  IN->Mangle();

  ASTDeclarationNode *DN = new ASTDeclarationNode(DId, IN, ASTTypeInt, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *
ASTProductionFactory::ProductionRule_227(const ASTToken *TK,
                                         const ASTIdentifierNode *DId,
                                         const ASTStatementNode *SN) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DId && "Invalid ASTIdentifierNode argument!");
  assert(SN && "Invalid ASTStatementNode argument!");

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
          DId, ASTIntNode::IntBits, ASTTypeInt)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeInt.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(DId)) {
    std::stringstream M;
    M << "Declaration " << DId->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  const ASTExpressionNode *EN = nullptr;
  if (SN->GetASTType() == ASTTypeFunctionCallStatement) {
    const ASTFunctionCallStatementNode *FSN =
        dynamic_cast<const ASTFunctionCallStatementNode *>(SN);
    assert(FSN && "Could not dynamic_cast to an ASTFunctionCallStatementNode!");
    EN = FSN->GetFunctionCall();
  } else {
    EN = SN->GetExpression();
  }

  assert(EN &&
         "Could not obtain an ASTExpressionNode from the ASTStatementNode!");

  ASTIntNode *IN = nullptr;

  if (EN->GetASTType() == ASTTypeInt) {
    const ASTIntNode *II = dynamic_cast<const ASTIntNode *>(EN);
    assert(II && "Could not dynamic_cast to an ASTIntNode!");

    uint32_t V = II->IsSigned() ? static_cast<uint32_t>(II->GetSignedValue())
                                : II->GetUnsignedValue();
    IN = ASTBuilder::Instance().CreateASTIntNode(DId, V);
  } else {
    IN = ASTBuilder::Instance().CreateASTIntNode(DId, EN, true);
  }

  assert(IN && "Could not create an ASTIntNode!");

  IN->SetLocation(TK->GetLocation());
  IN->Mangle();

  ASTDeclarationNode *DN = new ASTDeclarationNode(DId, IN, ASTTypeInt, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTIntNode *
ASTProductionFactory::ProductionRule_800(const ASTToken *TK,
                                         const std::string &S) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(!S.empty() && "Invalid std::string argument!");

  ASTCVRQualifiers CVR(ASTTypeConst);
  ASTIntNode *RI = nullptr;
  int Base = 10;

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  ASTIdentifierNode *Id = nullptr;

  bool N = S[0] == u8'-';

  if (S.length() > 1 && std::toupper(S[S.length() - 1]) == u8'U') {
    uint32_t V = 0;
    uint64_t UI;

    std::stringstream IS;
    IS << "ast-uint-node-"
       << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
    Id = ASTBuilder::Instance().CreateASTIdentifierNode(
        IS.str(), ASTIntNode::IntBits, ASTTypeInt);
    assert(Id && "Could not create a valid ASTIdentifierNode!");

    Id->SetPolymorphicName(IS.str());
    Id->SetDeclarationContext(CTX);

    ASTSymbolTableEntry *STE = new ASTSymbolTableEntry(Id, ASTTypeInt);
    assert(STE && "Could not create a valid ASTSymbolTableEntry!");

    try {
      if (S[0] == u8'0' && (S[1] == u8'b' || S[1] == u8'B')) {
        Base = 2;
        UI = std::stoul(S.substr(2), 0, Base);
        if (UI > UINT_MAX) {
          V = 0;
          throw std::out_of_range(
              "Unsigned Integer constant exceeds UINT_MAX!");
        } else {
          V = static_cast<uint32_t>(UI);
        }
      } else if (S[0] == u8'0' && (S[1] == u8'o' || S[1] == u8'O')) {
        Base = 8;
        UI = std::stoul(S.substr(2), 0, Base);
        if (UI > UINT_MAX) {
          V = 0;
          throw std::out_of_range(
              "Unsigned Integer constant exceeds UINT_MAX!");
        } else {
          V = static_cast<uint32_t>(UI);
        }
      } else if (S[0] == u8'0' && (S[1] == u8'x' || S[1] == u8'X')) {
        Base = 16;
        UI = std::stoul(S.substr(2), 0, Base);
        if (UI > UINT_MAX) {
          V = 0;
          throw std::out_of_range(
              "Unsigned Integer constant exceeds UINT_MAX!");
        } else {
          V = static_cast<uint32_t>(UI);
        }
      } else {
        UI = std::stoul(S);
        if (UI > UINT_MAX) {
          V = 0;
          throw std::out_of_range(
              "Unsigned Integer constant exceeds UINT_MAX!");
        } else {
          V = static_cast<uint32_t>(UI);
        }
      }

      RI = new ASTIntNode(Id, V, CVR);
      assert(RI && "Could not create a valid ASTIntNode!");

      RI->SetLocation(TK->GetLocation());
      RI->SetConst();
      RI->SetConstantFolded();
      RI->Mangle();
      RI->MangleLiteral();

      STE->SetContext(CTX);
      STE->ResetValue();
      STE->SetValue(new ASTValue<>(RI, ASTTypeInt), ASTTypeInt);

      if (!ASTSymbolTable::Instance().Insert(Id, STE)) {
        std::stringstream M;
        M << "Could not insert a valid SymbolTableEntry into the SymbolTable!";
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(Id), M.str(),
            DiagLevel::Error);
        return ASTIntNode::ExpressionError(Id, M.str());
      }

      Id->SetSymbolTableEntry(STE);
      Id->SetHasSymbolTableEntry(true);

      if (ASTDeclarationContextTracker::Instance().CurrentContextIsGlobal()) {
        Id->SetGlobalScope();
        STE->SetGlobalScope();
      } else {
        Id->SetLocalScope();
        STE->SetLocalScope();
      }

      Id->SetExpression(RI);
    } catch (const std::out_of_range &E) {
      std::stringstream M;
      M << "Numeric integer constant exceeds the available bit width.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(TK), M.str(),
          DiagLevel::Warning);

      ASTMPIntegerNode *MPI = nullptr;
      unsigned Bits = 128U;
      int R = 0;

      ASTIdentifierNode *MPId = ASTIdentifierNode::MPInt.Clone();
      assert(MPId && "Could not clone a valid ASTIdentifierNode!");

      do {
        mpz_t MPZ;
        mpz_init2(MPZ, Bits);
        R = mpz_set_str(MPZ, S.c_str(), Base);
        if (R == 0) {
          MPId->SetBits(Bits);
          MPI = new ASTMPIntegerNode(MPId, Bits, MPZ, true);
          assert(MPI && "Could not create a valid ASTMPIntegerNode!");
          MPI->SetLocation(TK->GetLocation());
          MPI->Mangle();
          break;
        } else {
          Bits *= 2U;
        }
      } while (R != 0 && Bits < 2049U);

      assert(MPI && "Could not create a valid ASTMPIntegerNode!");

      RI = new ASTIntNode(Id, MPI, Bits, CVR, ASTSignbit::Unsigned);
      assert(RI && "Could not create a valid ASTIntNode!");

      RI->SetLocation(TK->GetLocation());
      RI->SetString(MPI->GetValue());
      RI->SetOverflow();
      RI->SetSignBit(Unsigned);
      RI->SetConst();
      RI->SetConstantFolded();
      RI->SetMP(true);
      RI->Mangle();

      STE->SetContext(CTX);
      STE->ResetValue();
      STE->SetValue(new ASTValue<>(RI, ASTTypeInt), ASTTypeInt);
      MPId->SetSymbolTableEntry(STE);

      if (!ASTSymbolTable::Instance().Insert(Id, STE)) {
        M.str("");
        M.clear();
        M << "Could not insert a valid SymbolTableEntry into the SymbolTable!";
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(Id), M.str(),
            DiagLevel::Error);
        return ASTIntNode::ExpressionError(Id, M.str());
      }

      Id->SetSymbolTableEntry(STE);
      Id->SetHasSymbolTableEntry(true);

      if (ASTDeclarationContextTracker::Instance().CurrentContextIsGlobal()) {
        Id->SetGlobalScope();
        STE->SetGlobalScope();
      } else {
        Id->SetLocalScope();
        STE->SetLocalScope();
      }

      Id->SetExpression(RI);
    } catch (const std::invalid_argument &E) {
      RI = nullptr;
      std::stringstream M;
      M << "Value " << S << " is not an integer constant.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(TK), M.str(),
          DiagLevel::Error);
      return ASTIntNode::ExpressionError(Id, M.str());
    } catch (...) {
      RI = nullptr;
      std::stringstream M;
      M << "Runtime exception caught.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
      return ASTIntNode::ExpressionError(Id, M.str());
    }
  } else {
    int32_t V = 0;
    int64_t SI;

    std::stringstream IS;
    IS << "ast-int-node-"
       << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
    Id = ASTBuilder::Instance().CreateASTIdentifierNode(
        IS.str(), ASTIntNode::IntBits, ASTTypeInt);
    assert(Id && "Could not create a valid ASTIdentifierNode!");

    Id->SetPolymorphicName(IS.str());
    Id->SetDeclarationContext(CTX);

    ASTSymbolTableEntry *STE = new ASTSymbolTableEntry(Id, ASTTypeInt);
    assert(STE && "Could not create a valid ASTSymbolTableEntry!");

    try {
      if (S[0] == u8'-' || S[0] == u8'+') {
        if (S[1] == u8'0' && (S[2] == u8'b' || S[2] == u8'B')) {
          Base = 2;
          SI = std::stol(S.substr(3), 0, Base);
          if (SI > INT_MAX || SI < INT_MIN) {
            V = 0;
            throw std::out_of_range(
                "Integer constant exceeds INT_MAX | INT_MIN!");
          } else {
            V = static_cast<int32_t>(SI);
            if (N)
              V = -V;
          }
        } else if (S[1] == u8'0' && (S[2] == u8'o' || S[2] == u8'O')) {
          Base = 8;
          SI = std::stol(S.substr(3), 0, Base);
          if (SI > INT_MAX || SI < INT_MIN) {
            V = 0;
            throw std::out_of_range(
                "Integer constant exceeds INT_MAX | INT_MIN!");
          } else {
            V = static_cast<int32_t>(SI);
            if (N)
              V = -V;
          }
        } else if (S[1] == u8'0' && (S[2] == u8'x' || S[2] == u8'X')) {
          Base = 16;
          SI = std::stol(S.substr(3), 0, Base);
          if (SI > INT_MAX || SI < INT_MIN) {
            V = 0;
            throw std::out_of_range(
                "Integer constant exceeds INT_MAX | INT_MIN!");
          } else {
            V = static_cast<int32_t>(SI);
            if (N)
              V = -V;
          }
        } else {
          SI = std::stol(S);
          if (SI > INT_MAX || SI < INT_MIN) {
            V = 0;
            throw std::out_of_range(
                "Integer constant exceeds INT_MAX | INT_MIN!");
          } else {
            V = static_cast<int32_t>(SI);
          }
        }
      } else if (S[0] == u8'0' && (S[1] == u8'b' || S[1] == u8'B')) {
        Base = 2;
        SI = std::stol(S.substr(2), 0, Base);
        if (SI > INT_MAX || SI < INT_MIN) {
          V = 0;
          throw std::out_of_range(
              "Integer constant exceeds INT_MAX | INT_MIN!");
        } else {
          V = static_cast<int32_t>(SI);
          if (N)
            V = -V;
        }
      } else if (S[0] == u8'0' && (S[1] == u8'o' || S[1] == u8'O')) {
        Base = 8;
        SI = std::stol(S.substr(2), 0, Base);
        if (SI > INT_MAX || SI < INT_MIN) {
          V = 0;
          throw std::out_of_range(
              "Integer constant exceeds INT_MAX | INT_MIN!");
        } else {
          V = static_cast<int32_t>(SI);
          if (N)
            V = -V;
        }
      } else if (S[0] == u8'0' && (S[1] == u8'x' || S[1] == u8'X')) {
        Base = 16;
        SI = std::stol(S.substr(2), 0, Base);
        if (SI > INT_MAX || SI < INT_MIN) {
          V = 0;
          throw std::out_of_range(
              "Integer constant exceeds INT_MAX | INT_MIN!");
        } else {
          V = static_cast<int32_t>(SI);
          if (N)
            V = -V;
        }
      } else {
        SI = std::stol(S);
        if (SI > INT_MAX || SI < INT_MIN) {
          V = 0;
          throw std::out_of_range(
              "Integer constant exceeds INT_MAX | INT_MIN!");
        } else {
          V = static_cast<int32_t>(SI);
        }
      }

      RI = new ASTIntNode(Id, V, CVR);
      assert(RI && "Could not create a valid ASTIntNode!");

      RI->SetLocation(TK->GetLocation());
      RI->SetConst();
      RI->SetConstantFolded();
      RI->Mangle();
      RI->MangleLiteral();
      RI->SetMP(true);

      STE->SetContext(CTX);
      STE->ResetValue();
      STE->SetValue(new ASTValue<>(RI, ASTTypeInt), ASTTypeInt);

      if (!ASTSymbolTable::Instance().Insert(Id, STE)) {
        std::stringstream M;
        M << "Could not insert a valid SymbolTableEntry into the SymbolTable!";
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(Id), M.str(),
            DiagLevel::Error);
        return ASTIntNode::ExpressionError(Id, M.str());
      }

      Id->SetSymbolTableEntry(STE);
      Id->SetHasSymbolTableEntry(true);
      if (ASTDeclarationContextTracker::Instance().CurrentContextIsGlobal()) {
        Id->SetGlobalScope();
        STE->SetGlobalScope();
      } else {
        Id->SetLocalScope();
        STE->SetLocalScope();
      }

      Id->SetExpression(RI);
    } catch (const std::out_of_range &E) {
      std::stringstream M;
      M << "Numeric integer constant exceeds the available bit width.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(TK), M.str(),
          DiagLevel::Warning);

      ASTMPIntegerNode *MPI = nullptr;
      unsigned Bits = 128U;
      int R = 0;

      ASTIdentifierNode *MPId = ASTIdentifierNode::MPInt.Clone();
      assert(MPId && "Could not clone a valid ASTIdentifierNode!");
      MPId->SetLocation(TK->GetLocation());

      do {
        mpz_t MPZ;
        mpz_init2(MPZ, Bits);
        R = mpz_set_str(MPZ, S.c_str(), Base);
        if (R == 0) {
          MPId->SetBits(Bits);
          MPI = new ASTMPIntegerNode(MPId, Bits, MPZ, false);
          assert(MPI && "Could not create a valid ASTMPIntegerNode!");
          MPI->SetLocation(TK->GetLocation());
          MPI->Mangle();
          break;
        } else {
          mpz_clear(MPZ);
          Bits *= 2U;
        }
      } while (R != 0 && Bits < 2049U);

      assert(MPI && "Could not create a valid ASTMPIntegerNode!");

      RI = new ASTIntNode(Id, MPI, Bits, CVR, ASTSignbit::Signed);
      assert(RI && "Could not create a valid ASTIntNode!");

      RI->SetLocation(TK->GetLocation());
      RI->SetString(MPI->GetValue());
      RI->SetOverflow();
      RI->SetSignBit(Signed);
      RI->SetConst();
      RI->SetConstantFolded();
      RI->SetMP(true);
      RI->Mangle();

      STE->SetContext(CTX);
      STE->ResetValue();
      STE->SetValue(new ASTValue<>(RI, ASTTypeInt), ASTTypeInt);
      MPId->SetSymbolTableEntry(STE);

      if (!ASTSymbolTable::Instance().Insert(Id, STE)) {
        M.str("");
        M.clear();
        M << "Could not insert a valid SymbolTableEntry into the SymbolTable!";
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(TK), M.str(),
            DiagLevel::Error);
        return ASTIntNode::ExpressionError(Id, M.str());
      }

      Id->SetSymbolTableEntry(STE);
      Id->SetHasSymbolTableEntry(true);
      if (ASTDeclarationContextTracker::Instance().CurrentContextIsGlobal()) {
        Id->SetGlobalScope();
        STE->SetGlobalScope();
      } else {
        Id->SetLocalScope();
        STE->SetLocalScope();
      }

      Id->SetExpression(RI);
    } catch (const std::invalid_argument &E) {
      RI = nullptr;
      std::stringstream M;
      M << "Value " << S << " is not an integer constant.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(TK), M.str(),
          DiagLevel::Error);
      return ASTIntNode::ExpressionError(Id, M.str());
    } catch (...) {
      RI = nullptr;
      std::stringstream M;
      M << "Runtime exception caught.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
      return ASTIntNode::ExpressionError(Id, M.str());
    }
  }

  return RI;
}

ASTDoubleNode *
ASTProductionFactory::ProductionRule_801(const ASTToken *TK,
                                         const std::string &RS) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(!RS.empty() && "Invalid std::string argument!");

  ASTDoubleNode *RD = nullptr;
  ASTSymbolTableEntry *STE = nullptr;

  std::stringstream IS;
  IS << "ast-double-node-"
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      IS.str(), ASTDoubleNode::DoubleBits, ASTTypeDouble);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  Id->SetPolymorphicName(IS.str());
  ASTCVRQualifiers CVR(ASTTypeConst);

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  try {
    double D = std::stod(RS);
    RD = new ASTDoubleNode(Id, D, CVR);
    assert(RD && "Could not create a valid ASTDoubleNode!");
    RD->SetConst();
    RD->SetConstantFolded();
  } catch (const std::out_of_range &E) {
    std::stringstream M;
    M << "Numeric floating-point constant exceeds the available bit width.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(), M.str(), DiagLevel::Warning);

    int R = 0;
    int Bits = 128;
    ASTMPDecimalNode *MPD = nullptr;
    ASTIdentifierNode *MPId = ASTIdentifierNode::MPDec.Clone();
    assert(MPId && "Could not clone a valid ASTIdentifierNode!");
    MPId->SetLocation(TK->GetLocation());

    do {
      mpfr_t MPV;
      mpfr_init2(MPV, Bits);
      R = mpfr_strtofr(MPV, RS.c_str(), NULL, 10, MPFR_RNDN);
      if (R == 0) {
        MPId->SetBits(Bits);
        MPD = new ASTMPDecimalNode(MPId, Bits, MPV);
        assert(MPD && "Could not create a valid ASTMPDecimalNode!");

        MPD->SetLocation(TK->GetLocation());
        MPD->Mangle();
        break;
      } else {
        mpfr_clear(MPV);
        Bits *= 2;
      }
    } while (R != 0 && Bits < 2049);

    assert(MPD && "Could not create a valid ASTMPDecimalNode!");

    RD = new ASTDoubleNode(Id, MPD, CVR);
    assert(RD && "Could not create a valid ASTDoubleNode!");

    RD->SetLocation(TK->GetLocation());
    RD->SetString(RS);
    RD->SetMP(true);
    RD->SetConst();
    RD->SetConstantFolded();
    RD->Mangle();

    STE = new ASTSymbolTableEntry(Id, ASTTypeDouble);
    assert(STE && "Could not create a valid ASTSymbolTableEntry!");

    STE->SetContext(CTX);
    STE->ResetValue();
    STE->SetValue(new ASTValue<>(RD, ASTTypeDouble), ASTTypeDouble);
    MPId->SetSymbolTableEntry(STE);

    if (!ASTSymbolTable::Instance().Insert(Id, STE)) {
      M.str("");
      M.clear();
      M << "Could not insert a valid SymbolTableEntry into the SymbolTable!";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(TK), M.str(),
          DiagLevel::Error);
      return ASTDoubleNode::ExpressionError(Id, M.str());
    }

    Id->SetSymbolTableEntry(STE);
    Id->SetHasSymbolTableEntry(true);
    if (ASTDeclarationContextTracker::Instance().CurrentContextIsGlobal()) {
      Id->SetGlobalScope();
      STE->SetGlobalScope();
    } else {
      Id->SetLocalScope();
      STE->SetLocalScope();
    }
  } catch (const std::invalid_argument &E) {
    std::stringstream M;
    M << RS << " is not a valid decimal number representation.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(), M.str(), DiagLevel::Error);
    return ASTDoubleNode::ExpressionError(Id, M.str());
  }

  if (!RD) {
    std::stringstream M;
    M << "Failure instantiating a decimal value from numeric literal constant.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(), M.str(), DiagLevel::Error);
    return ASTDoubleNode::ExpressionError(Id, M.str());
  }

  STE = new ASTSymbolTableEntry(Id, ASTTypeDouble);
  assert(STE && "Could not create a valid ASTSymbolTableEntry!");

  RD->SetString(RS);
  RD->SetConst();
  RD->SetConstantFolded();
  RD->Mangle();
  RD->MangleLiteral();

  STE->ResetValue();
  STE->SetValue(new ASTValue<>(RD, ASTTypeDouble), ASTTypeDouble);

  if (!ASTSymbolTable::Instance().Insert(Id, STE)) {
    std::stringstream M;
    M << "Could not insert a valid SymbolTableEntry into the SymbolTable!";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTDoubleNode::ExpressionError(Id, M.str());
  }

  Id->SetSymbolTableEntry(STE);
  Id->SetHasSymbolTableEntry(true);
  if (ASTDeclarationContextTracker::Instance().CurrentContextIsGlobal()) {
    Id->SetGlobalScope();
    STE->SetGlobalScope();
  } else {
    Id->SetLocalScope();
    STE->SetLocalScope();
  }

  Id->SetExpression(RD);
  return RD;
}

ASTIntNode *ASTProductionFactory::ProductionRule_802(const ASTToken *TK,
                                                     ASTType ITy) const {
  assert(TK && "Invalid ASTToken argument!");
  assert((ITy == ASTTypeInt || ITy == ASTTypeUInt) &&
         "Wrong ASTType for ASTIntNode ProductionRule!");

  if (ITy == ASTTypeInt) {
    std::stringstream S;
    S << "ast-int-type-param-"
      << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

    ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
        S.str(), ASTIntNode::IntBits, ASTTypeInt);
    assert(Id && "Could not create a valid ASTIdentifierNode!");

    ASTIntNode *RI = ASTBuilder::Instance().CreateASTIntNode(Id, int32_t(0));
    assert(RI && "Could not create a valid ASTIntNode!");
    assert(RI->IsSigned() && "Wrong Signbit for Signed ASTIntNode!");

    RI->SetLocation(TK->GetLocation());
    RI->Mangle();

    ASTParameter *P = new ASTParameter(Id, RI);
    assert(P && "Could not create a valid ASTParameter!");

    P->SetLocation(TK->GetLocation());
    ASTParameterBuilder::Instance().Append(P);
    return RI;
  }

  std::stringstream S;
  S << "ast-uint-type-param-"
    << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      S.str(), ASTIntNode::IntBits, ASTTypeInt);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  ASTIntNode *RI = ASTBuilder::Instance().CreateASTIntNode(Id, uint32_t(0U));
  assert(RI && "Could not create a valid ASTIntNode!");
  assert(!RI->IsSigned() && "Wrong Signbit for Unsigned ASTIntNode!");

  RI->SetLocation(TK->GetLocation());
  RI->Mangle();

  ASTParameter *P = new ASTParameter(Id, RI);
  assert(P && "Could not create a valid ASTParameter!");

  P->SetLocation(TK->GetLocation());
  ASTParameterBuilder::Instance().Append(P);
  return RI;
}

ASTFloatNode *
ASTProductionFactory::ProductionRule_803(const ASTToken *TK) const {
  assert(TK && "Invalid ASTToken argument!");

  std::stringstream S;
  S << "ast-float-type-param-"
    << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      S.str(), ASTFloatNode::FloatBits, ASTTypeFloat);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  ASTFloatNode *RF = ASTBuilder::Instance().CreateASTFloatNode(Id, 0.0f);
  assert(RF && "Could not create a valid ASTFloatNode!");

  RF->SetLocation(TK->GetLocation());
  RF->Mangle();
  ASTParameter *P = new ASTParameter(Id, RF);
  assert(P && "Could not create a valid ASTParameter!");

  P->SetLocation(TK->GetLocation());
  ASTParameterBuilder::Instance().Append(P);
  return RF;
}

ASTMPIntegerNode *ASTProductionFactory::ProductionRule_804(const ASTToken *TK,
                                                           const ASTIntNode *II,
                                                           ASTType ITy) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(II && "Invalid ASTIntNode argument!");
  assert((ITy == ASTTypeMPInteger || ITy == ASTTypeMPUInteger) &&
         "Wrong ASTType for ASTMPIntegerNode Production Rule!");

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(II);
  if (ASTIdentifierNode::InvalidBits(Bits)) {
    std::stringstream M;
    M << "Invalid number of bits for ASTMPInteger expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(II), M.str(), DiagLevel::Error);
    return ASTMPIntegerNode::ExpressionError(M.str());
  }

  std::stringstream S;
  S << "ast-mpinteger-type-param-"
    << DIAGLineCounter::Instance().GetIdentifierLocation();
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      S.str(), Bits, ASTTypeMPInteger);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  ASTMPIntegerNode *MPI = ASTBuilder::Instance().CreateASTMPIntegerNode(
      Id, Bits, ITy == ASTTypeMPUInteger);
  assert(MPI && "Could not create a valid ASTMPIntegerNode!");

  MPI->SetLocation(TK->GetLocation());
  MPI->Mangle();
  ASTParameter *P = new ASTParameter(Id, MPI);
  assert(P && "Could not create a valid ASTParameter!");

  P->SetLocation(TK->GetLocation());
  ASTParameterBuilder::Instance().Append(P);
  return MPI;
}

ASTMPIntegerNode *ASTProductionFactory::ProductionRule_805(
    const ASTToken *TK, const ASTIdentifierNode *IId, ASTType ITy) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(IId && "Invalid ASTIdentifierNode argument!");
  assert((ITy == ASTTypeMPInteger || ITy == ASTTypeMPUInteger) &&
         "Wrong ASTType for ASTMPIntegerNode Production Rule!");

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(IId);
  if (ASTIdentifierNode::InvalidBits(Bits)) {
    std::stringstream M;
    M << "Invalid number of bits for ASTMPInteger expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(IId), M.str(),
        DiagLevel::Error);
    return ASTMPIntegerNode::ExpressionError(M.str());
  }

  std::stringstream S;
  S << "ast-mpinteger-type-param-"
    << DIAGLineCounter::Instance().GetIdentifierLocation();
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      S.str(), Bits, ASTTypeMPInteger);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  ASTMPIntegerNode *MPI = ASTBuilder::Instance().CreateASTMPIntegerNode(
      Id, Bits, ITy == ASTTypeMPUInteger);
  assert(MPI && "Could not create a valid ASTMPIntegerNode!");

  MPI->SetLocation(TK->GetLocation());
  MPI->Mangle();
  ASTParameter *P = new ASTParameter(Id, MPI);
  assert(P && "Could not create a valid ASTParameter!");

  P->SetLocation(TK->GetLocation());
  ASTParameterBuilder::Instance().Append(P);
  return MPI;
}

ASTMPDecimalNode *
ASTProductionFactory::ProductionRule_806(const ASTToken *TK,
                                         const ASTIntNode *II) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(II && "Invalid ASTIntNode argument!");

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(II);
  if (ASTIdentifierNode::InvalidBits(Bits)) {
    std::stringstream M;
    M << "Invalid number of bits for complex expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(II), M.str(), DiagLevel::Error);
    return ASTMPDecimalNode::ExpressionError(M.str());
  }

  std::stringstream S;
  S << "ast-mpdecimal-type-param-"
    << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      S.str(), Bits, ASTTypeMPDecimal);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  ASTMPDecimalNode *MPD =
      ASTBuilder::Instance().CreateASTMPDecimalNode(Id, Bits);
  assert(MPD && "Could not create a valid ASTMPDecimalNode!");

  MPD->SetLocation(TK->GetLocation());
  MPD->Mangle();

  ASTParameter *P = new ASTParameter(Id, MPD);
  assert(P && "Could not create a valid ASTParameter!");

  P->SetLocation(TK->GetLocation());
  ASTParameterBuilder::Instance().Append(P);
  return MPD;
}

ASTMPDecimalNode *
ASTProductionFactory::ProductionRule_807(const ASTToken *TK,
                                         const ASTIdentifierNode *IId) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(IId && "Invalid ASTIdentifierNode argument!");

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(IId);
  if (ASTIdentifierNode::InvalidBits(Bits)) {
    std::stringstream M;
    M << "Invalid number of bits for complex expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(IId), M.str(),
        DiagLevel::Error);
    return ASTMPDecimalNode::ExpressionError(M.str());
  }

  std::stringstream S;
  S << "ast-mpdecimal-type-param-"
    << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      S.str(), Bits, ASTTypeMPDecimal);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  ASTMPDecimalNode *MPD =
      ASTBuilder::Instance().CreateASTMPDecimalNode(Id, Bits);
  assert(MPD && "Could not create a valid ASTMPDecimalNode!");

  MPD->SetLocation(TK->GetLocation());
  MPD->Mangle();

  ASTParameter *P = new ASTParameter(Id, MPD);
  assert(P && "Could not create a valid ASTParameter!");

  P->SetLocation(TK->GetLocation());
  ASTParameterBuilder::Instance().Append(P);
  return MPD;
}

ASTMPComplexNode *
ASTProductionFactory::ProductionRule_808(const ASTToken *TK,
                                         const ASTIntNode *II) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(II && "Invalid ASTIntNode argument!");

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(II);
  if (ASTIdentifierNode::InvalidBits(Bits)) {
    std::stringstream M;
    M << "Invalid number of bits for complex expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(II), M.str(), DiagLevel::Error);
    return ASTMPComplexNode::ExpressionError(M.str());
  }

  std::stringstream S;
  S << "ast-mpcomplex-type-param-"
    << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      S.str(), Bits, ASTTypeMPComplex);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());

  ASTMPComplexNode *MPC =
      ASTBuilder::Instance().CreateASTMPComplexNode(Id, Bits);
  assert(MPC && "Could not create a valid ASTMPComplexNode!");

  MPC->SetLocation(TK->GetLocation());
  MPC->Mangle();

  ASTParameter *P = new ASTParameter(Id, MPC);
  assert(P && "Could not create a valid ASTParameter!");

  P->SetLocation(TK->GetLocation());
  ASTParameterBuilder::Instance().Append(P);
  return MPC;
}

ASTMPComplexNode *
ASTProductionFactory::ProductionRule_809(const ASTToken *TK,
                                         const ASTIdentifierNode *IId) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(IId && "Invalid ASTIdentifierNode argument!");

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(IId);
  if (ASTIdentifierNode::InvalidBits(Bits)) {
    std::stringstream M;
    M << "Invalid number of bits for complex expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(IId), M.str(),
        DiagLevel::Error);
    return ASTMPComplexNode::ExpressionError(M.str());
  }

  std::stringstream S;
  S << "ast-mpcomplex-type-param-"
    << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      S.str(), Bits, ASTTypeMPComplex);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());

  ASTMPComplexNode *MPC =
      ASTBuilder::Instance().CreateASTMPComplexNode(Id, Bits);
  assert(MPC && "Could not create a valid ASTMPComplexNode!");

  MPC->SetLocation(TK->GetLocation());
  MPC->Mangle();

  ASTParameter *P = new ASTParameter(Id, MPC);
  assert(P && "Could not create a valid ASTParameter!");

  P->SetLocation(TK->GetLocation());
  ASTParameterBuilder::Instance().Append(P);
  return MPC;
}

ASTEllipsisNode *
ASTProductionFactory::ProductionRule_810(const ASTToken *TK) const {
  assert(TK && "Invalid ASTToken argument!");

  std::stringstream ES;
  ES << "ast-ellipsis-"
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      ES.str(), ASTEllipsisNode::EllipsisBits, ASTTypeEllipsis);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());
  Id->SetPolymorphicName("ellipsis");

  ASTEllipsisNode *ELN = ASTBuilder::Instance().CreateASTEllipsisNode(Id);
  assert(ELN && "Could not create a valid ASTEllipsisNode!");

  ELN->SetLocation(TK->GetLocation());
  ELN->Mangle();
  return ELN;
}

ASTStringNode *
ASTProductionFactory::ProductionRule_811(const ASTToken *TK,
                                         const std::string &S) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(!S.empty() && "Invalid std::string argument!");

  std::stringstream SS;
  SS << "ast-string-literal-"
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTIdentifierNode *Id = new ASTIdentifierNode(SS.str(), ASTTypeStringLiteral,
                                                S.length() * CHAR_BIT);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());
  Id->SetPolymorphicName(S);

  ASTStringNode *SN = new ASTStringNode(Id, S, true);
  assert(SN && "Could not create a valid ASTStringNode!");

  SN->SetLocation(TK->GetLocation());
  SN->Mangle();
  return SN;
}

ASTStringNode *
ASTProductionFactory::ProductionRule_812(const ASTToken *TK,
                                         const std::string &TS) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(!TS.empty() && "Invalid std::string argument!");

  std::stringstream TSS;
  TSS << "ast-time-unit-"
      << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTIdentifierNode *Id = new ASTIdentifierNode(TSS.str(), ASTTypeStringLiteral,
                                                TS.length() * CHAR_BIT);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  Id->SetPolymorphicName(TK->GetString());
  Id->SetLocation(TK->GetLocation());

  ASTStringNode *TSN = new ASTStringNode(Id, TK->GetString(), true);
  assert(TSN && "Could not create a valid TimeUnit ASTStringNode!");

  TSN->SetLocation(TK->GetLocation());
  TSN->Mangle();
  return TSN;
}

ASTBoolNode *
ASTProductionFactory::ProductionRule_813(const ASTToken *TK) const {
  assert(TK && "Invalid ASTToken argument!");

  if (TK->GetString() != "true" && TK->GetString() != "false") {
    std::stringstream M;
    M << "A boolean only accepts 'true' and 'false' as literals.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTBoolNode::ExpressionError(M.str());
  }

  ASTBoolNode *BN;

  if (TK->GetString() == "true")
    BN = new ASTBoolNode(true);
  else
    BN = new ASTBoolNode(false);
  assert(BN && "Could not create a valid ASTBoolNode!");

  BN->SetLocation(TK->GetLocation());
  BN->Mangle();
  return BN;
}

ASTStringNode *ASTProductionFactory::ProductionRule_814(const ASTToken *TK,
                                                        ASTType QTy) const {
  assert(TK && "Invalid ASTToken argument!");
  assert((QTy == ASTTypeBoundQubit || QTy == ASTTypeUnboundQubit) ||
         "Invalid ASTType for Bound/Unbound Qubit!");

  if (QTy == ASTTypeBoundQubit &&
      !ASTStringUtils::Instance().IsBoundQubit(TK->GetString())) {
    std::stringstream M;
    M << "'" << TK->GetString() << "' is not a Bound Qubit Identifier.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTStringNode::ExpressionError(M.str());
  }

  ASTStringNode *QSN = new ASTStringNode(TK->GetString());
  assert(QSN && "Could not create a valid ASTStringNode!");

  if (const ASTSymbolTableEntry *STE =
          ASTSymbolTable::Instance().FindQubit(TK->GetString())) {
    const ASTIdentifierNode *QId = STE->GetIdentifier();
    assert(QId && "Could not obtain a valid ASTIdentifierNode!");

    const_cast<ASTIdentifierNode *>(QId)->SetLocation(TK->GetLocation());

    switch (STE->GetValueType()) {
    case ASTTypeQubit: {
      ASTQubitNode *QN = STE->GetValue()->GetValue<ASTQubitNode *>();
      assert(QN &&
             "Could not obtain a valid ASTQubitNode from the SymbolTable!");
      QN->Mangle();
    } break;
    case ASTTypeQubitContainer: {
      ASTQubitContainerNode *QCN =
          STE->GetValue()->GetValue<ASTQubitContainerNode *>();
      assert(QCN && "Could not obtain a valid ASTQubitContainerNode from the "
                    "SymbolTable!");
      QCN->Mangle();
    } break;
    case ASTTypeQubitContainerAlias: {
      ASTQubitContainerAliasNode *QCAN =
          STE->GetValue()->GetValue<ASTQubitContainerAliasNode *>();
      assert(QCAN && "Could not obtain a valid ASTQubitContainerAliasNode from "
                     "the SymbolTable!");
      QCAN->Mangle();
    } break;
    default:
      break;
    }
  }

  QSN->SetLocation(TK->GetLocation());
  QSN->Mangle();
  return QSN;
}

ASTStringNode *ASTProductionFactory::ProductionRule_815(
    const ASTToken *TK, const ASTArraySubscriptNode *ASN, ASTType QTy) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(ASN && "Invalid ASTArraySubscriptNode argument!");
  assert((QTy == ASTTypeBoundQubit || QTy == ASTTypeUnboundQubit) &&
         "Invalid ASTType for Bound/Unbound Qubit!");

  if (QTy == ASTTypeBoundQubit &&
      !ASTStringUtils::Instance().IsBoundQubit(TK->GetString())) {
    std::stringstream M;
    M << "'" << TK->GetString() << "' is not a Bound Qubit Identifier.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTStringNode::ExpressionError(M.str());
  }

  std::stringstream QS;
  QS << TK->GetString() << '[' << ASN->GetUnsignedIndexValue() << ']';

  ASTStringNode *QSN = new ASTStringNode(QS.str());
  assert(QSN && "Could not create a valid ASTStringNode!");

  if (const ASTSymbolTableEntry *STE =
          ASTSymbolTable::Instance().FindQubit(QS.str())) {
    switch (STE->GetValueType()) {
    case ASTTypeQubit: {
      ASTQubitNode *QN = STE->GetValue()->GetValue<ASTQubitNode *>();
      assert(QN &&
             "Could not obtain a valid ASTQubitNode from the SymbolTable!");
      QN->Mangle();
    } break;
    case ASTTypeQubitContainer: {
      ASTQubitContainerNode *QCN =
          STE->GetValue()->GetValue<ASTQubitContainerNode *>();
      assert(QCN && "Could not obtain a valid ASTQubitContainerNode from the "
                    "SymbolTable!");
      QCN->Mangle();
    } break;
    case ASTTypeQubitContainerAlias: {
      ASTQubitContainerAliasNode *QCAN =
          STE->GetValue()->GetValue<ASTQubitContainerAliasNode *>();
      assert(QCAN && "Could not obtain a valid ASTQubitContainerAliasNode from "
                     "the SymbolTable!");
      QCAN->Mangle();
    } break;
    default:
      break;
    }
  }

  QS.str("");
  QS.clear();
  QS << TK->GetString() << ':' << ASN->GetUnsignedIndexValue();

  if (const ASTSymbolTableEntry *STE =
          ASTSymbolTable::Instance().FindQubit(QS.str())) {
    switch (STE->GetValueType()) {
    case ASTTypeQubit: {
      ASTQubitNode *QN = STE->GetValue()->GetValue<ASTQubitNode *>();
      assert(QN &&
             "Could not obtain a valid ASTQubitNode from the SymbolTable!");
      QN->Mangle();
    } break;
    case ASTTypeQubitContainer: {
      ASTQubitContainerNode *QCN =
          STE->GetValue()->GetValue<ASTQubitContainerNode *>();
      assert(QCN && "Could not obtain a valid ASTQubitContainerNode from the "
                    "SymbolTable!");
      QCN->Mangle();
    } break;
    case ASTTypeQubitContainerAlias: {
      ASTQubitContainerAliasNode *QCAN =
          STE->GetValue()->GetValue<ASTQubitContainerAliasNode *>();
      assert(QCAN && "Could not obtain a valid ASTQubitContainerAliasNode from "
                     "the SymbolTable!");
      QCAN->Mangle();
    } break;
    default:
      break;
    }
  }

  QSN->SetLocation(TK->GetLocation());
  QSN->Mangle();
  return QSN;
}

ASTStringNode *ASTProductionFactory::ProductionRule_816(const ASTToken *ITK,
                                                        const ASTToken *STK,
                                                        bool D) const {
  assert(ITK && "Invalid ASTToken argument!");
  assert(STK && "Invalid ASTToken argument!");

  if (STK->GetString().find(u8' ') != std::string::npos) {
    std::stringstream M;
    M << "Malformed aggregate type element suffix.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(STK), M.str(),
        DiagLevel::Error);
    return ASTStringNode::ExpressionError(M.str());
  }

  std::stringstream S;
  if (D)
    S << ITK->GetString() << '.' << STK->GetString();
  else
    S << ITK->GetString() << STK->GetString();

  ASTStringNode *SN = new ASTStringNode(S.str());
  assert(SN && "Could not create a valid ASTStringNode!");

  SN->SetLocation(STK->GetLocation());
  SN->Mangle();
  return SN;
}

ASTCBitNode *
ASTProductionFactory::ProductionRule_817(const ASTToken *TK,
                                         const ASTIdentifierNode *IId) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(IId && "Invalid ASTIdentifierNode argument!");

  ASTScopeController::Instance().CheckIdentifier(IId);

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(IId);
  if (ASTIdentifierNode::InvalidBits(Bits)) {
    std::stringstream M;
    M << "Invalid number of bits for complex expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(IId), M.str(),
        DiagLevel::Error);
    return ASTCBitNode::ExpressionError(M.str());
  }

  std::stringstream S;
  S << "ast-cbit-type-param-"
    << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      S.str(), Bits, ASTTypeBitset);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  ASTCBitNode *CBN =
      ASTBuilder::Instance().CreateASTCBitNode(Id, Id->GetBits(), 0UL);
  assert(CBN && "Could not create an ASTCBitNode!");

  CBN->SetLocation(TK->GetLocation());
  CBN->Mangle();
  ASTCBitNodeMap::Instance().Insert(Id, CBN);

  ASTParameter *P = new ASTParameter(Id, CBN);
  assert(P && "Could not create a valid ASTParameter!");

  P->SetLocation(TK->GetLocation());
  ASTParameterBuilder::Instance().Append(P);
  return CBN;
}

ASTCBitNode *
ASTProductionFactory::ProductionRule_817(const ASTToken *TK,
                                         const ASTIntNode *II) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(II && "Invalid ASTIntNode argument!");

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(II);
  if (ASTIdentifierNode::InvalidBits(Bits)) {
    std::stringstream M;
    M << "Invalid number of bits for bit expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(II), M.str(), DiagLevel::Error);
    return ASTCBitNode::ExpressionError(M.str());
  }

  std::stringstream S;
  S << "ast-cbit-type-param-"
    << DIAGLineCounter::Instance().GetIdentifierLocation();
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      S.str(), Bits, ASTTypeBitset);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  ASTCBitNode *CBN =
      ASTBuilder::Instance().CreateASTCBitNode(Id, Id->GetBits(), 0UL);
  assert(CBN && "Could not create an ASTCBitNode!");

  CBN->SetLocation(TK->GetLocation());
  CBN->Mangle();
  ASTCBitNodeMap::Instance().Insert(Id, CBN);

  ASTParameter *P = new ASTParameter(Id, CBN);
  assert(P && "Could not create a valid ASTParameter!");

  P->SetLocation(TK->GetLocation());
  ASTParameterBuilder::Instance().Append(P);
  return CBN;
}

ASTCBitNode *
ASTProductionFactory::ProductionRule_817(const ASTToken *TK) const {
  assert(TK && "Invalid ASTToken argument!");

  std::stringstream S;
  S << "ast-cbit-type-param-"
    << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      S.str(), 1U, ASTTypeBitset);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  ASTCBitNode *CBN =
      ASTBuilder::Instance().CreateASTCBitNode(Id, Id->GetBits(), 0UL);
  assert(CBN && "Could not create an ASTCBitNode!");

  CBN->SetLocation(TK->GetLocation());
  CBN->Mangle();
  ASTCBitNodeMap::Instance().Insert(Id, CBN);

  ASTParameter *P = new ASTParameter(Id, CBN);
  assert(P && "Could not create a valid ASTParameter!");

  P->SetLocation(TK->GetLocation());
  ASTParameterBuilder::Instance().Append(P);
  return CBN;
}

ASTAngleNode *
ASTProductionFactory::ProductionRule_818(const ASTToken *TK,
                                         const ASTIdentifierNode *IId) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(IId && "Invalid ASTIdentifierNode argument!");

  ASTScopeController::Instance().CheckIdentifier(IId);

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(IId);
  if (ASTIdentifierNode::InvalidBits(Bits)) {
    std::stringstream M;
    M << "Invalid number of bits for angle expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(IId), M.str(),
        DiagLevel::Error);
    return ASTAngleNode::ExpressionError(M.str());
  }

  std::stringstream S;
  S << "ast-angle-type-param-"
    << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      S.str(), Bits, ASTTypeAngle);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  ASTAngleType ATy = ASTAngleNode::DetermineAngleType(Id->GetName());
  ASTAngleNode *ANG = ASTBuilder::Instance().CreateASTAngleNode(Id, ATy, Bits);
  assert(ANG && "Could not create a valid ASTAngleNode!");

  ANG->SetLocation(TK->GetLocation());
  ANG->Mangle();
  ASTSymbolTable::Instance().TransferAngleToLSTM(Id, Bits, ASTTypeAngle);

  ASTParameter *P = new ASTParameter(Id, ANG);
  assert(P && "Could not create a valid ASTParameter!");

  P->SetLocation(TK->GetLocation());
  ASTParameterBuilder::Instance().Append(P);
  return ANG;
}

ASTAngleNode *
ASTProductionFactory::ProductionRule_818(const ASTToken *TK,
                                         const ASTIntNode *II) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(II && "Invalid ASTIntNode argument!");

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(II);
  if (ASTIdentifierNode::InvalidBits(Bits)) {
    std::stringstream M;
    M << "Invalid number of bits for angle expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(II), M.str(), DiagLevel::Error);
    return ASTAngleNode::ExpressionError(M.str());
  }

  std::stringstream S;
  S << "ast-angle-type-param-"
    << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      S.str(), Bits, ASTTypeAngle);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  ASTAngleType ATy = ASTAngleNode::DetermineAngleType(Id->GetName());
  ASTAngleNode *ANG = ASTBuilder::Instance().CreateASTAngleNode(Id, ATy, Bits);
  assert(ANG && "Could not create a valid ASTAngleNode!");

  ANG->SetLocation(TK->GetLocation());
  ANG->Mangle();
  ASTSymbolTable::Instance().TransferAngleToLSTM(Id, Bits, ASTTypeAngle);

  ASTParameter *P = new ASTParameter(Id, ANG);
  assert(P && "Could not create a valid ASTParameter!");

  P->SetLocation(TK->GetLocation());
  ASTParameterBuilder::Instance().Append(P);
  return ANG;
}

ASTAngleNode *
ASTProductionFactory::ProductionRule_818(const ASTToken *TK) const {
  assert(TK && "Invalid ASTToken argument!");

  std::stringstream S;
  S << "ast-angle-type-param-"
    << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      S.str(), ASTAngleNode::AngleBits, ASTTypeAngle);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  ASTAngleType ATy = ASTAngleNode::DetermineAngleType(Id->GetName());
  ASTAngleNode *ANG = ASTBuilder::Instance().CreateASTAngleNode(
      Id, ATy, ASTAngleNode::AngleBits);
  assert(ANG && "Could not create a valid ASTAngleNode!");

  ANG->SetLocation(TK->GetLocation());
  ANG->Mangle();
  ASTSymbolTable::Instance().TransferAngleToLSTM(Id, ASTAngleNode::AngleBits,
                                                 ASTTypeAngle);

  ASTParameter *P = new ASTParameter(Id, ANG);
  assert(P && "Could not create a valid ASTParameter!");

  P->SetLocation(TK->GetLocation());
  ASTParameterBuilder::Instance().Append(P);
  return ANG;
}

ASTQubitContainerNode *
ASTProductionFactory::ProductionRule_819(const ASTToken *TK,
                                         const ASTIdentifierNode *IId) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(IId && "Invalid ASTIdentifierNode argument!");

  ASTScopeController::Instance().CheckIdentifier(IId);

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(IId);
  if (ASTIdentifierNode::InvalidBits(Bits)) {
    std::stringstream M;
    M << "Invalid number of bits for qubit expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(IId), M.str(),
        DiagLevel::Error);
    return ASTQubitContainerNode::ExpressionError(M.str());
  }

  std::stringstream S;
  S << "ast-qubit-type-param-"
    << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      S.str(), Bits, ASTTypeQubitContainer);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  ASTQubitContainerNode *QCN =
      ASTBuilder::Instance().CreateASTQubitContainerNode(Id, Bits);
  assert(QCN && "Could not create a valid ASTQubitContainerNode!");

  QCN->SetLocation(TK->GetLocation());
  QCN->LocalFunctionArgument();
  QCN->Mangle();

  ASTParameter *P = new ASTParameter(Id, QCN);
  assert(P && "Could not create a valid ASTParameter!");

  P->SetLocation(TK->GetLocation());
  ASTParameterBuilder::Instance().Append(P);
  return QCN;
}

ASTQubitContainerNode *
ASTProductionFactory::ProductionRule_819(const ASTToken *TK,
                                         const ASTIntNode *II) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(II && "Invalid ASTIntNode argument!");

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(II);
  if (ASTIdentifierNode::InvalidBits(Bits)) {
    std::stringstream M;
    M << "Invalid number of bits for qubit expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(II), M.str(), DiagLevel::Error);
    return ASTQubitContainerNode::ExpressionError(M.str());
  }

  std::stringstream S;
  S << "ast-qubit-type-param-"
    << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      S.str(), Bits, ASTTypeQubitContainer);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  ASTQubitContainerNode *QCN =
      ASTBuilder::Instance().CreateASTQubitContainerNode(Id, Bits);
  assert(QCN && "Could not create a valid ASTQubitContainerNode!");

  QCN->SetLocation(TK->GetLocation());
  QCN->LocalFunctionArgument();
  QCN->Mangle();

  ASTParameter *P = new ASTParameter(Id, QCN);
  assert(P && "Could not create a valid ASTParameter!");

  P->SetLocation(TK->GetLocation());
  ASTParameterBuilder::Instance().Append(P);
  return QCN;
}

ASTQubitContainerNode *
ASTProductionFactory::ProductionRule_819(const ASTToken *TK) const {
  assert(TK && "Invalid ASTToken argument!");

  std::stringstream S;
  S << "ast-qubit-type-param-"
    << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      S.str(), 1U, ASTTypeQubitContainer);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  ASTQubitContainerNode *QCN =
      ASTBuilder::Instance().CreateASTQubitContainerNode(Id, 1U);
  assert(QCN && "Could not create a valid ASTQubitContainerNode!");

  QCN->SetLocation(TK->GetLocation());
  QCN->LocalFunctionArgument();
  QCN->Mangle();

  ASTParameter *P = new ASTParameter(Id, QCN);
  assert(P && "Could not create a valid ASTParameter!");

  P->SetLocation(TK->GetLocation());
  ASTParameterBuilder::Instance().Append(P);
  return QCN;
}

ASTDurationNode *
ASTProductionFactory::ProductionRule_820(const ASTToken *TK) const {
  assert(TK && "Invalid ASTToken argument!");

  std::stringstream S;
  S << "ast-duration-type-param-"
    << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      S.str(), ASTDurationNode::DurationBits, ASTTypeDuration);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  ASTDurationNode *DN = ASTBuilder::Instance().CreateASTDurationNode(Id, "0dt");
  assert(DN && "Could not create a valid ASTDurationNode!");

  DN->SetLocation(TK->GetLocation());
  DN->Mangle();

  ASTParameter *P = new ASTParameter(Id, DN);
  assert(P && "Could not create a valid ASTParameter!");

  P->SetLocation(TK->GetLocation());
  ASTParameterBuilder::Instance().Append(P);
  return DN;
}

static bool CreateASTArrayIdentifierName(std::stringstream &S, ASTType Ty,
                                         const ASTToken *TK) {
  switch (Ty) {
  case ASTTypeCBitArray:
    S << "ast-bit-array-type-param-"
      << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
    break;
  case ASTTypeQubitArray:
    S << "ast-qubit-array-type-param-"
      << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
    break;
  case ASTTypeAngleArray:
    S << "ast-angle-array-type-param-"
      << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
    break;
  case ASTTypeBoolArray:
    S << "ast-bool-array-type-param-"
      << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
    break;
  case ASTTypeIntArray:
    S << "ast-int-array-type-param-"
      << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
    break;
  case ASTTypeMPIntegerArray:
    S << "ast-mpinteger-array-type-param-"
      << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
    break;
  case ASTTypeFloatArray:
    S << "ast-float-array-type-param-"
      << DIAGLineCounter::Instance().GetIdentifierLocation();
    break;
  case ASTTypeMPDecimalArray:
    S << "ast-mpdecimal-array-type-param-"
      << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
    break;
  case ASTTypeDurationArray:
    S << "ast-duration-array-type-param-"
      << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
    break;
  case ASTTypeMPComplexArray:
    S << "ast-mpcomplex-array-type-param-"
      << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
    break;
  case ASTTypeOpenPulseFrameArray:
    S << "ast-frame-array-type-param-"
      << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
    break;
  case ASTTypeOpenPulsePortArray:
    S << "ast-port-array-type-param-"
      << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
    break;
  case ASTTypeOpenPulseWaveformArray:
    S << "ast-waveform-array-type-param-"
      << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
    break;
  default:
    S << "Arrays of type " << PrintTypeEnum(Ty) << " are not "
      << "allowed.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), S.str(), DiagLevel::Error);
    return false;
    break;
  }

  return true;
}

static ASTArrayNode *ArrayConstructionError(ASTType Ty, const ASTToken *TK,
                                            const std::string &ERM,
                                            bool Unsigned = false) {
  switch (Ty) {
  case ASTTypeCBitArray:
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), ERM, DiagLevel::Error);
    return ASTCBitArrayNode::ExpressionError(ERM, TK);
    break;
  case ASTTypeQubitArray:
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), ERM, DiagLevel::Error);
    return ASTQubitArrayNode::ExpressionError(ERM, TK);
    break;
  case ASTTypeAngleArray:
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), ERM, DiagLevel::Error);
    return ASTAngleArrayNode::ExpressionError(ERM, TK);
    break;
  case ASTTypeBoolArray:
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), ERM, DiagLevel::Error);
    return ASTBoolArrayNode::ExpressionError(ERM, TK);
    break;
  case ASTTypeIntArray:
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), ERM, DiagLevel::Error);
    return ASTIntArrayNode::ExpressionError(ERM, Unsigned, TK);
    break;
  case ASTTypeMPIntegerArray:
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), ERM, DiagLevel::Error);
    return ASTMPIntegerArrayNode::ExpressionError(ERM, Unsigned, TK);
    break;
  case ASTTypeFloatArray:
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), ERM, DiagLevel::Error);
    return ASTFloatArrayNode::ExpressionError(ERM, TK);
    break;
  case ASTTypeMPDecimalArray:
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), ERM, DiagLevel::Error);
    return ASTMPDecimalArrayNode::ExpressionError(ERM, TK);
    break;
  case ASTTypeDurationArray:
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), ERM, DiagLevel::Error);
    return ASTDurationArrayNode::ExpressionError(ERM, TK);
    break;
  case ASTTypeMPComplexArray:
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), ERM, DiagLevel::Error);
    return ASTMPComplexArrayNode::ExpressionError(ERM, TK);
    break;
  case ASTTypeOpenPulseFrameArray:
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), ERM, DiagLevel::Error);
    return ASTOpenPulseFrameArrayNode::ExpressionError(ERM, TK);
    break;
  case ASTTypeOpenPulsePortArray:
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), ERM, DiagLevel::Error);
    return ASTOpenPulsePortArrayNode::ExpressionError(ERM, TK);
    break;
  case ASTTypeOpenPulseWaveformArray:
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), ERM, DiagLevel::Error);
    return ASTOpenPulseWaveformArrayNode::ExpressionError(ERM, TK);
    break;
  default:
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), ERM, DiagLevel::Error);
    return new ASTInvalidArrayNode(ERM, TK);
    break;
  }

  return nullptr;
}

static void ValidateArrayFeature(ASTType Ty) {
  switch (Ty) {
  case ASTTypeCBitArray:
    QasmFeatureTester::Instance().ValidateFeature("array");
    QasmFeatureTester::Instance().ValidateFeature("bitset");
    break;
  case ASTTypeQubitArray:
    QasmFeatureTester::Instance().ValidateFeature("array");
    break;
  case ASTTypeAngleArray:
    QasmFeatureTester::Instance().ValidateFeature("array");
    QasmFeatureTester::Instance().ValidateFeature("angle");
    break;
  case ASTTypeBoolArray:
    QasmFeatureTester::Instance().ValidateFeature("array");
    break;
  case ASTTypeIntArray:
    QasmFeatureTester::Instance().ValidateFeature("array");
    break;
  case ASTTypeMPIntegerArray:
    QasmFeatureTester::Instance().ValidateFeature("array");
    QasmFeatureTester::Instance().ValidateFeature("mpinteger");
    break;
  case ASTTypeFloatArray:
    QasmFeatureTester::Instance().ValidateFeature("array");
    break;
  case ASTTypeMPDecimalArray:
    QasmFeatureTester::Instance().ValidateFeature("array");
    QasmFeatureTester::Instance().ValidateFeature("mpdecimal");
    break;
  case ASTTypeDurationArray:
    QasmFeatureTester::Instance().ValidateFeature("array");
    QasmFeatureTester::Instance().ValidateFeature("duration");
    QasmFeatureTester::Instance().ValidateFeature("durationof");
    break;
  case ASTTypeMPComplexArray:
    QasmFeatureTester::Instance().ValidateFeature("array");
    QasmFeatureTester::Instance().ValidateFeature("mpcomplex");
    break;
  case ASTTypeOpenPulseFrameArray:
    QasmFeatureTester::Instance().ValidateFeature("array");
    QasmFeatureTester::Instance().ValidateFeature("frame");
    break;
  case ASTTypeOpenPulsePortArray:
    QasmFeatureTester::Instance().ValidateFeature("array");
    QasmFeatureTester::Instance().ValidateFeature("port");
    break;
  case ASTTypeOpenPulseWaveformArray:
    QasmFeatureTester::Instance().ValidateFeature("array");
    QasmFeatureTester::Instance().ValidateFeature("waveform");
    break;
  default:
    break;
  }
}

static ASTArrayNode *ConstructASTArray(const ASTIdentifierNode *Id,
                                       const ASTToken *TK, ASTType Ty,
                                       unsigned Bits, unsigned TyBits = 0U,
                                       bool Unsigned = false) {
  ASTArrayNode *AN = nullptr;

  switch (Ty) {
  case ASTTypeCBitArray:
    ValidateArrayFeature(Ty);
    if (TyBits == 0U)
      AN = ASTBuilder::Instance().CreateASTCBitArrayNode(Id, Bits);
    else
      AN = ASTBuilder::Instance().CreateASTCBitArrayNode(Id, Bits, TyBits);
    assert(AN && "Could not create a valid ASTCBitArrayNode!");
    break;
  case ASTTypeQubitArray:
    ValidateArrayFeature(Ty);
    if (TyBits == 0U)
      AN = ASTBuilder::Instance().CreateASTQubitArrayNode(Id, Bits);
    else
      AN = ASTBuilder::Instance().CreateASTQubitArrayNode(Id, Bits, TyBits);
    assert(AN && "Could not create a valid ASTQubitArrayNode!");
    break;
  case ASTTypeAngleArray:
    ValidateArrayFeature(Ty);
    if (TyBits == 0U)
      AN = ASTBuilder::Instance().CreateASTAngleArrayNode(Id, Bits);
    else
      AN = ASTBuilder::Instance().CreateASTAngleArrayNode(Id, Bits, TyBits);
    assert(AN && "Could not create a valid ASTAngleArrayNode!");
    break;
  case ASTTypeBoolArray:
    ValidateArrayFeature(Ty);
    AN = ASTBuilder::Instance().CreateASTBoolArrayNode(Id, Bits);
    assert(AN && "Could not create a valid ASTBoolArrayNode!");
    break;
  case ASTTypeIntArray:
    ValidateArrayFeature(Ty);
    AN = ASTBuilder::Instance().CreateASTIntArrayNode(Id, Bits, Unsigned);
    assert(AN && "Could not create a valid ASTIntArrayNode!");
    break;
  case ASTTypeMPIntegerArray:
    ValidateArrayFeature(Ty);
    if (TyBits == 0U)
      AN = ASTBuilder::Instance().CreateASTMPIntegerArrayNode(
          Id, Bits, ASTMPDecimalNode::DefaultBits, Unsigned);
    else
      AN = ASTBuilder::Instance().CreateASTMPIntegerArrayNode(Id, Bits, TyBits,
                                                              Unsigned);
    assert(AN && "Could not create a valid ASTMPIntegerArrayNode!");
    break;
  case ASTTypeFloatArray:
    ValidateArrayFeature(Ty);
    AN = ASTBuilder::Instance().CreateASTFloatArrayNode(Id, Bits);
    assert(AN && "Could not create a valid ASTFloatArrayNode!");
    break;
  case ASTTypeMPDecimalArray:
    ValidateArrayFeature(Ty);
    if (TyBits == 0U)
      AN = ASTBuilder::Instance().CreateASTMPDecimalArrayNode(
          Id, Bits, ASTMPDecimalNode::DefaultBits);
    else
      AN = ASTBuilder::Instance().CreateASTMPDecimalArrayNode(Id, Bits, TyBits);
    assert(AN && "Could not create a valid ASTMPDecimalArrayNode!");
    break;
  case ASTTypeDurationArray:
    ValidateArrayFeature(Ty);
    AN = ASTBuilder::Instance().CreateASTDurationArrayNode(Id, Bits, "0dt");
    assert(AN && "Could not create a valid ASTDurationArrayNode!");
    break;
  case ASTTypeMPComplexArray:
    ValidateArrayFeature(Ty);
    if (TyBits == 0U)
      AN = ASTBuilder::Instance().CreateASTMPComplexArrayNode(
          Id, Bits, ASTMPComplexNode::DefaultBits);
    else
      AN = ASTBuilder::Instance().CreateASTMPComplexArrayNode(Id, Bits, TyBits);
    assert(AN && "Could not create a valid ASTMPComplexArrayNode!");
    break;
  case ASTTypeOpenPulseFrameArray:
    ValidateArrayFeature(Ty);
    AN = ASTBuilder::Instance().CreateASTOpenPulseFrameArrayNode(Id, Bits);
    assert(AN && "Could not create a valid ASTOpenPulseFrameArrayNode!");
    break;
  case ASTTypeOpenPulsePortArray:
    ValidateArrayFeature(Ty);
    AN = ASTBuilder::Instance().CreateASTOpenPulsePortArrayNode(Id, Bits);
    assert(AN && "Could not create a valid ASTOpenPulsePortArrayNode!");
    break;
  case ASTTypeOpenPulseWaveformArray:
    ValidateArrayFeature(Ty);
    AN = ASTBuilder::Instance().CreateASTOpenPulseWaveformArrayNode(Id, Bits);
    assert(AN && "Could not create a valid ASTOpenPulseWaveformArrayNode!");
    break;
  default: {
    std::stringstream M;
    M << "Arrays of type " << PrintTypeEnum(Ty) << " are not "
      << "allowed.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return new ASTInvalidArrayNode(M.str(), TK);
  } break;
  }

  return AN;
}

ASTArrayNode *ASTProductionFactory::ProductionRule_821(
    const ASTToken *TK,
    const std::variant<const ASTIntNode *, const ASTIdentifierNode *> &II,
    ASTType Ty, bool Unsigned) const {
  assert(TK && "Invalid ASTToken argument!");

  QasmFeatureTester::Instance().ValidateFeature("array");

  if (!ASTExpressionValidator::Instance().IsArrayType(Ty)) {
    std::stringstream M;
    M << "Invalid array type " << PrintTypeEnum(Ty) << '.';
    return ArrayConstructionError(Ty, TK, M.str());
  }

  unsigned Bits = ASTProductionFactory::Instance().GetVariantBits(II);
  if (ASTIdentifierNode::InvalidBits(Bits)) {
    std::stringstream M;
    M << "Invalid number of bits for array expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ArrayConstructionError(Ty, TK, M.str());
  }

  std::stringstream S;

  if (!CreateASTArrayIdentifierName(S, Ty, TK))
    return ArrayConstructionError(Ty, TK, S.str());

  ASTIdentifierNode *Id =
      ASTBuilder::Instance().CreateASTIdentifierNode(S.str(), Bits, Ty);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());
  ASTSymbolTable::Instance().LocalScope(Id, Bits, Ty);

  ASTArrayNode *AN = ConstructASTArray(Id, TK, Ty, Bits, 1U, Unsigned);

  if (AN->IsError())
    return AN;

  AN->SetLocation(TK->GetLocation());
  AN->Mangle();

  ASTParameter *P = new ASTParameter(Id, AN);
  assert(P && "Could not create a valid ASTParameter!");

  P->SetLocation(TK->GetLocation());
  ASTParameterBuilder::Instance().Append(P);
  return AN;
}

ASTArrayNode *ASTProductionFactory::ProductionRule_821(
    const ASTToken *TK,
    const std::variant<const ASTIntNode *, const ASTIdentifierNode *> &II,
    const std::variant<const ASTIntNode *, const ASTIdentifierNode *> &CX,
    ASTType Ty, bool Unsigned) const {
  assert(TK && "Invalid ASTToken argument!");

  QasmFeatureTester::Instance().ValidateFeature("array");

  if (!ASTExpressionValidator::Instance().IsArrayType(Ty)) {
    std::stringstream M;
    M << "Invalid array type " << PrintTypeEnum(Ty) << '.';
    return ArrayConstructionError(Ty, TK, M.str());
  }

  unsigned Bits = ASTProductionFactory::Instance().GetVariantBits(II);
  if (ASTIdentifierNode::InvalidBits(Bits)) {
    std::stringstream M;
    M << "Invalid number of bits for array expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ArrayConstructionError(Ty, TK, M.str());
  }

  unsigned TyBits = std::max<unsigned>(
      ASTProductionFactory::Instance().GetVariantBits(CX), 1U);

  if (ASTIdentifierNode::InvalidBits(TyBits)) {
    ASTType TTy = ASTUtils::Instance().GetArrayElementType(Ty);
    std::stringstream M;
    M << "Invalid number of bits for " << PrintTypeEnum(TTy) << " expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ArrayConstructionError(Ty, TK, M.str());
  }

  std::stringstream S;

  if (!CreateASTArrayIdentifierName(S, Ty, TK))
    return ArrayConstructionError(Ty, TK, S.str());

  ASTIdentifierNode *Id =
      ASTBuilder::Instance().CreateASTIdentifierNode(S.str(), Bits, Ty);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());
  ASTSymbolTable::Instance().LocalScope(Id, Bits, Ty);

  ASTArrayNode *AN = ConstructASTArray(Id, TK, Ty, Bits, TyBits, Unsigned);

  if (AN->IsError())
    return AN;

  AN->SetLocation(TK->GetLocation());
  AN->Mangle();

  ASTParameter *P = new ASTParameter(Id, AN);
  assert(P && "Could not create a valid ASTParameter!");

  P->SetLocation(TK->GetLocation());
  ASTParameterBuilder::Instance().Append(P);
  return AN;
}

ASTArrayNode *ASTProductionFactory::ProductionRule_821(
    const ASTToken *TK,
    const std::variant<const ASTIntNode *, const ASTIdentifierNode *> &II,
    const std::variant<const ASTIntNode *, const ASTIdentifierNode *> &CX,
    const std::variant<const ASTIntNode *, const ASTIdentifierNode *> &DX,
    ASTType Ty, bool Unsigned) const {
  assert(TK && "Invalid ASTToken argument!");
  // FIXME: IMPLEMENT N-DIMENSIONAL ARRAYS.

  QasmFeatureTester::Instance().ValidateFeature("array");

  if (!ASTExpressionValidator::Instance().IsArrayType(Ty)) {
    std::stringstream M;
    M << "Invalid array type " << PrintTypeEnum(Ty) << '.';
    return ArrayConstructionError(Ty, TK, M.str());
  }

  unsigned Bits = ASTProductionFactory::Instance().GetVariantBits(II);
  if (ASTIdentifierNode::InvalidBits(Bits)) {
    std::stringstream M;
    M << "Invalid number of bits for array expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ArrayConstructionError(Ty, TK, M.str());
  }

  unsigned TyBits = std::max<unsigned>(
      ASTProductionFactory::Instance().GetVariantBits(CX), 1U);

  if (ASTIdentifierNode::InvalidBits(TyBits)) {
    ASTType TTy = ASTUtils::Instance().GetArrayElementType(Ty);
    std::stringstream M;
    M << "Invalid number of bits for " << PrintTypeEnum(TTy) << " expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ArrayConstructionError(Ty, TK, M.str());
  }

  unsigned DBits = std::max<unsigned>(
      ASTProductionFactory::Instance().GetVariantBits(DX), 1U);

  if (ASTIdentifierNode::InvalidBits(DBits)) {
    std::stringstream M;
    M << "Invalid number of bits for array dimension.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ArrayConstructionError(Ty, TK, M.str());
  }

  std::stringstream S;

  if (!CreateASTArrayIdentifierName(S, Ty, TK))
    return ArrayConstructionError(Ty, TK, S.str());

  ASTIdentifierNode *Id =
      ASTBuilder::Instance().CreateASTIdentifierNode(S.str(), Bits, Ty);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());
  ASTSymbolTable::Instance().LocalScope(Id, Bits, Ty);

  ASTArrayNode *AN = ConstructASTArray(Id, TK, Ty, Bits, TyBits, Unsigned);

  if (AN->IsError())
    return AN;

  AN->SetLocation(TK->GetLocation());
  AN->Mangle();

  ASTParameter *P = new ASTParameter(Id, AN);
  assert(P && "Could not create a valid ASTParameter!");

  P->SetLocation(TK->GetLocation());
  ASTParameterBuilder::Instance().Append(P);
  return AN;
}

ASTArrayNode *ASTProductionFactory::ProductionRule_821(
    const ASTToken *TK,
    const std::variant<const ASTIntNode *, const ASTIdentifierNode *> &II,
    const ASTStringNode *TS, ASTType Ty) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(TS && "Invalid ASTStringNode argument!");

  QasmFeatureTester::Instance().ValidateFeature("array");
  QasmFeatureTester::Instance().ValidateFeature("duration");

  if (!ASTExpressionValidator::Instance().IsArrayType(Ty)) {
    std::stringstream M;
    M << "Invalid array type " << PrintTypeEnum(Ty) << '.';
    return ArrayConstructionError(Ty, TK, M.str());
  }

  unsigned Bits = ASTProductionFactory::Instance().GetVariantBits(II);
  if (ASTIdentifierNode::InvalidBits(Bits)) {
    std::stringstream M;
    M << "Invalid number of bits for array expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ArrayConstructionError(Ty, TK, M.str());
  }

  std::stringstream S;

  if (!CreateASTArrayIdentifierName(S, Ty, TK))
    return ArrayConstructionError(Ty, TK, S.str());

  ASTIdentifierNode *Id =
      ASTBuilder::Instance().CreateASTIdentifierNode(S.str(), Bits, Ty);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());
  ASTSymbolTable::Instance().LocalScope(Id, Bits, Ty);

  ASTArrayNode *AN = ASTBuilder::Instance().CreateASTDurationArrayNode(
      Id, Bits, TS->GetValue());
  if (!AN) {
    std::stringstream M;
    M << "Failure creating a duration array.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ArrayConstructionError(Ty, TK, M.str());
  }

  AN->SetLocation(TK->GetLocation());
  AN->Mangle();

  ASTParameter *P = new ASTParameter(Id, AN);
  assert(P && "Could not create a valid ASTParameter!");

  P->SetLocation(TK->GetLocation());
  ASTParameterBuilder::Instance().Append(P);
  return AN;
}

ASTArrayNode *ASTProductionFactory::ProductionRule_821(
    const ASTToken *TK,
    const std::variant<const ASTIntNode *, const ASTIdentifierNode *> &II,
    const std::variant<const ASTIntNode *, const ASTIdentifierNode *> &DX,
    const ASTStringNode *TS, ASTType Ty) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(TS && "Invalid ASTStringNode argument!");

  QasmFeatureTester::Instance().ValidateFeature("array");
  QasmFeatureTester::Instance().ValidateFeature("duration");

  // FIXME: IMPLEMENT N-DIMENSIONAL ARRAYS.
  if (!ASTExpressionValidator::Instance().IsArrayType(Ty)) {
    std::stringstream M;
    M << "Invalid array type " << PrintTypeEnum(Ty) << '.';
    return ArrayConstructionError(Ty, TK, M.str());
  }

  unsigned Bits = ASTProductionFactory::Instance().GetVariantBits(II);
  if (ASTIdentifierNode::InvalidBits(Bits)) {
    std::stringstream M;
    M << "Invalid number of bits for array expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ArrayConstructionError(Ty, TK, M.str());
  }

  unsigned DBits = std::max<unsigned>(
      ASTProductionFactory::Instance().GetVariantBits(DX), 1U);

  if (ASTIdentifierNode::InvalidBits(DBits)) {
    std::stringstream M;
    M << "Invalid number of bits for array dimension expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ArrayConstructionError(Ty, TK, M.str());
  }

  std::stringstream S;

  if (!CreateASTArrayIdentifierName(S, Ty, TK))
    return ArrayConstructionError(Ty, TK, S.str());

  ASTIdentifierNode *Id =
      ASTBuilder::Instance().CreateASTIdentifierNode(S.str(), Bits, Ty);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());
  ASTSymbolTable::Instance().LocalScope(Id, Bits, Ty);

  ASTArrayNode *AN = ASTBuilder::Instance().CreateASTDurationArrayNode(
      Id, Bits, TS->GetValue());
  if (!AN) {
    std::stringstream M;
    M << "Failure creating a duration array.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ArrayConstructionError(Ty, TK, M.str());
  }

  AN->SetLocation(TK->GetLocation());
  AN->Mangle();

  ASTParameter *P = new ASTParameter(Id, AN);
  assert(P && "Could not create a valid ASTParameter!");

  P->SetLocation(TK->GetLocation());
  ASTParameterBuilder::Instance().Append(P);
  return AN;
}

ASTArrayNode *ASTProductionFactory::ProductionRule_821(
    const ASTToken *TK,
    const std::variant<const ASTIntNode *, const ASTIdentifierNode *> &II,
    const ASTDurationOfNode *DON, ASTType Ty) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DON && "Invalid ASTDurationOfNode argument!");

  QasmFeatureTester::Instance().ValidateFeature("array");
  QasmFeatureTester::Instance().ValidateFeature("durationof");

  unsigned Size = std::max<unsigned>(
      ASTProductionFactory::Instance().GetVariantBits(II), 1U);
  if (ASTIdentifierNode::InvalidBits(Size)) {
    std::stringstream M;
    M << "Invalid number of bits for durationof array expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ArrayConstructionError(Ty, TK, M.str());
  }

  std::stringstream S;

  if (!CreateASTArrayIdentifierName(S, Ty, TK))
    return ArrayConstructionError(Ty, TK, S.str());

  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      S.str(), Size, ASTTypeDurationArray);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());
  ASTSymbolTable::Instance().LocalScope(Id, Size, Ty);

  ASTArrayNode *AN =
      ASTBuilder::Instance().CreateASTDurationArrayNode(Id, Size, DON);
  if (!AN) {
    std::stringstream M;
    M << "Failure creating a duration array.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ArrayConstructionError(Ty, TK, M.str());
  }

  AN->SetLocation(TK->GetLocation());
  AN->Mangle();

  ASTParameter *P = new ASTParameter(Id, AN);
  assert(P && "Could not create a valid ASTParameter!");

  P->SetLocation(TK->GetLocation());
  ASTParameterBuilder::Instance().Append(P);
  return AN;
}

ASTArrayNode *ASTProductionFactory::ProductionRule_821(
    const ASTToken *TK,
    const std::variant<const ASTIntNode *, const ASTIdentifierNode *> &II,
    const std::variant<const ASTIntNode *, const ASTIdentifierNode *> &DX,
    const ASTDurationOfNode *DON, ASTType Ty) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DON && "Invalid ASTDurationOfNode argument!");
  // FIXME: IMPLEMENT N-DIMENSIONAL ARRAYS.

  QasmFeatureTester::Instance().ValidateFeature("array");
  QasmFeatureTester::Instance().ValidateFeature("durationof");

  unsigned Size = std::max<unsigned>(
      ASTProductionFactory::Instance().GetVariantBits(II), 1U);
  if (ASTIdentifierNode::InvalidBits(Size)) {
    std::stringstream M;
    M << "Invalid number of bits for durationof array expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ArrayConstructionError(Ty, TK, M.str());
  }

  unsigned DSize = std::max<unsigned>(
      ASTProductionFactory::Instance().GetVariantBits(DX), 1U);
  if (ASTIdentifierNode::InvalidBits(DSize)) {
    std::stringstream M;
    M << "Invalid number of bits for durationof array dimension expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ArrayConstructionError(Ty, TK, M.str());
  }

  std::stringstream S;

  if (!CreateASTArrayIdentifierName(S, Ty, TK))
    return ArrayConstructionError(Ty, TK, S.str());

  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      S.str(), Size, ASTTypeDurationArray);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());
  ASTSymbolTable::Instance().LocalScope(Id, Size, Ty);

  ASTArrayNode *AN =
      ASTBuilder::Instance().CreateASTDurationArrayNode(Id, Size, DON);
  if (!AN) {
    std::stringstream M;
    M << "Failure creating a duration array.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ArrayConstructionError(Ty, TK, M.str());
  }

  AN->SetLocation(TK->GetLocation());
  AN->Mangle();

  ASTParameter *P = new ASTParameter(Id, AN);
  assert(P && "Could not create a valid ASTParameter!");

  P->SetLocation(TK->GetLocation());
  ASTParameterBuilder::Instance().Append(P);
  return AN;
}

ASTArrayNode *ASTProductionFactory::ProductionRule_822(
    const ASTToken *TK, const ASTIdentifierNode *Id,
    const std::variant<const ASTIntNode *, const ASTIdentifierNode *> &II,
    ASTType Ty, bool Unsigned) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(Id->GetSymbolType() == Ty &&
         "Inconsistent ASTIdentifierNode <-> array symbol type!");

  ASTScopeController::Instance().CheckScopeAndUndefined(Id);

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  ASTType CTy = CTX->GetContextType();
  if (!ASTScopeController::Instance().CheckArrayContextType(CTy) &&
      !ASTIdentifierTypeController::Instance().IsFunctionArgument(TK, Id, Ty,
                                                                  CTX)) {
    std::stringstream M;
    M << "Arrays cannot be declared within an " << PrintTypeEnum(CTy)
      << " declaration context.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ArrayConstructionError(Ty, TK, M.str());
  }

  unsigned Bits = ASTProductionFactory::Instance().GetVariantBits(II);
  if (ASTIdentifierNode::InvalidBits(Bits)) {
    std::stringstream M;
    M << "Invalid number of bits for array expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ArrayConstructionError(Ty, TK, M.str());
  }

  Id->SetBits(Bits);

  if (!ASTDeclarationContextTracker::Instance().IsGlobalContext(CTX)) {
    if (!ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(Id, Bits,
                                                                 Ty)) {
      std::stringstream M;
      M << "Could not transfer Symbol Table Entry for "
        << PrintTypeEnum(Id->GetSymbolType()) << '.';
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
      return ArrayConstructionError(Ty, TK, M.str());
    }
  }

  ASTArrayNode *AN = ConstructASTArray(Id, TK, Ty, Bits, 1U, Unsigned);
  AN->SetLocation(TK->GetLocation());
  AN->Mangle();
  return AN;
}

ASTArrayNode *ASTProductionFactory::ProductionRule_822(
    const ASTToken *TK, const ASTIdentifierNode *Id,
    const std::variant<const ASTIntNode *, const ASTIdentifierNode *> &II,
    const ASTStringNode *TS, ASTType Ty) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(Id->GetSymbolType() == Ty &&
         "Inconsistent ASTIdentifierNode <-> array symbol type!");
  assert(TS && "Invalid ASTStringNode argument!");

  ASTScopeController::Instance().CheckScopeAndUndefined(Id);

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  ASTType CTy = CTX->GetContextType();
  if (!ASTScopeController::Instance().CheckArrayContextType(CTy)) {
    std::stringstream M;
    M << "Arrays cannot be declared within an " << PrintTypeEnum(CTy)
      << " declaration context.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ArrayConstructionError(Ty, TK, M.str());
  }

  unsigned Bits = ASTProductionFactory::Instance().GetVariantBits(II);
  if (ASTIdentifierNode::InvalidBits(Bits)) {
    std::stringstream M;
    M << "Invalid number of bits for array expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ArrayConstructionError(Ty, TK, M.str());
  }

  Id->SetBits(Bits);

  if (!ASTDeclarationContextTracker::Instance().IsGlobalContext(CTX)) {
    if (!ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(Id, Bits,
                                                                 Ty)) {
      std::stringstream M;
      M << "Could not transfer Symbol Table Entry for "
        << PrintTypeEnum(Id->GetSymbolType()) << '.';
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
      return ArrayConstructionError(Ty, TK, M.str());
    }
  }

  ASTArrayNode *AN = ASTBuilder::Instance().CreateASTDurationArrayNode(
      Id, Bits, TS->GetValue());
  if (!AN) {
    std::stringstream M;
    M << "Failure creating a duration array.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ArrayConstructionError(Ty, TK, M.str());
  }

  AN->SetLocation(TK->GetLocation());
  AN->Mangle();
  return AN;
}

ASTArrayNode *ASTProductionFactory::ProductionRule_822(
    const ASTToken *TK, const ASTIdentifierNode *Id,
    const std::variant<const ASTIntNode *, const ASTIdentifierNode *> &II,
    const std::variant<const ASTIntNode *, const ASTIdentifierNode *> &DX,
    const ASTStringNode *TS, ASTType Ty) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(Id->GetSymbolType() == Ty &&
         "Inconsistent ASTIdentifierNode <-> array symbol type!");
  assert(TS && "Invalid ASTStringNode argument!");

  ASTScopeController::Instance().CheckScopeAndUndefined(Id);

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  ASTType CTy = CTX->GetContextType();
  if (!ASTScopeController::Instance().CheckArrayContextType(CTy)) {
    std::stringstream M;
    M << "Arrays cannot be declared within an " << PrintTypeEnum(CTy)
      << " declaration context.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ArrayConstructionError(Ty, TK, M.str());
  }

  unsigned Bits = ASTProductionFactory::Instance().GetVariantBits(II);
  if (ASTIdentifierNode::InvalidBits(Bits)) {
    std::stringstream M;
    M << "Invalid number of bits for array expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ArrayConstructionError(Ty, TK, M.str());
  }

  Id->SetBits(Bits);

  unsigned DBits = ASTProductionFactory::Instance().GetVariantBits(DX);
  if (ASTIdentifierNode::InvalidBits(DBits)) {
    std::stringstream M;
    M << "Invalid number of bits for array dimension expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ArrayConstructionError(Ty, TK, M.str());
  }

  if (!ASTDeclarationContextTracker::Instance().IsGlobalContext(CTX)) {
    if (!ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(Id, Bits,
                                                                 Ty)) {
      std::stringstream M;
      M << "Could not transfer Symbol Table Entry for "
        << PrintTypeEnum(Id->GetSymbolType()) << '.';
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
      return ArrayConstructionError(Ty, TK, M.str());
    }
  }

  // FIXME: IMPLEMENT N-DIMENSIONAL ARRAYS.
  ASTArrayNode *AN = ASTBuilder::Instance().CreateASTDurationArrayNode(
      Id, Bits, TS->GetValue());
  if (!AN) {
    std::stringstream M;
    M << "Failure creating a duration array.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ArrayConstructionError(Ty, TK, M.str());
  }

  AN->SetLocation(TK->GetLocation());
  AN->Mangle();
  return AN;
}

ASTArrayNode *ASTProductionFactory::ProductionRule_822(
    const ASTToken *TK, const ASTIdentifierNode *Id,
    const std::variant<const ASTIntNode *, const ASTIdentifierNode *> &II,
    const ASTDurationOfNode *DON, ASTType Ty) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(Id->GetSymbolType() == Ty &&
         "Inconsistent ASTIdentifierNode <-> array symbol type!");
  assert(DON && "Invalid ASTDurationOfNode argument!");

  ASTScopeController::Instance().CheckScopeAndUndefined(Id);

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  ASTType CTy = CTX->GetContextType();
  if (!ASTScopeController::Instance().CheckArrayContextType(CTy)) {
    std::stringstream M;
    M << "Arrays cannot be declared within an " << PrintTypeEnum(CTy)
      << " declaration context.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ArrayConstructionError(Ty, TK, M.str());
  }

  unsigned Bits = ASTProductionFactory::Instance().GetVariantBits(II);
  if (ASTIdentifierNode::InvalidBits(Bits)) {
    std::stringstream M;
    M << "Invalid number of bits for array expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ArrayConstructionError(Ty, TK, M.str());
  }

  Id->SetBits(Bits);

  if (!ASTDeclarationContextTracker::Instance().IsGlobalContext(CTX)) {
    if (!ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(Id, Bits,
                                                                 Ty)) {
      std::stringstream M;
      M << "Could not transfer Symbol Table Entry for "
        << PrintTypeEnum(Id->GetSymbolType()) << '.';
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
      return ArrayConstructionError(Ty, TK, M.str());
    }
  }

  ASTArrayNode *AN =
      ASTBuilder::Instance().CreateASTDurationArrayNode(Id, Bits, DON);
  if (!AN) {
    std::stringstream M;
    M << "Failure creating a duration array.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ArrayConstructionError(Ty, TK, M.str());
  }

  AN->SetLocation(TK->GetLocation());
  AN->Mangle();
  return AN;
}

ASTArrayNode *ASTProductionFactory::ProductionRule_822(
    const ASTToken *TK, const ASTIdentifierNode *Id,
    const std::variant<const ASTIntNode *, const ASTIdentifierNode *> &II,
    const std::variant<const ASTIntNode *, const ASTIdentifierNode *> &DX,
    const ASTDurationOfNode *DON, ASTType Ty) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(Id->GetSymbolType() == Ty &&
         "Inconsistent ASTIdentifierNode <-> array symbol type!");
  assert(DON && "Invalid ASTDurationOfNode argument!");

  ASTScopeController::Instance().CheckScopeAndUndefined(Id);

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  ASTType CTy = CTX->GetContextType();
  if (!ASTScopeController::Instance().CheckArrayContextType(CTy)) {
    std::stringstream M;
    M << "Arrays cannot be declared within an " << PrintTypeEnum(CTy)
      << " declaration context.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ArrayConstructionError(Ty, TK, M.str());
  }

  unsigned Bits = ASTProductionFactory::Instance().GetVariantBits(II);
  if (ASTIdentifierNode::InvalidBits(Bits)) {
    std::stringstream M;
    M << "Invalid number of bits for array expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ArrayConstructionError(Ty, TK, M.str());
  }

  Id->SetBits(Bits);

  unsigned DBits = ASTProductionFactory::Instance().GetVariantBits(DX);
  if (ASTIdentifierNode::InvalidBits(DBits)) {
    std::stringstream M;
    M << "Invalid number of bits for array dimension expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ArrayConstructionError(Ty, TK, M.str());
  }

  if (!ASTDeclarationContextTracker::Instance().IsGlobalContext(CTX)) {
    if (!ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(Id, Bits,
                                                                 Ty)) {
      std::stringstream M;
      M << "Could not transfer Symbol Table Entry for "
        << PrintTypeEnum(Id->GetSymbolType()) << '.';
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
      return ArrayConstructionError(Ty, TK, M.str());
    }
  }

  // FIXME: IMPLEMENT N-DIMENSIONAL ARRAYS.
  ASTArrayNode *AN =
      ASTBuilder::Instance().CreateASTDurationArrayNode(Id, Bits, DON);
  if (!AN) {
    std::stringstream M;
    M << "Failure creating a duration array.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ArrayConstructionError(Ty, TK, M.str());
  }

  AN->SetLocation(TK->GetLocation());
  AN->Mangle();
  return AN;
}

ASTArrayNode *ASTProductionFactory::ProductionRule_822(
    const ASTToken *TK, const ASTIdentifierNode *Id,
    const std::variant<const ASTIntNode *, const ASTIdentifierNode *> &II,
    const std::variant<const ASTIntNode *, const ASTIdentifierNode *> &CX,
    ASTType Ty, bool Unsigned) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(Id->GetSymbolType() == Ty &&
         "Inconsistent ASTIdentifierNode <-> array symbol type!");

  ASTScopeController::Instance().CheckScopeAndUndefined(Id);

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  ASTType CTy = CTX->GetContextType();
  if (!ASTScopeController::Instance().CheckArrayContextType(CTy)) {
    std::stringstream M;
    M << "Arrays cannot be declared within an " << PrintTypeEnum(CTy)
      << " declaration context.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ArrayConstructionError(Ty, TK, M.str());
  }

  unsigned Bits = ASTProductionFactory::Instance().GetVariantBits(II);
  if (ASTIdentifierNode::InvalidBits(Bits)) {
    std::stringstream M;
    M << "Invalid number of bits for array expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ArrayConstructionError(Ty, TK, M.str());
  }

  Id->SetBits(Bits);

  unsigned TyBits = ASTProductionFactory::Instance().GetVariantBits(CX);
  if (ASTIdentifierNode::InvalidBits(TyBits)) {
    std::stringstream M;
    M << "Invalid number of bits for array element expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ArrayConstructionError(Ty, TK, M.str());
  }

  if (!ASTDeclarationContextTracker::Instance().IsGlobalContext(CTX)) {
    if (!ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(Id, Bits,
                                                                 Ty)) {
      std::stringstream M;
      M << "Could not transfer Symbol Table Entry for "
        << PrintTypeEnum(Id->GetSymbolType()) << '.';
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
      return ArrayConstructionError(Ty, TK, M.str());
    }
  }

  ASTArrayNode *AN = ConstructASTArray(Id, TK, Ty, Bits, TyBits, Unsigned);
  AN->SetLocation(TK->GetLocation());
  AN->Mangle();
  return AN;
}

ASTArrayNode *ASTProductionFactory::ProductionRule_822(
    const ASTToken *TK, const ASTIdentifierNode *Id,
    const std::variant<const ASTIntNode *, const ASTIdentifierNode *> &II,
    const std::variant<const ASTIntNode *, const ASTIdentifierNode *> &CX,
    const std::variant<const ASTIntNode *, const ASTIdentifierNode *> &DX,
    ASTType Ty, bool Unsigned) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(Id->GetSymbolType() == Ty &&
         "Inconsistent ASTIdentifierNode <-> array symbol type!");

  ASTScopeController::Instance().CheckScopeAndUndefined(Id);

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  ASTType CTy = CTX->GetContextType();
  if (!ASTScopeController::Instance().CheckArrayContextType(CTy)) {
    std::stringstream M;
    M << "Arrays cannot be declared within an " << PrintTypeEnum(CTy)
      << " declaration context.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ArrayConstructionError(Ty, TK, M.str());
  }

  unsigned Bits = ASTProductionFactory::Instance().GetVariantBits(II);
  if (ASTIdentifierNode::InvalidBits(Bits)) {
    std::stringstream M;
    M << "Invalid number of bits for array expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ArrayConstructionError(Ty, TK, M.str());
  }

  Id->SetBits(Bits);

  unsigned TyBits = ASTProductionFactory::Instance().GetVariantBits(CX);
  if (ASTIdentifierNode::InvalidBits(TyBits)) {
    std::stringstream M;
    M << "Invalid number of bits for array element expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ArrayConstructionError(Ty, TK, M.str());
  }

  unsigned DBits = ASTProductionFactory::Instance().GetVariantBits(DX);
  if (ASTIdentifierNode::InvalidBits(DBits)) {
    std::stringstream M;
    M << "Invalid number of bits for array dimension expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ArrayConstructionError(Ty, TK, M.str());
  }

  if (!ASTDeclarationContextTracker::Instance().IsGlobalContext(CTX)) {
    if (!ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(Id, Bits,
                                                                 Ty)) {
      std::stringstream M;
      M << "Could not transfer Symbol Table Entry for "
        << PrintTypeEnum(Id->GetSymbolType()) << '.';
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
      return ArrayConstructionError(Ty, TK, M.str());
    }
  }

  // FIXME: IMPLEMENT N-DIMENSIONAL ARRAYS.
  ASTArrayNode *AN = ConstructASTArray(Id, TK, Ty, Bits, TyBits, Unsigned);
  AN->SetLocation(TK->GetLocation());
  AN->Mangle();
  return AN;
}

ASTDurationNode *
ASTProductionFactory::ProductionRule_820(const ASTToken *TK,
                                         const ASTStringNode *TU) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(TU && "Invalid ASTStringNode argument!");

  std::stringstream S;
  S << "ast-duration-type-param-"
    << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      S.str(), ASTDurationNode::DurationBits, ASTTypeDuration);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  ASTDurationNode *DN =
      ASTBuilder::Instance().CreateASTDurationNode(Id, TU->GetValue());
  assert(DN && "Could not create a valid ASTDurationNode!");

  DN->SetLocation(TK->GetLocation());
  DN->Mangle();

  ASTParameter *P = new ASTParameter(Id, DN);
  assert(P && "Could not create a valid ASTParameter!");

  P->SetLocation(TK->GetLocation());
  ASTParameterBuilder::Instance().Append(P);
  return DN;
}

static bool TransferNamedTypeDeclIdentifier(const ASTIdentifierNode *Id,
                                            ASTType Ty) {
  switch (Ty) {
  case ASTTypeBitset:
    return ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
        Id, Id->GetBits(), Ty);
    break;
  case ASTTypeBool:
    return ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
        Id, ASTBoolNode::BoolBits, Ty);
    break;
  case ASTTypeInt:
  case ASTTypeUInt:
    return ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
        Id, ASTIntNode::IntBits, ASTTypeInt);
    break;
  case ASTTypeFloat:
    return ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
        Id, ASTFloatNode::FloatBits, Ty);
    break;
  case ASTTypeDouble:
    return ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
        Id, ASTDoubleNode::DoubleBits, Ty);
    break;
  case ASTTypeQubitContainer:
    return ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(Id, 1U, Ty);
    break;
  case ASTTypeQubitContainerAlias:
    return ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(Id, 1U, Ty);
    break;
  case ASTTypeAngle:
    return ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
        Id, ASTAngleNode::AngleBits, Ty);
    break;
  case ASTTypeDuration:
    return ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
        Id, ASTDurationNode::DurationBits, Ty);
    break;
  case ASTTypeDurationOf:
    return ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
        Id, ASTDurationOfNode::DurationOfBits, Ty);
    break;
  case ASTTypeMPInteger:
  case ASTTypeMPUInteger:
    return ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
        Id, ASTMPIntegerNode::DefaultBits, ASTTypeMPInteger);
    break;
  case ASTTypeMPDecimal:
    return ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
        Id, ASTMPDecimalNode::DefaultBits, Ty);
    break;
  case ASTTypeMPComplex:
    return ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
        Id, ASTMPComplexNode::DefaultBits, Ty);
    break;
  case ASTTypeEllipsis:
    return true;
    break;
  case ASTTypeOpenPulseFrame:
    return ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
        Id, Id->GetBits(), Ty);
    break;
  case ASTTypeOpenPulsePort:
    return ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
        Id, Id->GetBits(), Ty);
    break;
  case ASTTypeOpenPulseWaveform:
    return ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
        Id, Id->GetBits(), Ty);
    break;
  case ASTTypeCBitArray:
    return ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
        Id, Id->GetBits(), Ty);
    break;
  case ASTTypeQubitArray:
    return ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
        Id, Id->GetBits(), Ty);
    break;
  case ASTTypeAngleArray:
    return ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
        Id, Id->GetBits(), Ty);
    break;
  case ASTTypeBoolArray:
    return ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
        Id, Id->GetBits(), Ty);
    break;
  case ASTTypeIntArray:
    return ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
        Id, Id->GetBits(), Ty);
    break;
  case ASTTypeMPIntegerArray:
    return ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
        Id, Id->GetBits(), Ty);
    break;
  case ASTTypeFloatArray:
    return ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
        Id, Id->GetBits(), Ty);
    break;
  case ASTTypeMPDecimalArray:
    return ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
        Id, Id->GetBits(), Ty);
    break;
  case ASTTypeMPComplexArray:
    return ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
        Id, Id->GetBits(), Ty);
    break;
  case ASTTypeDurationArray:
    return ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
        Id, Id->GetBits(), Ty);
    break;
  case ASTTypeOpenPulseFrameArray:
    return ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
        Id, Id->GetBits(), Ty);
    break;
  case ASTTypeOpenPulsePortArray:
    return ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
        Id, Id->GetBits(), Ty);
    break;
  case ASTTypeOpenPulseWaveformArray:
    return ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
        Id, Id->GetBits(), Ty);
    break;
  default: {
    std::stringstream M;
    M << "Type " << PrintTypeEnum(Ty) << " cannot be used to instantiate "
      << "a NamedTypeDecl.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
  } break;
  }

  return false;
}

static bool TransferNamedTypeDeclIdentifier(const ASTIdentifierNode *Id,
                                            unsigned Bits, ASTType Ty) {
  switch (Ty) {
  case ASTTypeMPInteger:
  case ASTTypeMPUInteger:
    return ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
        Id, Bits, ASTTypeMPInteger);
    break;
  case ASTTypeQubitContainer:
  case ASTTypeQubitContainerAlias:
  case ASTTypeAngle:
  case ASTTypeMPDecimal:
  case ASTTypeMPComplex:
  case ASTTypeCBitArray:
  case ASTTypeQubitArray:
  case ASTTypeAngleArray:
  case ASTTypeBoolArray:
  case ASTTypeIntArray:
  case ASTTypeMPIntegerArray:
  case ASTTypeFloatArray:
  case ASTTypeMPDecimalArray:
  case ASTTypeDurationArray:
  case ASTTypeMPComplexArray:
  case ASTTypeOpenPulseFrameArray:
  case ASTTypeOpenPulsePortArray:
  case ASTTypeOpenPulseWaveformArray:
    return ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(Id, Bits,
                                                                   Ty);
    break;
  default: {
    std::stringstream M;
    M << "Type " << PrintTypeEnum(Ty) << " cannot be used to instantiate "
      << "an arbitrary width NamedTypeDecl.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
  } break;
  }

  return false;
}

static ASTDeclarationNode *
CreateFixedSizeNamedTypeDecl(const ASTToken *TK, const ASTIdentifierNode *Id,
                             const ASTStringNode *TS, ASTType Ty, bool Const) {
  ASTDeclarationNode *DN;

  switch (Ty) {
  case ASTTypeBitset: {
    Id->SetBits(1U);
    ASTCBitNode *CB = ASTBuilder::Instance().CreateASTCBitNode(Id, 1UL, 0UL);
    assert(CB && "Could not create a valid ASTCBitNode!");

    CB->SetLocation(TK->GetLocation());
    CB->Mangle();
    CB->SetConst(Const);
    Id->SetExpression(CB);
    ASTSymbolTable::Instance().LocalScope(Id, 1U, Ty);

    DN = new ASTDeclarationNode(Id, CB, ASTTypeBitset);
    assert(DN && "Could not create a valid NamedTypeDecl ASTDeclarationNode!");
  } break;
  case ASTTypeBool: {
    ASTBoolNode *BB = ASTBuilder::Instance().CreateASTBoolNode(Id, false);
    assert(BB && "Could not create a valid ASTBoolNode!");

    BB->SetLocation(TK->GetLocation());
    BB->Mangle();
    BB->SetConst(Const);
    Id->SetExpression(BB);
    ASTSymbolTable::Instance().LocalScope(Id, ASTBoolNode::BoolBits, Ty);

    DN = new ASTDeclarationNode(Id, BB, Ty);
    assert(DN && "Could not create a valid NamedTypeDecl ASTDeclarationNode!");
  } break;
  case ASTTypeInt: {
    ASTIntNode *II = ASTBuilder::Instance().CreateASTIntNode(Id, int32_t(0));
    assert(II && "Could not create a valid ASTIntNode!");

    II->SetLocation(TK->GetLocation());
    II->Mangle();
    II->SetConst(Const);
    Id->SetExpression(II);
    ASTSymbolTable::Instance().LocalScope(Id, ASTIntNode::IntBits, Ty);

    DN = new ASTDeclarationNode(Id, II, Ty);
    assert(DN && "Could not create a valid NamedTypeDecl ASTDeclarationNode!");
  } break;
  case ASTTypeUInt: {
    ASTIntNode *II = ASTBuilder::Instance().CreateASTIntNode(Id, uint32_t(0));
    assert(II && "Could not create a valid ASTIntNode!");

    II->SetLocation(TK->GetLocation());
    II->Mangle();
    II->SetConst(Const);
    Id->SetExpression(II);
    ASTSymbolTable::Instance().LocalScope(Id, ASTIntNode::IntBits, ASTTypeInt);

    DN = new ASTDeclarationNode(Id, II, ASTTypeInt);
    assert(DN && "Could not create a valid NamedTypeDecl ASTDeclarationNode!");
  } break;
  case ASTTypeFloat: {
    ASTFloatNode *FF = ASTBuilder::Instance().CreateASTFloatNode(Id, 0.0f);
    assert(FF && "Could not create a valid ASTFloatNode!");

    FF->SetLocation(TK->GetLocation());
    FF->Mangle();
    FF->SetConst(Const);
    Id->SetExpression(FF);
    ASTSymbolTable::Instance().LocalScope(Id, ASTFloatNode::FloatBits, Ty);

    DN = new ASTDeclarationNode(Id, FF, Ty);
    assert(DN && "Could not create a valid NamedTypeDecl ASTDeclarationNode!");
  } break;
  case ASTTypeDouble: {
    ASTDoubleNode *DD = ASTBuilder::Instance().CreateASTDoubleNode(Id, 0.0);
    assert(DD && "Could not create a valid ASTDoubleNode!");

    DD->SetLocation(TK->GetLocation());
    DD->Mangle();
    DD->SetConst(Const);
    Id->SetExpression(DD);
    ASTSymbolTable::Instance().LocalScope(Id, ASTDoubleNode::DoubleBits, Ty);

    DN = new ASTDeclarationNode(Id, DD, Ty);
    assert(DN && "Could not create a valid NamedTypeDecl ASTDeclarationNode!");
  } break;
  case ASTTypeQubitContainer: {
    Id->SetBits(1U);
    ASTQubitContainerNode *QN =
        ASTBuilder::Instance().CreateASTQubitContainerNode(Id, 1U);
    assert(QN && "Could not create a valid ASTQubitContainerNode!");

    ASTSymbolTableEntry *STE = ASTSymbolTable::Instance().Lookup(Id, 1U, Ty);
    assert(STE && "Could not retrieve a valid SymbolTable Entry!");

    QN->LocalFunctionArgument();
    QN->SetLocation(TK->GetLocation());
    QN->Mangle();
    QN->SetConst(Const);
    Id->SetExpression(QN);
    ASTSymbolTable::Instance().LocalScope(Id, 1U, Ty);

    DN = new ASTDeclarationNode(Id, QN, Ty);
    assert(DN && "Could not create a valid NamedTypeDecl ASTDeclarationNode!");
  } break;
  case ASTTypeAngle: {
    ASTAngleNode *AN = ASTBuilder::Instance().CreateASTAngleNode(
        Id, ASTAngleNode::DetermineAngleType(Id));
    assert(AN && "Could not create a valid ASTAngleNode!");

    AN->SetLocation(TK->GetLocation());
    AN->Mangle();
    AN->SetConst(Const);
    Id->SetExpression(AN);
    ASTSymbolTable::Instance().TransferAngleToLSTM(Id, ASTAngleNode::AngleBits,
                                                   Ty);
    ASTSymbolTable::Instance().LocalScope(Id, ASTAngleNode::AngleBits, Ty);

    DN = new ASTDeclarationNode(Id, AN, Ty);
    assert(DN && "Could not create a valid NamedTypeDecl ASTDeclarationNode!");
  } break;
  case ASTTypeDuration: {
    ASTDurationNode *DDN;
    if (TS)
      DDN = ASTBuilder::Instance().CreateASTDurationNode(Id, TS->GetValue());
    else
      DDN = ASTBuilder::Instance().CreateASTDurationNode(Id, "0dt");
    assert(DDN && "Could not create a valid ASTDurationNode!");

    DDN->SetLocation(TK->GetLocation());
    DDN->Mangle();
    DDN->SetConst(Const);
    Id->SetExpression(DDN);
    ASTSymbolTable::Instance().LocalScope(Id, ASTDurationNode::DurationBits,
                                          Ty);

    DN = new ASTDeclarationNode(Id, DDN, Ty);
    assert(DN && "Could not create a valid NamedTypeDecl ASTDeclarationNode!");
  } break;
  case ASTTypeOpenPulseFrame: {
    ASTExpressionList EL;
    const unsigned FBits = OpenPulse::ASTOpenPulseFrameNode::FrameBits;

    OpenPulse::ASTOpenPulseFrameNode *FN =
        ASTBuilder::Instance().CreateASTOpenPulseFrameNode(Id, &EL);
    assert(FN && "Could not create a valid OpenPulse FrameNode!");

    FN->SetLocation(TK->GetLocation());
    FN->Mangle();
    FN->SetConst(Const);
    Id->SetExpression(FN);
    ASTSymbolTable::Instance().LocalScope(Id, FBits, Ty);

    DN = new ASTDeclarationNode(Id, FN, Ty);
    assert(DN && "Could not create a valid NamedTypeDecl ASTDeclarationNode!");
  } break;
  case ASTTypeOpenPulsePort: {
    const unsigned PBits = OpenPulse::ASTOpenPulsePortNode::PortBits;
    OpenPulse::ASTOpenPulsePortNode *PN =
        ASTBuilder::Instance().CreateASTOpenPulsePortNode(
            Id, static_cast<uint64_t>(lrand48()));
    assert(PN && "Could not create a valid OpenPulse PortNode!");

    PN->SetLocation(TK->GetLocation());
    PN->Mangle();
    PN->SetConst(Const);
    Id->SetExpression(PN);
    ASTSymbolTable::Instance().LocalScope(Id, PBits, Ty);

    DN = new ASTDeclarationNode(Id, PN, Ty);
    assert(DN && "Could not create a valid NamedTypeDecl ASTDeclarationNode!");
  } break;
  case ASTTypeOpenPulseWaveform: {
    ASTMPComplexList CXL;
    const unsigned WFBits = OpenPulse::ASTOpenPulseWaveformNode::WaveformBits;
    OpenPulse::ASTOpenPulseWaveformNode *WF =
        ASTBuilder::Instance().CreateASTOpenPulseWaveformNode(Id, CXL);
    assert(WF && "Could not create a valid OpenPulse WaveformNode!");

    WF->SetLocation(TK->GetLocation());
    WF->Mangle();
    WF->SetConst(Const);
    Id->SetExpression(WF);
    ASTSymbolTable::Instance().LocalScope(Id, WFBits, Ty);

    DN = new ASTDeclarationNode(Id, WF, Ty);
    assert(DN && "Could not create a valid NamedTypeDecl ASTDeclarationNode!");
  } break;
  default: {
    std::stringstream M;
    M << "Type " << PrintTypeEnum(Ty) << " cannot be used to instantiate "
      << "a fixed width NamedTypeDecl.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    DN = ASTDeclarationNode::DeclarationError(Id, M.str());
  } break;
  }

  DN->SetLocation(TK->GetLocation());
  return DN;
}

static ASTDeclarationNode *
CreateArbitrarySizeNamedTypeDecl(const ASTToken *TK,
                                 const ASTIdentifierNode *Id, ASTArrayNode *ARN,
                                 unsigned Bits, ASTType Ty, bool Const) {
  ASTDeclarationNode *DN = nullptr;

  switch (Ty) {
  case ASTTypeBitset: {
    Id->SetBits(Bits);
    ASTCBitNode *CB = ASTBuilder::Instance().CreateASTCBitNode(Id, Bits, 0UL);
    assert(CB && "Could not create a valid ASTCBitNode!");

    CB->SetLocation(TK->GetLocation());
    CB->Mangle();
    CB->SetConst(Const);
    Id->SetExpression(CB);
    ASTSymbolTable::Instance().LocalScope(Id, Bits, Ty);

    DN = new ASTDeclarationNode(Id, CB, Ty);
    assert(DN && "Could not create a valid NamedTypeDecl ASTDeclarationNode!");
  } break;
  case ASTTypeMPInteger: {
    Id->SetBits(Bits);
    ASTMPIntegerNode *MPI =
        ASTBuilder::Instance().CreateASTMPIntegerNode(Id, Bits);
    assert(MPI && "Could not create a valid ASTMPIntegerNode!");

    MPI->SetLocation(TK->GetLocation());
    MPI->Mangle();
    MPI->SetConst(Const);
    Id->SetExpression(MPI);
    ASTSymbolTable::Instance().LocalScope(Id, Bits, Ty);

    DN = new ASTDeclarationNode(Id, MPI, Ty);
    assert(DN && "Could not create a valid NamedTypeDecl ASTDeclarationNode!");
  } break;
  case ASTTypeMPUInteger: {
    Id->SetBits(Bits);
    ASTMPIntegerNode *MPI =
        ASTBuilder::Instance().CreateASTMPIntegerNode(Id, Bits, true);
    assert(MPI && "Could not create a valid ASTMPIntegerNode!");

    MPI->SetLocation(TK->GetLocation());
    MPI->Mangle();
    MPI->SetConst(Const);
    Id->SetExpression(MPI);
    ASTSymbolTable::Instance().LocalScope(Id, Bits, ASTTypeMPInteger);

    DN = new ASTDeclarationNode(Id, MPI, ASTTypeMPInteger);
    assert(DN && "Could not create a valid NamedTypeDecl ASTDeclarationNode!");
  } break;
  case ASTTypeQubitContainer: {
    Id->SetBits(Bits);
    ASTQubitContainerNode *QN =
        ASTBuilder::Instance().CreateASTQubitContainerNode(Id, Bits);
    assert(QN && "Could not create a valid ASTQubitContainerNode!");

    ASTSymbolTableEntry *STE = ASTSymbolTable::Instance().Lookup(Id, Bits, Ty);
    assert(STE && "Could not retrieve a valid SymbolTable Entry!");

    QN->SetLocation(TK->GetLocation());
    QN->LocalFunctionArgument();
    QN->Mangle();
    QN->SetConst(Const);
    Id->SetExpression(QN);
    ASTSymbolTable::Instance().LocalScope(Id, Bits, Ty);

    DN = new ASTDeclarationNode(Id, QN, ASTTypeQubitContainer);
    assert(DN && "Could not create a valid NamedTypeDecl ASTDeclarationNode!");
  } break;
  case ASTTypeAngle: {
    Id->SetBits(Bits);
    ASTAngleType ATy = ASTAngleNode::DetermineAngleType(Id);

    ASTAngleNode *AN = ASTBuilder::Instance().CreateASTAngleNode(Id, ATy, Bits);
    assert(AN && "Could not create a valid ASTAngleNode!");

    AN->SetLocation(TK->GetLocation());
    AN->Mangle();
    AN->SetConst(Const);
    Id->SetExpression(AN);
    ASTSymbolTable::Instance().TransferAngleToLSTM(Id, Bits, Ty);
    ASTSymbolTable::Instance().LocalScope(Id, Bits, Ty);

    DN = new ASTDeclarationNode(Id, AN, ASTTypeAngle);
    assert(DN && "Could not create a valid NamedTypeDecl ASTDeclarationNode!");
  } break;
  case ASTTypeMPDecimal: {
    Id->SetBits(Bits);
    ASTMPDecimalNode *MPD =
        ASTBuilder::Instance().CreateASTMPDecimalNode(Id, Bits);
    assert(MPD && "Could not create a valid ASTMPDecimalNode!");

    MPD->SetLocation(TK->GetLocation());
    MPD->Mangle();
    MPD->SetConst(Const);
    Id->SetExpression(MPD);
    ASTSymbolTable::Instance().LocalScope(Id, Bits, Ty);

    DN = new ASTDeclarationNode(Id, MPD, Ty);
    assert(DN && "Could not create a valid NamedTypeDecl ASTDeclarationNode!");
  } break;
  case ASTTypeMPComplex: {
    Id->SetBits(Bits);
    ASTMPComplexNode *MPC =
        ASTBuilder::Instance().CreateASTMPComplexNode(Id, Bits);
    assert(MPC && "Could not create a valid ASTMPComplexNode!");

    MPC->SetLocation(TK->GetLocation());
    MPC->Mangle();
    MPC->SetConst(Const);
    Id->SetExpression(MPC);
    ASTSymbolTable::Instance().LocalScope(Id, Bits, Ty);

    DN = new ASTDeclarationNode(Id, MPC, ASTTypeMPComplex);
    assert(DN && "Could not create a valid NamedTypeDecl ASTDeclarationNode!");
  } break;
  case ASTTypeCBitArray: {
    if (ASTCBitArrayNode *AN = dynamic_cast<ASTCBitArrayNode *>(ARN)) {
      ASTType ATy = AN->GetASTType();
      assert(ATy == Ty && "Array Type mismatch!");

      ASTSymbolTableEntry *STE =
          ASTSymbolTable::Instance().Lookup(Id, Id->GetBits(), ATy);
      assert(STE && "Could not retrieve a valid SymbolTable Entry!");

      STE->SetLocalScope();
      AN->SetLocation(TK->GetLocation());
      AN->Mangle();
      AN->SetConst(Const);
      Id->SetExpression(AN);
      ASTSymbolTable::Instance().LocalScope(Id, Id->GetBits(), ATy);

      DN = new ASTDeclarationNode(Id, AN, ATy);
      assert(DN &&
             "Could not create a valid NamedTypeDecl ASTDeclarationNode!");
    } else {
      std::string M("Could not dynamic_cast to a valid ASTCBitArrayNode.");
      DN = ASTDeclarationNode::DeclarationError(Id, M);
      DN->SetLocation(TK->GetLocation());
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(TK), M, DiagLevel::ICE);
      return DN;
    }
  } break;
  case ASTTypeQubitArray: {
    if (ASTQubitArrayNode *AN = dynamic_cast<ASTQubitArrayNode *>(ARN)) {
      ASTType ATy = AN->GetASTType();
      assert(ATy == Ty && "Array Type mismatch!");

      ASTSymbolTableEntry *STE =
          ASTSymbolTable::Instance().Lookup(Id, Id->GetBits(), ATy);
      assert(STE && "Could not retrieve a valid SymbolTable Entry!");

      STE->SetLocalScope();
      AN->SetLocation(TK->GetLocation());
      AN->Mangle();
      AN->SetConst(Const);
      Id->SetExpression(AN);
      ASTSymbolTable::Instance().LocalScope(Id, Id->GetBits(), ATy);

      DN = new ASTDeclarationNode(Id, AN, ATy);
      assert(DN &&
             "Could not create a valid NamedTypeDecl ASTDeclarationNode!");
    } else {
      std::string M("Could not dynamic_cast to a valid ASTQubitArrayNode.");
      DN = ASTDeclarationNode::DeclarationError(Id, M);
      DN->SetLocation(TK->GetLocation());
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(TK), M, DiagLevel::ICE);
      return DN;
    }
  } break;
  case ASTTypeAngleArray: {
    if (ASTAngleArrayNode *AN = dynamic_cast<ASTAngleArrayNode *>(ARN)) {
      ASTType ATy = AN->GetASTType();
      assert(ATy == Ty && "Array Type mismatch!");

      ASTSymbolTableEntry *STE =
          ASTSymbolTable::Instance().Lookup(Id, Id->GetBits(), ATy);
      assert(STE && "Could not retrieve a valid SymbolTable Entry!");

      STE->SetLocalScope();
      AN->SetLocation(TK->GetLocation());
      AN->Mangle();
      AN->SetConst(Const);
      Id->SetExpression(AN);
      ASTSymbolTable::Instance().LocalScope(Id, Id->GetBits(), ATy);

      DN = new ASTDeclarationNode(Id, AN, ATy);
      assert(DN &&
             "Could not create a valid NamedTypeDecl ASTDeclarationNode!");
    } else {
      std::string M("Could not dynamic_cast to a valid ASTAngleArrayNode.");
      DN = ASTDeclarationNode::DeclarationError(Id, M);
      DN->SetLocation(TK->GetLocation());
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(TK), M, DiagLevel::ICE);
      return DN;
    }
  } break;
  case ASTTypeBoolArray: {
    if (ASTBoolArrayNode *AN = dynamic_cast<ASTBoolArrayNode *>(ARN)) {
      ASTType ATy = AN->GetASTType();
      assert(ATy == Ty && "Array Type mismatch!");

      ASTSymbolTableEntry *STE =
          ASTSymbolTable::Instance().Lookup(Id, Id->GetBits(), ATy);
      assert(STE && "Could not retrieve a valid SymbolTable Entry!");

      STE->SetLocalScope();
      AN->SetLocation(TK->GetLocation());
      AN->Mangle();
      AN->SetConst(Const);
      Id->SetExpression(AN);
      ASTSymbolTable::Instance().LocalScope(Id, Id->GetBits(), ATy);

      DN = new ASTDeclarationNode(Id, AN, ATy);
      assert(DN &&
             "Could not create a valid NamedTypeDecl ASTDeclarationNode!");
    } else {
      std::string M("Could not dynamic_cast to a valid ASTBoolArrayNode.");
      DN = ASTDeclarationNode::DeclarationError(Id, M);
      DN->SetLocation(TK->GetLocation());
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(TK), M, DiagLevel::ICE);
      return DN;
    }
  } break;
  case ASTTypeIntArray: {
    if (ASTIntArrayNode *AN = dynamic_cast<ASTIntArrayNode *>(ARN)) {
      ASTType ATy = AN->GetASTType();
      assert(ATy == Ty && "Array Type mismatch!");

      ASTSymbolTableEntry *STE =
          ASTSymbolTable::Instance().Lookup(Id, Id->GetBits(), ATy);
      assert(STE && "Could not retrieve a valid SymbolTable Entry!");

      STE->SetLocalScope();
      AN->SetLocation(TK->GetLocation());
      AN->Mangle();
      AN->SetConst(Const);
      Id->SetExpression(AN);
      ASTSymbolTable::Instance().LocalScope(Id, Id->GetBits(), ATy);

      DN = new ASTDeclarationNode(Id, AN, ATy);
      assert(DN &&
             "Could not create a valid NamedTypeDecl ASTDeclarationNode!");
    } else {
      std::string M("Could not dynamic_cast to a valid ASTIntArrayNode.");
      DN = ASTDeclarationNode::DeclarationError(Id, M);
      DN->SetLocation(TK->GetLocation());
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(TK), M, DiagLevel::ICE);
      return DN;
    }
  } break;
  case ASTTypeMPIntegerArray: {
    if (ASTMPIntegerArrayNode *AN =
            dynamic_cast<ASTMPIntegerArrayNode *>(ARN)) {
      ASTType ATy = AN->GetASTType();
      assert(ATy == Ty && "Array Type mismatch!");

      ASTSymbolTableEntry *STE =
          ASTSymbolTable::Instance().Lookup(Id, Id->GetBits(), ATy);
      assert(STE && "Could not retrieve a valid SymbolTable Entry!");

      STE->SetLocalScope();
      AN->SetLocation(TK->GetLocation());
      AN->Mangle();
      AN->SetConst(Const);
      Id->SetExpression(AN);
      ASTSymbolTable::Instance().LocalScope(Id, Id->GetBits(), ATy);

      DN = new ASTDeclarationNode(Id, AN, ATy);
      assert(DN &&
             "Could not create a valid NamedTypeDecl ASTDeclarationNode!");
    } else {
      std::string M("Could not dynamic_cast to a valid ASTMPIntegerArrayNode.");
      DN = ASTDeclarationNode::DeclarationError(Id, M);
      DN->SetLocation(TK->GetLocation());
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(TK), M, DiagLevel::ICE);
      return DN;
    }
  } break;
  case ASTTypeFloatArray: {
    if (ASTFloatArrayNode *AN = dynamic_cast<ASTFloatArrayNode *>(ARN)) {
      ASTType ATy = AN->GetASTType();
      assert(ATy == Ty && "Array Type mismatch!");

      ASTSymbolTableEntry *STE =
          ASTSymbolTable::Instance().Lookup(Id, Id->GetBits(), ATy);
      assert(STE && "Could not retrieve a valid SymbolTable Entry!");

      STE->SetLocalScope();
      AN->SetLocation(TK->GetLocation());
      AN->Mangle();
      AN->SetConst(Const);
      Id->SetExpression(AN);
      ASTSymbolTable::Instance().LocalScope(Id, Id->GetBits(), ATy);

      DN = new ASTDeclarationNode(Id, AN, ATy);
      assert(DN &&
             "Could not create a valid NamedTypeDecl ASTDeclarationNode!");
    } else {
      std::string M("Could not dynamic_cast to a valid ASTFloatArrayNode.");
      DN = ASTDeclarationNode::DeclarationError(Id, M);
      DN->SetLocation(TK->GetLocation());
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(TK), M, DiagLevel::ICE);
      return DN;
    }
  } break;
  case ASTTypeMPDecimalArray: {
    if (ASTMPDecimalArrayNode *AN =
            dynamic_cast<ASTMPDecimalArrayNode *>(ARN)) {
      ASTType ATy = AN->GetASTType();
      assert(ATy == Ty && "Array Type mismatch!");

      ASTSymbolTableEntry *STE =
          ASTSymbolTable::Instance().Lookup(Id, Id->GetBits(), ATy);
      assert(STE && "Could not retrieve a valid SymbolTable Entry!");

      STE->SetLocalScope();
      AN->SetLocation(TK->GetLocation());
      AN->Mangle();
      AN->SetConst(Const);
      Id->SetExpression(AN);
      ASTSymbolTable::Instance().LocalScope(Id, Id->GetBits(), ATy);

      DN = new ASTDeclarationNode(Id, AN, ATy);
      assert(DN &&
             "Could not create a valid NamedTypeDecl ASTDeclarationNode!");
    } else {
      std::string M("Could not dynamic_cast to a valid ASTMPDecimalArrayNode.");
      DN = ASTDeclarationNode::DeclarationError(Id, M);
      DN->SetLocation(TK->GetLocation());
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(TK), M, DiagLevel::ICE);
      return DN;
    }
  } break;
  case ASTTypeMPComplexArray: {
    if (ASTMPComplexArrayNode *AN =
            dynamic_cast<ASTMPComplexArrayNode *>(ARN)) {
      ASTType ATy = AN->GetASTType();
      assert(ATy == Ty && "Array Type mismatch!");

      ASTSymbolTableEntry *STE =
          ASTSymbolTable::Instance().Lookup(Id, Id->GetBits(), ATy);
      assert(STE && "Could not retrieve a valid SymbolTable Entry!");

      STE->SetLocalScope();
      AN->SetLocation(TK->GetLocation());
      AN->Mangle();
      AN->SetConst(Const);
      Id->SetExpression(AN);
      ASTSymbolTable::Instance().LocalScope(Id, Id->GetBits(), ATy);

      DN = new ASTDeclarationNode(Id, AN, ATy);
      assert(DN &&
             "Could not create a valid NamedTypeDecl ASTDeclarationNode!");
    } else {
      std::string M("Could not dynamic_cast to a valid ASTMPComplexArrayNode.");
      DN = ASTDeclarationNode::DeclarationError(Id, M);
      DN->SetLocation(TK->GetLocation());
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(TK), M, DiagLevel::ICE);
      return DN;
    }
  } break;
  case ASTTypeDurationArray: {
    if (ASTDurationArrayNode *AN = dynamic_cast<ASTDurationArrayNode *>(ARN)) {
      ASTType ATy = AN->GetASTType();
      assert(ATy == Ty && "Array Type mismatch!");

      ASTSymbolTableEntry *STE =
          ASTSymbolTable::Instance().Lookup(Id, Id->GetBits(), ATy);
      assert(STE && "Could not retrieve a valid SymbolTable Entry!");

      STE->SetLocalScope();
      AN->SetLocation(TK->GetLocation());
      AN->Mangle();
      AN->SetConst(Const);
      Id->SetExpression(AN);
      ASTSymbolTable::Instance().LocalScope(Id, Id->GetBits(), ATy);

      DN = new ASTDeclarationNode(Id, AN, ATy);
      assert(DN &&
             "Could not create a valid NamedTypeDecl ASTDeclarationNode!");
    } else {
      std::string M("Could not dynamic_cast to a valid ASTDurationArrayNode.");
      DN = ASTDeclarationNode::DeclarationError(Id, M);
      DN->SetLocation(TK->GetLocation());
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(TK), M, DiagLevel::ICE);
      return DN;
    }
  } break;
  case ASTTypeOpenPulseFrameArray: {
    if (ASTOpenPulseFrameArrayNode *AN =
            dynamic_cast<ASTOpenPulseFrameArrayNode *>(ARN)) {
      ASTType ATy = AN->GetASTType();
      assert(ATy == Ty && "Array Type mismatch!");

      ASTSymbolTableEntry *STE =
          ASTSymbolTable::Instance().Lookup(Id, Id->GetBits(), ATy);
      assert(STE && "Could not retrieve a valid SymbolTable Entry!");

      STE->SetLocalScope();
      AN->SetLocation(TK->GetLocation());
      AN->Mangle();
      AN->SetConst(Const);
      Id->SetExpression(AN);
      ASTSymbolTable::Instance().LocalScope(Id, Id->GetBits(), ATy);

      DN = new ASTDeclarationNode(Id, AN, ATy);
      assert(DN &&
             "Could not create a valid NamedTypeDecl ASTDeclarationNode!");
    } else {
      std::string M(
          "Could not dynamic_cast to a valid ASTOpenPulseFrameArrayNode.");
      DN = ASTDeclarationNode::DeclarationError(Id, M);
      DN->SetLocation(TK->GetLocation());
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(TK), M, DiagLevel::ICE);
      return DN;
    }
  } break;
  case ASTTypeOpenPulsePortArray: {
    if (ASTOpenPulsePortArrayNode *AN =
            dynamic_cast<ASTOpenPulsePortArrayNode *>(ARN)) {
      ASTType ATy = AN->GetASTType();
      assert(ATy == Ty && "Array Type mismatch!");

      ASTSymbolTableEntry *STE =
          ASTSymbolTable::Instance().Lookup(Id, Id->GetBits(), ATy);
      assert(STE && "Could not retrieve a valid SymbolTable Entry!");

      STE->SetLocalScope();
      AN->SetLocation(TK->GetLocation());
      AN->Mangle();
      AN->SetConst(Const);
      Id->SetExpression(AN);
      ASTSymbolTable::Instance().LocalScope(Id, Id->GetBits(), ATy);

      DN = new ASTDeclarationNode(Id, AN, ATy);
      assert(DN &&
             "Could not create a valid NamedTypeDecl ASTDeclarationNode!");
    } else {
      std::string M(
          "Could not dynamic_cast to a valid ASTOpenPulsePortArrayNode.");
      DN = ASTDeclarationNode::DeclarationError(Id, M);
      DN->SetLocation(TK->GetLocation());
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(TK), M, DiagLevel::ICE);
      return DN;
    }
  } break;
  case ASTTypeOpenPulseWaveformArray: {
    if (ASTOpenPulseWaveformArrayNode *AN =
            dynamic_cast<ASTOpenPulseWaveformArrayNode *>(ARN)) {
      ASTType ATy = AN->GetASTType();
      assert(ATy == Ty && "Array Type mismatch!");

      ASTSymbolTableEntry *STE =
          ASTSymbolTable::Instance().Lookup(Id, Id->GetBits(), ATy);
      assert(STE && "Could not retrieve a valid SymbolTable Entry!");

      STE->SetLocalScope();
      AN->SetLocation(TK->GetLocation());
      AN->Mangle();
      AN->SetConst(Const);
      Id->SetExpression(AN);
      ASTSymbolTable::Instance().LocalScope(Id, Id->GetBits(), ATy);

      DN = new ASTDeclarationNode(Id, AN, ATy);
      assert(DN &&
             "Could not create a valid NamedTypeDecl ASTDeclarationNode!");
    } else {
      std::string M("Could not dynamic_cast to a valid "
                    "ASTOpenPulseWaveformArrayNode.");
      DN = ASTDeclarationNode::DeclarationError(Id, M);
      DN->SetLocation(TK->GetLocation());
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(TK), M, DiagLevel::ICE);
      return DN;
    }
  } break;
  default: {
    std::stringstream M;
    M << "Type " << PrintTypeEnum(Ty) << " cannot be used to instantiate "
      << "an arbitrary width NamedTypeDecl.";
    DN = ASTDeclarationNode::DeclarationError(Id, M.str());
  } break;
  }

  DN->SetLocation(TK->GetLocation());
  return DN;
}

ASTDeclarationNode *
ASTProductionFactory::ProductionRule_850(const ASTToken *TK,
                                         const ASTIdentifierNode *Id,
                                         ASTType Ty, bool Const) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");

  if (!TransferNamedTypeDeclIdentifier(Id, Ty)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for " << PrintTypeEnum(Ty)
      << '.';
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  ASTDeclarationNode *DN =
      CreateFixedSizeNamedTypeDecl(TK, Id, nullptr, Ty, Const);
  if (DN->IsError()) {
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), DN->GetError(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, DN->GetError());
  }

  DN->SetLocation(TK->GetLocation());
  DN->SetConst(Const);
  return DN;
}

ASTDeclarationNode *ASTProductionFactory::ProductionRule_850(
    const ASTToken *TK, const ASTIdentifierNode *Id, const ASTStringNode *TS,
    ASTType Ty, bool Const) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(TS && "Invalid ASTStringNode argument!");

  if (!TransferNamedTypeDeclIdentifier(Id, Ty)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for " << PrintTypeEnum(Ty)
      << '.';
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  ASTDeclarationNode *DN = CreateFixedSizeNamedTypeDecl(TK, Id, TS, Ty, Const);
  if (DN->IsError()) {
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), DN->GetError(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, DN->GetError());
  }

  DN->SetLocation(TK->GetLocation());
  DN->SetConst(Const);
  return DN;
}

ASTDeclarationNode *ASTProductionFactory::ProductionRule_850(
    const ASTToken *TK, const ASTIdentifierNode *Id,
    const std::variant<const ASTIntNode *, const ASTIdentifierNode *> &II,
    ASTType Ty, bool Const) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");

  unsigned Bits = ASTProductionFactory::Instance().GetVariantBits(II);
  if (ASTIdentifierNode::InvalidBits(Bits)) {
    std::stringstream M;
    M << "Invalid number of bits for arbitrary sized NamedTypeDecl.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  if (!TransferNamedTypeDeclIdentifier(Id, Ty)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for " << PrintTypeEnum(Ty)
      << '.';
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  ASTDeclarationNode *DN =
      CreateArbitrarySizeNamedTypeDecl(TK, Id, nullptr, Bits, Ty, Const);
  if (DN->IsError()) {
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), DN->GetError(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, DN->GetError());
  }

  DN->SetLocation(TK->GetLocation());
  DN->SetConst(Const);
  return DN;
}

ASTDeclarationNode *ASTProductionFactory::ProductionRule_850(
    const ASTToken *TK, const ASTIdentifierNode *Id, unsigned Size,
    ASTArrayNode *ARN, ASTType Ty, bool Const) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(ARN && "Invalid ASTArrayNode argument!");

  if (ASTIdentifierNode::InvalidBits(Size)) {
    std::stringstream M;
    M << "Invalid number of bits for arbitrary sized NamedTypeDecl.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  if (!TransferNamedTypeDeclIdentifier(Id, Size, Ty)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for " << PrintTypeEnum(Ty)
      << '.';
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  ASTDeclarationNode *DN =
      CreateArbitrarySizeNamedTypeDecl(TK, Id, ARN, Size, Ty, Const);
  if (DN->IsError()) {
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), DN->GetError(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, DN->GetError());
  }

  DN->SetLocation(TK->GetLocation());
  DN->SetConst(Const);
  return DN;
}

ASTDeclarationNode *ASTProductionFactory::ProductionRule_850(
    const ASTToken *TK, const ASTIdentifierNode *Id, bool Const) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTidentifierNode argument!");

  ASTScopeController::Instance().CheckScopeAndUndefined(Id);

  ASTAngleNode *AN = nullptr;
  ASTDeclarationNode *DN = nullptr;

  if (ASTAngleContextControl::Instance().InOpenContext() &&
      ASTTypeSystemBuilder::Instance().IsImplicitAngle(Id->GetName())) {
    ASTSymbolTableEntry *STE = ASTSymbolTable::Instance().Lookup(
        Id, ASTAngleNode::AngleBits, ASTTypeAngle);
    if (STE && STE->HasValue()) {
      AN = STE->GetValue()->GetValue<ASTAngleNode *>();
      assert(AN && "Could not obtain a valid ASTAngleNode "
                   "from the SymbolTable!");
    } else {
      ASTAngleType ATy = ASTAngleNode::DetermineAngleType(Id->GetName());
      AN = ASTBuilder::Instance().CreateASTAngleNode(Id->GetName(), ATy,
                                                     ASTAngleNode::AngleBits);
      assert(AN && "Could not create a valid ASTAngleNode!");

      AN->SetLocation(TK->GetLocation());
      AN->Mangle();
      AN->SetConst(Const);
      Id->SetExpression(AN);
      ASTSymbolTable::Instance().LocalScope(Id, ASTAngleNode::AngleBits,
                                            ASTTypeAngle);

      STE = ASTSymbolTable::Instance().Lookup(Id, ASTAngleNode::AngleBits,
                                              ASTTypeAngle);
      assert(STE && "Could not obtain a valid SymbolTable Entry!");
      STE->SetLocalScope();
    }
  } else if (!ASTTypeSystemBuilder::Instance().IsReservedAngle(Id->GetName())) {
    if (!(AN = ASTAngleNodeBuilder::Instance().FindInMap(
              Id->GetName(), ASTAngleNode::AngleBits))) {
      Id->SetBits(ASTAngleNode::AngleBits);
      const_cast<ASTIdentifierNode *>(Id)->SetLocalScope();
      ASTIdentifierNode *AId = ASTBuilder::Instance().CreateASTIdentifierNode(
          Id->GetName(), ASTAngleNode::AngleBits, ASTTypeAngle);
      assert(AId && "Could not create a valid Angle ASTIdentifierNode!");

      AN = ASTBuilder::Instance().CreateASTAngleNode(AId, ASTAngleTypeGeneric,
                                                     ASTAngleNode::AngleBits);
      assert(AN && "Could not create a valid ASTAngleNode!");

      AN->SetLocation(TK->GetLocation());
      AN->Mangle();
      AN->SetConst(Const);
      AId->SetExpression(AN);
      ASTSymbolTable::Instance().LocalScope(Id, ASTAngleNode::AngleBits,
                                            ASTTypeAngle);
      ASTSymbolTableEntry *STE = ASTSymbolTable::Instance().Lookup(
          AId, ASTAngleNode::AngleBits, ASTTypeAngle);
      assert(STE && "Implicit Angle Node has no SymbolTable Entry!");
      assert(STE->HasValue() && "Implicit Angle Node SymbolTable Entry "
                                "has no Value!");

      STE->SetLocalScope();
    }
  } else {
    AN = ASTAngleNodeBuilder::Instance().FindInMap(Id->GetName(),
                                                   ASTAngleNode::AngleBits);
    assert(AN && "Could not retrieve a valid reserved Angle!");
    ASTSymbolTable::Instance().LocalScope(Id, ASTAngleNode::AngleBits,
                                          ASTTypeAngle);
  }

  assert(AN && "Could not obtain a valid ASTAngleNode!");
  if (!AN) {
    std::stringstream M;
    M << "Could not create a valid implicit ASTAngleNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  DN = new ASTDeclarationNode(Id, AN, ASTTypeAngle);
  assert(DN && "Could not create a valid NamedTypeDecl ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  DN->SetConst(Const);
  return DN;
}

ASTDeclarationNode *
ASTProductionFactory::ProductionRule_850(const ASTToken *TK,
                                         ASTEllipsisNode *EL) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(EL && "Invalid ASTEllipsisNode argument!");

  EL->SetLocation(TK->GetLocation());
  EL->Mangle();
  ASTSymbolTable::Instance().LocalScope(
      EL->GetIdentifier(), ASTEllipsisNode::EllipsisBits, ASTTypeEllipsis);

  ASTDeclarationNode *DN =
      new ASTDeclarationNode(EL->GetIdentifier(), EL, EL->GetASTType());
  assert(DN && "Could not create a valid NamedTypeDecl ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  return DN;
}

ASTForLoopRangeExpressionNode *ASTProductionFactory::ProductionRule_860(
    const ASTToken *TK, const ASTIdentifierNode *Id, const ASTIntegerList *IL,
    const std::variant<const ASTIntNode *, const ASTIdentifierNode *> &II,
    ASTOpType OTy) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(IL && "Invalid ASTIntegerList argument!");

  ASTScopeController::Instance().CheckIdentifier(Id);

  std::stringstream OS;
  OS << "ast-for-range-binary-op-" << PrintDashOpTypeEnum(OTy) << '-'
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTBinaryOpNode *BOP = nullptr;

  switch (II.index()) {
  case 0: {
    if (const ASTIntNode *IIi = std::get<0>(II)) {
      BOP =
          ASTBuilder::Instance().CreateASTBinaryOpNode(OS.str(), Id, IIi, OTy);
      assert(BOP && "Could not create a valid ASTBinaryOpNode!");
      BOP->SetLocation(TK->GetLocation());
      BOP->Mangle();
    } else {
      std::stringstream M;
      M << "Invalid ASTIntNode operand obtained from std::variant.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
      return ASTForLoopRangeExpressionNode::ExpressionError(M.str());
    }
  } break;
  case 1: {
    if (const ASTIdentifierNode *IId = std::get<1>(II)) {
      BOP =
          ASTBuilder::Instance().CreateASTBinaryOpNode(OS.str(), Id, IId, OTy);
      assert(BOP && "Could not create a valid ASTBinaryOpNode!");
      BOP->SetLocation(TK->GetLocation());
      BOP->Mangle();
    } else {
      std::stringstream M;
      M << "Invalid ASTIdentifierNode operand obtained from std::variant.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
      return ASTForLoopRangeExpressionNode::ExpressionError(M.str());
    }
  } break;
  default: {
    std::stringstream M;
    M << "Invalid std::variant index.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTForLoopRangeExpressionNode::ExpressionError(M.str());
  } break;
  }

  if (!BOP) {
    std::stringstream M;
    M << "Could not create a valid ASTBinaryOpNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTForLoopRangeExpressionNode::ExpressionError(M.str());
  }

  ASTForLoopRangeExpressionNode *LRE =
      new ASTForLoopRangeExpressionNode(*IL, BOP);
  assert(LRE && "Could not create a valid ASTForLoopRangeExpressionNode!");

  LRE->SetLocation(TK->GetLocation());
  LRE->Mangle();
  return LRE;
}

ASTGPhaseExpressionNode *
ASTProductionFactory::ProductionRule_870(const ASTToken *TK,
                                         const ASTIdentifierNode *TId) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(TId && "Invalid ASTIdentifierNode argument!");

  ASTScopeController::Instance().CheckIdentifier(TId);

  std::stringstream IS;
  IS << "ast-gphase-" << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      IS.str(), ASTGPhaseExpressionNode::GPhaseBits, ASTTypeGPhaseExpression);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  ASTGPhaseExpressionNode *GPE =
      ASTBuilder::Instance().CreateASTGPhaseExpressionNode(Id, TId);
  assert(GPE && "Could not create a valid ASTGPhaseExpressionNode!");

  if (!GPE) {
    std::stringstream M;
    M << "Could not create a valid ASTGPhaseExpressionNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTGPhaseExpressionNode::ExpressionError(M.str());
  }

  GPE->SetLocation(TK->GetLocation());
  GPE->Mangle();
  return GPE;
}

ASTGPhaseExpressionNode *
ASTProductionFactory::ProductionRule_870(const ASTToken *TK,
                                         const ASTBinaryOpNode *BOP) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(BOP && "Invalid ASTBinaryOpNode argument!");

  std::stringstream IS;
  IS << "ast-gphase-" << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      IS.str(), ASTGPhaseExpressionNode::GPhaseBits, ASTTypeGPhaseExpression);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  ASTGPhaseExpressionNode *GPE =
      ASTBuilder::Instance().CreateASTGPhaseExpressionNode(Id, BOP);
  assert(GPE && "Could not create a valid ASTGPhaseExpressionNode!");

  if (!GPE) {
    std::stringstream M;
    M << "Could not create a valid ASTGPhaseExpressionNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTGPhaseExpressionNode::ExpressionError(M.str());
  }

  GPE->SetLocation(TK->GetLocation());
  GPE->Mangle();
  return GPE;
}

ASTGPhaseExpressionNode *
ASTProductionFactory::ProductionRule_870(const ASTToken *TK,
                                         const ASTUnaryOpNode *UOP) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(UOP && "Invalid ASTUnaryOpNode argument!");

  std::stringstream IS;
  IS << "ast-gphase-" << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      IS.str(), ASTGPhaseExpressionNode::GPhaseBits, ASTTypeGPhaseExpression);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  ASTGPhaseExpressionNode *GPE =
      ASTBuilder::Instance().CreateASTGPhaseExpressionNode(Id, UOP);
  assert(GPE && "Could not create a valid ASTGPhaseExpressionNode!");

  if (!GPE) {
    std::stringstream M;
    M << "Could not create a valid ASTGPhaseExpressionNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTGPhaseExpressionNode::ExpressionError(M.str());
  }

  GPE->SetLocation(TK->GetLocation());
  GPE->Mangle();
  return GPE;
}

ASTComplexExpressionNode *
ASTProductionFactory::ProductionRule_880(const ASTToken *TK,
                                         const ASTBinaryOpNode *BOP) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(BOP && "Invalid ASTBinaryOpNode argument!");

  std::stringstream S;
  S << "ast-complex-expression-"
    << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      S.str(), ASTComplexExpressionNode::ExpressionBits,
      ASTTypeComplexExpression);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  BOP->MakeImaginary();
  ASTComplexExpressionNode *ACE =
      ASTBuilder::Instance().CreateASTComplexExpressionNode(Id, BOP);
  assert(ACE && "Could not create a valid ASTComplexExpressionNode!");

  ACE->SetLocation(TK->GetLocation());
  ACE->Mangle();
  return ACE;
}

ASTComplexExpressionNode *
ASTProductionFactory::ProductionRule_880(const ASTToken *TK,
                                         const ASTUnaryOpNode *UOP) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(UOP && "Invalid ASTUnaryOpNode argument!");

  std::stringstream S;
  S << "ast-complex-expression-"
    << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      S.str(), ASTComplexExpressionNode::ExpressionBits,
      ASTTypeComplexExpression);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  ASTMPDecimalNode *MPD = new ASTMPDecimalNode(
      ASTIdentifierNode::MPDec.Clone(), ASTMPDecimalNode::DefaultBits, 1.0);
  assert(MPD && "Could not create a valid ASTMPDecimalNode!");

  ASTBinaryOpNode *BOP = new ASTBinaryOpNode(
      ASTIdentifierNode::BinaryOp.Clone(), UOP, MPD, ASTOpTypeMul);
  assert(BOP && "Could not create a valid ASTBinaryOpNode!");

  BOP->MakeImaginary();
  ASTComplexExpressionNode *ACE =
      ASTBuilder::Instance().CreateASTComplexExpressionNode(Id, BOP);
  assert(ACE && "Could not create a valid ASTComplexExpressionNode!");

  ACE->SetLocation(TK->GetLocation());
  ACE->Mangle();
  return ACE;
}

ASTDeclarationNode *
ASTProductionFactory::ProductionRule_150(const ASTToken *TK,
                                         const ASTIdentifierNode *Id) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
          Id, ASTDoubleNode::DoubleBits, ASTTypeDouble)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeDouble.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
    std::stringstream M;
    M << "Declaration " << Id->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  ASTDoubleNode *DBL =
      ASTBuilder::Instance().CreateASTDoubleNode(Id, double(0.0));
  assert(DBL && "Could not create a valid ASTDoubleNode!");

  DBL->SetLocation(TK->GetLocation());
  DBL->Mangle();
  ASTDeclarationNode *DN =
      new ASTDeclarationNode(Id, DBL, ASTTypeDouble, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *
ASTProductionFactory::ProductionRule_151(const ASTToken *TK,
                                         const ASTIdentifierNode *Id,
                                         const ASTExpressionNode *EN) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(EN && "Invalid ASTExpressionNode argument!");

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
          Id, ASTDoubleNode::DoubleBits, ASTTypeDouble)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeDouble.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
    std::stringstream M;
    M << "Declaration " << Id->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  ASTDoubleNode *DN = nullptr;

  if (EN->GetASTType() == ASTTypeDouble) {
    const ASTDoubleNode *EDN = dynamic_cast<const ASTDoubleNode *>(EN);
    assert(EDN && "Could not dynamic_cast to an ASTDoubleNode!");
    DN = ASTBuilder::Instance().CreateASTDoubleNode(Id, EDN->GetValue());
  } else if (EN->GetASTType() == ASTTypeFloat) {
    const ASTFloatNode *EFN = dynamic_cast<const ASTFloatNode *>(EN);
    assert(EFN && "Could not dynamic_cast to an ASTFloatNode!");
    DN = ASTBuilder::Instance().CreateASTDoubleNode(Id, EFN->GetValue());
  } else if (EN->GetASTType() == ASTTypeInt) {
    const ASTIntNode *EIN = dynamic_cast<const ASTIntNode *>(EN);
    assert(EIN && "Could not dynamic_cast to an ASTIntNode!");

    int64_t V = EIN->IsSigned() ? EIN->GetSignedValue()
                                : static_cast<int64_t>(EIN->GetUnsignedValue());
    DN = ASTBuilder::Instance().CreateASTDoubleNode(Id, double(V));
  } else {
    const ASTImplicitConversionNode *ICX = new ASTImplicitConversionNode(
        EN, ASTTypeDouble, ASTDoubleNode::DoubleBits);
    assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    DN = ASTBuilder::Instance().CreateASTDoubleNode(Id, ICX);
  }

  assert(DN && "Could not create a valid ASTDoubleNode!");

  DN->SetLocation(TK->GetLocation());
  DN->Mangle();
  ASTDeclarationNode *DDN =
      new ASTDeclarationNode(Id, DN, ASTTypeDouble, false);
  assert(DDN && "Could not create a valid ASTDeclarationNode!");

  DDN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DDN);
  ASTDeclarationBuilder::Instance().Append(DDN);
  return DDN;
}

ASTDeclarationNode *
ASTProductionFactory::ProductionRule_140(const ASTToken *TK,
                                         const ASTIdentifierNode *Id) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
          Id, ASTFloatNode::FloatBits, ASTTypeFloat)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeFloat.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
    std::stringstream M;
    M << "Declaration " << Id->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  ASTFloatNode *FLT = ASTBuilder::Instance().CreateASTFloatNode(Id, 0.0f);
  assert(FLT && "Could not create a valid ASTFloatNode!");

  FLT->SetLocation(TK->GetLocation());
  FLT->Mangle();

  ASTDeclarationNode *DN = new ASTDeclarationNode(Id, FLT, ASTTypeFloat, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *
ASTProductionFactory::ProductionRule_141(const ASTToken *TK,
                                         const ASTIdentifierNode *DId,
                                         const ASTExpressionNode *EN) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DId && "Invalid ASTIdentifierNode argument!");
  assert(EN && "Invalid ASTExpressionNode argument!");

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
          DId, ASTFloatNode::FloatBits, ASTTypeFloat)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeFloat.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(DId)) {
    std::stringstream M;
    M << "Declaration " << DId->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  ASTFloatNode *FIN = nullptr;
  ASTAngleNode *AN = nullptr;
  bool FromArray = false;
  bool FromValue = false;
  bool FromExpr = false;
  bool FromAngle = false;
  float FV;

  ASTType ETy = EN->GetASTType();

  switch (ETy) {
  case ASTTypeInt:
    if (const ASTIntNode *I = dynamic_cast<const ASTIntNode *>(EN)) {
      FromValue = true;
      if (I->IsSigned())
        FV = static_cast<float>(I->GetSignedValue());
      else
        FV = static_cast<float>(I->GetUnsignedValue());
    }
    break;
  case ASTTypeBool:
    if (const ASTBoolNode *B = dynamic_cast<const ASTBoolNode *>(EN)) {
      FromValue = true;
      FV = static_cast<float>(static_cast<int32_t>(B->GetValue()));
    }
    break;
  case ASTTypeFloat:
    if (const ASTFloatNode *F = dynamic_cast<const ASTFloatNode *>(EN)) {
      FromValue = true;
      FV = F->GetValue();
    }
    break;
  case ASTTypeDouble:
    if (const ASTDoubleNode *D = dynamic_cast<const ASTDoubleNode *>(EN)) {
      FromValue = true;
      FV = static_cast<float>(D->GetValue());
    }
    break;
  case ASTTypeLongDouble:
    if (const ASTLongDoubleNode *LD =
            dynamic_cast<const ASTLongDoubleNode *>(EN)) {
      FromValue = true;
      FV = static_cast<float>(LD->GetValue());
    }
    break;
  case ASTTypeMPInteger:
    if (const ASTMPIntegerNode *MPI =
            dynamic_cast<const ASTMPIntegerNode *>(EN)) {
      FromValue = true;
      FV = static_cast<float>(MPI->ToSignedInt());
    }
    break;
  case ASTTypeMPDecimal:
    if (const ASTMPDecimalNode *MPD =
            dynamic_cast<const ASTMPDecimalNode *>(EN)) {
      FromValue = true;
      FV = MPD->ToFloat();
    }
    break;
  case ASTTypeAngle: {
    if (const ASTAngleNode *AAN = dynamic_cast<const ASTAngleNode *>(EN)) {
      FromValue = true;
      FV = AAN->AsFloat();
    }
  } break;
  case ASTTypeBinaryOp:
  case ASTTypeUnaryOp:
  case ASTTypeExpression:
  case ASTTypeCast:
    FromExpr = true;
    break;
  case ASTTypeCBitArray:
  case ASTTypeCBitNArray:
  case ASTTypeQubitArray:
  case ASTTypeQubitNArray:
  case ASTTypeAngleArray:
  case ASTTypeBoolArray:
  case ASTTypeMPIntegerArray:
  case ASTTypeMPDecimalArray:
  case ASTTypeLengthArray:
  case ASTTypeDurationArray:
  case ASTTypeFloatArray:
  case ASTTypeIntArray: {
    std::stringstream M;
    M << "An array cannot be assigned to a floating-point scalar.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  } break;
  case ASTTypeQubit: {
    std::stringstream M;
    M << "A Qubit cannot be assigned to a floating-point scalar.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  } break;
  case ASTTypeBitset: {
    std::stringstream M;
    M << "A Bitset cannot be assigned to a floating-point scalar.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  } break;
  case ASTTypeIdentifier: {
    const ASTIdentifierNode *IId =
        EN->IsIdentifier() ? EN->GetIdentifier()
        : EN->IsExpression()
            ? dynamic_cast<const ASTIdentifierNode *>(EN->GetExpression())
            : nullptr;
    assert(IId && "Could not obtain an unindexed ASTIdentifierNode!");

    ASTScopeController::Instance().CheckUndefined(IId);
    ASTScopeController::Instance().CheckOutOfScope(IId);

    const ASTIdentifierRefNode *IdR =
        dynamic_cast<const ASTIdentifierRefNode *>(IId);
    // FIXME: Implicit Casts.
    if (IdR && IdR->IsIndexed()) {
      IdR = dynamic_cast<const ASTIdentifierRefNode *>(EN->GetExpression());
      assert(IdR && "Could not dynamic_cast to an ASTIdentifierRefNode!");
    }

    if (IdR && IdR->IsIndexed()) {
      const ASTSymbolTableEntry *STE = IdR->GetSymbolTableEntry();
      assert(STE && "ASTIdentifierRefNode has no SymbolTable Entry!");

      if (STE->GetValueType() != ASTTypeFloat) {
        std::stringstream M;
        M << "Impossible ASTFloatNode Initialization from an "
          << PrintTypeEnum(ETy) << ".";
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(DId), M.str(),
            DiagLevel::Error);
        return ASTDeclarationNode::DeclarationError(DId, M.str());
      }

      FIN = STE->GetValue()->GetValue<ASTFloatNode *>();
      assert(FIN && "Could not obtain a valid ASTFloatNode from "
                    "the ASTFloatArrayNode!");
      FromArray = true;
    } else if (IId && !IdR) {
      if (ASTTypeSystemBuilder::Instance().IsReservedAngle(IId->GetName())) {
        AN = ASTAngleNodeBuilder::Instance().FindInMap(IId->GetName(),
                                                       ASTAngleNode::AngleBits);
        assert(
            AN &&
            "Could not obtain a valid Reserved Angle from the Symbol Table!");
        FromAngle = true;
        FV = AN->AsFloat();
      } else {
        AN = ASTAngleNodeBuilder::Instance().FindInMap(IId->GetName(),
                                                       ASTAngleNode::AngleBits);
        if (AN) {
          FromAngle = true;
          FV = AN->AsFloat();
        }
      }
    } else {
      std::stringstream M;
      M << "Impossible ASTFloatNode Initialization from an "
        << PrintTypeEnum(ETy) << "!";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(DId), M.str(),
          DiagLevel::Error);
      return ASTDeclarationNode::DeclarationError(DId, M.str());
    }
  } break;
  default: {
    std::stringstream M;
    M << "Impossible ASTFloatNode Initialization from an " << PrintTypeEnum(ETy)
      << "!";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  } break;
  }

  ASTFloatNode *FLT = nullptr;

  if (FromArray) {
    FLT = ASTBuilder::Instance().CreateASTFloatNode(DId, FIN->GetValue());
  } else if (FromValue) {
    FLT = ASTBuilder::Instance().CreateASTFloatNode(DId, FV);
  } else if (FromAngle) {
    FLT = ASTBuilder::Instance().CreateASTFloatNode(DId, FV);
  } else if (FromExpr) {
    if (EN->GetASTType() == ASTTypeCast) {
      const ASTCastExpressionNode *CX =
          dynamic_cast<const ASTCastExpressionNode *>(EN);
      assert(CX && "Could not dynamic_cast to an ASTCastExpressionNode!");
      FLT = ASTBuilder::Instance().CreateASTFloatNode(DId, CX);
    } else {
      FLT = ASTBuilder::Instance().CreateASTFloatNode(DId, EN);
    }
  } else {
    FLT = ASTBuilder::Instance().CreateASTFloatNode(DId, EN);
  }

  assert(FLT && "Could not create a valid ASTFloatNode!");

  FLT->SetLocation(TK->GetLocation());
  FLT->Mangle();
  ASTDeclarationNode *DN =
      new ASTDeclarationNode(DId, FLT, ASTTypeFloat, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *ASTProductionFactory::ProductionRule_142(
    const ASTToken *TK, const ASTIdentifierNode *DId,
    const ASTFunctionCallStatementNode *FC) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DId && "Invalid ASTIdentifierNode argument!");
  assert(FC && "Invalid ASTFunctionCallStatementNode argument!");

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
          DId, ASTFloatNode::FloatBits, ASTTypeFloat)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeFloat.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(DId)) {
    std::stringstream M;
    M << "Declaration " << DId->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  const ASTFunctionCallNode *EN = FC->GetFunctionCall();
  assert(EN && "Could not obtain a valid ASTFunctionCallNode!");

  if (!EN->ReturnsResult()) {
    std::stringstream M;
    M << "Assignment requires a non-void return type.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  ASTFloatNode *FLT = ASTBuilder::Instance().CreateASTFloatNode(DId, EN);
  assert(FLT && "Could not create a valid ASTFloatNode!");

  FLT->SetLocation(TK->GetLocation());
  FLT->Mangle();
  ASTDeclarationNode *DN =
      new ASTDeclarationNode(DId, FLT, ASTTypeFloat, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *
ASTProductionFactory::ProductionRule_143(const ASTToken *TK,
                                         const ASTIdentifierNode *Id,
                                         const ASTIntNode *II) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(II && "Invalid bit width size ASTIntNode argument!");

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(II);
  assert(!ASTIdentifierNode::InvalidBits(Bits) &&
         "Invalid number of bits for ASTMPDecimal!");

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(Id, Bits,
                                                          ASTTypeMPDecimal)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeMPDecimal.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
    std::stringstream M;
    M << "Declaration " << Id->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  ASTMPDecimalNode *MPD =
      ASTBuilder::Instance().CreateASTMPDecimalNode(Id, Bits);
  assert(MPD && "Could not create an ASTMPDecimalNode!");

  MPD->SetLocation(TK->GetLocation());
  MPD->Mangle();
  ASTDeclarationNode *DN =
      new ASTDeclarationNode(Id, MPD, ASTTypeMPDecimal, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *
ASTProductionFactory::ProductionRule_144(const ASTToken *TK,
                                         const ASTIdentifierNode *Id,
                                         const ASTIdentifierNode *IId) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(IId && "Invalid ASTIdentifierNode argument!");

  ASTScopeController::Instance().CheckUndefined(IId);
  ASTScopeController::Instance().CheckOutOfScope(IId);

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(IId);
  assert(!ASTIdentifierNode::InvalidBits(Bits) &&
         "Invalid number of Bits for Index Identifier!");

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(Id, Bits,
                                                          ASTTypeMPDecimal)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeMPDecimal.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
    std::stringstream M;
    M << "Declaration " << Id->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  ASTMPDecimalNode *MPD =
      ASTBuilder::Instance().CreateASTMPDecimalNode(Id, Bits);
  assert(MPD && "Could not create an ASTMPDecimalNode!");

  MPD->SetLocation(TK->GetLocation());
  MPD->Mangle();
  ASTDeclarationNode *DN =
      new ASTDeclarationNode(Id, MPD, ASTTypeMPDecimal, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *ASTProductionFactory::ProductionRule_145(
    const ASTToken *TK, const ASTIdentifierNode *DId, const ASTIntNode *II,
    const ASTExpressionNode *EN) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DId && "Invalid ASTIdentifierNode argument!");
  assert(II && "Invalid ASTIntNode bit width argument!");
  assert(EN && "Invalid ASTExpressionNode argument!");

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(II);
  assert(!ASTIdentifierNode::InvalidBits(Bits) &&
         "Invalid number of Bits for Index Identifier!");

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(DId, Bits,
                                                          ASTTypeMPDecimal)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeMPDecimal.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(DId)) {
    std::stringstream M;
    M << "Declaration " << DId->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  std::string MPDVS;
  bool FromArray = false;
  bool FromValue = false;
  bool FromExpr = false;
  const ASTImplicitConversionNode *ICX = nullptr;
  mpfr_t MPV;

  ASTType ETy = EN->GetASTType();

  switch (ETy) {
  case ASTTypeBool: {
    if (const ASTBoolNode *BN = dynamic_cast<const ASTBoolNode *>(EN)) {
      FromValue = true;
      mpfr_init2(MPV, Bits);
      mpfr_set_ui(MPV, static_cast<unsigned>(BN->GetValue()), MPFR_RNDN);
      ICX = new ASTImplicitConversionNode(BN, ASTTypeMPDecimal, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
  } break;
  case ASTTypeInt: {
    if (const ASTIntNode *IN = dynamic_cast<const ASTIntNode *>(EN)) {
      FromValue = true;
      mpfr_init2(MPV, Bits);
      if (IN->IsSigned())
        mpfr_set_si(MPV, IN->GetSignedValue(), MPFR_RNDN);
      else
        mpfr_set_ui(MPV, IN->GetUnsignedValue(), MPFR_RNDN);
      ICX = new ASTImplicitConversionNode(IN, ASTTypeMPDecimal, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
  } break;
  case ASTTypeFloat: {
    if (const ASTFloatNode *FN = dynamic_cast<const ASTFloatNode *>(EN)) {
      FromValue = true;
      mpfr_init2(MPV, Bits);
      mpfr_set_flt(MPV, FN->GetValue(), MPFR_RNDN);
      ICX = new ASTImplicitConversionNode(FN, ASTTypeMPDecimal, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
  } break;
  case ASTTypeDouble: {
    if (const ASTDoubleNode *DN = dynamic_cast<const ASTDoubleNode *>(EN)) {
      FromValue = true;
      mpfr_init2(MPV, Bits);

      if (DN->IsString() || DN->IsMP()) {
        if (ASTMPDecimalNode::InitMPFRFromString(
                MPV, DN->GetString().c_str()) != 0) {
          std::stringstream M;
          M << "Failed conversion from String to ASTMPDecimal.";
          QasmDiagnosticEmitter::Instance().EmitDiagnostic(
              DIAGLineCounter::Instance().GetLocation(EN), M.str(),
              DiagLevel::Error);
          return ASTDeclarationNode::DeclarationError(DId, M.str());
        }
      } else {
        mpfr_set_d(MPV, DN->GetValue(), MPFR_RNDN);
      }

      ICX = new ASTImplicitConversionNode(DN, ASTTypeMPDecimal, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
  } break;
  case ASTTypeLongDouble: {
    if (const ASTLongDoubleNode *LN =
            dynamic_cast<const ASTLongDoubleNode *>(EN)) {
      FromValue = true;
      mpfr_init2(MPV, Bits);
      mpfr_set_ld(MPV, LN->GetValue(), MPFR_RNDN);
      ICX = new ASTImplicitConversionNode(LN, ASTTypeMPDecimal, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
  } break;
  case ASTTypeMPInteger: {
    if (const ASTMPIntegerNode *MPI =
            dynamic_cast<const ASTMPIntegerNode *>(EN)) {
      FromValue = true;
      mpfr_init2(MPV, Bits);
      mpfr_set_z(MPV, MPI->GetMPValue(), MPFR_RNDN);
      ICX = new ASTImplicitConversionNode(MPI, ASTTypeMPDecimal, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
  } break;
  case ASTTypeMPDecimal: {
    if (const ASTMPDecimalNode *MPDD =
            dynamic_cast<const ASTMPDecimalNode *>(EN)) {
      FromValue = true;
      mpfr_set(MPV, MPDD->GetMPValue(), MPFR_RNDN);
    }
  } break;
  case ASTTypeBitset: {
    if (const ASTCBitNode *CB = dynamic_cast<const ASTCBitNode *>(EN)) {
      FromValue = true;
      mpfr_init2(MPV, Bits);
      if (mpfr_set_str(MPV, CB->AsString().c_str(), 2, MPFR_RNDN) != 0)
        mpfr_set_nan(MPV);
      ICX = new ASTImplicitConversionNode(CB, ASTTypeMPDecimal, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
  } break;
  case ASTTypeAngle: {
    if (const ASTAngleNode *AN = dynamic_cast<const ASTAngleNode *>(EN)) {
      FromValue = true;
      mpfr_init2(MPV, Bits);
      mpfr_set(MPV, AN->GetMPValue(), MPFR_RNDN);
      ICX = new ASTImplicitConversionNode(AN, ASTTypeMPDecimal, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
  } break;
  case ASTTypeStringLiteral: {
    if (const ASTStringNode *S = dynamic_cast<const ASTStringNode *>(EN)) {
      FromValue = true;
      mpfr_init2(MPV, Bits);
      std::string MPS = ASTStringUtils::Instance().Sanitize(S->GetValue());
      mpfr_set_str(MPV, MPS.c_str(), 10, MPFR_RNDN);
    }
  } break;
  case ASTTypeBinaryOp:
  case ASTTypeUnaryOp:
  case ASTTypeExpression:
  case ASTTypeCast:
    FromExpr = true;
    break;
  case ASTTypeImplicitConversion:
    ICX = new ASTImplicitConversionNode(EN, ASTTypeMPDecimal, Bits);
    assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    FromExpr = true;
    break;
  case ASTTypeCBitArray:
  case ASTTypeCBitNArray:
  case ASTTypeQubitArray:
  case ASTTypeQubitNArray:
  case ASTTypeAngleArray:
  case ASTTypeBoolArray:
  case ASTTypeMPIntegerArray:
  case ASTTypeMPDecimalArray:
  case ASTTypeLengthArray:
  case ASTTypeDurationArray:
  case ASTTypeFloatArray:
  case ASTTypeIntArray: {
    std::stringstream M;
    M << "An array cannot be assigned to a multiple-precision decimal.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  } break;
  case ASTTypeQubit: {
    std::stringstream M;
    M << "A Qubit cannot be assigned to a multiple-precision decimal.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  } break;
  case ASTTypeIdentifier: {
    const ASTIdentifierNode *Id = EN->GetIdentifier();
    assert(Id && "Could not obtain a valid ASTIdentifierNode!");

    ASTScopeController::Instance().CheckUndefined(Id);
    ASTScopeController::Instance().CheckOutOfScope(Id);

    const ASTIdentifierRefNode *IdR =
        dynamic_cast<const ASTIdentifierRefNode *>(Id);
    if (!IdR) {
      const ASTSymbolTableEntry *STE = Id->GetSymbolTableEntry();
      assert(STE && "Could not obtain a valid ASTSymbolTableEntry!");
      assert(
          STE->GetValueType() == Id->GetSymbolType() &&
          "Type mismatch between ASTIdentifierNode and ASTSymbolTableEntry!");

      switch (Id->GetSymbolType()) {
      case ASTTypeBool: {
        if (ASTBoolNode *BN = STE->GetValue()->GetValue<ASTBoolNode *>()) {
          FromValue = true;
          mpfr_init2(MPV, Bits);
          mpfr_set_ui(MPV, static_cast<unsigned>(BN->GetValue()), MPFR_RNDN);
          ICX = new ASTImplicitConversionNode(BN, ASTTypeMPDecimal, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeInt: {
        if (ASTIntNode *IN = STE->GetValue()->GetValue<ASTIntNode *>()) {
          FromValue = true;
          mpfr_init2(MPV, Bits);
          if (IN->IsSigned())
            mpfr_set_si(MPV, IN->GetSignedValue(), MPFR_RNDN);
          else
            mpfr_set_ui(MPV, IN->GetUnsignedValue(), MPFR_RNDN);
          ICX = new ASTImplicitConversionNode(IN, ASTTypeMPDecimal, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeFloat: {
        if (ASTFloatNode *FN = STE->GetValue()->GetValue<ASTFloatNode *>()) {
          FromValue = true;
          mpfr_init2(MPV, Bits);
          mpfr_set_flt(MPV, FN->GetValue(), MPFR_RNDN);
          ICX = new ASTImplicitConversionNode(FN, ASTTypeMPDecimal, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeDouble: {
        if (ASTDoubleNode *DN = STE->GetValue()->GetValue<ASTDoubleNode *>()) {
          FromValue = true;
          mpfr_init2(MPV, Bits);
          if (DN->IsMPDecimal())
            mpfr_set(MPV, DN->GetMPDecimal()->GetMPValue(), MPFR_RNDN);
          else
            mpfr_set_d(MPV, DN->GetValue(), MPFR_RNDN);
          ICX = new ASTImplicitConversionNode(DN, ASTTypeMPDecimal, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeLongDouble: {
        if (ASTLongDoubleNode *LN =
                STE->GetValue()->GetValue<ASTLongDoubleNode *>()) {
          FromValue = true;
          mpfr_init2(MPV, Bits);
          mpfr_set_ld(MPV, LN->GetValue(), MPFR_RNDN);
          ICX = new ASTImplicitConversionNode(LN, ASTTypeMPDecimal, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeMPInteger: {
        if (ASTMPIntegerNode *MPI =
                STE->GetValue()->GetValue<ASTMPIntegerNode *>()) {
          FromValue = true;
          mpfr_init2(MPV, Bits);
          mpfr_set_z(MPV, MPI->GetMPValue(), MPFR_RNDN);
          ICX = new ASTImplicitConversionNode(MPI, ASTTypeMPDecimal, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeMPDecimal: {
        if (ASTMPDecimalNode *MPDD =
                STE->GetValue()->GetValue<ASTMPDecimalNode *>()) {
          FromValue = true;
          mpfr_init2(MPV, Bits);
          mpfr_set(MPV, MPDD->GetMPValue(), MPFR_RNDN);
        }
      } break;
      case ASTTypeAngle: {
        if (ASTAngleNode *AN = STE->GetValue()->GetValue<ASTAngleNode *>()) {
          FromValue = true;
          mpfr_init2(MPV, Bits);
          mpfr_set(MPV, AN->GetMPValue(), MPFR_RNDN);
          ICX = new ASTImplicitConversionNode(AN, ASTTypeMPDecimal, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeMPComplex: {
        if (ASTMPComplexNode *MPC =
                STE->GetValue()->GetValue<ASTMPComplexNode *>()) {
          FromValue = true;
          mpfr_set(MPV, MPC->GetRealAsMPDecimal()->GetMPValue(), MPFR_RNDN);
          ICX = new ASTImplicitConversionNode(MPC, ASTTypeMPDecimal, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeStringLiteral: {
        if (ASTStringNode *SN = STE->GetValue()->GetValue<ASTStringNode *>()) {
          FromValue = true;
          mpfr_init2(MPV, Bits);
          std::string MPS = ASTStringUtils::Instance().Sanitize(SN->GetValue());
          mpfr_set_str(MPV, MPS.c_str(), 10, MPFR_RNDN);
        }
      } break;
      case ASTTypeBitset: {
        if (ASTCBitNode *CB = STE->GetValue()->GetValue<ASTCBitNode *>()) {
          FromValue = true;
          mpfr_init2(MPV, Bits);
          if (mpfr_set_str(MPV, CB->AsString().c_str(), 2, MPFR_RNDN) != 0)
            mpfr_set_nan(MPV);
          ICX = new ASTImplicitConversionNode(CB, ASTTypeMPDecimal, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      default: {
        std::stringstream M;
        M << "Impossible initialization of an ASTMPDecimalNode from an "
          << PrintTypeEnum(Id->GetSymbolType()) << '.';
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(EN), M.str(),
            DiagLevel::Error);
        return ASTDeclarationNode::DeclarationError(Id, M.str());
      } break;
      }
    } else {
      assert(IdR && "Could not dynamic_cast to an ASTIdentifierRefNode!");

      const ASTIdentifierNode *IId = IdR->GetIdentifier();
      assert(IId && "Could not obtain an unindexed ASTIdentifierNode!");

      ASTScopeController::Instance().CheckUndefined(IId);
      ASTScopeController::Instance().CheckOutOfScope(IId);

      if (IdR->IsIndexed()) {
        const ASTSymbolTableEntry *STE = IdR->GetSymbolTableEntry();
        assert(STE && "ASTIdentifierRefNode has no SymbolTable Entry!");

        switch (STE->GetValueType()) {
        case ASTTypeBool: {
          if (ASTBoolNode *BN = STE->GetValue()->GetValue<ASTBoolNode *>()) {
            FromValue = true;
            mpfr_init2(MPV, Bits);
            mpfr_set_ui(MPV, static_cast<unsigned>(BN->GetValue()), MPFR_RNDN);
            ICX = new ASTImplicitConversionNode(BN, ASTTypeMPDecimal, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
        } break;
        case ASTTypeInt: {
          if (ASTIntNode *IN = STE->GetValue()->GetValue<ASTIntNode *>()) {
            FromValue = true;
            mpfr_init2(MPV, Bits);
            if (IN->IsSigned())
              mpfr_set_si(MPV, IN->GetSignedValue(), MPFR_RNDN);
            else
              mpfr_set_ui(MPV, IN->GetUnsignedValue(), MPFR_RNDN);
            ICX = new ASTImplicitConversionNode(IN, ASTTypeMPDecimal, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
        } break;
        case ASTTypeFloat: {
          if (ASTFloatNode *FN = STE->GetValue()->GetValue<ASTFloatNode *>()) {
            FromValue = true;
            mpfr_init2(MPV, Bits);
            mpfr_set_flt(MPV, FN->GetValue(), MPFR_RNDN);
            ICX = new ASTImplicitConversionNode(FN, ASTTypeMPDecimal, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
        } break;
        case ASTTypeDouble: {
          if (ASTDoubleNode *DN =
                  STE->GetValue()->GetValue<ASTDoubleNode *>()) {
            FromValue = true;
            mpfr_init2(MPV, Bits);
            if (DN->IsMPDecimal())
              mpfr_set(MPV, DN->GetMPDecimal()->GetMPValue(), MPFR_RNDN);
            else
              mpfr_set_d(MPV, DN->GetValue(), MPFR_RNDN);
            ICX = new ASTImplicitConversionNode(DN, ASTTypeMPDecimal, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
        } break;
        case ASTTypeLongDouble: {
          if (ASTLongDoubleNode *LN =
                  STE->GetValue()->GetValue<ASTLongDoubleNode *>()) {
            FromValue = true;
            mpfr_init2(MPV, Bits);
            mpfr_set_ld(MPV, LN->GetValue(), MPFR_RNDN);
            ICX = new ASTImplicitConversionNode(LN, ASTTypeMPDecimal, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
        } break;
        case ASTTypeMPInteger: {
          if (ASTMPIntegerNode *MPI =
                  STE->GetValue()->GetValue<ASTMPIntegerNode *>()) {
            FromValue = true;
            mpfr_init2(MPV, Bits);
            mpfr_set_z(MPV, MPI->GetMPValue(), MPFR_RNDN);
            ICX = new ASTImplicitConversionNode(MPI, ASTTypeMPDecimal, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
        } break;
        case ASTTypeMPDecimal: {
          if (ASTMPDecimalNode *MPDD =
                  STE->GetValue()->GetValue<ASTMPDecimalNode *>()) {
            FromValue = true;
            mpfr_init2(MPV, Bits);
            mpfr_set(MPV, MPDD->GetMPValue(), MPFR_RNDN);
          }
        } break;
        case ASTTypeAngle: {
          if (ASTAngleNode *AN = STE->GetValue()->GetValue<ASTAngleNode *>()) {
            FromValue = true;
            mpfr_init2(MPV, Bits);
            mpfr_set(MPV, AN->GetMPValue(), MPFR_RNDN);
            ICX = new ASTImplicitConversionNode(AN, ASTTypeMPDecimal, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
        } break;
        case ASTTypeMPComplex: {
          if (ASTMPComplexNode *MPC =
                  STE->GetValue()->GetValue<ASTMPComplexNode *>()) {
            FromValue = true;
            mpfr_set(MPV, MPC->GetRealAsMPDecimal()->GetMPValue(), MPFR_RNDN);
            ICX = new ASTImplicitConversionNode(MPC, ASTTypeMPDecimal, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
        } break;
        case ASTTypeStringLiteral: {
          if (ASTStringNode *SN =
                  STE->GetValue()->GetValue<ASTStringNode *>()) {
            FromValue = true;
            mpfr_init2(MPV, Bits);
            std::string MPS =
                ASTStringUtils::Instance().Sanitize(SN->GetValue());
            mpfr_set_str(MPV, MPS.c_str(), 10, MPFR_RNDN);
          }
        } break;
        case ASTTypeBitset: {
          if (ASTCBitNode *CB = STE->GetValue()->GetValue<ASTCBitNode *>()) {
            FromValue = true;
            mpfr_init2(MPV, Bits);
            if (mpfr_set_str(MPV, CB->AsString().c_str(), 2, MPFR_RNDN) != 0)
              mpfr_set_nan(MPV);
            ICX = new ASTImplicitConversionNode(CB, ASTTypeMPDecimal, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
        } break;
        default: {
          std::stringstream M;
          M << "Impossible initialization of an ASTMPDecimalNode from an "
            << PrintTypeEnum(Id->GetSymbolType()) << '.';
          QasmDiagnosticEmitter::Instance().EmitDiagnostic(
              DIAGLineCounter::Instance().GetLocation(EN), M.str(),
              DiagLevel::Error);
          return ASTDeclarationNode::DeclarationError(Id, M.str());
        } break;
        }
      }
    }
  } break;
  default: {
    std::stringstream M;
    M << "Impossible ASTMPDecimalNode Initialization from an "
      << PrintTypeEnum(ETy) << ".";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  } break;
  }

  ASTMPDecimalNode *MPDD = nullptr;

  if (FromArray) {
    MPDD =
        ASTBuilder::Instance().CreateASTMPDecimalNode(DId, Bits, MPDVS.c_str());
  } else if (FromValue) {
    MPDD = ASTBuilder::Instance().CreateASTMPDecimalNode(DId, Bits, MPV);
    mpfr_clear(MPV);
  } else if (FromExpr) {
    if (EN->GetASTType() == ASTTypeCast) {
      const ASTCastExpressionNode *CX =
          dynamic_cast<const ASTCastExpressionNode *>(EN);
      assert(CX && "Could not dynamic_cast to an ASTCastExpressionNode!");
      MPDD = ASTBuilder::Instance().CreateASTMPDecimalNodeFromExpression(
          DId, Bits, CX);
    } else {
      MPDD = ASTBuilder::Instance().CreateASTMPDecimalNodeFromExpression(
          DId, Bits, EN);
    }
  } else {
    MPDD = ASTBuilder::Instance().CreateASTMPDecimalNodeFromExpression(
        DId, Bits, EN);
  }

  assert(MPDD && "Could not create an ASTMPDecimalNode!");

  if (FromValue) {
    MPDD->SetConstantFolded(true);
    if (ICX)
      MPDD->SetImplicitConversion(ICX);
  }

  MPDD->SetLocation(DId->GetLocation());
  MPDD->Mangle();
  ASTDeclarationNode *DN =
      new ASTDeclarationNode(DId, MPDD, ASTTypeMPDecimal, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *ASTProductionFactory::ProductionRule_146(
    const ASTToken *TK, const ASTIdentifierNode *DId, const ASTIntNode *II,
    const ASTFunctionCallStatementNode *FC) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DId && "Invalid ASTIdentifierNode argument!");
  assert(II && "Invalid ASTMPDecimalNode Index argument!");
  assert(FC && "Invalid ASTFunctionCallStatementNode argument!");

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(II);
  assert(!ASTIdentifierNode::InvalidBits(Bits) &&
         "Invalid number of Bits for ASTMPDecimalNode!");

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(DId, Bits,
                                                          ASTTypeMPDecimal)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeMPDecimal.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(DId)) {
    std::stringstream M;
    M << "Declaration " << DId->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  const ASTFunctionCallNode *EN = FC->GetFunctionCall();
  assert(EN && "Could not obtain a valid ASTFunctionCallNode!");

  if (!EN->ReturnsResult()) {
    std::stringstream M;
    M << "Assignment requires a non-void return type.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  ASTMPDecimalNode *MPDD =
      ASTBuilder::Instance().CreateASTMPDecimalNodeFromExpression(DId, Bits,
                                                                  EN);
  assert(MPDD && "Could not create an ASTMPDecimalNode!");

  MPDD->SetLocation(TK->GetLocation());
  MPDD->Mangle();
  ASTDeclarationNode *DN =
      new ASTDeclarationNode(DId, MPDD, ASTTypeMPDecimal, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *ASTProductionFactory::ProductionRule_147(
    const ASTToken *TK, const ASTIdentifierNode *DId,
    const ASTIdentifierNode *IId, const ASTExpressionNode *EN) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DId && "Invalid ASTIdentifierNode argument!");
  assert(IId && "Invalid ASTIntNode Index argument!");
  assert(EN && "Invalid ASTExpressionNode argument!");

  ASTScopeController::Instance().CheckUndefined(IId);
  ASTScopeController::Instance().CheckOutOfScope(IId);

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(IId);
  assert(!ASTIdentifierNode::InvalidBits(Bits) &&
         "Invalid number of Bits for Index Identifier!");

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(DId, Bits,
                                                          ASTTypeMPDecimal)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeMPDecimal.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(DId)) {
    std::stringstream M;
    M << "Declaration " << DId->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  std::string MPDVS;
  bool FromArray = false;
  bool FromValue = false;
  bool FromExpr = false;
  const ASTImplicitConversionNode *ICX = nullptr;
  mpfr_t MPV;

  ASTType ETy = EN->GetASTType();

  switch (ETy) {
  case ASTTypeBool: {
    if (const ASTBoolNode *BN = dynamic_cast<const ASTBoolNode *>(EN)) {
      FromValue = true;
      mpfr_init2(MPV, Bits);
      mpfr_set_ui(MPV, static_cast<unsigned>(BN->GetValue()), MPFR_RNDN);
      ICX = new ASTImplicitConversionNode(BN, ASTTypeMPDecimal, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
  } break;
  case ASTTypeInt: {
    if (const ASTIntNode *IN = dynamic_cast<const ASTIntNode *>(EN)) {
      FromValue = true;
      mpfr_init2(MPV, Bits);
      if (IN->IsSigned())
        mpfr_set_si(MPV, IN->GetSignedValue(), MPFR_RNDN);
      else
        mpfr_set_ui(MPV, IN->GetUnsignedValue(), MPFR_RNDN);
      ICX = new ASTImplicitConversionNode(IN, ASTTypeMPDecimal, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
  } break;
  case ASTTypeFloat: {
    if (const ASTFloatNode *FN = dynamic_cast<const ASTFloatNode *>(EN)) {
      FromValue = true;
      mpfr_init2(MPV, Bits);
      mpfr_set_flt(MPV, FN->GetValue(), MPFR_RNDN);
      ICX = new ASTImplicitConversionNode(FN, ASTTypeMPDecimal, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
  } break;
  case ASTTypeDouble: {
    if (const ASTDoubleNode *DN = dynamic_cast<const ASTDoubleNode *>(EN)) {
      FromValue = true;
      mpfr_init2(MPV, Bits);

      if (DN->IsString() || DN->IsMP()) {
        if (ASTMPDecimalNode::InitMPFRFromString(
                MPV, DN->GetString().c_str()) != 0) {
          std::stringstream M;
          M << "Failed conversion from String to ASTMPDecimal.";
          QasmDiagnosticEmitter::Instance().EmitDiagnostic(
              DIAGLineCounter::Instance().GetLocation(EN), M.str(),
              DiagLevel::Error);
          return ASTDeclarationNode::DeclarationError(DId, M.str());
        }
      } else {
        mpfr_set_d(MPV, DN->GetValue(), MPFR_RNDN);
      }

      ICX = new ASTImplicitConversionNode(DN, ASTTypeMPDecimal, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
  } break;
  case ASTTypeLongDouble: {
    if (const ASTLongDoubleNode *LN =
            dynamic_cast<const ASTLongDoubleNode *>(EN)) {
      FromValue = true;
      mpfr_init2(MPV, Bits);
      mpfr_set_ld(MPV, LN->GetValue(), MPFR_RNDN);
      ICX = new ASTImplicitConversionNode(LN, ASTTypeMPDecimal, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
  } break;
  case ASTTypeMPInteger: {
    if (const ASTMPIntegerNode *MPI =
            dynamic_cast<const ASTMPIntegerNode *>(EN)) {
      FromValue = true;
      mpfr_init2(MPV, Bits);
      mpfr_set_z(MPV, MPI->GetMPValue(), MPFR_RNDN);
      ICX = new ASTImplicitConversionNode(MPI, ASTTypeMPDecimal, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
  } break;
  case ASTTypeMPDecimal: {
    if (const ASTMPDecimalNode *MPDD =
            dynamic_cast<const ASTMPDecimalNode *>(EN)) {
      FromValue = true;
      mpfr_set(MPV, MPDD->GetMPValue(), MPFR_RNDN);
    }
  } break;
  case ASTTypeBitset: {
    if (const ASTCBitNode *CB = dynamic_cast<const ASTCBitNode *>(EN)) {
      FromValue = true;
      mpfr_init2(MPV, Bits);
      if (mpfr_set_str(MPV, CB->AsString().c_str(), 2, MPFR_RNDN) != 0)
        mpfr_set_nan(MPV);
      ICX = new ASTImplicitConversionNode(CB, ASTTypeMPDecimal, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
  } break;
  case ASTTypeAngle: {
    if (const ASTAngleNode *AN = dynamic_cast<const ASTAngleNode *>(EN)) {
      FromValue = true;
      mpfr_init2(MPV, Bits);
      mpfr_set(MPV, AN->GetMPValue(), MPFR_RNDN);
      ICX = new ASTImplicitConversionNode(AN, ASTTypeMPDecimal, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
  } break;
  case ASTTypeStringLiteral: {
    if (const ASTStringNode *S = dynamic_cast<const ASTStringNode *>(EN)) {
      FromValue = true;
      mpfr_init2(MPV, Bits);
      std::string MPS = ASTStringUtils::Instance().Sanitize(S->GetValue());
      mpfr_set_str(MPV, MPS.c_str(), 10, MPFR_RNDN);
    }
  } break;
  case ASTTypeBinaryOp:
  case ASTTypeUnaryOp:
  case ASTTypeExpression:
  case ASTTypeCast:
    FromExpr = true;
    break;
  case ASTTypeImplicitConversion:
    ICX = new ASTImplicitConversionNode(EN, ASTTypeMPDecimal, Bits);
    assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    FromExpr = true;
    break;
  case ASTTypeCBitArray:
  case ASTTypeCBitNArray:
  case ASTTypeQubitArray:
  case ASTTypeQubitNArray:
  case ASTTypeAngleArray:
  case ASTTypeBoolArray:
  case ASTTypeMPIntegerArray:
  case ASTTypeMPDecimalArray:
  case ASTTypeLengthArray:
  case ASTTypeDurationArray:
  case ASTTypeFloatArray:
  case ASTTypeIntArray: {
    std::stringstream M;
    M << "An array cannot be assigned to a multiple-precision decimal.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  } break;
  case ASTTypeQubit: {
    std::stringstream M;
    M << "A Qubit cannot be assigned to a multiple-precision decimal.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  } break;
  case ASTTypeIdentifier: {
    const ASTIdentifierNode *Id = EN->GetIdentifier();
    assert(Id && "Could not obtain a valid ASTIdentifierNode!");

    ASTScopeController::Instance().CheckUndefined(Id);
    ASTScopeController::Instance().CheckOutOfScope(Id);

    const ASTIdentifierRefNode *IdR =
        dynamic_cast<const ASTIdentifierRefNode *>(Id);
    if (!IdR) {
      const ASTSymbolTableEntry *STE = Id->GetSymbolTableEntry();
      assert(STE && "Could not obtain a valid ASTSymbolTableEntry!");
      assert(
          STE->GetValueType() == Id->GetSymbolType() &&
          "Type mismatch between ASTIdentifierNode and ASTSymbolTableEntry!");

      switch (Id->GetSymbolType()) {
      case ASTTypeBool: {
        if (ASTBoolNode *BN = STE->GetValue()->GetValue<ASTBoolNode *>()) {
          FromValue = true;
          mpfr_init2(MPV, Bits);
          mpfr_set_ui(MPV, static_cast<unsigned>(BN->GetValue()), MPFR_RNDN);
          ICX = new ASTImplicitConversionNode(BN, ASTTypeMPDecimal, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeInt: {
        if (ASTIntNode *IN = STE->GetValue()->GetValue<ASTIntNode *>()) {
          FromValue = true;
          mpfr_init2(MPV, Bits);
          if (IN->IsSigned())
            mpfr_set_si(MPV, IN->GetSignedValue(), MPFR_RNDN);
          else
            mpfr_set_ui(MPV, IN->GetUnsignedValue(), MPFR_RNDN);
          ICX = new ASTImplicitConversionNode(IN, ASTTypeMPDecimal, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeFloat: {
        if (ASTFloatNode *FN = STE->GetValue()->GetValue<ASTFloatNode *>()) {
          FromValue = true;
          mpfr_init2(MPV, Bits);
          mpfr_set_flt(MPV, FN->GetValue(), MPFR_RNDN);
          ICX = new ASTImplicitConversionNode(FN, ASTTypeMPDecimal, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeDouble: {
        if (ASTDoubleNode *DN = STE->GetValue()->GetValue<ASTDoubleNode *>()) {
          FromValue = true;
          mpfr_init2(MPV, Bits);
          if (DN->IsMPDecimal())
            mpfr_set(MPV, DN->GetMPDecimal()->GetMPValue(), MPFR_RNDN);
          else
            mpfr_set_d(MPV, DN->GetValue(), MPFR_RNDN);
          ICX = new ASTImplicitConversionNode(DN, ASTTypeMPDecimal, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeLongDouble: {
        if (ASTLongDoubleNode *LN =
                STE->GetValue()->GetValue<ASTLongDoubleNode *>()) {
          FromValue = true;
          mpfr_init2(MPV, Bits);
          mpfr_set_ld(MPV, LN->GetValue(), MPFR_RNDN);
          ICX = new ASTImplicitConversionNode(LN, ASTTypeMPDecimal, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeMPInteger: {
        if (ASTMPIntegerNode *MPI =
                STE->GetValue()->GetValue<ASTMPIntegerNode *>()) {
          FromValue = true;
          mpfr_init2(MPV, Bits);
          mpfr_set_z(MPV, MPI->GetMPValue(), MPFR_RNDN);
          ICX = new ASTImplicitConversionNode(MPI, ASTTypeMPDecimal, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeMPDecimal: {
        if (ASTMPDecimalNode *MPDD =
                STE->GetValue()->GetValue<ASTMPDecimalNode *>()) {
          FromValue = true;
          mpfr_init2(MPV, Bits);
          mpfr_set(MPV, MPDD->GetMPValue(), MPFR_RNDN);
        }
      } break;
      case ASTTypeAngle: {
        if (ASTAngleNode *AN = STE->GetValue()->GetValue<ASTAngleNode *>()) {
          FromValue = true;
          mpfr_init2(MPV, Bits);
          mpfr_set(MPV, AN->GetMPValue(), MPFR_RNDN);
          ICX = new ASTImplicitConversionNode(AN, ASTTypeMPDecimal, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeMPComplex: {
        if (ASTMPComplexNode *MPC =
                STE->GetValue()->GetValue<ASTMPComplexNode *>()) {
          FromValue = true;
          mpfr_set(MPV, MPC->GetRealAsMPDecimal()->GetMPValue(), MPFR_RNDN);
          ICX = new ASTImplicitConversionNode(MPC, ASTTypeMPDecimal, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeStringLiteral: {
        if (ASTStringNode *SN = STE->GetValue()->GetValue<ASTStringNode *>()) {
          FromValue = true;
          mpfr_init2(MPV, Bits);
          std::string MPS = ASTStringUtils::Instance().Sanitize(SN->GetValue());
          mpfr_set_str(MPV, MPS.c_str(), 10, MPFR_RNDN);
        }
      } break;
      case ASTTypeBitset: {
        if (ASTCBitNode *CB = STE->GetValue()->GetValue<ASTCBitNode *>()) {
          FromValue = true;
          mpfr_init2(MPV, Bits);
          if (mpfr_set_str(MPV, CB->AsString().c_str(), 2, MPFR_RNDN) != 0)
            mpfr_set_nan(MPV);
          ICX = new ASTImplicitConversionNode(CB, ASTTypeMPDecimal, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      default: {
        std::stringstream M;
        M << "Impossible initialization of an ASTMPDecimalNode from an "
          << PrintTypeEnum(Id->GetSymbolType()) << '.';
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(EN), M.str(),
            DiagLevel::Error);
        return ASTDeclarationNode::DeclarationError(Id, M.str());
      } break;
      }
    } else {
      assert(IdR && "Could not dynamic_cast to an ASTIdentifierRefNode!");

      Id = IdR->GetIdentifier();
      assert(Id && "Could not obtain an unindexed ASTIdentifierNode!");

      ASTScopeController::Instance().CheckUndefined(Id);
      ASTScopeController::Instance().CheckOutOfScope(Id);

      if (IdR->IsIndexed()) {
        const ASTSymbolTableEntry *STE = IdR->GetSymbolTableEntry();
        assert(STE && "ASTIdentifierRefNode has no SymbolTable Entry!");

        switch (STE->GetValueType()) {
        case ASTTypeBool: {
          if (ASTBoolNode *BN = STE->GetValue()->GetValue<ASTBoolNode *>()) {
            FromValue = true;
            mpfr_init2(MPV, Bits);
            mpfr_set_ui(MPV, static_cast<unsigned>(BN->GetValue()), MPFR_RNDN);
            ICX = new ASTImplicitConversionNode(BN, ASTTypeMPDecimal, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
        } break;
        case ASTTypeInt: {
          if (ASTIntNode *IN = STE->GetValue()->GetValue<ASTIntNode *>()) {
            FromValue = true;
            mpfr_init2(MPV, Bits);
            if (IN->IsSigned())
              mpfr_set_si(MPV, IN->GetSignedValue(), MPFR_RNDN);
            else
              mpfr_set_ui(MPV, IN->GetUnsignedValue(), MPFR_RNDN);
            ICX = new ASTImplicitConversionNode(IN, ASTTypeMPDecimal, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
        } break;
        case ASTTypeFloat: {
          if (ASTFloatNode *FN = STE->GetValue()->GetValue<ASTFloatNode *>()) {
            FromValue = true;
            mpfr_init2(MPV, Bits);
            mpfr_set_flt(MPV, FN->GetValue(), MPFR_RNDN);
            ICX = new ASTImplicitConversionNode(FN, ASTTypeMPDecimal, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
        } break;
        case ASTTypeDouble: {
          if (ASTDoubleNode *DN =
                  STE->GetValue()->GetValue<ASTDoubleNode *>()) {
            FromValue = true;
            mpfr_init2(MPV, Bits);
            if (DN->IsMPDecimal())
              mpfr_set(MPV, DN->GetMPDecimal()->GetMPValue(), MPFR_RNDN);
            else
              mpfr_set_d(MPV, DN->GetValue(), MPFR_RNDN);
            ICX = new ASTImplicitConversionNode(DN, ASTTypeMPDecimal, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
        } break;
        case ASTTypeLongDouble: {
          if (ASTLongDoubleNode *LN =
                  STE->GetValue()->GetValue<ASTLongDoubleNode *>()) {
            FromValue = true;
            mpfr_init2(MPV, Bits);
            mpfr_set_ld(MPV, LN->GetValue(), MPFR_RNDN);
            ICX = new ASTImplicitConversionNode(LN, ASTTypeMPDecimal, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
        } break;
        case ASTTypeMPInteger: {
          if (ASTMPIntegerNode *MPI =
                  STE->GetValue()->GetValue<ASTMPIntegerNode *>()) {
            FromValue = true;
            mpfr_init2(MPV, Bits);
            mpfr_set_z(MPV, MPI->GetMPValue(), MPFR_RNDN);
            ICX = new ASTImplicitConversionNode(MPI, ASTTypeMPDecimal, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
        } break;
        case ASTTypeMPDecimal: {
          if (ASTMPDecimalNode *MPDD =
                  STE->GetValue()->GetValue<ASTMPDecimalNode *>()) {
            FromValue = true;
            mpfr_init2(MPV, Bits);
            mpfr_set(MPV, MPDD->GetMPValue(), MPFR_RNDN);
          }
        } break;
        case ASTTypeAngle: {
          if (ASTAngleNode *AN = STE->GetValue()->GetValue<ASTAngleNode *>()) {
            FromValue = true;
            mpfr_init2(MPV, Bits);
            mpfr_set(MPV, AN->GetMPValue(), MPFR_RNDN);
            ICX = new ASTImplicitConversionNode(AN, ASTTypeMPDecimal, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
        } break;
        case ASTTypeMPComplex: {
          if (ASTMPComplexNode *MPC =
                  STE->GetValue()->GetValue<ASTMPComplexNode *>()) {
            FromValue = true;
            mpfr_set(MPV, MPC->GetRealAsMPDecimal()->GetMPValue(), MPFR_RNDN);
            ICX = new ASTImplicitConversionNode(MPC, ASTTypeMPDecimal, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
        } break;
        case ASTTypeStringLiteral: {
          if (ASTStringNode *SN =
                  STE->GetValue()->GetValue<ASTStringNode *>()) {
            FromValue = true;
            mpfr_init2(MPV, Bits);
            std::string MPS =
                ASTStringUtils::Instance().Sanitize(SN->GetValue());
            mpfr_set_str(MPV, MPS.c_str(), 10, MPFR_RNDN);
          }
        } break;
        case ASTTypeBitset: {
          if (ASTCBitNode *CB = STE->GetValue()->GetValue<ASTCBitNode *>()) {
            FromValue = true;
            mpfr_init2(MPV, Bits);
            if (mpfr_set_str(MPV, CB->AsString().c_str(), 2, MPFR_RNDN) != 0)
              mpfr_set_nan(MPV);
            ICX = new ASTImplicitConversionNode(CB, ASTTypeMPDecimal, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
        } break;
        default: {
          std::stringstream M;
          M << "Impossible initialization of an ASTMPDecimalNode from an "
            << PrintTypeEnum(Id->GetSymbolType()) << '.';
          QasmDiagnosticEmitter::Instance().EmitDiagnostic(
              DIAGLineCounter::Instance().GetLocation(EN), M.str(),
              DiagLevel::Error);
          return ASTDeclarationNode::DeclarationError(Id, M.str());
        } break;
        }
      }
    }
  } break;
  default: {
    std::stringstream M;
    M << "Impossible ASTMPDecimalNode Initialization from an "
      << PrintTypeEnum(ETy) << ".";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  } break;
  }

  ASTMPDecimalNode *MPDD = nullptr;

  if (FromArray) {
    MPDD =
        ASTBuilder::Instance().CreateASTMPDecimalNode(DId, Bits, MPDVS.c_str());
  } else if (FromValue) {
    MPDD = ASTBuilder::Instance().CreateASTMPDecimalNode(DId, Bits, MPV);
    mpfr_clear(MPV);
  } else if (FromExpr) {
    if (EN->GetASTType() == ASTTypeCast) {
      const ASTCastExpressionNode *CX =
          dynamic_cast<const ASTCastExpressionNode *>(EN);
      assert(CX && "Could not dynamic_cast to an ASTCastExpressionNode!");
      MPDD = ASTBuilder::Instance().CreateASTMPDecimalNodeFromExpression(
          DId, Bits, CX);
    } else {
      MPDD = ASTBuilder::Instance().CreateASTMPDecimalNodeFromExpression(
          DId, Bits, EN);
    }
  } else {
    MPDD = ASTBuilder::Instance().CreateASTMPDecimalNodeFromExpression(
        DId, Bits, EN);
  }

  assert(MPDD && "Could not create an ASTMPDecimalNode!");

  if (FromValue) {
    MPDD->SetConstantFolded(true);
    if (ICX)
      MPDD->SetImplicitConversion(ICX);
  }

  MPDD->SetLocation(TK->GetLocation());
  MPDD->Mangle();
  ASTDeclarationNode *DN =
      new ASTDeclarationNode(DId, MPDD, ASTTypeMPDecimal, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *ASTProductionFactory::ProductionRule_148(
    const ASTToken *TK, const ASTIdentifierNode *DId,
    const ASTIdentifierNode *BId,
    const ASTFunctionCallStatementNode *FC) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DId && "Invalid ASTIdentifierNode argument!");
  assert(BId && "Invalid ASTIntNode BitIndex argument!");
  assert(FC && "Invalid ASTFunctionCallStatementNode argument!");

  ASTScopeController::Instance().CheckUndefined(BId);
  ASTScopeController::Instance().CheckOutOfScope(BId);

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(BId);
  assert(!ASTIdentifierNode::InvalidBits(Bits) &&
         "Invalid number of Bits for Index Identifier!");

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(DId, Bits,
                                                          ASTTypeMPDecimal)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeMPDecimal.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(DId)) {
    std::stringstream M;
    M << "Declaration " << DId->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  const ASTFunctionCallNode *EN = FC->GetFunctionCall();
  assert(EN && "Could not obtain a valid ASTFunctionCallNode!");

  if (!EN->ReturnsResult()) {
    std::stringstream M;
    M << "Assignment requires a non-void return type.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  ASTMPDecimalNode *MPDD =
      ASTBuilder::Instance().CreateASTMPDecimalNodeFromExpression(DId, Bits,
                                                                  EN);
  assert(MPDD && "Could not create an ASTMPDecimalNode!");

  MPDD->SetLocation(TK->GetLocation());
  MPDD->Mangle();
  ASTDeclarationNode *DN =
      new ASTDeclarationNode(DId, MPDD, ASTTypeMPDecimal, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *ASTProductionFactory::ProductionRule_170(
    const ASTToken *TK, const std::string &SId, ASTExpressionNode *EN) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(!SId.empty() && "Invalid Identifier argument!");
  assert(EN && "Invalid ASTExpressionNode argument!");

  unsigned Bits = static_cast<unsigned>(~0x0);
  ASTType ETy = EN->GetASTType();

  ASTIdentifierNode *Id = ASTBuilder::Instance().FindASTIdentifierNode(SId);
  if (Id) {
    if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
      std::stringstream M;
      M << "Declaration " << Id->GetName() << " shadows a "
        << "previous declaration.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(Id), M.str(),
          DiagLevel::Error);
      return ASTDeclarationNode::DeclarationError(Id, M.str());
    }

    Bits = Id->GetBits();
  } else {
    switch (ETy) {
    case ASTTypeBool:
      Id = ASTBuilder::Instance().CreateASTIdentifierNode(
          SId, ASTBoolNode::BoolBits, ASTTypeAngle);
      assert(Id && "Could not create a valid ASTIdentifierNode!");
      Id->SetLocation(TK->GetLocation());
      Bits = Id->GetBits();
      break;
    case ASTTypeInt:
      Id = ASTBuilder::Instance().CreateASTIdentifierNode(
          SId, ASTIntNode::IntBits, ASTTypeAngle);
      assert(Id && "Could not create a valid ASTIdentifierNode!");
      Id->SetLocation(TK->GetLocation());
      Bits = Id->GetBits();
      break;
    case ASTTypeFloat:
      Id = ASTBuilder::Instance().CreateASTIdentifierNode(
          SId, ASTFloatNode::FloatBits, ASTTypeAngle);
      assert(Id && "Could not create a valid ASTIdentifierNode!");
      Id->SetLocation(TK->GetLocation());
      Bits = Id->GetBits();
      break;
    case ASTTypeDouble:
      Id = ASTBuilder::Instance().CreateASTIdentifierNode(
          SId, ASTDoubleNode::DoubleBits, ASTTypeAngle);
      assert(Id && "Could not create a valid ASTIdentifierNode!");
      Id->SetLocation(TK->GetLocation());
      Bits = Id->GetBits();
      break;
    case ASTTypeLongDouble:
      Id = ASTBuilder::Instance().CreateASTIdentifierNode(
          SId, ASTLongDoubleNode::LongDoubleBits, ASTTypeAngle);
      assert(Id && "Could not create a valid ASTIdentifierNode!");
      Id->SetLocation(TK->GetLocation());
      Bits = Id->GetBits();
      break;
    case ASTTypeMPInteger: {
      if (ASTMPIntegerNode *MPI = dynamic_cast<ASTMPIntegerNode *>(EN)) {
        Id = ASTBuilder::Instance().CreateASTIdentifierNode(SId, MPI->GetBits(),
                                                            ASTTypeAngle);
        assert(Id && "Could not create a valid ASTIdentifierNode!");
        Id->SetLocation(TK->GetLocation());
      } else {
        Id = ASTBuilder::Instance().CreateASTIdentifierNode(
            SId, ASTMPIntegerNode::DefaultBits, ASTTypeAngle);
        assert(Id && "Could not create a valid ASTIdentifierNode!");
        Id->SetLocation(TK->GetLocation());
      }

      Bits = Id->GetBits();
    } break;
    case ASTTypeMPDecimal: {
      if (ASTMPDecimalNode *MPD = dynamic_cast<ASTMPDecimalNode *>(EN)) {
        Id = ASTBuilder::Instance().CreateASTIdentifierNode(SId, MPD->GetBits(),
                                                            ASTTypeAngle);
        assert(Id && "Could not create a valid ASTIdentifierNode!");
        Id->SetLocation(TK->GetLocation());
      } else {
        Id = ASTBuilder::Instance().CreateASTIdentifierNode(
            SId, ASTMPDecimalNode::DefaultBits, ASTTypeAngle);
        assert(Id && "Could not create a valid ASTIdentifierNode!");
        Id->SetLocation(TK->GetLocation());
      }

      Bits = Id->GetBits();
    } break;
    case ASTTypeMPComplex: {
      if (ASTMPComplexNode *MPC = dynamic_cast<ASTMPComplexNode *>(EN)) {
        Id = ASTBuilder::Instance().CreateASTIdentifierNode(SId, MPC->GetBits(),
                                                            ASTTypeAngle);
        assert(Id && "Could not create a valid ASTIdentifierNode!");
        Id->SetLocation(TK->GetLocation());
      } else {
        Id = ASTBuilder::Instance().CreateASTIdentifierNode(
            SId, ASTMPComplexNode::DefaultBits, ASTTypeAngle);
        assert(Id && "Could not create a valid ASTIdentifierNode!");
        Id->SetLocation(TK->GetLocation());
      }

      Bits = Id->GetBits();
    } break;
    case ASTTypeStringLiteral:
      if (ASTStringNode *SN = dynamic_cast<ASTStringNode *>(EN)) {
        Id = ASTBuilder::Instance().CreateASTIdentifierNode(SId, SN->Size(),
                                                            ASTTypeAngle);
        assert(Id && "Could not create a valid ASTIdentifierNode!");
        Id->SetLocation(TK->GetLocation());
      } else {
        Id = ASTBuilder::Instance().CreateASTIdentifierNode(
            SId, ASTMPComplexNode::DefaultBits, ASTTypeAngle);
        assert(Id && "Could not create a valid ASTIdentifierNode!");
        Id->SetLocation(TK->GetLocation());
      }

      Bits = Id->GetBits();
      break;
    case ASTTypeAngle: {
      if (ASTAngleNode *ANG = dynamic_cast<ASTAngleNode *>(EN)) {
        Id = ASTBuilder::Instance().CreateASTIdentifierNode(SId, ANG->GetBits(),
                                                            ASTTypeAngle);
        assert(Id && "Could not create a valid ASTIdentifierNode!");
        Id->SetLocation(TK->GetLocation());
      } else {
        Id = ASTBuilder::Instance().CreateASTIdentifierNode(
            SId, ASTAngleNode::AngleBits, ASTTypeAngle);
        assert(Id && "Could not create a valid ASTIdentifierNode!");
        Id->SetLocation(TK->GetLocation());
      }

      Bits = Id->GetBits();
    } break;
    case ASTTypeBinaryOp:
      Id = ASTBuilder::Instance().CreateASTIdentifierNode(
          SId, ASTAngleNode::AngleBits, ASTTypeAngle);
      assert(Id && "Could not create a valid ASTIdentifierNode!");
      Id->SetLocation(TK->GetLocation());
      Bits = Id->GetBits();
      break;
    case ASTTypeUnaryOp:
      Id = ASTBuilder::Instance().CreateASTIdentifierNode(
          SId, ASTAngleNode::AngleBits, ASTTypeAngle);
      assert(Id && "Could not create a valid ASTIdentifierNode!");
      Id->SetLocation(TK->GetLocation());
      Bits = Id->GetBits();
      break;
    default: {
      std::stringstream M;
      M << "An expression of type " << PrintTypeEnum(ETy) << " cannot "
        << "yield an implicit type const declaration.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(EN), M.str(),
          DiagLevel::Error);
      return ASTDeclarationNode::DeclarationError(Id, M.str());
    } break;
    }
  }

  assert(Id && "Could not create an ASTIdentifierNode!");
  assert(Bits != static_cast<unsigned>(~0x0) && "Invalid Angle Bits!");

  ASTSymbolTableEntry *STE = Id->GetSymbolTableEntry();
  ASTAngleNode *ANG = nullptr;

  switch (ETy) {
  case ASTTypeBool:
    if (ASTBoolNode *BN = dynamic_cast<ASTBoolNode *>(EN)) {
      ANG = new ASTAngleNode(Id, static_cast<double>(BN->GetValue()),
                             ASTAngleTypeGeneric, Bits);
      assert(ANG && "Could not create a valid ASTAngleNode!");
    }
    break;
  case ASTTypeInt:
    if (ASTIntNode *IN = dynamic_cast<ASTIntNode *>(EN)) {
      ANG = new ASTAngleNode(Id, static_cast<double>(IN->GetSignedValue()),
                             ASTAngleTypeGeneric, Bits);
      assert(ANG && "Could not create a valid ASTAngleNode!");
    }
    break;
  case ASTTypeFloat:
    if (ASTFloatNode *FN = dynamic_cast<ASTFloatNode *>(EN)) {
      ANG = new ASTAngleNode(Id, static_cast<double>(FN->GetValue()),
                             ASTAngleTypeGeneric, Bits);
      assert(ANG && "Could not create a valid ASTAngleNode!");
    }
    break;
  case ASTTypeDouble:
    if (ASTDoubleNode *DN = dynamic_cast<ASTDoubleNode *>(EN)) {
      ANG = new ASTAngleNode(Id, static_cast<double>(DN->GetValue()),
                             ASTAngleTypeGeneric, Bits);
      assert(ANG && "Could not create a valid ASTAngleNode!");
    }
    break;
  case ASTTypeLongDouble:
    if (ASTLongDoubleNode *LN = dynamic_cast<ASTLongDoubleNode *>(EN)) {
      ANG = new ASTAngleNode(Id, LN, ASTAngleTypeGeneric, Bits);
      assert(ANG && "Could not create a valid ASTAngleNode!");
    }
    break;
  case ASTTypeMPInteger:
    if (ASTMPIntegerNode *MPI = dynamic_cast<ASTMPIntegerNode *>(EN)) {
      ANG = new ASTAngleNode(Id, MPI, ASTAngleTypeGeneric, Bits);
      assert(ANG && "Could not create a valid ASTAngleNode!");
    }
    break;
  case ASTTypeMPDecimal:
    if (ASTMPDecimalNode *MPD = dynamic_cast<ASTMPDecimalNode *>(EN)) {
      ANG = new ASTAngleNode(Id, MPD, ASTAngleTypeGeneric, Bits);
      assert(ANG && "Could not create a valid ASTAngleNode!");
    }
    break;
  case ASTTypeMPComplex:
    if (ASTMPComplexNode *MPC = dynamic_cast<ASTMPComplexNode *>(EN)) {
      ANG = new ASTAngleNode(Id, MPC->GetRealAsMPDecimal(), ASTAngleTypeGeneric,
                             Bits);
      assert(ANG && "Could not create a valid ASTAngleNode!");
    }
    break;
  case ASTTypeStringLiteral: {
    if (ASTStringNode *SN = dynamic_cast<ASTStringNode *>(EN)) {
      int Base = 10;
      std::string ASN = SN->GetValue();

      if (ASTStringUtils::Instance().IsBinary(ASN)) {
        ASN = ASN.substr(2, std::string::npos);
        Base = 2;
      } else if (ASTStringUtils::Instance().IsHex(ASN)) {
        ASN = ASN.substr(2, std::string::npos);
        Base = 16;
      }

      ANG = new ASTAngleNode(Id, Bits, ASN, ASTAngleTypeGeneric, Base);
      assert(ANG && "Could not create a valid ASTAngleNode!");
    }
  } break;
  case ASTTypeAngle:
    if (ASTAngleNode *AN = dynamic_cast<ASTAngleNode *>(EN)) {
      ANG = AN->Clone(Id, Bits);
      assert(ANG && "Could not create a valid ASTAngleNode!");
      ANG->SetAngleType(ASTAngleTypeGeneric);
    }
    break;
  case ASTTypeBinaryOp:
    if (ASTBinaryOpNode *BOP = dynamic_cast<ASTBinaryOpNode *>(EN)) {
      ANG = new ASTAngleNode(Id, BOP, ASTAngleTypeGeneric, Bits);
      assert(ANG && "Could not create a valid ASTAngleNode!");
    }
    break;
  case ASTTypeUnaryOp:
    if (ASTUnaryOpNode *UOP = dynamic_cast<ASTUnaryOpNode *>(EN)) {
      ANG = new ASTAngleNode(Id, UOP, ASTAngleTypeGeneric, Bits);
      assert(ANG && "Could not create a valid ASTAngleNode!");
    }
    break;
  default: {
    std::stringstream M;
    M << "Impossible initialization of an ASTTypeAngle from an "
      << PrintTypeEnum(ETy) << ".";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  } break;
  }

  if (!ANG) {
    std::stringstream M;
    M << "Could not instantiate an ASTAngleNode from an Expression of Type "
      << PrintTypeEnum(ETy) << ".";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  ANG->SetLocation(TK->GetLocation());
  ANG->SetConst();
  ANG->Mangle();

  STE->ResetValue();
  STE->SetValue(new ASTValue<>(ANG, ASTTypeAngle), ASTTypeAngle);
  assert(STE->HasValue() &&
         "Could not create a valid SymbolTable Entry Value!");

  ASTDeclarationNode *DN = new ASTDeclarationNode(Id, ANG, ASTTypeAngle, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  DN->SetConst();
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *ASTProductionFactory::ProductionRule_171(
    const ASTToken *TK, const std::string &SId, const ASTIntNode *II,
    ASTExpressionNode *EN) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(!SId.empty() && "Invalid Identifier argument!");
  assert(II && "Invalid ASTIntNode argument!");
  assert(EN && "Invalid ASTExpressionNode argument!");

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(II);
  assert(!ASTIdentifierNode::InvalidBits(Bits) &&
         "Invalid number of bits for const type!");

  ASTType ETy = EN->GetASTType();

  ASTIdentifierNode *Id = ASTBuilder::Instance().FindASTIdentifierNode(SId);
  if (Id) {
    if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
      std::stringstream M;
      M << "Declaration " << Id->GetName() << " shadows a "
        << "previous declaration.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(Id), M.str(),
          DiagLevel::Error);
      return ASTDeclarationNode::DeclarationError(Id, M.str());
    }
  } else {
    switch (ETy) {
    case ASTTypeBool:
    case ASTTypeInt:
    case ASTTypeFloat:
    case ASTTypeDouble:
    case ASTTypeLongDouble:
    case ASTTypeMPInteger:
    case ASTTypeMPDecimal:
    case ASTTypeMPComplex:
    case ASTTypeStringLiteral:
    case ASTTypeAngle:
    case ASTTypeBinaryOp:
    case ASTTypeUnaryOp:
      Id = ASTBuilder::Instance().CreateASTIdentifierNode(SId, Bits,
                                                          ASTTypeAngle);
      assert(Id && "Could not create an ASTIdentifierNode!");
      Id->SetLocation(TK->GetLocation());
      break;
    default: {
      std::stringstream M;
      M << "An expression of type " << PrintTypeEnum(ETy) << " cannot "
        << "yield an implicit type const declaration.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(EN), M.str(),
          DiagLevel::Error);
      return ASTDeclarationNode::DeclarationError(Id, M.str());
    } break;
    }
  }

  assert(Id && "Could not create an ASTIdentifierNode!");
  assert(Bits != static_cast<unsigned>(~0x0) && "Invalid Angle Bits!");

  ASTAngleNode *ANG = nullptr;

  switch (ETy) {
  case ASTTypeBool:
    if (ASTBoolNode *BN = dynamic_cast<ASTBoolNode *>(EN)) {
      ANG = new ASTAngleNode(Id, static_cast<double>(BN->GetValue()),
                             ASTAngleTypeGeneric, Bits);
      assert(ANG && "Could not create a valid ASTAngleNode!");
    }
    break;
  case ASTTypeInt:
    if (ASTIntNode *IN = dynamic_cast<ASTIntNode *>(EN)) {
      ANG = new ASTAngleNode(Id, static_cast<double>(IN->GetSignedValue()),
                             ASTAngleTypeGeneric, Bits);
      assert(ANG && "Could not create a valid ASTAngleNode!");
    }
    break;
  case ASTTypeFloat:
    if (ASTFloatNode *FN = dynamic_cast<ASTFloatNode *>(EN)) {
      ANG = new ASTAngleNode(Id, static_cast<double>(FN->GetValue()),
                             ASTAngleTypeGeneric, Bits);
      assert(ANG && "Could not create a valid ASTAngleNode!");
    }
    break;
  case ASTTypeDouble:
    if (ASTDoubleNode *DN = dynamic_cast<ASTDoubleNode *>(EN)) {
      ANG = new ASTAngleNode(Id, static_cast<double>(DN->GetValue()),
                             ASTAngleTypeGeneric, Bits);
      assert(ANG && "Could not create a valid ASTAngleNode!");
    }
    break;
  case ASTTypeLongDouble:
    if (ASTLongDoubleNode *LN = dynamic_cast<ASTLongDoubleNode *>(EN)) {
      ANG = new ASTAngleNode(Id, LN, ASTAngleTypeGeneric, Bits);
      assert(ANG && "Could not create a valid ASTAngleNode!");
    }
    break;
  case ASTTypeMPInteger:
    if (ASTMPIntegerNode *MPI = dynamic_cast<ASTMPIntegerNode *>(EN)) {
      ANG = new ASTAngleNode(Id, MPI, ASTAngleTypeGeneric, Bits);
      assert(ANG && "Could not create a valid ASTAngleNode!");
    }
    break;
  case ASTTypeMPDecimal:
    if (ASTMPDecimalNode *MPD = dynamic_cast<ASTMPDecimalNode *>(EN)) {
      ANG = new ASTAngleNode(Id, MPD, ASTAngleTypeGeneric, Bits);
      assert(ANG && "Could not create a valid ASTAngleNode!");
    }
    break;
  case ASTTypeMPComplex:
    if (ASTMPComplexNode *MPC = dynamic_cast<ASTMPComplexNode *>(EN)) {
      ANG = new ASTAngleNode(Id, MPC->GetRealAsMPDecimal(), ASTAngleTypeGeneric,
                             Bits);
      assert(ANG && "Could not create a valid ASTAngleNode!");
    }
    break;
  case ASTTypeStringLiteral: {
    if (ASTStringNode *SN = dynamic_cast<ASTStringNode *>(EN)) {
      int Base = 10;
      std::string ASN = SN->GetValue();

      if (ASTStringUtils::Instance().IsBinary(ASN)) {
        if (ASN[0] == u8'0' && (ASN[1] == u8'b' || ASN[1] == u8'B'))
          ASN = ASN.substr(2, std::string::npos);
        Base = 2;
      } else if (ASTStringUtils::Instance().IsHex(ASN)) {
        if (ASN[0] == u8'0' && (ASN[1] == u8'x' || ASN[1] == u8'X'))
          ASN = ASN.substr(2, std::string::npos);
        Base = 16;
      }

      ANG = new ASTAngleNode(Id, Bits, ASN, ASTAngleTypeGeneric, Base);
      assert(ANG && "Could not create a valid ASTAngleNode!");
    }
  } break;
  case ASTTypeAngle:
    if (ASTAngleNode *AN = dynamic_cast<ASTAngleNode *>(EN)) {
      ANG = AN->Clone(Id, Bits);
      assert(ANG && "Could not create a valid ASTAngleNode!");
      ANG->SetAngleType(ASTAngleTypeGeneric);
    }
    break;
  case ASTTypeBinaryOp:
    if (ASTBinaryOpNode *BOP = dynamic_cast<ASTBinaryOpNode *>(EN)) {
      ANG = new ASTAngleNode(Id, BOP, ASTAngleTypeGeneric, Bits);
      assert(ANG && "Could not create a valid ASTAngleNode!");
    }
    break;
  case ASTTypeUnaryOp:
    if (ASTUnaryOpNode *UOP = dynamic_cast<ASTUnaryOpNode *>(EN)) {
      ANG = new ASTAngleNode(Id, UOP, ASTAngleTypeGeneric, Bits);
      assert(ANG && "Could not create a valid ASTAngleNode!");
    }
    break;
  default: {
    std::stringstream M;
    M << "Impossible initialization of an ASTTypeAngle from an "
      << PrintTypeEnum(ETy) << ".";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  } break;
  }

  if (!ANG) {
    std::stringstream M;
    M << "Could not instantiate an ASTAngleNode from an Expression of Type "
      << PrintTypeEnum(ETy) << ".";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  ANG->SetLocation(TK->GetLocation());
  ANG->SetConst();
  ANG->Mangle();

  ASTSymbolTableEntry *STE = Id->GetSymbolTableEntry();
  assert(STE && "Identifier has no SymbolTable Entry!");

  STE->ResetValue();
  STE->SetValue(new ASTValue<>(ANG, ASTTypeAngle), ASTTypeAngle);
  assert(STE->HasValue() &&
         "Could not create a valid SymbolTable Entry Value!");

  ASTDeclarationNode *DN = new ASTDeclarationNode(Id, ANG, ASTTypeAngle, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  DN->SetConst();

  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *ASTProductionFactory::ProductionRule_172(
    const ASTToken *TK, const std::string &SId, const ASTIdentifierNode *IId,
    ASTExpressionNode *EN) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(!SId.empty() && "Invalid Identifier argument!");
  assert(IId && "Invalid ASTIdentifierNode argument!");
  assert(EN && "Invalid ASTExpressionNode argument!");

  ASTScopeController::Instance().CheckOutOfScope(IId);

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(IId);
  assert(!ASTIdentifierNode::InvalidBits(Bits) &&
         "Invalid number of bits for const type!");

  ASTType ETy = EN->GetASTType();

  ASTIdentifierNode *Id = ASTBuilder::Instance().FindASTIdentifierNode(SId);
  if (Id) {
    if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
      std::stringstream M;
      M << "Declaration " << Id->GetName() << " shadows a "
        << "previous declaration.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(Id), M.str(),
          DiagLevel::Error);
      return ASTDeclarationNode::DeclarationError(Id, M.str());
    }
  } else {
    switch (ETy) {
    case ASTTypeBool:
    case ASTTypeInt:
    case ASTTypeFloat:
    case ASTTypeDouble:
    case ASTTypeLongDouble:
    case ASTTypeMPInteger:
    case ASTTypeMPDecimal:
    case ASTTypeMPComplex:
    case ASTTypeStringLiteral:
    case ASTTypeAngle:
    case ASTTypeBinaryOp:
    case ASTTypeUnaryOp:
      Id = ASTBuilder::Instance().CreateASTIdentifierNode(SId, Bits,
                                                          ASTTypeAngle);
      assert(Id && "Could not create an ASTIdentifierNode!");
      Id->SetLocation(TK->GetLocation());
      break;
    default: {
      std::stringstream M;
      M << "An expression of type " << PrintTypeEnum(ETy) << " cannot "
        << "yield an implicit type const declaration.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(EN), M.str(),
          DiagLevel::Error);
      return ASTDeclarationNode::DeclarationError(Id, M.str());
    } break;
    }
  }

  assert(Id && "Could not create an ASTIdentifierNode!");
  assert(Bits != static_cast<unsigned>(~0x0) && "Invalid Angle Bits!");

  ASTAngleNode *ANG = nullptr;

  switch (ETy) {
  case ASTTypeBool:
    if (ASTBoolNode *BN = dynamic_cast<ASTBoolNode *>(EN)) {
      ANG = new ASTAngleNode(Id, static_cast<double>(BN->GetValue()),
                             ASTAngleTypeGeneric, Bits);
      assert(ANG && "Could not create a valid ASTAngleNode!");
    }
    break;
  case ASTTypeInt:
    if (ASTIntNode *IN = dynamic_cast<ASTIntNode *>(EN)) {
      ANG = new ASTAngleNode(Id, static_cast<double>(IN->GetSignedValue()),
                             ASTAngleTypeGeneric, Bits);
      assert(ANG && "Could not create a valid ASTAngleNode!");
    }
    break;
  case ASTTypeFloat:
    if (ASTFloatNode *FN = dynamic_cast<ASTFloatNode *>(EN)) {
      ANG = new ASTAngleNode(Id, static_cast<double>(FN->GetValue()),
                             ASTAngleTypeGeneric, Bits);
      assert(ANG && "Could not create a valid ASTAngleNode!");
    }
    break;
  case ASTTypeDouble:
    if (ASTDoubleNode *DN = dynamic_cast<ASTDoubleNode *>(EN)) {
      ANG = new ASTAngleNode(Id, static_cast<double>(DN->GetValue()),
                             ASTAngleTypeGeneric, Bits);
      assert(ANG && "Could not create a valid ASTAngleNode!");
    }
    break;
  case ASTTypeLongDouble:
    if (ASTLongDoubleNode *LN = dynamic_cast<ASTLongDoubleNode *>(EN)) {
      ANG = new ASTAngleNode(Id, LN, ASTAngleTypeGeneric, Bits);
      assert(ANG && "Could not create a valid ASTAngleNode!");
    }
    break;
  case ASTTypeMPInteger:
    if (ASTMPIntegerNode *MPI = dynamic_cast<ASTMPIntegerNode *>(EN)) {
      ANG = new ASTAngleNode(Id, MPI, ASTAngleTypeGeneric, Bits);
      assert(ANG && "Could not create a valid ASTAngleNode!");
    }
    break;
  case ASTTypeMPDecimal:
    if (ASTMPDecimalNode *MPD = dynamic_cast<ASTMPDecimalNode *>(EN)) {
      ANG = new ASTAngleNode(Id, MPD, ASTAngleTypeGeneric, Bits);
      assert(ANG && "Could not create a valid ASTAngleNode!");
    }
    break;
  case ASTTypeMPComplex:
    if (ASTMPComplexNode *MPC = dynamic_cast<ASTMPComplexNode *>(EN)) {
      ANG = new ASTAngleNode(Id, MPC->GetRealAsMPDecimal(), ASTAngleTypeGeneric,
                             Bits);
      assert(ANG && "Could not create a valid ASTAngleNode!");
    }
    break;
  case ASTTypeStringLiteral: {
    if (ASTStringNode *SN = dynamic_cast<ASTStringNode *>(EN)) {
      int Base = 10;
      std::string ASN = SN->GetValue();

      if (ASTStringUtils::Instance().IsBinary(ASN)) {
        if (ASN[0] == u8'0' && (ASN[1] == u8'b' || ASN[1] == u8'B'))
          ASN = ASN.substr(2, std::string::npos);
        Base = 2;
      } else if (ASTStringUtils::Instance().IsHex(ASN)) {
        if (ASN[0] == u8'0' && (ASN[1] == u8'x' || ASN[1] == u8'X'))
          ASN = ASN.substr(2, std::string::npos);
        Base = 16;
      }

      ANG = new ASTAngleNode(Id, Bits, ASN, ASTAngleTypeGeneric, Base);
      assert(ANG && "Could not create a valid ASTAngleNode!");
    }
  } break;
  case ASTTypeAngle:
    if (ASTAngleNode *AN = dynamic_cast<ASTAngleNode *>(EN)) {
      ANG = AN->Clone(Id, Bits);
      assert(ANG && "Could not create a valid ASTAngleNode!");
      ANG->SetAngleType(ASTAngleTypeGeneric);
    }
    break;
  case ASTTypeBinaryOp:
    if (ASTBinaryOpNode *BOP = dynamic_cast<ASTBinaryOpNode *>(EN)) {
      ANG = new ASTAngleNode(Id, BOP, ASTAngleTypeGeneric, Bits);
      assert(ANG && "Could not create a valid ASTAngleNode!");
    }
    break;
  case ASTTypeUnaryOp:
    if (ASTUnaryOpNode *UOP = dynamic_cast<ASTUnaryOpNode *>(EN)) {
      ANG = new ASTAngleNode(Id, UOP, ASTAngleTypeGeneric, Bits);
      assert(ANG && "Could not create a valid ASTAngleNode!");
    }
    break;
  default: {
    std::stringstream M;
    M << "Impossible initialization of an ASTTypeAngle from an "
      << PrintTypeEnum(ETy) << ".";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  } break;
  }

  if (!ANG) {
    std::stringstream M;
    M << "Could not instantiate an ASTAngleNode from an Expression of Type "
      << PrintTypeEnum(ETy) << ".";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  ANG->SetLocation(TK->GetLocation());
  ANG->SetConst();
  ANG->Mangle();

  ASTSymbolTableEntry *STE = Id->GetSymbolTableEntry();
  assert(STE && "Identifier has no SymbolTable Entry!");

  STE->ResetValue();
  STE->SetValue(new ASTValue<>(ANG, ASTTypeAngle), ASTTypeAngle);
  assert(STE->HasValue() &&
         "Could not create a valid SymbolTable Entry Value!");

  ASTDeclarationNode *DN = new ASTDeclarationNode(Id, ANG, ASTTypeAngle, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  DN->SetConst();

  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *
ASTProductionFactory::ProductionRule_180(const ASTToken *TK,
                                         const ASTIdentifierNode *Id) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
          Id, ASTAngleNode::AngleBits, ASTTypeAngle)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeAngle.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
    std::stringstream M;
    M << "Declaration " << Id->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  ASTAngleType ATy = ASTAngleNode::DetermineAngleType(Id->GetName());
  ASTAngleNode *AN =
      ASTBuilder::Instance().CreateASTAngleNode(Id, ATy, Id->GetBits());
  assert(AN && "Could not create a valid ASTAngleNode!");

  AN->SetLocation(TK->GetLocation());
  AN->Mangle();

  ASTAngleNodeBuilder::Instance().Append(AN);
  ASTAngleNodeBuilder::Instance().Insert(AN);

  ASTDeclarationNode *DN = new ASTDeclarationNode(Id, AN, ASTTypeAngle, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *
ASTProductionFactory::ProductionRule_181(const ASTToken *TK,
                                         const ASTIdentifierNode *Id,
                                         const ASTExpressionNode *EN) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(EN && "Invalid ASTExpressionNode argument!");

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
          Id, ASTAngleNode::AngleBits, ASTTypeAngle)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeInt.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
    std::stringstream M;
    M << "Declaration " << Id->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  ASTType ETy = EN->GetASTType();
  ASTAngleNode *AAN = nullptr;
  bool FromAngle = false;
  bool FromValue = false;
  bool FromExpr = true;
  const ASTImplicitConversionNode *ICX = nullptr;
  const unsigned Bits = ASTAngleNode::AngleBits;
  mpfr_t MPV;

  switch (ETy) {
  case ASTTypeBool:
    if (const ASTBoolNode *BN = dynamic_cast<const ASTBoolNode *>(EN)) {
      FromValue = true;
      mpfr_init2(MPV, Bits);
      mpfr_set_ui(MPV, static_cast<unsigned>(BN->GetValue()), MPFR_RNDN);
      ICX = new ASTImplicitConversionNode(BN, ASTTypeAngle, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeInt:
    if (const ASTIntNode *IN = dynamic_cast<const ASTIntNode *>(EN)) {
      FromValue = true;
      mpfr_init2(MPV, Bits);
      if (IN->IsSigned())
        mpfr_set_si(MPV, IN->GetSignedValue(), MPFR_RNDN);
      else
        mpfr_set_ui(MPV, IN->GetUnsignedValue(), MPFR_RNDN);
      ICX = new ASTImplicitConversionNode(IN, ASTTypeAngle, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeFloat:
    if (const ASTFloatNode *FN = dynamic_cast<const ASTFloatNode *>(EN)) {
      mpfr_init2(MPV, Bits);
      FromValue = true;
      mpfr_set_flt(MPV, FN->GetValue(), MPFR_RNDN);
      ICX = new ASTImplicitConversionNode(FN, ASTTypeAngle, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeDouble:
    if (const ASTDoubleNode *DN = dynamic_cast<const ASTDoubleNode *>(EN)) {
      mpfr_init2(MPV, Bits);
      FromValue = true;
      mpfr_set_d(MPV, DN->GetValue(), MPFR_RNDN);
      ICX = new ASTImplicitConversionNode(DN, ASTTypeAngle, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeLongDouble:
    if (const ASTLongDoubleNode *LN =
            dynamic_cast<const ASTLongDoubleNode *>(EN)) {
      mpfr_init2(MPV, Bits);
      FromValue = true;
      mpfr_set_ld(MPV, LN->GetValue(), MPFR_RNDN);
      ICX = new ASTImplicitConversionNode(LN, ASTTypeAngle, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeMPInteger:
    if (const ASTMPIntegerNode *MPII =
            dynamic_cast<const ASTMPIntegerNode *>(EN)) {
      FromValue = true;
      mpfr_init2(MPV, Bits);
      mpfr_set_z(MPV, MPII->GetMPValue(), MPFR_RNDN);
      ICX = new ASTImplicitConversionNode(MPII, ASTTypeAngle, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeMPDecimal:
    if (const ASTMPDecimalNode *MPDD =
            dynamic_cast<const ASTMPDecimalNode *>(EN)) {
      FromValue = true;
      mpfr_init2(MPV, Bits);
      mpfr_set(MPV, MPDD->GetMPValue(), MPFR_RNDN);
      ICX = new ASTImplicitConversionNode(MPDD, ASTTypeAngle, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeBitset:
    if (const ASTCBitNode *CB = dynamic_cast<const ASTCBitNode *>(EN)) {
      FromValue = true;
      mpfr_init2(MPV, Bits);
      if (mpfr_set_str(MPV, CB->AsString().c_str(), 2, MPFR_RNDN) != 0)
        mpfr_set_nan(MPV);
      ICX = new ASTImplicitConversionNode(CB, ASTTypeAngle, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeAngle:
    if (const ASTAngleNode *AN = dynamic_cast<const ASTAngleNode *>(EN)) {
      FromValue = true;
      mpfr_init2(MPV, Bits);
      mpfr_set(MPV, AN->GetMPValue(), MPFR_RNDN);
    }
    break;
  case ASTTypeStringLiteral: {
    if (const ASTStringNode *SN = dynamic_cast<const ASTStringNode *>(EN)) {
      FromValue = true;
      mpfr_init2(MPV, Bits);
      std::string MPS = ASTStringUtils::Instance().Sanitize(SN->GetValue());
      if (MPS.find_first_of(u8'.') == std::string::npos)
        MPS += ".0";
      mpfr_set_str(MPV, MPS.c_str(), 10, MPFR_RNDN);
    }
  } break;
  case ASTTypeBinaryOp:
  case ASTTypeUnaryOp:
  case ASTTypeExpression:
    FromExpr = true;
    ICX = new ASTImplicitConversionNode(EN, ASTTypeAngle, Bits);
    assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    break;
  case ASTTypeCast:
    FromExpr = true;
    break;
  case ASTTypeImplicitConversion:
    FromExpr = true;
    ICX = new ASTImplicitConversionNode(EN, ASTTypeAngle, Bits);
    assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    break;
  case ASTTypeCBitArray:
  case ASTTypeCBitNArray:
  case ASTTypeQubitArray:
  case ASTTypeQubitNArray:
  case ASTTypeAngleArray:
  case ASTTypeBoolArray:
  case ASTTypeMPIntegerArray:
  case ASTTypeMPDecimalArray:
  case ASTTypeLengthArray:
  case ASTTypeDurationArray:
  case ASTTypeFloatArray:
  case ASTTypeIntArray: {
    std::stringstream M;
    M << "An " << PrintTypeEnum(ETy) << " array cannot be assigned "
      << "to an angle.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  } break;
  case ASTTypeQubit: {
    std::stringstream M;
    M << "A Qubit cannot be assigned to an angle.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  } break;
  case ASTTypeIdentifier: {
    Id = EN->GetIdentifier();
    assert(Id && "Could not obtain a valid ASTIdentifierNode!");

    ASTScopeController::Instance().CheckUndefined(Id);
    ASTScopeController::Instance().CheckOutOfScope(Id);

    const ASTIdentifierRefNode *IdR =
        dynamic_cast<const ASTIdentifierRefNode *>(Id);
    if (!IdR) {
      const ASTSymbolTableEntry *STE = Id->GetSymbolTableEntry();
      assert(STE && "Could not obtain a valid ASTSymbolTableEntry!");
      assert(STE->GetValueType() == Id->GetSymbolType() &&
             "Type mismatch ASTIdentifierNode <-> ASTSymbolTableEntry!");

      switch (Id->GetSymbolType()) {
      case ASTTypeBool: {
        if (ASTBoolNode *BN = STE->GetValue()->GetValue<ASTBoolNode *>()) {
          FromValue = true;
          mpfr_init2(MPV, Bits);
          mpfr_set_ui(MPV, static_cast<unsigned>(BN->GetValue()), MPFR_RNDN);
          ICX = new ASTImplicitConversionNode(BN, ASTTypeAngle, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeInt: {
        if (ASTIntNode *IN = STE->GetValue()->GetValue<ASTIntNode *>()) {
          FromValue = true;
          mpfr_init2(MPV, Bits);
          if (IN->IsSigned())
            mpfr_set_si(MPV, IN->GetSignedValue(), MPFR_RNDN);
          else
            mpfr_set_ui(MPV, IN->GetUnsignedValue(), MPFR_RNDN);
          ICX = new ASTImplicitConversionNode(IN, ASTTypeAngle, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeFloat: {
        if (ASTFloatNode *FN = STE->GetValue()->GetValue<ASTFloatNode *>()) {
          mpfr_init2(MPV, Bits);
          FromValue = true;
          mpfr_set_flt(MPV, FN->GetValue(), MPFR_RNDN);
          ICX = new ASTImplicitConversionNode(FN, ASTTypeAngle, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeDouble: {
        if (ASTDoubleNode *DN = STE->GetValue()->GetValue<ASTDoubleNode *>()) {
          mpfr_init2(MPV, Bits);
          FromValue = true;
          mpfr_set_d(MPV, DN->GetValue(), MPFR_RNDN);
          ICX = new ASTImplicitConversionNode(DN, ASTTypeAngle, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeLongDouble: {
        if (ASTLongDoubleNode *LN =
                STE->GetValue()->GetValue<ASTLongDoubleNode *>()) {
          mpfr_init2(MPV, Bits);
          FromValue = true;
          mpfr_set_ld(MPV, LN->GetValue(), MPFR_RNDN);
          ICX = new ASTImplicitConversionNode(LN, ASTTypeAngle, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeAngle: {
        if (ASTAngleNode *ANG = STE->GetValue()->GetValue<ASTAngleNode *>()) {
          FromValue = true;
          mpfr_init2(MPV, Bits);
          mpfr_set(MPV, ANG->GetMPValue(), MPFR_RNDN);
        }
      } break;
      case ASTTypeMPInteger: {
        if (ASTMPIntegerNode *MPI =
                STE->GetValue()->GetValue<ASTMPIntegerNode *>()) {
          FromValue = true;
          mpfr_init2(MPV, Bits);
          mpfr_set_z(MPV, MPI->GetMPValue(), MPFR_RNDN);
          ICX = new ASTImplicitConversionNode(MPI, ASTTypeAngle, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeMPDecimal: {
        if (ASTMPDecimalNode *MPD =
                STE->GetValue()->GetValue<ASTMPDecimalNode *>()) {
          FromValue = true;
          mpfr_init2(MPV, Bits);
          mpfr_set(MPV, MPD->GetMPValue(), MPFR_RNDN);
          ICX = new ASTImplicitConversionNode(MPD, ASTTypeAngle, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeMPComplex: {
        if (ASTMPComplexNode *MPC =
                STE->GetValue()->GetValue<ASTMPComplexNode *>()) {
          FromValue = true;
          mpfr_init2(MPV, Bits);
          mpfr_set(MPV, MPC->GetRealAsMPDecimal()->GetMPValue(), MPFR_RNDN);
          ICX = new ASTImplicitConversionNode(MPC, ASTTypeAngle, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeBitset: {
        if (ASTCBitNode *CBN = STE->GetValue()->GetValue<ASTCBitNode *>()) {
          FromValue = true;
          mpfr_init2(MPV, Bits);
          if (mpfr_set_str(MPV, CBN->AsString().c_str(), 2, MPFR_RNDN) != 0)
            mpfr_set_nan(MPV);
          ICX = new ASTImplicitConversionNode(CBN, ASTTypeAngle, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      default: {
        std::stringstream M;
        M << "Impossible assignment to an ASTTypeAngle from an "
          << PrintTypeEnum(Id->GetSymbolType()) << '.';
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(Id), M.str(),
            DiagLevel::ICE);
        return ASTDeclarationNode::DeclarationError(Id, M.str());
      } break;
      }
    } else {
      assert(IdR && "Could not dynamic_cast to an ASTIdentifierNode!");

      const ASTIdentifierNode *IId = IdR->GetIdentifier();
      assert(IId && "Could not obtain an unindexed ASTIdentifierNode!");

      ASTScopeController::Instance().CheckUndefined(IId);
      ASTScopeController::Instance().CheckOutOfScope(IId);

      if (IdR->IsIndexed()) {
        ASTSymbolTableEntry *STE = ASTSymbolTable::Instance().Lookup(
            IdR, IdR->GetBits(), IdR->GetReferenceType());
        assert(STE && "ASTIdentifierRefNode has no SymbolTable Entry!");

        switch (STE->GetValueType()) {
        case ASTTypeBool: {
          if (ASTBoolNode *BN = STE->GetValue()->GetValue<ASTBoolNode *>()) {
            FromValue = true;
            mpfr_init2(MPV, Bits);
            mpfr_set_ui(MPV, static_cast<unsigned>(BN->GetValue()), MPFR_RNDN);
            ICX = new ASTImplicitConversionNode(BN, ASTTypeAngle, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
        } break;
        case ASTTypeInt: {
          if (ASTIntNode *IN = STE->GetValue()->GetValue<ASTIntNode *>()) {
            FromValue = true;
            mpfr_init2(MPV, Bits);
            if (IN->IsSigned())
              mpfr_set_si(MPV, IN->GetSignedValue(), MPFR_RNDN);
            else
              mpfr_set_ui(MPV, IN->GetUnsignedValue(), MPFR_RNDN);
            ICX = new ASTImplicitConversionNode(IN, ASTTypeAngle, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
        } break;
        case ASTTypeFloat: {
          if (ASTFloatNode *FN = STE->GetValue()->GetValue<ASTFloatNode *>()) {
            mpfr_init2(MPV, Bits);
            FromValue = true;
            mpfr_set_flt(MPV, FN->GetValue(), MPFR_RNDN);
            ICX = new ASTImplicitConversionNode(FN, ASTTypeAngle, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
        } break;
        case ASTTypeDouble: {
          if (ASTDoubleNode *DN =
                  STE->GetValue()->GetValue<ASTDoubleNode *>()) {
            mpfr_init2(MPV, Bits);
            FromValue = true;
            mpfr_set_d(MPV, DN->GetValue(), MPFR_RNDN);
            ICX = new ASTImplicitConversionNode(DN, ASTTypeAngle, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
        } break;
        case ASTTypeLongDouble: {
          if (ASTLongDoubleNode *LN =
                  STE->GetValue()->GetValue<ASTLongDoubleNode *>()) {
            mpfr_init2(MPV, Bits);
            FromValue = true;
            mpfr_set_ld(MPV, LN->GetValue(), MPFR_RNDN);
            ICX = new ASTImplicitConversionNode(LN, ASTTypeAngle, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
        } break;
        case ASTTypeAngle: {
          if (ASTAngleNode *ANG = STE->GetValue()->GetValue<ASTAngleNode *>()) {
            FromValue = true;
            mpfr_init2(MPV, Bits);
            mpfr_set(MPV, ANG->GetMPValue(), MPFR_RNDN);
          }
        } break;
        case ASTTypeMPInteger: {
          if (ASTMPIntegerNode *MPI =
                  STE->GetValue()->GetValue<ASTMPIntegerNode *>()) {
            FromValue = true;
            mpfr_init2(MPV, Bits);
            mpfr_set_z(MPV, MPI->GetMPValue(), MPFR_RNDN);
            ICX = new ASTImplicitConversionNode(MPI, ASTTypeAngle, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
        } break;
        case ASTTypeMPDecimal: {
          if (ASTMPDecimalNode *MPD =
                  STE->GetValue()->GetValue<ASTMPDecimalNode *>()) {
            FromValue = true;
            mpfr_init2(MPV, Bits);
            mpfr_set(MPV, MPD->GetMPValue(), MPFR_RNDN);
            ICX = new ASTImplicitConversionNode(MPD, ASTTypeAngle, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
        } break;
        case ASTTypeMPComplex: {
          if (ASTMPComplexNode *MPC =
                  STE->GetValue()->GetValue<ASTMPComplexNode *>()) {
            FromValue = true;
            mpfr_init2(MPV, Bits);
            mpfr_set(MPV, MPC->GetRealAsMPDecimal()->GetMPValue(), MPFR_RNDN);
            ICX = new ASTImplicitConversionNode(MPC, ASTTypeAngle, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
        } break;
        case ASTTypeBitset: {
          if (ASTCBitNode *CBN = STE->GetValue()->GetValue<ASTCBitNode *>()) {
            FromValue = true;
            mpfr_init2(MPV, Bits);
            if (mpfr_set_str(MPV, CBN->AsString().c_str(), 2, MPFR_RNDN) != 0)
              mpfr_set_nan(MPV);
            ICX = new ASTImplicitConversionNode(CBN, ASTTypeAngle, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
        } break;
        default: {
          std::stringstream M;
          M << "Impossible assignment to an ASTTypeAngle from an "
            << PrintTypeEnum(Id->GetSymbolType()) << '.';
          QasmDiagnosticEmitter::Instance().EmitDiagnostic(
              DIAGLineCounter::Instance().GetLocation(Id), M.str(),
              DiagLevel::ICE);
          return ASTDeclarationNode::DeclarationError(Id, M.str());
        } break;
        }
      } else if (ASTTypeSystemBuilder::Instance().IsReservedAngle(
                     Id->GetName())) {
        AAN = ASTAngleNodeBuilder::Instance().FindInMap(
            Id->GetName(), ASTAngleNode::AngleBits);
        if (!AAN) {
          std::stringstream M;
          M << "Reserved angle " << Id->GetName() << " not found in the "
            << "reserved angle table.";
          QasmDiagnosticEmitter::Instance().EmitDiagnostic(
              DIAGLineCounter::Instance().GetLocation(Id), M.str(),
              DiagLevel::ICE);
          return ASTDeclarationNode::DeclarationError(Id, M.str());
        }
      } else {
        std::stringstream M;
        M << "Impossible ASTAngleNode Initialization from an "
          << PrintTypeEnum(ETy) << ".";
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(EN), M.str(),
            DiagLevel::Error);
        return ASTDeclarationNode::DeclarationError(Id, M.str());
      }
    }
  } break;
  default: {
    std::stringstream M;
    M << "Impossible ASTAngleNode assignment from an " << PrintTypeEnum(ETy)
      << ".";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  } break;
  }

  ASTAngleType ATy = ASTAngleNode::DetermineAngleType(Id->GetName());
  Id->SetBits(ASTAngleNode::AngleBits);
  ASTAngleNode *AN = nullptr;

  if (FromValue) {
    AN = ASTBuilder::Instance().CreateASTAngleNode(Id, ATy, MPV,
                                                   ASTAngleNode::AngleBits);
    assert(AN && "Could not create an ASTAngleNode!");
    mpfr_clear(MPV);
  } else if (FromExpr) {
    AN = ASTBuilder::Instance().CreateASTAngleNode(Id, EN, ATy,
                                                   ASTAngleNode::AngleBits);
    assert(AN && "Could not create an ASTAngleNode!");
  } else if (FromAngle) {
    AN = ASTBuilder::Instance().CreateASTAngleNode(Id, ATy,
                                                   ASTAngleNode::AngleBits);
    assert(AN && "Could not create an ASTAngleNode!");
    AN->SetValue(AAN->GetValue(10));
  } else {
    AN = ASTBuilder::Instance().CreateASTAngleNode(Id, EN, ATy,
                                                   ASTAngleNode::AngleBits);
    assert(AN && "Could not create an ASTAngleNode!");
  }

  if (FromValue) {
    AN->SetConstantFolded(true);
    if (ICX)
      AN->SetImplicitConversion(ICX);
  }

  AN->SetLocation(TK->GetLocation());
  AN->Mangle();

  ASTAngleNodeBuilder::Instance().Append(AN);
  ASTAngleNodeBuilder::Instance().Insert(AN);

  ASTDeclarationNode *DN = new ASTDeclarationNode(Id, AN, ASTTypeAngle, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *ASTProductionFactory::ProductionRule_182(
    const ASTToken *TK, const ASTIdentifierNode *Id,
    const ASTFunctionCallStatementNode *FC) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(FC && "Invalid ASTFunctionCallStatementNode argument!");

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
          Id, ASTAngleNode::AngleBits, ASTTypeAngle)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeInt.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
    std::stringstream M;
    M << "Declaration " << Id->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  const ASTFunctionCallNode *EN = FC->GetFunctionCall();
  assert(EN && "Could not obtain a valid ASTFunctionCallNode!");

  if (!EN->ReturnsResult()) {
    std::stringstream M;
    M << "Assignment requires a non-void return type.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  ASTAngleType ATy = ASTAngleNode::DetermineAngleType(Id->GetName());
  ASTAngleNode *AN = ASTBuilder::Instance().CreateASTAngleNode(
      Id, EN, ATy, ASTAngleNode::AngleBits);
  assert(AN && "Could not create an ASTAngleNode!");

  AN->SetLocation(TK->GetLocation());
  AN->Mangle();

  ASTAngleNodeBuilder::Instance().Append(AN);
  ASTAngleNodeBuilder::Instance().Insert(AN);

  ASTDeclarationNode *DN = new ASTDeclarationNode(Id, AN, ASTTypeAngle, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *
ASTProductionFactory::ProductionRule_240(const ASTToken *TK,
                                         const ASTIdentifierNode *Id,
                                         const ASTIntNode *II) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(II && "Invalid ASTIntNode argument!");

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(II);
  assert(!ASTIdentifierNode::InvalidBits(Bits) && "Invalid angle bit width!");

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(Id, Bits,
                                                          ASTTypeAngle)) {
    std::stringstream M;
    M << "Could not transfer SymbolTable Entry for ASTTypeAngle.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
    std::stringstream M;
    M << "Declaration " << Id->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  ASTAngleType ATy = ASTAngleNode::DetermineAngleType(Id->GetName());
  ASTAngleNode *AN = ASTBuilder::Instance().CreateASTAngleNode(Id, ATy, Bits);
  assert(AN && "Could not create an ASTAngleNode!");

  AN->SetLocation(TK->GetLocation());
  AN->Mangle();
  ASTAngleNodeBuilder::Instance().Append(AN);
  ASTAngleNodeBuilder::Instance().Insert(AN);

  ASTDeclarationNode *DN = new ASTDeclarationNode(Id, AN, ASTTypeAngle, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *
ASTProductionFactory::ProductionRule_241(const ASTToken *TK,
                                         const ASTIdentifierNode *Id,
                                         const ASTIdentifierNode *IId) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(IId && "Invalid ASTIdentifierNode Index argument!");

  ASTScopeController::Instance().CheckUndefined(Id);
  ASTScopeController::Instance().CheckOutOfScope(IId);

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(IId);
  assert(!ASTIdentifierNode::InvalidBits(Bits) &&
         "Invalid number of Bits for Angle Declaration!");

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(Id, Bits,
                                                          ASTTypeAngle)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeAngle.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
    std::stringstream M;
    M << "Declaration " << Id->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  ASTAngleType ATy = ASTAngleNode::DetermineAngleType(Id->GetName());
  ASTAngleNode *AN = ASTBuilder::Instance().CreateASTAngleNode(Id, ATy, Bits);
  assert(AN && "Could not create an ASTAngleNode!");

  AN->SetLocation(TK->GetLocation());
  AN->Mangle();
  ASTAngleNodeBuilder::Instance().Append(AN);
  ASTAngleNodeBuilder::Instance().Insert(AN);

  ASTDeclarationNode *DN = new ASTDeclarationNode(Id, AN, ASTTypeAngle, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *ASTProductionFactory::ProductionRule_242(
    const ASTToken *TK, const ASTIdentifierNode *Id, const ASTIntNode *II,
    const ASTExpressionNode *EN) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(II && "Invalid ASTIntNode argument!");
  assert(EN && "Invalid ASTExpressionNode in initialization declaration!");

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(II);
  assert(!ASTIdentifierNode::InvalidBits(Bits) && "Invalid angle bit width!");

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(Id, Bits,
                                                          ASTTypeAngle)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeInt.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
    std::stringstream M;
    M << "Declaration " << Id->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  Id->SetBits(Bits);

  ASTAngleNode *AN = nullptr;
  bool FromArray = false;
  bool FromValue = false;
  bool FromExpr = false;
  bool FromAngle = false;
  const ASTImplicitConversionNode *ICX = nullptr;
  mpfr_t MPV;

  ASTType ETy = EN->GetASTType();

  switch (ETy) {
  case ASTTypeBool:
    if (const ASTBoolNode *BN = dynamic_cast<const ASTBoolNode *>(EN)) {
      FromValue = true;
      mpfr_init2(MPV, Bits);
      mpfr_set_ui(MPV, static_cast<unsigned>(BN->GetValue()), MPFR_RNDN);
      ICX = new ASTImplicitConversionNode(BN, ASTTypeAngle, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeInt:
    if (const ASTIntNode *IN = dynamic_cast<const ASTIntNode *>(EN)) {
      FromValue = true;
      mpfr_init2(MPV, Bits);
      if (IN->IsSigned())
        mpfr_set_si(MPV, IN->GetSignedValue(), MPFR_RNDN);
      else
        mpfr_set_ui(MPV, IN->GetUnsignedValue(), MPFR_RNDN);
      ICX = new ASTImplicitConversionNode(IN, ASTTypeAngle, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeFloat:
    if (const ASTFloatNode *FN = dynamic_cast<const ASTFloatNode *>(EN)) {
      mpfr_init2(MPV, Bits);
      FromValue = true;
      mpfr_set_flt(MPV, FN->GetValue(), MPFR_RNDN);
      ICX = new ASTImplicitConversionNode(FN, ASTTypeAngle, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeDouble:
    if (const ASTDoubleNode *DN = dynamic_cast<const ASTDoubleNode *>(EN)) {
      mpfr_init2(MPV, Bits);
      FromValue = true;
      mpfr_set_d(MPV, DN->GetValue(), MPFR_RNDN);
      ICX = new ASTImplicitConversionNode(DN, ASTTypeAngle, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeLongDouble:
    if (const ASTLongDoubleNode *LN =
            dynamic_cast<const ASTLongDoubleNode *>(EN)) {
      mpfr_init2(MPV, Bits);
      FromValue = true;
      mpfr_set_ld(MPV, LN->GetValue(), MPFR_RNDN);
      ICX = new ASTImplicitConversionNode(LN, ASTTypeAngle, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeMPInteger:
    if (const ASTMPIntegerNode *MPII =
            dynamic_cast<const ASTMPIntegerNode *>(EN)) {
      FromValue = true;
      mpfr_init2(MPV, Bits);
      mpfr_set_z(MPV, MPII->GetMPValue(), MPFR_RNDN);
      ICX = new ASTImplicitConversionNode(MPII, ASTTypeAngle, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeMPDecimal:
    if (const ASTMPDecimalNode *MPDD =
            dynamic_cast<const ASTMPDecimalNode *>(EN)) {
      FromValue = true;
      mpfr_init2(MPV, Bits);
      mpfr_set(MPV, MPDD->GetMPValue(), MPFR_RNDN);
      ICX = new ASTImplicitConversionNode(MPDD, ASTTypeAngle, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeBitset:
    if (const ASTCBitNode *CB = dynamic_cast<const ASTCBitNode *>(EN)) {
      FromValue = true;
      mpfr_init2(MPV, Bits);
      if (mpfr_set_str(MPV, CB->AsString().c_str(), 2, MPFR_RNDN) != 0)
        mpfr_set_nan(MPV);
      ICX = new ASTImplicitConversionNode(CB, ASTTypeAngle, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeAngle:
    if (const ASTAngleNode *AAN = dynamic_cast<const ASTAngleNode *>(EN)) {
      FromValue = true;
      mpfr_init2(MPV, Bits);
      mpfr_set(MPV, AAN->GetMPValue(), MPFR_RNDN);
    }
    break;
  case ASTTypeStringLiteral: {
    if (const ASTStringNode *SN = dynamic_cast<const ASTStringNode *>(EN)) {
      FromValue = true;
      mpfr_init2(MPV, Bits);
      std::string MPS = ASTStringUtils::Instance().Sanitize(SN->GetValue());
      if (MPS.find_first_of(u8'.') == std::string::npos)
        MPS += ".0";
      mpfr_set_str(MPV, MPS.c_str(), 10, MPFR_RNDN);
    }
  } break;
  case ASTTypeBinaryOp:
  case ASTTypeUnaryOp:
  case ASTTypeExpression:
    FromExpr = true;
    ICX = new ASTImplicitConversionNode(EN, ASTTypeAngle, Bits);
    assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    break;
  case ASTTypeCast:
    FromExpr = true;
    break;
  case ASTTypeImplicitConversion:
    FromExpr = true;
    ICX = new ASTImplicitConversionNode(EN, ASTTypeAngle, Bits);
    assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    break;
  case ASTTypeCBitArray:
  case ASTTypeCBitNArray:
  case ASTTypeQubitArray:
  case ASTTypeQubitNArray:
  case ASTTypeAngleArray:
  case ASTTypeBoolArray:
  case ASTTypeMPIntegerArray:
  case ASTTypeMPDecimalArray:
  case ASTTypeLengthArray:
  case ASTTypeDurationArray:
  case ASTTypeFloatArray:
  case ASTTypeIntArray: {
    std::stringstream M;
    M << "An " << PrintTypeEnum(ETy) << " array cannot be assigned "
      << "to an angle.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  } break;
  case ASTTypeQubit: {
    std::stringstream M;
    M << "A Qubit cannot be assigned to an angle.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  } break;
  case ASTTypeIdentifier: {
    const ASTIdentifierNode *AId = EN->GetIdentifier();
    assert(AId && "Could not obtain a valid ASTIdentifierNode!");

    ASTScopeController::Instance().CheckUndefined(AId);
    ASTScopeController::Instance().CheckOutOfScope(AId);

    const ASTIdentifierRefNode *AIdR =
        dynamic_cast<const ASTIdentifierRefNode *>(AId);
    if (!AIdR) {
      const ASTSymbolTableEntry *STE = AId->GetSymbolTableEntry();
      assert(STE && "Could not obtain a valid ASTSymbolTableEntry!");
      assert(STE->GetValueType() == Id->GetSymbolType() &&
             "Type mismatch ASTIdentifierNode <-> ASTSymbolTableEntry!");

      switch (Id->GetSymbolType()) {
      case ASTTypeBool: {
        if (ASTBoolNode *BN = STE->GetValue()->GetValue<ASTBoolNode *>()) {
          FromValue = true;
          mpfr_init2(MPV, Bits);
          mpfr_set_ui(MPV, static_cast<unsigned>(BN->GetValue()), MPFR_RNDN);
          ICX = new ASTImplicitConversionNode(BN, ASTTypeAngle, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeInt: {
        if (ASTIntNode *IN = STE->GetValue()->GetValue<ASTIntNode *>()) {
          FromValue = true;
          mpfr_init2(MPV, Bits);
          if (IN->IsSigned())
            mpfr_set_si(MPV, IN->GetSignedValue(), MPFR_RNDN);
          else
            mpfr_set_ui(MPV, IN->GetUnsignedValue(), MPFR_RNDN);
          ICX = new ASTImplicitConversionNode(IN, ASTTypeAngle, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeFloat: {
        if (ASTFloatNode *FN = STE->GetValue()->GetValue<ASTFloatNode *>()) {
          mpfr_init2(MPV, Bits);
          FromValue = true;
          mpfr_set_flt(MPV, FN->GetValue(), MPFR_RNDN);
          ICX = new ASTImplicitConversionNode(FN, ASTTypeAngle, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeDouble: {
        if (ASTDoubleNode *DN = STE->GetValue()->GetValue<ASTDoubleNode *>()) {
          mpfr_init2(MPV, Bits);
          FromValue = true;
          mpfr_set_d(MPV, DN->GetValue(), MPFR_RNDN);
          ICX = new ASTImplicitConversionNode(DN, ASTTypeAngle, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeLongDouble: {
        if (ASTLongDoubleNode *LN =
                STE->GetValue()->GetValue<ASTLongDoubleNode *>()) {
          mpfr_init2(MPV, Bits);
          FromValue = true;
          mpfr_set_ld(MPV, LN->GetValue(), MPFR_RNDN);
          ICX = new ASTImplicitConversionNode(LN, ASTTypeAngle, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeAngle: {
        if (ASTAngleNode *ANG = STE->GetValue()->GetValue<ASTAngleNode *>()) {
          FromValue = true;
          mpfr_init2(MPV, Bits);
          mpfr_set(MPV, ANG->GetMPValue(), MPFR_RNDN);
        }
      } break;
      case ASTTypeMPInteger: {
        if (ASTMPIntegerNode *MPI =
                STE->GetValue()->GetValue<ASTMPIntegerNode *>()) {
          FromValue = true;
          mpfr_init2(MPV, Bits);
          mpfr_set_z(MPV, MPI->GetMPValue(), MPFR_RNDN);
          ICX = new ASTImplicitConversionNode(MPI, ASTTypeAngle, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeMPDecimal: {
        if (ASTMPDecimalNode *MPD =
                STE->GetValue()->GetValue<ASTMPDecimalNode *>()) {
          FromValue = true;
          mpfr_init2(MPV, Bits);
          mpfr_set(MPV, MPD->GetMPValue(), MPFR_RNDN);
          ICX = new ASTImplicitConversionNode(MPD, ASTTypeAngle, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeMPComplex: {
        if (ASTMPComplexNode *MPC =
                STE->GetValue()->GetValue<ASTMPComplexNode *>()) {
          FromValue = true;
          mpfr_init2(MPV, Bits);
          mpfr_set(MPV, MPC->GetRealAsMPDecimal()->GetMPValue(), MPFR_RNDN);
          ICX = new ASTImplicitConversionNode(MPC, ASTTypeAngle, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeBitset: {
        if (ASTCBitNode *CBN = STE->GetValue()->GetValue<ASTCBitNode *>()) {
          FromValue = true;
          mpfr_init2(MPV, Bits);
          if (mpfr_set_str(MPV, CBN->AsString().c_str(), 2, MPFR_RNDN) != 0)
            mpfr_set_nan(MPV);
          ICX = new ASTImplicitConversionNode(CBN, ASTTypeAngle, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      default: {
        std::stringstream M;
        M << "Impossible assignment to an ASTTypeAngle from an "
          << PrintTypeEnum(Id->GetSymbolType()) << '.';
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(Id), M.str(),
            DiagLevel::ICE);
        return ASTDeclarationNode::DeclarationError(Id, M.str());
      } break;
      }
    } else {
      assert(AIdR && "Could not dynamic_cast to an ASTIdentifierNode!");

      AId = AIdR->GetIdentifier();
      assert(AId && "Could not obtain an unindexed ASTIdentifierNode!");

      ASTScopeController::Instance().CheckUndefined(AId);
      ASTScopeController::Instance().CheckOutOfScope(AId);

      if (AIdR->IsIndexed()) {
        ASTSymbolTableEntry *STE = ASTSymbolTable::Instance().Lookup(
            AIdR, AIdR->GetBits(), AIdR->GetReferenceType());
        assert(STE && "ASTIdentifierRefNode has no SymbolTable Entry!");

        switch (STE->GetValueType()) {
        case ASTTypeBool: {
          if (ASTBoolNode *BN = STE->GetValue()->GetValue<ASTBoolNode *>()) {
            FromValue = true;
            mpfr_init2(MPV, Bits);
            mpfr_set_ui(MPV, static_cast<unsigned>(BN->GetValue()), MPFR_RNDN);
            ICX = new ASTImplicitConversionNode(BN, ASTTypeAngle, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
        } break;
        case ASTTypeInt: {
          if (ASTIntNode *IN = STE->GetValue()->GetValue<ASTIntNode *>()) {
            FromValue = true;
            mpfr_init2(MPV, Bits);
            if (IN->IsSigned())
              mpfr_set_si(MPV, IN->GetSignedValue(), MPFR_RNDN);
            else
              mpfr_set_ui(MPV, IN->GetUnsignedValue(), MPFR_RNDN);
            ICX = new ASTImplicitConversionNode(IN, ASTTypeAngle, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
        } break;
        case ASTTypeFloat: {
          if (ASTFloatNode *FN = STE->GetValue()->GetValue<ASTFloatNode *>()) {
            mpfr_init2(MPV, Bits);
            FromValue = true;
            mpfr_set_flt(MPV, FN->GetValue(), MPFR_RNDN);
            ICX = new ASTImplicitConversionNode(FN, ASTTypeAngle, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
        } break;
        case ASTTypeDouble: {
          if (ASTDoubleNode *DN =
                  STE->GetValue()->GetValue<ASTDoubleNode *>()) {
            mpfr_init2(MPV, Bits);
            FromValue = true;
            mpfr_set_d(MPV, DN->GetValue(), MPFR_RNDN);
            ICX = new ASTImplicitConversionNode(DN, ASTTypeAngle, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
        } break;
        case ASTTypeLongDouble: {
          if (ASTLongDoubleNode *LN =
                  STE->GetValue()->GetValue<ASTLongDoubleNode *>()) {
            mpfr_init2(MPV, Bits);
            FromValue = true;
            mpfr_set_ld(MPV, LN->GetValue(), MPFR_RNDN);
            ICX = new ASTImplicitConversionNode(LN, ASTTypeAngle, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
        } break;
        case ASTTypeAngle: {
          if (ASTAngleNode *ANG = STE->GetValue()->GetValue<ASTAngleNode *>()) {
            FromValue = true;
            mpfr_init2(MPV, Bits);
            mpfr_set(MPV, ANG->GetMPValue(), MPFR_RNDN);
          }
        } break;
        case ASTTypeMPInteger: {
          if (ASTMPIntegerNode *MPI =
                  STE->GetValue()->GetValue<ASTMPIntegerNode *>()) {
            FromValue = true;
            mpfr_init2(MPV, Bits);
            mpfr_set_z(MPV, MPI->GetMPValue(), MPFR_RNDN);
            ICX = new ASTImplicitConversionNode(MPI, ASTTypeAngle, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
        } break;
        case ASTTypeMPDecimal: {
          if (ASTMPDecimalNode *MPD =
                  STE->GetValue()->GetValue<ASTMPDecimalNode *>()) {
            FromValue = true;
            mpfr_init2(MPV, Bits);
            mpfr_set(MPV, MPD->GetMPValue(), MPFR_RNDN);
            ICX = new ASTImplicitConversionNode(MPD, ASTTypeAngle, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
        } break;
        case ASTTypeMPComplex: {
          if (ASTMPComplexNode *MPC =
                  STE->GetValue()->GetValue<ASTMPComplexNode *>()) {
            FromValue = true;
            mpfr_init2(MPV, Bits);
            mpfr_set(MPV, MPC->GetRealAsMPDecimal()->GetMPValue(), MPFR_RNDN);
            ICX = new ASTImplicitConversionNode(MPC, ASTTypeAngle, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
        } break;
        case ASTTypeBitset: {
          if (ASTCBitNode *CBN = STE->GetValue()->GetValue<ASTCBitNode *>()) {
            FromValue = true;
            mpfr_init2(MPV, Bits);
            if (mpfr_set_str(MPV, CBN->AsString().c_str(), 2, MPFR_RNDN) != 0)
              mpfr_set_nan(MPV);
            ICX = new ASTImplicitConversionNode(CBN, ASTTypeAngle, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
        } break;
        default: {
          std::stringstream M;
          M << "Impossible assignment to an ASTTypeAngle from an "
            << PrintTypeEnum(Id->GetSymbolType()) << '.';
          QasmDiagnosticEmitter::Instance().EmitDiagnostic(
              DIAGLineCounter::Instance().GetLocation(Id), M.str(),
              DiagLevel::ICE);
          return ASTDeclarationNode::DeclarationError(Id, M.str());
        } break;
        }
      } else if (ASTTypeSystemBuilder::Instance().IsReservedAngle(
                     Id->GetName())) {
        AN = ASTAngleNodeBuilder::Instance().FindInMap(Id->GetName(),
                                                       ASTAngleNode::AngleBits);
        if (!AN) {
          std::stringstream M;
          M << "Reserved angle " << Id->GetName() << " not found in the "
            << "reserved angle table.";
          QasmDiagnosticEmitter::Instance().EmitDiagnostic(
              DIAGLineCounter::Instance().GetLocation(Id), M.str(),
              DiagLevel::ICE);
          return ASTDeclarationNode::DeclarationError(Id, M.str());
        }

        FromAngle = true;
      } else {
        std::stringstream M;
        M << "Impossible ASTAngleNode Initialization from an "
          << PrintTypeEnum(ETy) << ".";
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(EN), M.str(),
            DiagLevel::Error);
        return ASTDeclarationNode::DeclarationError(Id, M.str());
      }
    }
  } break;
  default: {
    std::stringstream M;
    M << "Impossible ASTAngleNode assignment from an " << PrintTypeEnum(ETy)
      << ".";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  } break;
  }

  ASTAngleType ATy = ASTAngleNode::DetermineAngleType(Id->GetName());
  ASTAngleNode *ANG = nullptr;

  if (FromArray) {
    ANG = ASTBuilder::Instance().CloneASTAngleNode(Id, AN, Bits);
  } else if (FromValue) {
    ANG = ASTBuilder::Instance().CreateASTAngleNode(Id, ATy, MPV, Bits);
    mpfr_clear(MPV);
  } else if (FromExpr) {
    ANG = ASTBuilder::Instance().CreateASTAngleNodeFromExpression(Id, EN, ATy,
                                                                  Bits);
  } else if (FromAngle) {
    ANG = ASTBuilder::Instance().CreateASTAngleNode(Id, ATy, Bits);
    assert(ANG && "Could not create an ASTAngleNode!");
    ANG->SetValue(AN->GetValue(10));
  } else {
    ANG = ASTBuilder::Instance().CreateASTAngleNode(Id, EN, ATy, Bits);
  }

  assert(ANG && "Could not create an ASTAngleNode!");

  if (FromValue) {
    ANG->SetConstantFolded(true);
    if (ICX)
      ANG->SetImplicitConversion(ICX);
  }

  ANG->SetLocation(TK->GetLocation());
  ANG->Mangle();

  ASTAngleNodeBuilder::Instance().Append(ANG);
  ASTAngleNodeBuilder::Instance().Insert(ANG);

  ASTDeclarationNode *DN = new ASTDeclarationNode(Id, ANG, ASTTypeAngle, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *ASTProductionFactory::ProductionRule_243(
    const ASTToken *TK, const ASTIdentifierNode *Id, const ASTIntNode *II,
    const ASTFunctionCallStatementNode *FC) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(II && "Invalid ASTIntNode argument!");
  assert(FC && "Invalid ASTFunctionCallStatementNode argument!");

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(II);
  assert(!ASTIdentifierNode::InvalidBits(Bits) &&
         "Invalid number of Bits for Angle Declaration!");

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(Id, Bits,
                                                          ASTTypeAngle)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeAngle.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
    std::stringstream M;
    M << "Declaration " << Id->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  const ASTFunctionCallNode *EN = FC->GetFunctionCall();
  assert(EN && "Could not obtain a valid ASTFunctionCallNode!");

  if (!EN->ReturnsResult()) {
    std::stringstream M;
    M << "Assignment requires a non-void return type.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  ASTAngleType ATy = ASTAngleNode::DetermineAngleType(Id->GetName());
  ASTAngleNode *ANG = ASTBuilder::Instance().CreateASTAngleNodeFromExpression(
      Id, EN, ATy, Bits);
  assert(ANG && "Could not create an ASTAngleNode!");

  ANG->SetLocation(TK->GetLocation());
  ANG->Mangle();

  ASTAngleNodeBuilder::Instance().Append(ANG);
  ASTAngleNodeBuilder::Instance().Insert(ANG);

  ASTDeclarationNode *DN = new ASTDeclarationNode(Id, ANG, ASTTypeAngle, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *ASTProductionFactory::ProductionRule_244(
    const ASTToken *TK, const ASTIdentifierNode *Id,
    const ASTIdentifierNode *IId, const ASTExpressionNode *EN) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(IId && "Invalid ASTIdentifierNode argument!");
  assert(EN && "Invalid ASTExpressionNode argument!");

  ASTScopeController::Instance().CheckUndefined(IId);
  ASTScopeController::Instance().CheckOutOfScope(IId);

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(IId);
  assert(!ASTIdentifierNode::InvalidBits(Bits) &&
         "Invalid number of Bits for Angle Declaration!");

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(Id, Bits,
                                                          ASTTypeAngle)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeInt.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
    std::stringstream M;
    M << "Declaration " << Id->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  ASTType ETy = EN->GetASTType();
  ASTAngleNode *AAN = nullptr;
  bool FromAngle = false;
  bool FromValue = false;
  bool FromExpr = false;
  const ASTImplicitConversionNode *ICX = nullptr;
  mpfr_t MPV;

  switch (ETy) {
  case ASTTypeBool:
    if (const ASTBoolNode *BN = dynamic_cast<const ASTBoolNode *>(EN)) {
      FromValue = true;
      mpfr_init2(MPV, Bits);
      mpfr_set_ui(MPV, static_cast<unsigned>(BN->GetValue()), MPFR_RNDN);
      ICX = new ASTImplicitConversionNode(BN, ASTTypeAngle, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeInt:
    if (const ASTIntNode *IN = dynamic_cast<const ASTIntNode *>(EN)) {
      FromValue = true;
      mpfr_init2(MPV, Bits);
      if (IN->IsSigned())
        mpfr_set_si(MPV, IN->GetSignedValue(), MPFR_RNDN);
      else
        mpfr_set_ui(MPV, IN->GetUnsignedValue(), MPFR_RNDN);
      ICX = new ASTImplicitConversionNode(IN, ASTTypeAngle, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeFloat:
    if (const ASTFloatNode *FN = dynamic_cast<const ASTFloatNode *>(EN)) {
      mpfr_init2(MPV, Bits);
      FromValue = true;
      mpfr_set_flt(MPV, FN->GetValue(), MPFR_RNDN);
      ICX = new ASTImplicitConversionNode(FN, ASTTypeAngle, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeDouble:
    if (const ASTDoubleNode *DN = dynamic_cast<const ASTDoubleNode *>(EN)) {
      mpfr_init2(MPV, Bits);
      FromValue = true;
      mpfr_set_d(MPV, DN->GetValue(), MPFR_RNDN);
      ICX = new ASTImplicitConversionNode(DN, ASTTypeAngle, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeLongDouble:
    if (const ASTLongDoubleNode *LN =
            dynamic_cast<const ASTLongDoubleNode *>(EN)) {
      mpfr_init2(MPV, Bits);
      FromValue = true;
      mpfr_set_ld(MPV, LN->GetValue(), MPFR_RNDN);
      ICX = new ASTImplicitConversionNode(LN, ASTTypeAngle, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeMPInteger:
    if (const ASTMPIntegerNode *MPII =
            dynamic_cast<const ASTMPIntegerNode *>(EN)) {
      FromValue = true;
      mpfr_init2(MPV, Bits);
      mpfr_set_z(MPV, MPII->GetMPValue(), MPFR_RNDN);
      ICX = new ASTImplicitConversionNode(MPII, ASTTypeAngle, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeMPDecimal:
    if (const ASTMPDecimalNode *MPDD =
            dynamic_cast<const ASTMPDecimalNode *>(EN)) {
      FromValue = true;
      mpfr_init2(MPV, Bits);
      mpfr_set(MPV, MPDD->GetMPValue(), MPFR_RNDN);
      ICX = new ASTImplicitConversionNode(MPDD, ASTTypeAngle, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeBitset:
    if (const ASTCBitNode *CB = dynamic_cast<const ASTCBitNode *>(EN)) {
      FromValue = true;
      mpfr_init2(MPV, Bits);
      if (mpfr_set_str(MPV, CB->AsString().c_str(), 2, MPFR_RNDN) != 0)
        mpfr_set_nan(MPV);
      ICX = new ASTImplicitConversionNode(CB, ASTTypeAngle, Bits);
      assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    }
    break;
  case ASTTypeAngle:
    if (const ASTAngleNode *ANG = dynamic_cast<const ASTAngleNode *>(EN)) {
      FromValue = true;
      mpfr_init2(MPV, Bits);
      mpfr_set(MPV, ANG->GetMPValue(), MPFR_RNDN);
    }
    break;
  case ASTTypeStringLiteral: {
    if (const ASTStringNode *SN = dynamic_cast<const ASTStringNode *>(EN)) {
      FromValue = true;
      mpfr_init2(MPV, Bits);
      std::string MPS = ASTStringUtils::Instance().Sanitize(SN->GetValue());
      if (MPS.find_first_of(u8'.') == std::string::npos)
        MPS += ".0";
      mpfr_set_str(MPV, MPS.c_str(), 10, MPFR_RNDN);
    }
  } break;
  case ASTTypeBinaryOp:
  case ASTTypeUnaryOp:
  case ASTTypeExpression:
    FromExpr = true;
    ICX = new ASTImplicitConversionNode(EN, ASTTypeAngle, Bits);
    assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    break;
  case ASTTypeCast:
    FromExpr = true;
    break;
  case ASTTypeImplicitConversion:
    FromExpr = true;
    ICX = new ASTImplicitConversionNode(EN, ASTTypeAngle, Bits);
    assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
    break;
  case ASTTypeCBitArray:
  case ASTTypeCBitNArray:
  case ASTTypeQubitArray:
  case ASTTypeQubitNArray:
  case ASTTypeAngleArray:
  case ASTTypeBoolArray:
  case ASTTypeMPIntegerArray:
  case ASTTypeMPDecimalArray:
  case ASTTypeLengthArray:
  case ASTTypeDurationArray:
  case ASTTypeFloatArray:
  case ASTTypeIntArray: {
    std::stringstream M;
    M << "An " << PrintTypeEnum(ETy) << " array cannot be assigned "
      << "to an angle.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  } break;
  case ASTTypeQubit: {
    std::stringstream M;
    M << "A Qubit cannot be assigned to an angle.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  } break;
  case ASTTypeIdentifier: {
    const ASTIdentifierNode *AId = EN->GetIdentifier();
    assert(AId && "Could not obtain a valid ASTIdentifierNode!");

    ASTScopeController::Instance().CheckUndefined(AId);
    ASTScopeController::Instance().CheckOutOfScope(AId);

    const ASTIdentifierRefNode *AIdR =
        dynamic_cast<const ASTIdentifierRefNode *>(AId);
    if (!AIdR) {
      const ASTSymbolTableEntry *STE = AId->GetSymbolTableEntry();
      assert(STE && "Could not obtain a valid ASTSymbolTableEntry!");
      assert(STE->GetValueType() == Id->GetSymbolType() &&
             "Type mismatch ASTIdentifierNode <-> ASTSymbolTableEntry!");

      switch (AId->GetSymbolType()) {
      case ASTTypeBool: {
        if (ASTBoolNode *BN = STE->GetValue()->GetValue<ASTBoolNode *>()) {
          FromValue = true;
          mpfr_init2(MPV, Bits);
          mpfr_set_ui(MPV, static_cast<unsigned>(BN->GetValue()), MPFR_RNDN);
          ICX = new ASTImplicitConversionNode(BN, ASTTypeAngle, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeInt: {
        if (ASTIntNode *IN = STE->GetValue()->GetValue<ASTIntNode *>()) {
          FromValue = true;
          mpfr_init2(MPV, Bits);
          if (IN->IsSigned())
            mpfr_set_si(MPV, IN->GetSignedValue(), MPFR_RNDN);
          else
            mpfr_set_ui(MPV, IN->GetUnsignedValue(), MPFR_RNDN);
          ICX = new ASTImplicitConversionNode(IN, ASTTypeAngle, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeFloat: {
        if (ASTFloatNode *FN = STE->GetValue()->GetValue<ASTFloatNode *>()) {
          mpfr_init2(MPV, Bits);
          FromValue = true;
          mpfr_set_flt(MPV, FN->GetValue(), MPFR_RNDN);
          ICX = new ASTImplicitConversionNode(FN, ASTTypeAngle, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeDouble: {
        if (ASTDoubleNode *DN = STE->GetValue()->GetValue<ASTDoubleNode *>()) {
          mpfr_init2(MPV, Bits);
          FromValue = true;
          mpfr_set_d(MPV, DN->GetValue(), MPFR_RNDN);
          ICX = new ASTImplicitConversionNode(DN, ASTTypeAngle, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeLongDouble: {
        if (ASTLongDoubleNode *LN =
                STE->GetValue()->GetValue<ASTLongDoubleNode *>()) {
          mpfr_init2(MPV, Bits);
          FromValue = true;
          mpfr_set_ld(MPV, LN->GetValue(), MPFR_RNDN);
          ICX = new ASTImplicitConversionNode(LN, ASTTypeAngle, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeAngle: {
        if (ASTAngleNode *ANG = STE->GetValue()->GetValue<ASTAngleNode *>()) {
          FromValue = true;
          mpfr_init2(MPV, Bits);
          mpfr_set(MPV, ANG->GetMPValue(), MPFR_RNDN);
        }
      } break;
      case ASTTypeMPInteger: {
        if (ASTMPIntegerNode *MPI =
                STE->GetValue()->GetValue<ASTMPIntegerNode *>()) {
          FromValue = true;
          mpfr_init2(MPV, Bits);
          mpfr_set_z(MPV, MPI->GetMPValue(), MPFR_RNDN);
          ICX = new ASTImplicitConversionNode(MPI, ASTTypeAngle, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeMPDecimal: {
        if (ASTMPDecimalNode *MPD =
                STE->GetValue()->GetValue<ASTMPDecimalNode *>()) {
          FromValue = true;
          mpfr_init2(MPV, Bits);
          mpfr_set(MPV, MPD->GetMPValue(), MPFR_RNDN);
          ICX = new ASTImplicitConversionNode(MPD, ASTTypeAngle, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeMPComplex: {
        if (ASTMPComplexNode *MPC =
                STE->GetValue()->GetValue<ASTMPComplexNode *>()) {
          FromValue = true;
          mpfr_init2(MPV, Bits);
          mpfr_set(MPV, MPC->GetRealAsMPDecimal()->GetMPValue(), MPFR_RNDN);
          ICX = new ASTImplicitConversionNode(MPC, ASTTypeAngle, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      case ASTTypeBitset: {
        if (ASTCBitNode *CBN = STE->GetValue()->GetValue<ASTCBitNode *>()) {
          FromValue = true;
          mpfr_init2(MPV, Bits);
          if (mpfr_set_str(MPV, CBN->AsString().c_str(), 2, MPFR_RNDN) != 0)
            mpfr_set_nan(MPV);
          ICX = new ASTImplicitConversionNode(CBN, ASTTypeAngle, Bits);
          assert(ICX && "Could not create a valid ASTImplicitConversionNode!");
        }
      } break;
      default: {
        std::stringstream M;
        M << "Impossible assignment to an ASTTypeAngle from an "
          << PrintTypeEnum(Id->GetSymbolType()) << '.';
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(Id), M.str(),
            DiagLevel::ICE);
        return ASTDeclarationNode::DeclarationError(Id, M.str());
      } break;
      }
    } else {
      assert(AIdR && "Could not dynamic_cast to an ASTIdentifierNode!");

      AId = AIdR->GetIdentifier();
      assert(AId && "Could not obtain an unindexed ASTIdentifierNode!");

      ASTScopeController::Instance().CheckUndefined(AId);
      ASTScopeController::Instance().CheckOutOfScope(AId);

      if (AIdR->IsIndexed()) {
        ASTSymbolTableEntry *STE = ASTSymbolTable::Instance().Lookup(
            AIdR, AIdR->GetBits(), AIdR->GetReferenceType());
        assert(STE && "ASTIdentifierRefNode has no SymbolTable Entry!");

        switch (STE->GetValueType()) {
        case ASTTypeBool: {
          if (ASTBoolNode *BN = STE->GetValue()->GetValue<ASTBoolNode *>()) {
            FromValue = true;
            mpfr_init2(MPV, Bits);
            mpfr_set_ui(MPV, static_cast<unsigned>(BN->GetValue()), MPFR_RNDN);
            ICX = new ASTImplicitConversionNode(BN, ASTTypeAngle, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
        } break;
        case ASTTypeInt: {
          if (ASTIntNode *IN = STE->GetValue()->GetValue<ASTIntNode *>()) {
            FromValue = true;
            mpfr_init2(MPV, Bits);
            if (IN->IsSigned())
              mpfr_set_si(MPV, IN->GetSignedValue(), MPFR_RNDN);
            else
              mpfr_set_ui(MPV, IN->GetUnsignedValue(), MPFR_RNDN);
            ICX = new ASTImplicitConversionNode(IN, ASTTypeAngle, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
        } break;
        case ASTTypeFloat: {
          if (ASTFloatNode *FN = STE->GetValue()->GetValue<ASTFloatNode *>()) {
            mpfr_init2(MPV, Bits);
            FromValue = true;
            mpfr_set_flt(MPV, FN->GetValue(), MPFR_RNDN);
            ICX = new ASTImplicitConversionNode(FN, ASTTypeAngle, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
        } break;
        case ASTTypeDouble: {
          if (ASTDoubleNode *DN =
                  STE->GetValue()->GetValue<ASTDoubleNode *>()) {
            mpfr_init2(MPV, Bits);
            FromValue = true;
            mpfr_set_d(MPV, DN->GetValue(), MPFR_RNDN);
            ICX = new ASTImplicitConversionNode(DN, ASTTypeAngle, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
        } break;
        case ASTTypeLongDouble: {
          if (ASTLongDoubleNode *LN =
                  STE->GetValue()->GetValue<ASTLongDoubleNode *>()) {
            mpfr_init2(MPV, Bits);
            FromValue = true;
            mpfr_set_ld(MPV, LN->GetValue(), MPFR_RNDN);
            ICX = new ASTImplicitConversionNode(LN, ASTTypeAngle, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
        } break;
        case ASTTypeAngle: {
          if (ASTAngleNode *AN = STE->GetValue()->GetValue<ASTAngleNode *>()) {
            FromValue = true;
            mpfr_init2(MPV, Bits);
            mpfr_set(MPV, AN->GetMPValue(), MPFR_RNDN);
          }
        } break;
        case ASTTypeMPInteger: {
          if (ASTMPIntegerNode *MPI =
                  STE->GetValue()->GetValue<ASTMPIntegerNode *>()) {
            FromValue = true;
            mpfr_init2(MPV, Bits);
            mpfr_set_z(MPV, MPI->GetMPValue(), MPFR_RNDN);
            ICX = new ASTImplicitConversionNode(MPI, ASTTypeAngle, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
        } break;
        case ASTTypeMPDecimal: {
          if (ASTMPDecimalNode *MPD =
                  STE->GetValue()->GetValue<ASTMPDecimalNode *>()) {
            FromValue = true;
            mpfr_init2(MPV, Bits);
            mpfr_set(MPV, MPD->GetMPValue(), MPFR_RNDN);
            ICX = new ASTImplicitConversionNode(MPD, ASTTypeAngle, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
        } break;
        case ASTTypeMPComplex: {
          if (ASTMPComplexNode *MPC =
                  STE->GetValue()->GetValue<ASTMPComplexNode *>()) {
            FromValue = true;
            mpfr_init2(MPV, Bits);
            mpfr_set(MPV, MPC->GetRealAsMPDecimal()->GetMPValue(), MPFR_RNDN);
            ICX = new ASTImplicitConversionNode(MPC, ASTTypeAngle, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
        } break;
        case ASTTypeBitset: {
          if (ASTCBitNode *CBN = STE->GetValue()->GetValue<ASTCBitNode *>()) {
            FromValue = true;
            mpfr_init2(MPV, Bits);
            if (mpfr_set_str(MPV, CBN->AsString().c_str(), 2, MPFR_RNDN) != 0)
              mpfr_set_nan(MPV);
            ICX = new ASTImplicitConversionNode(CBN, ASTTypeAngle, Bits);
            assert(ICX &&
                   "Could not create a valid ASTImplicitConversionNode!");
          }
        } break;
        default: {
          std::stringstream M;
          M << "Impossible assignment to an ASTTypeAngle from an "
            << PrintTypeEnum(Id->GetSymbolType()) << '.';
          QasmDiagnosticEmitter::Instance().EmitDiagnostic(
              DIAGLineCounter::Instance().GetLocation(Id), M.str(),
              DiagLevel::ICE);
          return ASTDeclarationNode::DeclarationError(Id, M.str());
        } break;
        }
      } else if (ASTTypeSystemBuilder::Instance().IsReservedAngle(
                     Id->GetName())) {
        AAN = ASTAngleNodeBuilder::Instance().FindInMap(
            Id->GetName(), ASTAngleNode::AngleBits);
        if (!AAN) {
          std::stringstream M;
          M << "Reserved angle " << Id->GetName() << " not found in the "
            << "reserved angle table.";
          QasmDiagnosticEmitter::Instance().EmitDiagnostic(
              DIAGLineCounter::Instance().GetLocation(Id), M.str(),
              DiagLevel::ICE);
          return ASTDeclarationNode::DeclarationError(Id, M.str());
        }
      } else {
        std::stringstream M;
        M << "Impossible ASTAngleNode Initialization from an "
          << PrintTypeEnum(ETy) << ".";
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(EN), M.str(),
            DiagLevel::Error);
        return ASTDeclarationNode::DeclarationError(Id, M.str());
      }
    }
  } break;
  default: {
    std::stringstream M;
    M << "Impossible ASTAngleNode assignment from an " << PrintTypeEnum(ETy)
      << ".";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  } break;
  }

  ASTAngleType ATy = ASTAngleNode::DetermineAngleType(Id->GetName());
  ASTAngleNode *AN = nullptr;

  if (FromValue) {
    AN = ASTBuilder::Instance().CreateASTAngleNode(Id, ATy, MPV, Bits);
    mpfr_clear(MPV);
    assert(AN && "Could not create an ASTAngleNode!");
  } else if (FromExpr) {
    AN = ASTBuilder::Instance().CreateASTAngleNode(Id, EN, ATy, Bits);
    assert(AN && "Could not create an ASTAngleNode!");
  } else if (FromAngle) {
    AN = ASTBuilder::Instance().CreateASTAngleNode(Id, ATy, Bits);
    assert(AN && "Could not create an ASTAngleNode!");
    AN->SetValue(AAN->GetValue(10));
  } else {
    AN = ASTBuilder::Instance().CreateASTAngleNode(Id, EN, ATy, Bits);
    assert(AN && "Could not create an ASTAngleNode!");
  }

  if (FromValue) {
    AN->SetConstantFolded(true);
    if (ICX)
      AN->SetImplicitConversion(ICX);
  }

  AN->SetLocation(TK->GetLocation());
  AN->Mangle();

  ASTAngleNodeBuilder::Instance().Append(AN);
  ASTAngleNodeBuilder::Instance().Insert(AN);

  ASTDeclarationNode *DN = new ASTDeclarationNode(Id, AN, ASTTypeAngle, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *ASTProductionFactory::ProductionRule_245(
    const ASTToken *TK, const ASTIdentifierNode *Id,
    const ASTIdentifierNode *IId,
    const ASTFunctionCallStatementNode *FC) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(IId && "Invalid ASTIdentifierNode argument!");
  assert(FC && "Invalid ASTFunctionCallStatementNode argument!");

  ASTScopeController::Instance().CheckUndefined(IId);
  ASTScopeController::Instance().CheckOutOfScope(IId);

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(IId);
  assert(!ASTIdentifierNode::InvalidBits(Bits) &&
         "Invalid number of Bits for Angle Declaration!");

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(Id, Bits,
                                                          ASTTypeAngle)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeInt.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
    std::stringstream M;
    M << "Declaration " << Id->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  const ASTFunctionCallNode *EN = FC->GetFunctionCall();
  assert(EN && "Could not obtain a valid ASTFunctionCallNode!");

  if (!EN->ReturnsResult()) {
    std::stringstream M;
    M << "Assignment requires a non-void return type.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  ASTAngleType ATy = ASTAngleNode::DetermineAngleType(Id->GetName());
  ASTAngleNode *AN =
      ASTBuilder::Instance().CreateASTAngleNode(Id, EN, ATy, Bits);
  assert(AN && "Could not create an ASTAngleNode!");

  AN->SetLocation(TK->GetLocation());
  AN->Mangle();

  ASTAngleNodeBuilder::Instance().Append(AN);
  ASTAngleNodeBuilder::Instance().Insert(AN);

  ASTDeclarationNode *DN = new ASTDeclarationNode(Id, AN, ASTTypeAngle, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTMPComplexNode *
ASTProductionFactory::ProductionRule_250(const ASTToken *TK,
                                         const ASTIdentifierNode *Id) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");

  const unsigned Bits = ASTMPComplexNode::DefaultBits;

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(Id, Bits,
                                                          ASTTypeMPComplex)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeMPComplex.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
    return ASTMPComplexNode::ExpressionError(Id, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
    std::stringstream M;
    M << "Declaration " << Id->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTMPComplexNode::ExpressionError(Id, M.str());
  }

  ASTMPComplexNode *MPC =
      ASTBuilder::Instance().CreateASTMPComplexNode(Id, Bits);
  assert(MPC && "Could not create a valid ASTMPComplexNode!");

  MPC->SetLocation(TK->GetLocation());
  MPC->Mangle();
  return MPC;
}

ASTMPComplexNode *
ASTProductionFactory::ProductionRule_251(const ASTToken *TK,
                                         const ASTIdentifierNode *Id,
                                         const ASTIntNode *SI) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(SI && "Invalid ASTIntNode argument!");

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(SI);
  if (ASTIdentifierNode::InvalidBits(Bits)) {
    std::stringstream M;
    M << "Invalid number of bits for complex expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTMPComplexNode::ExpressionError(Id, M.str());
  }

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(Id, Bits,
                                                          ASTTypeMPComplex)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeMPComplex.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
    return ASTMPComplexNode::ExpressionError(Id, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
    std::stringstream M;
    M << "Declaration " << Id->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTMPComplexNode::ExpressionError(Id, M.str());
  }

  ASTMPComplexNode *MPC =
      ASTBuilder::Instance().CreateASTMPComplexNode(Id, Bits);
  assert(MPC && "Could not create a valid ASTMPComplexNode!");

  MPC->SetLocation(TK->GetLocation());
  MPC->Mangle();
  return MPC;
}

ASTMPComplexNode *
ASTProductionFactory::ProductionRule_252(const ASTToken *TK,
                                         const ASTIdentifierNode *Id,
                                         const ASTIdentifierNode *SId) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(SId && "Invalid ASTIdentifierNode argument!");

  ASTScopeController::Instance().CheckOutOfScope(SId);

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(SId);
  if (ASTIdentifierNode::InvalidBits(Bits)) {
    std::stringstream M;
    M << "Invalid number of bits for complex expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTMPComplexNode::ExpressionError(Id, M.str());
  }

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(Id, Bits,
                                                          ASTTypeMPComplex)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeMPComplex.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
    return ASTMPComplexNode::ExpressionError(Id, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
    std::stringstream M;
    M << "Declaration " << Id->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTMPComplexNode::ExpressionError(Id, M.str());
  }

  ASTMPComplexNode *MPC =
      ASTBuilder::Instance().CreateASTMPComplexNode(Id, Bits);
  assert(MPC && "Could not create a valid ASTMPComplexNode!");

  MPC->SetLocation(TK->GetLocation());
  MPC->Mangle();
  return MPC;
}

ASTMPComplexNode *ASTProductionFactory::ProductionRule_253(
    const ASTToken *TK, const ASTIdentifierNode *Id, const ASTIntNode *SI,
    const ASTComplexExpressionNode *CEN) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(SI && "Invalid ASTIntNode argument!");
  assert(CEN && "Invalid ASTComplexExpressionNode argument!");

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(SI);
  if (ASTIdentifierNode::InvalidBits(Bits)) {
    std::stringstream M;
    M << "Invalid number of bits for complex expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(SI), M.str(), DiagLevel::Error);
    return ASTMPComplexNode::ExpressionError(Id, M.str());
  }

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(Id, Bits,
                                                          ASTTypeMPComplex)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeMPComplex.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
    return ASTMPComplexNode::ExpressionError(Id, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
    std::stringstream M;
    M << "Declaration " << Id->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTMPComplexNode::ExpressionError(Id, M.str());
  }

  ASTMPComplexNode *MPC =
      ASTBuilder::Instance().CreateASTMPComplexNode(Id, CEN, Bits);
  assert(MPC && "Could not create a valid ASTMPComplexNode!");

  MPC->SetLocation(TK->GetLocation());
  MPC->Mangle();
  return MPC;
}

ASTMPComplexNode *ASTProductionFactory::ProductionRule_254(
    const ASTToken *TK, const ASTIdentifierNode *Id, const ASTIntNode *SI,
    ASTBinaryOpNode *BOP) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(SI && "Invalid ASTIntNode argument!");
  assert(BOP && "Invalid ASTBinaryOpNode argument!");

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(SI);
  if (ASTIdentifierNode::InvalidBits(Bits)) {
    std::stringstream M;
    M << "Invalid number of bits for complex expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(SI), M.str(), DiagLevel::Error);
    return ASTMPComplexNode::ExpressionError(Id, M.str());
  }

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(Id, Bits,
                                                          ASTTypeMPComplex)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeMPComplex.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
    return ASTMPComplexNode::ExpressionError(Id, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
    std::stringstream M;
    M << "Declaration " << Id->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTMPComplexNode::ExpressionError(Id, M.str());
  }

  ASTComplexExpressionNode *CEN =
      new ASTComplexExpressionNode(&ASTIdentifierNode::MPComplex, BOP);
  assert(CEN && "Could not create a valid ASTComplexExpressionNode!");

  ASTMPComplexNode *MPC =
      ASTBuilder::Instance().CreateASTMPComplexNode(Id, CEN, Bits);
  assert(MPC && "Could not create a valid ASTMPComplexNode!");

  MPC->SetLocation(TK->GetLocation());
  MPC->Mangle();
  return MPC;
}

ASTMPComplexNode *ASTProductionFactory::ProductionRule_255(
    const ASTToken *TK, const ASTIdentifierNode *Id, const ASTIntNode *SI,
    ASTUnaryOpNode *UOP) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(SI && "Invalid ASTIntNode argument!");
  assert(UOP && "Invalid ASTUnaryOpNode argument!");

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(SI);
  if (ASTIdentifierNode::InvalidBits(Bits)) {
    std::stringstream M;
    M << "Invalid number of bits for complex expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(SI), M.str(), DiagLevel::Error);
    return ASTMPComplexNode::ExpressionError(Id, M.str());
  }

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(Id, Bits,
                                                          ASTTypeMPComplex)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeMPComplex.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
    return ASTMPComplexNode::ExpressionError(Id, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
    std::stringstream M;
    M << "Declaration " << Id->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTMPComplexNode::ExpressionError(Id, M.str());
  }

  ASTComplexExpressionNode *CEN =
      new ASTComplexExpressionNode(&ASTIdentifierNode::MPComplex, UOP);
  assert(CEN && "Could not create a valid ASTComplexExpressionNode!");

  ASTMPComplexNode *MPC =
      ASTBuilder::Instance().CreateASTMPComplexNode(Id, CEN, Bits);
  assert(MPC && "Could not create a valid ASTMPComplexNode!");

  MPC->SetLocation(TK->GetLocation());
  MPC->Mangle();
  return MPC;
}

ASTMPComplexNode *ASTProductionFactory::ProductionRule_256(
    const ASTToken *TK, const ASTIdentifierNode *Id,
    const ASTIdentifierNode *SId, const ASTComplexExpressionNode *CEN) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(SId && "Invalid ASTIdentifierNode argument!");
  assert(CEN && "Invalid ASTComplexExpressionNode argument!");

  ASTScopeController::Instance().CheckOutOfScope(SId);

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(SId);
  if (ASTIdentifierNode::InvalidBits(Bits)) {
    std::stringstream M;
    M << "Invalid number of bits for complex expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(SId), M.str(),
        DiagLevel::Error);
    return ASTMPComplexNode::ExpressionError(Id, M.str());
  }

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(Id, Bits,
                                                          ASTTypeMPComplex)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeMPComplex.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
    return ASTMPComplexNode::ExpressionError(Id, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
    std::stringstream M;
    M << "Declaration " << Id->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTMPComplexNode::ExpressionError(Id, M.str());
  }

  ASTMPComplexNode *MPC =
      ASTBuilder::Instance().CreateASTMPComplexNode(Id, CEN, Bits);
  assert(MPC && "Could not create a valid ASTMPComplexNode!");

  MPC->SetLocation(TK->GetLocation());
  MPC->Mangle();
  return MPC;
}

ASTMPComplexNode *ASTProductionFactory::ProductionRule_257(
    const ASTToken *TK, const ASTIdentifierNode *Id,
    const ASTIdentifierNode *SId, ASTBinaryOpNode *BOP) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(SId && "Invalid ASTIdentifierNode argument!");
  assert(BOP && "Invalid ASTBinaryOpNode argument!");

  ASTScopeController::Instance().CheckOutOfScope(SId);

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(SId);
  if (ASTIdentifierNode::InvalidBits(Bits)) {
    std::stringstream M;
    M << "Invalid number of bits for complex expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(SId), M.str(),
        DiagLevel::Error);
    return ASTMPComplexNode::ExpressionError(Id, M.str());
  }

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(Id, Bits,
                                                          ASTTypeMPComplex)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeMPComplex.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
    return ASTMPComplexNode::ExpressionError(Id, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
    std::stringstream M;
    M << "Declaration " << Id->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTMPComplexNode::ExpressionError(Id, M.str());
  }

  ASTComplexExpressionNode *CEN =
      new ASTComplexExpressionNode(&ASTIdentifierNode::MPComplex, BOP);
  assert(CEN && "Could not create a valid ASTComplexExpressionNode!");

  ASTMPComplexNode *MPC =
      ASTBuilder::Instance().CreateASTMPComplexNode(Id, CEN, Bits);
  assert(MPC && "Could not create a valid ASTMPComplexNode!");

  MPC->SetLocation(TK->GetLocation());
  MPC->Mangle();
  return MPC;
}

ASTMPComplexNode *ASTProductionFactory::ProductionRule_258(
    const ASTToken *TK, const ASTIdentifierNode *Id,
    const ASTIdentifierNode *SId, ASTUnaryOpNode *UOP) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(SId && "Invalid ASTIdentifierNode argument!");
  assert(UOP && "Invalid ASTUnaryOpNode argument!");

  ASTScopeController::Instance().CheckOutOfScope(SId);

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(SId);
  if (ASTIdentifierNode::InvalidBits(Bits)) {
    std::stringstream M;
    M << "Invalid number of bits for complex expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(SId), M.str(),
        DiagLevel::Error);
    return ASTMPComplexNode::ExpressionError(Id, M.str());
  }

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(Id, Bits,
                                                          ASTTypeMPComplex)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeMPComplex.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
    return ASTMPComplexNode::ExpressionError(Id, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
    std::stringstream M;
    M << "Declaration " << Id->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTMPComplexNode::ExpressionError(Id, M.str());
  }

  ASTComplexExpressionNode *CEN =
      new ASTComplexExpressionNode(&ASTIdentifierNode::MPComplex, UOP);
  assert(CEN && "Could not create a valid ASTComplexExpressionNode!");

  ASTMPComplexNode *MPC =
      ASTBuilder::Instance().CreateASTMPComplexNode(Id, CEN, Bits);
  assert(MPC && "Could not create a valid ASTMPComplexNode!");

  MPC->SetLocation(TK->GetLocation());
  MPC->Mangle();
  return MPC;
}

ASTMPComplexNode *ASTProductionFactory::ProductionRule_259(
    const ASTToken *TK, const ASTIdentifierNode *Id, const ASTIntNode *SI,
    const ASTIdentifierNode *RId) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(SI && "Invalid ASTIntNode argument!");
  assert(RId && "Invalid ASTIdentifierNode argument!");

  ASTScopeController::Instance().CheckOutOfScope(RId);

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(SI);
  if (ASTIdentifierNode::InvalidBits(Bits)) {
    std::stringstream M;
    M << "Invalid number of bits for complex expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(SI), M.str(), DiagLevel::Error);
    return ASTMPComplexNode::ExpressionError(Id, M.str());
  }

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(Id, Bits,
                                                          ASTTypeMPComplex)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeMPComplex.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
    return ASTMPComplexNode::ExpressionError(Id, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
    std::stringstream M;
    M << "Declaration " << Id->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTMPComplexNode::ExpressionError(Id, M.str());
  }

  const ASTSymbolTableEntry *STE = ASTSymbolTable::Instance().Lookup(RId);
  if (!STE) {
    std::stringstream M;
    M << "Identifier '" << RId->GetName() << "' does not have a SymbolTable "
      << "Entry.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTMPComplexNode::ExpressionError(Id, M.str());
  }

  ASTMPComplexNode *MPC = nullptr;
  ASTMPComplexNode *MPCC = nullptr;
  ASTMPDecimalNode *MPD = nullptr;

  if (STE->GetValueType() == ASTTypeMPComplex) {
    MPCC = STE->GetValue()->GetValue<ASTMPComplexNode *>();
    if (!MPCC) {
      std::stringstream M;
      M << "Identifier '" << RId->GetName() << "' does not represent a valid "
        << PrintTypeEnum(STE->GetValueType()) << '.';
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(Id), M.str(),
          DiagLevel::Error);
      return ASTMPComplexNode::ExpressionError(Id, M.str());
    }

    MPCC = STE->GetValue()->GetValue<ASTMPComplexNode *>();
    assert(MPCC && "Could not obtain a valid ASTMPComplexNode!");
  } else {
    switch (STE->GetValueType()) {
    case ASTTypeMPDecimal:
      MPD = STE->GetValue()->GetValue<ASTMPDecimalNode *>();
      if (!MPD) {
        std::stringstream M;
        M << "Identifier '" << RId->GetName() << "' does not represent a valid "
          << PrintTypeEnum(STE->GetValueType()) << '.';
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(Id), M.str(),
            DiagLevel::Error);
        return ASTMPComplexNode::ExpressionError(Id, M.str());
      }
      break;
    case ASTTypeMPInteger:
    case ASTTypeMPUInteger: {
      ASTMPIntegerNode *MPI = STE->GetValue()->GetValue<ASTMPIntegerNode *>();
      if (!MPD) {
        std::stringstream M;
        M << "Identifier '" << RId->GetName() << "' does not represent a valid "
          << PrintTypeEnum(STE->GetValueType()) << '.';
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(Id), M.str(),
            DiagLevel::Error);
        return ASTMPComplexNode::ExpressionError(Id, M.str());
      }

      MPD = MPI->AsMPDecimal();
      if (!MPD) {
        std::stringstream M;
        M << "Identifier '" << RId->GetName() << "' does not represent a valid "
          << PrintTypeEnum(STE->GetValueType()) << '.';
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(Id), M.str(),
            DiagLevel::Error);
        return ASTMPComplexNode::ExpressionError(Id, M.str());
      }
    } break;
    case ASTTypeFloat: {
      ASTFloatNode *F = STE->GetValue()->GetValue<ASTFloatNode *>();
      if (!F) {
        std::stringstream M;
        M << "Identifier '" << RId->GetName() << "' does not represent a valid "
          << PrintTypeEnum(STE->GetValueType()) << '.';
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(Id), M.str(),
            DiagLevel::Error);
        return ASTMPComplexNode::ExpressionError(Id, M.str());
      }

      MPD = new ASTMPDecimalNode(ASTIdentifierNode::MPDec.Clone(),
                                 ASTMPDecimalNode::DefaultBits, F->GetValue());
      if (!MPD) {
        std::stringstream M;
        M << "Identifier '" << RId->GetName() << "' does not represent a valid "
          << PrintTypeEnum(STE->GetValueType()) << '.';
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(Id), M.str(),
            DiagLevel::Error);
        return ASTMPComplexNode::ExpressionError(Id, M.str());
      }
    } break;
    case ASTTypeDouble: {
      ASTDoubleNode *D = STE->GetValue()->GetValue<ASTDoubleNode *>();
      if (!D) {
        std::stringstream M;
        M << "Identifier '" << RId->GetName() << "' does not represent a valid "
          << PrintTypeEnum(STE->GetValueType()) << '.';
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(Id), M.str(),
            DiagLevel::Error);
        return ASTMPComplexNode::ExpressionError(Id, M.str());
      }

      MPD = new ASTMPDecimalNode(ASTIdentifierNode::MPDec.Clone(),
                                 ASTMPDecimalNode::DefaultBits, D->GetValue());
      if (!MPD) {
        std::stringstream M;
        M << "Identifier '" << RId->GetName() << "' does not represent a valid "
          << PrintTypeEnum(STE->GetValueType()) << '.';
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(Id), M.str(),
            DiagLevel::Error);
        return ASTMPComplexNode::ExpressionError(Id, M.str());
      }
    } break;
    case ASTTypeInt: {
      ASTIntNode *I = STE->GetValue()->GetValue<ASTIntNode *>();
      if (!I) {
        std::stringstream M;
        M << "Identifier '" << RId->GetName() << "' does not represent a valid "
          << PrintTypeEnum(STE->GetValueType()) << '.';
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(Id), M.str(),
            DiagLevel::Error);
        return ASTMPComplexNode::ExpressionError(Id, M.str());
      }

      MPD = new ASTMPDecimalNode(ASTIdentifierNode::MPDec.Clone(),
                                 ASTMPDecimalNode::DefaultBits,
                                 I->IsSigned() ? double(I->GetSignedValue())
                                               : double(I->GetUnsignedValue()));
      if (!MPD) {
        std::stringstream M;
        M << "Identifier '" << RId->GetName() << "' does not represent a valid "
          << PrintTypeEnum(STE->GetValueType()) << '.';
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(Id), M.str(),
            DiagLevel::Error);
        return ASTMPComplexNode::ExpressionError(Id, M.str());
      }
    } break;
    default: {
      std::stringstream M;
      M << "Impossible assignment to an " << PrintTypeEnum(ASTTypeMPComplex)
        << " from an " << PrintTypeEnum(STE->GetValueType()) << '.';
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(Id), M.str(),
          DiagLevel::Error);
      return ASTMPComplexNode::ExpressionError(Id, M.str());
    } break;
    }
  }

  if (MPCC)
    MPC = ASTBuilder::Instance().CreateASTMPComplexNode(Id, MPCC, Bits);
  else {
    ASTMPDecimalNode *MPCI =
        new ASTMPDecimalNode(ASTIdentifierNode::MPDec.Clone(),
                             ASTMPDecimalNode::DefaultBits, double(1.0));
    assert(MPCI && "Could not create a valid ASTMPDecimalNode!");
    MPC = ASTBuilder::Instance().CreateASTMPComplexNode(Id, MPD, MPCI,
                                                        ASTOpTypeMul);
  }

  assert(MPC && "Could not create a valid ASTMPComplexNode!");

  MPC->SetLocation(TK->GetLocation());
  MPC->Mangle();
  return MPC;
}

ASTMPComplexNode *ASTProductionFactory::ProductionRule_260(
    const ASTToken *TK, const ASTIdentifierNode *Id,
    const ASTIdentifierNode *SId, const ASTIdentifierNode *RId) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(SId && "Invalid ASTIdentifierNode argument!");
  assert(RId && "Invalid ASTIdentifierNode argument!");

  ASTScopeController::Instance().CheckOutOfScope(RId);
  ASTScopeController::Instance().CheckOutOfScope(SId);

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(SId);
  if (ASTIdentifierNode::InvalidBits(Bits)) {
    std::stringstream M;
    M << "Invalid number of bits for complex expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(SId), M.str(),
        DiagLevel::Error);
    return ASTMPComplexNode::ExpressionError(Id, M.str());
  }

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(Id, Bits,
                                                          ASTTypeMPComplex)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeMPComplex.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
    return ASTMPComplexNode::ExpressionError(Id, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
    std::stringstream M;
    M << "Declaration " << Id->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTMPComplexNode::ExpressionError(Id, M.str());
  }

  const ASTSymbolTableEntry *STE = ASTSymbolTable::Instance().Lookup(RId);
  if (!STE) {
    std::stringstream M;
    M << "Identifier '" << RId->GetName() << "' does not have a SymbolTable "
      << "Entry.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTMPComplexNode::ExpressionError(Id, M.str());
  }

  ASTMPComplexNode *MPC = nullptr;
  ASTMPComplexNode *MPCC = nullptr;
  ASTMPDecimalNode *MPD = nullptr;

  if (STE->GetValueType() == ASTTypeMPComplex) {
    MPCC = STE->GetValue()->GetValue<ASTMPComplexNode *>();
    if (!MPCC) {
      std::stringstream M;
      M << "Identifier '" << RId->GetName() << "' does not represent a valid "
        << PrintTypeEnum(STE->GetValueType()) << '.';
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(Id), M.str(),
          DiagLevel::Error);
      return ASTMPComplexNode::ExpressionError(Id, M.str());
    }

    MPCC = STE->GetValue()->GetValue<ASTMPComplexNode *>();
    assert(MPCC && "Could not obtain a valid ASTMPComplexNode!");
  } else {
    switch (STE->GetValueType()) {
    case ASTTypeMPDecimal:
      MPD = STE->GetValue()->GetValue<ASTMPDecimalNode *>();
      if (!MPD) {
        std::stringstream M;
        M << "Identifier '" << RId->GetName() << "' does not represent a valid "
          << PrintTypeEnum(STE->GetValueType()) << '.';
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(Id), M.str(),
            DiagLevel::Error);
        return ASTMPComplexNode::ExpressionError(Id, M.str());
      }
      break;
    case ASTTypeMPInteger:
    case ASTTypeMPUInteger: {
      ASTMPIntegerNode *MPI = STE->GetValue()->GetValue<ASTMPIntegerNode *>();
      if (!MPD) {
        std::stringstream M;
        M << "Identifier '" << RId->GetName() << "' does not represent a valid "
          << PrintTypeEnum(STE->GetValueType()) << '.';
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(Id), M.str(),
            DiagLevel::Error);
        return ASTMPComplexNode::ExpressionError(Id, M.str());
      }

      MPD = MPI->AsMPDecimal();
      if (!MPD) {
        std::stringstream M;
        M << "Identifier '" << RId->GetName() << "' does not represent a valid "
          << PrintTypeEnum(STE->GetValueType()) << '.';
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(Id), M.str(),
            DiagLevel::Error);
        return ASTMPComplexNode::ExpressionError(Id, M.str());
      }
    } break;
    case ASTTypeFloat: {
      ASTFloatNode *F = STE->GetValue()->GetValue<ASTFloatNode *>();
      if (!F) {
        std::stringstream M;
        M << "Identifier '" << RId->GetName() << "' does not represent a valid "
          << PrintTypeEnum(STE->GetValueType()) << '.';
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(Id), M.str(),
            DiagLevel::Error);
        return ASTMPComplexNode::ExpressionError(Id, M.str());
      }

      MPD = new ASTMPDecimalNode(ASTIdentifierNode::MPDec.Clone(),
                                 ASTMPDecimalNode::DefaultBits, F->GetValue());
      if (!MPD) {
        std::stringstream M;
        M << "Identifier '" << RId->GetName() << "' does not represent a valid "
          << PrintTypeEnum(STE->GetValueType()) << '.';
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(Id), M.str(),
            DiagLevel::Error);
        return ASTMPComplexNode::ExpressionError(Id, M.str());
      }
    } break;
    case ASTTypeDouble: {
      ASTDoubleNode *D = STE->GetValue()->GetValue<ASTDoubleNode *>();
      if (!D) {
        std::stringstream M;
        M << "Identifier '" << RId->GetName() << "' does not represent a valid "
          << PrintTypeEnum(STE->GetValueType()) << '.';
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(Id), M.str(),
            DiagLevel::Error);
        return ASTMPComplexNode::ExpressionError(Id, M.str());
      }

      MPD = new ASTMPDecimalNode(ASTIdentifierNode::MPDec.Clone(),
                                 ASTMPDecimalNode::DefaultBits, D->GetValue());
      if (!MPD) {
        std::stringstream M;
        M << "Identifier '" << RId->GetName() << "' does not represent a valid "
          << PrintTypeEnum(STE->GetValueType()) << '.';
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(Id), M.str(),
            DiagLevel::Error);
        return ASTMPComplexNode::ExpressionError(Id, M.str());
      }
    } break;
    case ASTTypeInt: {
      ASTIntNode *I = STE->GetValue()->GetValue<ASTIntNode *>();
      if (!I) {
        std::stringstream M;
        M << "Identifier '" << RId->GetName() << "' does not represent a valid "
          << PrintTypeEnum(STE->GetValueType()) << '.';
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(Id), M.str(),
            DiagLevel::Error);
        return ASTMPComplexNode::ExpressionError(Id, M.str());
      }

      MPD = new ASTMPDecimalNode(ASTIdentifierNode::MPDec.Clone(),
                                 ASTMPDecimalNode::DefaultBits,
                                 I->IsSigned() ? double(I->GetSignedValue())
                                               : double(I->GetUnsignedValue()));
      if (!MPD) {
        std::stringstream M;
        M << "Identifier '" << RId->GetName() << "' does not represent a valid "
          << PrintTypeEnum(STE->GetValueType()) << '.';
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(Id), M.str(),
            DiagLevel::Error);
        return ASTMPComplexNode::ExpressionError(Id, M.str());
      }
    } break;
    default: {
      std::stringstream M;
      M << "Impossible assignment to an " << PrintTypeEnum(ASTTypeMPComplex)
        << " from an " << PrintTypeEnum(STE->GetValueType()) << '.';
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(Id), M.str(),
          DiagLevel::Error);
      return ASTMPComplexNode::ExpressionError(Id, M.str());
    } break;
    }
  }

  if (MPCC)
    MPC = ASTBuilder::Instance().CreateASTMPComplexNode(Id, MPCC, Bits);
  else {
    ASTMPDecimalNode *MPCI =
        new ASTMPDecimalNode(ASTIdentifierNode::MPDec.Clone(),
                             ASTMPDecimalNode::DefaultBits, double(1.0));
    assert(MPCI && "Could not create a valid ASTMPDecimalNode!");
    MPC = ASTBuilder::Instance().CreateASTMPComplexNode(Id, MPD, MPCI,
                                                        ASTOpTypeMul);
  }

  assert(MPC && "Could not create a valid ASTMPComplexNode!");

  MPC->SetLocation(TK->GetLocation());
  MPC->Mangle();
  return MPC;
}

ASTMPComplexNode *ASTProductionFactory::ProductionRule_261(
    const ASTToken *TK, const ASTIdentifierNode *Id, const ASTIntNode *SI,
    const ASTFunctionCallStatementNode *FCS) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(SI && "Invalid ASTIntNode argument!");
  assert(FCS && "Invalid ASTFunctionCallStatementNode argument!");

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(SI);
  if (ASTIdentifierNode::InvalidBits(Bits)) {
    std::stringstream M;
    M << "Invalid number of bits for complex expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(SI), M.str(), DiagLevel::Error);
    return ASTMPComplexNode::ExpressionError(Id, M.str());
  }

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(Id, Bits,
                                                          ASTTypeMPComplex)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeMPComplex.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
    return ASTMPComplexNode::ExpressionError(Id, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
    std::stringstream M;
    M << "Declaration " << Id->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTMPComplexNode::ExpressionError(Id, M.str());
  }

  const ASTFunctionCallNode *FC = FCS->GetFunctionCall();
  assert(FC && "Could not obtain a valid ASTFunctionCallNode!");

  ASTType FTy = FC->GetResultType();
  if (!ASTExpressionValidator::Instance().IsAssignableToComplexType(FTy)) {
    std::stringstream M;
    M << "Function Call return type " << PrintTypeEnum(FC->GetResultType())
      << " cannot be used to instantiate an " << PrintTypeEnum(ASTTypeMPComplex)
      << '.';
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(FC), M.str(), DiagLevel::Error);
    return ASTMPComplexNode::ExpressionError(Id, M.str());
  }

  ASTMPComplexNode *MPC =
      ASTBuilder::Instance().CreateASTMPComplexNode(Id, FC, Bits);
  assert(MPC && "Could not create a valid ASTMPComplexNode!");

  MPC->SetLocation(TK->GetLocation());
  MPC->Mangle();
  return MPC;
}

ASTMPComplexNode *ASTProductionFactory::ProductionRule_262(
    const ASTToken *TK, const ASTIdentifierNode *Id,
    const ASTIdentifierNode *SId,
    const ASTFunctionCallStatementNode *FCS) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(SId && "Invalid ASTIdentifierNode argument!");
  assert(FCS && "Invalid ASTFunctionCallStatementNode argument!");

  ASTScopeController::Instance().CheckOutOfScope(SId);

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(SId);
  if (ASTIdentifierNode::InvalidBits(Bits)) {
    std::stringstream M;
    M << "Invalid number of bits for complex expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(SId), M.str(),
        DiagLevel::Error);
    return ASTMPComplexNode::ExpressionError(Id, M.str());
  }

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(Id, Bits,
                                                          ASTTypeMPComplex)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeMPComplex.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
    return ASTMPComplexNode::ExpressionError(Id, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
    std::stringstream M;
    M << "Declaration " << Id->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTMPComplexNode::ExpressionError(Id, M.str());
  }

  const ASTFunctionCallNode *FC = FCS->GetFunctionCall();
  assert(FC && "Could not obtain a valid ASTFunctionCallNode!");

  ASTType FTy = FC->GetResultType();
  if (!ASTExpressionValidator::Instance().IsAssignableToComplexType(FTy)) {
    std::stringstream M;
    M << "Function Call return type " << PrintTypeEnum(FC->GetResultType())
      << " cannot be used to instantiate an " << PrintTypeEnum(ASTTypeMPComplex)
      << '.';
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(FC), M.str(), DiagLevel::Error);
    return ASTMPComplexNode::ExpressionError(Id, M.str());
  }

  ASTMPComplexNode *MPC =
      ASTBuilder::Instance().CreateASTMPComplexNode(Id, FC, Bits);
  assert(MPC && "Could not create a valid ASTMPComplexNode!");

  MPC->SetLocation(TK->GetLocation());
  MPC->Mangle();
  return MPC;
}

static ASTRotateNode *CreateASTRotateNode(const ASTToken *TK,
                                          const ASTIdentifierNode *RId,
                                          const ASTIntNode *LI,
                                          const ASTIntNode *RI,
                                          ASTRotationType RoTy) {
  assert(RId && "Invalid ASTIdentifierNode argument!");
  assert(LI && "Invalid ASTIntNode argument!");
  assert(RI && "Invalid ASTIntNode argument!");

  const ASTMPIntegerNode *LMPI = nullptr;
  ASTRotateNode *RN = nullptr;

  if (LI->IsMPInteger()) {
    LMPI = LI->GetMPInteger();
    assert(LMPI &&
           "Could not obtain a valid ASTMPIntegerNode from the ASTIntNode!");
    if (!LMPI) {
      std::stringstream M;
      M << "Could not obtain a valid ASTMPIntegerNode from the ASTIntNode.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(TK), M.str(),
          DiagLevel::Error);
      return ASTRotateNode::ExpressionError(M.str(), RoTy);
    }

    RN = ASTBuilder::Instance().CreateASTRotateNode(RId, LMPI, RI, RoTy);
    assert(RN && "Could not create a valid ASTRotateNode!");
    RId->SetBits(LMPI->GetBits());
  } else {
    RN = ASTBuilder::Instance().CreateASTRotateNode(RId, LI, RI, RoTy);
    assert(RN && "Could not create a valid ASTRotateNode!");
    RId->SetBits(LI->GetBits());
  }

  if (!RN) {
    std::stringstream M;
    M << "Could not create a valid ASTRotateNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTRotateNode::ExpressionError(M.str(), RoTy);
  }

  RN->SetLocation(TK->GetLocation());
  RN->Mangle();
  return RN;
}

static ASTRotateNode *CreateASTRotateNode(const ASTToken *TK,
                                          const ASTIdentifierNode *RId,
                                          const ASTIdentifierNode *LId,
                                          const ASTIntNode *RI,
                                          ASTRotationType RoTy) {
  assert(RId && "Invalid ASTIdentifierNode argument!");
  assert(LId && "Invalid ASTIdentifierNode argument!");
  assert(RI && "Invalid ASTIntNode argument!");

  if (RI->IsMPInteger()) {
    std::stringstream M;
    M << "Using a multiple-precision integer for second rotation "
      << "operand is not allowed.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTRotateNode::ExpressionError(M.str(), RoTy);
  }

  ASTSymbolTableEntry *STE = ASTSymbolTable::Instance().Lookup(
      LId, LId->GetBits(), LId->GetSymbolType());
  assert(STE && "Left operand Identifier has no SymbolTable Entry!");
  if (!STE) {
    std::stringstream M;
    M << "Left operand Identifier has no SymbolTable Entry.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTRotateNode::ExpressionError(M.str(), RoTy);
  }

  ASTRotateNode *RN = nullptr;

  switch (LId->GetSymbolType()) {
  case ASTTypeInt:
  case ASTTypeUInt: {
    ASTIntNode *LI = STE->GetValue()->GetValue<ASTIntNode *>();
    assert(LI && "Could not obtain a valid ASTIntNode from the SymbolTable!");
    if (!LI) {
      std::stringstream M;
      M << "Could not obtain a valid ASTIntNode from the SymbolTable.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(TK), M.str(),
          DiagLevel::Error);
      return ASTRotateNode::ExpressionError(M.str(), RoTy);
    }

    if (LI->IsMPInteger()) {
      const ASTMPIntegerNode *MPI = LI->GetMPInteger();
      assert(MPI &&
             "Could not obtain a valid ASTMPIntegerNode from the ASTIntNode!");
      if (!MPI) {
        std::stringstream M;
        M << "Could not obtain a valid ASTMPIntegerNode from the ASTIntNode.";
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(TK), M.str(),
            DiagLevel::Error);
        return ASTRotateNode::ExpressionError(M.str(), RoTy);
      }

      RId->SetBits(MPI->GetBits());
      RN = ASTBuilder::Instance().CreateASTRotateNode(RId, MPI, RI, RoTy);
      assert(RN && "Could not create a valid ASTRotateNode!");
    } else {
      RId->SetBits(LI->GetBits());
      RN = ASTBuilder::Instance().CreateASTRotateNode(RId, LI, RI, RoTy);
      assert(RN && "Could not create a valid ASTRotateNode!");
    }
  } break;
  case ASTTypeMPInteger:
  case ASTTypeMPUInteger: {
    ASTMPIntegerNode *MPI = STE->GetValue()->GetValue<ASTMPIntegerNode *>();
    assert(MPI &&
           "Could not obtain a valid ASTMPIntegerNode from the SymbolTable!");
    if (!MPI) {
      std::stringstream M;
      M << "Could not obtain a valid ASTMPIntegerNode from the SymbolTable.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(TK), M.str(),
          DiagLevel::Error);
      return ASTRotateNode::ExpressionError(M.str(), RoTy);
    }

    RId->SetBits(MPI->GetBits());
    RN = ASTBuilder::Instance().CreateASTRotateNode(RId, MPI, RI, RoTy);
    assert(RN && "Could not create a valid ASTRotateNode!");
  } break;
  case ASTTypeBitset: {
    ASTCBitNode *CBN = STE->GetValue()->GetValue<ASTCBitNode *>();
    assert(CBN && "Could not obtain a valid ASTCBitNode from the SymbolTable!");
    if (!CBN) {
      std::stringstream M;
      M << "Could not obtain a valid ASTCBitNode from the SymbolTable.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(TK), M.str(),
          DiagLevel::Error);
      return ASTRotateNode::ExpressionError(M.str(), RoTy);
    }

    RId->SetBits(CBN->GetBits());
    RN = ASTBuilder::Instance().CreateASTRotateNode(RId, CBN, RI, RoTy);
    assert(RN && "Could not create a valid ASTRotateNode!");
  } break;
  default: {
    std::stringstream M;
    M << "Only integer or bitset types can be rotation targets.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTRotateNode::ExpressionError(M.str(), RoTy);
  } break;
  }

  if (!RN) {
    std::stringstream M;
    M << "Could not create a valid ASTRotateNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTRotateNode::ExpressionError(M.str(), RoTy);
  }

  RN->SetLocation(TK->GetLocation());
  RN->Mangle();
  return RN;
}

static ASTRotateNode *CreateASTRotateNode(const ASTToken *TK,
                                          const ASTIdentifierNode *Id,
                                          const ASTIntNode *LI,
                                          const ASTIdentifierNode *RId,
                                          ASTRotationType RoTy) {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(LI && "Invalid ASTIntNode argument!");
  assert(RId && "Invalid ASTIdentifierNode argument!");

  if (RId->GetSymbolType() != ASTTypeInt &&
      RId->GetSymbolType() != ASTTypeUInt) {
    std::stringstream M;
    M << "Second operand of a rotation can only be a 32-bit signed integer.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTRotateNode::ExpressionError(M.str(), RoTy);
  }

  ASTSymbolTableEntry *RSTE = ASTSymbolTable::Instance().Lookup(
      RId, RId->GetBits(), RId->GetSymbolType());
  assert(RSTE && "Could not obtain a valid second operand SymbolTable Entry!");
  if (!RSTE) {
    std::stringstream M;
    M << "Could not obtain a valid second operand SymbolTable Entry.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTRotateNode::ExpressionError(M.str(), RoTy);
  }

  ASTIntNode *RI = RSTE->GetValue()->GetValue<ASTIntNode *>();
  assert(RI && "Could not obtain a valid second operand ASTIntNode!");
  if (!RI) {
    std::stringstream M;
    M << "Could not obtain a valid second operand ASTIntNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTRotateNode::ExpressionError(M.str(), RoTy);
  }

  Id->SetBits(LI->GetBits());
  return CreateASTRotateNode(TK, Id, LI, RI, RoTy);
}

static ASTRotateNode *CreateASTRotateNode(const ASTToken *TK,
                                          const ASTIdentifierNode *Id,
                                          const ASTIdentifierNode *LId,
                                          const ASTIdentifierNode *RId,
                                          ASTRotationType RoTy) {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(LId && "Invalid ASTIdentifierNode argument!");
  assert(RId && "Invalid ASTIdentifierNode argument!");

  if (RId->GetSymbolType() != ASTTypeInt &&
      RId->GetSymbolType() != ASTTypeUInt) {
    std::stringstream M;
    M << "Second operand of a rotation can only be a 32-bit signed integer.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTRotateNode::ExpressionError(M.str(), RoTy);
  }

  ASTSymbolTableEntry *RSTE = ASTSymbolTable::Instance().Lookup(
      RId, RId->GetBits(), RId->GetSymbolType());
  assert(RSTE && "Could not obtain a valid second operand SymbolTable Entry!");
  if (!RSTE) {
    std::stringstream M;
    M << "Could not obtain a valid second operand SymbolTable Entry.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTRotateNode::ExpressionError(M.str(), RoTy);
  }

  ASTIntNode *RI = RSTE->GetValue()->GetValue<ASTIntNode *>();
  assert(RI && "Could not obtain a valid second operand ASTIntNode!");
  if (!RI) {
    std::stringstream M;
    M << "Could not obtain a valid second operand ASTIntNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTRotateNode::ExpressionError(M.str(), RoTy);
  }

  if (RI->IsMPInteger()) {
    std::stringstream M;
    M << "Using a multiple-precision integer for second rotation "
      << "operand is not allowed.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTRotateNode::ExpressionError(M.str(), RoTy);
  }

  return CreateASTRotateNode(TK, Id, LId, RI, RoTy);
}

static ASTRotateNode *CreateASTRotateNode(const ASTToken *TK,
                                          const ASTIdentifierNode *Id,
                                          const ASTCBitNode *LCB,
                                          const ASTIntNode *RI,
                                          ASTRotationType RoTy) {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(LCB && "Invalid ASTCBitNode argument!");
  assert(RI && "Invalid ASTIntNode argument!");

  if (RI->IsMPInteger()) {
    std::stringstream M;
    M << "Using a multiple-precision integer for second rotation "
      << "operand is not allowed.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTRotateNode::ExpressionError(M.str(), RoTy);
  }

  Id->SetBits(LCB->GetBits());
  ASTRotateNode *RN =
      ASTBuilder::Instance().CreateASTRotateNode(Id, LCB, RI, RoTy);
  assert(RN && "Could not create a valid ASTRotateNode!");
  if (!RN) {
    std::stringstream M;
    M << "Could not create a valid ASTRotateNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTRotateNode::ExpressionError(M.str(), RoTy);
  }

  RN->SetLocation(TK->GetLocation());
  RN->Mangle();
  return RN;
}

static ASTRotateNode *CreateASTRotateNode(const ASTToken *TK,
                                          const ASTIdentifierNode *Id,
                                          const ASTCBitNode *LCB,
                                          const ASTIdentifierNode *RId,
                                          ASTRotationType RoTy) {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(LCB && "Invalid ASTCBitNode argument!");
  assert(RId && "Invalid ASTIdentifierNode argument!");

  if (RId->GetSymbolType() != ASTTypeInt &&
      RId->GetSymbolType() != ASTTypeUInt) {
    std::stringstream M;
    M << "Second operand of a rotation can only be a 32-bit signed integer.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTRotateNode::ExpressionError(M.str(), RoTy);
  }

  ASTSymbolTableEntry *RSTE = ASTSymbolTable::Instance().Lookup(
      RId, RId->GetBits(), RId->GetSymbolType());
  assert(RSTE && "Could not obtain a valid second operand SymbolTable Entry!");
  if (!RSTE) {
    std::stringstream M;
    M << "Could not obtain a valid second operand SymbolTable Entry.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTRotateNode::ExpressionError(M.str(), RoTy);
  }

  ASTIntNode *RI = RSTE->GetValue()->GetValue<ASTIntNode *>();
  assert(RI && "Could not obtain a valid second operand ASTIntNode!");
  if (!RI) {
    std::stringstream M;
    M << "Could not obtain a valid second operand ASTIntNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTRotateNode::ExpressionError(M.str(), RoTy);
  }

  RId->SetBits(LCB->GetBits());
  return CreateASTRotateNode(TK, Id, LCB, RI, RoTy);
}

ASTRotateNode *ASTProductionFactory::ProductionRule_310(
    const ASTToken *TK,
    const std::variant<const ASTIntNode *, const ASTIdentifierNode *,
                       const ASTCBitNode *> &LII,
    const std::variant<const ASTIntNode *, const ASTIdentifierNode *> &RII,
    ASTRotationType RoTy) const {
  assert(TK && "Invalid ASTToken argument!");
  assert((RoTy == ASTRotationTypeLeft || RoTy == ASTRotationTypeRight) &&
         "Invalid rotation type argument!");

  if (RoTy != ASTRotationTypeLeft && RoTy != ASTRotationTypeRight) {
    std::stringstream M;
    M << "Invalid rotation type (" << PrintRotationType(RoTy) << ") argument.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTRotateNode::ExpressionError(M.str(), RoTy);
  }

  std::stringstream RS;

  if (RoTy == ASTRotationTypeLeft)
    RS << "ast-rotate-left-"
       << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  else
    RS << "ast-rotate-right-"
       << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTIdentifierNode *RId = ASTBuilder::Instance().CreateASTIdentifierNode(
      RS.str(), 0U, ASTTypeRotateExpr);
  assert(RId && "Could not create a valid ASTIdentifierNode!");

  RId->SetLocation(TK->GetLocation());
  ASTRotateNode *RN = nullptr;

  switch (LII.index()) {
  case 0: {
    switch (RII.index()) {
    case 0:
      RN = CreateASTRotateNode(TK, RId, std::get<0>(LII), std::get<0>(RII),
                               RoTy);
      break;
    case 1:
      RN = CreateASTRotateNode(TK, RId, std::get<0>(LII), std::get<1>(RII),
                               RoTy);
      break;
    default: {
      std::stringstream M;
      M << "Invalid right std::variant index for second rotation operand.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(TK), M.str(),
          DiagLevel::Error);
      return ASTRotateNode::ExpressionError(M.str(), RoTy);
    } break;
    }
  } break;
  case 1: {
    switch (RII.index()) {
    case 0:
      RN = CreateASTRotateNode(TK, RId, std::get<1>(LII), std::get<0>(RII),
                               RoTy);
      break;
    case 1:
      RN = CreateASTRotateNode(TK, RId, std::get<1>(LII), std::get<1>(RII),
                               RoTy);
      break;
    default: {
      std::stringstream M;
      M << "Invalid right std::variant index for second rotation operand.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(TK), M.str(),
          DiagLevel::Error);
      return ASTRotateNode::ExpressionError(M.str(), RoTy);
    } break;
    }
  } break;
  case 2: {
    switch (RII.index()) {
    case 0:
      RN = CreateASTRotateNode(TK, RId, std::get<2>(LII), std::get<0>(RII),
                               RoTy);
      break;
    case 1:
      RN = CreateASTRotateNode(TK, RId, std::get<2>(LII), std::get<1>(RII),
                               RoTy);
      break;
    default: {
      std::stringstream M;
      M << "Invalid right std::variant index for second rotation operand.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(TK), M.str(),
          DiagLevel::Error);
      return ASTRotateNode::ExpressionError(M.str(), RoTy);
    } break;
    }
  } break;
  default: {
    std::stringstream M;
    M << "Invalid left std::variant index for rotation operand.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTRotateNode::ExpressionError(M.str(), RoTy);
  } break;
  }

  assert(RN && "Could not create a valid ASTRotateNode!");
  if (!RN) {
    std::stringstream M;
    M << "Could not create a valid ASTRotateNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTRotateNode::ExpressionError(M.str(), RoTy);
  }

  RId->SetBits(RN->GetBits());
  RN->SetLocation(TK->GetLocation());
  RN->Mangle();
  return RN;
}

ASTRotateStatementNode *
ASTProductionFactory::ProductionRule_310(const ASTToken *TK,
                                         const ASTRotateNode *RN) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(RN && "Invalid ASTRotationNode argument!");

  ASTRotateStatementNode *RSN = new ASTRotateStatementNode(RN);
  assert(RSN && "Could not create a valid ASTRotateStatementNode!");
  if (!RSN) {
    std::stringstream M;
    M << "Could not create a valid ASTRotateStatementNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTRotateStatementNode::StatementError(RN->GetIdentifier(), M.str());
  }

  RSN->SetLocation(TK->GetLocation());
  RSN->Mangle();
  return RSN;
}

ASTPopcountNode *
ASTProductionFactory::ProductionRule_320(const ASTToken *TK,
                                         const ASTIntNode *I) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(I && "Invalid ASTIntNode argument!");

  const ASTMPIntegerNode *MPI = nullptr;

  if (I->IsMPInteger()) {
    MPI = I->GetMPInteger();
    assert(MPI && "Invalid ASTMPIntegerNode contained by ASTIntNode!");
    if (!MPI) {
      std::stringstream M;
      M << "Invalid ASTMPIntegerNode contained by ASTIntNode.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(I), M.str(),
          DiagLevel::Error);
      return ASTPopcountNode::ExpressionError(M.str());
    }
  }

  std::stringstream PS;
  PS << "ast-popcount-"
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      PS.str(), I->GetBits(), ASTTypePopcountExpr);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  ASTSymbolTableEntry *STE =
      ASTSymbolTable::Instance().Lookup(Id, Id->GetBits(), Id->GetSymbolType());
  assert(STE && "Could not obtain a valid Target SymbolTable Entry!");
  assert(STE->HasValue() && "Target SymbolTable Entry has no Value!");

  ASTPopcountNode *PN = nullptr;

  if (MPI)
    PN = ASTBuilder::Instance().CreateASTPopcountNode(Id, MPI);
  else
    PN = ASTBuilder::Instance().CreateASTPopcountNode(Id, I);

  assert(PN && "Could not create a valid ASTPopcountNode!");
  if (!PN) {
    std::stringstream M;
    M << "Could not create a valid ASTPopcountNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTPopcountNode::ExpressionError(M.str());
  }

  PN->SetLocation(TK->GetLocation());
  PN->Mangle();
  return PN;
}

ASTPopcountNode *
ASTProductionFactory::ProductionRule_320(const ASTToken *TK,
                                         const ASTIdentifierNode *TId) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(TId && "Invalid ASTIdentifierNode argument!");

  ASTScopeController::Instance().CheckUndefined(TId);
  ASTScopeController::Instance().CheckOutOfScope(TId);

  std::stringstream PS;
  PS << "ast-popcount-"
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      PS.str(), TId->GetBits(), ASTTypePopcountExpr);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  ASTSymbolTableEntry *STE = ASTSymbolTable::Instance().Lookup(
      TId, TId->GetBits(), TId->GetSymbolType());
  assert(STE && "Could not obtain a valid Target SymbolTable Entry!");
  assert(STE->HasValue() && "Target SymbolTable Entry has no Value!");

  ASTPopcountNode *PN = nullptr;

  switch (STE->GetValueType()) {
  case ASTTypeInt:
  case ASTTypeUInt: {
    if (ASTIntNode *I = STE->GetValue()->GetValue<ASTIntNode *>()) {
      if (I->IsMPInteger()) {
        if (const ASTMPIntegerNode *MPI = I->GetMPInteger()) {
          PN = ASTBuilder::Instance().CreateASTPopcountNode(Id, MPI);
          assert(PN && "Could not create a valid ASTPopcountNode!");
        } else {
          std::stringstream M;
          M << "Invalid ASTMPIntegerNode contained by ASTIntNode.";
          QasmDiagnosticEmitter::Instance().EmitDiagnostic(
              DIAGLineCounter::Instance().GetLocation(I), M.str(),
              DiagLevel::Error);
          return ASTPopcountNode::ExpressionError(M.str());
        }
      } else {
        PN = ASTBuilder::Instance().CreateASTPopcountNode(Id, I);
        assert(PN && "Could not create a valid ASTPopcountNode!");
      }
    } else {
      std::stringstream M;
      M << "Could not obtain a valid ASTIntNode from the SymbolTable.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(TId), M.str(),
          DiagLevel::Error);
      return ASTPopcountNode::ExpressionError(M.str());
    }
  } break;
  case ASTTypeMPInteger:
  case ASTTypeMPUInteger: {
    if (ASTMPIntegerNode *MPI =
            STE->GetValue()->GetValue<ASTMPIntegerNode *>()) {
      PN = ASTBuilder::Instance().CreateASTPopcountNode(Id, MPI);
      assert(PN && "Could not create a valid ASTPopcountNode!");
    } else {
      std::stringstream M;
      M << "Could not obtain a valid ASTMPIntegerNode from the SymbolTable.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(TId), M.str(),
          DiagLevel::Error);
      return ASTPopcountNode::ExpressionError(M.str());
    }
  } break;
  case ASTTypeBitset: {
    if (ASTCBitNode *CBN = STE->GetValue()->GetValue<ASTCBitNode *>()) {
      PN = ASTBuilder::Instance().CreateASTPopcountNode(Id, CBN);
      assert(PN && "Could not create a valid ASTPopcountNode!");
    } else {
      std::stringstream M;
      M << "Could not obtain a valid ASTCBitNode from the SymbolTable.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(TId), M.str(),
          DiagLevel::Error);
      return ASTPopcountNode::ExpressionError(M.str());
    }
  } break;
  default: {
    std::stringstream M;
    M << "Only Integer or Bitset types can be popcount targets.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TId), M.str(),
        DiagLevel::Error);
    return ASTPopcountNode::ExpressionError(M.str());
  } break;
  }

  if (!PN) {
    std::stringstream M;
    M << "Could not create a valid ASTPopcountNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTPopcountNode::ExpressionError(M.str());
  }

  PN->SetLocation(TK->GetLocation());
  PN->Mangle();
  return PN;
}

ASTPopcountStatementNode *
ASTProductionFactory::ProductionRule_320(const ASTToken *TK,
                                         const ASTPopcountNode *PN) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(PN && "Invalid ASTPopcountNode argument!");

  ASTPopcountStatementNode *PSN = new ASTPopcountStatementNode(PN);
  assert(PSN && "Could not create a valid ASTPopcountStatementNode!");
  if (!PSN) {
    std::stringstream M;
    M << "Could not create a valid ASTPopcountStatementNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTPopcountStatementNode::StatementError(PN->GetIdentifier(),
                                                    M.str());
  }

  PSN->SetLocation(TK->GetLocation());
  PSN->Mangle();
  return PSN;
}

ASTBinaryOpNode *
ASTProductionFactory::ProductionRule_450(const ASTToken *TK,
                                         const ASTIdentifierNode *Id,
                                         const ASTExpressionNode *EX) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(EX && "Invalid ASTExpressionNode argument!");

  ASTScopeController::Instance().CheckOutOfScope(Id);

  if (!ASTExpressionValidator::Instance().IsAssignableType(Id))
    return ASTProductionFactory::Instance().ProductionRule_7003(TK);

  if (!ASTExpressionValidator::Instance().CanBeAssignedTo(Id))
    return ASTProductionFactory::Instance().ProductionRule_7003(TK);

  if (Id->GetSymbolType() == ASTTypeUndefined) {
    std::stringstream M;
    M << "Identifier has not been assigned a defined Type.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTBinaryOpNode::ExpressionError(M.str(), ASTOpTypeAssign);
  }

  std::stringstream ES;
  ES << "binary-op-assign-"
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTBinaryOpNode *BOP = ASTBuilder::Instance().CreateASTBinaryOpNode(
      ES.str(), Id, EX, ASTOpTypeAssign);
  if (!BOP) {
    std::stringstream M;
    M << "Could not create a valid ASTBinaryOpNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTBinaryOpNode::ExpressionError(M.str(), ASTOpTypeAssign);
  }

  BOP->SetLocation(TK->GetLocation());
  BOP->Mangle();
  return BOP;
}

ASTBinaryOpNode *
ASTProductionFactory::ProductionRule_451(const ASTToken *TK,
                                         const ASTIdentifierNode *Id,
                                         const ASTFunctionCallNode *FCN) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(FCN && "Invalid ASTFunctionCallNode argument!");

  ASTScopeController::Instance().CheckOutOfScope(Id);

  if (!ASTExpressionValidator::Instance().IsAssignableType(Id))
    return ASTProductionFactory::Instance().ProductionRule_7003(TK);

  if (!ASTExpressionValidator::Instance().CanBeAssignedTo(Id))
    return ASTProductionFactory::Instance().ProductionRule_7003(TK);

  if (Id->GetSymbolType() == ASTTypeUndefined) {
    std::stringstream M;
    M << "Identifier has not been assigned a defined Type.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTBinaryOpNode::ExpressionError(M.str(), ASTOpTypeAssign);
  }

  if (!FCN->ReturnsResult()) {
    std::stringstream M;
    M << "Assignment requires a non-void return type.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTBinaryOpNode::ExpressionError(M.str(), ASTOpTypeAssign);
  }

  std::stringstream ES;
  ES << "binary-op-assign-"
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTBinaryOpNode *BOP = ASTBuilder::Instance().CreateASTBinaryOpNode(
      ES.str(), Id, FCN, ASTOpTypeAssign);
  if (!BOP) {
    std::stringstream M;
    M << "Could not create a valid ASTBinaryOpNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTBinaryOpNode::ExpressionError(M.str(), ASTOpTypeAssign);
  }

  BOP->SetLocation(TK->GetLocation());
  BOP->Mangle();

  if (!ASTExpressionValidator::Instance().Validate(BOP)) {
    std::stringstream M;
    ASTType RTy = FCN->GetResultType();
    M << "Impossible assignment of " << PrintTypeEnum(RTy) << " to "
      << PrintTypeEnum(Id->GetSymbolType()) << '.';
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTBinaryOpNode::ExpressionError(M.str(), ASTOpTypeAssign);
  }

  return BOP;
}

ASTBinaryOpNode *ASTProductionFactory::ProductionRule_452(
    const ASTToken *TK, const ASTIdentifierNode *Id,
    const ASTComplexExpressionNode *CEX) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(CEX && "Invalid ASTComplexExpressionNode argument!");

  ASTScopeController::Instance().CheckOutOfScope(Id);

  if (!ASTExpressionValidator::Instance().IsAssignableType(Id))
    return ASTProductionFactory::Instance().ProductionRule_7003(TK);

  if (!ASTExpressionValidator::Instance().CanBeAssignedTo(Id))
    return ASTProductionFactory::Instance().ProductionRule_7003(TK);

  if (Id->GetSymbolType() == ASTTypeUndefined) {
    std::stringstream M;
    M << "Identifier has not been assigned a defined Type.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTBinaryOpNode::ExpressionError(M.str(), ASTOpTypeAssign);
  }

  std::stringstream ES;
  ES << "binary-op-assign-"
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTBinaryOpNode *BOP = ASTBuilder::Instance().CreateASTBinaryOpNode(
      ES.str(), Id, CEX, ASTOpTypeAssign);
  if (!BOP) {
    std::stringstream M;
    M << "Could not create a valid ASTBinaryOpNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTBinaryOpNode::ExpressionError(M.str(), ASTOpTypeAssign);
  }

  BOP->SetLocation(TK->GetLocation());
  BOP->Mangle();

  if (!ASTExpressionValidator::Instance().Validate(BOP)) {
    std::stringstream M;
    ASTType RTy = CEX->GetASTType();
    M << "Impossible assignment of " << PrintTypeEnum(RTy) << " to "
      << PrintTypeEnum(Id->GetSymbolType()) << '.';
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTBinaryOpNode::ExpressionError(M.str(), ASTOpTypeAssign);
  }

  return BOP;
}

ASTBinaryOpNode *
ASTProductionFactory::ProductionRule_453(const ASTToken *TK,
                                         const ASTIdentifierNode *Id,
                                         const ASTBinaryOpNode *BOPN) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(BOPN && "Invalid ASTBinaryOpNode argument!");

  ASTScopeController::Instance().CheckOutOfScope(Id);

  if (!ASTExpressionValidator::Instance().IsAssignableType(Id))
    return ASTProductionFactory::Instance().ProductionRule_7003(TK);

  if (!ASTExpressionValidator::Instance().CanBeAssignedTo(Id))
    return ASTProductionFactory::Instance().ProductionRule_7003(TK);

  if (Id->GetSymbolType() == ASTTypeUndefined) {
    std::stringstream M;
    M << "Identifier has not been assigned a defined Type.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTBinaryOpNode::ExpressionError(M.str(), ASTOpTypeAssign);
  }

  std::stringstream ES;
  ES << "binary-op-assign-"
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTBinaryOpNode *BOP = ASTBuilder::Instance().CreateASTBinaryOpNode(
      ES.str(), Id, BOPN, ASTOpTypeAssign);
  if (!BOP) {
    std::stringstream M;
    M << "Could not create a valid ASTBinaryOpNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTBinaryOpNode::ExpressionError(M.str(), ASTOpTypeAssign);
  }

  BOP->SetLocation(TK->GetLocation());
  BOP->Mangle();

  if (!ASTExpressionValidator::Instance().Validate(BOP)) {
    std::stringstream M;
    ASTType RTy = ASTExpressionEvaluator::Instance().EvaluatesTo(BOPN);
    M << "Impossible assignment of " << PrintTypeEnum(RTy) << " to "
      << PrintTypeEnum(Id->GetSymbolType()) << '.';
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTBinaryOpNode::ExpressionError(M.str(), ASTOpTypeAssign);
  }

  return BOP;
}

ASTBinaryOpNode *
ASTProductionFactory::ProductionRule_454(const ASTToken *TK,
                                         const ASTIdentifierNode *Id,
                                         const ASTRotateNode *RN) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(RN && "Invalid ASTRotateNode argument!");

  ASTScopeController::Instance().CheckOutOfScope(Id);

  if (!ASTExpressionValidator::Instance().IsAssignableType(Id))
    return ASTProductionFactory::Instance().ProductionRule_7003(TK);

  if (!ASTExpressionValidator::Instance().CanBeAssignedTo(Id))
    return ASTProductionFactory::Instance().ProductionRule_7003(TK);

  if (Id->GetSymbolType() == ASTTypeUndefined) {
    std::stringstream M;
    M << "Identifier has not been assigned a defined Type.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTBinaryOpNode::ExpressionError(M.str(), ASTOpTypeAssign);
  }

  std::stringstream ES;
  ES << "binary-op-assign-"
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTBinaryOpNode *BOP = ASTBuilder::Instance().CreateASTBinaryOpNode(
      ES.str(), Id, RN, ASTOpTypeAssign);
  if (!BOP) {
    std::stringstream M;
    M << "Could not create a valid ASTBinaryOpNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTBinaryOpNode::ExpressionError(M.str(), ASTOpTypeAssign);
  }

  BOP->SetLocation(TK->GetLocation());
  BOP->Mangle();
  return BOP;
}

ASTBinaryOpNode *
ASTProductionFactory::ProductionRule_455(const ASTToken *TK,
                                         const ASTIdentifierNode *Id,
                                         const ASTPopcountNode *PN) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(PN && "Invalid ASTPopcountNode argument!");

  ASTScopeController::Instance().CheckOutOfScope(Id);

  if (!ASTExpressionValidator::Instance().IsAssignableType(Id))
    return ASTProductionFactory::Instance().ProductionRule_7003(TK);

  if (!ASTExpressionValidator::Instance().CanBeAssignedTo(Id))
    return ASTProductionFactory::Instance().ProductionRule_7003(TK);

  if (Id->GetSymbolType() == ASTTypeUndefined) {
    std::stringstream M;
    M << "Identifier has not been assigned a defined Type.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTBinaryOpNode::ExpressionError(M.str(), ASTOpTypeAssign);
  }

  std::stringstream ES;
  ES << "binary-op-assign-"
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTBinaryOpNode *BOP = ASTBuilder::Instance().CreateASTBinaryOpNode(
      ES.str(), Id, PN, ASTOpTypeAssign);
  if (!BOP) {
    std::stringstream M;
    M << "Could not create a valid ASTBinaryOpNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTBinaryOpNode::ExpressionError(M.str(), ASTOpTypeAssign);
  }

  BOP->SetLocation(TK->GetLocation());
  BOP->Mangle();
  return BOP;
}

ASTBinaryOpNode *
ASTProductionFactory::ProductionRule_456(const ASTToken *TK,
                                         const ASTIdentifierNode *Id,
                                         const ASTStringNode *TS) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(TS && "Invalid ASTStringNode argument!");

  ASTScopeController::Instance().CheckOutOfScope(Id);

  if (!ASTExpressionValidator::Instance().IsAssignableType(Id))
    return ASTProductionFactory::Instance().ProductionRule_7003(TK);

  if (!ASTExpressionValidator::Instance().CanBeAssignedTo(Id))
    return ASTProductionFactory::Instance().ProductionRule_7003(TK);

  if (Id->GetSymbolType() == ASTTypeUndefined) {
    std::stringstream M;
    M << "Identifier has not been assigned a defined Type.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTBinaryOpNode::ExpressionError(M.str(), ASTOpTypeAssign);
  }

  std::stringstream ES;
  ES << "binary-op-assign-"
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTBinaryOpNode *BOP = ASTBuilder::Instance().CreateASTBinaryOpNode(
      ES.str(), Id, TS, ASTOpTypeAssign);
  if (!BOP) {
    std::stringstream M;
    M << "Could not create a valid ASTBinaryOpNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTBinaryOpNode::ExpressionError(M.str(), ASTOpTypeAssign);
  }

  BOP->SetLocation(TK->GetLocation());
  BOP->Mangle();
  return BOP;
}

ASTBinaryOpNode *
ASTProductionFactory::ProductionRule_457(const ASTToken *TK,
                                         const ASTIdentifierNode *Id,
                                         const ASTBoolNode *BN) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(BN && "Invalid ASTBoolNode argument!");

  ASTScopeController::Instance().CheckOutOfScope(Id);

  if (!ASTExpressionValidator::Instance().IsAssignableType(Id))
    return ASTProductionFactory::Instance().ProductionRule_7003(TK);

  if (!ASTExpressionValidator::Instance().CanBeAssignedTo(Id))
    return ASTProductionFactory::Instance().ProductionRule_7003(TK);

  if (Id->GetSymbolType() == ASTTypeUndefined) {
    std::stringstream M;
    M << "Identifier has not been assigned a defined Type.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTBinaryOpNode::ExpressionError(M.str(), ASTOpTypeAssign);
  }

  std::stringstream ES;
  ES << "binary-op-assign-"
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTBinaryOpNode *BOP = ASTBuilder::Instance().CreateASTBinaryOpNode(
      ES.str(), Id, BN, ASTOpTypeAssign);
  if (!BOP) {
    std::stringstream M;
    M << "Could not create a valid ASTBinaryOpNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTBinaryOpNode::ExpressionError(M.str(), ASTOpTypeAssign);
  }

  BOP->SetLocation(TK->GetLocation());
  BOP->Mangle();
  return BOP;
}

ASTBinaryOpNode *ASTProductionFactory::ProductionRule_580(
    const ASTToken *TK, const ASTExpressionNode *LXN,
    const ASTExpressionNode *RXN, ASTOpType OTy) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(LXN && "Invalid ASTExpressionNode argument!");
  assert(RXN && "Invalid ASTExpressionNode argument!");

  if (ASTExpressionValidator::Instance().IsAssignmentOp(OTy) &&
      !ASTExpressionValidator::Instance().IsAssignableType(LXN))
    return ASTProductionFactory::Instance().ProductionRule_7003(TK);

  if (ASTExpressionValidator::Instance().IsAssignmentOp(OTy) &&
      !ASTExpressionValidator::Instance().CanBeAssignedTo(LXN))
    return ASTProductionFactory::Instance().ProductionRule_7003(TK);

  if (LXN->GetASTType() == ASTTypeIdentifier &&
      RXN->GetASTType() == ASTTypeIdentifier) {
    const ASTIdentifierNode *LId = LXN->GetIdentifier();
    const ASTIdentifierNode *RId = RXN->GetIdentifier();

    if (!LId) {
      std::stringstream M;
      M << "Invalid LHS ASTIdentifierNode contained in ASTExpressionNode.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(TK), M.str(),
          DiagLevel::Error);
      return ASTBinaryOpNode::ExpressionError(M.str(), OTy);
    }

    if (!RId) {
      std::stringstream M;
      M << "Invalid RHS ASTIdentifierNode contained in ASTExpressionNode.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(TK), M.str(),
          DiagLevel::Error);
      return ASTBinaryOpNode::ExpressionError(M.str(), OTy);
    }

    return ASTProductionFactory::Instance().ProductionRule_583(TK, LId, RId,
                                                               OTy);
  } else if (LXN->GetASTType() == ASTTypeIdentifier) {
    const ASTIdentifierNode *LId = LXN->GetIdentifier();

    if (!LId) {
      std::stringstream M;
      M << "Invalid LHS ASTIdentifierNode contained in ASTExpressionNode.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(TK), M.str(),
          DiagLevel::Error);
      return ASTBinaryOpNode::ExpressionError(M.str(), OTy);
    }

    return ASTProductionFactory::Instance().ProductionRule_581(TK, LId, RXN,
                                                               OTy);
  } else if (RXN->GetASTType() == ASTTypeIdentifier) {
    const ASTIdentifierNode *RId = RXN->GetIdentifier();

    if (!RId) {
      std::stringstream M;
      M << "Invalid RHS ASTIdentifierNode contained in ASTExpressionNode.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(TK), M.str(),
          DiagLevel::Error);
      return ASTBinaryOpNode::ExpressionError(M.str(), OTy);
    }

    return ASTProductionFactory::Instance().ProductionRule_582(TK, LXN, RId,
                                                               OTy);
  }

  std::stringstream ES;
  ES << "binary-op-" << PrintDashOpTypeEnum(OTy) << '-'
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTBinaryOpNode *BOP =
      ASTBuilder::Instance().CreateASTBinaryOpNode(ES.str(), LXN, RXN, OTy);
  if (!BOP) {
    std::stringstream M;
    M << "Could not create a valid ASTBinaryOpNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTBinaryOpNode::ExpressionError(M.str(), OTy);
  }

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  BOP->SetDeclarationContext(CTX);
  BOP->SetLocation(TK->GetLocation());
  BOP->Mangle();
  return BOP;
}

ASTBinaryOpNode *ASTProductionFactory::ProductionRule_581(
    const ASTToken *TK, const ASTIdentifierNode *LId,
    const ASTExpressionNode *RXN, ASTOpType OTy) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(LId && "Invalid ASTIdentifierNode argument!");
  assert(RXN && "Invalid ASTExpressionNode argument!");

  if (ASTExpressionValidator::Instance().IsAssignmentOp(OTy) &&
      !ASTExpressionValidator::Instance().IsAssignableType(LId))
    return ASTProductionFactory::Instance().ProductionRule_7003(TK);

  std::stringstream ES;
  ES << "binary-op-" << PrintDashOpTypeEnum(OTy) << '-'
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTBinaryOpNode *BOP =
      ASTBuilder::Instance().CreateASTBinaryOpNode(ES.str(), LId, RXN, OTy);
  if (!BOP) {
    std::stringstream M;
    M << "Could not create a valid ASTBinaryOpNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTBinaryOpNode::ExpressionError(M.str(), OTy);
  }

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  BOP->SetDeclarationContext(CTX);
  BOP->SetLocation(TK->GetLocation());
  BOP->Mangle();
  return BOP;
}

ASTBinaryOpNode *ASTProductionFactory::ProductionRule_582(
    const ASTToken *TK, const ASTExpressionNode *LXN,
    const ASTIdentifierNode *RId, ASTOpType OTy) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(LXN && "Invalid ASTExpressionNode argument!");
  assert(RId && "Invalid ASTIdentifierNode argument!");

  if (ASTExpressionValidator::Instance().IsAssignmentOp(OTy) &&
      !ASTExpressionValidator::Instance().IsAssignableType(LXN))
    return ASTProductionFactory::Instance().ProductionRule_7003(TK);

  std::stringstream ES;
  ES << "binary-op-" << PrintDashOpTypeEnum(OTy) << '-'
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTBinaryOpNode *BOP =
      ASTBuilder::Instance().CreateASTBinaryOpNode(ES.str(), LXN, RId, OTy);
  if (!BOP) {
    std::stringstream M;
    M << "Could not create a valid ASTBinaryOpNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTBinaryOpNode::ExpressionError(M.str(), OTy);
  }

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  BOP->SetDeclarationContext(CTX);
  BOP->SetLocation(TK->GetLocation());
  BOP->Mangle();
  return BOP;
}

ASTBinaryOpNode *ASTProductionFactory::ProductionRule_583(
    const ASTToken *TK, const ASTIdentifierNode *LId,
    const ASTIdentifierNode *RId, ASTOpType OTy) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(LId && "Invalid ASTIdentifierNode argument!");
  assert(RId && "Invalid ASTIdentifierNode argument!");

  if (ASTExpressionValidator::Instance().IsAssignmentOp(OTy) &&
      !ASTExpressionValidator::Instance().IsAssignableType(LId))
    return ASTProductionFactory::Instance().ProductionRule_7003(TK);

  std::stringstream ES;
  ES << "binary-op-" << PrintDashOpTypeEnum(OTy) << '-'
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTBinaryOpNode *BOP =
      ASTBuilder::Instance().CreateASTBinaryOpNode(ES.str(), LId, RId, OTy);
  if (!BOP) {
    std::stringstream M;
    M << "Could not create a valid ASTBinaryOpNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTBinaryOpNode::ExpressionError(M.str(), OTy);
  }

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  BOP->SetDeclarationContext(CTX);
  BOP->SetLocation(TK->GetLocation());
  BOP->Mangle();
  return BOP;
}

ASTBinaryOpNode *ASTProductionFactory::ProductionRule_584(
    const ASTToken *TK, const ASTExpressionNode *LXN,
    const ASTFunctionCallNode *FCN, ASTOpType OTy) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(LXN && "Invalid ASTExpressionNode argument!");
  assert(FCN && "Invalid ASTFunctionCallNode argument!");

  if (ASTExpressionValidator::Instance().IsAssignmentOp(OTy) &&
      !ASTExpressionValidator::Instance().IsAssignableType(LXN))
    return ASTProductionFactory::Instance().ProductionRule_7003(TK);

  std::stringstream ES;
  ES << "binary-op-" << PrintDashOpTypeEnum(OTy) << '-'
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTBinaryOpNode *BOP =
      ASTBuilder::Instance().CreateASTBinaryOpNode(ES.str(), LXN, FCN, OTy);
  if (!BOP) {
    std::stringstream M;
    M << "Could not create a valid ASTBinaryOpNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTBinaryOpNode::ExpressionError(M.str(), OTy);
  }

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  BOP->SetDeclarationContext(CTX);
  BOP->SetLocation(TK->GetLocation());
  BOP->Mangle();
  return BOP;
}

ASTBinaryOpNode *ASTProductionFactory::ProductionRule_585(
    const ASTToken *TK, const ASTIdentifierNode *LId,
    const ASTFunctionCallNode *FCN, ASTOpType OTy) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(LId && "Invalid ASTIdentifierNode argument!");
  assert(FCN && "Invalid ASTFunctionCallNode argument!");

  if (ASTExpressionValidator::Instance().IsAssignmentOp(OTy) &&
      !ASTExpressionValidator::Instance().IsAssignableType(LId))
    return ASTProductionFactory::Instance().ProductionRule_7003(TK);

  std::stringstream ES;
  ES << "binary-op-" << PrintDashOpTypeEnum(OTy) << '-'
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTBinaryOpNode *BOP =
      ASTBuilder::Instance().CreateASTBinaryOpNode(ES.str(), LId, FCN, OTy);
  if (!BOP) {
    std::stringstream M;
    M << "Could not create a valid ASTBinaryOpNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTBinaryOpNode::ExpressionError(M.str(), OTy);
  }

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  BOP->SetDeclarationContext(CTX);
  BOP->SetLocation(TK->GetLocation());
  BOP->Mangle();
  return BOP;
}

ASTBinaryOpNode *ASTProductionFactory::ProductionRule_586(
    const ASTToken *TK, const ASTIdentifierNode *LId,
    const ASTBinaryOpNode *RBOP, ASTOpType OTy) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(LId && "Invalid ASTIdentifierNode argument!");
  assert(RBOP && "Invalid ASTBinaryOpNode argument!");

  if (ASTExpressionValidator::Instance().IsAssignmentOp(OTy) &&
      !ASTExpressionValidator::Instance().IsAssignableType(LId))
    return ASTProductionFactory::Instance().ProductionRule_7003(TK);

  std::stringstream ES;
  ES << "binary-op-" << PrintDashOpTypeEnum(OTy) << '-'
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTBinaryOpNode *BOP =
      ASTBuilder::Instance().CreateASTBinaryOpNode(ES.str(), LId, RBOP, OTy);
  if (!BOP) {
    std::stringstream M;
    M << "Could not create a valid ASTBinaryOpNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTBinaryOpNode::ExpressionError(M.str(), OTy);
  }

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  BOP->SetDeclarationContext(CTX);
  BOP->SetLocation(TK->GetLocation());
  BOP->Mangle();
  return BOP;
}

ASTBinaryOpNode *ASTProductionFactory::ProductionRule_587(
    const ASTToken *TK, const ASTIdentifierNode *LId,
    const ASTUnaryOpNode *RUOP, ASTOpType OTy) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(LId && "Invalid ASTIdentifierNode argument!");
  assert(RUOP && "Invalid ASTUnaryOpNode argument!");

  if (ASTExpressionValidator::Instance().IsAssignmentOp(OTy) &&
      !ASTExpressionValidator::Instance().IsAssignableType(LId))
    return ASTProductionFactory::Instance().ProductionRule_7003(TK);

  std::stringstream ES;
  ES << "binary-op-" << PrintDashOpTypeEnum(OTy) << '-'
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTBinaryOpNode *BOP =
      ASTBuilder::Instance().CreateASTBinaryOpNode(ES.str(), LId, RUOP, OTy);
  if (!BOP) {
    std::stringstream M;
    M << "Could not create a valid ASTBinaryOpNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTBinaryOpNode::ExpressionError(M.str(), OTy);
  }

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  BOP->SetDeclarationContext(CTX);
  BOP->SetLocation(TK->GetLocation());
  BOP->Mangle();
  return BOP;
}

ASTBinaryOpNode *ASTProductionFactory::ProductionRule_588(
    const ASTToken *TK, const ASTExpressionNode *LXN,
    const ASTBinaryOpNode *RBOP, ASTOpType OTy) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(LXN && "Invalid ASTExpressionNode argument!");
  assert(RBOP && "Invalid ASTBinaryOpNode argument!");

  if (ASTExpressionValidator::Instance().IsAssignmentOp(OTy) &&
      !ASTExpressionValidator::Instance().IsAssignableType(LXN))
    return ASTProductionFactory::Instance().ProductionRule_7003(TK);

  std::stringstream ES;
  ES << "binary-op-" << PrintDashOpTypeEnum(OTy) << '-'
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTBinaryOpNode *BOP =
      ASTBuilder::Instance().CreateASTBinaryOpNode(ES.str(), LXN, RBOP, OTy);
  if (!BOP) {
    std::stringstream M;
    M << "Could not create a valid ASTBinaryOpNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTBinaryOpNode::ExpressionError(M.str(), OTy);
  }

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  BOP->SetDeclarationContext(CTX);
  BOP->SetLocation(TK->GetLocation());
  BOP->Mangle();
  return BOP;
}

ASTBinaryOpNode *ASTProductionFactory::ProductionRule_589(
    const ASTToken *TK, const ASTExpressionNode *LXN,
    const ASTUnaryOpNode *RUOP, ASTOpType OTy) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(LXN && "Invalid ASTExpressionNode argument!");
  assert(RUOP && "Invalid ASTUnaryOpNode argument!");

  if (ASTExpressionValidator::Instance().IsAssignmentOp(OTy) &&
      !ASTExpressionValidator::Instance().IsAssignableType(LXN))
    return ASTProductionFactory::Instance().ProductionRule_7003(TK);

  std::stringstream ES;
  ES << "binary-op-" << PrintDashOpTypeEnum(OTy) << '-'
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTBinaryOpNode *BOP =
      ASTBuilder::Instance().CreateASTBinaryOpNode(ES.str(), LXN, RUOP, OTy);
  if (!BOP) {
    std::stringstream M;
    M << "Could not create a valid ASTBinaryOpNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTBinaryOpNode::ExpressionError(M.str(), OTy);
  }

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  BOP->SetDeclarationContext(CTX);
  BOP->SetLocation(TK->GetLocation());
  BOP->Mangle();
  return BOP;
}

ASTBinaryOpNode *ASTProductionFactory::ProductionRule_590(
    const ASTToken *TK, const ASTBinaryOpNode *LBOP,
    const ASTBinaryOpNode *RBOP, ASTOpType OTy) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(LBOP && "Invalid ASTBinaryOpNode argument!");
  assert(RBOP && "Invalid ASTBinaryOpNode argument!");

  ASTType LTy = ASTExpressionEvaluator::Instance().EvaluatesTo(LBOP);

  if (ASTExpressionValidator::Instance().IsAssignmentOp(OTy) &&
      !ASTExpressionValidator::Instance().IsAssignableType(LTy))
    return ASTProductionFactory::Instance().ProductionRule_7003(TK);

  std::stringstream ES;
  ES << "binary-op-" << PrintDashOpTypeEnum(OTy) << '-'
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTBinaryOpNode *BOP =
      ASTBuilder::Instance().CreateASTBinaryOpNode(ES.str(), LBOP, RBOP, OTy);
  if (!BOP) {
    std::stringstream M;
    M << "Could not create a valid ASTBinaryOpNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTBinaryOpNode::ExpressionError(M.str(), OTy);
  }

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  BOP->SetDeclarationContext(CTX);
  BOP->SetLocation(TK->GetLocation());
  BOP->Mangle();
  return BOP;
}

ASTBinaryOpNode *ASTProductionFactory::ProductionRule_591(
    const ASTToken *TK, const ASTBinaryOpNode *LBOP, const ASTUnaryOpNode *RUOP,
    ASTOpType OTy) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(LBOP && "Invalid ASTBinaryOpNode argument!");
  assert(RUOP && "Invalid ASTUnaryOpNode argument!");

  ASTType LTy = ASTExpressionEvaluator::Instance().EvaluatesTo(LBOP);

  if (ASTExpressionValidator::Instance().IsAssignmentOp(OTy) &&
      !ASTExpressionValidator::Instance().IsAssignableType(LTy))
    return ASTProductionFactory::Instance().ProductionRule_7003(TK);

  std::stringstream ES;
  ES << "binary-op-" << PrintDashOpTypeEnum(OTy) << '-'
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTBinaryOpNode *BOP =
      ASTBuilder::Instance().CreateASTBinaryOpNode(ES.str(), LBOP, RUOP, OTy);
  if (!BOP) {
    std::stringstream M;
    M << "Could not create a valid ASTBinaryOpNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTBinaryOpNode::ExpressionError(M.str(), OTy);
  }

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  BOP->SetDeclarationContext(CTX);
  BOP->SetLocation(TK->GetLocation());
  BOP->Mangle();
  return BOP;
}

ASTBinaryOpNode *ASTProductionFactory::ProductionRule_592(
    const ASTToken *TK, const ASTUnaryOpNode *LUOP, const ASTBinaryOpNode *RBOP,
    ASTOpType OTy) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(LUOP && "Invalid ASTUnaryOpNode argument!");
  assert(RBOP && "Invalid ASTBinaryOpNode argument!");

  ASTType LTy = ASTExpressionEvaluator::Instance().EvaluatesTo(LUOP);

  if (ASTExpressionValidator::Instance().IsAssignmentOp(OTy) &&
      !ASTExpressionValidator::Instance().IsAssignableType(LTy))
    return ASTProductionFactory::Instance().ProductionRule_7003(TK);

  std::stringstream ES;
  ES << "binary-op-" << PrintDashOpTypeEnum(OTy) << '-'
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTBinaryOpNode *BOP =
      ASTBuilder::Instance().CreateASTBinaryOpNode(ES.str(), LUOP, RBOP, OTy);
  if (!BOP) {
    std::stringstream M;
    M << "Could not create a valid ASTBinaryOpNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTBinaryOpNode::ExpressionError(M.str(), OTy);
  }

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  BOP->SetDeclarationContext(CTX);
  BOP->SetLocation(TK->GetLocation());
  BOP->Mangle();
  return BOP;
}

ASTBinaryOpNode *ASTProductionFactory::ProductionRule_593(
    const ASTToken *TK, const ASTUnaryOpNode *LUOP, const ASTUnaryOpNode *RUOP,
    ASTOpType OTy) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(LUOP && "Invalid ASTUnaryOpNode argument!");
  assert(RUOP && "Invalid ASTUnaryOpNode argument!");

  ASTType LTy = ASTExpressionEvaluator::Instance().EvaluatesTo(LUOP);

  if (ASTExpressionValidator::Instance().IsAssignmentOp(OTy) &&
      !ASTExpressionValidator::Instance().IsAssignableType(LTy))
    return ASTProductionFactory::Instance().ProductionRule_7003(TK);

  std::stringstream ES;
  ES << "binary-op-" << PrintDashOpTypeEnum(OTy) << '-'
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTBinaryOpNode *BOP =
      ASTBuilder::Instance().CreateASTBinaryOpNode(ES.str(), LUOP, RUOP, OTy);
  if (!BOP) {
    std::stringstream M;
    M << "Could not create a valid ASTBinaryOpNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTBinaryOpNode::ExpressionError(M.str(), OTy);
  }

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  BOP->SetDeclarationContext(CTX);
  BOP->SetLocation(TK->GetLocation());
  BOP->Mangle();
  return BOP;
}

ASTBinaryOpNode *ASTProductionFactory::ProductionRule_594(
    const ASTToken *TK, const ASTBinaryOpNode *LBOP,
    const ASTExpressionNode *RXN, ASTOpType OTy) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(LBOP && "Invalid ASTBinaryOpNode argument!");
  assert(RXN && "Invalid ASTExpressionNode argument!");

  ASTType LTy = ASTExpressionEvaluator::Instance().EvaluatesTo(LBOP);

  if (ASTExpressionValidator::Instance().IsAssignmentOp(OTy) &&
      !ASTExpressionValidator::Instance().IsAssignableType(LTy))
    return ASTProductionFactory::Instance().ProductionRule_7003(TK);

  std::stringstream ES;
  ES << "binary-op-" << PrintDashOpTypeEnum(OTy) << '-'
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTBinaryOpNode *BOP =
      ASTBuilder::Instance().CreateASTBinaryOpNode(ES.str(), LBOP, RXN, OTy);
  if (!BOP) {
    std::stringstream M;
    M << "Could not create a valid ASTBinaryOpNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTBinaryOpNode::ExpressionError(M.str(), OTy);
  }

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  BOP->SetDeclarationContext(CTX);
  BOP->SetLocation(TK->GetLocation());
  BOP->Mangle();
  return BOP;
}

ASTBinaryOpNode *ASTProductionFactory::ProductionRule_600(
    const ASTToken *TK, const ASTIdentifierNode *Id, ASTOpType OTy) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");

  if (OTy != ASTOpTypePreDec && OTy != ASTOpTypePreInc) {
    std::stringstream M;
    M << "Invalid use of Production Rule for ASTOpType "
      << PrintDashOpTypeEnum(OTy) << '.';
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTBinaryOpNode::ExpressionError(M.str(), OTy);
  }

  ASTScopeController::Instance().CheckOutOfScope(Id);

  std::stringstream ES;
  ES << "binary-op-" << PrintDashOpTypeEnum(OTy) << '-'
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTOperatorNode *OPX =
      Id->HasExpression()
          ? ASTBuilder::Instance().CreateASTOperatorNode(Id->GetExpression(),
                                                         OTy)
          : ASTBuilder::Instance().CreateASTOperatorNode(Id, OTy);
  assert(OPX && "Failed to create valid ASTOperatorNode!");

  ASTIntNode *IN = OTy == ASTOpTypePreDec ? new ASTIntNode(int32_t(-1))
                                          : new ASTIntNode(uint32_t(1));
  assert(IN && "Failed to create a valid ASTIntNode!");

  ASTBinaryOpNode *BOP = ASTBuilder::Instance().CreateASTBinaryOpNode(
      ES.str(), OPX, IN, ASTOpTypeAdd);
  if (!BOP) {
    std::stringstream M;
    M << "Could not create a valid ASTBinaryOpNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTBinaryOpNode::ExpressionError(M.str(), OTy);
  }

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  BOP->SetDeclarationContext(CTX);
  BOP->SetLocation(TK->GetLocation());
  BOP->Mangle();
  return BOP;
}

ASTBinaryOpNode *ASTProductionFactory::ProductionRule_601(
    const ASTToken *TK, const ASTExpressionNode *EX, ASTOpType OTy) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(EX && "Invalid ASTExpressionNode argument!");

  if (OTy != ASTOpTypePreDec && OTy != ASTOpTypePreInc) {
    std::stringstream M;
    M << "Invalid use of Production Rule for ASTOpType "
      << PrintDashOpTypeEnum(OTy) << '.';
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTBinaryOpNode::ExpressionError(M.str(), OTy);
  }

  std::stringstream ES;
  ES << "binary-op-" << PrintDashOpTypeEnum(OTy) << '-'
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTOperatorNode *OPX = ASTBuilder::Instance().CreateASTOperatorNode(EX, OTy);
  assert(OPX && "Failed to create a valid ASTOperatorNode!");

  ASTIntNode *IN = OTy == ASTOpTypePreDec ? new ASTIntNode(int32_t(-1))
                                          : new ASTIntNode(uint32_t(1));
  assert(IN && "Failed to create a valid ASTIntNode!");

  ASTBinaryOpNode *BOP = ASTBuilder::Instance().CreateASTBinaryOpNode(
      ES.str(), OPX, IN, ASTOpTypeAdd);
  if (!BOP) {
    std::stringstream M;
    M << "Could not create a valid ASTBinaryOpNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTBinaryOpNode::ExpressionError(M.str(), OTy);
  }

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  BOP->SetDeclarationContext(CTX);
  BOP->SetLocation(TK->GetLocation());
  BOP->Mangle();
  return BOP;
}

ASTBinaryOpNode *ASTProductionFactory::ProductionRule_602(
    const ASTToken *TK, const ASTIdentifierNode *Id, ASTOpType OTy) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");

  if (OTy != ASTOpTypePostDec && OTy != ASTOpTypePostInc) {
    std::stringstream M;
    M << "Invalid use of Production Rule for ASTOpType "
      << PrintDashOpTypeEnum(OTy) << '.';
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTBinaryOpNode::ExpressionError(M.str(), OTy);
  }

  ASTScopeController::Instance().CheckOutOfScope(Id);

  std::stringstream ES;
  ES << "binary-op-" << PrintDashOpTypeEnum(OTy) << '-'
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTOperatorNode *OPX =
      Id->HasExpression()
          ? ASTBuilder::Instance().CreateASTOperatorNode(Id->GetExpression(),
                                                         OTy)
          : ASTBuilder::Instance().CreateASTOperatorNode(Id, OTy);
  assert(OPX && "Failed to create valid ASTOperatorNode!");

  ASTIntNode *IN = OTy == ASTOpTypePostDec ? new ASTIntNode(int32_t(-1))
                                           : new ASTIntNode(uint32_t(1));
  assert(IN && "Failed to create a valid ASTIntNode!");

  ASTBinaryOpNode *BOP = ASTBuilder::Instance().CreateASTBinaryOpNode(
      ES.str(), OPX, IN, ASTOpTypeAdd);
  if (!BOP) {
    std::stringstream M;
    M << "Could not create a valid ASTBinaryOpNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTBinaryOpNode::ExpressionError(M.str(), OTy);
  }

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  BOP->SetDeclarationContext(CTX);
  BOP->SetLocation(TK->GetLocation());
  BOP->Mangle();
  return BOP;
}

ASTBinaryOpNode *ASTProductionFactory::ProductionRule_603(
    const ASTToken *TK, const ASTExpressionNode *EX, ASTOpType OTy) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(EX && "Invalid ASTExpressionNode argument!");

  if (OTy != ASTOpTypePostDec && OTy != ASTOpTypePostInc) {
    std::stringstream M;
    M << "Invalid use of Production Rule for ASTOpType "
      << PrintDashOpTypeEnum(OTy) << '.';
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTBinaryOpNode::ExpressionError(M.str(), OTy);
  }

  std::stringstream ES;
  ES << "binary-op-" << PrintDashOpTypeEnum(OTy) << '-'
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTOperatorNode *OPX = ASTBuilder::Instance().CreateASTOperatorNode(EX, OTy);
  assert(OPX && "Failed to create a valid ASTOperatorNode!");

  ASTIntNode *IN = OTy == ASTOpTypePostDec ? new ASTIntNode(int32_t(-1))
                                           : new ASTIntNode(uint32_t(1));
  assert(IN && "Failed to create a valid ASTIntNode!");

  ASTBinaryOpNode *BOP = ASTBuilder::Instance().CreateASTBinaryOpNode(
      ES.str(), OPX, IN, ASTOpTypeAdd);
  if (!BOP) {
    std::stringstream M;
    M << "Could not create a valid ASTBinaryOpNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTBinaryOpNode::ExpressionError(M.str(), OTy);
  }

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  BOP->SetDeclarationContext(CTX);
  BOP->SetLocation(TK->GetLocation());
  BOP->Mangle();
  return BOP;
}

ASTBinaryOpStatementNode *
ASTProductionFactory::ProductionRule_605(const ASTToken *TK,
                                         ASTBinaryOpNode *BOP) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(BOP && "Invalid ASTBinaryOpNode argument!");

  ASTBinaryOpStatementNode *BON = new ASTBinaryOpStatementNode(BOP);
  assert(BON && "Could not create a valid ASTBinaryOpStatementNode!");

  BON->SetLocation(TK->GetLocation());
  return BON;
}

ASTDurationNode *ASTProductionFactory::ProductionRule_1200(
    const ASTToken *TK, ASTIdentifierNode *DId, ASTStringNode *TS) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DId && "Invalid ASTIdentifierNode argument!");
  assert(TS && "Invalid Time Unit argument!");

  QasmFeatureTester::Instance().ValidateFeature("duration");

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
          DId, ASTDurationNode::DurationBits, ASTTypeDuration)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeDuration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTDurationNode::ExpressionError(M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(DId)) {
    std::stringstream M;
    M << "Declaration " << DId->GetName() << " shadows an "
      << "existing declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTDurationNode::ExpressionError(M.str());
  }

  ASTDurationNode *DRN =
      ASTBuilder::Instance().CreateASTDurationNode(DId, TS->GetValue());
  assert(DRN && "Could not create a valid ASTDurationNode!");

  DRN->SetLocation(TK->GetLocation());
  DRN->SetConstantFolded();
  DRN->Mangle();
  ASTDeclarationNode *DN =
      new ASTDeclarationNode(DId, DRN, ASTTypeDuration, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  return DRN;
}

ASTDurationNode *ASTProductionFactory::ProductionRule_1201(
    const ASTToken *TK, ASTIdentifierNode *DId, ASTDurationOfNode *DON) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DId && "Invalid ASTIdentifierNode argument!");
  assert(DON && "Invalid ASTDurationOfNode argument!");

  QasmFeatureTester::Instance().ValidateFeature("duration");

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
          DId, ASTDurationNode::DurationBits, ASTTypeDuration)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeDuration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTDurationNode::ExpressionError(M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(DId)) {
    std::stringstream M;
    M << "Declaration " << DId->GetName() << " shadows an "
      << "existing declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTDurationNode::ExpressionError(M.str());
  }

  ASTDurationNode *DRN = ASTBuilder::Instance().CreateASTDurationNode(DId, DON);
  assert(DRN && "Could not create a valid ASTDurationNode!");

  DRN->SetLocation(TK->GetLocation());
  DRN->Mangle();
  ASTDeclarationNode *DN =
      new ASTDeclarationNode(DId, DRN, ASTTypeDuration, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  return DRN;
}

ASTDurationNode *ASTProductionFactory::ProductionRule_1202(
    const ASTToken *TK, ASTIdentifierNode *DId, ASTIdentifierNode *Id,
    ASTStringNode *TS) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DId && "Invalid ASTIdentifierNode argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(TS && "Invalid time unit argument!");

  QasmFeatureTester::Instance().ValidateFeature("duration");
  ASTScopeController::Instance().CheckOutOfScope(Id);

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
          DId, ASTDurationNode::DurationBits, ASTTypeDuration)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeDuration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTDurationNode::ExpressionError(M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(DId)) {
    std::stringstream M;
    M << "Declaration " << DId->GetName() << " shadows an "
      << "existing declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTDurationNode::ExpressionError(M.str());
  }

  ASTType ETy = ASTTypeUndefined;
  ASTDurationNode *DRN = nullptr;
  std::string LU = TS->GetValue();
  std::string LS;

  if (ASTIdentifierRefNode *IdR = dynamic_cast<ASTIdentifierRefNode *>(Id)) {
    ASTSymbolTableEntry *LSTE = ASTSymbolTable::Instance().Lookup(IdR);
    assert(LSTE && "ASTIdentifierRefNode has no SymbolTable Entry!");

    if (IdR->IsIndexed()) {
      ETy = LSTE->GetValueType();
      switch (ETy) {
      case ASTTypeDurationArray: {
        ASTDurationArrayNode *DAN = dynamic_cast<ASTDurationArrayNode *>(
            LSTE->GetValue()->GetValue<ASTArrayNode *>());
        assert(DAN && "Could not dynamic_cast to an ASTDurationArrayNode!");

        auto Index = IdR->GetIndex();
        DAN->ValidateIndex(Index, IdR->GetLocation());
        DRN = DAN->GetElement(Index);
        assert(DRN && "Could not obtain a valid ASTDurationNode from "
                      "the ASTDurationArrayNode!");
        LS = DRN->AsString();
      } break;
      case ASTTypeDuration: {
        DRN = LSTE->GetValue()->GetValue<ASTDurationNode *>();
        assert(DRN && "Could not obtain a valid ASTDurationNode!");
        LS = DRN->AsString();
      } break;
      default: {
        std::stringstream M;
        M << "Impossible ASTDurationNode Initialization from an "
          << PrintTypeEnum(ETy) << ".";
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(Id), M.str(),
            DiagLevel::Error);
        return ASTDurationNode::ExpressionError(M.str());
      } break;
      }
    }
  } else {
    ASTSymbolTableEntry *LSTE = ASTSymbolTable::Instance().Lookup(Id);
    assert(LSTE && "ASTIdentifierRefNode has no SymbolTable Entry!");
    ETy = LSTE->GetValueType();
    switch (ETy) {
    case ASTTypeDurationArray: {
      ASTDurationArrayNode *DAN = dynamic_cast<ASTDurationArrayNode *>(
          LSTE->GetValue()->GetValue<ASTArrayNode *>());
      assert(DAN && "Could not dynamic_cast to an ASTDurationArrayNode!");

      auto Index = Id->GetBits();
      DAN->ValidateIndex(Index, Id->GetLocation());
      DRN = DAN->GetElement(Index);
      assert(DRN && "Could not obtain a valid ASTDurationNode from "
                    "the ASTLengthArrayNode!");
      LS = DRN->AsString();
    } break;
    case ASTTypeDuration: {
      DRN = LSTE->GetValue()->GetValue<ASTDurationNode *>();
      assert(DRN && "Could not obtain a valid ASTDurationNode!");
      LS = DRN->AsString();
    } break;
    default: {
      std::stringstream M;
      M << "Impossible ASTDurationNode Initialization from an "
        << PrintTypeEnum(ETy) << ".";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(Id), M.str(),
          DiagLevel::Error);
      return ASTDurationNode::ExpressionError(M.str());
    } break;
    }
  }

  assert(DRN && "Could not obtain a valid ASTDurationNode!");
  assert(LS.length() && "Could not obtain a valid Duration Unit!");

  if (LU != LS) {
    std::stringstream M;
    M << "Length Duration mismatch between LHS Declaration and RHS "
      << "Operand (" << LU << " vs. " << LS << ").";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTDurationNode::ExpressionError(M.str());
  }

  DRN = ASTBuilder::Instance().CreateASTDurationNode(DId, LS);
  assert(DRN && "Could not create a valid ASTDurationNode!");

  DRN->SetLocation(TK->GetLocation());
  DRN->Mangle();
  ASTDeclarationNode *DN =
      new ASTDeclarationNode(DId, DRN, ASTTypeDuration, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  return DRN;
}

ASTDurationNode *ASTProductionFactory::ProductionRule_1203(
    const ASTToken *TK, ASTIdentifierNode *DId, ASTIdentifierNode *Id) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DId && "Invalid ASTIdentifierNode argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");

  QasmFeatureTester::Instance().ValidateFeature("duration");
  ASTScopeController::Instance().CheckOutOfScope(Id);

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(DId)) {
    std::stringstream M;
    M << "Declaration " << DId->GetName() << " shadows an "
      << "existing declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTDurationNode::ExpressionError(M.str());
  }

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
          DId, ASTDurationNode::DurationBits, ASTTypeDuration)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeDuration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTDurationNode::ExpressionError(M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(DId)) {
    std::stringstream M;
    M << "Declaration " << DId->GetName() << " shadows an "
      << "existing declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTDurationNode::ExpressionError(M.str());
  }

  ASTType ETy = ASTTypeUndefined;
  ASTDurationNode *DRN = nullptr;
  std::string LS;

  if (ASTIdentifierRefNode *IdR = dynamic_cast<ASTIdentifierRefNode *>(Id)) {
    ASTSymbolTableEntry *LSTE = ASTSymbolTable::Instance().Lookup(IdR);
    assert(LSTE && "ASTIdentifierRefNode has no SymbolTable Entry!");

    if (IdR->IsIndexed()) {
      ETy = LSTE->GetValueType();
      switch (ETy) {
      case ASTTypeDurationArray: {
        ASTDurationArrayNode *DAN = dynamic_cast<ASTDurationArrayNode *>(
            LSTE->GetValue()->GetValue<ASTArrayNode *>());
        assert(DAN && "Could not dynamic_cast to an ASTLengthArrayNode!");

        auto Index = IdR->GetIndex();
        DAN->ValidateIndex(Index, IdR->GetLocation());
        DRN = DAN->GetElement(Index);
        assert(DRN && "Could not obtain a valid ASTDurationNode from "
                      "the ASTDurationArrayNode!");
        LS = DRN->AsString();
      } break;
      case ASTTypeDuration: {
        DRN = LSTE->GetValue()->GetValue<ASTDurationNode *>();
        assert(DRN && "Could not obtain a valid ASTDurationNode!");
        LS = DRN->AsString();
      } break;
      default: {
        std::stringstream M;
        M << "Impossible ASTDurationNode Initialization from an "
          << PrintTypeEnum(ETy) << ".";
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(DId), M.str(),
            DiagLevel::Error);
        return ASTDurationNode::ExpressionError(M.str());
      } break;
      }
    }
  } else {
    ASTSymbolTableEntry *LSTE = ASTSymbolTable::Instance().Lookup(Id);
    assert(LSTE && "ASTIdentifierRefNode has no SymbolTable Entry!");
    ETy = LSTE->GetValueType();
    switch (ETy) {
    case ASTTypeDurationArray: {
      ASTDurationArrayNode *DAN = dynamic_cast<ASTDurationArrayNode *>(
          LSTE->GetValue()->GetValue<ASTArrayNode *>());
      assert(DAN && "Could not dynamic_cast to an ASTLengthArrayNode!");

      auto Index = Id->GetBits();
      DAN->ValidateIndex(Index, Id->GetLocation());
      DRN = DAN->GetElement(Index);
      assert(DRN && "Could not obtain a valid ASTDurationNode from "
                    "the ASTDurationArrayNode!");
      LS = DRN->AsString();
    } break;
    case ASTTypeDuration: {
      DRN = LSTE->GetValue()->GetValue<ASTDurationNode *>();
      assert(DRN && "Could not obtain a valid ASTDurationNode!");
      LS = DRN->AsString();
    } break;
    default: {
      std::stringstream M;
      M << "Impossible ASTDurationNode Initialization from an "
        << PrintTypeEnum(ETy) << ".";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(DId), M.str(),
          DiagLevel::Error);
      return ASTDurationNode::ExpressionError(M.str());
    } break;
    }
  }

  assert(DRN && "Could not obtain a valid ASTDurationNode!");
  assert(LS.length() && "Could not obtain a valid Duration Unit!");

  DRN = ASTBuilder::Instance().CreateASTDurationNode(DId, LS);
  assert(DRN && "Could not create a valid ASTDurationNode!");

  DRN->SetLocation(TK->GetLocation());
  DRN->Mangle();
  ASTDeclarationNode *DN =
      new ASTDeclarationNode(DId, DRN, ASTTypeDuration, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  return DRN;
}

ASTDurationNode *ASTProductionFactory::ProductionRule_1204(
    const ASTToken *TK, ASTIdentifierNode *DId, ASTBinaryOpNode *BOP) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DId && "Invalid ASTIdentifierNode argument!");
  assert(BOP && "Invalid ASTBinaryOpNode argument!");

  QasmFeatureTester::Instance().ValidateFeature("duration");

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
          DId, ASTDurationNode::DurationBits, ASTTypeDuration)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeDuration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTDurationNode::ExpressionError(M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(DId)) {
    std::stringstream M;
    M << "Declaration " << DId->GetName() << " shadows an "
      << "existing declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTDurationNode::ExpressionError(M.str());
  }

  ASTDurationNode *DRN = ASTBuilder::Instance().CreateASTDurationNode(DId, BOP);
  assert(DRN && "Could not create a valid ASTDurationNode!");

  DRN->SetLocation(TK->GetLocation());
  DRN->Mangle();
  ASTDeclarationNode *DN =
      new ASTDeclarationNode(DId, DRN, ASTTypeDuration, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  return DRN;
}

ASTDurationNode *ASTProductionFactory::ProductionRule_1205(
    const ASTToken *TK, ASTIdentifierNode *DId,
    ASTFunctionCallStatementNode *FC) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DId && "Invalid ASTIdentifierNode argument!");
  assert(FC && "Invalid ASTFunctionCallStatementNode argument!");

  QasmFeatureTester::Instance().ValidateFeature("duration");

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
          DId, ASTDurationNode::DurationBits, ASTTypeDuration)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeDuration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTDurationNode::ExpressionError(M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(DId)) {
    std::stringstream M;
    M << "Declaration " << DId->GetName() << " shadows an "
      << "existing declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTDurationNode::ExpressionError(M.str());
  }

  const ASTFunctionCallNode *EN = FC->GetFunctionCall();
  assert(EN && "Could not obtain a valid ASTFunctionCallNode!");

  if (!EN->ReturnsResult()) {
    std::stringstream M;
    M << "Assignment requires a non-void return type.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDurationNode::ExpressionError(M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(DId)) {
    std::stringstream M;
    M << "Declaration " << DId->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTDurationNode::ExpressionError(M.str());
  }

  ASTDurationNode *DRN = ASTBuilder::Instance().CreateASTDurationNode(DId, EN);
  assert(DRN && "Could not create a valid ASTDurationNode!");

  DRN->SetLocation(TK->GetLocation());
  DRN->Mangle();
  ASTDeclarationNode *DN =
      new ASTDeclarationNode(DId, DRN, ASTTypeDuration, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  return DRN;
}

ASTDeclarationNode *
ASTProductionFactory::ProductionRule_1206(const ASTToken *TK,
                                          ASTDurationNode *DN) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DN && "Invalid ASTDurationNode argument!");

  QasmFeatureTester::Instance().ValidateFeature("duration");

  ASTDeclarationNode *DDN =
      new ASTDeclarationNode(DN->GetIdentifier(), DN, ASTTypeDuration, false);
  assert(DDN && "Could not create a valid ASTDeclarationNode!");

  DDN->SetLocation(TK->GetLocation());
  ASTDeclarationBuilder::Instance().Append(DDN);
  return DDN;
}

ASTDeclarationNode *
ASTProductionFactory::ProductionRule_1207(const ASTToken *TK,
                                          ASTDurationOfNode *DON) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DON && "Invalid ASTDurationOfNode argument!");

  QasmFeatureTester::Instance().ValidateFeature("durationof");

  ASTDeclarationNode *DN =
      new ASTDeclarationNode(DON->GetIdentifier(), ASTTypeDurationOf);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDurationNode *
ASTProductionFactory::ProductionRule_1209(const ASTToken *TK,
                                          const ASTStringNode *DSN) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DSN && "Invalid ASTStringNode argument!");

  QasmFeatureTester::Instance().ValidateFeature("duration");

  std::stringstream DSI;
  DSI << "ast-duration-argument-"
      << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      DSI.str(), ASTDurationNode::DurationBits, ASTTypeDuration);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());
  Id->SetLocalScope();

  ASTDurationNode *DN =
      ASTBuilder::Instance().CreateASTDurationNode(Id, DSN->GetValue());
  assert(DN && "Could not create a valid ASTDurationNode!");

  DN->SetLocation(TK->GetLocation());
  DN->Mangle();

  ASTSymbolTableEntry *STE = ASTSymbolTable::Instance().Lookup(
      Id, ASTDurationNode::DurationBits, ASTTypeDuration);
  assert(STE && "ASTDurationNode has no SymbolTable Entry!");

  STE->SetLocalScope();
  return DN;
}

ASTDurationOfNode *
ASTProductionFactory::ProductionRule_1250(const ASTToken *TK,
                                          const ASTIdentifierNode *TId) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(TId && "Invalid ASTIdentifierNode argument!");

  QasmFeatureTester::Instance().ValidateFeature("durationof");
  ASTScopeController::Instance().CheckOutOfScope(TId);

  switch (TId->GetSymbolType()) {
  case ASTTypeGate:
  case ASTTypeCXGate:
  case ASTTypeCCXGate:
  case ASTTypeCNotGate:
  case ASTTypeHadamardGate:
  case ASTTypeUGate:
  case ASTTypeDefcal:
  case ASTTypeDefcalGroup:
  case ASTTypeBox:
  case ASTTypeBoxAs:
  case ASTTypeBoxTo:
    break;
  default: {
    std::stringstream M;
    M << "Target durationof operand can only be a gate, defcal or box.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTDurationOfNode::StatementError(M.str());
  } break;
  }

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  std::stringstream IS;
  IS << "ast-durationof-operator-"
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      IS.str(), ASTDurationOfNode::DurationOfBits, ASTTypeDurationOf);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  Id->SetDeclarationContext(CTX);
  Id->SetLocation(TK->GetLocation());

  ASTSymbolTableEntry *STE =
      ASTSymbolTable::Instance().Lookup(Id, Id->GetBits(), Id->GetSymbolType());
  assert(STE && "Could not retrieve a valid SymbolTable Entry!");

  Id->SetPolymorphicName(ASTDemangler::TypeName(Id->GetSymbolType()));
  ASTDurationOfNode *DON =
      ASTBuilder::Instance().CreateASTDurationOfNode(Id, TId);
  assert(DON && "Could not create a valid ASTDurationOfNode!");

  DON->SetDeclarationContext(CTX);
  DON->SetLocation(TK->GetLocation());
  DON->Mangle();
  return DON;
}

ASTDurationOfNode *
ASTProductionFactory::ProductionRule_1251(const ASTToken *TK,
                                          ASTGateQOpNode *QOP) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(QOP && "Invalid ASTGateQOpNode argument!");

  QasmFeatureTester::Instance().ValidateFeature("durationof");

  const ASTIdentifierNode *TId = QOP->GetOperand();
  assert(TId && "Invalid ASTIdentifierNode operand!");

  switch (QOP->GetOpASTType()) {
  case ASTTypeGate:
  case ASTTypeCXGate:
  case ASTTypeCCXGate:
  case ASTTypeCNotGate:
  case ASTTypeHadamardGate:
  case ASTTypeUGate:
  case ASTTypeDefcal:
  case ASTTypeDefcalGroup:
    break;
  default: {
    std::stringstream M;
    M << "Target durationof operand can only be a gate or a defcal.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTDurationOfNode::StatementError(M.str());
  } break;
  }

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  std::stringstream IS;
  IS << "ast-durationof-operator-"
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      IS.str(), ASTDurationOfNode::DurationOfBits, ASTTypeDurationOf);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  Id->SetDeclarationContext(CTX);
  Id->SetLocation(TK->GetLocation());

  ASTSymbolTableEntry *STE =
      ASTSymbolTable::Instance().Lookup(Id, Id->GetBits(), Id->GetSymbolType());
  assert(STE && "Could not retrieve a valid SymbolTable Entry!");

  Id->SetPolymorphicName(ASTDemangler::TypeName(Id->GetSymbolType()));
  ASTDurationOfNode *DON =
      ASTBuilder::Instance().CreateASTDurationOfNode(Id, QOP);
  assert(DON && "Could not create a valid ASTDurationOfNode!");

  DON->SetDeclarationContext(CTX);
  DON->SetLocation(TK->GetLocation());
  DON->Mangle();
  return DON;
}

ASTDelayNode *
ASTProductionFactory::ProductionRule_1300(const ASTToken *TK,
                                          const ASTIdentifierNode *DId) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DId && "Invalid ASTIdentifierNode argument!");

  ASTScopeController::Instance().CheckUndefined(DId);
  ASTScopeController::Instance().CheckOutOfScope(DId);

  std::stringstream S;
  S << "ast-delay-node-"
    << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      S.str(), ASTDelayNode::DelayBits, ASTTypeDelay);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  Id->SetPolymorphicName(ASTDemangler::TypeName(Id->GetSymbolType()));
  Id->SetLocation(TK->GetLocation());

  ASTDelayNode *DN = ASTBuilder::Instance().CreateASTDelayNode(Id, DId);
  assert(DN && "Could not create a valid ASTDelayNode!");

  if (!DN) {
    std::stringstream M;
    M << "Could not create a valid ASTDelayNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTDelayNode::ExpressionError(M.str());
  }

  DN->SetLocation(TK->GetLocation());
  DN->Mangle();
  return DN;
}

ASTDelayNode *
ASTProductionFactory::ProductionRule_1300(const ASTToken *TK,
                                          const ASTStringNode *TS,
                                          const ASTIdentifierList *IL) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(TS && "Invalid ASTStringNode argument!");
  assert(IL && "Invalid ASTIdentifierList argument!");

  for (ASTIdentifierList::const_iterator I = IL->begin(); I != IL->end(); ++I) {
    ASTIdentifierTypeController::Instance().CheckIdentifier(*I);
    ASTScopeController::Instance().CheckOutOfScope(*I);
  }

  std::stringstream S;
  S << "ast-delay-node-"
    << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      S.str(), ASTDelayNode::DelayBits, ASTTypeDelay);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  Id->SetPolymorphicName(ASTDemangler::TypeName(Id->GetSymbolType()));
  Id->SetLocation(TK->GetLocation());

  // This ASTIdentifierNode represents the TimeUnit. It has a Type
  // but it will never have a SymbolTable Entry. Which is why it
  // is created directly instead of through ASTBuilder.
  ASTIdentifierNode *TId =
      new ASTIdentifierNode(TS->GetValue(), ASTTypeTimeUnit, 64U);
  assert(TId && "Could not create a valid ASTIdentifierNode!");

  TId->SetLocation(TK->GetLocation());

  ASTDelayNode *DN =
      ASTBuilder::Instance().CreateASTDelayNode(Id, TId, *IL, TS->GetValue());
  assert(DN && "Could not create a valid ASTDelayNode!");

  if (!DN) {
    std::stringstream M;
    M << "Could not create a valid ASTDelayNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTDelayNode::ExpressionError(M.str());
  }

  DN->SetLocation(TK->GetLocation());
  DN->Mangle();
  return DN;
}

ASTDelayNode *
ASTProductionFactory::ProductionRule_1300(const ASTToken *TK,
                                          const ASTStringNode *TS) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(TS && "Invalid ASTStringNode argument!");

  ASTIdentifierList IL;
  std::stringstream S;
  S << "ast-delay-node-"
    << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      S.str(), ASTDelayNode::DelayBits, ASTTypeDelay);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());
  Id->SetPolymorphicName(ASTDemangler::TypeName(Id->GetSymbolType()));

  // This ASTIdentifierNode represents the TimeUnit. It has a Type
  // but it will never have a SymbolTable Entry. Which is why it
  // is created directly instead of through ASTBuilder.
  ASTIdentifierNode *TId =
      new ASTIdentifierNode(TS->GetValue(), ASTTypeTimeUnit, 64U);
  assert(TId && "Could not create a valid ASTIdentifierNode!");

  TId->SetLocation(TK->GetLocation());

  ASTDelayNode *DN =
      ASTBuilder::Instance().CreateASTDelayNode(Id, TId, IL, TS->GetValue());
  assert(DN && "Could not create a valid ASTDelayNode!");

  if (!DN) {
    std::stringstream M;
    M << "Could not create a valid ASTDelayNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTDelayNode::ExpressionError(M.str());
  }

  DN->SetLocation(TK->GetLocation());
  DN->Mangle();
  return DN;
}

ASTDelayNode *
ASTProductionFactory::ProductionRule_1300(const ASTToken *TK,
                                          const ASTDurationOfNode *DON) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DON && "Invalid ASTDurationNode argument!");

  std::stringstream S;
  S << "ast-delay-node-"
    << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      S.str(), ASTDelayNode::DelayBits, ASTTypeDelay);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());
  Id->SetPolymorphicName(ASTDemangler::TypeName(Id->GetSymbolType()));

  ASTIdentifierList IL;
  ASTDelayNode *DN = ASTBuilder::Instance().CreateASTDelayNode(Id, DON, IL);
  assert(DN && "Could not create a valid ASTDelayNode!");

  if (!DN) {
    std::stringstream M;
    M << "Could not create a valid ASTDelayNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTDelayNode::ExpressionError(M.str());
  }

  DN->SetLocation(TK->GetLocation());
  DN->Mangle();
  return DN;
}

ASTDelayNode *
ASTProductionFactory::ProductionRule_1300(const ASTToken *TK,
                                          const ASTDurationOfNode *DON,
                                          const ASTIdentifierList *IL) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DON && "Invalid ASTDurationNode argument!");
  assert(IL && "Invalid ASTIdentifierList argument!");

  for (ASTIdentifierList::const_iterator I = IL->begin(); I != IL->end(); ++I) {
    ASTIdentifierTypeController::Instance().CheckIdentifier(*I);
    ASTScopeController::Instance().CheckOutOfScope(*I);
  }

  std::stringstream S;
  S << "ast-delay-node-"
    << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      S.str(), ASTDelayNode::DelayBits, ASTTypeDelay);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());
  Id->SetPolymorphicName(ASTDemangler::TypeName(Id->GetSymbolType()));

  ASTDelayNode *DN = ASTBuilder::Instance().CreateASTDelayNode(Id, DON, *IL);
  assert(DN && "Could not create a valid ASTDelayNode!");

  if (!DN) {
    std::stringstream M;
    M << "Could not create a valid ASTDelayNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTDelayNode::ExpressionError(M.str());
  }

  DN->SetLocation(TK->GetLocation());
  DN->Mangle();
  return DN;
}

ASTDelayNode *
ASTProductionFactory::ProductionRule_1300(const ASTToken *TK,
                                          const ASTIdentifierNode *DId,
                                          const ASTIdentifierList *IL) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DId && "Invalid ASTIdentifierNode argument!");
  assert(IL && "Invalid ASTIdentifierList argument!");

  for (ASTIdentifierList::const_iterator I = IL->begin(); I != IL->end(); ++I) {
    ASTIdentifierTypeController::Instance().CheckIdentifier(*I);
    ASTScopeController::Instance().CheckOutOfScope(*I);
  }

  std::stringstream S;
  S << "ast-delay-node-"
    << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      S.str(), ASTDelayNode::DelayBits, ASTTypeDelay);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());
  Id->SetPolymorphicName(ASTDemangler::TypeName(Id->GetSymbolType()));

  ASTSymbolTableEntry *STE = ASTSymbolTable::Instance().Lookup(
      DId, DId->GetBits(), DId->GetSymbolType());
  assert(STE && "Could not retrieve a valid Delay SymbolTable Entry!");

  ASTDelayNode *DN = nullptr;

  switch (STE->GetValueType()) {
  case ASTTypeBinaryOp: {
    ASTBinaryOpNode *BOP = STE->GetValue()->GetValue<ASTBinaryOpNode *>();
    assert(BOP && "Invalid SymbolTable Entry for Delay ASTBinaryOpNode!");
    DN = ASTBuilder::Instance().CreateASTDelayNode(Id, BOP);
  } break;
  case ASTTypeUnaryOp: {
    ASTUnaryOpNode *UOP = STE->GetValue()->GetValue<ASTUnaryOpNode *>();
    assert(UOP && "Invalid SymbolTable Entry for Delay ASTUnaryOpNode!");
    DN = ASTBuilder::Instance().CreateASTDelayNode(Id, UOP);
  } break;
  case ASTTypeDuration: {
    ASTDurationNode *DDN = STE->GetValue()->GetValue<ASTDurationNode *>();
    assert(DDN && "Invalid SymbolTable Entry for Delay ASTDurationNode!");
    DN = ASTBuilder::Instance().CreateASTDelayNode(Id, DDN, *IL);
  } break;
  case ASTTypeDurationOf: {
    ASTDurationOfNode *DON = STE->GetValue()->GetValue<ASTDurationOfNode *>();
    assert(DON && "Invalid SymbolTable Entry for Delay ASTLengthNode!");
    DN = ASTBuilder::Instance().CreateASTDelayNode(Id, DON, *IL);
  } break;
  default:
    DN = ASTBuilder::Instance().CreateASTDelayNode(Id, DId, *IL);
    break;
  }

  assert(DN && "Could not create a valid ASTDelayNode!");

  if (!DN) {
    std::stringstream M;
    M << "Could not create a valid ASTDelayNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTDelayNode::ExpressionError(M.str());
  }

  DN->SetLocation(TK->GetLocation());
  DN->Mangle();
  return DN;
}

ASTDelayNode *
ASTProductionFactory::ProductionRule_1300(const ASTToken *TK,
                                          const ASTBinaryOpNode *BOP) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(BOP && "Invalid ASTBinaryOpNode argument!");

  std::stringstream S;
  S << "ast-delay-node-"
    << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      S.str(), ASTDelayNode::DelayBits, ASTTypeDelay);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());
  Id->SetPolymorphicName(ASTDemangler::TypeName(Id->GetSymbolType()));

  ASTDelayNode *DN = ASTBuilder::Instance().CreateASTDelayNode(Id, BOP);
  assert(DN && "Could not create a valid ASTDelayNode!");

  if (!DN) {
    std::stringstream M;
    M << "Could not create a valid ASTDelayNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTDelayNode::ExpressionError(M.str());
  }

  DN->SetLocation(TK->GetLocation());
  DN->Mangle();
  return DN;
}

ASTDelayNode *
ASTProductionFactory::ProductionRule_1300(const ASTToken *TK,
                                          const ASTUnaryOpNode *UOP) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(UOP && "Invalid ASTUnaryOpNode argument!");

  std::stringstream S;
  S << "ast-delay-node-"
    << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      S.str(), ASTDelayNode::DelayBits, ASTTypeDelay);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());
  Id->SetPolymorphicName(ASTDemangler::TypeName(Id->GetSymbolType()));

  ASTDelayNode *DN = ASTBuilder::Instance().CreateASTDelayNode(Id, UOP);
  assert(DN && "Could not create a valid ASTDelayNode!");

  if (!DN) {
    std::stringstream M;
    M << "Could not create a valid ASTDelayNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTDelayNode::ExpressionError(M.str());
  }

  DN->SetLocation(TK->GetLocation());
  DN->Mangle();
  return DN;
}

ASTDelayNode *
ASTProductionFactory::ProductionRule_1300(const ASTToken *TK,
                                          const ASTIdentifierNode *TId,
                                          const ASTIdentifierNode *QId) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(TId && "Invalid ASTIdentifierNode argument!");
  assert(QId && "Invalid ASTIdentifierNode argument!");

  ASTIdentifierTypeController::Instance().CheckIdentifier(TId);
  ASTIdentifierTypeController::Instance().CheckIdentifier(QId);
  ASTScopeController::Instance().CheckOutOfScope(TId);
  ASTScopeController::Instance().CheckOutOfScope(QId);

  std::stringstream S;
  S << "ast-delay-node-"
    << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      S.str(), ASTDelayNode::DelayBits, ASTTypeDelay);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());
  Id->SetPolymorphicName(ASTDemangler::TypeName(Id->GetSymbolType()));

  ASTDelayNode *DN = ASTBuilder::Instance().CreateASTDelayNode(Id, TId, QId);
  assert(DN && "Could not create a valid ASTDelayNode!");

  if (!DN) {
    std::stringstream M;
    M << "Could not create a valid ASTDelayNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTDelayNode::ExpressionError(M.str());
  }

  DN->SetLocation(TK->GetLocation());
  DN->Mangle();
  return DN;
}

ASTDelayStatementNode *
ASTProductionFactory::ProductionRule_1300(const ASTToken *TK,
                                          const ASTDelayNode *DN) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DN && "Invalid ASTDelayNode argument!");

  ASTDelayStatementNode *DSN =
      new ASTDelayStatementNode(DN->GetIdentifier(), DN);
  if (!DSN) {
    std::stringstream M;
    M << "Could not create a valid ASTDelayStatementNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTDelayStatementNode::StatementError(M.str());
  }

  DSN->SetLocation(TK->GetLocation());
  DSN->Mangle();
  return DSN;
}

ASTStretchNode *
ASTProductionFactory::ProductionRule_1350(const ASTToken *TK,
                                          const ASTIdentifierNode *DId) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DId && "Invalid ASTIdentifierNode argument!");

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
          DId, ASTStretchNode::StretchBits, ASTTypeStretch)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for "
      << PrintTypeEnum(DId->GetSymbolType()) << '.';
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(), DiagLevel::ICE);
    return ASTStretchNode::ExpressionError(DId, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(DId)) {
    std::stringstream M;
    M << "Declaration " << DId->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(),
        DiagLevel::Error);
    return ASTStretchNode::ExpressionError(DId, M.str());
  }

  ASTStretchNode *SN = ASTBuilder::Instance().CreateASTStretchNode(DId);
  assert(SN && "Could not create a valid ASTStretchNode!");
  if (!SN) {
    std::stringstream M;
    M << "Could not create a valid ASTStretchNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(), DiagLevel::ICE);
    return ASTStretchNode::ExpressionError(DId, M.str());
  }

  SN->SetLocation(TK->GetLocation());
  SN->Mangle();

  ASTDeclarationNode *DSN =
      new ASTDeclarationNode(DId, SN, ASTTypeStretch, false);
  assert(DSN && "Could not create a valid Stretch ASTDeclarationNode!");
  if (!DSN) {
    std::stringstream M;
    M << "Could not create a valid Stretch ASTDeclarationNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(), DiagLevel::ICE);
    return ASTStretchNode::ExpressionError(DId, M.str());
  }

  ASTDeclarationBuilder::Instance().Append(DSN);

  ASTStretchStatementNode *SSN = new ASTStretchStatementNode(SN);
  assert(SSN && "Could not create a valid ASTStretchStatementNode!");
  if (!SSN) {
    std::stringstream M;
    M << "Could not create a valid ASTStretchStatementNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(), DiagLevel::ICE);
    return ASTStretchNode::ExpressionError(DId, M.str());
  }

  ASTStatementBuilder::Instance().Append(SSN);
  return SN;
}

ASTStretchStatementNode *
ASTProductionFactory::ProductionRule_1350(const ASTToken *TK,
                                          const ASTStretchNode *SN) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(SN && "Invalid ASTStretchNode argument!");

  ASTStretchStatementNode *SSN = new ASTStretchStatementNode(SN);
  assert(SSN && "Could not create a valid ASTStretchStatementNode!");
  if (!SSN) {
    std::stringstream M;
    M << "Could not create a valid ASTStretchStatementNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTStretchStatementNode::StatementError(M.str());
  }

  SSN->SetLocation(TK->GetLocation());
  SSN->Mangle();
  return SSN;
}

ASTBoxStatementNode *
ASTProductionFactory::ProductionRule_1400(const ASTToken *TK,
                                          const ASTIdentifierNode *Id,
                                          const ASTStatementList *SL) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(SL && "Invalid ASTStatementList argument!");

  if (!ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
          Id, ASTBoxExpressionNode::BoxBits, ASTTypeBox)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for "
      << PrintTypeEnum(Id->GetSymbolType()) << '.';
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
    return ASTBoxStatementNode::StatementError(Id, M.str());
  }

  ASTBoxExpressionNode *BX =
      ASTBuilder::Instance().CreateASTBoxExpressionNode(Id, *SL);
  assert(BX && "Could not create a valid ASTBoxExpressionNode!");
  if (!BX) {
    std::stringstream M;
    M << "Could not create a valid ASTBoxExpressionNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
    return ASTBoxStatementNode::StatementError(Id, M.str());
  }

  BX->SetLocation(TK->GetLocation());
  BX->Mangle();

  ASTBoxStatementNode *BXSN = new ASTBoxStatementNode(BX);
  assert(BXSN && "Could not create a valid ASTBoxStatementNode!");
  if (!BXSN) {
    std::stringstream M;
    M << "Could not create a valid ASTBoxStatementNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
    return ASTBoxStatementNode::StatementError(Id, M.str());
  }

  BXSN->SetLocation(TK->GetLocation());
  BXSN->Mangle();
  return BXSN;
}

ASTBoxStatementNode *
ASTProductionFactory::ProductionRule_1401(const ASTToken *TK,
                                          const ASTIdentifierNode *Id,
                                          const ASTStatementList *SL) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(SL && "Invalid ASTStatementList argument!");

  if (!ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
          Id, ASTBoxExpressionNode::BoxBits, ASTTypeBox)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for "
      << PrintTypeEnum(Id->GetSymbolType()) << '.';
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
    return ASTBoxStatementNode::StatementError(Id, M.str());
  }

  ASTBoxAsExpressionNode *BXA =
      ASTBuilder::Instance().CreateASTBoxAsExpressionNode(Id, *SL);
  assert(BXA && "Could not create a valid ASTBoxAsExpressionNode!");
  if (!BXA) {
    std::stringstream M;
    M << "Could not create a valid ASTBoxAsExpressionNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
    return ASTBoxStatementNode::StatementError(Id, M.str());
  }

  BXA->SetLocation(TK->GetLocation());
  BXA->Mangle();

  ASTBoxStatementNode *BXSN = new ASTBoxStatementNode(BXA);
  assert(BXSN && "Could not create a valid ASTBoxStatementNode!");
  if (!BXSN) {
    std::stringstream M;
    M << "Could not create a valid ASTBoxStatementNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
    return ASTBoxStatementNode::StatementError(Id, M.str());
  }

  BXSN->SetLocation(TK->GetLocation());
  BXSN->Mangle();
  return BXSN;
}

ASTBoxStatementNode *
ASTProductionFactory::ProductionRule_1402(const ASTToken *TK,
                                          const ASTStringNode *TS,
                                          const ASTStatementList *SL) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(TS && "Invalid ASTStringNode argument!");
  assert(SL && "Invalid ASTStatementList argument!");

  std::stringstream S;
  S << "ast-box-to-" << DIAGLineCounter::Instance().GetIdentifierLocation();
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      S.str(), ASTBoxToExpressionNode::BoxToBits, ASTTypeBoxTo);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());

  ASTBoxToExpressionNode *BXT =
      ASTBuilder::Instance().CreateASTBoxToExpressionNode(Id, TS->GetValue(),
                                                          *SL);
  assert(BXT && "Could not create a valid ASTBoxToExpressionNode!");
  if (!BXT) {
    std::stringstream M;
    M << "Could not create a valid ASTBoxToExpressionNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
    return ASTBoxStatementNode::StatementError(Id, M.str());
  }

  BXT->SetLocation(TK->GetLocation());
  BXT->Mangle();

  ASTBoxStatementNode *BXSN = new ASTBoxStatementNode(BXT);
  assert(BXSN && "Could not create a valid ASTBoxStatementNode!");
  if (!BXSN) {
    std::stringstream M;
    M << "Could not create a valid ASTBoxStatementNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
    return ASTBoxStatementNode::StatementError(Id, M.str());
  }

  BXSN->SetLocation(TK->GetLocation());
  BXSN->Mangle();
  return BXSN;
}

ASTDeclarationNode *
ASTProductionFactory::ProductionRule_1100(const ASTToken *TK,
                                          const ASTIdentifierNode *DId) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DId && "Invalid ASTIdentifierNode argument!");

  unsigned Bits = DId->GetBits() == 0 ? 1 : DId->GetBits();
  DId->SetBits(Bits);
  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
          DId, Bits, ASTTypeQubitContainer)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeQubitContainer.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(DId)) {
    std::stringstream M;
    M << "Declaration " << DId->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  ASTQubitContainerNode *QCN =
      ASTBuilder::Instance().CreateASTQubitContainerNode(DId, Bits);
  assert(QCN && "Could not create a valid ASTQubitContainerNode!");

  QCN->SetLocation(DId->GetLocation());
  QCN->Mangle();
  ASTDeclarationNode *DN =
      new ASTDeclarationNode(DId, QCN, ASTTypeQubitContainer, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *
ASTProductionFactory::ProductionRule_1101(const ASTToken *TK,
                                          const ASTIdentifierNode *DId,
                                          const ASTIntNode *BI) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DId && "Invalid ASTIdentifierNode argument!");
  assert(BI && "Invalid ASTIntegerNode argument!");

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(BI);
  assert(!ASTIdentifierNode::InvalidBits(Bits) &&
         "Invalid number of bits for ASTQubitContainerNode!");

  DId->SetBits(Bits);
  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
          DId, Bits, ASTTypeQubitContainer)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeQubitContainer.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(DId)) {
    std::stringstream M;
    M << "Declaration " << DId->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  ASTQubitContainerNode *QCN =
      ASTBuilder::Instance().CreateASTQubitContainerNode(DId, Bits);
  assert(QCN && "Could not create a valid ASTQubitContainerNode!");

  QCN->SetLocation(DId->GetLocation());
  QCN->Mangle();
  ASTDeclarationNode *DN =
      new ASTDeclarationNode(DId, QCN, ASTTypeQubitContainer, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *
ASTProductionFactory::ProductionRule_1102(const ASTToken *TK,
                                          const ASTIdentifierNode *DId,
                                          const ASTIdentifierNode *IXd) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DId && "Invalid ASTIdentifierNode argument!");
  assert(IXd && "Invalid Qubit Index ASTIdentifierNode!");

  ASTScopeController::Instance().CheckUndefined(IXd);
  ASTScopeController::Instance().CheckOutOfScope(IXd);

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(IXd);
  assert(!ASTIdentifierNode::InvalidBits(Bits) &&
         "Invalid number of bits for Index Identifier!");

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
          DId, Bits, ASTTypeQubitContainer)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeQubitContainer.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(DId)) {
    std::stringstream M;
    M << "Declaration " << DId->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  ASTQubitContainerNode *QCN =
      ASTBuilder::Instance().CreateASTQubitContainerNode(DId, Bits);
  assert(QCN && "Could not create a valid ASTQubitContainerNode!");

  QCN->SetLocation(DId->GetLocation());
  QCN->Mangle();
  ASTDeclarationNode *DN =
      new ASTDeclarationNode(DId, QCN, ASTTypeQubitContainer, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *
ASTProductionFactory::ProductionRule_1103(const ASTToken *TK,
                                          const ASTIdentifierNode *DId,
                                          const ASTExpressionNode *EN) const {
  assert(DId && "Invalid ASTIdentifierNode argument!");
  assert(EN && "Invalid ASTExpressionNode argument!");

  if (DId->IsReference() && DId->IsUnresolvedLValue())
    DId = const_cast<ASTIdentifierNode *>(DId->GetIdentifier());

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
          DId, 1, ASTTypeQubitContainer)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeQubitContainer.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(DId)) {
    std::stringstream M;
    M << "Declaration " << DId->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  const ASTIdentifierNode *QId = EN->GetIdentifier();

  if (!QId) {
    std::stringstream M;
    M << "Qubits cannot be initialized from an "
      << PrintTypeEnum(EN->GetASTType()) << " expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  ASTSymbolTableEntry *STE = ASTSymbolTable::Instance().Lookup(
      QId, QId->GetBits(), QId->GetSymbolType());
  assert(STE && "Could not retrieve a valid SymbolTable Entry!");
  assert(STE->HasValue() && "SymbolTable Entry has no Value!");

  ASTQubitContainerNode *QCN = nullptr;

  switch (STE->GetValueType()) {
  case ASTTypeQubitArray: {
    ASTQubitArrayNode *QAN = dynamic_cast<ASTQubitArrayNode *>(
        STE->GetValue()->GetValue<ASTArrayNode *>());
    assert(QAN && "Could not retrieve a valid ASTQubitArrayNode!");

    auto Index = QId->GetBits();
    QAN->ValidateIndex(Index, QId->GetLocation());
    QCN = QAN->GetElement(Index);
    assert(QCN && "Could not dynamic_cast to an ASTQubitContainerNode!");
  } break;
  case ASTTypeQubitContainer: {
    QCN = STE->GetValue()->GetValue<ASTQubitContainerNode *>();
    assert(QCN && "Could not obtain a valid ASTQubitContainerNode!");
  } break;
  case ASTTypeQubit: {
    ASTQubitNode *QN = STE->GetValue()->GetValue<ASTQubitNode *>();
    if (QN) {
      QCN = new ASTQubitContainerNode(QN->GetIdentifier(), 1U);
      assert(QCN && "Could not create a valid ASTQubitContainerNode!");
    } else {
      QCN = STE->GetValue()->GetValue<ASTQubitContainerNode *>();
      assert(QCN && "Could not obtain a valid ASTQubitContainerNode!");
    }
  } break;
  default: {
    std::stringstream M;
    M << "Impossible initialization assignment of an ASTQubitContainer "
      << "from an " << PrintTypeEnum(STE->GetValueType()) << ".";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  } break;
  }

  if (!QCN) {
    std::stringstream M;
    M << "Impossible initialization assignment of an ASTQubitContainer "
      << "from an " << PrintTypeEnum(STE->GetValueType()) << ".";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  // Qubits cannot be copied. This is a shallow clone of the same
  // Qubits as the LHS.
  ASTQubitContainerNode *NQCN =
      ASTBuilder::Instance().CreateASTQubitContainerNode(DId, 1,
                                                         QCN->CloneQubits());
  assert(NQCN && "Could not create a valid ASTQubitContainerNode!");

  NQCN->SetLocation(DId->GetLocation());
  NQCN->Mangle();
  ASTDeclarationNode *DN =
      new ASTDeclarationNode(DId, NQCN, ASTTypeQubitContainer, false);
  assert(DN && "Could not create a valid ASTQubitContainerNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *ASTProductionFactory::ProductionRule_1104(
    const ASTToken *TK, const ASTIdentifierNode *DId,
    const ASTFunctionCallStatementNode *FC) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DId && "Invalid ASTIdentifierNode argument!");
  assert(FC && "Invalid ASTFunctionCallStatementNode argument!");

  const ASTFunctionCallNode *EN = FC->GetFunctionCall();
  assert(EN && "Could not obtain a valid ASTFunctionCallNode!");

  std::stringstream M;
  M << "A Function cannot return Qubits.";
  QasmDiagnosticEmitter::Instance().EmitDiagnostic(
      DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
  return ASTDeclarationNode::DeclarationError(DId, M.str());
}

ASTDeclarationNode *ASTProductionFactory::ProductionRule_1105(
    const ASTToken *TK, const ASTIdentifierNode *DId, const ASTIntNode *IXd,
    const ASTExpressionNode *EN) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DId && "Invalid ASTIdentifierNode argument!");
  assert(IXd && "Invalid ASTIntNode Qubit Size argument!");
  assert(EN && "Invalid ASTExpressionNode argument!");

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(IXd);
  assert(!ASTIdentifierNode::InvalidBits(Bits) && "Invalid number of bits!");

  if (DId->IsReference() && DId->IsUnresolvedLValue()) {
    DId = const_cast<ASTIdentifierNode *>(DId->GetIdentifier());
    Bits = DId->GetBits();
    assert(!ASTIdentifierNode::InvalidBits(Bits) && "Invalid number of bits!");
  }

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
          DId, Bits, ASTTypeQubitContainer)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeQubitContainer.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(DId)) {
    std::stringstream M;
    M << "Declaration " << DId->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  const ASTIdentifierNode *QId = EN->GetIdentifier();

  if (!QId) {
    std::stringstream M;
    M << "Qubits cannot be initialized from an "
      << PrintTypeEnum(EN->GetASTType()) << " expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  ASTSymbolTableEntry *STE = ASTSymbolTable::Instance().Lookup(
      QId, QId->GetBits(), QId->GetSymbolType());
  assert(STE && "Could not retrieve a valid SymbolTable Entry!");
  assert(STE->HasValue() && "SymbolTable Entry has no Value!");

  switch (STE->GetValueType()) {
  case ASTTypeQubit:
  case ASTTypeQubitContainer:
    break;
  default: {
    std::stringstream M;
    M << "Impossible initialization assignment for an ASTQubitContainer "
      << "from an " << PrintTypeEnum(STE->GetValueType());
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  } break;
  }

  ASTQubitContainerNode *QCN = nullptr;

  if (QId->IsReference()) {
    if (const ASTIdentifierRefNode *QIdR =
            dynamic_cast<const ASTIdentifierRefNode *>(QId)) {
      const ASTSymbolTableEntry *QSTE = QIdR->GetSymbolTableEntry();
      assert(QSTE &&
             "Invalid SymbolTable Entry obtained from ASTIdentifierRefNode!");

      QCN = QSTE->GetValue()->GetValue<ASTQubitContainerNode *>();
    }
  } else {
    QCN = STE->GetValue()->GetValue<ASTQubitContainerNode *>();
  }

  assert(QCN && "Could not dynamic_cast to an ASTQubitContainerNode!");

  // Qubits cannot be copied. This is a shallow clone of the same
  // Qubits as the LHS.
  ASTQubitContainerNode *NQCN =
      ASTBuilder::Instance().CreateASTQubitContainerNode(DId, Bits,
                                                         QCN->CloneQubits());
  assert(NQCN && "Could not create a valid ASTQubitContainerNode!");

  NQCN->SetLocation(DId->GetLocation());
  NQCN->Mangle();
  ASTDeclarationNode *DN =
      new ASTDeclarationNode(DId, NQCN, ASTTypeQubitContainer, false);
  assert(DN && "Could not create a valid ASTQubitContainerNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *ASTProductionFactory::ProductionRule_1106(
    const ASTToken *TK, const ASTIdentifierNode *DId,
    const ASTIdentifierNode *IXd, const ASTExpressionNode *EN) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DId && "Invalid ASTIdentifierNode argument!");
  assert(IXd && "Invalid ASTIdentifierNode Size argument!");
  assert(EN && "Invalid ASTExpressionNode argument!");

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(IXd);
  assert(!ASTIdentifierNode::InvalidBits(Bits) && "Invalid number of bits!");

  if (DId->IsReference() && DId->IsUnresolvedLValue()) {
    DId = const_cast<ASTIdentifierNode *>(DId->GetIdentifier());
    Bits = DId->GetBits();
    assert(!ASTIdentifierNode::InvalidBits(Bits) && "Invalid number of bits!");
  }

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
          DId, Bits, ASTTypeQubitContainer)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeQubitContainer.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(DId)) {
    std::stringstream M;
    M << "Declaration " << DId->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  const ASTIdentifierNode *QId = EN->GetIdentifier();

  if (!QId) {
    std::stringstream M;
    M << "Qubits cannot be initialized from an "
      << PrintTypeEnum(EN->GetASTType()) << " expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  ASTSymbolTableEntry *STE = ASTSymbolTable::Instance().Lookup(
      QId, QId->GetBits(), QId->GetSymbolType());
  assert(STE && "Could not retrieve a valid SymbolTable Entry!");
  assert(STE->HasValue() && "SymbolTable Entry has no Value!");

  ASTQubitContainerNode *QCN = nullptr;

  switch (STE->GetValueType()) {
  case ASTTypeQubitArray: {
    ASTQubitArrayNode *QAN = dynamic_cast<ASTQubitArrayNode *>(
        STE->GetValue()->GetValue<ASTArrayNode *>());
    assert(QAN && "Could not retrieve a valid ASTQubitArrayNode!");

    auto Index = QId->GetBits();
    QAN->ValidateIndex(Index, QId->GetLocation());
    QCN = QAN->GetElement(Index);
    assert(QCN && "Could not dynamic_cast to an ASTQubitContainerNode!");
  } break;
  case ASTTypeQubitContainer: {
    QCN = STE->GetValue()->GetValue<ASTQubitContainerNode *>();
    assert(QCN && "Could not obtain a valid ASTQubitContainerNode!");
  } break;
  case ASTTypeQubit: {
    ASTQubitNode *QN = STE->GetValue()->GetValue<ASTQubitNode *>();
    if (QN) {
      QCN = new ASTQubitContainerNode(QN->GetIdentifier(), 1U);
      assert(QCN && "Could not create a valid ASTQubitContainerNode!");
    } else {
      QCN = STE->GetValue()->GetValue<ASTQubitContainerNode *>();
      assert(QCN && "Could not obtain a valid ASTQubitContainerNode!");
    }
  } break;
  default: {
    std::stringstream M;
    M << "Impossible initialization assignment of an ASTQubitContainer "
      << "from an " << PrintTypeEnum(STE->GetValueType()) << ".";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  } break;
  }

  if (!QCN) {
    std::stringstream M;
    M << "Impossible initialization assignment of an ASTQubitContainer "
      << "from an " << PrintTypeEnum(STE->GetValueType()) << ".";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(DId, M.str());
  }

  assert(QCN && "Could not dynamic_cast to an ASTQubitContainerNode!");

  // Qubits cannot be copied. This is a shallow clone of the same
  // Qubits as the LHS.
  ASTQubitContainerNode *NQCN =
      ASTBuilder::Instance().CreateASTQubitContainerNode(DId, Bits,
                                                         QCN->CloneQubits());
  assert(NQCN && "Could not create a valid ASTQubitContainerNode!");

  NQCN->SetLocation(DId->GetLocation());
  NQCN->Mangle();
  ASTDeclarationNode *DN =
      new ASTDeclarationNode(DId, NQCN, ASTTypeQubitContainer, false);
  assert(DN && "Could not create a valid ASTQubitContainerNode!");

  DN->SetLocation(TK->GetLocation());
  ASTStatementBuilder::Instance().Append(DN);
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *ASTProductionFactory::ProductionRule_1150(
    const ASTIdentifierNode *AId, const std::string *QN, const std::string *FIX,
    ASTIntegerList *IL) const {
  assert(AId && "Invalid ASTIdentifierNode argument!");
  assert(IL && "Invalid ASTIntegerList argument!");
  assert(QN && "Invalid string argument!");
  assert(FIX && "Invalid string argument!");

  IL->Prepend(std::stoi(*FIX));
  unsigned ABits = static_cast<unsigned>(IL->Size());

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
          AId, ABits, ASTTypeQubitContainerAlias)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for "
         "ASTTypeQubitContainerAlias.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(AId), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(AId, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(AId)) {
    std::stringstream M;
    M << "Declaration " << AId->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(AId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(AId, M.str());
  }

  const ASTIdentifierNode *QId = ASTSymbolTable::Instance().LookupQubit(*QN);
  if (!QId) {
    std::stringstream M;
    M << "Non-existent Qubit " << *QN << '.';
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(AId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(AId, M.str());
  }

  ASTSymbolTableEntry *TSTE = ASTSymbolTable::Instance().Lookup(QId);
  assert(TSTE && "Target ASTQubitContainer has no SymbolTable Entry!");
  assert(TSTE->HasValue() && "SymbolTableEntry for ASTQubitContainer "
                             "has no Value!");

  const ASTIdentifierNode *TId = TSTE->GetIdentifier();
  assert(TId && "Invalid ASTIdentifierNode for ASTQubitContainer!");

  if (TSTE->GetValueType() != ASTTypeQubitContainer &&
      TSTE->GetValueType() != ASTTypeQubitContainerAlias) {
    std::stringstream M;
    M << "Identifier " << TId->GetName() << " is neither a Qubit Container "
      << "nor a Qubit Container Alias.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(TId, M.str());
  }

  ASTSymbolTableEntry *ASTE = ASTSymbolTable::Instance().Lookup(
      AId, AId->GetBits(), AId->GetSymbolType());
  assert(ASTE && "Invalid SymbolTable Entry for ASTQubitContainerAlias!");

  ASTDeclarationNode *DN = nullptr;

  if (TSTE->GetValueType() == ASTTypeQubitContainer) {
    ASTQubitContainerNode *QCN =
        TSTE->GetValue()->GetValue<ASTQubitContainerNode *>();
    assert(QCN && "Could not retrieve a valid ASTQubitContainerNode "
                  "from the SymbolTable Entry!");

    ASTQubitContainerAliasNode *QCAN = QCN->CreateAlias(AId, *IL, ',');
    assert(QCAN && "Could not create a valid ASTQubitContainerAliasNode!");

    QCAN->SetLocation(AId->GetLocation());
    QCAN->Mangle();
    ASTE->ResetValue();
    ASTE->SetValue(new ASTValue<>(QCAN, ASTTypeQubitContainerAlias),
                   ASTTypeQubitContainerAlias);
    assert(ASTE->HasValue() && "Container SymbolTable Entry has no Value!");

    DN = new ASTDeclarationNode(AId, QCAN, ASTTypeQubitContainerAlias, false);
    assert(DN && "Could not create a valid ASTDeclarationNode!");

    DN->SetLocation(AId->GetLocation());
    ASTDeclarationBuilder::Instance().Append(DN);
  } else if (TSTE->GetValueType() == ASTTypeQubitContainerAlias) {
    ASTQubitContainerAliasNode *SQCAN =
        TSTE->GetValue()->GetValue<ASTQubitContainerAliasNode *>();
    assert(SQCAN && "Could not retrieve a valid ASTQubitContainerAliasNode "
                    "from the SymbolTable Entry!");

    ASTQubitContainerAliasNode *TQCAN = SQCAN->CreateAlias(AId, *IL, ',');
    assert(TQCAN && "Could not create a valid ASTQubitContainerAliasNode!");

    TQCAN->SetLocation(AId->GetLocation());
    TQCAN->Mangle();
    ASTE->ResetValue();
    ASTE->SetValue(new ASTValue<>(TQCAN, ASTTypeQubitContainerAlias),
                   ASTTypeQubitContainerAlias);
    DN = new ASTDeclarationNode(AId, TQCAN, ASTTypeQubitContainerAlias, false);
    assert(DN && "Could not create a valid ASTDeclarationNode!");

    DN->SetLocation(AId->GetLocation());
    ASTDeclarationBuilder::Instance().Append(DN);
  }

  ASTIdentifierTypeController::Instance().Reset();

  if (!DN) {
    std::stringstream M;
    M << "Identifier " << AId->GetName() << " represents a type that "
      << "cannot be aliased.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(AId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(AId, M.str());
  }

  return DN;
}

ASTDeclarationNode *ASTProductionFactory::ProductionRule_1151(
    const ASTIdentifierNode *AId, const std::string *QN, const std::string *FIX,
    ASTIntegerList *IL) const {
  assert(AId && "Invalid ASTIdentifierNode argument!");
  assert(IL && "Invalid ASTIntegerList argument!");
  assert(QN && "Invalid string argument!");
  assert(FIX && "Invalid string argument!");

  IL->Prepend(std::stoi(*FIX));
  unsigned ABits = static_cast<unsigned>(IL->Size());

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
          AId, ABits, ASTTypeQubitContainerAlias)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for "
         "ASTTypeQubitContainerAlias.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(AId), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(AId, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(AId)) {
    std::stringstream M;
    M << "Declaration " << AId->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(AId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(AId, M.str());
  }

  ASTSymbolTableEntry *ASTE = ASTSymbolTable::Instance().Lookup(
      AId, AId->GetBits(), AId->GetSymbolType());
  assert(ASTE && "Invalid SymbolTable Entry for ASTQubitContainerAlias!");

  const ASTIdentifierNode *QId = ASTSymbolTable::Instance().LookupQubit(*QN);
  if (!QId) {
    std::stringstream M;
    M << "Non-existent Qubit " << *QN << '.';
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(AId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(AId, M.str());
  }

  ASTSymbolTableEntry *TSTE = ASTSymbolTable::Instance().Lookup(QId);
  assert(TSTE && "Invalid SymbolTable Entry for ASTQubitContainer!");

  const ASTIdentifierNode *TId = TSTE->GetIdentifier();
  assert(TId && "Invalid ASTIdentifierNode for ASTQubitContainer!");
  assert(TSTE->HasValue() && "SymbolTableEntry for ASTQubitContainer "
                             "has no Value!");

  if (TSTE->GetValueType() != ASTTypeQubitContainer &&
      TSTE->GetValueType() != ASTTypeQubitContainerAlias) {
    std::stringstream M;
    M << "Identifier " << TId->GetName() << " is neither a Qubit Container "
      << "nor a Qubit Container Alias.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(AId, M.str());
  }

  ASTDeclarationNode *DN = nullptr;

  if (TSTE->GetValueType() == ASTTypeQubitContainer) {
    ASTQubitContainerNode *QCN =
        TSTE->GetValue()->GetValue<ASTQubitContainerNode *>();
    assert(QCN && "Could not retrieve a valid ASTQubitContainerNode "
                  "from the SymbolTable Entry!");

    ASTQubitContainerAliasNode *QCAN = QCN->CreateAlias(AId, *IL, ':');
    assert(QCAN && "Could not create a valid ASTQubitContainerAliasNode!");

    QCAN->SetLocation(AId->GetLocation());
    QCAN->Mangle();
    ASTE->ResetValue();
    ASTE->SetValue(new ASTValue<>(QCAN, ASTTypeQubitContainerAlias),
                   ASTTypeQubitContainerAlias);

    DN = new ASTDeclarationNode(AId, QCAN, ASTTypeQubitContainerAlias, false);
    assert(DN && "Could not create a valid ASTDeclarationNode!");

    DN->SetLocation(AId->GetLocation());
    ASTDeclarationBuilder::Instance().Append(DN);
  } else if (TSTE->GetValueType() == ASTTypeQubitContainerAlias) {
    ASTQubitContainerAliasNode *SQCAN =
        TSTE->GetValue()->GetValue<ASTQubitContainerAliasNode *>();
    assert(SQCAN && "Could not retrieve a valid ASTQubitContainerAliasNode "
                    "from the SymbolTable Entry!");

    ASTQubitContainerAliasNode *TQCAN = SQCAN->CreateAlias(AId, *IL, ':');
    assert(TQCAN && "Could not create a valid ASTQubitContainerAliasNode!");

    TQCAN->SetLocation(AId->GetLocation());
    TQCAN->Mangle();
    ASTE->ResetValue();
    ASTE->SetValue(new ASTValue<>(TQCAN, ASTTypeQubitContainerAlias),
                   ASTTypeQubitContainerAlias);

    DN = new ASTDeclarationNode(AId, TQCAN, ASTTypeQubitContainerAlias, false);
    assert(DN && "Could not create a valid ASTDeclarationNode!");

    DN->SetLocation(AId->GetLocation());
    ASTDeclarationBuilder::Instance().Append(DN);
  }

  ASTIdentifierTypeController::Instance().Reset();

  if (!DN) {
    std::stringstream M;
    M << "Identifier " << AId->GetName() << " represents a type that "
      << "cannot be aliased.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(AId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(AId, M.str());
  }

  return DN;
}

ASTDeclarationNode *
ASTProductionFactory::ProductionRule_1152(const ASTIdentifierNode *AId,
                                          const std::string *QN,
                                          ASTArraySubscriptNode *ASN) const {
  assert(AId && "Invalid QubitAlias ASTIdentifierNode!");
  assert(QN && "Invalid std::string argument!");
  assert(ASN && "Invalid ASTArraySubscriptNode argument!");

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
          AId, 1U, ASTTypeQubitContainerAlias)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for "
         "ASTTypeQubitContainerAlias.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(AId), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(AId, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(AId)) {
    std::stringstream M;
    M << "Declaration " << AId->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(AId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(AId, M.str());
  }

  ASTSymbolTableEntry *ASTE =
      ASTSymbolTable::Instance().Lookup(AId, 1U, ASTTypeQubitContainerAlias);
  assert(ASTE && "Invalid SymbolTable Entry for QubitAlias Identifier!");

  // We don't know yet if this is a QubitContainer or a QubitContainerAlias.
  const ASTIdentifierNode *QId = ASTSymbolTable::Instance().LookupQubit(*QN);
  if (!QId) {
    std::stringstream M;
    M << "Non-existent Qubit " << *QN << '.';
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(AId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(AId, M.str());
  }

  ASTSymbolTableEntry *TSTE = ASTSymbolTable::Instance().Lookup(QId);
  assert(TSTE && "Invalid SymbolTable Entry for ASTQubitContainer!");

  const ASTIdentifierNode *TId = TSTE->GetIdentifier();
  assert(TId && "Invalid ASTIdentifierNode for SymbolTable Entry!");
  assert(TSTE->HasValue() && "Target SymbolTable Entry has no Value!");

  if (TSTE->GetValueType() != ASTTypeQubitContainer &&
      TSTE->GetValueType() != ASTTypeQubitContainerAlias) {
    std::stringstream M;
    M << "Identifier " << TId->GetName() << " is neither a Qubit Container "
      << "nor a Qubit Container Alias.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(AId, M.str());
  }

  int32_t BitIndex = ASN->GetSignedIndexValue();
  ASTDeclarationNode *DN = nullptr;

  if (TSTE->GetValueType() == ASTTypeQubitContainer) {
    ASTQubitContainerNode *QCN =
        TSTE->GetValue()->GetValue<ASTQubitContainerNode *>();
    assert(QCN && "Could not retrieve a valid ASTQubitContainerNode "
                  "from the SymbolTable Entry!");

    ASTQubitContainerAliasNode *QCAN =
        ASTBuilder::Instance().CreateASTQubitContainerAliasNode(AId, QCN,
                                                                BitIndex);
    QCN->CreateAlias(AId, BitIndex);
    assert(QCAN && "Could not create a valid ASTQubitContainerAliasNode!");

    QCAN->SetLocation(AId->GetLocation());
    QCAN->Mangle();
    ASTE->ResetValue();
    ASTE->SetValue(new ASTValue<>(QCAN, ASTTypeQubitContainerAlias),
                   ASTTypeQubitContainerAlias);

    DN = new ASTDeclarationNode(AId, QCAN, ASTTypeQubitContainerAlias, false);
    assert(DN && "Could not create a valid ASTDeclarationNode!");

    DN->SetLocation(AId->GetLocation());
    ASTDeclarationBuilder::Instance().Append(DN);
  } else if (TSTE->GetValueType() == ASTTypeQubitContainerAlias) {
    ASTQubitContainerAliasNode *SQCAN =
        TSTE->GetValue()->GetValue<ASTQubitContainerAliasNode *>();
    assert(SQCAN && "Could not retrieve a valid ASTQubitContainerAliasNode "
                    " from the SymbolTable Entry!");

    ASTQubitContainerAliasNode *TQCAN =
        ASTBuilder::Instance().CreateASTQubitContainerAliasNode(AId, SQCAN,
                                                                BitIndex);
    assert(TQCAN && "Could not create a valid ASTQubitContainerAliasNode!");

    TQCAN->SetLocation(AId->GetLocation());
    TQCAN->Mangle();
    ASTE->ResetValue();
    ASTE->SetValue(new ASTValue<>(TQCAN, ASTTypeQubitContainerAlias),
                   ASTTypeQubitContainerAlias);

    DN = new ASTDeclarationNode(AId, TQCAN, ASTTypeQubitContainerAlias, false);
    assert(DN && "Could not create a valid ASTDeclarationNode!");

    DN->SetLocation(AId->GetLocation());
    ASTDeclarationBuilder::Instance().Append(DN);
  }

  ASTIdentifierTypeController::Instance().Reset();

  if (!DN) {
    std::stringstream M;
    M << "Identifier " << AId->GetName() << " represents a type that "
      << "cannot be aliased.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(AId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(AId, M.str());
  }

  return DN;
}

ASTDeclarationNode *
ASTProductionFactory::ProductionRule_1153(const ASTIdentifierNode *AId,
                                          const ASTIdentifierNode *QId,
                                          ASTQubitConcatList *QCL) const {
  assert(AId && "Invalid ASTIdentifierNode argument!");
  assert(QId && "Invalid ASTIdentifierNode argument!");
  assert(QCL && "Invalid ASTQubitConcatList argument!");

  const unsigned QCABits = ASTQubitContainerAliasNode::QubitContainerAliasBits;
  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
          AId, QCABits, ASTTypeQubitContainerAlias)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for "
         "ASTTypeQubitContainerAlias.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(AId), M.str(), DiagLevel::ICE);
    return ASTDeclarationNode::DeclarationError(AId, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(AId)) {
    std::stringstream M;
    M << "Declaration " << AId->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(AId), M.str(),
        DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(AId, M.str());
  }

  ASTSymbolTableEntry *CASTE = ASTSymbolTable::Instance().Lookup(
      AId, AId->GetBits(), AId->GetSymbolType());
  assert(CASTE && "Could not obtain a valid ASTSymbolTable Entry!");

  ASTSymbolTableEntry *QSTE = ASTSymbolTable::Instance().Lookup(QId);
  assert(QSTE && "Could not obtain a valid ASTSymbolTable Entry!");

  ASTQubitContainerAliasNode *QCA =
      ASTBuilder::Instance().CreateASTQubitContainerAliasNode(AId, int32_t(0));
  assert(QCA && "Could not create a valid ASTQubitContainerAlias!");

  QCA->SetLocation(AId->GetLocation());

  if (QSTE->HasValue()) {
    switch (QSTE->GetValueType()) {
    case ASTTypeQubit:
      QCA->AddQubit(QSTE->GetValue()->GetValue<ASTQubitNode *>());
      break;
    case ASTTypeQubitContainer: {
      ASTQubitContainerNode *QCN =
          QSTE->GetValue()->GetValue<ASTQubitContainerNode *>();
      assert(QCN && "Invalid ASTQubitContainerNode for first Identifier!");

      if (QId->IsReference()) {
        const ASTIdentifierRefNode *QIdR =
            dynamic_cast<const ASTIdentifierRefNode *>(QId);
        assert(QIdR && "Could not obtain a valid ASTIdentifierRefNode!");

        QCA->AddQubit(QCN->GetQubit(QIdR->GetIndex()));
      } else {
        *QCA += *QCN;
      }
    } break;
    case ASTTypeQubitContainerAlias: {
      ASTQubitContainerAliasNode *QCAN =
          QSTE->GetValue()->GetValue<ASTQubitContainerAliasNode *>();
      assert(QCAN &&
             "Invalid ASTQubitContainerAliasNode for first Identifier!");

      if (QId->IsReference()) {
        const ASTIdentifierRefNode *QIdR =
            dynamic_cast<const ASTIdentifierRefNode *>(QId);
        assert(QIdR && "Could not obtain a valid ASTIdentifierRefNode!");

        QCA->AddQubit(QCAN->GetQubit(QIdR->GetIndex()));
      } else {
        *QCA += *QCAN;
      }
    } break;
    default: {
      std::stringstream M;
      M << "Cannot insert an object of type "
        << PrintTypeEnum(QSTE->GetValueType()) << " into a Qubit Alias "
        << "Container.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(AId), M.str(),
          DiagLevel::Error);
      return ASTDeclarationNode::DeclarationError(AId, M.str());
    } break;
    }
  }

  for (ASTQubitConcatList::const_iterator I = QCL->begin(); I != QCL->end();
       ++I) {
    QId = *I;
    assert(QId && "Invalid ASTIdentifierNode iterator!");

    QSTE = ASTSymbolTable::Instance().Lookup(QId, QId->GetBits(),
                                             QId->GetSymbolType());
    assert(QSTE && "Could not obtain a valid SymbolTable Entry!");

    if (QSTE->HasValue()) {
      switch (QSTE->GetValueType()) {
      case ASTTypeQubit:
        QCA->AddQubit(QSTE->GetValue()->GetValue<ASTQubitNode *>());
        break;
      case ASTTypeQubitContainer: {
        ASTQubitContainerNode *QCN =
            QSTE->GetValue()->GetValue<ASTQubitContainerNode *>();
        assert(QCN && "Invalid ASTQubitContainerNode for first Identifier!");

        if (QId->IsReference()) {
          const ASTIdentifierRefNode *QIdR =
              dynamic_cast<const ASTIdentifierRefNode *>(QId);
          assert(QIdR && "Could not obtain a valid ASTIdentifierRefNode!");

          QCA->AddQubit(QCN->GetQubit(QIdR->GetIndex()));
        } else {
          *QCA += *QCN;
        }
      } break;
      case ASTTypeQubitContainerAlias: {
        ASTQubitContainerAliasNode *QCAN =
            QSTE->GetValue()->GetValue<ASTQubitContainerAliasNode *>();
        assert(QCAN &&
               "Invalid ASTQubitContainerAliasNode for first Identifier!");

        if (QId->IsReference()) {
          const ASTIdentifierRefNode *QIdR =
              dynamic_cast<const ASTIdentifierRefNode *>(QId);
          assert(QIdR && "Could not obtain a valid ASTIdentifierRefNode!");

          QCA->AddQubit(QCAN->GetQubit(QIdR->GetIndex()));
        } else {
          *QCA += *QCAN;
        }
      } break;
      default: {
        std::stringstream M;
        M << "An object of type " << PrintTypeEnum(QSTE->GetValueType())
          << " cannot be aliased.";
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(AId), M.str(),
            DiagLevel::Error);
        return ASTDeclarationNode::DeclarationError(AId, M.str());
      } break;
      }
    }
  }

  QCA->ComputeBits();
  QCA->SetLocation(AId->GetLocation());
  QCA->Mangle();
  AId->SetBits(QCA->Size());
  CASTE->ResetValue();
  CASTE->SetValue(new ASTValue<>(QCA, ASTTypeQubitContainerAlias),
                  ASTTypeQubitContainerAlias);
  assert(CASTE->HasValue() && "SymbolTable Entry has no Value!");

  ASTDeclarationNode *DN =
      new ASTDeclarationNode(AId, QCA, ASTTypeQubitContainerAlias, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(AId->GetLocation());
  ASTDeclarationBuilder::Instance().Append(DN);
  QCL->Clear();

  ASTIdentifierTypeController::Instance().Reset();

  return DN;
}

OpenPulse::ASTOpenPulseFrameNode *
ASTProductionFactory::ProductionRule_1700(const ASTToken *TKF,
                                          const ASTIdentifierNode *Id,
                                          const ASTExpressionList *EL) const {
  assert(TKF && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(EL && "Invalid ASTExpressionList argument!");

  QasmFeatureTester::Instance().ValidateFeature("frame");
  OpenPulse::ASTOpenPulseCalibrationBuilder::Instance().ValidateContext();

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  const unsigned Bits = OpenPulse::ASTOpenPulseFrameNode::FrameBits;
  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
          Id, Bits, ASTTypeOpenPulseFrame)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeOpenPulseFrame.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
    return OpenPulse::ASTOpenPulseFrameNode::ExpressionError(Id, M.str());
  }

  Id->SetDeclarationContext(CTX);

  OpenPulse::ASTOpenPulseFrameNode *FN =
      ASTBuilder::Instance().CreateASTOpenPulseFrameNode(Id, EL);
  assert(FN && "Could not create a valid ASTOpenPulseFrameNode!");

  FN->SetLocation(TKF->GetLocation());
  FN->SetDeclarationContext(CTX);
  FN->Mangle();
  return FN;
}

OpenPulse::ASTOpenPulseFrameNode *
ASTProductionFactory::ProductionRule_1701(const ASTToken *TKF,
                                          const ASTIdentifierNode *Id) const {
  assert(TKF && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");

  QasmFeatureTester::Instance().ValidateFeature("frame");
  OpenPulse::ASTOpenPulseCalibrationBuilder::Instance().ValidateContext();

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  const unsigned Bits = OpenPulse::ASTOpenPulseFrameNode::FrameBits;
  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
          Id, Bits, ASTTypeOpenPulseFrame)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeOpenPulseFrame.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
    return OpenPulse::ASTOpenPulseFrameNode::ExpressionError(Id, M.str());
  }

  Id->SetDeclarationContext(CTX);

  ASTExpressionList EL;

  OpenPulse::ASTOpenPulseFrameNode *FN =
      ASTBuilder::Instance().CreateASTOpenPulseFrameNode(Id, &EL);
  assert(FN && "Could not create a valid ASTOpenPulseFrameNode!");

  FN->SetLocation(TKF->GetLocation());
  FN->SetDeclarationContext(CTX);
  FN->SetExtern(true);
  FN->Mangle();
  return FN;
}

OpenPulse::ASTOpenPulseFrameNode *
ASTProductionFactory::ProductionRule_1702(const ASTToken *TKF,
                                          const ASTExpressionList *EL) const {
  assert(TKF && "Invalid ASTToken argument!");
  assert(EL && "Invalid ASTExpressionList argument!");

  QasmFeatureTester::Instance().ValidateFeature("frame");
  OpenPulse::ASTOpenPulseCalibrationBuilder::Instance().ValidateContext();

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  std::stringstream FS;
  FS << "ast-open-pulse-frame-"
     << DIAGLineCounter::Instance().GetIdentifierLocation();

  const unsigned Bits = OpenPulse::ASTOpenPulseFrameNode::FrameBits;
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      FS.str(), Bits, ASTTypeOpenPulseFrame);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
          Id, Bits, ASTTypeOpenPulseFrame)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeOpenPulseFrame.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
    return OpenPulse::ASTOpenPulseFrameNode::ExpressionError(Id, M.str());
  }

  Id->SetDeclarationContext(CTX);
  OpenPulse::ASTOpenPulseFrameNode *FN =
      ASTBuilder::Instance().CreateASTOpenPulseFrameNode(Id, EL);
  assert(FN && "Could not create a valid ASTOpenPulseFrameNode!");

  FN->SetLocation(TKF->GetLocation());
  FN->SetDeclarationContext(CTX);
  FN->Mangle();
  return FN;
}

OpenPulse::ASTOpenPulsePortNode *
ASTProductionFactory::ProductionRule_1710(const ASTToken *TK,
                                          const ASTIdentifierNode *Id) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");

  QasmFeatureTester::Instance().ValidateFeature("port");
  OpenPulse::ASTOpenPulseCalibrationBuilder::Instance().ValidateContext();

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  const unsigned Bits = OpenPulse::ASTOpenPulsePortNode::PortBits;
  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
          Id, Bits, ASTTypeOpenPulsePort)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeOpenPulsePort.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
    return OpenPulse::ASTOpenPulsePortNode::ExpressionError(Id, M.str());
  }

  OpenPulse::ASTOpenPulsePortNode *PN =
      ASTBuilder::Instance().CreateASTOpenPulsePortNode(Id, true);
  assert(PN && "Could not create a valid ASTOpenPulsePortNode!");

  PN->SetLocation(TK->GetLocation());
  PN->SetDeclarationContext(CTX);
  PN->Mangle();
  return PN;
}

OpenPulse::ASTOpenPulseWaveformNode *
ASTProductionFactory::ProductionRule_1720(const ASTToken *TK,
                                          const ASTIdentifierNode *Id,
                                          const ASTExpressionList *EL) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(EL && "Invalid ASTExpressionList argument!");

  QasmFeatureTester::Instance().ValidateFeature("waveform");
  OpenPulse::ASTOpenPulseCalibrationBuilder::Instance().ValidateContext();

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  const unsigned Bits = OpenPulse::ASTOpenPulseWaveformNode::WaveformBits;
  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
          Id, Bits, ASTTypeOpenPulseWaveform)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeOpenPulseWaveform.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
    return OpenPulse::ASTOpenPulseWaveformNode::ExpressionError(Id, M.str());
  }

  ASTMPComplexList CXL(*EL);
  OpenPulse::ASTOpenPulseWaveformNode *WFN =
      ASTBuilder::Instance().CreateASTOpenPulseWaveformNode(Id, CXL);
  assert(WFN && "Could not create a valid OpenPulse ASTOpenPulseWaveformNode!");

  WFN->SetLocation(TK->GetLocation());
  WFN->SetDeclarationContext(CTX);
  WFN->Mangle();
  return WFN;
}

OpenPulse::ASTOpenPulseWaveformNode *ASTProductionFactory::ProductionRule_1721(
    const ASTToken *TK, const ASTIdentifierNode *Id,
    const ASTFunctionCallStatementNode *FC) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(FC && "Invalid ASTFunctionCallStatementNode argument!");

  QasmFeatureTester::Instance().ValidateFeature("waveform");
  OpenPulse::ASTOpenPulseCalibrationBuilder::Instance().ValidateContext();

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  const unsigned Bits = OpenPulse::ASTOpenPulseWaveformNode::WaveformBits;
  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
          Id, Bits, ASTTypeOpenPulseWaveform)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeOpenPulseWaveform.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
    return OpenPulse::ASTOpenPulseWaveformNode::ExpressionError(Id, M.str());
  }

  const ASTFunctionCallNode *EN = FC->GetFunctionCall();
  assert(EN && "Could not obtain a valid ASTFunctionCallNode!");

  if (!EN->ReturnsResult()) {
    std::stringstream M;
    M << "Assignment requires a non-void return type.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return OpenPulse::ASTOpenPulseWaveformNode::ExpressionError(Id, M.str());
  }

  ASTType RTy = EN->GetResult()->GetResultType();
  OpenPulse::ASTOpenPulseWaveformNode *WFN = nullptr;

  switch (RTy) {
  case ASTTypeOpenPulseWaveform: {
    const OpenPulse::ASTOpenPulseWaveformNode *RWFN =
        EN->GetResult()->GetWaveform();
    assert(RWFN && "Invalid ASTWaveformNode obtained from Function Result!");
    WFN = ASTBuilder::Instance().CreateASTOpenPulseWaveformNode(
        Id, RWFN->GetSamples());
    assert(WFN &&
           "Could not create a valid OpenPulse ASTOpenPulseWaveformNode!");
  } break;
  case ASTTypeMPComplex: {
    ASTMPComplexList CXL;
    ASTMPComplexNode *MPC =
        const_cast<ASTMPComplexNode *>(EN->GetResult()->GetMPComplex());
    assert(MPC && "Invalid ASTMPComplexNode obtained from Function Result!");
    CXL.Append(new ASTMPComplexRep(MPC));
    WFN = ASTBuilder::Instance().CreateASTOpenPulseWaveformNode(Id, CXL);
    assert(WFN &&
           "Could not create a valid OpenPulse ASTOpenPulseWaveformNode!");
  } break;
  case ASTTypeComplexList: {
    const ASTMPComplexList *MPCL = EN->GetResult()->GetMPComplexList();
    assert(MPCL && "Invalid ASTMPComplexList obtained from Function Result!");
    WFN = ASTBuilder::Instance().CreateASTOpenPulseWaveformNode(Id, *MPCL);
    assert(WFN &&
           "Could not create a valid OpenPulse ASTOpenPulseWaveformNode!");
  } break;
  case ASTTypeBinaryOp: {
    ASTMPComplexList CXL;
    const ASTBinaryOpNode *BOP = EN->GetResult()->GetBinaryOp();
    assert(BOP && "Invalid ASTBinaryOpNode obtained from Function Result!");
    CXL.Append(new ASTMPComplexRep(BOP));
    WFN = ASTBuilder::Instance().CreateASTOpenPulseWaveformNode(Id, CXL);
    assert(WFN &&
           "Could not create a valid OpenPulse ASTOpenPulseWaveformNode!");
  } break;
  case ASTTypeUnaryOp: {
    ASTMPComplexList CXL;
    const ASTUnaryOpNode *UOP = EN->GetResult()->GetUnaryOp();
    assert(UOP && "Invalid ASTUnaryOpNode obtained from Function Result!");
    CXL.Append(new ASTMPComplexRep(UOP));
    WFN = ASTBuilder::Instance().CreateASTOpenPulseWaveformNode(Id, CXL);
    assert(WFN &&
           "Could not create a valid OpenPulse ASTOpenPulseWaveformNode!");
  } break;
  default: {
    std::stringstream M;
    M << "Impossible initialization of an OpenPulse Waveform "
      << "from Type " << PrintTypeEnum(RTy) << ".";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EN), M.str(), DiagLevel::Error);
    return OpenPulse::ASTOpenPulseWaveformNode::ExpressionError(Id, M.str());
  } break;
  }

  assert(WFN && "Could not create a valid OpenPulse ASTOpenPulseWaveformNode!");

  WFN->SetLocation(TK->GetLocation());
  WFN->SetDeclarationContext(CTX);
  WFN->SetFunctionCall(EN);
  WFN->SetFunctionResult(EN->GetResult());
  WFN->Mangle();
  return WFN;
}

OpenPulse::ASTOpenPulsePlayNode *
ASTProductionFactory::ProductionRule_1730(const ASTToken *TK,
                                          const ASTIdentifierNode *FId,
                                          const ASTExpressionList *EL) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(FId && "Invalid ASTIdentifierNode argument!");
  assert(EL && "Invalid ASTExpressionList argument!");

  QasmFeatureTester::Instance().ValidateFeature("play");
  ASTDefcalBuilder::Instance().ValidateDefcalContext();

  OpenPulse::ASTOpenPulseFrameNode *FN =
      OpenPulse::ASTOpenPulseController::Instance().GetFrameNode(FId);
  assert(FN && "Could not obtain a valid OpenPulse FrameNode!");

  if (!FN) {
    std::stringstream M;
    M << "Invalid or non-existent Frame " << FId->GetName() << '.';
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(FId), M.str(),
        DiagLevel::Error);
    return OpenPulse::ASTOpenPulsePlayNode::ExpressionError(FId, M.str());
  }

  FN->Mangle();
  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  std::stringstream PS;
  PS << "ast-open-pulse-play-"
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  const unsigned PBits = OpenPulse::ASTOpenPulsePlayNode::PlayBits;
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      PS.str(), PBits, ASTTypeOpenPulsePlay);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());
  Id->SetDeclarationContext(CTX);

  ASTMPComplexList CXL(*EL);
  OpenPulse::ASTOpenPulsePlayNode *PN =
      ASTBuilder::Instance().CreateASTOpenPulsePlayNode(Id, CXL, FN);
  assert(PN && "Could not create a valid OpenPulse PlayNode!");

  PN->SetLocation(TK->GetLocation());
  PN->SetDeclarationContext(CTX);
  PN->Mangle();
  return PN;
}

OpenPulse::ASTOpenPulsePlayNode *ASTProductionFactory::ProductionRule_1731(
    const ASTToken *TK, const ASTExpressionList *EL,
    const OpenPulse::ASTOpenPulseFrameNode *FN) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(EL && "Invalid ASTExpressionList argument!");
  assert(FN && "Invalid ASTOpenPulseFrameNode argument!");

  QasmFeatureTester::Instance().ValidateFeature("play");
  ASTDefcalBuilder::Instance().ValidateDefcalContext();

  const_cast<OpenPulse::ASTOpenPulseFrameNode *>(FN)->Mangle();
  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  std::stringstream PS;
  PS << "ast-open-pulse-play-"
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  const unsigned PBits = OpenPulse::ASTOpenPulsePlayNode::PlayBits;
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      PS.str(), PBits, ASTTypeOpenPulsePlay);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());
  Id->SetDeclarationContext(CTX);

  ASTMPComplexList CXL(*EL);
  OpenPulse::ASTOpenPulsePlayNode *PN =
      ASTBuilder::Instance().CreateASTOpenPulsePlayNode(Id, CXL, FN);
  assert(PN && "Could not create a valid OpenPulse PlayNode!");

  PN->SetLocation(TK->GetLocation());
  PN->SetDeclarationContext(CTX);
  PN->Mangle();
  return PN;
}

OpenPulse::ASTOpenPulsePlayNode *ASTProductionFactory::ProductionRule_1732(
    const ASTToken *TK, const OpenPulse::ASTOpenPulseWaveformNode *WN,
    const ASTIdentifierNode *FId) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(WN && "Invalid WaveformNode argument!");
  assert(FId && "Invalid ASTIdentifierNode argument!");

  QasmFeatureTester::Instance().ValidateFeature("play");
  ASTDefcalBuilder::Instance().ValidateDefcalContext();

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  OpenPulse::ASTOpenPulseFrameNode *FN =
      OpenPulse::ASTOpenPulseController::Instance().GetFrameNode(FId);
  assert(FN && "Could not obtain a valid OpenPulse FrameNode!");

  FN->Mangle();

  std::stringstream PS;
  PS << "ast-open-pulse-play-"
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  const unsigned PBits = OpenPulse::ASTOpenPulsePlayNode::PlayBits;
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      PS.str(), PBits, ASTTypeOpenPulsePlay);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());
  Id->SetDeclarationContext(CTX);

  OpenPulse::ASTOpenPulsePlayNode *PN =
      ASTBuilder::Instance().CreateASTOpenPulsePlayNode(Id, WN, FN);
  assert(PN && "Could not create a valid OpenPulse PlayNode!");

  PN->SetLocation(TK->GetLocation());
  PN->SetDeclarationContext(CTX);
  PN->Mangle();
  return PN;
}

OpenPulse::ASTOpenPulsePlayNode *
ASTProductionFactory::ProductionRule_1733(const ASTToken *TK,
                                          const ASTIdentifierNode *WId,
                                          const ASTIdentifierNode *FId) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(WId && "Invalid ASTIdentifierNode argument!");
  assert(FId && "Invalid ASTIdentifierNode argument!");

  QasmFeatureTester::Instance().ValidateFeature("play");
  ASTDefcalBuilder::Instance().ValidateDefcalContext();

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  OpenPulse::ASTOpenPulseWaveformNode *WN =
      OpenPulse::ASTOpenPulseController::Instance().GetWaveformNode(WId);
  if (!WN) {
    std::stringstream M;
    M << "Unknown or invalid ASTOpenPulseWaveform Node " << WId->GetName()
      << '.';
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(WId), M.str(),
        DiagLevel::Error);
    return OpenPulse::ASTOpenPulsePlayNode::ExpressionError(WId, M.str());
  }

  OpenPulse::ASTOpenPulseFrameNode *FN =
      OpenPulse::ASTOpenPulseController::Instance().GetFrameNode(FId);
  if (!FN) {
    std::stringstream M;
    M << "Unknown or invalid ASTOpenPulseFrameNode " << FId->GetName() << '.';
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(FId), M.str(),
        DiagLevel::Error);
    return OpenPulse::ASTOpenPulsePlayNode::ExpressionError(FId, M.str());
  }

  WN->Mangle();
  FN->Mangle();

  std::stringstream PS;
  PS << "ast-open-pulse-play-"
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  const unsigned PBits = OpenPulse::ASTOpenPulsePlayNode::PlayBits;
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      PS.str(), PBits, ASTTypeOpenPulsePlay);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());
  Id->SetDeclarationContext(CTX);

  OpenPulse::ASTOpenPulsePlayNode *PN =
      ASTBuilder::Instance().CreateASTOpenPulsePlayNode(Id, WN, FN);
  assert(PN && "Could not create a valid OpenPulse PlayNode!");

  PN->SetLocation(TK->GetLocation());
  PN->SetDeclarationContext(CTX);
  PN->Mangle();
  return PN;
}

OpenPulse::ASTOpenPulsePlayNode *ASTProductionFactory::ProductionRule_1734(
    const ASTToken *TK, const ASTIdentifierNode *WId,
    const OpenPulse::ASTOpenPulseFrameNode *FN) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(WId && "Invalid ASTIdentifierNode argument!");
  assert(FN && "Invalid ASTOpenPulseFrameNode argument!");

  QasmFeatureTester::Instance().ValidateFeature("play");
  ASTDefcalBuilder::Instance().ValidateDefcalContext();

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  OpenPulse::ASTOpenPulseWaveformNode *WN =
      OpenPulse::ASTOpenPulseController::Instance().GetWaveformNode(WId);
  if (!WN) {
    std::stringstream M;
    M << "Unknown or invalid ASTOpenPulseWaveformNode " << WId->GetName()
      << '.';
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(WId), M.str(),
        DiagLevel::Error);
    return OpenPulse::ASTOpenPulsePlayNode::ExpressionError(WId, M.str());
  }

  WN->Mangle();
  const_cast<OpenPulse::ASTOpenPulseFrameNode *>(FN)->Mangle();

  std::stringstream PS;
  PS << "ast-open-pulse-play-"
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  const unsigned PBits = OpenPulse::ASTOpenPulsePlayNode::PlayBits;
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      PS.str(), PBits, ASTTypeOpenPulsePlay);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());
  Id->SetDeclarationContext(CTX);

  OpenPulse::ASTOpenPulsePlayNode *PN =
      ASTBuilder::Instance().CreateASTOpenPulsePlayNode(Id, WN, FN);
  assert(PN && "Could not create a valid OpenPulse PlayNode!");

  PN->SetLocation(TK->GetLocation());
  PN->SetDeclarationContext(CTX);
  PN->Mangle();
  return PN;
}

OpenPulse::ASTOpenPulsePlayNode *ASTProductionFactory::ProductionRule_1735(
    const ASTToken *TK, const OpenPulse::ASTOpenPulseWaveformNode *WN,
    const OpenPulse::ASTOpenPulseFrameNode *FN) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(WN && "Invalid ASTOpenPulseWaveformNode argument!");
  assert(FN && "Invalid ASTOpenPulseFrameNode argument!");

  QasmFeatureTester::Instance().ValidateFeature("play");
  ASTDefcalBuilder::Instance().ValidateDefcalContext();

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  const_cast<OpenPulse::ASTOpenPulseWaveformNode *>(WN)->Mangle();
  const_cast<OpenPulse::ASTOpenPulseFrameNode *>(FN)->Mangle();

  std::stringstream PS;
  PS << "ast-open-pulse-play-"
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  const unsigned PBits = OpenPulse::ASTOpenPulsePlayNode::PlayBits;
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      PS.str(), PBits, ASTTypeOpenPulsePlay);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());
  Id->SetDeclarationContext(CTX);

  OpenPulse::ASTOpenPulsePlayNode *PN =
      ASTBuilder::Instance().CreateASTOpenPulsePlayNode(Id, WN, FN);
  assert(PN && "Could not create a valid OpenPulse PlayNode!");

  PN->SetLocation(TK->GetLocation());
  PN->SetDeclarationContext(CTX);
  PN->Mangle();
  return PN;
}

OpenPulse::ASTOpenPulsePlayNode *
ASTProductionFactory::ProductionRule_1736(const ASTToken *TK,
                                          const ASTFunctionCallNode *FCN,
                                          const ASTIdentifierNode *FId) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(FCN && "Invalid ASTFunctionCallNode argument!");
  assert(FId && "Invalid ASTIdentifierNode argument!");

  QasmFeatureTester::Instance().ValidateFeature("play");
  ASTDefcalBuilder::Instance().ValidateDefcalContext();

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  OpenPulse::ASTOpenPulseFrameNode *FN =
      OpenPulse::ASTOpenPulseController::Instance().GetFrameNode(FId);
  if (!FN) {
    std::stringstream M;
    M << "Unknown or invalid ASTOpenPulseFrameNode " << FId->GetName() << '.';
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(FId), M.str(),
        DiagLevel::Error);
    return OpenPulse::ASTOpenPulsePlayNode::ExpressionError(FId, M.str());
  }

  const_cast<ASTFunctionCallNode *>(FCN)->Mangle();
  FN->Mangle();

  std::stringstream PS;
  PS << "ast-open-pulse-play-"
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  const unsigned PBits = OpenPulse::ASTOpenPulsePlayNode::PlayBits;
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      PS.str(), PBits, ASTTypeOpenPulsePlay);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());
  Id->SetDeclarationContext(CTX);

  OpenPulse::ASTOpenPulsePlayNode *PN =
      ASTBuilder::Instance().CreateASTOpenPulsePlayNode(Id, FCN, FN);
  assert(PN && "Could not create a valid OpenPulse PlayNode!");

  PN->SetLocation(TK->GetLocation());
  PN->SetDeclarationContext(CTX);
  PN->Mangle();
  return PN;
}

OpenPulse::ASTOpenPulsePlayNode *ASTProductionFactory::ProductionRule_1737(
    const ASTToken *TK, const ASTFunctionCallNode *FCN,
    const OpenPulse::ASTOpenPulseFrameNode *FN) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(FCN && "Invalid ASTFunctionCallNode argument!");
  assert(FN && "Invalid ASTOpenPulseFrameNode argument!");

  QasmFeatureTester::Instance().ValidateFeature("play");
  ASTDefcalBuilder::Instance().ValidateDefcalContext();

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  const_cast<ASTFunctionCallNode *>(FCN)->Mangle();
  const_cast<OpenPulse::ASTOpenPulseFrameNode *>(FN)->Mangle();

  std::stringstream PS;
  PS << "ast-open-pulse-play-"
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  const unsigned PBits = OpenPulse::ASTOpenPulsePlayNode::PlayBits;
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      PS.str(), PBits, ASTTypeOpenPulsePlay);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());
  Id->SetDeclarationContext(CTX);

  OpenPulse::ASTOpenPulsePlayNode *PN =
      ASTBuilder::Instance().CreateASTOpenPulsePlayNode(Id, FCN, FN);
  assert(PN && "Could not create a valid OpenPulse PlayNode!");

  PN->SetLocation(TK->GetLocation());
  PN->SetDeclarationContext(CTX);
  PN->Mangle();
  return PN;
}

OpenPulse::ASTOpenPulseCalibration *
ASTProductionFactory::ProductionRule_1740(const ASTToken *TK,
                                          ASTStatementList *OPSL) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(OPSL && "Invalid ASTStatementList argument!");

  QasmFeatureTester::Instance().ValidateFeature("cal");
  OpenPulse::ASTOpenPulseCalibrationBuilder::Instance().ValidateContext();

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  if (!ASTDeclarationContextTracker::Instance().IsCalibrationContext(CTX)) {
    ASTIdentifierNode *CId =
        new ASTIdentifierNode("calibration-error", ASTTypeOpenPulseCalibration);
    assert(CId && "Could not create a valid ASTIdentifierNode!");

    std::stringstream M;
    M << "A calibration can only be declared within a calibration context.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return OpenPulse::ASTOpenPulseCalibration::ExpressionError(CId, M.str());
  }

  if (!ASTDeclarationContextTracker::Instance().IsGlobalContext(
          CTX->GetParentContext())) {
    ASTIdentifierNode *CId =
        new ASTIdentifierNode("calibration-error", ASTTypeOpenPulseCalibration);
    assert(CId && "Could not create a valid ASTIdentifierNode!");

    std::stringstream M;
    M << "A calibration can only be declared at global context.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return OpenPulse::ASTOpenPulseCalibration::ExpressionError(CId, M.str());
  }

  const_cast<ASTDeclarationContext *>(CTX)->SetContextType(
      ASTTypeOpenPulseCalibration);
  ASTScopeController::Instance().SetLocalScope(OPSL);

  const std::string &DCB = OpenPulse::ASTOpenPulseCalibration::DCB;
  OpenPulse::ASTOpenPulseCalibration *CAL = nullptr;
  ASTSymbolTableEntry *STE =
      ASTSymbolTable::Instance().FindCalibrationBlock(DCB);

  if (STE) {
    CAL = STE->GetValue()->GetValue<OpenPulse::ASTOpenPulseCalibration *>();
    assert(CAL && "Could not obtain a valid global calibration block!");
    ASTScopeController::Instance().SetCalBlockScope(OPSL, DCB);
    CAL->Append(*OPSL);
  } else {
    ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
        DCB, OpenPulse::ASTOpenPulseCalibration::CalibrationBits,
        ASTTypeOpenPulseCalibration);
    assert(Id && "Could not create a valid ASTIdentifierNode!");

    const ASTDeclarationContext *GCX =
        ASTDeclarationContextTracker::Instance().GetGlobalContext();
    assert(GCX && "Could not obtain a valid Global DeclarationContext!");

    CAL = ASTBuilder::Instance().CreateASTOpenPulseCalibration(Id, *OPSL);
    assert(CAL && "Could not create a valid ASTOpenPulseCalibration!");

    CAL->SetDeclarationContext(GCX);
    CAL->Mangle();
  }

  OPSL->Clear();
  ASTDeclarationContextTracker::Instance().PopCurrentContext();
  OpenPulse::ASTOpenPulseCalibrationBuilder::Instance().CloseContext();
  ASTCalContextBuilder::Instance().CloseContext();
  return CAL;
}

ASTDeclarationNode *ASTProductionFactory::ProductionRule_1750(
    const ASTToken *TK, const OpenPulse::ASTOpenPulseFrameNode *FN) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(FN && "Invalid ASTOpenPulseFrameNode argument!");

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  ASTDeclarationNode *DN = new ASTDeclarationNode(FN->GetIdentifier(), FN,
                                                  ASTTypeOpenPulseFrame, false);
  if (!DN) {
    std::stringstream M;
    M << "Could not create a valid ASTDeclarationNode for "
      << PrintTypeEnum(FN->GetASTType()) << '.';
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(FN->GetIdentifier(), M.str());
  }

  DN->SetDeclarationContext(CTX);
  DN->SetLocation(TK->GetLocation());
  return DN;
}

ASTDeclarationNode *ASTProductionFactory::ProductionRule_1751(
    const ASTToken *TK, const OpenPulse::ASTOpenPulsePortNode *PN) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(PN && "Invalid ASTOpenPulsePortNode argument!");

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  ASTDeclarationNode *DN = new ASTDeclarationNode(PN->GetIdentifier(), PN,
                                                  ASTTypeOpenPulsePort, false);
  if (!DN) {
    std::stringstream M;
    M << "Could not create a valid ASTDeclarationNode for "
      << PrintTypeEnum(PN->GetASTType()) << '.';
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(PN->GetIdentifier(), M.str());
  }

  DN->SetDeclarationContext(CTX);
  DN->SetLocation(TK->GetLocation());
  return DN;
}

ASTDeclarationNode *ASTProductionFactory::ProductionRule_1752(
    const ASTToken *TK, const OpenPulse::ASTOpenPulseWaveformNode *WFN) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(WFN && "Invalid ASTOpenPulseWaveformNode argument!");

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  ASTDeclarationNode *DN = new ASTDeclarationNode(
      WFN->GetIdentifier(), WFN, ASTTypeOpenPulseWaveform, false);
  if (!DN) {
    std::stringstream M;
    M << "Could not create a valid ASTDeclarationNode for "
      << PrintTypeEnum(WFN->GetASTType()) << '.';
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(WFN->GetIdentifier(), M.str());
  }

  DN->SetDeclarationContext(CTX);
  DN->SetLocation(TK->GetLocation());
  return DN;
}

OpenPulse::ASTOpenPulsePlayStatementNode *
ASTProductionFactory::ProductionRule_1760(
    const ASTToken *TK, const OpenPulse::ASTOpenPulsePlayNode *PN) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(PN && "Invalid ASTOpenPulsePlayNode argument!");

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  OpenPulse::ASTOpenPulsePlayStatementNode *PSN =
      new OpenPulse::ASTOpenPulsePlayStatementNode(PN);
  if (!PSN) {
    std::stringstream M;
    M << "Could not create a valid ASTOpenPulsePlayStatementNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return OpenPulse::ASTOpenPulsePlayStatementNode::StatementError(
        PN->GetIdentifier(), M.str());
  }

  PSN->SetLocation(TK->GetLocation());
  return PSN;
}

OpenPulse::ASTOpenPulseCalibrationStmt *
ASTProductionFactory::ProductionRule_1761(
    const ASTToken *TK, const OpenPulse::ASTOpenPulseCalibration *CAL) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(CAL && "Invalid ASTOpenPulseCalibration argument!");

  OpenPulse::ASTOpenPulseCalibrationStmt *CSN =
      new OpenPulse::ASTOpenPulseCalibrationStmt(CAL);
  if (!CSN) {
    std::stringstream M;
    M << "Could not create a valid ASTOpenPulseCalibrationStmt.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return OpenPulse::ASTOpenPulseCalibrationStmt::StatementError(
        CAL->GetIdentifier(), M.str());
  }

  CSN->SetLocation(TK->GetLocation());
  return CSN;
}

ASTReturnStatementNode *
ASTProductionFactory::ProductionRule_2000(const ASTToken *TK,
                                          ASTExpressionNode *EN) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(EN && "Invalid ASTExpressionNode argument!");

  QasmFeatureTester::Instance().ValidateFeature("return");

  if (EN->GetASTType() == ASTTypeIdentifier) {
    ASTIdentifierNode *RId = EN->GetIdentifier();
    assert(RId && "Could not obtain a valid ASTIdentifierNode!");
    return ProductionRule_2001(TK, RId);
  }

  std::stringstream RS;
  RS << "ast-return-statement-"
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      RS.str(), ASTReturnStatementNode::ReturnBits, ASTTypeReturn);
  assert(Id && "Could not create a valid Return ASTIdentifierNode!");

  ASTReturnStatementNode *RN =
      ASTBuilder::Instance().CreateASTReturnStatementNode(Id, EN);
  assert(RN && "Could not create a valid ASTReturnStatementNode!");

  RN->SetLocation(TK->GetLocation());
  ASTSymbolTableEntry *STE =
      ASTSymbolTable::Instance().Lookup(Id, Id->GetBits(), Id->GetSymbolType());
  assert(STE && "Invalid SymbolTable Entry for ASTReturnStatementNode!");

  STE->ResetValue();
  STE->SetValue(new ASTValue<>(RN, ASTTypeReturn), ASTTypeReturn);

  RN->Mangle();
  return RN;
}

ASTReturnStatementNode *
ASTProductionFactory::ProductionRule_2001(const ASTToken *TK,
                                          ASTIdentifierNode *RId) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(RId && "Invalid ASTIdentifierNode argument!");

  QasmFeatureTester::Instance().ValidateFeature("return");

  std::stringstream RS;
  RS << "ast-return-statement-"
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      RS.str(), ASTReturnStatementNode::ReturnBits, ASTTypeReturn);
  assert(Id && "Could not create a valid Return ASTIdentifierNode!");

  ASTReturnStatementNode *RN =
      ASTBuilder::Instance().CreateASTReturnStatementNode(Id, RId);
  assert(RN && "Could not create a valid ASTReturnStatementNode!");

  RN->SetLocation(TK->GetLocation());
  ASTSymbolTableEntry *STE =
      ASTSymbolTable::Instance().Lookup(Id, Id->GetBits(), Id->GetSymbolType());
  assert(STE && "Invalid SymbolTable Entry for ASTReturnStatementNode!");

  STE->ResetValue();
  STE->SetValue(new ASTValue<>(RN, ASTTypeReturn), ASTTypeReturn);

  RN->Mangle();
  return RN;
}

ASTReturnStatementNode *
ASTProductionFactory::ProductionRule_2002(const ASTToken *TK,
                                          ASTBinaryOpNode *BOP) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(BOP && "Invalid ASTBinaryOpNode argument!");

  QasmFeatureTester::Instance().ValidateFeature("return");

  std::stringstream RS;
  RS << "ast-return-statement-"
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      RS.str(), ASTReturnStatementNode::ReturnBits, ASTTypeReturn);
  assert(Id && "Could not create a valid Return ASTIdentifierNode!");

  ASTReturnStatementNode *RN =
      ASTBuilder::Instance().CreateASTReturnStatementNode(Id, BOP);
  assert(RN && "Could not create a valid ASTReturnStatementNode!");

  RN->SetLocation(TK->GetLocation());
  ASTSymbolTableEntry *STE =
      ASTSymbolTable::Instance().Lookup(Id, Id->GetBits(), Id->GetSymbolType());
  assert(STE && "Invalid SymbolTable Entry for ASTReturnStatementNode!");

  STE->ResetValue();
  STE->SetValue(new ASTValue<>(RN, ASTTypeReturn), ASTTypeReturn);

  RN->Mangle();
  return RN;
}

ASTReturnStatementNode *ASTProductionFactory::ProductionRule_2003(
    const ASTToken *TK, ASTFunctionCallStatementNode *FSN) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(FSN && "Invalid ASTFunctionCallStatementNode argument!");

  QasmFeatureTester::Instance().ValidateFeature("return");

  std::stringstream RS;
  RS << "ast-return-statement-"
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      RS.str(), ASTReturnStatementNode::ReturnBits, ASTTypeReturn);
  assert(Id && "Could not create a valid Return ASTIdentifierNode!");

  ASTReturnStatementNode *RN =
      ASTBuilder::Instance().CreateASTReturnStatementNode(Id, FSN);
  assert(RN && "Could not create a valid ASTReturnStatementNode!");

  RN->SetLocation(TK->GetLocation());
  ASTSymbolTableEntry *STE =
      ASTSymbolTable::Instance().Lookup(Id, Id->GetBits(), Id->GetSymbolType());
  assert(STE && "Invalid SymbolTable Entry for ASTReturnStatementNode!");

  STE->ResetValue();
  STE->SetValue(new ASTValue<>(RN, ASTTypeReturn), ASTTypeReturn);

  RN->Mangle();
  return RN;
}

ASTReturnStatementNode *
ASTProductionFactory::ProductionRule_2004(const ASTToken *TK,
                                          ASTMeasureNode *MN) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(MN && "Invalid ASTMeasureNode argument!");

  QasmFeatureTester::Instance().ValidateFeature("return");

  std::stringstream RS;
  RS << "ast-return-statement-"
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      RS.str(), ASTReturnStatementNode::ReturnBits, ASTTypeReturn);
  assert(Id && "Could not create a valid Return ASTIdentifierNode!");

  ASTReturnStatementNode *RN =
      ASTBuilder::Instance().CreateASTReturnStatementNode(Id, MN);
  assert(RN && "Could not create a valid ASTReturnStatementNode!");

  RN->SetLocation(TK->GetLocation());
  ASTSymbolTableEntry *STE =
      ASTSymbolTable::Instance().Lookup(Id, Id->GetBits(), Id->GetSymbolType());
  assert(STE && "Invalid SymbolTable Entry for ASTReturnStatementNode!");

  STE->ResetValue();
  STE->SetValue(new ASTValue<>(RN, ASTTypeReturn), ASTTypeReturn);

  RN->Mangle();
  return RN;
}

ASTReturnStatementNode *
ASTProductionFactory::ProductionRule_2005(const ASTToken *TK) const {
  assert(TK && "Invalid ASTToken argument!");

  QasmFeatureTester::Instance().ValidateFeature("return");

  std::stringstream RS;
  RS << "ast-return-statement-"
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      RS.str(), ASTReturnStatementNode::ReturnBits, ASTTypeReturn);
  assert(Id && "Could not create a valid Return ASTIdentifierNode!");

  ASTVoidNode *VN = new ASTVoidNode(ASTIdentifierNode::Void.Clone(), nullptr);
  assert(VN && "Could not create a valid ASTVoidNode!");

  VN->SetLocation(TK->GetLocation());
  VN->Mangle();

  ASTReturnStatementNode *RN =
      ASTBuilder::Instance().CreateASTReturnStatementNode(Id, VN);
  assert(RN && "Could not create a valid ASTReturnStatementNode!");

  RN->SetLocation(TK->GetLocation());
  ASTSymbolTableEntry *STE =
      ASTSymbolTable::Instance().Lookup(Id, Id->GetBits(), Id->GetSymbolType());
  assert(STE && "Invalid SymbolTable Entry for ASTReturnStatementNode!");

  STE->ResetValue();
  STE->SetValue(new ASTValue<>(RN, ASTTypeReturn), ASTTypeReturn);

  RN->Mangle();
  return RN;
}

ASTReturnStatementNode *
ASTProductionFactory::ProductionRule_2006(const ASTToken *TK,
                                          const std::string &BS) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(!BS.empty() && "Invalid std::string argument!");

  QasmFeatureTester::Instance().ValidateFeature("return");

  std::stringstream RS;
  RS << "ast-return-statement-"
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      RS.str(), ASTReturnStatementNode::ReturnBits, ASTTypeReturn);
  assert(Id && "Could not create a valid Return ASTIdentifierNode!");

  bool BV = BS == "true";
  ASTBoolNode *BN = new ASTBoolNode(ASTIdentifierNode::Bool.Clone(), BV);
  assert(BN && "Could not create a valid ASTBoolNode!");

  BN->SetLocation(TK->GetLocation());

  ASTReturnStatementNode *RN =
      ASTBuilder::Instance().CreateASTReturnStatementNode(Id, BN);
  assert(RN && "Could not create a valid ASTReturnStatementNode!");

  RN->SetLocation(TK->GetLocation());
  ASTSymbolTableEntry *STE =
      ASTSymbolTable::Instance().Lookup(Id, Id->GetBits(), Id->GetSymbolType());
  assert(STE && "Invalid SymbolTable Entry for ASTReturnStatementNode!");

  STE->ResetValue();
  STE->SetValue(new ASTValue<>(RN, ASTTypeReturn), ASTTypeReturn);

  RN->Mangle();
  return RN;
}

ASTDeclarationNode *
ASTProductionFactory::ProductionRule_2150(const ASTToken *TK,
                                          const ASTResultNode *RN) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(RN && "Invalid ASTResultNode argument!");

  const ASTIdentifierNode *Id = RN->GetIdentifier();
  assert(Id && "Invalid ASTIdentifierNode for FuncResultNode!");

  ASTDeclarationNode *DN = new ASTDeclarationNode(Id, RN, ASTTypeResult, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *
ASTProductionFactory::ProductionRule_3000(const ASTArrayNode *AN) const {
  assert(AN && "Invalid ASTArrayNode argument!");

  const ASTIdentifierNode *Id = AN->GetIdentifier();
  assert(Id && "Invalid ASTIdentifierNode for Array Declaration!");

  if (Id->GetSymbolType() == ASTTypeInvalidArray) {
    std::stringstream M;
    M << "Invalid ASTArrayNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(AN), M.str(), DiagLevel::Error);
    return ASTDeclarationNode::DeclarationError(Id, M.str());
  }

  ASTSymbolTableEntry *STE =
      ASTSymbolTable::Instance().Lookup(Id, Id->GetBits(), Id->GetSymbolType());
  assert(STE && "Could not retrieve a valid SymbolTable Entry!");
  assert(STE->HasValue() && "SymbolTable Entry has no Value!");

  ASTDeclarationNode *DN =
      new ASTDeclarationNode(Id, AN, STE->GetValueType(), false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(AN->GetLocation());
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *
ASTProductionFactory::ProductionRule_9000(const ASTMPComplexNode *MPC) const {
  assert(MPC && "Invalid ASTMPComplexNode argument!");

  const ASTIdentifierNode *Id = MPC->GetIdentifier();
  assert(Id && "Invalid ASTIdentifierNode for ASTMPComplex Declaration!");

  ASTSymbolTableEntry *STE =
      ASTSymbolTable::Instance().Lookup(Id, Id->GetBits(), Id->GetSymbolType());
  assert(STE && "Could not retrieve a valid SymbolTable Entry!");
  assert(STE->HasValue() && "SymbolTable Entry has no Value!");

  ASTDeclarationNode *DN =
      new ASTDeclarationNode(Id, MPC, STE->GetValueType(), false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(MPC->GetLocation());
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

ASTDeclarationNode *ASTProductionFactory::ProductionRule_5000(
    const ASTDefcalGrammarNode *DG) const {
  assert(DG && "Invalid ASTDefcalGrammarNode argument!");

  const ASTIdentifierNode *Id = DG->GetIdentifier();
  assert(Id && "Invalid ASTIdentifierNode for Grammar Declaration!");

  ASTDeclarationNode *DN =
      new ASTDeclarationNode(Id, DG, ASTTypeDefcalGrammar, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(DG->GetLocation());
  ASTDeclarationBuilder::Instance().Append(DN);
  return DN;
}

static void MaterializeGateQubitParams(const ASTToken *TK,
                                       ASTIdentifierList *QIL,
                                       ASTIdentifierList &LQIL,
                                       const ASTDeclarationContext *CTX) {
  assert(QIL && "Invalid ASTIdentifierList argument!");
  assert(CTX && "Invalid ASTDeclarationContext argument!");

  LQIL.Clear();

  for (ASTIdentifierList::iterator II = QIL->begin(); II != QIL->end(); ++II) {
    ASTSymbolTableEntry *QSTE = (*II)->GetSymbolTableEntry();
    if (QSTE && QSTE->HasValue()) {
      if (QSTE->GetValue()->GetASTType() == ASTTypeGateQubitParam) {
        (*II)->SetDeclarationContext(CTX);
        (*II)->SetGateLocal(true);
        (*II)->SetLocalScope();
        LQIL.Append(*II);
      } else {
        ASTIdentifierNode *QId =
            ASTProductionFactory::Instance().ProductionRule_1507(
                TK, (*II)->GetName());
        assert(QId &&
               "Could not create a valid GateQubitParam ASTIdentifierNode!");

        QId->SetDeclarationContext(CTX);
        QId->SetGateLocal(true);
        QId->SetLocalScope();
        LQIL.Append(QId);
        (*II)->RestoreType();
      }
    } else if (QSTE && !QSTE->HasValue()) {
      if (QSTE->GetValueType() == ASTTypeGateQubitParam) {
        ASTIdentifierNode *QId = *II;
        QId->SetDeclarationContext(CTX);
        QId->SetGateLocal(true);
        QId->SetLocalScope();
        LQIL.Append(QId);
        (*II)->RestoreType();
      } else {
        ASTIdentifierNode *QId =
            ASTProductionFactory::Instance().ProductionRule_1507(
                TK, (*II)->GetName());
        assert(QId &&
               "Could not create a valid GateQubitParam ASTIdentifierNode!");

        QId->SetDeclarationContext(CTX);
        QId->SetGateLocal(true);
        QId->SetLocalScope();
        LQIL.Append(QId);
        (*II)->RestoreType();
      }
    } else {
      ASTIdentifierNode *QId =
          ASTProductionFactory::Instance().ProductionRule_1507(
              TK, (*II)->GetName());
      assert(QId &&
             "Could not create a valid GateQubitParam ASTIdentifierNode!");

      QId->SetDeclarationContext(CTX);
      QId->SetGateLocal(true);
      QId->SetLocalScope();
      LQIL.Append(QId);
      (*II)->RestoreType();
    }
  }
}

ASTGateDeclarationNode *ASTProductionFactory::ProductionRule_1430(
    const ASTToken *TK, const ASTIdentifierNode *GId, ASTDeclarationList *DL,
    ASTIdentifierList *QIL, ASTGateQOpList *GOL) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(GId && "Invalid ASTIdentifierNode argument!");
  assert(DL && "Invalid ASTDeclarationList argument!");
  assert(QIL && "Invalid GateQubitParamList argument!");
  assert(GOL && "Invalid ASTGateQOpList argument!");

  ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  CTX->SetContextType(ASTTypeGate);

  if (ASTTypeSystemBuilder::Instance().IsBuiltinGate(GId->GetName())) {
    std::stringstream M;
    M << "Gate " << GId->GetName() << " is a builtin gate and cannot "
      << "be re-declared.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(GId), M.str(),
        DiagLevel::Error);
    return ASTGateDeclarationNode::DeclarationError(GId, M.str());
  }

  const std::string &GN = GId->GetName();
  GateKind GK = ASTGateNode::DetermineGateKind(GN);
  ASTType GT = ASTGateNode::DetermineGateType(GN);

  const ASTSymbolTableEntry *STE =
      ASTSymbolTable::Instance().FindGate(GId->GetName());
  if (!STE) {
    if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
            GId, ASTGateNode::GateBits, GT)) {
      std::stringstream M;
      M << "Could not transfer Symbol Table Entry for " << PrintTypeEnum(GT)
        << ".";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(GId), M.str(),
          DiagLevel::ICE);
      return ASTGateDeclarationNode::DeclarationError(GId, M.str());
    }

    STE = ASTSymbolTable::Instance().FindGate(GId->GetName());
    assert(STE && "Invalid SymbolTable Entry for ASTGateNode!");
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(GId)) {
    std::stringstream M;
    M << "Declaration " << GId->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(GId), M.str(),
        DiagLevel::Error);
    return ASTGateDeclarationNode::DeclarationError(GId, M.str());
  }

  if (QIL->Empty()) {
    std::stringstream M;
    M << "At least one Qubit parameter is required for gate "
      << "declarations.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(QIL), M.str(),
        DiagLevel::Error);
    return ASTGateDeclarationNode::DeclarationError(GId, M.str());
  }

  for (ASTIdentifierList::iterator II = QIL->begin(); II != QIL->end(); ++II) {
    if ((*II)->GetName()[0] == '$') {
      std::stringstream M;
      M << "Bound Qubits (" << (*II)->GetName() << ") are not allowed "
        << "as Gate Qubit parameters.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(*II), M.str(),
          DiagLevel::Error);
      return ASTGateDeclarationNode::DeclarationError(GId, M.str());
    }
  }

  ASTIdentifierList LQIL;

  MaterializeGateQubitParams(TK, QIL, LQIL, CTX);
  ASTIdentifierTypeController::Instance().CheckGateQubitParamType(LQIL);

  ASTParameterList *PAL = new ASTParameterList(DL);
  assert(PAL && "Could not create a valid ASTParameterList!");

  if (GN == "U" || GN == "CX" || GN == "CCX" || GN == "CNOT") {
    std::stringstream M;
    M << "A Standard Universal Gate [" << GN.c_str()
      << "] cannot have its own re-declaration!";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(GId), M.str(),
        DiagLevel::Error);
    return ASTGateDeclarationNode::DeclarationError(GId, M.str());
  }

  if (QIL->Empty()) {
    std::stringstream M;
    M << "At least one Qubit parameter is required for gate "
      << "declarations.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(QIL), M.str(),
        DiagLevel::Error);
    return ASTGateDeclarationNode::DeclarationError(GId, M.str());
  }

  ASTGateQubitParamBuilder::Instance().SetGateLocal();
  PAL->SetLocalScope();

  for (ASTParameterList::iterator PI = PAL->begin(); PI != PAL->end(); ++PI) {
    ASTParameter *P = dynamic_cast<ASTParameter *>(*PI);
    assert(P && "Could not dynamic_cast to a valid ASTParameter!");

    for (ASTIdentifierList::iterator II = QIL->begin(); II != QIL->end();
         ++II) {
      if ((*II)->GetName() != P->GetName()) {
        if (!ASTGateNodeBuilder::Instance().IsGlobalGate((*II)->GetName())) {
          (*II)->SetDeclarationContext(CTX);
          (*II)->SetGateLocal(true);
          (*II)->SetLocalScope();
        }
      }
    }
  }

  const ASTDeclarationContext *GCX =
      ASTDeclarationContextTracker::Instance().GetGlobalContext();
  GId->SetBits(ASTGateNode::GateBits);
  GId->SetDeclarationContext(GCX);

  ASTGateNode *GTN =
      ASTBuilder::Instance().CreateASTGateNode(GId, GK, *PAL, LQIL, *GOL);
  assert(GTN && "Could not create a valid ASTGateNode!");

  GTN->SetLocation(TK->GetLocation());
  GTN->SetDeclarationContext(GCX, GTN->GetASTType());
  GTN->Mangle();

  ASTGateDeclarationNode *GDN = new ASTGateDeclarationNode(GId, GTN);
  assert(GDN && "Could not create a valid ASTGateDeclarationNode!");

  GDN->SetLocation(TK->GetLocation());
  GDN->SetDeclarationContext(GCX);
  ASTDeclarationNode *DN = new ASTDeclarationNode(GId, GTN, GT, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  DN->SetDeclarationContext(GCX);
  ASTDeclarationBuilder::Instance().Append(DN);

  ASTSymbolTable::Instance().TransferLocalContextSymbols(CTX,
                                                         GTN->GetSymbolTable());

  ASTGateQubitTracker::Instance().Erase();
  QIL->DeleteSymbols();
  QIL->Clear();
  PAL->DeleteSymbols();
  PAL->Clear();
  ASTGateQubitParamBuilder::Instance().ReleaseQubits();
  ASTGateContextBuilder::Instance().CloseContext();
  GTN->ClearGateQubits();
  GTN->ClearLocalGateSymbols();
  ASTDeclarationContextTracker::Instance().PopCurrentContext();
  ASTIdentifierTypeController::Instance().StopAngleList();
  ASTIdentifierTypeController::Instance().StopQubitList();
  ASTIdentifierTypeController::Instance().Reset();
  ASTIdentifierTypeController::Instance().SetCurrentType(ASTTypeUndefined);
  return GDN;
}

ASTGateDeclarationNode *ASTProductionFactory::ProductionRule_1431(
    const ASTToken *TK, const ASTIdentifierNode *GId, ASTIdentifierList *QIL,
    ASTGateQOpList *GOL) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(GId && "Invalid ASTIdentifierNode argument!");
  assert(QIL && "Invalid GateQubitParamList argument!");
  assert(GOL && "Invalid ASTGateQOpList argument!");

  ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  CTX->SetContextType(ASTTypeGate);

  const std::string &GN = GId->GetName();
  GateKind GK = ASTGateNode::DetermineGateKind(GN);
  ASTType GT = ASTGateNode::DetermineGateType(GN);

  const ASTSymbolTableEntry *STE =
      ASTSymbolTable::Instance().FindGate(GId->GetName());
  if (!STE) {
    if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
            GId, ASTGateNode::GateBits, GT)) {
      std::stringstream M;
      M << "Could not transfer Symbol Table Entry for ASTTypeGate.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(GId), M.str(),
          DiagLevel::ICE);
      return ASTGateDeclarationNode::DeclarationError(GId, M.str());
    }

    STE = ASTSymbolTable::Instance().FindGate(GId->GetName());
    assert(STE && "Invalid SymbolTable Entry for ASTGateNode!");
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(GId)) {
    std::stringstream M;
    M << "Declaration " << GId->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(GId), M.str(),
        DiagLevel::Error);
    return ASTGateDeclarationNode::DeclarationError(GId, M.str());
  }

  if (QIL->Empty()) {
    std::stringstream M;
    M << "At least one Qubit parameter is required for gate "
      << "declarations.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(QIL), M.str(),
        DiagLevel::Error);
    return ASTGateDeclarationNode::DeclarationError(GId, M.str());
  }

  for (ASTIdentifierList::iterator II = QIL->begin(); II != QIL->end(); ++II) {
    if ((*II)->GetName()[0] == '$') {
      std::stringstream M;
      M << "Bound Qubits (" << (*II)->GetName() << ") are not allowed "
        << "as Gate Qubit parameters.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(*II), M.str(),
          DiagLevel::Error);
      return ASTGateDeclarationNode::DeclarationError(GId, M.str());
    }
  }

  ASTIdentifierList LQIL;

  MaterializeGateQubitParams(TK, QIL, LQIL, CTX);
  ASTIdentifierTypeController::Instance().CheckGateQubitParamType(LQIL);

  ASTParameterList *PAL = new ASTParameterList();
  assert(PAL && "Could not create a valid ASTParameterList!");

  PAL->SetLocation(TK->GetLocation());

  if (GN == "U" || GN == "CX" || GN == "CCX" || GN == "CNOT") {
    std::stringstream M;
    M << "A Standard Universal Gate [" << GN.c_str()
      << "] cannot have its own re-declaration!";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(GId), M.str(),
        DiagLevel::Error);
    return ASTGateDeclarationNode::DeclarationError(GId, M.str());
  }

  ASTGateQubitParamBuilder::Instance().SetGateLocal();
  std::stringstream M;

  const ASTDeclarationContext *GCX =
      ASTDeclarationContextTracker::Instance().GetGlobalContext();
  ASTGateNode *GTN =
      ASTBuilder::Instance().CreateASTGateNode(GId, GK, *PAL, LQIL, *GOL);
  assert(GTN && "Could not create a valid ASTGateNode!");

  GTN->SetLocation(TK->GetLocation());
  GTN->SetDeclarationContext(GCX, GTN->GetASTType());
  GTN->Mangle();

  ASTGateDeclarationNode *GDN = new ASTGateDeclarationNode(GId, GTN);
  assert(GDN && "Could not create a valid ASTGateDeclarationNode!");

  GDN->SetLocation(TK->GetLocation());
  GDN->SetDeclarationContext(GCX);
  ASTDeclarationNode *DN = new ASTDeclarationNode(GId, GTN, GT, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  DN->SetDeclarationContext(GCX);
  ASTDeclarationBuilder::Instance().Append(DN);

  ASTSymbolTable::Instance().TransferLocalContextSymbols(CTX,
                                                         GTN->GetSymbolTable());

  ASTGateQubitTracker::Instance().Erase();
  QIL->DeleteSymbols();
  QIL->Clear();
  ASTGateQubitParamBuilder::Instance().ReleaseQubits();
  ASTGateContextBuilder::Instance().CloseContext();
  GTN->ClearGateQubits();
  GTN->ClearLocalGateSymbols();
  ASTDeclarationContextTracker::Instance().PopCurrentContext();
  ASTIdentifierTypeController::Instance().StopAngleList();
  ASTIdentifierTypeController::Instance().StopQubitList();
  ASTIdentifierTypeController::Instance().Reset();
  ASTIdentifierTypeController::Instance().SetCurrentType(ASTTypeUndefined);
  return GDN;
}

ASTGateDeclarationNode *ASTProductionFactory::ProductionRule_1432(
    const ASTToken *TK, ASTIdentifierList *QIL, const ASTLocation &Loc,
    ASTGateQOpList *GL) const {
  assert(QIL && "Invalid ASTGateQubitParamList CX Gate argument!");
  assert(GL && "Invalid ASTGateQOpList CX Gate argument!");

  ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  CTX->SetContextType(ASTTypeGate);

  std::string CX = "CX";
  ASTIdentifierNode *GId = ASTBuilder::Instance().CreateASTIdentifierNode(
      CX, ASTGateNode::GateBits, ASTTypeCXGate);
  assert(GId && "Could not create a valid CX Gate ASTIdentifierNode!");

  GId->SetLocation(Loc);

  if (QIL->Empty()) {
    std::stringstream M;
    M << "At least one Qubit parameter is required for gate "
      << "declarations.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(QIL), M.str(),
        DiagLevel::Error);
    return ASTGateDeclarationNode::DeclarationError(GId, M.str());
  }

  for (ASTIdentifierList::iterator II = QIL->begin(); II != QIL->end(); ++II) {
    if ((*II)->GetName()[0] == '$') {
      std::stringstream M;
      M << "Bound Qubits (" << (*II)->GetName() << ") are not allowed "
        << "as Gate Qubit parameters.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(*II), M.str(),
          DiagLevel::Error);
      return ASTGateDeclarationNode::DeclarationError(GId, M.str());
    }
  }

  ASTIdentifierList LQIL;

  MaterializeGateQubitParams(TK, QIL, LQIL, CTX);
  ASTIdentifierTypeController::Instance().CheckGateQubitParamType(LQIL);

  ASTGateQubitParamBuilder::Instance().SetGateLocal();
  std::stringstream M;

  ASTParameterList PL;
  const ASTDeclarationContext *GCX =
      ASTDeclarationContextTracker::Instance().GetGlobalContext();
  ASTGateNode *CXG = ASTBuilder::Instance().CreateASTGateNode(
      GId, ASTGateKindCX, PL, *QIL, *GL);
  assert(CXG && "Could not create a valid CX ASTGateNode!");

  CXG->SetLocation(TK->GetLocation());
  CXG->SetDeclarationContext(GCX, CXG->GetASTType());
  CXG->Mangle();

  ASTGateDeclarationNode *GDN = new ASTGateDeclarationNode(GId, CXG);
  assert(GDN && "Could not create a valid CX ASTGateDeclarationNode!");

  GDN->SetLocation(TK->GetLocation());
  GDN->SetDeclarationContext(GCX);
  ASTDeclarationNode *DN = new ASTDeclarationNode(GId, CXG, ASTTypeGate, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  DN->SetDeclarationContext(GCX);
  ASTDeclarationBuilder::Instance().Append(DN);
  ASTGateQubitTracker::Instance().Erase();

  ASTSymbolTable::Instance().TransferLocalContextSymbols(CTX,
                                                         CXG->GetSymbolTable());

  QIL->DeleteSymbols();
  QIL->Clear();
  ASTGateQubitParamBuilder::Instance().ReleaseQubits();
  ASTGateContextBuilder::Instance().CloseContext();
  CXG->ClearGateQubits();
  CXG->ClearLocalGateSymbols();
  ASTDeclarationContextTracker::Instance().PopCurrentContext();
  ASTIdentifierTypeController::Instance().StopAngleList();
  ASTIdentifierTypeController::Instance().StopQubitList();
  ASTIdentifierTypeController::Instance().Reset();
  ASTIdentifierTypeController::Instance().SetCurrentType(ASTTypeUndefined);
  return GDN;
}

ASTGateDeclarationNode *ASTProductionFactory::ProductionRule_1433(
    const ASTToken *TK, const std::string *GS, const ASTLocation &Loc,
    ASTIdentifierList *QIL, ASTGateQOpList *GL) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(GS && "Invalid string argument!");
  assert(!GS->empty() && "Invalid string argument!");
  assert(QIL && "Invalid ASTGateQubitParamList Hadamard Gate argument!");
  assert(GL && "Invalid ASTGateQOpList Hadamard Gate argument!");

  std::string CX = "CX";
  ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  CTX->SetContextType(ASTTypeGate);

  ASTIdentifierNode *GId = ASTBuilder::Instance().CreateASTIdentifierNode(
      *GS, ASTGateNode::GateBits, ASTTypeHadamardGate);
  assert(GId && "Could not create a valid ASTIdentifierNode!");

  GId->SetLocation(Loc);
  const ASTSymbolTableEntry *STE = ASTSymbolTable::Instance().FindGate(*GS);
  if (!STE && !ASTSymbolTable::Instance().TransferUndefinedSymbol(
                  GId, ASTGateNode::GateBits, ASTTypeHadamardGate)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeGate.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(GId), M.str(), DiagLevel::ICE);
    return ASTGateDeclarationNode::DeclarationError(GId, M.str());
  }

  STE = ASTSymbolTable::Instance().FindGate(GId->GetName());
  assert(STE && "Invalid SymbolTable Entry for ASTGateNode!");

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(GId)) {
    std::stringstream M;
    M << "Declaration " << GId->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(GId), M.str(),
        DiagLevel::Error);
    return ASTGateDeclarationNode::DeclarationError(GId, M.str());
  }

  if (QIL->Empty()) {
    std::stringstream M;
    M << "At least one Qubit parameter is required for gate "
      << "declarations.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(QIL), M.str(),
        DiagLevel::Error);
    return ASTGateDeclarationNode::DeclarationError(GId, M.str());
  }

  for (ASTIdentifierList::iterator II = QIL->begin(); II != QIL->end(); ++II) {
    if (ASTStringUtils::Instance().IsBoundQubit((*II)->GetName())) {
      std::stringstream M;
      M << "Bound Qubits (" << (*II)->GetName() << ") are not allowed "
        << "as Gate Qubit parameters.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(), M.str(), DiagLevel::Error);
      return ASTGateDeclarationNode::DeclarationError(GId, M.str());
    }
  }

  ASTIdentifierList LQIL;

  MaterializeGateQubitParams(TK, QIL, LQIL, CTX);
  ASTIdentifierTypeController::Instance().CheckGateQubitParamType(LQIL);
  ASTGateQubitParamBuilder::Instance().SetGateLocal();

  const ASTDeclarationContext *CXG =
      ASTDeclarationContextTracker::Instance().GetGlobalContext();

  ASTParameterList *PAL = new ASTParameterList();
  assert(PAL && "Could not create a valid ASTParameterList!");

  PAL->SetLocation(TK->GetLocation());

  ASTGateNode *GTN = ASTBuilder::Instance().CreateASTGateNode(GId, ASTGateKindH,
                                                              *PAL, LQIL, *GL);
  assert(GTN && "Could not create a valid ASTGateNode!");

  GTN->SetLocation(TK->GetLocation());
  GTN->SetDeclarationContext(CXG, GTN->GetASTType());
  GTN->Mangle();

  ASTGateDeclarationNode *GDN = new ASTGateDeclarationNode(GId, GTN);
  assert(GDN && "Could not create a valid ASTGateDeclarationNode!");

  GDN->SetLocation(TK->GetLocation());
  GDN->SetDeclarationContext(CXG);

  ASTDeclarationNode *DN = new ASTDeclarationNode(GId, GTN, ASTTypeGate, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  DN->SetDeclarationContext(CXG);
  ASTDeclarationBuilder::Instance().Append(DN);
  ASTGateQubitTracker::Instance().Erase();

  ASTSymbolTable::Instance().TransferLocalContextSymbols(CTX,
                                                         GTN->GetSymbolTable());

  QIL->DeleteSymbols();
  QIL->Clear();
  ASTGateQubitParamBuilder::Instance().ReleaseQubits();
  ASTGateContextBuilder::Instance().CloseContext();
  GTN->ClearGateQubits();
  GTN->ClearLocalGateSymbols();
  ASTDeclarationContextTracker::Instance().PopCurrentContext();
  ASTIdentifierTypeController::Instance().StopAngleList();
  ASTIdentifierTypeController::Instance().StopQubitList();
  ASTIdentifierTypeController::Instance().Reset();
  ASTIdentifierTypeController::Instance().SetCurrentType(ASTTypeUndefined);
  return GDN;
}

ASTGateDeclarationNode *ASTProductionFactory::ProductionRule_1434(
    const ASTToken *TK, const std::string *GS, const ASTLocation &Loc,
    ASTDeclarationList *DL, ASTIdentifierList *QIL, ASTGateQOpList *GOL) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(GS && "Invalid string argument!");
  assert(!GS->empty() && "Invalid string argument!");
  assert(DL && "Invalid ASTDeclarationList argument!");
  assert(QIL && "Invalid ASTGateQubitParamList Hadamard Gate argument!");
  assert(GOL && "Invalid ASTGateQOpList Hadamard Gate argument!");

  ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  CTX->SetContextType(ASTTypeGate);

  ASTIdentifierNode *GId = ASTBuilder::Instance().CreateASTIdentifierNode(
      *GS, ASTGateNode::GateBits, ASTTypeHadamardGate);
  assert(GId && "Could not create a valid ASTIdentifierNode!");

  GId->SetLocation(Loc);
  GId->SetBits(ASTGateNode::GateBits);

  if (ASTTypeSystemBuilder::Instance().IsBuiltinGate(GId->GetName())) {
    std::stringstream M;
    M << "Gate " << GId->GetName() << " is a builtin gate and cannot "
      << "be re-declared.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(GId), M.str(),
        DiagLevel::Error);
    return ASTGateDeclarationNode::DeclarationError(GId, M.str());
  }

  const ASTSymbolTableEntry *STE = ASTSymbolTable::Instance().FindGate(*GS);
  if (!STE && !ASTSymbolTable::Instance().TransferUndefinedSymbol(
                  GId, ASTGateNode::GateBits, ASTTypeHadamardGate)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeGate.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(GId), M.str(), DiagLevel::ICE);
    return ASTGateDeclarationNode::DeclarationError(GId, M.str());
  }

  STE = ASTSymbolTable::Instance().FindGate(GId->GetName());
  assert(STE && "Invalid SymbolTable Entry for ASTGateNode!");

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(GId)) {
    std::stringstream M;
    M << "Declaration " << GId->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(GId), M.str(),
        DiagLevel::Error);
    return ASTGateDeclarationNode::DeclarationError(GId, M.str());
  }

  ASTParameterList *PAL = new ASTParameterList(DL);
  assert(PAL && "Could not create a valid ASTParameterList!");

  PAL->SetLocation(TK->GetLocation());

  if (QIL->Empty()) {
    std::stringstream M;
    M << "At least one Qubit parameter is required for gate "
      << "declarations.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(QIL), M.str(),
        DiagLevel::Error);
    return ASTGateDeclarationNode::DeclarationError(GId, M.str());
  }

  ASTGateQubitParamBuilder::Instance().SetGateLocal();
  PAL->SetLocalScope();

  for (ASTParameterList::iterator PI = PAL->begin(); PI != PAL->end(); ++PI) {
    ASTParameter *P = dynamic_cast<ASTParameter *>(*PI);
    assert(P && "Could not dynamic_cast to a valid ASTParameter!");

    for (ASTIdentifierList::iterator II = QIL->begin(); II != QIL->end();
         ++II) {
      if ((*II)->GetName() != P->GetName()) {
        if (!ASTGateNodeBuilder::Instance().IsGlobalGate((*II)->GetName())) {
          (*II)->SetDeclarationContext(CTX);
          (*II)->SetGateLocal(true);
          (*II)->SetLocalScope();
        }
      }
    }
  }

  for (ASTIdentifierList::iterator II = QIL->begin(); II != QIL->end(); ++II) {
    if (ASTStringUtils::Instance().IsBoundQubit((*II)->GetName())) {
      std::stringstream M;
      M << "Bound Qubits (" << (*II)->GetName() << ") are not allowed "
        << "as Gate Qubit parameters.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(*II), M.str(),
          DiagLevel::Error);
      return ASTGateDeclarationNode::DeclarationError(GId, M.str());
    }
  }

  ASTIdentifierList LQIL;

  MaterializeGateQubitParams(TK, QIL, LQIL, CTX);
  ASTIdentifierTypeController::Instance().CheckGateQubitParamType(LQIL);

  const ASTDeclarationContext *GCX =
      ASTDeclarationContextTracker::Instance().GetGlobalContext();
  ASTGateNode *GTN = ASTBuilder::Instance().CreateASTGateNode(
      GId, QASM::ASTGateKindH, *PAL, LQIL, *GOL);
  assert(GTN && "Could not create a valid ASTGateNode!");

  GTN->SetLocation(TK->GetLocation());
  GTN->SetDeclarationContext(GCX, GTN->GetASTType());
  GTN->Mangle();

  ASTGateDeclarationNode *GDN = new ASTGateDeclarationNode(GId, GTN);
  assert(GDN && "Could not create a valid ASTGateDeclarationNode!");

  GDN->SetLocation(TK->GetLocation());
  GDN->SetDeclarationContext(GCX);

  ASTDeclarationNode *DN = new ASTDeclarationNode(GId, GTN, ASTTypeGate, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  DN->SetDeclarationContext(GCX);
  ASTDeclarationBuilder::Instance().Append(DN);
  ASTGateQubitTracker::Instance().Erase();

  ASTSymbolTable::Instance().TransferLocalContextSymbols(CTX,
                                                         GTN->GetSymbolTable());

  QIL->DeleteSymbols();
  QIL->Clear();
  PAL->DeleteSymbols();
  PAL->Clear();
  ASTGateQubitParamBuilder::Instance().ReleaseQubits();
  ASTGateContextBuilder::Instance().CloseContext();
  GTN->ClearGateQubits();
  GTN->ClearLocalGateSymbols();
  ASTDeclarationContextTracker::Instance().PopCurrentContext();
  ASTIdentifierTypeController::Instance().StopAngleList();
  ASTIdentifierTypeController::Instance().StopQubitList();
  ASTIdentifierTypeController::Instance().Reset();
  ASTIdentifierTypeController::Instance().SetCurrentType(ASTTypeUndefined);
  return GDN;
}

ASTGateDeclarationNode *ASTProductionFactory::ProductionRule_1435(
    const ASTToken *TK, const ASTIdentifierNode *GId, ASTDeclarationList *DL,
    ASTIdentifierList *QIL) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(GId && "Invalid ASTIdentifierNode argument!");
  assert(DL && "Invalid ASTDeclarationList argument!");
  assert(QIL && "Invalid ASTIdentifierList argument!");

  QasmFeatureTester::Instance().ValidateFeature("opaque");
  ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  CTX->SetContextType(ASTTypeOpaque);

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
          GId, ASTGateNode::GateBits, ASTTypeGate)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeGate.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(GId), M.str(), DiagLevel::ICE);
    return ASTGateDeclarationNode::DeclarationError(GId, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(GId)) {
    std::stringstream M;
    M << "Declaration " << GId->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(GId), M.str(),
        DiagLevel::Error);
    return ASTGateDeclarationNode::DeclarationError(GId, M.str());
  }

  std::string GN = ASTStringUtils::Instance().ToUpper(GId->GetName());

  if (GN == "U" || GN == "CX" || GN == "CCX" || GN == "CNOT" || GN == "H" ||
      GN == "HADAMARD") {
    std::stringstream M;
    M << "A Standard Universal Gate [" << GN.c_str()
      << "] cannot have its own Opaque Re-Declaration!";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(GId), M.str(),
        DiagLevel::Error);
    return ASTGateDeclarationNode::DeclarationError(GId, M.str());
  }

  if (ASTTypeSystemBuilder::Instance().IsReservedGateV2(GN)) {
    std::stringstream M;
    M << "Reserved Identifier '" << GN.c_str() << "' cannot be "
      << "used to declare an Opaque Gate.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(GId), M.str(),
        DiagLevel::Error);
    return ASTGateDeclarationNode::DeclarationError(GId, M.str());
  }

  GateKind GK = ASTGateKindGeneric;
  ASTType GT = ASTTypeGate;

  ASTGateQOpList GOL;
  ASTParameterList *PAL = new ASTParameterList(*DL);
  assert(PAL && "Could not create a valid ASTParameterList!");

  PAL->SetLocation(TK->GetLocation());
  PAL->SetLocalScope();
  ASTGateQubitParamBuilder::Instance().SetGateLocal();

  for (ASTParameterList::iterator PI = PAL->begin(); PI != PAL->end(); ++PI) {
    ASTParameter *P = dynamic_cast<ASTParameter *>(*PI);
    assert(P && "Could not dynamic_cast to a valid ASTParameter!");

    for (ASTIdentifierList::iterator II = QIL->begin(); II != QIL->end();
         ++II) {
      if ((*II)->GetName() != P->GetName()) {
        if (!ASTGateNodeBuilder::Instance().IsGlobalGate((*II)->GetName())) {
          (*II)->SetDeclarationContext(CTX);
          (*II)->SetGateLocal(true);
          (*II)->SetLocalScope();
        }
      }
    }
  }

  for (ASTIdentifierList::iterator II = QIL->begin(); II != QIL->end(); ++II) {
    if ((*II)->GetName()[0] == '$') {
      std::stringstream M;
      M << "Bound Qubits (" << (*II)->GetName() << ") are not allowed "
        << "as Gate Qubit parameters.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(*II), M.str(),
          DiagLevel::Error);
      return ASTGateDeclarationNode::DeclarationError(GId, M.str());
    }
  }

  ASTIdentifierList LQIL;

  MaterializeGateQubitParams(TK, QIL, LQIL, CTX);
  ASTIdentifierTypeController::Instance().CheckGateQubitParamType(LQIL);

  const ASTDeclarationContext *GCX =
      ASTDeclarationContextTracker::Instance().GetGlobalContext();

  ASTGateNode *GTN =
      ASTBuilder::Instance().CreateASTGateNode(GId, GK, *PAL, LQIL, GOL);
  assert(GTN && "Could not create a valid ASTGateNode!");

  GTN->SetOpaque();
  GTN->SetLocation(TK->GetLocation());
  GTN->SetDeclarationContext(GCX, GTN->GetASTType());
  GTN->Mangle();

  ASTGateDeclarationNode *GDN = new ASTGateDeclarationNode(GId, GTN);
  assert(GDN && "Could not create a valid ASTGateDeclarationNode!");

  GDN->SetLocation(TK->GetLocation());
  GDN->SetDeclarationContext(GCX);

  ASTDeclarationNode *DN = new ASTDeclarationNode(GId, GTN, GT, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  DN->SetDeclarationContext(GCX);
  ASTDeclarationBuilder::Instance().Append(DN);
  ASTGateQubitTracker::Instance().Erase();
  ASTGateQubitParamBuilder::Instance().ReleaseQubits();
  PAL->DeleteSymbols();
  PAL->Clear();
  QIL->DeleteSymbols();
  QIL->Clear();
  ASTGateQubitParamBuilder::Instance().ReleaseQubits();
  ASTGateContextBuilder::Instance().CloseContext();
  ASTDeclarationContextTracker::Instance().PopCurrentContext();
  ASTIdentifierTypeController::Instance().StopAngleList();
  ASTIdentifierTypeController::Instance().StopQubitList();
  ASTIdentifierTypeController::Instance().Reset();
  ASTIdentifierTypeController::Instance().SetCurrentType(ASTTypeUndefined);
  return GDN;
}

ASTGateDeclarationNode *
ASTProductionFactory::ProductionRule_1436(const ASTToken *TK,
                                          const ASTIdentifierNode *GId,
                                          ASTIdentifierList *QIL) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(GId && "Invalid ASTIdentifierNode argument!");
  assert(QIL && "Invalid ASTIdentifierList argument!");

  QasmFeatureTester::Instance().ValidateFeature("opaque");
  ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  CTX->SetContextType(ASTTypeOpaque);

  if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
          GId, ASTGateNode::GateBits, ASTTypeGate)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeGate.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(GId), M.str(), DiagLevel::ICE);
    return ASTGateDeclarationNode::DeclarationError(GId, M.str());
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(GId)) {
    std::stringstream M;
    M << "Declaration " << GId->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(GId), M.str(),
        DiagLevel::Error);
    return ASTGateDeclarationNode::DeclarationError(GId, M.str());
  }

  std::string GN = ASTStringUtils::Instance().ToUpper(GId->GetName());

  if (GN == "U" || GN == "CX" || GN == "CCX" || GN == "CNOT" || GN == "H" ||
      GN == "HADAMARD") {
    std::stringstream M;
    M << "A Standard Universal Gate [" << GN.c_str()
      << "] cannot have its own Opaque Re-Declaration!";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(GId), M.str(),
        DiagLevel::Error);
    return ASTGateDeclarationNode::DeclarationError(GId, M.str());
  }

  if (ASTTypeSystemBuilder::Instance().IsReservedGateV2(GN)) {
    std::stringstream M;
    M << "Reserved Identifier '" << GN.c_str() << "' cannot be "
      << "used to declare an Opaque Gate.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(GId), M.str(),
        DiagLevel::Error);
    return ASTGateDeclarationNode::DeclarationError(GId, M.str());
  }

  GateKind GK = ASTGateKindGeneric;
  ASTType GT = ASTTypeGate;

  for (ASTIdentifierList::iterator II = QIL->begin(); II != QIL->end(); ++II) {
    if ((*II)->GetName()[0] == '$') {
      std::stringstream M;
      M << "Bound Qubits (" << (*II)->GetName() << ") are not allowed "
        << "as Gate Qubit parameters.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(*II), M.str(),
          DiagLevel::Error);
      return ASTGateDeclarationNode::DeclarationError(GId, M.str());
    }
  }

  ASTIdentifierList LQIL;

  MaterializeGateQubitParams(TK, QIL, LQIL, CTX);
  ASTIdentifierTypeController::Instance().CheckGateQubitParamType(LQIL);

  const ASTDeclarationContext *GCX =
      ASTDeclarationContextTracker::Instance().GetGlobalContext();

  ASTGateQOpList GOL;
  ASTParameterList *PAL = new ASTParameterList();
  assert(PAL && "Invalid ASTParameterList argument!");

  PAL->SetLocation(TK->GetLocation());
  PAL->SetLocalScope();
  ASTGateQubitParamBuilder::Instance().SetGateLocal();

  ASTGateNode *GTN =
      ASTBuilder::Instance().CreateASTGateNode(GId, GK, *PAL, LQIL, GOL);
  assert(GTN && "Could not create a valid ASTGateNode!");

  GTN->SetOpaque();
  GTN->SetLocation(TK->GetLocation());
  GTN->SetDeclarationContext(GCX, GTN->GetASTType());
  GTN->Mangle();

  ASTGateDeclarationNode *GDN = new ASTGateDeclarationNode(GId, GTN);
  assert(GDN && "Could not create a valid ASTGateDeclarationNode!");

  GDN->SetLocation(TK->GetLocation());
  GDN->SetDeclarationContext(GCX);

  ASTDeclarationNode *DN = new ASTDeclarationNode(GId, GTN, GT, false);
  assert(DN && "Could not create a valid ASTDeclarationNode!");

  DN->SetLocation(TK->GetLocation());
  DN->SetDeclarationContext(GCX);
  ASTDeclarationBuilder::Instance().Append(DN);
  ASTGateQubitTracker::Instance().Erase();
  ASTGateQubitParamBuilder::Instance().ReleaseQubits();
  PAL->DeleteSymbols();
  PAL->Clear();
  QIL->DeleteSymbols();
  QIL->Clear();
  ASTGateQubitParamBuilder::Instance().ReleaseQubits();
  ASTGateContextBuilder::Instance().CloseContext();
  ASTDeclarationContextTracker::Instance().PopCurrentContext();
  ASTIdentifierTypeController::Instance().StopAngleList();
  ASTIdentifierTypeController::Instance().StopQubitList();
  ASTIdentifierTypeController::Instance().Reset();
  ASTIdentifierTypeController::Instance().SetCurrentType(ASTTypeUndefined);
  return GDN;
}

ASTDefcalDeclarationNode *ASTProductionFactory::ProductionRule_1440(
    const ASTToken *TK, const ASTIdentifierNode *Id, ASTExpressionList *DEL,
    ASTBoundQubitList *BQL, ASTStatementList *DSL,
    const ASTStringNode *GS) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(DEL && "Invalid ASTExpressionList argument!");
  assert(DSL && "Invalid Defcal StatementList!");
  assert(BQL && "Invalid ASTBoundQubitList argument!");

  QasmFeatureTester::Instance().ValidateFeature("defcal");
  ASTDefcalBuilder::Instance().ValidateDefcalContext();

  ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  CTX->SetContextType(ASTTypeDefcal);

  Id->SetDefcalGroupName(Id->GetName());
  Id->SetBits(ASTDefcalNode::DefcalBits);

  ASTMapSymbolTableEntry *MSTE =
      ASTSymbolTable::Instance().FindDefcalGroup(Id->GetDefcalGroupName());
  if (!MSTE) {
    MSTE =
        ASTSymbolTable::Instance().CreateDefcalGroup(Id->GetDefcalGroupName());
    if (!MSTE) {
      std::stringstream M;
      M << "Failed to create a defcal group for " << Id->GetName() << '.';
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
      return ASTDefcalDeclarationNode::DeclarationError(Id, M.str());
    }

    assert(MSTE && "Could not obtain a valid defcal ASTMapSymbolTableEntry!");
  }

  if (!ASTDefcalBuilder::Instance().InOpenContext()) {
    std::stringstream M;
    M << "Defcal declaration " << Id->GetName() << " is outside an "
      << "open defcal context.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTDefcalDeclarationNode::DeclarationError(Id, M.str());
  }

  if (!BQL->ValidateQubits()) {
    std::stringstream M;
    M << "Defcal Bound Qubit validation failed.";
    ASTDefcalBuilder::Instance().CloseContext();
    OpenPulse::ASTOpenPulseCalibrationBuilder::Instance().CloseContext();
    ASTDeclarationContextTracker::Instance().PopCurrentContext();
    ASTDefcalContextBuilder::Instance().CloseContext();
    ASTDefcalBuilder::Instance().CloseContext();
    ASTIdentifierTypeController::Instance().StopAngleList();
    ASTIdentifierTypeController::Instance().StopQubitList();
    ASTIdentifierTypeController::Instance().Reset();
    ASTIdentifierTypeController::Instance().SetCurrentType(ASTTypeUndefined);
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(BQL), M.str(),
        DiagLevel::Error);
    return ASTDefcalDeclarationNode::DeclarationError(Id, M.str());
  }

  const ASTDeclarationContext *GCX =
      ASTDeclarationContextTracker::Instance().GetGlobalContext();

  Id->SetDeclarationContext(GCX);
  DSL->SetDeclarationContext(CTX);
  DSL->SetLocalScope();
  ASTScopeController::Instance().SetDeclarationContext(DEL, CTX);
  ASTScopeController::Instance().SetLocalScope(DEL);
  ASTScopeController::Instance().SetDeclarationContext(DSL, CTX);
  ASTScopeController::Instance().SetLocalScope(DSL);

  ASTExpressionNodeList *EL = new ASTExpressionNodeList(*DEL);
  assert(EL && "Could not create a valid ASTExpressionNodeList!");

  EL->SetLocation(TK->GetLocation());
  ASTScopeController::Instance().SetDeclarationContext(EL, CTX);
  ASTScopeController::Instance().SetLocalScope(EL);

  ASTDefcalNode *DN = nullptr;

  if (GS) {
    std::string SGS = ASTStringUtils::Instance().Sanitize(GS->GetValue());
    DN = ASTBuilder::Instance().CreateASTDefcalNode(Id, SGS, *EL, *DSL, BQL);
  } else {
    DN = ASTBuilder::Instance().CreateASTDefcalNode(Id, *EL, *DSL, BQL);
  }

  assert(DN && "Could not create a valid ASTDefcalNode!");

  DN->SetLocation(TK->GetLocation());
  DN->SetDeclarationContext(GCX);
  DN->TransferLocalSymbolTable();
  DSL->TransferDeclarations(DN->GetSymbolTable());
  DN->Mangle();

  ASTDefcalDeclarationNode *DDN =
      ASTBuilder::Instance().CreateASTDefcalDeclaration(Id, DN);
  assert(DDN && "Could not create a valid ASTDefcalDeclarationNode!");

  DDN->SetLocation(TK->GetLocation());
  DDN->SetDeclarationContext(GCX);

  ASTDefcalBuilder::Instance().CloseContext();
  OpenPulse::ASTOpenPulseCalibrationBuilder::Instance().CloseContext();
  ASTDeclarationContextTracker::Instance().PopCurrentContext();
  ASTIdentifierTypeController::Instance().StopAngleList();
  ASTIdentifierTypeController::Instance().StopQubitList();
  ASTIdentifierTypeController::Instance().Reset();
  ASTIdentifierTypeController::Instance().SetCurrentType(ASTTypeUndefined);
  ASTDefcalContextBuilder::Instance().CloseContext();
  return DDN;
}

ASTDefcalDeclarationNode *ASTProductionFactory::ProductionRule_1441(
    const ASTToken *TK, const ASTIdentifierNode *Id, ASTBoundQubitList *BQL,
    ASTStatementList *DSL, const ASTStringNode *GS) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(DSL && "Invalid Defcal StatementList!");
  assert(BQL && "Invalid ASTBoundQubitList argument!");

  QasmFeatureTester::Instance().ValidateFeature("defcal");
  ASTDefcalBuilder::Instance().ValidateDefcalContext();

  ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  CTX->SetContextType(ASTTypeDefcal);

  Id->SetDefcalGroupName(Id->GetName());
  Id->SetBits(ASTDefcalNode::DefcalBits);

  ASTMapSymbolTableEntry *MSTE =
      ASTSymbolTable::Instance().FindDefcalGroup(Id->GetDefcalGroupName());
  if (!MSTE) {
    MSTE =
        ASTSymbolTable::Instance().CreateDefcalGroup(Id->GetDefcalGroupName());
    if (!MSTE) {
      std::stringstream M;
      M << "Failed to create a defcal group for " << Id->GetName() << '.';
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
      return ASTDefcalDeclarationNode::DeclarationError(Id, M.str());
    }

    assert(MSTE && "Could not obtain a valid defcal ASTMapSymbolTableEntry!");
  }

  if (!ASTDefcalBuilder::Instance().InOpenContext()) {
    std::stringstream M;
    M << "defcal declaration " << Id->GetName() << " is outside an "
      << "open defcal context.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTDefcalDeclarationNode::DeclarationError(Id, M.str());
  }

  if (!BQL->ValidateQubits()) {
    std::stringstream M;
    M << "Defcal Bound Qubit validation failed.";
    ASTDefcalBuilder::Instance().CloseContext();
    OpenPulse::ASTOpenPulseCalibrationBuilder::Instance().CloseContext();
    ASTDeclarationContextTracker::Instance().PopCurrentContext();
    ASTDefcalContextBuilder::Instance().CloseContext();
    ASTIdentifierTypeController::Instance().StopAngleList();
    ASTIdentifierTypeController::Instance().StopQubitList();
    ASTIdentifierTypeController::Instance().Reset();
    ASTIdentifierTypeController::Instance().SetCurrentType(ASTTypeUndefined);
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(BQL), M.str(),
        DiagLevel::Error);
    return ASTDefcalDeclarationNode::DeclarationError(Id, M.str());
  }

  const ASTDeclarationContext *GCX =
      ASTDeclarationContextTracker::Instance().GetGlobalContext();

  Id->SetDeclarationContext(GCX);
  DSL->SetDeclarationContext(CTX);
  DSL->SetLocalScope();
  ASTScopeController::Instance().SetDeclarationContext(DSL, CTX);
  ASTScopeController::Instance().SetLocalScope(DSL);

  ASTExpressionNodeList EL;
  ASTScopeController::Instance().SetDeclarationContext(&EL, CTX);
  ASTScopeController::Instance().SetLocalScope(&EL);

  ASTDefcalNode *DN = nullptr;

  if (GS) {
    std::string SGS = ASTStringUtils::Instance().Sanitize(GS->GetValue());
    DN = ASTBuilder::Instance().CreateASTDefcalNode(Id, SGS, EL, *DSL, BQL);
  } else {
    DN = ASTBuilder::Instance().CreateASTDefcalNode(Id, EL, *DSL, BQL);
  }

  assert(DN && "Could not create a valid ASTDefcalNode!");

  DN->SetLocation(TK->GetLocation());
  DN->SetDeclarationContext(GCX);
  DN->TransferLocalSymbolTable();
  DSL->TransferDeclarations(DN->GetSymbolTable());
  DN->Mangle();

  ASTDefcalDeclarationNode *DDN =
      ASTBuilder::Instance().CreateASTDefcalDeclaration(Id, DN);
  assert(DDN && "Could not create a valid ASTDefcalDeclarationNode!");

  DDN->SetLocation(TK->GetLocation());
  DDN->SetDeclarationContext(GCX);

  ASTDefcalBuilder::Instance().CloseContext();
  OpenPulse::ASTOpenPulseCalibrationBuilder::Instance().CloseContext();
  ASTDeclarationContextTracker::Instance().PopCurrentContext();
  ASTIdentifierTypeController::Instance().StopAngleList();
  ASTIdentifierTypeController::Instance().StopQubitList();
  ASTIdentifierTypeController::Instance().Reset();
  ASTIdentifierTypeController::Instance().SetCurrentType(ASTTypeUndefined);
  ASTDefcalContextBuilder::Instance().CloseContext();
  return DDN;
}

ASTDefcalDeclarationNode *ASTProductionFactory::ProductionRule_1442(
    const ASTMeasureNode *MN, const ASTToken *TK, ASTStatementList *DSL,
    const ASTStringNode *GS) const {
  assert(MN && "Invalid ASTMeasureNode argument!");
  assert(TK && "Invalid ASTToken argument!");
  assert(DSL && "Invalid Defcal StatementList!");

  QasmFeatureTester::Instance().ValidateFeature("defcal");
  ASTDefcalBuilder::Instance().ValidateDefcalContext();

  ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  CTX->SetContextType(ASTTypeDefcal);

  if (!ASTDefcalBuilder::Instance().InOpenContext()) {
    std::stringstream M;
    M << "Defcal declaration " << MN->GetName() << " is outside an "
      << "open defcal context.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTDefcalDeclarationNode::DeclarationError(MN->GetIdentifier(),
                                                      M.str());
  }

  // defcal measure statements belong to the same defcal group.
  ASTMapSymbolTableEntry *MSTE =
      ASTSymbolTable::Instance().FindDefcalGroup("defcalmeasure");

  if (!MSTE)
    MSTE = ASTSymbolTable::Instance().CreateDefcalGroup("defcalmeasure");

  if (!MSTE) {
    std::stringstream M;
    M << "Failed to create a defcal group for defcal measure.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTDefcalDeclarationNode::DeclarationError(MN->GetIdentifier(),
                                                      M.str());
  }

  assert(MSTE && "Could not obtain a valid defcal group SymbolTableEntry!");

  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      "defcalmeasure", ASTDefcalNode::DefcalBits, ASTTypeDefcal);
  assert(Id && "Could not create a valid Defcal ASTIdentifierNode!");

  const ASTDeclarationContext *GCX =
      ASTDeclarationContextTracker::Instance().GetGlobalContext();

  Id->SetDefcalGroupName("defcalmeasure");
  Id->SetDeclarationContext(GCX);

  DSL->SetLocalScope();
  ASTScopeController::Instance().SetDeclarationContext(DSL, CTX);
  ASTScopeController::Instance().SetLocalScope(DSL);

  const ASTIdentifierNode *QId = MN->GetTarget()->GetIdentifier();
  assert(QId && "Could not retrieve a valid Measure Result ASTIdentifierNode!");

  if (!QId->IsBoundQubit()) {
    OpenPulse::ASTOpenPulseCalibrationBuilder::Instance().CloseContext();
    ASTDeclarationContextTracker::Instance().PopCurrentContext();
    ASTDefcalContextBuilder::Instance().CloseContext();
    ASTDefcalBuilder::Instance().CloseContext();
    ASTIdentifierTypeController::Instance().StopAngleList();
    ASTIdentifierTypeController::Instance().StopQubitList();
    ASTIdentifierTypeController::Instance().Reset();
    ASTIdentifierTypeController::Instance().SetCurrentType(ASTTypeUndefined);
    std::stringstream M;
    M << "Defcal Target Qubit must be a Bound Qubit.";
    ASTDefcalBuilder::Instance().CloseContext();
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTDefcalDeclarationNode::DeclarationError(Id, M.str());
  }

  ASTDefcalNode *DN = nullptr;

  if (GS) {
    std::string SGS = ASTStringUtils::Instance().Sanitize(GS->GetValue());
    DN = ASTBuilder::Instance().CreateASTDefcalNode(Id, SGS, *DSL, MN);
  } else {
    DN = ASTBuilder::Instance().CreateASTDefcalNode(Id, *DSL, MN);
  }

  assert(DN && "Could not create a valid ASTDefcalNode!");

  DN->SetLocation(TK->GetLocation());
  DN->SetDeclarationContext(GCX);
  DN->TransferLocalSymbolTable();
  DSL->TransferDeclarations(DN->GetSymbolTable());
  DN->Mangle();

  ASTDefcalDeclarationNode *DDN =
      ASTBuilder::Instance().CreateASTDefcalDeclaration(Id, DN);
  assert(DDN && "Could not create a valid ASTDefcalDeclarationNode!");

  DDN->SetLocation(TK->GetLocation());
  DDN->SetDeclarationContext(GCX);

  ASTDefcalBuilder::Instance().CloseContext();
  OpenPulse::ASTOpenPulseCalibrationBuilder::Instance().CloseContext();
  ASTDeclarationContextTracker::Instance().PopCurrentContext();
  ASTDefcalContextBuilder::Instance().CloseContext();
  ASTIdentifierTypeController::Instance().StopAngleList();
  ASTIdentifierTypeController::Instance().StopQubitList();
  ASTIdentifierTypeController::Instance().Reset();
  ASTIdentifierTypeController::Instance().SetCurrentType(ASTTypeUndefined);
  return DDN;
}

ASTDefcalDeclarationNode *ASTProductionFactory::ProductionRule_1443(
    const ASTToken *DTK, const ASTToken *RTK, ASTIdentifierNode *QId,
    ASTStatementList *DSL, const ASTStringNode *GS) const {
  assert(DTK && "Invalid ASTToken argument!");
  assert(RTK && "Invalid ASTToken argument!");
  assert(QId && "Invalid ASTIdentifierNode argument!");
  assert(DSL && "Invalid ASTStatementList argument!");

  QasmFeatureTester::Instance().ValidateFeature("defcal");
  ASTDefcalBuilder::Instance().ValidateDefcalContext();

  ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  CTX->SetContextType(ASTTypeDefcal);

  ASTScopeController::Instance().CheckOutOfScope(QId);
  ASTIdentifierTypeController::Instance().CheckIsHardwareQubit(QId);
  QId->SetRValue();

  if (!ASTDefcalBuilder::Instance().InOpenContext()) {
    std::stringstream M;
    M << "defcal reset declaration is outside an open defcal context.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DTK), M.str(),
        DiagLevel::Error);
    return ASTDefcalDeclarationNode::DeclarationError(QId, M.str());
  }

  std::stringstream S;
  S << "ast-reset-" << DIAGLineCounter::Instance().GetIdentifierLocation(RTK);

  ASTIdentifierNode *RId = ASTBuilder::Instance().CreateASTIdentifierNode(
      S.str(), ASTResetNode::ResetBits, ASTTypeReset);
  assert(RId && "Could not create a valid Reset ASTIdentifierNode!");

  RId->SetLocation(RTK->GetLocation());
  RId->SetResetName("reset");
  RId->SetDeclarationContext(CTX);

  ASTResetNode *RN = ASTBuilder::Instance().CreateASTResetNode(RId, QId);
  assert(RN && "Could not create a valid ASTResetNode!");

  RN->SetLocation(RTK->GetLocation());
  RN->SetDeclarationContext(CTX);
  RN->Mangle();

  // defcal reset statements belong to the same defcal group.
  ASTMapSymbolTableEntry *MSTE =
      ASTSymbolTable::Instance().FindDefcalGroup("defcalreset");

  if (!MSTE)
    MSTE = ASTSymbolTable::Instance().CreateDefcalGroup("defcalreset");
  if (!MSTE) {
    std::stringstream M;
    M << "Failed to create a defcal group for defcal reset.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DTK), M.str(), DiagLevel::ICE);
    return ASTDefcalDeclarationNode::DeclarationError(QId, M.str());
  }

  assert(MSTE && "Could not obtain a valid defcal ASTMapSymbolTableEntry!");

  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      "defcalreset", ASTDefcalNode::DefcalBits, ASTTypeDefcal);
  assert(Id && "Could not create a valid Defcal ASTIdentifierNode!");

  const ASTDeclarationContext *GCX =
      ASTDeclarationContextTracker::Instance().GetGlobalContext();

  Id->SetDefcalGroupName("defcalreset");
  Id->SetDeclarationContext(GCX);

  DSL->SetLocalScope();
  ASTScopeController::Instance().SetDeclarationContext(DSL, CTX);
  ASTScopeController::Instance().SetLocalScope(DSL);

  if (!QId->IsBoundQubit()) {
    OpenPulse::ASTOpenPulseCalibrationBuilder::Instance().CloseContext();
    ASTDeclarationContextTracker::Instance().PopCurrentContext();
    ASTDefcalContextBuilder::Instance().CloseContext();
    ASTDefcalBuilder::Instance().CloseContext();
    ASTIdentifierTypeController::Instance().StopAngleList();
    ASTIdentifierTypeController::Instance().StopQubitList();
    ASTIdentifierTypeController::Instance().Reset();
    ASTIdentifierTypeController::Instance().SetCurrentType(ASTTypeUndefined);
    std::stringstream M;
    M << "Defcal Target Qubit must be a Bound Qubit.";
    ASTDefcalBuilder::Instance().CloseContext();
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DTK), M.str(),
        DiagLevel::Error);
    return ASTDefcalDeclarationNode::DeclarationError(Id, M.str());
  }

  ASTDefcalNode *DN = nullptr;

  if (GS) {
    std::string SGS = ASTStringUtils::Instance().Sanitize(GS->GetValue());
    DN = ASTBuilder::Instance().CreateASTDefcalNode(Id, SGS, *DSL, RN);
  } else {
    DN = ASTBuilder::Instance().CreateASTDefcalNode(Id, *DSL, RN);
  }

  assert(DN && "Could not create a valid ASTDefcalNode!");

  DN->SetLocation(DTK->GetLocation());
  DN->SetDeclarationContext(GCX);
  DN->TransferLocalSymbolTable();
  DSL->TransferDeclarations(DN->GetSymbolTable());
  DN->Mangle();

  ASTDefcalDeclarationNode *DDN =
      ASTBuilder::Instance().CreateASTDefcalDeclaration(Id, DN);
  assert(DDN && "Could not create a valid ASTDefcalDeclarationNode!");

  DDN->SetLocation(DTK->GetLocation());
  DDN->SetDeclarationContext(GCX);

  ASTDefcalBuilder::Instance().CloseContext();
  OpenPulse::ASTOpenPulseCalibrationBuilder::Instance().CloseContext();
  ASTDeclarationContextTracker::Instance().PopCurrentContext();
  ASTDefcalContextBuilder::Instance().CloseContext();
  ASTIdentifierTypeController::Instance().StopAngleList();
  ASTIdentifierTypeController::Instance().StopQubitList();
  ASTIdentifierTypeController::Instance().Reset();
  ASTIdentifierTypeController::Instance().SetCurrentType(ASTTypeUndefined);
  return DDN;
}

ASTDefcalDeclarationNode *ASTProductionFactory::ProductionRule_1444(
    const ASTToken *DTK, const ASTToken *DLTK, const ASTStringNode *TS,
    ASTBoundQubitList *QL, ASTStatementList *DSL,
    const ASTStringNode *GS) const {
  assert(DTK && "Invalid ASTToken argument!");
  assert(DLTK && "Invalid ASTToken argument!");
  assert(TS && "Invalid ASTStringNode argument!");
  assert(QL && "Invalid ASTBoundQubitList argument!");
  assert(DSL && "Invalid ASTStatementList argument!");

  ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  CTX->SetContextType(ASTTypeDefcal);

  if (!ASTDefcalBuilder::Instance().InOpenContext()) {
    std::stringstream M;
    M << "Defcal delay declaration is outside an "
      << "open defcal context.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DTK), M.str(),
        DiagLevel::Error);
    const ASTIdentifierNode *Id = ASTIdentifierNode::Defcal.Clone();
    return ASTDefcalDeclarationNode::DeclarationError(Id, M.str());
  }

  // defcal delay statements belong to the same defcal group.
  ASTMapSymbolTableEntry *DSTE =
      ASTSymbolTable::Instance().FindDefcalGroup("defcaldelay");

  if (!DSTE)
    DSTE = ASTSymbolTable::Instance().CreateDefcalGroup("defcaldelay");

  if (!DSTE) {
    std::stringstream M;
    M << "Failed to create a defcal group for defcal delay.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DTK), M.str(), DiagLevel::ICE);
    const ASTIdentifierNode *Id = ASTIdentifierNode::Defcal.Clone();
    return ASTDefcalDeclarationNode::DeclarationError(Id, M.str());
  }

  assert(DSTE && "Could not obtain a valid defcal group SymbolTableEntry!");

  if (!QL->ValidateQubits()) {
    std::stringstream M;
    M << "Defcal Delay Bound Qubit validation failed.";
    ASTDefcalBuilder::Instance().CloseContext();
    OpenPulse::ASTOpenPulseCalibrationBuilder::Instance().CloseContext();
    ASTDeclarationContextTracker::Instance().PopCurrentContext();
    ASTDefcalContextBuilder::Instance().CloseContext();
    ASTDefcalBuilder::Instance().CloseContext();
    ASTIdentifierTypeController::Instance().StopAngleList();
    ASTIdentifierTypeController::Instance().StopQubitList();
    ASTIdentifierTypeController::Instance().Reset();
    ASTIdentifierTypeController::Instance().SetCurrentType(ASTTypeUndefined);
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(QL), M.str(), DiagLevel::Error);
    const ASTIdentifierNode *Id = ASTIdentifierNode::Defcal.Clone();
    return ASTDefcalDeclarationNode::DeclarationError(Id, M.str());
  }

  std::stringstream DLS;
  DLS << "ast-delay-node-"
      << DIAGLineCounter::Instance().GetIdentifierLocation(DLTK);
  ASTIdentifierNode *DLId = ASTBuilder::Instance().CreateASTIdentifierNode(
      DLS.str(), ASTDelayNode::DelayBits, ASTTypeDelay);
  assert(DLId && "Could not create a valid ASTIdentifierNode!");

  DLId->SetPolymorphicName("delay");
  ASTIdentifierNode *TId =
      new ASTIdentifierNode(TS->GetValue(), ASTTypeTimeUnit, 64U);
  assert(TId && "Could not create a valid ASTIdentifierNode!");

  ASTIdentifierList IL;

  ASTDelayNode *DN =
      ASTBuilder::Instance().CreateASTDelayNode(DLId, TId, IL, TS->GetValue());
  assert(DN && "Could not create a valid ASTDelayNode!");

  DN->SetLocation(DLTK->GetLocation());
  DN->SetDeclarationContext(CTX);
  DN->Mangle();

  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      "defcaldelay", ASTDefcalNode::DefcalBits, ASTTypeDefcal);
  assert(Id && "Could not create a valid Defcal ASTIdentifierNode!");

  const ASTDeclarationContext *GCX =
      ASTDeclarationContextTracker::Instance().GetGlobalContext();

  Id->SetDefcalGroupName("defcaldelay");
  Id->SetDeclarationContext(GCX);

  DSL->SetLocalScope();
  ASTScopeController::Instance().SetDeclarationContext(DSL, CTX);
  ASTScopeController::Instance().SetLocalScope(DSL);

  ASTDefcalNode *DCN = nullptr;

  if (GS) {
    std::string SGS = ASTStringUtils::Instance().Sanitize(GS->GetValue());
    DCN = ASTBuilder::Instance().CreateASTDefcalNode(Id, SGS, DN, *DSL, QL);
  } else {
    DCN = ASTBuilder::Instance().CreateASTDefcalNode(Id, DN, *DSL, QL);
  }

  assert(DCN && "Could not create a valid ASTDefcalNode!");

  DCN->SetLocation(DTK->GetLocation());
  DCN->SetDeclarationContext(GCX);
  DCN->TransferLocalSymbolTable();
  DSL->TransferDeclarations(DCN->GetSymbolTable());
  ASTSymbolTable::Instance().TransferLocalContextSymbols(CTX,
                                                         DCN->GetSymbolTable());
  DCN->Mangle();

  ASTDefcalDeclarationNode *DDN =
      ASTBuilder::Instance().CreateASTDefcalDeclaration(Id, DCN);
  assert(DDN && "Could not create a valid ASTDefcalDeclarationNode!");

  DDN->SetLocation(DTK->GetLocation());
  DDN->SetDeclarationContext(GCX);

  ASTDefcalBuilder::Instance().CloseContext();
  OpenPulse::ASTOpenPulseCalibrationBuilder::Instance().CloseContext();
  ASTDeclarationContextTracker::Instance().PopCurrentContext();
  ASTIdentifierTypeController::Instance().StopAngleList();
  ASTIdentifierTypeController::Instance().StopQubitList();
  ASTIdentifierTypeController::Instance().Reset();
  ASTIdentifierTypeController::Instance().SetCurrentType(ASTTypeUndefined);
  ASTDefcalContextBuilder::Instance().CloseContext();
  return DDN;
}

ASTDefcalDeclarationNode *ASTProductionFactory::ProductionRule_1445(
    const ASTToken *DTK, const ASTToken *DLTK, ASTDurationOfNode *DRN,
    ASTBoundQubitList *QL, ASTStatementList *DSL,
    const ASTStringNode *GS) const {
  assert(DTK && "Invalid ASTToken argument!");
  assert(DLTK && "Invalid ASTToken argument!");
  assert(DRN && "Invalid ASTDurationOfNode argument!");
  assert(QL && "Invalid ASTBoundQubitList argument!");
  assert(DSL && "Invalid ASTStatementList argument!");

  ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  CTX->SetContextType(ASTTypeDefcal);

  if (!ASTDefcalBuilder::Instance().InOpenContext()) {
    std::stringstream M;
    M << "Defcal delay declaration is outside an "
      << "open defcal context.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DTK), M.str(),
        DiagLevel::Error);
    const ASTIdentifierNode *Id = ASTIdentifierNode::Defcal.Clone();
    return ASTDefcalDeclarationNode::DeclarationError(Id, M.str());
  }

  // defcal delay statements belong to the same defcal group.
  ASTMapSymbolTableEntry *DSTE =
      ASTSymbolTable::Instance().FindDefcalGroup("defcalduration");

  if (!DSTE)
    DSTE = ASTSymbolTable::Instance().CreateDefcalGroup("defcalduration");

  if (!DSTE) {
    std::stringstream M;
    M << "Failed to create a defcal group for defcal duration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DTK), M.str(), DiagLevel::ICE);
    const ASTIdentifierNode *Id = ASTIdentifierNode::Defcal.Clone();
    return ASTDefcalDeclarationNode::DeclarationError(Id, M.str());
  }

  assert(DSTE && "Could not obtain a valid defcal group SymbolTableEntry!");

  if (!QL->ValidateQubits()) {
    std::stringstream M;
    M << "Defcal Delay Bound Qubit validation failed.";
    ASTDefcalBuilder::Instance().CloseContext();
    OpenPulse::ASTOpenPulseCalibrationBuilder::Instance().CloseContext();
    ASTDeclarationContextTracker::Instance().PopCurrentContext();
    ASTDefcalContextBuilder::Instance().CloseContext();
    ASTDefcalBuilder::Instance().CloseContext();
    ASTIdentifierTypeController::Instance().StopAngleList();
    ASTIdentifierTypeController::Instance().StopQubitList();
    ASTIdentifierTypeController::Instance().Reset();
    ASTIdentifierTypeController::Instance().SetCurrentType(ASTTypeUndefined);
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(QL), M.str(), DiagLevel::Error);
    const ASTIdentifierNode *Id = ASTIdentifierNode::Defcal.Clone();
    return ASTDefcalDeclarationNode::DeclarationError(Id, M.str());
  }

  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      "defcaldurationof", ASTDefcalNode::DefcalBits, ASTTypeDefcal);
  assert(Id && "Could not create a valid Defcal ASTIdentifierNode!");

  const ASTDeclarationContext *GCX =
      ASTDeclarationContextTracker::Instance().GetGlobalContext();

  Id->SetDefcalGroupName("defcaldurationof");
  Id->SetDeclarationContext(GCX);

  DSL->SetLocalScope();
  ASTScopeController::Instance().SetDeclarationContext(DSL, CTX);
  ASTScopeController::Instance().SetLocalScope(DSL);

  ASTDefcalNode *DCN = nullptr;

  if (GS) {
    std::string SGS = ASTStringUtils::Instance().Sanitize(GS->GetValue());
    DCN = ASTBuilder::Instance().CreateASTDefcalNode(Id, SGS, DRN, *DSL, QL);
  } else {
    DCN = ASTBuilder::Instance().CreateASTDefcalNode(Id, DRN, *DSL, QL);
  }

  assert(DCN && "Could not create a valid ASTDefcalNode!");

  DCN->SetLocation(DTK->GetLocation());
  DCN->SetDeclarationContext(GCX);
  DCN->TransferLocalSymbolTable();
  DSL->TransferDeclarations(DCN->GetSymbolTable());
  ASTSymbolTable::Instance().TransferLocalContextSymbols(CTX,
                                                         DCN->GetSymbolTable());
  DCN->Mangle();

  ASTDefcalDeclarationNode *DDN =
      ASTBuilder::Instance().CreateASTDefcalDeclaration(Id, DCN);
  assert(DDN && "Could not create a valid ASTDefcalDeclarationNode!");

  DDN->SetLocation(DTK->GetLocation());
  DDN->SetDeclarationContext(GCX);

  ASTDefcalBuilder::Instance().CloseContext();
  OpenPulse::ASTOpenPulseCalibrationBuilder::Instance().CloseContext();
  ASTDeclarationContextTracker::Instance().PopCurrentContext();
  ASTIdentifierTypeController::Instance().StopAngleList();
  ASTIdentifierTypeController::Instance().StopQubitList();
  ASTIdentifierTypeController::Instance().Reset();
  ASTIdentifierTypeController::Instance().SetCurrentType(ASTTypeUndefined);
  ASTDefcalContextBuilder::Instance().CloseContext();
  return DDN;
}

ASTDefcalDeclarationNode *ASTProductionFactory::ProductionRule_1445(
    const ASTToken *DTK, const ASTToken *DRTK, const ASTIdentifierNode *DId,
    ASTBoundQubitList *QL, ASTStatementList *DSL,
    const ASTStringNode *GS) const {
  assert(DTK && "Invalid ASTToken argument!");
  assert(DRTK && "Invalid ASTToken argument!");
  assert(DId && "Invalid ASTIdentifierNode argument!");
  assert(QL && "Invalid ASTBoundQubitList argument!");
  assert(DSL && "Invalid ASTStatementList argument!");

  ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  CTX->SetContextType(ASTTypeDefcal);

  if (!ASTDefcalBuilder::Instance().InOpenContext()) {
    std::stringstream M;
    M << "Defcal delay declaration is outside an "
      << "open defcal context.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DTK), M.str(),
        DiagLevel::Error);
    const ASTIdentifierNode *Id = ASTIdentifierNode::Defcal.Clone();
    return ASTDefcalDeclarationNode::DeclarationError(Id, M.str());
  }

  ASTScopeController::Instance().CheckScopeAndUndefined(DId);

  if (DId->GetSymbolType() != ASTTypeDuration) {
    std::stringstream M;
    M << "Defcal delay identifier argument is not a Duration Type.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DTK), M.str(),
        DiagLevel::Error);
    const ASTIdentifierNode *Id = ASTIdentifierNode::Defcal.Clone();
    return ASTDefcalDeclarationNode::DeclarationError(Id, M.str());
  }

  const ASTSymbolTableEntry *DRSTE =
      ASTSymbolTable::Instance().FindLocalSymbol(DId);
  if (!DRSTE)
    DRSTE = ASTSymbolTable::Instance().FindGlobalSymbol(DId);

  if (!DRSTE) {
    std::stringstream M;
    M << "Unknown Duration " << DId->GetName() << " at current scope.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DTK), M.str(),
        DiagLevel::Error);
    const ASTIdentifierNode *Id = ASTIdentifierNode::Defcal.Clone();
    return ASTDefcalDeclarationNode::DeclarationError(Id, M.str());
  }

  ASTDurationNode *DRN = DRSTE->GetValue()->GetValue<ASTDurationNode *>();
  assert(DRN &&
         "Could not obtain a valid ASTDurationNode from the SymbolTable!");

  // defcal delay statements belong to the same defcal group.
  ASTMapSymbolTableEntry *DSTE =
      ASTSymbolTable::Instance().FindDefcalGroup("defcaldelay");

  if (!DSTE)
    DSTE = ASTSymbolTable::Instance().CreateDefcalGroup("defcaldelay");

  if (!DSTE) {
    std::stringstream M;
    M << "Failed to create a defcal group for defcal duration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DTK), M.str(), DiagLevel::ICE);
    const ASTIdentifierNode *Id = ASTIdentifierNode::Defcal.Clone();
    return ASTDefcalDeclarationNode::DeclarationError(Id, M.str());
  }

  assert(DSTE && "Could not obtain a valid defcal group SymbolTableEntry!");

  if (!QL->ValidateQubits()) {
    std::stringstream M;
    M << "Defcal Delay Bound Qubit validation failed.";
    ASTDefcalBuilder::Instance().CloseContext();
    OpenPulse::ASTOpenPulseCalibrationBuilder::Instance().CloseContext();
    ASTDeclarationContextTracker::Instance().PopCurrentContext();
    ASTDefcalContextBuilder::Instance().CloseContext();
    ASTDefcalBuilder::Instance().CloseContext();
    ASTIdentifierTypeController::Instance().StopAngleList();
    ASTIdentifierTypeController::Instance().StopQubitList();
    ASTIdentifierTypeController::Instance().Reset();
    ASTIdentifierTypeController::Instance().SetCurrentType(ASTTypeUndefined);
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(QL), M.str(), DiagLevel::Error);
    const ASTIdentifierNode *Id = ASTIdentifierNode::Defcal.Clone();
    return ASTDefcalDeclarationNode::DeclarationError(Id, M.str());
  }

  ASTIdentifierList QIL;
  if (!QL->ToASTIdentifierList(QIL)) {
    std::stringstream M;
    M << "Could not convert an ASTBoundQubitList to an ASTIdentifierList.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(QL), M.str(), DiagLevel::ICE);
    const ASTIdentifierNode *Id = ASTIdentifierNode::Defcal.Clone();
    return ASTDefcalDeclarationNode::DeclarationError(Id, M.str());
  }

  std::stringstream DLSS;
  DLSS << "ast-delay-"
       << DIAGLineCounter::Instance().GetIdentifierLocation(DRTK);
  ASTIdentifierNode *DLId = ASTBuilder::Instance().CreateASTIdentifierNode(
      DLSS.str(), ASTDelayNode::DelayBits, ASTTypeDelay, CTX);
  assert(DLId && "Could not create a valid ASTIdentifierNode!");

  DLId->SetPolymorphicName("delay");
  DLId->SetDeclarationContext(CTX);
  DLId->SetLocalScope();

  ASTDelayNode *DLN = ASTBuilder::Instance().CreateASTDelayNode(DLId, DRN, QIL);
  assert(DLN && "Could not create a valid ASTDelayNode!");

  DLN->SetLocation(DRTK->GetLocation());
  DLN->SetDeclarationContext(CTX);
  DLN->Mangle();

  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      "defcaldelay", ASTDefcalNode::DefcalBits, ASTTypeDefcal);
  assert(Id && "Could not create a valid Defcal ASTIdentifierNode!");

  const ASTDeclarationContext *GCX =
      ASTDeclarationContextTracker::Instance().GetGlobalContext();

  Id->SetDefcalGroupName("defcaldelay");
  Id->SetPolymorphicName("defcaldelay");
  Id->SetDeclarationContext(GCX);
  Id->SetGlobalScope();

  DSL->SetLocalScope();
  ASTScopeController::Instance().SetDeclarationContext(DSL, CTX);
  ASTScopeController::Instance().SetLocalScope(DSL);

  ASTDefcalNode *DCN = nullptr;

  if (GS) {
    std::string SGS = ASTStringUtils::Instance().Sanitize(GS->GetValue());
    DCN = ASTBuilder::Instance().CreateASTDefcalNode(Id, SGS, DLN, *DSL, QL);
  } else {
    DCN = ASTBuilder::Instance().CreateASTDefcalNode(Id, DLN, *DSL, QL);
  }

  assert(DCN && "Could not create a valid ASTDefcalNode!");

  DCN->SetLocation(DTK->GetLocation());
  DCN->SetDeclarationContext(GCX);
  DCN->TransferLocalSymbolTable();
  DSL->TransferDeclarations(DCN->GetSymbolTable());
  ASTSymbolTable::Instance().TransferLocalContextSymbols(CTX,
                                                         DCN->GetSymbolTable());
  DCN->Mangle();

  ASTDefcalDeclarationNode *DDN =
      ASTBuilder::Instance().CreateASTDefcalDeclaration(Id, DCN);
  assert(DDN && "Could not create a valid ASTDefcalDeclarationNode!");

  DDN->SetLocation(DTK->GetLocation());
  DDN->SetDeclarationContext(GCX);

  ASTDefcalBuilder::Instance().CloseContext();
  OpenPulse::ASTOpenPulseCalibrationBuilder::Instance().CloseContext();
  ASTDeclarationContextTracker::Instance().PopCurrentContext();
  ASTIdentifierTypeController::Instance().StopAngleList();
  ASTIdentifierTypeController::Instance().StopQubitList();
  ASTIdentifierTypeController::Instance().Reset();
  ASTIdentifierTypeController::Instance().SetCurrentType(ASTTypeUndefined);
  ASTDefcalContextBuilder::Instance().CloseContext();
  return DDN;
}

ASTDefcalGrammarNode *
ASTProductionFactory::ProductionRule_1445(const ASTToken *TK,
                                          ASTStringNode *GS) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(GS && "Invalid ASTStringNode argument!");

  QasmFeatureTester::Instance().ValidateFeature("defcal");

  std::string DGS = ASTStringUtils::Instance().Sanitize(GS->GetValue());
  assert(!DGS.empty() && "Invalid defcal grammar identifier!");

  GS->SetValue(DGS);
  ASTIdentifierNode *Id = ASTBuilder::Instance().FindASTIdentifierNode(
      GS->GetValue(), ASTDefcalGrammarNode::GrammarBits, ASTTypeDefcalGrammar);
  if (!Id)
    Id = ASTBuilder::Instance().CreateASTIdentifierNode(
        GS->GetValue(), ASTDefcalGrammarNode::GrammarBits,
        ASTTypeDefcalGrammar);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  ASTSymbolTableEntry *STE =
      ASTSymbolTable::Instance().Lookup(Id, Id->GetBits(), Id->GetSymbolType());
  assert(STE && "Could not retrieve a valid SymbolTable Entry!");

  ASTDefcalGrammarNode *DG = nullptr;

  if (!STE->HasValue()) {
    const ASTDeclarationContext *GCX =
        ASTDeclarationContextTracker::Instance().GetGlobalContext();
    assert(GCX && "Could not obtain a valid Global ASTDeclarationContext!");

    DG = new ASTDefcalGrammarNode(Id, GS);
    assert(DG && "Could not create a valid ASTDefcalGrammarNode!");

    DG->SetLocation(TK->GetLocation());
    DG->SetDeclarationContext(GCX);

    STE->ResetValue();
    STE->SetValue(new ASTValue<>(DG, ASTTypeDefcalGrammar),
                  ASTTypeDefcalGrammar);
    assert(STE->HasValue() &&
           "SymbolTable Entry for ASTDefcalGrammar has no Value!");
  } else {
    DG = STE->GetValue()->GetValue<ASTDefcalGrammarNode *>();
    assert(DG && "Could not retrieve a valid ASTDefcalGrammarNode!");
  }

  ASTDefcalGrammarBuilder::Instance().SetCurrent(GS->GetValue());
  return DG;
}

ASTBarrierNode *
ASTProductionFactory::ProductionRule_1450(const ASTToken *TK,
                                          const ASTIdentifierList *IL) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(IL && "Invalid ASTIdentifierList argument!");

  QasmFeatureTester::Instance().ValidateFeature("barrier");
  IL->CheckOutOfScope();

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  std::stringstream S;
  S << "ast-barrier-" << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      S.str(), ASTBarrierNode::BarrierBits, ASTTypeBarrier);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  Id->SetDeclarationContext(CTX);

  ASTBarrierNode *BN = ASTBuilder::Instance().CreateASTBarrierNode(Id, *IL);
  assert(BN && "Could not create a valid ASTBarrierNode!");
  BN->SetDeclarationContext(CTX);
  BN->SetLocation(TK->GetLocation());
  BN->Mangle();
  return BN;
}

ASTBarrierNode *
ASTProductionFactory::ProductionRule_1451(const ASTToken *TK) const {
  assert(TK && "Invalid ASTToken argument!");

  QasmFeatureTester::Instance().ValidateFeature("barrier");
  ASTIdentifierList IL;

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  std::stringstream S;
  S << "ast-barrier-" << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      S.str(), ASTBarrierNode::BarrierBits, ASTTypeBarrier);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  Id->SetDeclarationContext(CTX);
  ASTBarrierNode *BN = ASTBuilder::Instance().CreateASTBarrierNode(Id, IL);
  assert(BN && "Could not create a valid ASTBarrierNode!");
  BN->SetDeclarationContext(CTX);
  BN->SetLocation(TK->GetLocation());
  BN->Mangle();
  return BN;
}

ASTResetNode *
ASTProductionFactory::ProductionRule_1480(const ASTToken *TK,
                                          const ASTIdentifierNode *TId) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(TId && "Invalid ASTIdentifierNode Reset argument!");

  ASTScopeController::Instance().CheckOutOfScope(TId);

  if (ASTGateContextBuilder::Instance().InOpenContext()) {
    std::stringstream M;
    M << "A reset cannot occur within a gate statement sequence.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTResetNode::StatementError(ASTIdentifierNode::Reset.Clone(),
                                        M.str());
  }

  const ASTSymbolTableEntry *STE = TId->GetSymbolTableEntry();
  assert(STE && "Could not obtain a valid Target SymbolTable Entry!");

  const ASTIdentifierRefNode *TTId = nullptr;
  bool IsRef = TId->IsReference() || TId->GetASTType() == ASTTypeIdentifierRef;

  if (IsRef) {
    TTId = dynamic_cast<const ASTIdentifierRefNode *>(TId);
    assert(TTId && "Could not dynamic_cast to an ASTIdentifierRefNode!");

    std::string QN =
        ASTStringUtils::Instance().GetIdentifierBase(TTId->GetName());
    assert(!QN.empty() &&
           "Could not obtain a valid base ASTIdentifierNode Name!");

    STE = ASTSymbolTable::Instance().FindQubit(QN);
    assert(STE && "Could not obtain a valid Target SymbolTable Entry!");

    TId = STE->GetIdentifier();
    assert(TId && "ASTSymbolTableEntry has an invalid ASTIdentifierNode!");
  }

  if (!STE->HasValue()) {
    std::stringstream M;
    M << "Attempting to reset an implicitly declared physical qubit ("
      << TId->GetName() << ").";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTResetNode::StatementError(ASTIdentifierNode::Reset.Clone(),
                                        M.str());
  }

  switch (TId->GetSymbolType()) {
  case ASTTypeQubit: {
    ASTQubitNode *QN = STE->GetValue()->GetValue<ASTQubitNode *>();
    assert(QN && "Could not obtain a valid ASTQubitNode!");
    QN->Mangle();
  } break;
  case ASTTypeQubitContainer: {
    ASTQubitContainerNode *QCN =
        STE->GetValue()->GetValue<ASTQubitContainerNode *>();
    assert(QCN && "Could not obtain a valid ASTQubitContainerNode!");
    QCN->Mangle();
  } break;
  case ASTTypeQubitContainerAlias: {
    ASTQubitContainerAliasNode *QCAN =
        STE->GetValue()->GetValue<ASTQubitContainerAliasNode *>();
    assert(QCAN && "Could not obtain a valid ASTQubitContainerAliasNode!");
    QCAN->Mangle();
  } break;
  case ASTTypeGateQubitParam: {
    std::stringstream M;
    M << "Attempting to reset a Gate Qubit Parameter.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTResetNode::StatementError(ASTIdentifierNode::Reset.Clone(),
                                        M.str());
  } break;
  default: {
    std::stringstream M;
    M << "Only Qubits can be reset.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTResetNode::StatementError(ASTIdentifierNode::Reset.Clone(),
                                        M.str());
  } break;
  }

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  std::stringstream S;
  S << "ast-reset-" << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      S.str(), ASTResetNode::ResetBits, ASTTypeReset);
  assert(Id && "Could not create a valid Reset ASTIdentifierNode!");

  Id->SetPolymorphicName("reset");
  Id->SetDeclarationContext(CTX);

  ASTResetNode *RN =
      ASTBuilder::Instance().CreateASTResetNode(Id, IsRef ? TTId : TId);
  assert(RN && "Could not create a valid ASTResetNode!");

  RN->SetDeclarationContext(CTX);
  RN->SetLocation(TK->GetLocation());
  RN->Mangle();
  return RN;
}

ASTMeasureNode *
ASTProductionFactory::ProductionRule_1461(const ASTToken *TK,
                                          const ASTIdentifierNode *TId,
                                          const ASTIdentifierNode *RId) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(TId && "Invalid ASTIdentifierNode argument!");
  assert(RId && "Invalid ASTIdentifierNode argument!");

  QasmFeatureTester::Instance().ValidateFeature("measure");
  ASTScopeController::Instance().CheckOutOfScope(TId);
  ASTScopeController::Instance().CheckOutOfScope(RId);

  if (ASTGateContextBuilder::Instance().InOpenContext()) {
    std::stringstream M;
    M << "A measure cannot occur within a gate statement sequence.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTMeasureNode::StatementError(ASTIdentifierNode::Measure.Clone(),
                                          M.str());
  }

  unsigned Bits = TId->GetBits();
  const ASTIdentifierRefNode *TIdR = nullptr;
  const ASTIdentifierRefNode *RIdR = nullptr;

  if (TId->IsReference()) {
    TIdR = dynamic_cast<const ASTIdentifierRefNode *>(TId);
    assert(TIdR && "Could not dynamic_cast to a valid ASTIdentifierRefNode!");
    Bits = 1;
  }

  if (RId->IsReference()) {
    RIdR = dynamic_cast<const ASTIdentifierRefNode *>(RId);
    assert(RIdR && "Could not dynamic_cast to a valid ASTIdentifierRefNode!");
    Bits = 1;
  }

  ASTSymbolTableEntry *TSTE =
      TIdR
          ? ASTSymbolTable::Instance().Lookup(TIdR, Bits, TIdR->GetSymbolType())
          : ASTSymbolTable::Instance().Lookup(TId, TId->GetBits(),
                                              TId->GetSymbolType());
  assert(TSTE && "Measure Target Identifier has no SymbolTableEntry!");

  ASTSymbolTableEntry *RSTE =
      RIdR
          ? ASTSymbolTable::Instance().Lookup(RIdR, Bits, RIdR->GetSymbolType())
          : ASTSymbolTable::Instance().Lookup(RId, RId->GetBits(),
                                              RId->GetSymbolType());
  assert(RSTE && "Measure Result Identifier has no SymbolTableEntry!");

  ASTCBitNode *CBN = nullptr;
  ASTAngleNode *ANG = nullptr;
  ASTMPComplexNode *MPC = nullptr;
  ASTType RTy = ASTTypeUndefined;
  unsigned IX = static_cast<unsigned>(~0x0);

  if (RSTE->HasValue()) {
    switch (RSTE->GetValueType()) {
    case ASTTypeBitset:
      CBN = RSTE->GetValue()->GetValue<ASTCBitNode *>();
      assert(CBN && "Invalid Bitset obtained from the SymbolTable!");
      RTy = CBN->GetASTType();
      break;
    case ASTTypeCBitArray: {
      ASTCBitArrayNode *CAN = dynamic_cast<ASTCBitArrayNode *>(
          RSTE->GetValue()->GetValue<ASTArrayNode *>());
      assert(CAN && "Could not dynamic_cast to an ASTCBitArrayNode!");
      unsigned I = RIdR ? RIdR->GetIndex() : RId->GetBits();
      assert(I != static_cast<unsigned>(~0x0) &&
             "Invalid ASTCBitArrayNode Index!");
      CAN->ValidateIndex(I, RIdR ? RIdR->GetLocation() : RId->GetLocation());
      CBN = CAN->GetElement(I);
      assert(CBN && "Invalid Bitset obtained from the ASTCBitArrayNode!");
      RTy = CBN->GetASTType();
    } break;
    case ASTTypeCBitNArray: {
      ASTCBitNArrayNode *CAN = dynamic_cast<ASTCBitNArrayNode *>(
          RSTE->GetValue()->GetValue<ASTArrayNode *>());
      assert(CAN && "Could not dynamic_cast to an ASTCBitArrayNode!");
      unsigned I = RIdR ? RIdR->GetIndex() : RId->GetBits();
      assert(I != static_cast<unsigned>(~0x0) &&
             "Invalid ASTCBitArrayNode Index!");
      CAN->ValidateIndex(I, RIdR ? RIdR->GetLocation() : RId->GetLocation());
      CBN = CAN->GetElement(I);
      assert(CBN && "Invalid Bitset obtained from the ASTCBitNArrayNode!");
      RTy = CBN->GetASTType();
    } break;
    case ASTTypeAngle: {
      ANG = dynamic_cast<ASTAngleNode *>(
          RSTE->GetValue()->GetValue<ASTAngleNode *>());
      assert(ANG && "Could not dynamic_cast to an ASTAngleNode!");
      IX = RIdR ? RIdR->GetIndex() : RId->GetBits();
      assert(IX != static_cast<unsigned>(~0x0) &&
             "Invalid ASTAngleNode Index!");
      RTy = ANG->GetASTType();
    } break;
    case ASTTypeMPComplex: {
      MPC = dynamic_cast<ASTMPComplexNode *>(
          RSTE->GetValue()->GetValue<ASTMPComplexNode *>());
      assert(MPC && "Could not dynamic_cast to an ASTMPComplexNode!");
      IX = RIdR ? RIdR->GetIndex() : RId->GetBits();
      assert(IX != static_cast<unsigned>(~0x0) &&
             "Invalid ASTAngleNode Index!");
      RTy = MPC->GetASTType();
    } break;
    case ASTTypeUndefined:
      if (RIdR)
        CBN = ASTBuilder::Instance().CreateASTCBitNode(RIdR, 1, 0UL);
      else
        CBN = ASTBuilder::Instance().CreateASTCBitNode(RId, 1, 0UL);
      assert(CBN && "Could not create a valid ASTCBitNode!");
      RSTE->ResetValue();
      RSTE->SetValue(new ASTValue<>(CBN, ASTTypeBitset), ASTTypeBitset);
      RTy = CBN->GetASTType();
      break;
    default: {
      std::stringstream M;
      M << "Impossible assignment of a Measure result to a "
        << PrintTypeEnum(RSTE->GetValueType()) << " type.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(RId), M.str(),
          DiagLevel::Error);
      return ASTMeasureNode::StatementError(ASTIdentifierNode::Measure.Clone(),
                                            M.str());
    } break;
    }
  } else {
    if (RIdR)
      CBN = ASTBuilder::Instance().CreateASTCBitNode(RIdR, 1, 0UL);
    else
      CBN = ASTBuilder::Instance().CreateASTCBitNode(RId, 1, 0UL);
    assert(CBN && "Could not create a valid ASTCBitNode!");
    RSTE->ResetValue();
    RSTE->SetValue(new ASTValue<>(CBN, ASTTypeBitset), ASTTypeBitset);
    RTy = CBN->GetASTType();
  }

  assert(RTy != ASTTypeUndefined && "Invalid Measure Result Type!");

  ASTQubitContainerNode *QCN = nullptr;

  if (!TSTE->HasValue()) {
    if (TId->IsReference()) {
      QCN = ASTBuilder::Instance().CreateASTQubitContainerNode(TIdR, Bits);
    } else if (ASTStringUtils::Instance().IsIndexedQubit(TId->GetName())) {
      std::stringstream QIN;
      QIN << ASTStringUtils::Instance().GetBaseQubitName(TId->GetName()) << '['
          << ASTStringUtils::Instance().GetQubitIndex(TId->GetName()) << ']';
      ASTSymbolTableEntry *QSTE = ASTSymbolTable::Instance().Lookup(
          QIN.str(), 1U, ASTTypeQubitContainer);
      if (QSTE) {
        TSTE = QSTE;
        TId = TSTE->GetIdentifier();
        if (TId->IsReference()) {
          TIdR =
              dynamic_cast<const ASTIdentifierRefNode *>(TSTE->GetIdentifier());
          assert(TIdR && "Could not dynamic_cast to an ASTIdentifierRefNode!");
        }
      } else {
      }
    } else {
      QCN = ASTBuilder::Instance().CreateASTQubitContainerNode(TId, Bits);
    }

    assert(QCN && "Could not create a valid ASTQubitContainerNode!");
  } else {
    if (TSTE->GetValueType() == ASTTypeQubitContainer) {
      QCN = TSTE->GetValue()->GetValue<ASTQubitContainerNode *>();
    } else if (TSTE->GetValueType() == ASTTypeQubit) {
      ASTQubitNode *QN = TSTE->GetValue()->GetValue<ASTQubitNode *>();
      assert(QN && "Could not obtain a valid ASTQubitNode!");
      QCN = new ASTQubitContainerNode(TId, 1U, {QN});
      assert(QCN && "Could not create a valid ASTQubitContainerNode!");
      QCN->SetLocation(QN->GetLocation());
      QCN->SetDeclarationContext(QN->GetDeclarationContext());
    } else if (TId->IsReference()) {
      if (TIdR->HasSymbolTableEntry() &&
          TIdR->GetSymbolTableEntry() == TId->GetSymbolTableEntry()) {
        QCN = TIdR->GetSymbolTableEntry()
                  ->GetValue()
                  ->GetValue<ASTQubitContainerNode *>();
      } else {
        QCN = ASTBuilder::Instance().CreateASTQubitContainerNode(TIdR, Bits);
      }
    } else if (ASTStringUtils::Instance().IsIndexedQubit(TId->GetName())) {
      std::string QBN =
          ASTStringUtils::Instance().GetBaseQubitName(TId->GetName());
      const ASTSymbolTableEntry *QSTE =
          ASTSymbolTable::Instance().FindQubit(QBN);
      assert(QSTE && "Base Qubit Container has no SymbolTable Entry!");
      QCN = QSTE->GetValue()->GetValue<ASTQubitContainerNode *>();
    } else {
      QCN = ASTBuilder::Instance().CreateASTQubitContainerNode(TId, Bits);
    }

    assert(QCN && "Could not retrieve a valid ASTQubitContainerNode!");
  }

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  std::stringstream MS;
  MS << "ast-measure-" << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *MId = ASTBuilder::Instance().CreateASTIdentifierNode(
      MS.str(), ASTMeasureNode::MeasureBits, ASTTypeMeasure);
  assert(MId && "Could not create a Measure ASTIdentifierNode!");

  MId->SetGateParamName("measure");
  MId->SetDeclarationContext(CTX);
  MId->SetLocation(TK->GetLocation());

  ASTMeasureNode *MN = nullptr;

  if (RTy == ASTTypeAngle)
    MN = ASTBuilder::Instance().CreateASTMeasureNode(MId, QCN, ANG, IX);
  else if (RTy == ASTTypeMPComplex)
    MN = ASTBuilder::Instance().CreateASTMeasureNode(MId, QCN, MPC, IX);
  else
    MN = ASTBuilder::Instance().CreateASTMeasureNode(MId, QCN, CBN);

  assert(MN && "Could not create an ASTMeasureNode!");

  if (RId->IsReference())
    MN->SetResultIndex(RIdR->GetIndex());

  if (TId->IsReference()) {
    MN->SetTargetIndex(TIdR->GetIndex());
  } else if (ASTStringUtils::Instance().IsIndexedQubit(TId->GetName())) {
    std::string TIS = ASTStringUtils::Instance().GetQubitIndex(TId->GetName());
    MN->SetTargetIndex(static_cast<unsigned>(std::stoul(TIS)));
  }

  MN->SetDeclarationContext(CTX);
  MN->SetLocation(TK->GetLocation());
  MN->Mangle();
  return MN;
}

ASTMeasureNode *
ASTProductionFactory::ProductionRule_1462(const ASTToken *TK,
                                          const ASTIdentifierNode *TId) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(TId && "Invalid ASTIdentifierNode argument!");

  QasmFeatureTester::Instance().ValidateFeature("measure");
  ASTScopeController::Instance().CheckOutOfScope(TId);
  ASTIdentifierTypeController::Instance().CheckIdentifier(TId);

  if (!ASTUtils::Instance().IsQubitType(TId->GetSymbolType())) {
    std::stringstream M;
    M << "Measure operand '" << TId->GetName() << "' is not a Qubit type.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TId), M.str(),
        DiagLevel::Error);
    return ASTMeasureNode::StatementError(ASTIdentifierNode::Measure.Clone(),
                                          M.str());
  }

  if (ASTGateContextBuilder::Instance().InOpenContext()) {
    std::stringstream M;
    M << "A measure cannot occur within a gate statement sequence.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTMeasureNode::StatementError(ASTIdentifierNode::Measure.Clone(),
                                          M.str());
  }

  if (TId->IsIndexed()) {
    TId = ASTBuilder::Instance().FindUnindexedASTIdentifierNode(TId);
    assert(TId && "Invalid ASTIdentifierNode argument!");
  }

  ASTSymbolTableEntry *TSTE = ASTSymbolTable::Instance().Lookup(TId);
  assert(TSTE && "Measure Result Identifier has no SymbolTableEntry!");

  ASTQubitContainerNode *QBN = nullptr;
  unsigned TBits = TId->GetBits();

  if (!TSTE->HasValue()) {
    QBN = ASTBuilder::Instance().CreateASTQubitContainerNode(TId, TBits);
    assert(QBN && "Could not create a valid Measure ASTQubitContainerNode!");
  } else {
    if (TSTE->GetValueType() == ASTTypeQubitContainer)
      QBN = TSTE->GetValue()->GetValue<ASTQubitContainerNode *>();
    else
      QBN = ASTBuilder::Instance().CreateASTQubitContainerNode(TId, TBits);
    assert(QBN && "Could not retrieve a valid ASTQubitContainerNode!");
  }

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  std::stringstream MID;
  MID << "ast-measure-"
      << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *MId = ASTBuilder::Instance().CreateASTIdentifierNode(
      MID.str(), ASTMeasureNode::MeasureBits, ASTTypeMeasure);
  assert(MId && "Could not create a Measure ASTIdentifierNode!");

  MId->SetGateParamName("measure");
  MId->SetLocation(TK->GetLocation());
  MId->SetDeclarationContext(CTX);

  ASTSymbolTableEntry *MSTE = ASTSymbolTable::Instance().Lookup(
      MId, MId->GetBits(), MId->GetSymbolType());
  assert(MSTE && "Could not create a SymbolTableEntry for Measure!");

  std::stringstream RID;
  RID << "ast-measure-result-"
      << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *RId = ASTBuilder::Instance().CreateASTIdentifierNode(
      RID.str(), TBits, ASTTypeBitset);
  assert(RId && "Could not create a Measure Result ASTIdentifierNode!");

  RId->SetGateParamName("measure-result");
  RId->SetLocation(TK->GetLocation());
  RId->SetDeclarationContext(CTX);

  ASTSymbolTableEntry *RSTE = ASTSymbolTable::Instance().Lookup(
      RId, RId->GetBits(), RId->GetSymbolType());
  assert(RSTE && "Could not create a SymbolTableEntry for Measure Result!");

  ASTCBitNode *CBN =
      ASTBuilder::Instance().CreateASTCBitNode(RId, RId->GetBits(), 0UL);
  assert(CBN && "Could not create a valid Measure ASTCBitNode!");

  CBN->Mangle();
  ASTMeasureNode *MN =
      ASTBuilder::Instance().CreateASTMeasureNode(MId, QBN, CBN);
  assert(MN && "Could not create an ASTMeasureNode!");

  MN->SetLocation(TK->GetLocation());
  MN->SetDeclarationContext(CTX);
  MN->Mangle();
  return MN;
}

ASTMeasureNode *ASTProductionFactory::ProductionRule_1463(
    const ASTToken *TK, const std::string &TS, const ASTToken *TSTK,
    const ASTIntNode *TIMin, const ASTIntNode *TIMax, const std::string &RS,
    const ASTToken *RSTK, const ASTIntNode *RIMin,
    const ASTIntNode *RIMax) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(!TS.empty() && "Invalid Target Qubit identifier name argument!");
  assert(TIMin && "Invalid ASTIntNode argument!");
  assert(TIMax && "Invalid ASTIntNode argument!");
  assert(!RS.empty() && "Invalid Result Bitset identifier name argument!");
  assert(RIMin && "Invalid ASTIntNode argument!");
  assert(RIMax && "Invalid ASTIntNode argument!");

  QasmFeatureTester::Instance().ValidateFeature("measure");

  if (ASTGateContextBuilder::Instance().InOpenContext()) {
    std::stringstream M;
    M << "A measure cannot occur within a gate statement sequence.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TSTK), M.str(),
        DiagLevel::Error);
    return ASTMeasureNode::StatementError(ASTIdentifierNode::Measure.Clone(),
                                          M.str());
  }

  int32_t RB = TIMin->GetSignedValue();
  int32_t RE = TIMax->GetSignedValue();
  int32_t TB = RIMin->GetSignedValue();
  int32_t TE = RIMax->GetSignedValue();

  assert(RB >= 0 && "Negative Indexes are not allowed!");
  assert(RE >= 0 && "Negative Indexes are not allowed!");
  assert(TB >= 0 && "Negative Indexes are not allowed!");
  assert(TE >= 0 && "Negative Indexes are not allowed!");

  if (RB < 0 || RE < 0 || TB < 0 || TE < 0) {
    std::stringstream M;
    M << "Negative indices are not allowed!";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTMeasureNode::StatementError(ASTIdentifierNode::Measure.Clone(),
                                          M.str());
  }

  int32_t TMax = std::max<int32_t>(TB, TE);
  int32_t TMin = std::min<int32_t>(TB, TE);
  unsigned TBits = static_cast<unsigned>(TMax - TMin + 1);

  int32_t RMax = std::max<int32_t>(RB, RE);
  int32_t RMin = std::min<int32_t>(RB, RE);
  unsigned RBits = static_cast<unsigned>(RMax - RMin + 1);
  assert(RBits == TBits &&
         "Measure Result Bits must be equal to Measure Target Bits!");

  if (TBits != RBits) {
    std::stringstream M;
    M << "Measure Target number of Bits must be equal to the "
      << "Measure Result number of Bits!";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTMeasureNode::StatementError(ASTIdentifierNode::Measure.Clone(),
                                          M.str());
  }

  std::vector<unsigned> RV;
  std::vector<unsigned> TV;

  if (RB < RE)
    for (unsigned I = 0; I < RBits; ++I)
      RV.push_back(static_cast<unsigned>(I + RMin));
  else if (RE < RB)
    for (unsigned I = 0; I < RBits; ++I)
      RV.push_back(static_cast<unsigned>(RMax - I));
  else
    RV.push_back(RB);

  if (TB < TE)
    for (unsigned I = 0; I < TBits; ++I)
      TV.push_back(static_cast<unsigned>(I + TMin));
  else if (TE < TB)
    for (unsigned I = 0; I < TBits; ++I)
      TV.push_back(static_cast<unsigned>(TMax - I));
  else
    TV.push_back(TB);

  const ASTSymbolTableEntry *TSTE = ASTSymbolTable::Instance().FindQubit(TS);
  if (!TSTE) {
    std::stringstream M;
    M << "Measure operand '" << TS << "' is not a Qubit.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TSTK), M.str(),
        DiagLevel::Error);
    return ASTMeasureNode::StatementError(ASTIdentifierNode::Measure.Clone(),
                                          M.str());
  }

  assert(TSTE && "Measure Target Identifier has no SymbolTableEntry!");

  const ASTIdentifierNode *TId = TSTE->GetIdentifier();
  assert(TId && "Invalid Measure Target ASTIdentifierNode!");

  ASTScopeController::Instance().CheckOutOfScope(TId);

  if (!ASTUtils::Instance().IsQubitType(TId->GetSymbolType())) {
    std::stringstream M;
    M << "Measure operand '" << TId->GetName() << "' is not a Qubit type.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TSTK), M.str(),
        DiagLevel::Error);
    return ASTMeasureNode::StatementError(ASTIdentifierNode::Measure.Clone(),
                                          M.str());
  }

  ASTSymbolTableEntry *RSTE = ASTSymbolTable::Instance().Lookup(RS);
  assert(RSTE && " Measure Result Identifier has no SymbolTable Entry!");

  const ASTIdentifierNode *RId = RSTE->GetIdentifier();
  assert(RId && "Invalid Measure Result ASTIdentifierNode!");

  ASTScopeController::Instance().CheckOutOfScope(RId);

  switch (RId->GetSymbolType()) {
  case ASTTypeBitset:
  case ASTTypeCBitArray:
  case ASTTypeCBitNArray:
  case ASTTypeAngle:
  case ASTTypeMPComplex:
    break;
  default: {
    std::stringstream M;
    M << "Impossible assignment of a Measure result to a "
      << PrintTypeEnum(RId->GetSymbolType()) << " type.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(RId), M.str(),
        DiagLevel::Error);
    return ASTMeasureNode::StatementError(ASTIdentifierNode::Measure.Clone(),
                                          M.str());
  } break;
  }

  ASTQubitContainerNode *QCN = nullptr;

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  if (!TSTE->HasValue()) {
    QCN = ASTBuilder::Instance().CreateASTQubitContainerNode(TId, TBits);
    assert(QCN && "Could not create a valid ASTQubitContainerNode!");
  } else {
    if (TSTE->GetValueType() == ASTTypeQubitContainer) {
      QCN = TSTE->GetValue()->GetValue<ASTQubitContainerNode *>();
    } else if (ASTStringUtils::Instance().IsIndexedQubit(TId->GetName())) {
      std::string QBN =
          ASTStringUtils::Instance().GetBaseQubitName(TId->GetName());
      const ASTSymbolTableEntry *QSTE =
          ASTSymbolTable::Instance().FindQubit(QBN);
      assert(QSTE && "Base Qubit Container has no SymbolTable Entry!");
      QCN = QSTE->GetValue()->GetValue<ASTQubitContainerNode *>();
    } else {
      QCN = ASTBuilder::Instance().CreateASTQubitContainerNode(TId, TBits);
    }

    assert(QCN && "Could not retrieve a valid ASTQubitContainerNode!");
  }

  ASTCBitNode *CBN = nullptr;
  ASTAngleNode *ANG = nullptr;
  ASTMPComplexNode *MPC = nullptr;
  ASTType RTy = ASTTypeUndefined;

  if (!RSTE->HasValue()) {
    CBN = ASTBuilder::Instance().CreateASTCBitNode(RId, RBits, 0UL);
    assert(CBN && "Could not create a valid ASTCBitNode!");
    CBN->SetDeclarationContext(CTX);
    CBN->SetLocation(RSTK->GetLocation());
    RTy = CBN->GetASTType();
  } else if (RSTE->GetValueType() == ASTTypeBitset) {
    CBN = RSTE->GetValue()->GetValue<ASTCBitNode *>();
    assert(CBN && "Could not obtain a valid Result ASTCBitNode!");
    RTy = CBN->GetASTType();
  } else if (RSTE->GetValueType() == ASTTypeAngle) {
    ANG = RSTE->GetValue()->GetValue<ASTAngleNode *>();
    assert(ANG && "Could not obtain a valid Result ASTAngleNode!");
    RTy = ANG->GetASTType();
  } else if (RSTE->GetValueType() == ASTTypeMPComplex) {
    MPC = RSTE->GetValue()->GetValue<ASTMPComplexNode *>();
    assert(MPC && "Could not obtain a valid Result ASTMPComplexNode!");
    RTy = MPC->GetASTType();
  } else {
    CBN = ASTBuilder::Instance().CreateASTCBitNode(RId, RBits, 0UL);
    assert(CBN && "Could not create a valid ASTCBitNode!");
    CBN->SetDeclarationContext(CTX);
    CBN->SetLocation(RSTK->GetLocation());
    RTy = CBN->GetASTType();
  }

  assert(RTy != ASTTypeUndefined &&
         "Could not obtain a valid Measure Result Type!");

  std::stringstream MS;
  MS << "ast-measure-" << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTIdentifierNode *MId = ASTBuilder::Instance().CreateASTIdentifierNode(
      MS.str(), ASTMeasureNode::MeasureBits, ASTTypeMeasure);
  assert(MId && "Could not create a Measure ASTIdentifierNode!");

  MId->SetGateParamName("measure");
  MId->SetLocation(TK->GetLocation());
  MId->SetDeclarationContext(CTX);

  ASTMeasureNode *MN = nullptr;

  if (RTy == ASTTypeAngle)
    MN = ASTBuilder::Instance().CreateASTMeasureNode(MId, QCN, ANG);
  else if (RTy == ASTTypeMPComplex)
    MN = ASTBuilder::Instance().CreateASTMeasureNode(MId, QCN, MPC);
  else
    MN = ASTBuilder::Instance().CreateASTMeasureNode(MId, QCN, CBN);

  assert(MN && "Could not create an ASTMeasureNode!");

  for (unsigned I = 0; I < RBits; ++I)
    MN->AddTargetAndResultIndex(TV[I], RV[I]);

  MN->SetDeclarationContext(CTX);
  MN->SetLocation(TK->GetLocation());
  MN->Mangle();
  return MN;
}

ASTMeasureNode *
ASTProductionFactory::ProductionRule_1464(const ASTToken *TK,
                                          const ASTIdentifierNode *TId,
                                          const std::string &BS) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(TId && "Invalid ASTIdentifierNode argument!");
  assert(!BS.empty() && "Invalid bitsize string argument!");

  QasmFeatureTester::Instance().ValidateFeature("measure");

  const ASTIdentifierRefNode *TIdR = nullptr;
  if (TId->IsReference()) {
    TIdR = dynamic_cast<const ASTIdentifierRefNode *>(TId);
    assert(TIdR && "Could not dynamic_cast to an ASTIdentifierRefNode!");
  }

  ASTScopeController::Instance().CheckOutOfScope(TId);
  ASTIdentifierTypeController::Instance().CheckIdentifier(TId);
  ASTIdentifierTypeController::Instance().CheckMeasureTarget(TId);

  const ASTSymbolTableEntry *TSTE = nullptr;
  if (ASTStringUtils::Instance().IsIndexedQubit(TId->GetName())) {
    std::string QN =
        ASTStringUtils::Instance().GetBaseQubitName(TId->GetName());
    TSTE = ASTSymbolTable::Instance().FindQubit(QN);
  } else if (TIdR) {
    std::string QN =
        ASTStringUtils::Instance().GetIdentifierBase(TIdR->GetName());
    TSTE = ASTSymbolTable::Instance().FindQubit(QN);
  } else {
    TSTE = ASTSymbolTable::Instance().FindQubit(TId->GetName());
  }

  assert(TSTE && "Measure Target Identifier has no SymbolTableEntry!");

  if (!TSTE->HasValue()) {
    std::stringstream M;
    M << "Measure Target " << TId->GetName() << " SymbolTable Entry "
      << "has no Value.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TId), M.str(),
        DiagLevel::Error);
    return ASTMeasureNode::StatementError(ASTIdentifierNode::Measure.Clone(),
                                          M.str());
  }

  ASTQubitContainerNode *QBN =
      TSTE->GetValue()->GetValue<ASTQubitContainerNode *>();
  assert(QBN && "Could not obtain a valid target ASTQubitContainerNode!");

  QBN->Mangle();

  unsigned Bits = static_cast<unsigned>(std::stoul(BS));
  assert(!ASTIdentifierNode::InvalidBits(Bits) &&
         "Invalid number of bits for bitset result!");

  if (Bits != QBN->Size()) {
    std::stringstream M;
    M << "Mismatch between the qubit measure target size and the "
      << "measure result size.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TId), M.str(),
        DiagLevel::Warning);
  }

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  std::stringstream QN;
  QN << "ast-measure-result-bitset-"
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *RId = ASTBuilder::Instance().CreateASTIdentifierNode(
      QN.str(), Bits, ASTTypeBitset);
  assert(RId && "Could not create a valid ASTIdentifierNode!");

  RId->SetGateParamName("bitset");
  RId->SetDeclarationContext(CTX);
  RId->SetLocation(TK->GetLocation());

  ASTCBitNode *CBN = ASTBuilder::Instance().CreateASTCBitNode(RId, Bits, 0UL);
  assert(CBN && "Could not create a valid ASTCBitNode!");

  CBN->SetDeclarationContext(CTX);
  CBN->SetLocation(TK->GetLocation());
  CBN->Mangle();

  std::stringstream MID;
  MID << "ast-measure-"
      << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *MId = ASTBuilder::Instance().CreateASTIdentifierNode(
      MID.str(), ASTMeasureNode::MeasureBits, ASTTypeMeasure);
  assert(MId && "Could not create a Measure ASTIdentifierNode!");

  MId->SetGateParamName("measure");
  MId->SetDeclarationContext(CTX);
  MId->SetLocation(TK->GetLocation());

  ASTMeasureNode *MN =
      ASTBuilder::Instance().CreateASTMeasureNode(MId, QBN, CBN);
  assert(MN && "Could not create an ASTMeasureNode!");

  for (unsigned I = 0; I < QBN->Size(); ++I)
    MN->AddTargetIndex(QBN->GetQubit(I)->GetIndex());

  for (unsigned I = 0; I < CBN->Size(); ++I)
    MN->AddResultIndex(I);

  MN->SetDeclarationContext(CTX);
  MN->SetLocation(TK->GetLocation());
  MN->Mangle();
  return MN;
}

ASTIdentifierNode *
ASTProductionFactory::ProductionRule_1500(const ASTToken *TK,
                                          const std::string &TS) const {
  assert(TK && "Invalid ASTToken argument!");
  ASTIdentifierNode *RId =
      ASTTypeDiscovery::Instance().ResolveASTIdentifier(TK, TS);

  if (!RId) {
    std::stringstream M;
    M << "Failure creating a valid ASTIdentifierNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTIdentifierNode::IdentifierError(M.str());
  }

  RId->SetLocation(TK->GetLocation());
  return RId;
}

ASTIdentifierNode *
ASTProductionFactory::ProductionRule_1501(const ASTToken *TK,
                                          const ASTStringNode *BQS) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(BQS && "Invalid ASTStringNode argument!");

  const std::string &BQ = BQS->GetValue();
  ASTIdentifierNode *QId = ASTBuilder::Instance().FindASTIdentifierNode(BQ);
  if (!QId)
    QId = ASTBuilder::Instance().CreateASTIdentifierNode(BQ, 0,
                                                         ASTTypeQubitContainer);

  if (!QId) {
    std::stringstream M;
    M << "Failure creating a valid ASTIdentifierNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTIdentifierNode::IdentifierError(M.str());
  }

  QId->SetLocation(BQS->GetLocation());
  ASTSymbolTableEntry *STE =
      ASTSymbolTable::Instance().Lookup(QId, 0, ASTTypeQubitContainer);
  assert(STE && "ASTIdentifierNode has no SymbolTable Entry!");

  const ASTDeclarationContext *GCX =
      ASTDeclarationContextTracker::Instance().GetGlobalContext();
  assert(GCX && "Could not obtain a valid Global DeclarationContext!");

  QId->SetDeclarationContext(GCX);
  QId->SetGlobalScope();
  STE->SetContext(GCX);
  STE->SetGlobalScope();
  QId->SetLocation(TK->GetLocation());

  ASTIdentifierBuilder::Instance().Append(QId);
  ASTIdentifierTypeController::Instance().Reset();
  return QId;
}

ASTIdentifierNode *
ASTProductionFactory::ProductionRule_1502(const ASTToken *TK,
                                          const ASTStringNode *UQS) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(UQS && "Invalid ASTStringNode argument!");

  const std::string &UQ = UQS->GetValue();
  ASTIdentifierNode *QId = ASTBuilder::Instance().FindASTIdentifierNode(
      UQ, 1U, ASTTypeQubitContainer);
  if (!QId)
    QId = ASTBuilder::Instance().FindASTIdentifierNode(UQ);
  if (!QId)
    QId = ASTBuilder::Instance().FindOrCreateASTIdentifierNode(UQ, 1U,
                                                               ASTTypeQubit);

  if (!QId) {
    std::stringstream M;
    M << "Failure creating a valid ASTIdentifierNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTIdentifierNode::IdentifierError(M.str());
  }

  QId->SetLocation(UQS->GetLocation());
  ASTSymbolTableEntry *STE = ASTSymbolTable::Instance().Lookup(
      QId, QId->GetBits(), QId->GetSymbolType());
  assert(STE && "ASTIdentifierNode has no SymbolTable Entry!");

  ASTIdentifierBuilder::Instance().Append(QId);
  ASTIdentifierTypeController::Instance().Reset();
  return QId;
}

ASTIdentifierNode *ASTProductionFactory::ProductionRule_1503(
    const ASTToken *TK, const ASTStringNode *SN, const char *P) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(SN && "Invalid ASTStringNode argument!");
  assert(P && "Invalid complex number part argument!");

  std::size_t IX = SN->GetValue().find('.');
  if (IX == std::string::npos) {
    std::stringstream M;
    M << SN->GetValue() << " is not a complex number " << P << " identifier.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTIdentifierNode::IdentifierError(M.str());
  }

  std::string CRS = SN->GetValue().substr(0, IX);
  ASTIdentifierNode *CId =
      ASTBuilder::Instance().FindASTIdentifierNode(CRS, ASTTypeMPComplex);
  if (!CId) {
    std::stringstream M;
    M << "Identifier " << CId->GetName() << " does not reference a "
      << "known ASTMPComplex symbol.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTIdentifierNode::IdentifierError(M.str());
  }

  ASTSymbolTableEntry *STE = ASTSymbolTable::Instance().Lookup(
      CId, CId->GetBits(), CId->GetSymbolType());
  if (!STE) {
    std::stringstream M;
    M << "Identifier " << CId->GetName() << " has no SymbolTable Entry.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTIdentifierNode::IdentifierError(M.str());
  }

  if (STE->GetValueType() != ASTTypeMPComplex) {
    std::stringstream M;
    M << "Identifier " << CRS << " is not a complex number.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(CId), M.str(),
        DiagLevel::Error);
    return ASTIdentifierNode::IdentifierError(M.str());
  }

  ASTMPComplexNode *MPC = STE->GetValue()->GetValue<ASTMPComplexNode *>();
  assert(MPC && "Could not obtain a valid ASTMPComplexNode!");

  MPC->Mangle();
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      SN->GetValue(), CId->GetBits(), CId->GetValueType());
  if (!Id) {
    std::stringstream M;
    M << "Failure creating a valid ASTIdentifierNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTIdentifierNode::IdentifierError(M.str());
  }

  Id->SetComplexPart(true);
  Id->SetMangledName(CId->GetMangledName());
  ASTSymbolTableEntry *CSTE =
      ASTSymbolTable::Instance().Lookup(Id, Id->GetBits(), Id->GetSymbolType());
  assert(CSTE && "ASTIdentifierNode has no SymbolTable Entry!");

  if (!CSTE->HasValue()) {
    if (!ASTSymbolTable::Instance().Update(Id, CSTE, STE)) {
      std::stringstream M;
      M << "Failed to update the corresponding SymbolTable Entry!";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
      return ASTIdentifierNode::IdentifierError(M.str());
    }
  }

  Id->SetLocation(TK->GetLocation());
  ASTIdentifierBuilder::Instance().Append(Id);
  ASTIdentifierTypeController::Instance().Reset();
  return Id;
}

ASTIdentifierNode *
ASTProductionFactory::ProductionRule_1504(const ASTToken *TK,
                                          const ASTStringNode *SN) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(SN && "Invalid ASTStringNode argument!");

  std::string IDS = SN->SplitLeftOnDot();
  if (IDS.empty()) {
    std::stringstream M;
    M << "Invalid expression for frame dot member access operator.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTIdentifierNode::IdentifierError(M.str());
  }

  const unsigned FBits = OpenPulse::ASTOpenPulseFrameNode::FrameBits;
  ASTIdentifierNode *Id = nullptr;
  ASTSymbolTableEntry *STE = ASTSymbolTable::Instance().Lookup(
      SN->GetValue(), FBits, ASTTypeOpenPulseFrame);
  if (STE) {
    Id = STE->GetIdentifier();
  } else {
    STE = ASTSymbolTable::Instance().Lookup(IDS, FBits, ASTTypeOpenPulseFrame);
    if (!STE) {
      std::stringstream M;
      M << "Identifier " << SN << " does reference a known symbol.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(SN), M.str(),
          DiagLevel::Error);
      return ASTIdentifierNode::IdentifierError(M.str());
    }

    Id = ASTBuilder::Instance().CreateASTIdentifierNode(SN->GetValue(), FBits,
                                                        ASTTypeOpenPulseFrame);
    if (!Id) {
      std::stringstream M;
      M << "Failure creating a valid ASTIdentifierNode.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
      return ASTIdentifierNode::IdentifierError(M.str());
    }

    ASTSymbolTableEntry *NSTE =
        ASTSymbolTable::Instance().Lookup(Id, FBits, ASTTypeOpenPulseFrame);
    if (!NSTE) {
      std::stringstream M;
      M << "OpenPulse Fram has no SymbolTable Entry.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
      return ASTIdentifierNode::IdentifierError(M.str());
    }

    OpenPulse::ASTOpenPulseFrameNode *FN =
        STE->GetValue()->GetValue<OpenPulse::ASTOpenPulseFrameNode *>();
    assert(FN && "Invalid Frame SymbolTable Entry Value!");

    NSTE->ResetValue();
    NSTE->SetValue(new ASTValue<>(FN, ASTTypeOpenPulseFrame),
                   ASTTypeOpenPulseFrame);
    assert(NSTE->HasValue() && "Aggregate Frame SymbolTable Entry "
                               "has no Value!");
  }

  Id->SetLocation(TK->GetLocation());
  ASTIdentifierTypeController::Instance().Reset();
  return Id;
}

ASTIdentifierNode *ASTProductionFactory::ProductionRule_1505(
    const ASTToken *TK, const ASTArraySubscriptNode *ASN,
    const ASTArraySubscriptList *ASL, const std::string &IS) const {
  assert(TK && "Invalid ASTIdentifierNode argument!");
  assert(ASN && "Invalid ASTArraySubscriptNode argument!");
  assert(ASL && "Invalid ASTArraySubscriptList argument!");
  assert(!IS.empty() && "Invalid std::string argument!");

  // FIXME: REMOVE THIS DIAGNOSTIC WHEN N-DIMENSIONAL ARRAYS ARE IMPLEMENTED.
  if (!ASL->Empty()) {
    std::stringstream M;
    M << "N-Dimensional array subscripts are not supported yet.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTIdentifierNode::IdentifierError(M.str());
  }

  ASTType CTy = ASTIdentifierTypeController::Instance().GetCurrentType();

  if (CTy == ASTTypeQReg)
    CTy = ASTTypeQubitContainer;
  else if (CTy == ASTTypeCReg)
    CTy = ASTTypeBitset;

  ASTIdentifierNode *RId = nullptr;

  if (ASTOpenQASMVersionTracker::Instance().GetVersion() == 2.0 &&
      (CTy == ASTTypeQubitContainer || CTy == ASTTypeBitset)) {
    ASTIdentifierTypeController::Instance().SetCurrentType(CTy);
    std::string BS = ASN->AsIndexedString();
    unsigned Bits = ASTStringUtils::Instance().GetIdentifierIndex(BS);
    RId = ASTTypeDiscovery::Instance().ResolveASTIdentifier(TK, IS);
    RId->SetBits(Bits);
  } else if (ASTOpenQASMVersionTracker::Instance().GetVersion() == 2.0 &&
             (ASTIdentifierTypeController::Instance().IsGateType(CTy) ||
              CTy == ASTTypeOpaque)) {
    ASTIdentifierTypeController::Instance().SetPreviousType(CTy);
    ASTIdentifierTypeController::Instance().SetCurrentType(
        ASTTypeQubitContainer);
    std::string Id = IS;
    Id += ASN->AsIndexedString();

    if (!ASL->Empty())
      Id += ASL->AsIndexedString();

    RId =
        ASTTypeDiscovery::Instance().ResolveASTIdentifierRef(TK, Id, ASN, ASL);
  } else {
    std::string Id = IS;
    Id += ASN->AsIndexedString();

    if (!ASL->Empty())
      Id += ASL->AsIndexedString();

    RId =
        ASTTypeDiscovery::Instance().ResolveASTIdentifierRef(TK, Id, ASN, ASL);
  }

  if (!RId) {
    std::stringstream M;
    M << "Failure creating a valid ASTIdentifierNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTIdentifierNode::IdentifierError(M.str());
  }

  RId->SetLocation(TK->GetLocation());
  ASTIdentifierTypeController::Instance().Reset();
  return RId;
}

ASTIdentifierNode *ASTProductionFactory::ProductionRule_1506(
    const ASTToken *TK, const ASTStringNode *QS,
    const ASTArraySubscriptNode *ASN, const ASTArraySubscriptList *ASL) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(QS && "Invalid ASTStringNode argument!");
  assert(ASN && "Invalid ASTArraySubscriptNode argument!");

  const std::string &QN = QS->GetValue();
  ASTType QTy = ASTIdentifierTypeController::Instance().GetCurrentType();
  ASTIdentifierNode *QId =
      ASTBuilder::Instance().FindOrCreateASTIdentifierNode(QN, 0, QTy);

  if (!QId) {
    std::stringstream M;
    M << "Could not obtain a valid Qubit ASTIdentifierNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTIdentifierNode::IdentifierError(M.str());
  }

  const ASTDeclarationContext *GCX =
      ASTDeclarationContextTracker::Instance().GetGlobalContext();
  assert(GCX && "Could not obtain a valid ASTDeclarationContext!");

  // Qubits are always Global.
  QId->SetDeclarationContext(GCX);
  QId->SetGlobalScope();

  ASTSymbolTableEntry *QSTE = ASTSymbolTable::Instance().Lookup(
      QId, QId->GetBits(), QId->GetSymbolType());
  if (!QSTE) {
    std::stringstream M;
    M << "Qubit " << QId->GetName() << " has no SymbolTable Entry.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTIdentifierNode::IdentifierError(M.str());
  }

  // Qubits are always Global.
  QSTE->SetContext(GCX);
  QSTE->SetGlobalScope();

  if (ASL && !ASL->Empty()) {
    std::stringstream M;
    M << "Multi-dimensional Qubit registers are not allowed.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTIdentifierNode::IdentifierError(M.str());
  }

  unsigned Index = ASN->GetUnsignedIndexValue();
  std::stringstream IS;
  IS << QN << ':' << Index;

  ASTIdentifierNode *Id =
      ASTBuilder::Instance().FindASTIdentifierNode(IS.str());
  if (!Id) {
    std::stringstream M;
    M << "Could not obtain a valid Qubit ASTIdentifierNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTIdentifierNode::IdentifierError(M.str());
  }

  ASTSymbolTableEntry *STE =
      ASTSymbolTable::Instance().Lookup(IS.str(), 1U, ASTTypeQubit);
  assert(STE && "Could not obtain a valid ASTQubit SymbolTable Entry!");
  assert(STE->GetIdentifier() == Id &&
         "Inconsistent ASTIdentifierNode for the SymbolTable Entry!");

  ASTIdentifierNode *RId =
      const_cast<ASTIdentifierNode *>(STE->GetIdentifier());
  if (!RId) {
    std::stringstream M;
    M << "Invalid ASTIdentifierNode obtained from the SymbolTable Entry.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTIdentifierNode::IdentifierError(M.str());
  }

  return RId;
}

ASTIdentifierNode *
ASTProductionFactory::ProductionRule_1507(const ASTToken *TK,
                                          const std::string &N) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(!N.empty() && "Invalid Identifier Name!");

  ASTIdentifierNode *QId = new ASTIdentifierNode(N, ASTTypeGateQubitParam, 1U);
  assert(QId && "Could not create a valid GateQubitParam ASTIdentifierNode!");

  ASTSymbolTableEntry *STE =
      new ASTSymbolTableEntry(QId, ASTTypeGateQubitParam);
  assert(STE && "Could not create a valid GateQubitParam SymbolTable Entry!");

  STE->ResetValue();
  STE->SetLocalScope();
  QId->SetSymbolTableEntry(STE);
  QId->SetLocalScope();
  ASTType CTy = ASTIdentifierTypeController::Instance().GetCurrentType();
  ASTIdentifierTypeController::Instance().SetPreviousType(CTy);
  ASTIdentifierTypeController::Instance().SetCurrentType(ASTTypeGateQubitParam);
  return QId;
}

ASTArraySubscriptNode *
ASTProductionFactory::ProductionRule_1520(const ASTToken *TK,
                                          const ASTIntNode *II) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(II && "Invalid ASTIntNode argument!");

  ASTArraySubscriptNode *ASN = nullptr;

  if (II->IsMPInteger())
    ASN = new ASTArraySubscriptNode(II->GetMPInteger());
  else
    ASN = new ASTArraySubscriptNode(II);

  assert(ASN && "Could not create a valid ASTArraySubscriptNode!");

  ASN->SetLocation(TK->GetLocation());
  return ASN;
}

ASTArraySubscriptNode *
ASTProductionFactory::ProductionRule_1520(const ASTToken *TK,
                                          const ASTIdentifierNode *IId) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(IId && "Invalid ASTIdentifierNode argument!");

  std::variant<const ASTIntNode *, const ASTMPIntegerNode *,
               const ASTCBitNode *>
      IIV;
  if (!ASTUtils::Instance().GetVariantIntegerValue(IId, IIV)) {
    std::stringstream M;
    M << "Subscript identifier does not reference an Integer Constant "
      << "Expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTArraySubscriptNode::ExpressionError(M.str());
  }

  ASTArraySubscriptNode *ASN = nullptr;

  switch (IIV.index()) {
  case 0:
    ASN = new ASTArraySubscriptNode(std::get<0>(IIV));
    assert(ASN && "Could not obtain a valid ASTIntNode from std::variant!");
    break;
  case 1:
    ASN = new ASTArraySubscriptNode(std::get<1>(IIV));
    assert(ASN &&
           "Could not obtain a valid ASTMPIntegerNode from std::variant!");
    break;
  case 2:
    ASN = new ASTArraySubscriptNode(std::get<2>(IIV));
    assert(ASN &&
           "Could not obtain a valid ASTMPIntegerNode from std::variant!");
    break;
  default:
    break;
  }

  if (!ASN) {
    std::stringstream M;
    M << "Could not instantiate a valid ASTSubscriptNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTArraySubscriptNode::ExpressionError(M.str());
  }

  if (IId->IsInductionVariable())
    ASN->SetInductionVariable(IId);
  else
    ASN->SetIndexIdentifier(IId);

  ASN->SetLocation(TK->GetLocation());
  return ASN;
}

ASTArraySubscriptNode *
ASTProductionFactory::ProductionRule_1520(const ASTToken *TK,
                                          const ASTBinaryOpNode *BOP) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(BOP && "Invalid ASTBinaryOpNode argument!");

  ASTType Ty = ASTExpressionEvaluator::Instance().EvaluatesTo(BOP);
  if (!ASTExpressionValidator::Instance().IsScalarIntegerType(Ty)) {
    std::stringstream M;
    M << "Subscript expression does not evaluate to an Integer Constant "
      << "Expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTArraySubscriptNode::ExpressionError(M.str());
  }

  ASTArraySubscriptNode *ASN = new ASTArraySubscriptNode(BOP);
  assert(ASN && "Could not obtain a valid ASTArraySubscriptNode!");

  if (!ASN) {
    std::stringstream M;
    M << "Could not instantiate a valid ASTSubscriptNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTArraySubscriptNode::ExpressionError(M.str());
  }

  ASN->SetLocation(TK->GetLocation());
  return ASN;
}

ASTArraySubscriptNode *
ASTProductionFactory::ProductionRule_1520(const ASTToken *TK,
                                          const ASTUnaryOpNode *UOP) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(UOP && "Invalid ASTUnaryOpNode argument!");

  ASTType Ty = ASTExpressionEvaluator::Instance().EvaluatesTo(UOP);
  if (!ASTExpressionValidator::Instance().IsScalarIntegerType(Ty)) {
    std::stringstream M;
    M << "Subscript expression does not evaluate to an Integer Constant "
      << "Expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTArraySubscriptNode::ExpressionError(M.str());
  }

  ASTArraySubscriptNode *ASN = new ASTArraySubscriptNode(UOP);
  assert(ASN && "Could not obtain a valid ASTArraySubscriptNode!");

  if (!ASN) {
    std::stringstream M;
    M << "Could not instantiate a valid ASTSubscriptNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTArraySubscriptNode::ExpressionError(M.str());
  }

  ASN->SetLocation(TK->GetLocation());
  return ASN;
}

ASTFunctionDeclarationNode *ASTProductionFactory::ProductionRule_2300(
    const ASTToken *TK, const ASTIdentifierNode *Id, ASTDeclarationList *DL,
    ASTResultNode *Res, ASTStatementList *SL) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode Function argument!");
  assert(DL && "Invalid ASTDeclarationList argument!");
  assert(Res && "Invalid ASTResult Function Argument!");
  assert(SL && "Invalid ASTStatementList argument!");

  if (ASTTypeSystemBuilder::Instance().IsReservedFunction(Id->GetName())) {
    if (ASTTypeSystemBuilder::Instance().IsRegistered(Id->GetName())) {
      std::stringstream M;
      M << "Identifier '" << Id->GetName() << "' is reserved for built-in "
        << "functions and cannot be used to create a user-defined function.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(Id), M.str(),
          DiagLevel::Error);
      return ASTFunctionDeclarationNode::DeclarationError(Id, M.str());
    }
  }

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  const ASTDeclarationContext *GCX =
      ASTDeclarationContextTracker::Instance().GetGlobalContext();
  assert(GCX && "Could not obtain a valid ASTDeclarationContext!");

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
    std::stringstream M;
    M << "Declaration " << Id->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTFunctionDeclarationNode::DeclarationError(Id, M.str());
  }

  // Functions always have Global Scope.
  Id->SetDeclarationContext(GCX);
  const_cast<ASTIdentifierNode *>(Id)->SetGlobalScope();
  Id->SetBits(ASTFunctionDefinitionNode::FunctionBits);

  if (ASTSymbolTableEntry *RSTE =
          ASTSymbolTable::Instance().Lookup(Res->GetIdentifier())) {
    if (!ASTSymbolTable::Instance().TransferGlobalSymbolToLocal(
            Res->GetIdentifier(), RSTE)) {
      std::stringstream M;
      M << "Failure transferring result symbol to the Local Symbol Table.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(Res->GetIdentifier()),
          M.str(), DiagLevel::ICE);
      return ASTFunctionDeclarationNode::DeclarationError(Id, M.str());
    }

    RSTE->SetLocalScope();
    const_cast<ASTIdentifierNode *>(Res->GetIdentifier())->SetLocalScope();
    ASTScopeController::Instance().SetLocalScope(Res->GetIdentifier());
  }

  // All function parameters are at function declaration context scope.
  DL->SetDeclarationContext(CTX);
  ASTScopeController::Instance().SetDeclarationContext(DL, CTX);

  SL->SetDeclarationContext(CTX);
  ASTScopeController::Instance().SetDeclarationContext(SL, CTX);
  SL->SetLocalScope();

  ASTFunctionDefinitionNode *FDN =
      ASTBuilder::Instance().CreateASTFunctionDefinition(Id, *DL, *SL, Res);
  assert(FDN && "Could not create an ASTFunctionDeclarationNode!");

  FDN->SetDeclarationContext(GCX);
  Res->SetDeclarationContext(CTX);
  Res->SetFunction(Id, FDN);
  FDN->SetLocation(TK->GetLocation());
  FDN->SetResult(Res);
  FDN->Mangle();
  Res->Mangle();

  if (!ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
          Res->GetIdentifier(), Res->GetIdentifier()->GetBits(),
          Res->GetIdentifier()->GetSymbolType())) {
    std::stringstream M;
    M << "Failure transferring ASTResultNode to Local Symbol Table.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Res->GetIdentifier()), M.str(),
        DiagLevel::Error);
    return ASTFunctionDeclarationNode::DeclarationError(Id, M.str());
  }

  std::pair<ASTType, ASTType> RP;
  if (!FDN->CheckReturnType(RP)) {
    std::stringstream M;
    M << "Function Return <-> Result Type mismatch: expected "
      << PrintTypeEnum(RP.first) << ", got " << PrintTypeEnum(RP.second) << '.';
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Res), M.str(),
        DiagLevel::Error);
    return ASTFunctionDeclarationNode::DeclarationError(Id, M.str());
  }

  std::pair<ASTType, ASTType> SP;
  if (const ASTReturnStatementNode *RSN = FDN->CheckReturnStatements(SP)) {
    std::stringstream M;
    M << "Function Return <-> Result Type mismatch: expected "
      << PrintTypeEnum(RP.first) << ", got " << PrintTypeEnum(RP.second) << '.';
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(RSN), M.str(),
        DiagLevel::Error);
    return ASTFunctionDeclarationNode::DeclarationError(Id, M.str());
  }

  DL->TransferSymbols(FDN->GetSymbolTable());
  SL->TransferDeclarations(FDN->GetSymbolTable());
  SL->TransferStatements(FDN->GetSymbolTable());
  ASTDeclarationBuilder::Instance().TransferResult(Res, FDN->GetSymbolTable());
  ASTSymbolTable::Instance().TransferLocalContextSymbols(CTX,
                                                         FDN->GetSymbolTable());
  ASTIfConditionalsGraphController::Instance().RemoveOutOfScope(*SL, CTX);

  std::stringstream FDS;
  FDS << "ast-func-decl-" << Id->GetName();
  ASTIdentifierNode *FId = ASTBuilder::Instance().CreateASTIdentifierNode(
      FDS.str(), ASTFunctionDeclarationNode::FunctionDeclBits,
      ASTTypeFunctionDeclaration);
  assert(FId && "Could not create a valid ASTIdentifierNode!");

  // Functions always have Global Scope.
  FId->SetDeclarationContext(GCX);
  FId->SetGlobalScope();
  FId->SetLocation(TK->GetLocation());

  ASTFunctionDeclarationNode *FN =
      ASTBuilder::Instance().CreateASTFunctionDeclaration(FId, FDN);
  assert(FN && "Could not create a valid ASTFunctionDeclarationNode!");

  FN->SetDeclarationContext(GCX);
  FN->SetLocation(TK->GetLocation());
  FN->Mangle();

  // Symbol Table Cleanup.
  ASTIdentifierBuilder::Instance().Clear();
  ASTParameterBuilder::Instance().Clear();
  ASTFunctionContextBuilder::Instance().CloseContext();
  ASTDeclarationContextTracker::Instance().PopCurrentContext();

  if (ASTTypeSystemBuilder::Instance().IsReservedFunction(Id->GetName()))
    ASTTypeSystemBuilder::Instance().RegisterFunction(Id->GetName());

  return FN;
}

ASTFunctionDeclarationNode *ASTProductionFactory::ProductionRule_2301(
    const ASTToken *TK, const ASTIdentifierNode *Id, ASTResultNode *Res,
    ASTStatementList *SL) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode Function argument!");
  assert(Res && "Invalid ASTResult Function Argument!");
  assert(SL && "Invalid ASTStatementList argument!");

  if (ASTTypeSystemBuilder::Instance().IsReservedFunction(Id->GetName())) {
    if (ASTTypeSystemBuilder::Instance().IsRegistered(Id->GetName())) {
      std::stringstream M;
      M << "Identifier '" << Id->GetName() << "' is reserved for built-in "
        << "functions and cannot be used to create a user-defined function.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(Id), M.str(),
          DiagLevel::Error);
      return ASTFunctionDeclarationNode::DeclarationError(Id, M.str());
    }
  }

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  const ASTDeclarationContext *GCX =
      ASTDeclarationContextTracker::Instance().GetGlobalContext();
  assert(GCX && "Could not obtain a valid ASTDeclarationContext!");

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
    std::stringstream M;
    M << "Declaration " << Id->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTFunctionDeclarationNode::DeclarationError(Id, M.str());
  }

  // Functions always have Global Scope.
  const_cast<ASTIdentifierNode *>(Id)->SetDeclarationContext(GCX);
  const_cast<ASTIdentifierNode *>(Id)->SetGlobalScope();
  const_cast<ASTIdentifierNode *>(Id)->SetBits(
      ASTFunctionDefinitionNode::FunctionBits);

  if (ASTSymbolTableEntry *RSTE =
          ASTSymbolTable::Instance().Lookup(Res->GetIdentifier())) {
    if (!ASTSymbolTable::Instance().TransferGlobalSymbolToLocal(
            Res->GetIdentifier(), RSTE)) {
      std::stringstream M;
      M << "Failure transferring result symbol to the Local Symbol Table.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(Res->GetIdentifier()),
          M.str(), DiagLevel::ICE);
      return ASTFunctionDeclarationNode::DeclarationError(Id, M.str());
    }

    RSTE->SetLocalScope();
    const_cast<ASTIdentifierNode *>(Res->GetIdentifier())->SetLocalScope();
    ASTScopeController::Instance().SetLocalScope(Res->GetIdentifier());
  }

  // All function parameters are at function declaration context scope.
  ASTDeclarationList PDL;
  PDL.SetDeclarationContext(CTX);
  PDL.SetLocalScope();

  // Cleanup below.
  ASTParameterList PL(PDL);
  SL->SetLocalScope();
  ASTScopeController::Instance().SetDeclarationContext(SL, CTX);

  ASTFunctionDefinitionNode *FDN =
      ASTBuilder::Instance().CreateASTFunctionDefinition(Id, PDL, *SL, Res);
  assert(FDN && "Could not create a valid ASTFunctionDeclarationNode!");

  FDN->SetDeclarationContext(GCX);
  Res->SetDeclarationContext(CTX);
  Res->SetFunction(Id, FDN);
  FDN->SetLocation(TK->GetLocation());
  FDN->SetResult(Res);
  FDN->Mangle();
  Res->Mangle();

  if (!ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
          Res->GetIdentifier(), Res->GetIdentifier()->GetBits(),
          Res->GetIdentifier()->GetSymbolType())) {
    std::stringstream M;
    M << "Failure transferring ASTResultNode to Local Symbol Table.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Res->GetIdentifier()), M.str(),
        DiagLevel::Error);
    return ASTFunctionDeclarationNode::DeclarationError(Id, M.str());
  }

  std::pair<ASTType, ASTType> RP;
  if (!FDN->CheckReturnType(RP)) {
    std::stringstream M;
    M << "Function Return <-> Result Type mismatch: expected "
      << PrintTypeEnum(RP.first) << ", got " << PrintTypeEnum(RP.second) << '.';
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Res), M.str(),
        DiagLevel::Error);
    return ASTFunctionDeclarationNode::DeclarationError(Id, M.str());
  }

  std::pair<ASTType, ASTType> SP;
  if (const ASTReturnStatementNode *RSN = FDN->CheckReturnStatements(SP)) {
    std::stringstream M;
    M << "Function Return <-> Result Type mismatch: expected "
      << PrintTypeEnum(RP.first) << ", got " << PrintTypeEnum(RP.second) << '.';
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(RSN), M.str(),
        DiagLevel::Error);
    return ASTFunctionDeclarationNode::DeclarationError(Id, M.str());
  }

  SL->TransferDeclarations(FDN->GetSymbolTable());
  SL->TransferStatements(FDN->GetSymbolTable());
  ASTDeclarationBuilder::Instance().TransferResult(Res, FDN->GetSymbolTable());
  ASTSymbolTable::Instance().TransferLocalContextSymbols(CTX,
                                                         FDN->GetSymbolTable());
  ASTIfConditionalsGraphController::Instance().RemoveOutOfScope(*SL, CTX);

  std::stringstream FDS;
  FDS << "ast-func-decl-" << Id->GetName();
  ASTIdentifierNode *FId = ASTBuilder::Instance().CreateASTIdentifierNode(
      FDS.str(), ASTFunctionDeclarationNode::FunctionDeclBits,
      ASTTypeFunctionDeclaration);
  assert(FId && "Could not create a valid ASTIdentifierNode!");

  // Functions always have Global Scope.
  FId->SetDeclarationContext(GCX);
  FId->SetGlobalScope();
  FId->SetLocation(TK->GetLocation());

  ASTFunctionDeclarationNode *FN =
      ASTBuilder::Instance().CreateASTFunctionDeclaration(FId, FDN);
  assert(FN && "Could not create a valid ASTFunctionDeclarationNode!");

  FN->SetDeclarationContext(GCX);
  FN->SetLocation(TK->GetLocation());
  FN->Mangle();

  // Symbol Table Cleanup.
  PL.DeleteSymbols();
  PL.Clear();
  ASTIdentifierBuilder::Instance().Clear();
  ASTParameterBuilder::Instance().Clear();
  ASTFunctionContextBuilder::Instance().CloseContext();
  ASTDeclarationContextTracker::Instance().PopCurrentContext();

  if (ASTTypeSystemBuilder::Instance().IsReservedFunction(Id->GetName()))
    ASTTypeSystemBuilder::Instance().RegisterFunction(Id->GetName());

  return FN;
}

ASTFunctionDeclarationNode *ASTProductionFactory::ProductionRule_2302(
    const ASTToken *TK, const ASTIdentifierNode *Id, ASTDeclarationList *DL,
    ASTStatementList *SL) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode Function argument!");
  assert(DL && "Invalid ASTDeclarationList argument!");
  assert(SL && "Invalid ASTStatementList argument!");

  if (ASTTypeSystemBuilder::Instance().IsReservedFunction(Id->GetName())) {
    if (ASTTypeSystemBuilder::Instance().IsRegistered(Id->GetName())) {
      std::stringstream M;
      M << "Identifier '" << Id->GetName() << "' is reserved for built-in "
        << "functions and cannot be used to create a user-defined function.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(Id), M.str(),
          DiagLevel::Error);
      return ASTFunctionDeclarationNode::DeclarationError(Id, M.str());
    }
  }

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  const ASTDeclarationContext *GCX =
      ASTDeclarationContextTracker::Instance().GetGlobalContext();
  assert(GCX && "Could not obtain a valid ASTDeclarationContext!");

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
    std::stringstream M;
    M << "Declaration " << Id->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTFunctionDeclarationNode::DeclarationError(Id, M.str());
  }

  // Functions always have Global Scope.
  const_cast<ASTIdentifierNode *>(Id)->SetDeclarationContext(GCX);
  const_cast<ASTIdentifierNode *>(Id)->SetGlobalScope();
  const_cast<ASTIdentifierNode *>(Id)->SetBits(
      ASTFunctionDefinitionNode::FunctionBits);

  std::stringstream IS;
  IS << "ast-result-void-"
     << DIAGLineCounter::Instance().GetIdentifierLocation();
  ASTIdentifierNode *RId = ASTBuilder::Instance().CreateASTIdentifierNode(
      IS.str(), ASTResultNode::ResultBits, ASTTypeResult);
  assert(RId && "Could not create an ASTIdentifierNode!");

  RId->SetPolymorphicName("result");
  ASTResultNode *Res = ASTBuilder::Instance().CreateASTResultNode(
      RId, ASTTypeVoid, ASTResultNode::ResultBits);
  assert(Res && "Could not create an ASTResultNode!");

  if (ASTSymbolTableEntry *RSTE =
          ASTSymbolTable::Instance().Lookup(Res->GetIdentifier())) {
    if (!ASTSymbolTable::Instance().TransferGlobalSymbolToLocal(
            Res->GetIdentifier(), RSTE)) {
      std::stringstream M;
      M << "Failure transferring result symbol to the Local Symbol Table.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(Res->GetIdentifier()),
          M.str(), DiagLevel::ICE);
      return ASTFunctionDeclarationNode::DeclarationError(Id, M.str());
    }

    RSTE->SetLocalScope();
    const_cast<ASTIdentifierNode *>(Res->GetIdentifier())->SetLocalScope();
    ASTScopeController::Instance().SetLocalScope(Res->GetIdentifier());
  }

  // All function parameters are at function declaration context scope.
  DL->SetDeclarationContext(CTX);
  ASTScopeController::Instance().SetDeclarationContext(DL, CTX);

  // Cleanup below.
  ASTParameterList PL(DL);
  SL->SetDeclarationContext(CTX);
  ASTScopeController::Instance().SetDeclarationContext(SL, CTX);
  SL->SetLocalScope();

  ASTFunctionDefinitionNode *FDN =
      ASTBuilder::Instance().CreateASTFunctionDefinition(Id, *DL, *SL, Res);
  assert(FDN && "Could not create an ASTFunctionDeclarationNode!");

  FDN->SetDeclarationContext(GCX);
  Res->SetDeclarationContext(CTX);
  Res->SetFunction(Id, FDN);
  FDN->SetLocation(TK->GetLocation());
  FDN->SetResult(Res);
  FDN->Mangle();
  Res->Mangle();

  if (!ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
          Res->GetIdentifier(), Res->GetIdentifier()->GetBits(),
          Res->GetIdentifier()->GetSymbolType())) {
    std::stringstream M;
    M << "Failure transferring ASTResultNode to Local Symbol Table.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Res->GetIdentifier()), M.str(),
        DiagLevel::Error);
    return ASTFunctionDeclarationNode::DeclarationError(Id, M.str());
  }

  std::pair<ASTType, ASTType> RP;
  if (!FDN->CheckReturnType(RP)) {
    std::stringstream M;
    M << "Function Return <-> Result Type mismatch: expected "
      << PrintTypeEnum(RP.first) << ", got " << PrintTypeEnum(RP.second) << '.';
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Res), M.str(),
        DiagLevel::Error);
    return ASTFunctionDeclarationNode::DeclarationError(Id, M.str());
  }

  std::pair<ASTType, ASTType> SP;
  if (const ASTReturnStatementNode *RSN = FDN->CheckReturnStatements(SP)) {
    std::stringstream M;
    M << "Function Return <-> Result Type mismatch: expected "
      << PrintTypeEnum(RP.first) << ", got " << PrintTypeEnum(RP.second) << '.';
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(RSN), M.str(),
        DiagLevel::Error);
    return ASTFunctionDeclarationNode::DeclarationError(Id, M.str());
  }

  DL->TransferSymbols(FDN->GetSymbolTable());
  SL->TransferDeclarations(FDN->GetSymbolTable());
  SL->TransferStatements(FDN->GetSymbolTable());
  ASTDeclarationBuilder::Instance().TransferResult(Res, FDN->GetSymbolTable());
  ASTSymbolTable::Instance().TransferLocalContextSymbols(CTX,
                                                         FDN->GetSymbolTable());
  ASTIfConditionalsGraphController::Instance().RemoveOutOfScope(*SL, CTX);

  std::stringstream FDS;
  FDS << "ast-func-decl-" << Id->GetName();
  ASTIdentifierNode *FId = ASTBuilder::Instance().CreateASTIdentifierNode(
      FDS.str(), ASTFunctionDeclarationNode::FunctionDeclBits,
      ASTTypeFunctionDeclaration);
  assert(FId && "Could not create an ASTIdentifierNode!");

  // Functions always have Global Scope.
  FId->SetDeclarationContext(GCX);
  FId->SetGlobalScope();
  FId->SetLocation(TK->GetLocation());

  ASTFunctionDeclarationNode *FN =
      ASTBuilder::Instance().CreateASTFunctionDeclaration(FId, FDN);
  assert(FN && "Could not create an ASTFunctionDeclarationNode!");

  FN->SetDeclarationContext(GCX);
  FN->SetLocation(TK->GetLocation());
  FN->Mangle();

  // Symbol Table Cleanup.
  PL.DeleteSymbols();
  PL.Clear();
  ASTIdentifierBuilder::Instance().Clear();
  ASTParameterBuilder::Instance().Clear();
  ASTFunctionContextBuilder::Instance().CloseContext();
  ASTDeclarationContextTracker::Instance().PopCurrentContext();

  if (ASTTypeSystemBuilder::Instance().IsReservedFunction(Id->GetName()))
    ASTTypeSystemBuilder::Instance().RegisterFunction(Id->GetName());

  return FN;
}

ASTFunctionDeclarationNode *
ASTProductionFactory::ProductionRule_2303(const ASTToken *TK,
                                          const ASTIdentifierNode *Id,
                                          ASTStatementList *SL) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode Function argument!");
  assert(SL && "Invalid ASTStatementList argument!");

  if (ASTTypeSystemBuilder::Instance().IsReservedFunction(Id->GetName())) {
    if (ASTTypeSystemBuilder::Instance().IsRegistered(Id->GetName())) {
      std::stringstream M;
      M << "Identifier '" << Id->GetName() << "' is reserved for built-in "
        << "functions and cannot be used to create a user-defined function.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(Id), M.str(),
          DiagLevel::Error);
      return ASTFunctionDeclarationNode::DeclarationError(Id, M.str());
    }
  }

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  const ASTDeclarationContext *GCX =
      ASTDeclarationContextTracker::Instance().GetGlobalContext();
  assert(GCX && "Could not obtain a valid ASTDeclarationContext!");

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
    std::stringstream M;
    M << "Declaration " << Id->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTFunctionDeclarationNode::DeclarationError(Id, M.str());
  }

  // Functions always have Global Scope.
  const_cast<ASTIdentifierNode *>(Id)->SetDeclarationContext(GCX);
  const_cast<ASTIdentifierNode *>(Id)->SetGlobalScope();
  const_cast<ASTIdentifierNode *>(Id)->SetBits(
      ASTFunctionDefinitionNode::FunctionBits);

  std::stringstream IS;
  IS << "ast-result-void-"
     << DIAGLineCounter::Instance().GetIdentifierLocation();
  ASTIdentifierNode *RId = ASTBuilder::Instance().CreateASTIdentifierNode(
      IS.str(), ASTResultNode::ResultBits, ASTTypeResult);
  assert(RId && "Could not create an ASTIdentifierNode!");

  RId->SetPolymorphicName("result");
  ASTResultNode *Res = ASTBuilder::Instance().CreateASTResultNode(
      RId, ASTTypeVoid, ASTResultNode::ResultBits);
  assert(Res && "Could not create an ASTResultNode!");

  if (ASTSymbolTableEntry *RSTE =
          ASTSymbolTable::Instance().Lookup(Res->GetIdentifier())) {
    if (!ASTSymbolTable::Instance().TransferGlobalSymbolToLocal(
            Res->GetIdentifier(), RSTE)) {
      std::stringstream M;
      M << "Failure transferring result symbol to the Local Symbol Table.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(Res->GetIdentifier()),
          M.str(), DiagLevel::ICE);
      return ASTFunctionDeclarationNode::DeclarationError(Id, M.str());
    }

    RSTE->SetLocalScope();
    const_cast<ASTIdentifierNode *>(Res->GetIdentifier())->SetLocalScope();
    ASTScopeController::Instance().SetLocalScope(Res->GetIdentifier());
  }

  // Cleanup below.
  ASTDeclarationList DL;
  SL->SetDeclarationContext(CTX);
  ASTScopeController::Instance().SetDeclarationContext(SL, CTX);
  SL->SetLocalScope();

  ASTFunctionDefinitionNode *FDN =
      ASTBuilder::Instance().CreateASTFunctionDefinition(Id, DL, *SL, Res);
  assert(FDN && "Could not create an ASTFunctionDeclarationNode!");

  FDN->SetDeclarationContext(GCX);
  Res->SetDeclarationContext(CTX);
  Res->SetFunction(Id, FDN);
  FDN->SetLocation(TK->GetLocation());
  FDN->SetResult(Res);
  FDN->Mangle();
  Res->Mangle();

  if (!ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
          Res->GetIdentifier(), Res->GetIdentifier()->GetBits(),
          Res->GetIdentifier()->GetSymbolType())) {
    std::stringstream M;
    M << "Failure transferring ASTResultNode to Local Symbol Table.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Res->GetIdentifier()), M.str(),
        DiagLevel::Error);
    return ASTFunctionDeclarationNode::DeclarationError(Id, M.str());
  }

  std::pair<ASTType, ASTType> RP;
  if (!FDN->CheckReturnType(RP)) {
    std::stringstream M;
    M << "Function Return <-> Result Type mismatch: expected "
      << PrintTypeEnum(RP.first) << ", got " << PrintTypeEnum(RP.second) << '.';
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Res), M.str(),
        DiagLevel::Error);
    return ASTFunctionDeclarationNode::DeclarationError(Id, M.str());
  }

  std::pair<ASTType, ASTType> SP;
  if (const ASTReturnStatementNode *RSN = FDN->CheckReturnStatements(SP)) {
    std::stringstream M;
    M << "Function Return <-> Result Type mismatch: expected "
      << PrintTypeEnum(RP.first) << ", got " << PrintTypeEnum(RP.second) << '.';
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(RSN), M.str(),
        DiagLevel::Error);
    return ASTFunctionDeclarationNode::DeclarationError(Id, M.str());
  }

  SL->TransferDeclarations(FDN->GetSymbolTable());
  SL->TransferStatements(FDN->GetSymbolTable());
  ASTDeclarationBuilder::Instance().TransferResult(Res, FDN->GetSymbolTable());
  ASTSymbolTable::Instance().TransferLocalContextSymbols(CTX,
                                                         FDN->GetSymbolTable());
  ASTIfConditionalsGraphController::Instance().RemoveOutOfScope(*SL, CTX);

  std::stringstream FDS;
  FDS << "ast-func-decl-" << Id->GetName();
  ASTIdentifierNode *FId = ASTBuilder::Instance().CreateASTIdentifierNode(
      FDS.str(), ASTFunctionDeclarationNode::FunctionDeclBits,
      ASTTypeFunctionDeclaration);
  assert(FId && "Could not create an ASTIdentifierNode!");

  // Functions always have Global Scope.
  FId->SetDeclarationContext(GCX);
  FId->SetGlobalScope();
  FId->SetLocation(TK->GetLocation());

  ASTFunctionDeclarationNode *FN =
      ASTBuilder::Instance().CreateASTFunctionDeclaration(FId, FDN);
  assert(FN && "Could not create an ASTFunctionDeclarationNode!");

  FN->SetDeclarationContext(GCX);
  FN->SetLocation(TK->GetLocation());
  FN->Mangle();

  // Symbol Table Cleanup.
  ASTIdentifierBuilder::Instance().Clear();
  ASTParameterBuilder::Instance().Clear();
  ASTFunctionContextBuilder::Instance().CloseContext();
  ASTDeclarationContextTracker::Instance().PopCurrentContext();

  if (ASTTypeSystemBuilder::Instance().IsReservedFunction(Id->GetName()))
    ASTTypeSystemBuilder::Instance().RegisterFunction(Id->GetName());

  return FN;
}

ASTKernelDeclarationNode *ASTProductionFactory::ProductionRule_2500(
    const ASTToken *ETK, ASTIdentifierNode *Id, ASTDeclarationList *DL,
    ASTResultNode *Res, const ASTToken *RTK) const {
  assert(ETK && "Invalid ASTToken argument!");
  assert(RTK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(DL && "Invalid ASTDeclarationNode argument!");
  assert(Res && "Invalid ASTResultNode argument!");

  QasmFeatureTester::Instance().ValidateFeature("extern");

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  const ASTDeclarationContext *GCX =
      ASTDeclarationContextTracker::Instance().GetGlobalContext();
  assert(GCX && "Could not obtain a valid ASTDeclarationContext!");

  const ASTDeclarationContext *CCX =
      ASTDeclarationContextTracker::Instance().GetDefaultCalibrationContext();
  assert(CCX && "Could not obtain a valid ASTDeclarationContext!");

  if (ASTDeclarationContextTracker::Instance().InGlobalContext() ||
      ASTDeclarationContextTracker::Instance().InCalibrationContext()) {
    if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
            Id, ASTKernelNode::KernelBits, ASTTypeKernel)) {
      std::stringstream M;
      M << "Could not transfer Symbol Table Entry for ASTTypeKernel.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
      return ASTKernelDeclarationNode::DeclarationError(Id, M.str());
    }
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
    std::stringstream M;
    M << "Declaration " << Id->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTKernelDeclarationNode::DeclarationError(Id, M.str());
  }

  const ASTIdentifierNode *RId = Res->GetIdentifier();
  assert(RId && "Invalid ASTIdentifierNode for ASTResultNode!");

  if (ASTSymbolTableEntry *RSTE = ASTSymbolTable::Instance().Lookup(RId)) {
    if (!ASTSymbolTable::Instance().TransferGlobalSymbolToLocal(RId, RSTE)) {
      std::stringstream M;
      M << "Failure transferring result symbol to the Local Symbol Table.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(RId), M.str(),
          DiagLevel::ICE);
      return ASTKernelDeclarationNode::DeclarationError(Id, M.str());
    }

    RSTE->SetContext(CTX);
    RSTE->SetLocalScope();
    const_cast<ASTIdentifierNode *>(RId)->SetDeclarationContext(CTX);
    const_cast<ASTIdentifierNode *>(RId)->SetLocalScope();
    ASTScopeController::Instance().SetLocalScope(RId);
  }

  DL->SetDeclarationContext(CTX);
  ASTScopeController::Instance().SetDeclarationContext(DL, CTX);

  ASTStatementList SL;
  SL.SetDeclarationContext(CTX);
  ASTScopeController::Instance().SetDeclarationContext(&SL, CTX);

  ASTKernelNode *KN =
      ASTBuilder::Instance().CreateASTKernelNode(Id, *DL, SL, Res);
  assert(KN && "Could not create a valid ASTKernelNode!");

  if (ASTDeclarationContextTracker::Instance().InCalibrationContext()) {
    const_cast<ASTIdentifierNode *>(Id)->SetDeclarationContext(CCX);
    KN->SetDeclarationContext(CCX);
  } else {
    const_cast<ASTIdentifierNode *>(Id)->SetDeclarationContext(GCX);
    KN->SetDeclarationContext(GCX);
  }

  Res->SetDeclarationContext(CTX);
  Res->SetLocation(RTK->GetLocation());
  const_cast<ASTIdentifierNode *>(RId)->SetDeclarationContext(CTX);

  KN->SetLocation(ETK->GetLocation());
  KN->SetExtern(true);
  KN->SetResult(Res);
  Res->SetKernel(Id, KN);
  KN->Mangle();
  Res->Mangle();

  if (!ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
          RId, RId->GetBits(), RId->GetSymbolType())) {
    std::stringstream M;
    M << "Failure transferring ASTResultNode to Local Symbol Table.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(RId), M.str(),
        DiagLevel::Error);
    return ASTKernelDeclarationNode::DeclarationError(Id, M.str());
  }

  DL->TransferSymbols(KN->GetSymbolTable());
  ASTDeclarationBuilder::Instance().TransferSymbol(RId, KN->GetSymbolTable());

  const ASTSymbolTableEntry *KSTE = ASTSymbolTable::Instance().Lookup(Id);
  assert(KSTE && "Extern function has no SymbolTable Entry!");

  if (!ASTSymbolTable::Instance().TransferLocalSymbolToGlobal(Id, KSTE)) {
    std::stringstream M;
    M << "Failure transferring ASTKerneNode to Global Symbol Table.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(RId), M.str(),
        DiagLevel::Error);
    return ASTKernelDeclarationNode::DeclarationError(Id, M.str());
  }

  ASTKernelDeclarationNode *KDN =
      ASTBuilder::Instance().CreateASTKernelDeclaration(Id, KN);
  assert(KDN && "Could not create a valid ASTKernelDeclarationNode!");

  KDN->SetLocation(ETK->GetLocation());
  KDN->Mangle();

  if (ASTDeclarationContextTracker::Instance().InCalibrationContext())
    KDN->SetDeclarationContext(CCX);
  else
    KDN->SetDeclarationContext(GCX);

  ASTKernelContextBuilder::Instance().CloseContext();
  ASTExternBraceMatcher::Instance().Reset();
  ASTDeclarationContextTracker::Instance().PopCurrentContext();
  return KDN;
}

ASTKernelDeclarationNode *ASTProductionFactory::ProductionRule_2501(
    const ASTToken *ETK, ASTIdentifierNode *Id, ASTDeclarationList *DL,
    const ASTToken *RTK) const {
  assert(ETK && "Invalid ASTToken argument!");
  assert(RTK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(DL && "Invalid ASTDeclarationNode argument!");

  QasmFeatureTester::Instance().ValidateFeature("extern");

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  const ASTDeclarationContext *GCX =
      ASTDeclarationContextTracker::Instance().GetGlobalContext();
  assert(GCX && "Could not obtain a valid ASTDeclarationContext!");

  const ASTDeclarationContext *CCX =
      ASTDeclarationContextTracker::Instance().GetDefaultCalibrationContext();
  assert(CCX && "Could not obtain a valid ASTDeclarationContext!");

  if (ASTDeclarationContextTracker::Instance().InGlobalContext() ||
      ASTDeclarationContextTracker::Instance().InCalibrationContext()) {
    if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
            Id, ASTKernelNode::KernelBits, ASTTypeKernel)) {
      std::stringstream M;
      M << "Could not transfer Symbol Table Entry for ASTTypeKernel.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
      return ASTKernelDeclarationNode::DeclarationError(Id, M.str());
    }
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
    std::stringstream M;
    M << "Declaration " << Id->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTKernelDeclarationNode::DeclarationError(Id, M.str());
  }

  std::stringstream IS;
  IS << "ast-result-void-"
     << DIAGLineCounter::Instance().GetIdentifierLocation(RTK);
  ASTIdentifierNode *RId = ASTBuilder::Instance().CreateASTIdentifierNode(
      IS.str(), ASTResultNode::ResultBits, ASTTypeResult);
  assert(RId && "Could not create an ASTIdentifierNode!");

  RId->SetPolymorphicName("result");
  ASTResultNode *Res = ASTBuilder::Instance().CreateASTResultNode(
      RId, ASTTypeVoid, ASTResultNode::ResultBits);
  assert(Res && "Could not create a valid ASTResultNode!");

  if (ASTSymbolTableEntry *RSTE = ASTSymbolTable::Instance().Lookup(RId)) {
    if (!ASTSymbolTable::Instance().TransferGlobalSymbolToLocal(RId, RSTE)) {
      std::stringstream M;
      M << "Failure transferring result symbol to the Local Symbol Table.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(RId), M.str(),
          DiagLevel::ICE);
      return ASTKernelDeclarationNode::DeclarationError(Id, M.str());
    }

    RSTE->SetContext(CTX);
    RSTE->SetLocalScope();
    RId->SetDeclarationContext(CTX);
    RId->SetLocalScope();
    ASTScopeController::Instance().SetLocalScope(RId);
  }

  DL->SetDeclarationContext(CTX);
  ASTScopeController::Instance().SetDeclarationContext(DL, CTX);

  ASTStatementList SL;
  SL.SetDeclarationContext(CTX);
  ASTScopeController::Instance().SetDeclarationContext(&SL, CTX);

  ASTKernelNode *KN =
      ASTBuilder::Instance().CreateASTKernelNode(Id, *DL, SL, Res);
  assert(KN && "Could not create a valid ASTKernelNode!");

  if (ASTDeclarationContextTracker::Instance().InCalibrationContext()) {
    const_cast<ASTIdentifierNode *>(Id)->SetDeclarationContext(CCX);
    KN->SetDeclarationContext(CCX);
  } else {
    const_cast<ASTIdentifierNode *>(Id)->SetDeclarationContext(GCX);
    KN->SetDeclarationContext(GCX);
  }

  Res->SetDeclarationContext(CTX);
  Res->SetLocation(RTK->GetLocation());

  KN->SetLocation(ETK->GetLocation());
  KN->SetExtern(true);
  KN->SetResult(Res);
  Res->SetKernel(Id, KN);
  Res->SetLocation(RTK->GetLocation());
  KN->Mangle();
  Res->Mangle();

  if (!ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
          RId, RId->GetBits(), RId->GetSymbolType())) {
    std::stringstream M;
    M << "Failure transferring ASTResultNode to Local Symbol Table.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(RId), M.str(),
        DiagLevel::Error);
    return ASTKernelDeclarationNode::DeclarationError(Id, M.str());
  }

  DL->TransferSymbols(KN->GetSymbolTable());
  ASTDeclarationBuilder::Instance().TransferSymbol(RId, KN->GetSymbolTable());

  const ASTSymbolTableEntry *KSTE = ASTSymbolTable::Instance().Lookup(Id);
  assert(KSTE && "Extern function has no SymbolTable Entry!");

  if (!ASTSymbolTable::Instance().TransferLocalSymbolToGlobal(Id, KSTE)) {
    std::stringstream M;
    M << "Failure transferring ASTKerneNode to Global Symbol Table.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(RId), M.str(),
        DiagLevel::Error);
    return ASTKernelDeclarationNode::DeclarationError(Id, M.str());
  }

  ASTKernelDeclarationNode *KDN =
      ASTBuilder::Instance().CreateASTKernelDeclaration(Id, KN);
  assert(KDN && "Could not create a valid ASTKernelDeclarationNode!");

  KDN->SetLocation(ETK->GetLocation());
  KDN->Mangle();

  if (ASTDeclarationContextTracker::Instance().InCalibrationContext())
    KDN->SetDeclarationContext(CCX);
  else
    KDN->SetDeclarationContext(GCX);

  ASTKernelContextBuilder::Instance().CloseContext();
  ASTExternBraceMatcher::Instance().Reset();
  ASTDeclarationContextTracker::Instance().PopCurrentContext();
  return KDN;
}

ASTKernelDeclarationNode *
ASTProductionFactory::ProductionRule_2502(const ASTToken *ETK,
                                          const ASTIdentifierNode *Id,
                                          const ASTToken *RTK) const {
  assert(ETK && "Invalid ASTToken argument!");
  assert(RTK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");

  QasmFeatureTester::Instance().ValidateFeature("extern");

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  const ASTDeclarationContext *GCX =
      ASTDeclarationContextTracker::Instance().GetGlobalContext();
  assert(GCX && "Could not obtain a valid ASTDeclarationContext!");

  const ASTDeclarationContext *CCX =
      ASTDeclarationContextTracker::Instance().GetDefaultCalibrationContext();
  assert(CCX && "Could not obtain a valid ASTDeclarationContext!");

  if (ASTDeclarationContextTracker::Instance().InGlobalContext() ||
      ASTDeclarationContextTracker::Instance().InCalibrationContext()) {
    if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
            Id, ASTKernelNode::KernelBits, ASTTypeKernel)) {
      std::stringstream M;
      M << "Could not transfer Symbol Table Entry for ASTTypeKernel.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
      return ASTKernelDeclarationNode::DeclarationError(Id, M.str());
    }
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
    std::stringstream M;
    M << "Declaration " << Id->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTKernelDeclarationNode::DeclarationError(Id, M.str());
  }

  std::stringstream IS;
  IS << "ast-result-void-"
     << DIAGLineCounter::Instance().GetIdentifierLocation(RTK);
  ASTIdentifierNode *RId = ASTBuilder::Instance().CreateASTIdentifierNode(
      IS.str(), ASTResultNode::ResultBits, ASTTypeResult);
  assert(RId && "Could not create an ASTIdentifierNode!");

  RId->SetLocation(RTK->GetLocation());
  RId->SetPolymorphicName("result");
  ASTResultNode *Res = ASTBuilder::Instance().CreateASTResultNode(
      RId, ASTTypeVoid, ASTResultNode::ResultBits);
  assert(Res && "Could not create a valid ASTResultNode!");

  if (ASTSymbolTableEntry *RSTE = ASTSymbolTable::Instance().Lookup(RId)) {
    if (!ASTSymbolTable::Instance().TransferGlobalSymbolToLocal(RId, RSTE)) {
      std::stringstream M;
      M << "Failure transferring result symbol to the Local Symbol Table.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(RId), M.str(),
          DiagLevel::ICE);
      return ASTKernelDeclarationNode::DeclarationError(Id, M.str());
    }

    RSTE->SetContext(CTX);
    RSTE->SetLocalScope();
    RId->SetDeclarationContext(CTX);
    RId->SetLocalScope();
    ASTScopeController::Instance().SetLocalScope(RId);
  }

  ASTDeclarationList DL;
  ASTScopeController::Instance().SetDeclarationContext(&DL, CTX);

  ASTStatementList SL;
  ASTScopeController::Instance().SetDeclarationContext(&SL, CTX);

  ASTKernelNode *KN =
      ASTBuilder::Instance().CreateASTKernelNode(Id, DL, SL, Res);
  assert(KN && "Could not create a valid ASTKernelNode!");

  if (ASTDeclarationContextTracker::Instance().InCalibrationContext()) {
    const_cast<ASTIdentifierNode *>(Id)->SetDeclarationContext(CCX);
    KN->SetDeclarationContext(CCX);
  } else {
    const_cast<ASTIdentifierNode *>(Id)->SetDeclarationContext(GCX);
    KN->SetDeclarationContext(GCX);
  }

  Res->SetDeclarationContext(CTX);
  Res->SetLocation(RTK->GetLocation());

  KN->SetLocation(ETK->GetLocation());
  KN->SetExtern(true);
  KN->SetResult(Res);
  Res->SetKernel(Id, KN);
  KN->Mangle();
  Res->Mangle();

  if (!ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
          RId, RId->GetBits(), RId->GetSymbolType())) {
    std::stringstream M;
    M << "Failure transferring ASTResultNode to Local Symbol Table.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(RId), M.str(),
        DiagLevel::Error);
    return ASTKernelDeclarationNode::DeclarationError(Id, M.str());
  }

  ASTDeclarationBuilder::Instance().TransferSymbol(RId, KN->GetSymbolTable());

  const ASTSymbolTableEntry *KSTE = ASTSymbolTable::Instance().Lookup(Id);
  assert(KSTE && "Extern function has no SymbolTable Entry!");

  if (!ASTSymbolTable::Instance().TransferLocalSymbolToGlobal(Id, KSTE)) {
    std::stringstream M;
    M << "Failure transferring ASTKerneNode to Global Symbol Table.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(RId), M.str(),
        DiagLevel::Error);
    return ASTKernelDeclarationNode::DeclarationError(Id, M.str());
  }

  ASTKernelDeclarationNode *KDN =
      ASTBuilder::Instance().CreateASTKernelDeclaration(Id, KN);
  assert(KDN && "Could not create a valid ASTKernelDeclarationNode!");

  KDN->SetLocation(ETK->GetLocation());
  KDN->Mangle();

  if (ASTDeclarationContextTracker::Instance().InCalibrationContext())
    KDN->SetDeclarationContext(CCX);
  else
    KDN->SetDeclarationContext(GCX);

  ASTKernelContextBuilder::Instance().CloseContext();
  ASTExternBraceMatcher::Instance().Reset();
  ASTDeclarationContextTracker::Instance().PopCurrentContext();
  return KDN;
}

ASTKernelDeclarationNode *ASTProductionFactory::ProductionRule_2503(
    const ASTToken *ETK, ASTIdentifierNode *Id, ASTResultNode *Res,
    const ASTToken *RTK) const {
  assert(ETK && "Invalid ASTToken argument!");
  assert(RTK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(Res && "Invalid ASTResultNode argument!");

  QasmFeatureTester::Instance().ValidateFeature("extern");

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  const ASTDeclarationContext *GCX =
      ASTDeclarationContextTracker::Instance().GetGlobalContext();
  assert(GCX && "Could not obtain a valid ASTDeclarationContext!");

  const ASTDeclarationContext *CCX =
      ASTDeclarationContextTracker::Instance().GetDefaultCalibrationContext();
  assert(CCX && "Could not obtain a valid ASTDeclarationContext!");

  if (ASTDeclarationContextTracker::Instance().InGlobalContext() ||
      ASTDeclarationContextTracker::Instance().InCalibrationContext()) {
    if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
            Id, ASTKernelNode::KernelBits, ASTTypeKernel)) {
      std::stringstream M;
      M << "Could not transfer Symbol Table Entry for ASTTypeKernel.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
      return ASTKernelDeclarationNode::DeclarationError(Id, M.str());
    }
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
    std::stringstream M;
    M << "Declaration " << Id->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTKernelDeclarationNode::DeclarationError(Id, M.str());
  }

  const ASTIdentifierNode *RId = Res->GetIdentifier();
  assert(RId && "Invalid ASTIdentifierNode for ASTResultNode!");

  if (ASTSymbolTableEntry *RSTE = ASTSymbolTable::Instance().Lookup(RId)) {
    if (!ASTSymbolTable::Instance().TransferGlobalSymbolToLocal(RId, RSTE)) {
      std::stringstream M;
      M << "Failure transferring result symbol to the Local Symbol Table.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(RId), M.str(),
          DiagLevel::ICE);
      return ASTKernelDeclarationNode::DeclarationError(Id, M.str());
    }

    RSTE->SetContext(CTX);
    RSTE->SetLocalScope();
    const_cast<ASTIdentifierNode *>(RId)->SetDeclarationContext(CTX);
    const_cast<ASTIdentifierNode *>(RId)->SetLocalScope();
    ASTScopeController::Instance().SetLocalScope(RId);
  }

  ASTDeclarationList DL;
  DL.SetDeclarationContext(CTX);
  ASTScopeController::Instance().SetDeclarationContext(&DL, CTX);

  ASTStatementList SL;
  SL.SetDeclarationContext(CTX);
  ASTScopeController::Instance().SetDeclarationContext(&SL, CTX);

  ASTKernelNode *KN =
      ASTBuilder::Instance().CreateASTKernelNode(Id, DL, SL, Res);
  assert(KN && "Could not create a valid ASTKernelNode!");

  if (ASTDeclarationContextTracker::Instance().InCalibrationContext()) {
    const_cast<ASTIdentifierNode *>(Id)->SetDeclarationContext(CCX);
    KN->SetDeclarationContext(CCX);
  } else {
    const_cast<ASTIdentifierNode *>(Id)->SetDeclarationContext(GCX);
    KN->SetDeclarationContext(GCX);
  }

  Res->SetDeclarationContext(CTX);
  Res->SetLocation(RTK->GetLocation());

  KN->SetLocation(ETK->GetLocation());
  KN->SetExtern(true);
  KN->SetResult(Res);
  Res->SetKernel(Id, KN);
  KN->Mangle();
  Res->Mangle();

  if (!ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
          RId, RId->GetBits(), RId->GetSymbolType())) {
    std::stringstream M;
    M << "Failure transferring ASTResultNode to Local Symbol Table.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(RId), M.str(),
        DiagLevel::Error);
    return ASTKernelDeclarationNode::DeclarationError(Id, M.str());
  }

  ASTDeclarationBuilder::Instance().TransferSymbol(RId, KN->GetSymbolTable());

  const ASTSymbolTableEntry *KSTE = ASTSymbolTable::Instance().Lookup(Id);
  assert(KSTE && "Extern function has no SymbolTable Entry!");

  if (!ASTSymbolTable::Instance().TransferLocalSymbolToGlobal(Id, KSTE)) {
    std::stringstream M;
    M << "Failure transferring ASTKerneNode to Global Symbol Table.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(RId), M.str(),
        DiagLevel::Error);
    return ASTKernelDeclarationNode::DeclarationError(Id, M.str());
  }

  ASTKernelDeclarationNode *KDN =
      ASTBuilder::Instance().CreateASTKernelDeclaration(Id, KN);
  assert(KDN && "Could not create a valid ASTKernelDeclarationNode!");

  KDN->SetLocation(ETK->GetLocation());
  KDN->Mangle();

  if (ASTDeclarationContextTracker::Instance().InCalibrationContext())
    KDN->SetDeclarationContext(CCX);
  else
    KDN->SetDeclarationContext(GCX);

  ASTKernelContextBuilder::Instance().CloseContext();
  ASTExternBraceMatcher::Instance().Reset();
  ASTDeclarationContextTracker::Instance().PopCurrentContext();
  return KDN;
}

ASTKernelDeclarationNode *ASTProductionFactory::ProductionRule_2504(
    const ASTToken *ETK, ASTIdentifierNode *Id, ASTDeclarationList *DL,
    ASTStatementList *SL, ASTResultNode *Res, const ASTToken *RTK) const {
  assert(ETK && "Invalid ASTToken argument!");
  assert(RTK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(DL && "Invalid ASTDeclarationList argument!");
  assert(SL && "Invalid ASTStatementList argument!");
  assert(Res && "Invalid ASTResultNode argument!");

  QasmFeatureTester::Instance().ValidateFeature("extern");

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  const ASTDeclarationContext *GCX =
      ASTDeclarationContextTracker::Instance().GetGlobalContext();
  assert(GCX && "Could not obtain a valid ASTDeclarationContext!");

  const ASTDeclarationContext *CCX =
      ASTDeclarationContextTracker::Instance().GetDefaultCalibrationContext();
  assert(CCX && "Could not obtain a valid ASTDeclarationContext!");

  if (ASTDeclarationContextTracker::Instance().InGlobalContext() ||
      ASTDeclarationContextTracker::Instance().InCalibrationContext()) {
    if (!ASTSymbolTable::Instance().TransferUndefinedSymbol(
            Id, ASTKernelNode::KernelBits, ASTTypeKernel)) {
      std::stringstream M;
      M << "Could not transfer Symbol Table Entry for ASTTypeKernel.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
      return ASTKernelDeclarationNode::DeclarationError(Id, M.str());
    }
  }

  if (ASTDeclarationBuilder::Instance().DeclAlreadyExists(Id)) {
    std::stringstream M;
    M << "Declaration " << Id->GetName() << " shadows a "
      << "previous declaration.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return ASTKernelDeclarationNode::DeclarationError(Id, M.str());
  }

  const ASTIdentifierNode *RId = Res->GetIdentifier();
  assert(RId && "Invalid ASTIdentifierNode for ASTResultNode!");

  if (ASTSymbolTableEntry *RSTE = ASTSymbolTable::Instance().Lookup(RId)) {
    if (!ASTSymbolTable::Instance().TransferGlobalSymbolToLocal(RId, RSTE)) {
      std::stringstream M;
      M << "Failure transferring result symbol to the Local Symbol Table.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(RId), M.str(),
          DiagLevel::ICE);
      return ASTKernelDeclarationNode::DeclarationError(Id, M.str());
    }

    RSTE->SetContext(CTX);
    RSTE->SetLocalScope();
    const_cast<ASTIdentifierNode *>(RId)->SetDeclarationContext(CTX);
    const_cast<ASTIdentifierNode *>(RId)->SetLocalScope();
    ASTScopeController::Instance().SetLocalScope(RId);
  }

  DL->SetDeclarationContext(CTX);
  ASTScopeController::Instance().SetDeclarationContext(DL, CTX);

  SL->SetDeclarationContext(CTX);
  ASTScopeController::Instance().SetDeclarationContext(SL, CTX);

  ASTKernelNode *KN =
      ASTBuilder::Instance().CreateASTKernelNode(Id, *DL, *SL, Res);
  assert(KN && "Could not create a valid ASTKernelNode!");

  if (ASTDeclarationContextTracker::Instance().InCalibrationContext()) {
    const_cast<ASTIdentifierNode *>(Id)->SetDeclarationContext(CCX);
    KN->SetDeclarationContext(CCX);
  } else {
    const_cast<ASTIdentifierNode *>(Id)->SetDeclarationContext(GCX);
    KN->SetDeclarationContext(GCX);
  }

  Res->SetDeclarationContext(CTX);
  Res->SetLocation(RTK->GetLocation());

  KN->SetLocation(ETK->GetLocation());
  KN->SetExtern(true);
  KN->SetResult(Res);
  Res->SetKernel(Id, KN);
  KN->Mangle();
  Res->Mangle();

  if (!ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
          RId, RId->GetBits(), RId->GetSymbolType())) {
    std::stringstream M;
    M << "Failure transferring ASTResultNode to Local Symbol Table.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(RId), M.str(),
        DiagLevel::Error);
    return ASTKernelDeclarationNode::DeclarationError(Id, M.str());
  }

  SL->TransferDeclarations(KN->GetSymbolTable());
  SL->TransferStatements(KN->GetSymbolTable());

  DL->TransferSymbols(KN->GetSymbolTable());
  ASTDeclarationBuilder::Instance().TransferSymbol(RId, KN->GetSymbolTable());

  const ASTSymbolTableEntry *KSTE = ASTSymbolTable::Instance().Lookup(Id);
  assert(KSTE && "Extern function has no SymbolTable Entry!");

  if (!ASTSymbolTable::Instance().TransferLocalSymbolToGlobal(Id, KSTE)) {
    std::stringstream M;
    M << "Failure transferring ASTKerneNode to Global Symbol Table.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(RId), M.str(),
        DiagLevel::Error);
    return ASTKernelDeclarationNode::DeclarationError(Id, M.str());
  }

  ASTKernelDeclarationNode *KDN =
      ASTBuilder::Instance().CreateASTKernelDeclaration(Id, KN);
  assert(KDN && "Could not create a valid ASTKernelDeclarationNode!");

  KDN->SetLocation(ETK->GetLocation());
  KDN->Mangle();

  if (ASTDeclarationContextTracker::Instance().InCalibrationContext())
    KDN->SetDeclarationContext(CCX);
  else
    KDN->SetDeclarationContext(GCX);

  ASTKernelContextBuilder::Instance().CloseContext();
  ASTExternBraceMatcher::Instance().Reset();
  ASTDeclarationContextTracker::Instance().PopCurrentContext();
  return KDN;
}

ASTResultNode *
ASTProductionFactory::ProductionRule_2100(const ASTToken *TK) const {
  assert(TK && "Invalid ASTToken argument!");

  std::stringstream IS;
  IS << "ast-result-angle-"
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      IS.str(), ASTResultNode::ResultBits, ASTTypeResult);
  assert(Id && "Could not create an ASTIdentifierNode!");

  Id->SetPolymorphicName("result");
  Id->SetLocation(TK->GetLocation());

  ASTResultNode *RN =
      ASTBuilder::Instance().CreateASTResultNode(Id, ASTTypeAngle);
  assert(RN && "Could not create an ASTResultNode!");

  RN->SetLocation(TK->GetLocation());
  ASTIdentifierNode *AId =
      new ASTIdentifierNode("angle", ASTTypeAngle, ASTAngleNode::AngleBits);
  assert(AId && "Could not create a valid ASTIdentifierNode!");

  AId->SetLocation(TK->GetLocation());
  ASTAngleNode *AN = new ASTAngleNode(AId);
  assert(AN && "Could not create a valid ASTAngleNode!");

  AN->SetLocation(TK->GetLocation());
  AN->Mangle();

  ASTIdentifierTypeController::Instance().SetPreviousCurrent();
  RN->SetResult(AN);
  return RN;
}

ASTResultNode *
ASTProductionFactory::ProductionRule_2101(const ASTIdentifierNode *IId,
                                          const ASTToken *TK) const {
  assert(IId && "Invalid ASTIdentifierNode argument!");
  assert(TK && "Invalid ASTToken argument!");

  ASTScopeController::Instance().CheckOutOfScope(IId);

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(IId);
  assert(!ASTIdentifierNode::InvalidBits(Bits) && "Invalid angle bit width!");

  std::stringstream IS;
  IS << "ast-result-angle-" << Bits << '-'
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *RId = ASTBuilder::Instance().CreateASTIdentifierNode(
      IS.str(), ASTResultNode::ResultBits, ASTTypeResult);
  assert(RId && "Could not create an ASTIdentifierNode!");

  RId->SetPolymorphicName("result");
  RId->SetLocation(TK->GetLocation());

  ASTResultNode *RN =
      ASTBuilder::Instance().CreateASTResultNode(RId, ASTTypeAngle, Bits);
  assert(RN && "Could not create an ASTResultNode!");

  RN->SetLocation(TK->GetLocation());
  ASTIdentifierNode *AId = new ASTIdentifierNode("angle", ASTTypeAngle, Bits);
  assert(AId && "Could not create a valid ASTIdentifierNode!");

  AId->SetLocation(TK->GetLocation());
  ASTAngleNode *AN = new ASTAngleNode(AId, ASTAngleTypeGeneric, Bits);
  assert(AN && "Could not create a valid ASTAngleNode!");

  AN->SetLocation(TK->GetLocation());
  AN->Mangle();

  ASTIdentifierTypeController::Instance().SetPreviousCurrent();
  RN->SetResult(AN);
  return RN;
}

ASTResultNode *
ASTProductionFactory::ProductionRule_2102(const ASTIntNode *II,
                                          const ASTToken *TK) const {
  assert(II && "Invalid ASTIntNode argument!");
  assert(TK && "Invalid ASTToken argument!");

  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(II);
  assert(!ASTIdentifierNode::InvalidBits(Bits) && "Invalid angle bit width!");

  std::stringstream IS;
  IS << "ast-result-angle-" << Bits << '-'
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *RId = ASTBuilder::Instance().CreateASTIdentifierNode(
      IS.str(), ASTResultNode::ResultBits, ASTTypeResult);
  assert(RId && "Could not create an ASTIdentifierNode!");

  RId->SetPolymorphicName("result");
  RId->SetLocation(TK->GetLocation());

  ASTResultNode *RN =
      ASTBuilder::Instance().CreateASTResultNode(RId, ASTTypeAngle, Bits);
  assert(RN && "Could not create an ASTResultNode!");

  RN->SetLocation(TK->GetLocation());
  ASTIdentifierNode *AId = new ASTIdentifierNode("angle", ASTTypeAngle, Bits);
  assert(AId && "Could not create a valid ASTIdentifierNode!");

  AId->SetLocation(TK->GetLocation());
  ASTAngleNode *AN = new ASTAngleNode(AId, ASTAngleTypeGeneric, Bits);
  assert(AN && "Could not create a valid ASTAngleNode!");

  AN->SetLocation(TK->GetLocation());
  AN->Mangle();

  ASTIdentifierTypeController::Instance().SetPreviousCurrent();
  RN->SetResult(AN);
  return RN;
}

ASTResultNode *
ASTProductionFactory::ProductionRule_2103(const ASTBinaryOpNode *BOP,
                                          const ASTToken *TK) const {
  assert(BOP && "Invalid ASTBinaryOpNode argument!");
  assert(TK && "Invalid ASTToken argument!");

  std::stringstream IS;
  IS << "ast-result-angle-"
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *RId = ASTBuilder::Instance().CreateASTIdentifierNode(
      IS.str(), ASTResultNode::ResultBits, ASTTypeResult);
  assert(RId && "Could not create an ASTIdentifierNode!");

  RId->SetPolymorphicName("result");
  RId->SetLocation(TK->GetLocation());

  ASTResultNode *RN = ASTBuilder::Instance().CreateASTResultNode(
      RId, ASTTypeAngle, ASTAngleNode::AngleBits);
  assert(RN && "Could not create an ASTResultNode!");

  RN->SetLocation(TK->GetLocation());

  ASTIdentifierNode *AId =
      new ASTIdentifierNode("angle", ASTTypeAngle, ASTAngleNode::AngleBits);
  assert(AId && "Could not create a valid ASTIdentifierNode!");

  AId->SetLocation(TK->GetLocation());
  ASTAngleNode *AN =
      new ASTAngleNode(AId, ASTAngleTypeGeneric, ASTAngleNode::AngleBits);
  assert(AN && "Could not create a valid ASTAngleNode!");

  AN->SetLocation(TK->GetLocation());
  AN->Mangle();

  ASTIdentifierTypeController::Instance().SetPreviousCurrent();
  RN->SetResult(AN);
  return RN;
}

ASTResultNode *
ASTProductionFactory::ProductionRule_2104(const ASTToken *TK) const {
  assert(TK && "Invalid ASTToken argument!");

  std::stringstream IS;
  IS << "ast-result-cbit-"
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      IS.str(), ASTResultNode::ResultBits, ASTTypeResult);
  assert(Id && "Could not create an ASTIdentifierNode!");

  Id->SetPolymorphicName("result");
  Id->SetLocation(TK->GetLocation());

  ASTResultNode *RN =
      ASTBuilder::Instance().CreateASTResultNode(Id, ASTTypeBitset, 1U);
  assert(RN && "Could not create an ASTResultNode!");

  RN->SetLocation(TK->GetLocation());
  ASTIdentifierNode *BId = new ASTIdentifierNode("bitset", ASTTypeBitset, 1U);
  assert(BId && "Could not create a valid ASTIdentifierNode!");

  BId->SetLocation(TK->GetLocation());
  ASTCBitNode *CBN = new ASTCBitNode(BId, 1U);
  assert(CBN && "Could not create a valid ASTCBitNode!");

  CBN->SetLocation(TK->GetLocation());
  CBN->Mangle();

  ASTIdentifierTypeController::Instance().SetPreviousCurrent();
  RN->SetResult(CBN);
  return RN;
}

ASTResultNode *
ASTProductionFactory::ProductionRule_2105(const ASTIdentifierNode *IId,
                                          const ASTToken *TK) const {
  assert(IId && "Invalid ASTIdentifierNode argument!");
  assert(TK && "Invalid ASTToken argument!");

  ASTScopeController::Instance().CheckOutOfScope(IId);
  unsigned Bits = ASTUtils::Instance().GetUnsignedValue(IId);

  if (ASTIdentifierNode::InvalidBits(Bits)) {
    std::stringstream M;
    M << "Invalid number of Bit Index Bits.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTResultNode::ExpressionError(M.str());
  }

  std::stringstream IS;
  IS << "ast-result-cbit-" << Bits << '-'
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *RId = ASTBuilder::Instance().CreateASTIdentifierNode(
      IS.str(), ASTResultNode::ResultBits, ASTTypeResult);
  assert(RId && "Could not create a valid ASTIdentifierNode!");

  RId->SetPolymorphicName("result");
  RId->SetBits(Bits);
  RId->SetLocation(TK->GetLocation());

  ASTResultNode *RN =
      ASTBuilder::Instance().CreateASTResultNode(RId, ASTTypeBitset, Bits);
  assert(RN && "Could not create an ASTResultNode!");

  RN->SetLocation(TK->GetLocation());

  ASTIdentifierNode *BId = new ASTIdentifierNode("bitset", ASTTypeBitset, Bits);
  assert(BId && "Could not create a valid ASTIdentifierNode!");

  BId->SetBits(Bits);
  BId->SetLocation(TK->GetLocation());

  ASTCBitNode *CBN = new ASTCBitNode(BId, Bits);
  assert(CBN && "Could not create a valid ASTCBitNode!");

  CBN->SetLocation(TK->GetLocation());
  CBN->Mangle();

  ASTIdentifierTypeController::Instance().SetPreviousCurrent();
  RN->SetResult(CBN);
  return RN;
}

ASTResultNode *
ASTProductionFactory::ProductionRule_2106(const ASTBinaryOpNode *BOP,
                                          const ASTToken *TK) const {
  assert(BOP && "Invalid ASTBinaryOpNode argument!");
  assert(TK && "Invalid ASTToken argument!");

  std::stringstream M;
  M << "A Bitset size must be a compile-time integer constant expression.";
  QasmDiagnosticEmitter::Instance().EmitDiagnostic(
      DIAGLineCounter::Instance().GetLocation(BOP), M.str(), DiagLevel::Error);
  return ASTResultNode::ExpressionError(M.str());
}

ASTResultNode *
ASTProductionFactory::ProductionRule_2107(const std::string *IS,
                                          const ASTToken *TK) const {
  assert(IS && "Invalid string argument!");
  assert(TK && "Invalid ASTToken argument!");

  unsigned Bits = static_cast<unsigned>(std::stoi(*IS));

  if (ASTIdentifierNode::InvalidBits(Bits)) {
    std::stringstream M;
    M << "Invalid number of bits for bitset size.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTResultNode::ExpressionError(M.str());
  }

  std::stringstream ISS;
  ISS << "ast-result-cbit-" << Bits << "-"
      << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      ISS.str(), ASTResultNode::ResultBits, ASTTypeResult);
  assert(Id && "Could not create an ASTIdentifierNode!");

  Id->SetBits(Bits);
  Id->SetLocation(TK->GetLocation());
  Id->SetPolymorphicName("result");

  ASTResultNode *RN =
      ASTBuilder::Instance().CreateASTResultNode(Id, ASTTypeBitset, Bits);
  assert(RN && "Could not create an ASTResultNode!");

  RN->SetLocation(TK->GetLocation());
  ASTIdentifierNode *BId = new ASTIdentifierNode("bitset", ASTTypeBitset, Bits);
  assert(BId && "Could not create a valid ASTIdentifierNode!");

  ASTCBitNode *CBN = new ASTCBitNode(BId, Bits);
  assert(CBN && "Could not create a valid ASTCBitNode!");

  CBN->SetLocation(TK->GetLocation());
  CBN->Mangle();

  ASTIdentifierTypeController::Instance().SetPreviousCurrent();
  RN->SetResult(CBN);
  return RN;
}

ASTResultNode *
ASTProductionFactory::ProductionRule_2108(const ASTToken *TK) const {
  assert(TK && "Invalid ASTToken Argument!");

  std::stringstream M;
  M << "A function cannot return a Qubit.";
  QasmDiagnosticEmitter::Instance().EmitDiagnostic(
      DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
  return ASTResultNode::ExpressionError(M.str());
}

ASTResultNode *
ASTProductionFactory::ProductionRule_2109(const ASTToken *TK) const {
  assert(TK && "Invalid ASTToken Argument!");

  std::stringstream IS;
  IS << "ast-result-bool-"
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      IS.str(), ASTResultNode::ResultBits, ASTTypeResult);
  assert(Id && "Could not create an ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());
  Id->SetPolymorphicName("result");

  ASTResultNode *RN =
      ASTBuilder::Instance().CreateASTResultNode(Id, ASTTypeBool);
  assert(RN && "Could not create an ASTResultNode!");

  RN->SetLocation(TK->GetLocation());
  ASTIdentifierNode *BId =
      new ASTIdentifierNode("bool", ASTTypeBool, ASTBoolNode::BoolBits);
  assert(BId && "Could not create a valid ASTBoolNode!");

  BId->SetLocation(TK->GetLocation());
  ASTBoolNode *BN = new ASTBoolNode(BId, false);
  assert(BN && "Could not create a valid ASTBoolNode!");

  BN->SetLocation(TK->GetLocation());
  BN->Mangle();

  ASTIdentifierTypeController::Instance().SetPreviousCurrent();
  RN->SetResult(BN);
  return RN;
}

ASTResultNode *
ASTProductionFactory::ProductionRule_2110(const ASTToken *TK) const {
  assert(TK && "Invalid ASTToken Argument!");

  std::stringstream IS;
  IS << "ast-result-int-"
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      IS.str(), ASTResultNode::ResultBits, ASTTypeResult);
  assert(Id && "Could not create an ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());
  Id->SetPolymorphicName("result");

  ASTResultNode *RN =
      ASTBuilder::Instance().CreateASTResultNode(Id, ASTTypeInt);
  assert(RN && "Could not create an ASTResultNode!");

  RN->SetLocation(TK->GetLocation());
  ASTIdentifierNode *IId =
      new ASTIdentifierNode("int", ASTTypeInt, ASTIntNode::IntBits);
  assert(IId && "Could not create a valid ASTIntNode!");

  IId->SetLocation(TK->GetLocation());

  ASTIntNode *IN = new ASTIntNode(IId, int32_t(0));
  assert(IN && "Could not create a valid ASTIntNode!");

  IN->SetLocation(TK->GetLocation());
  IN->Mangle();

  ASTIdentifierTypeController::Instance().SetPreviousCurrent();
  RN->SetResult(IN);
  return RN;
}

ASTResultNode *
ASTProductionFactory::ProductionRule_2111(const ASTToken *TK) const {
  assert(TK && "Invalid ASTToken Argument!");

  std::stringstream IS;
  IS << "ast-result-uint-"
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      IS.str(), ASTResultNode::ResultBits, ASTTypeResult);
  assert(Id && "Could not create an ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());
  Id->SetPolymorphicName("result");

  ASTResultNode *RN = ASTBuilder::Instance().CreateASTResultNode(
      Id, ASTTypeUInt, ASTIntNode::IntBits, ASTSignbit::Unsigned);
  assert(RN && "Could not create an ASTResultNode!");

  RN->SetLocation(TK->GetLocation());

  ASTIdentifierNode *IId =
      new ASTIdentifierNode("uint", ASTTypeInt, ASTIntNode::IntBits);
  assert(IId && "Could not create a valid ASTIntNode!");

  IId->SetLocation(TK->GetLocation());

  ASTIntNode *IN = new ASTIntNode(IId, uint32_t(0U));
  assert(IN && "Could not create a valid ASTIntNode!");

  IN->SetLocation(TK->GetLocation());
  IN->Mangle();

  ASTIdentifierTypeController::Instance().SetPreviousCurrent();
  RN->SetResult(IN);
  return RN;
}

ASTResultNode *
ASTProductionFactory::ProductionRule_2112(const ASTMPIntegerNode *MPI) const {
  assert(MPI && "Invalid ASTMPIntegerNode argument!");

  std::stringstream IS;
  IS << "ast-result-mpinteger-"
     << DIAGLineCounter::Instance().GetIdentifierLocation();
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      IS.str(), ASTResultNode::ResultBits, ASTTypeResult);
  assert(Id && "Could not create an ASTIdentifierNode!");

  Id->SetLocation(MPI->GetLocation());
  Id->SetPolymorphicName("result");

  ASTResultNode *RN = ASTBuilder::Instance().CreateASTResultNode(
      Id, ASTTypeMPInteger, MPI->GetBits(), MPI->GetSignBit());
  assert(RN && "Could not create an ASTResultNode!");

  RN->SetLocation(MPI->GetLocation());

  ASTIdentifierTypeController::Instance().SetPreviousCurrent();
  RN->SetResult(MPI);
  return RN;
}

ASTResultNode *
ASTProductionFactory::ProductionRule_2113(const ASTToken *TK) const {
  assert(TK && "Invalid ASTToken Argument!");

  std::stringstream IS;
  IS << "ast-result-float-"
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      IS.str(), ASTResultNode::ResultBits, ASTTypeResult);
  assert(Id && "Could not create an ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());
  Id->SetPolymorphicName("result");

  ASTResultNode *RN =
      ASTBuilder::Instance().CreateASTResultNode(Id, ASTTypeFloat);
  assert(RN && "Could not create an ASTResultNode!");

  RN->SetLocation(TK->GetLocation());
  ASTIdentifierNode *FId =
      new ASTIdentifierNode("float", ASTTypeFloat, ASTFloatNode::FloatBits);
  assert(FId && "Could not create a valid ASTIdentifierNode!");

  FId->SetLocation(TK->GetLocation());
  ASTFloatNode *FN = new ASTFloatNode(FId, 0.0f);
  assert(FN && "Could not create a valid ASTFloatNode!");

  FN->SetLocation(TK->GetLocation());
  FN->Mangle();

  ASTIdentifierTypeController::Instance().SetPreviousCurrent();
  RN->SetResult(FN);
  return RN;
}

ASTResultNode *
ASTProductionFactory::ProductionRule_2114(const ASTToken *TK) const {
  assert(TK && "Invalid ASTToken Argument!");

  std::stringstream IS;
  IS << "ast-result-double-"
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      IS.str(), ASTResultNode::ResultBits, ASTTypeResult);
  assert(Id && "Could not create an ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());
  Id->SetPolymorphicName("result");

  ASTResultNode *RN =
      ASTBuilder::Instance().CreateASTResultNode(Id, ASTTypeDouble);
  assert(RN && "Could not create an ASTResultNode!");

  RN->SetLocation(TK->GetLocation());
  ASTIdentifierNode *DId =
      new ASTIdentifierNode("double", ASTTypeDouble, ASTDoubleNode::DoubleBits);
  assert(DId && "Could not create a valid ASTIdentifierNode!");

  DId->SetLocation(TK->GetLocation());
  ASTDoubleNode *DN = new ASTDoubleNode(DId, 0.0);
  assert(DN && "Could not create a valid ASTDoubleNode!");

  DN->SetLocation(TK->GetLocation());
  DN->Mangle();

  ASTIdentifierTypeController::Instance().SetPreviousCurrent();
  RN->SetResult(DN);
  return RN;
}

ASTResultNode *
ASTProductionFactory::ProductionRule_2115(const ASTMPDecimalNode *MPD) const {
  assert(MPD && "Invalid ASTMPDecimalNode argument!");

  std::stringstream IS;
  IS << "ast-result-type-mpdecimal-"
     << DIAGLineCounter::Instance().GetIdentifierLocation(MPD);
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      IS.str(), MPD->GetBits(), ASTTypeResult);
  assert(Id && "Could not create an ASTIdentifierNode!");

  Id->SetLocation(MPD->GetLocation());
  Id->SetPolymorphicName("result");

  ASTResultNode *RN = ASTBuilder::Instance().CreateASTResultNode(
      Id, ASTTypeMPDecimal, MPD->GetBits());
  assert(RN && "Could not create an ASTResultNode!");

  RN->SetLocation(MPD->GetLocation());
  ASTIdentifierTypeController::Instance().SetPreviousCurrent();
  RN->SetResult(MPD);
  return RN;
}

ASTResultNode *
ASTProductionFactory::ProductionRule_2116(const ASTMPComplexNode *MPC) const {
  assert(MPC && "Invalid ASTMPComplexNode argument!");

  std::stringstream IS;
  IS << "ast-result-type-mpcomplex-"
     << DIAGLineCounter::Instance().GetIdentifierLocation(MPC);
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      IS.str(), MPC->GetBits(), ASTTypeResult);
  assert(Id && "Could not create an ASTIdentifierNode!");

  Id->SetLocation(MPC->GetLocation());
  Id->SetPolymorphicName("result");

  ASTResultNode *RN = ASTBuilder::Instance().CreateASTResultNode(
      Id, ASTTypeMPComplex, MPC->GetBits());
  assert(RN && "Could not create an ASTResultNode!");

  RN->SetLocation(MPC->GetLocation());
  ASTIdentifierTypeController::Instance().SetPreviousCurrent();
  RN->SetResult(MPC);
  return RN;
}

ASTResultNode *
ASTProductionFactory::ProductionRule_2117(const ASTToken *TK) const {
  assert(TK && "Invalid ASTToken Argument!");

  std::stringstream IS;
  IS << "ast-result-type-waveform-"
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      IS.str(), OpenPulse::ASTOpenPulseWaveformNode::WaveformBits,
      ASTTypeResult);
  assert(Id && "Could not create an ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());
  Id->SetPolymorphicName("result");

  ASTResultNode *RN = ASTBuilder::Instance().CreateASTResultNode(
      Id, ASTTypeOpenPulseWaveform,
      OpenPulse::ASTOpenPulseWaveformNode::WaveformBits);
  assert(RN && "Could not create an ASTResultNode!");

  RN->SetLocation(TK->GetLocation());
  ASTIdentifierNode *WId =
      new ASTIdentifierNode("waveform", ASTTypeOpenPulseWaveform,
                            OpenPulse::ASTOpenPulseWaveformNode::WaveformBits);
  assert(WId && "Could not create a valid ASTIdentifierNode!");

  WId->SetLocation(TK->GetLocation());
  OpenPulse::ASTOpenPulseWaveformNode *WFN =
      new OpenPulse::ASTOpenPulseWaveformNode(WId, ASTMPComplexList());
  assert(WFN && "Could not create a valid ASTOpenPulseWaveformNode!");

  WFN->SetLocation(TK->GetLocation());
  WFN->Mangle();

  ASTIdentifierTypeController::Instance().SetPreviousCurrent();
  RN->SetResult(WFN);
  return RN;
}

ASTResultNode *
ASTProductionFactory::ProductionRule_2118(const ASTToken *TK) const {
  assert(TK && "Invalid ASTToken Argument!");

  std::stringstream IS;
  IS << "ast-result-type-frame-"
     << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      IS.str(), OpenPulse::ASTOpenPulseFrameNode::FrameBits, ASTTypeResult);
  assert(Id && "Could not create an ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());
  Id->SetPolymorphicName("result");

  ASTResultNode *RN = ASTBuilder::Instance().CreateASTResultNode(
      Id, ASTTypeOpenPulseFrame, OpenPulse::ASTOpenPulseFrameNode::FrameBits);
  assert(RN && "Could not create an ASTResultNode!");

  RN->SetLocation(TK->GetLocation());
  ASTIdentifierNode *FId =
      new ASTIdentifierNode("frame", ASTTypeOpenPulseFrame,
                            OpenPulse::ASTOpenPulseFrameNode::FrameBits);
  assert(FId && "Could not create a valid ASTIdentifierNode!");

  FId->SetLocation(TK->GetLocation());

  OpenPulse::ASTOpenPulseFrameNode *FN =
      new OpenPulse::ASTOpenPulseFrameNode(FId);
  assert(FN && "Could not create a valid ASTOpenPulseFrameNode!");

  FN->SetLocation(TK->GetLocation());
  FN->Mangle();

  ASTIdentifierTypeController::Instance().SetPreviousCurrent();
  RN->SetResult(FN);
  return RN;
}

ASTPragmaNode *
ASTProductionFactory::ProductionRule_2600(const ASTToken *TK,
                                          const std::string *PS) const {
  assert(PS && "Invalid string argument!");
  assert(TK && "Invalid ASTToken argument!");

  const std::vector<std::string> &PDV =
      ASTPragmaContextBuilder::Instance().GetDirectiveVector();
  if (PDV.empty()) {
    std::stringstream M;
    M << "Malformed pragma directive.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTPragmaNode::ExpressionError(M.str());
  }

  const std::string &PD = PDV.front();
  ASTExpressionNodeList EL;
  ASTLocation Loc(TK->GetLocation());
  Loc.ColNo += 7U;

  for (std::vector<std::string>::const_iterator I = PDV.begin() + 1;
       I != PDV.end(); ++I) {
    ASTIdentifierNode *SId =
        new ASTIdentifierNode(*I, ASTTypeStringLiteral, 0UL);
    assert(SId && "Could not create a valid ASTIdentifierNode!");

    SId->SetLocation(Loc);
    SId->SetPolymorphicName(*I);
    ASTStringNode *SN = new ASTStringNode(SId, *I, true);
    assert(SN && "Could not create a valid ASTStringNode!");

    SN->SetLocation(Loc);
    SN->Mangle();
    EL.Append(SN);
    Loc.ColNo += static_cast<uint32_t>((*I).length()) + 1U;
  }

  std::stringstream PSS;
  PSS << "ast-pragma-" << PD << "-"
      << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *Id = new ASTIdentifierNode(PSS.str(), ASTTypePragma,
                                                ASTPragmaNode::PragmaBits);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());
  Id->SetPolymorphicName("pragma");

  ASTPragmaNode *PN = new ASTPragmaNode(Id, PD, EL);
  assert(PN && "Could not create a valid ASTPragmaNode!");

  PN->SetLocation(TK->GetLocation());
  PN->Mangle();

  ASTPragmaContextBuilder::Instance().CloseContext();
  ASTIdentifierTypeController::Instance().Reset();
  return PN;
}

ASTPragmaStatementNode *
ASTProductionFactory::ProductionRule_2601(const ASTPragmaNode *PN) const {
  assert(PN && "Invalid ASTPragmaNode argument!");

  if (!PN) {
    std::stringstream M;
    M << "Malformed pragma directive.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(), M.str(), DiagLevel::Error);
    return ASTPragmaStatementNode::StatementError(M.str());
  }

  ASTPragmaStatementNode *PSN = new ASTPragmaStatementNode(PN);
  assert(PSN && "Could not create a valid ASTPragmaStatementNode!");

  PSN->SetLocation(PN->GetLocation());
  return PSN;
}

ASTAnnotationNode *
ASTProductionFactory::ProductionRule_2610(const ASTToken *TK,
                                          const ASTStringList *SL) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(SL && "Invalid ASTStringList argument!");

  const std::string &AD = TK->GetString();
  const std::vector<std::string> &ADV =
      ASTAnnotationContextBuilder::Instance().GetDirectiveVector();
  if (ADV.empty()) {
    std::stringstream M;
    M << "Malformed annotation directive.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTAnnotationNode::ExpressionError(M.str());
    ASTIdentifierTypeController::Instance().Reset();
  }

  ASTExpressionNodeList EXL;
  EXL.SetLocation(TK->GetLocation());

  for (ASTStringList::const_iterator I = SL->begin(); I != SL->end(); ++I) {
    const std::string &LS = (*I)->GetValue();
    if (ASTStringUtils::Instance().IsWhitespace(LS) || LS == AD)
      continue;

    EXL.Append(*I);
  }

  const std::string ADS = AD.substr(1, std::string::npos);
  std::stringstream ANS;
  ANS << "ast-annotation-" << ADS << '-'
      << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTIdentifierNode *Id = new ASTIdentifierNode(
      ANS.str(), ASTTypeAnnotation, ASTAnnotationNode::AnnotationBits);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());
  Id->SetPolymorphicName(ADS);

  ASTAnnotationNode *AN = new ASTAnnotationNode(Id, ADS, EXL);
  assert(AN && "Could not create a valid ASTAnnotationNode!");

  AN->SetLocation(TK->GetLocation());
  AN->Mangle();

  ASTAnnotationContextBuilder::Instance().Clear();
  ASTAnnotationContextBuilder::Instance().CloseContext();
  ASTIdentifierTypeController::Instance().Reset();
  return AN;
}

ASTAnnotationStatementNode *
ASTProductionFactory::ProductionRule_2610(const ASTToken *TK,
                                          const ASTAnnotationNode *AN) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(AN && "Invalid ASTAnnotationNode argument!");

  if (!AN) {
    std::stringstream M;
    M << "Malformed annotation directive.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    ASTIdentifierTypeController::Instance().Reset();
    return ASTAnnotationStatementNode::StatementError(M.str());
  }

  ASTAnnotationStatementNode *ASN = new ASTAnnotationStatementNode(AN);
  assert(ASN && "Could not create a valid ASTAnnotationStatementNode!");

  ASN->SetLocation(TK->GetLocation());
  ASN->Mangle();
  return ASN;
}

ASTFunctionCallNode *
ASTProductionFactory::ProductionRule_2700(const ASTToken *TK,
                                          const ASTIdentifierNode *Id,
                                          const ASTExpressionList *EL) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(EL && "Invalid ASTExpressionList argument!");

  ASTScopeController::Instance().CheckScopeAndUndefined(Id);
  ASTIdentifierTypeController::Instance().CheckIdentifier(Id);
  ASTIdentifierTypeController::Instance().CheckIsCallable(Id);

  ASTSymbolTableEntry *STE =
      ASTSymbolTable::Instance().Lookup(Id, Id->GetBits(), Id->GetSymbolType());
  assert(STE && "No SymbolTable Entry found for callable object!");

  ASTFunctionCallNode *FCN = nullptr;

  switch (STE->GetValueType()) {
  case ASTTypeFunction: {
    ASTFunctionDefinitionNode *FDN =
        STE->GetValue()->GetValue<ASTFunctionDefinitionNode *>();
    assert(FDN && "Invalid ASTFunctionDefinition from SymbolTable Value!");
    if (!FDN) {
      std::stringstream M;
      M << "Invalid ASTFunctionDefinition from SymbolTable Value.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
      return ASTFunctionCallNode::ExpressionError(Id, M.str());
    }

    assert(FDN->GetNumParameters() == EL->Size() &&
           "Inconsistent number of Function Arguments <-> Parameters!");
    if (FDN->GetNumParameters() != EL->Size()) {
      std::stringstream M;
      M << "Inconsistent number of Function Arguments <-> Parameters.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(TK), M.str(),
          DiagLevel::Error);
      return ASTFunctionCallNode::ExpressionError(Id, M.str());
    }

    std::stringstream CS;
    CS << "ast-function-call-expression-" << Id->GetName() << '-'
       << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
    FCN = ASTBuilder::Instance().CreateASTFunctionCallNode(CS.str(), FDN, EL);
    assert(FCN && "Could not create a valid FunctionCallNode!");
    if (!FCN) {
      std::stringstream M;
      M << "Could not create a valid FunctionCallExpressionNode.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
      return ASTFunctionCallNode::ExpressionError(Id, M.str());
    }
  } break;
  case ASTTypeKernel: {
    ASTKernelNode *KN = STE->GetValue()->GetValue<ASTKernelNode *>();
    assert(KN && "Invalid ASTKernelNode from SymbolTable Value!");
    if (!KN) {
      std::stringstream M;
      M << "Invalid ASTKernelNode from SymbolTable Value.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
      return ASTFunctionCallNode::ExpressionError(Id, M.str());
    }

    assert(KN->GetParameters().size() == EL->Size() &&
           "Inconsistent number of Kernel Arguments <-> Parameters!");
    if (KN->GetParameters().size() != EL->Size()) {
      std::stringstream M;
      M << "Inconsistent number of Kernel Arguments <-> Parameters.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(TK), M.str(),
          DiagLevel::Error);
      return ASTFunctionCallNode::ExpressionError(Id, M.str());
    }

    std::stringstream CS;
    CS << "ast-kernel-call-expression-" << Id->GetName() << '-'
       << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
    FCN = ASTBuilder::Instance().CreateASTFunctionCallNode(CS.str(), KN, EL);
    assert(FCN && "Could not create a valid KernelCallNode!");
    if (!FCN) {
      std::stringstream M;
      M << "Could not create a valid KernelCallExpressionNode.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
      return ASTFunctionCallNode::ExpressionError(Id, M.str());
    }
  } break;
  case ASTTypeDefcalGroup: {
    std::stringstream M;
    M << "A Defcal Group cannot be called. Defcals need overloading "
      << "resolution before they can be called.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTFunctionCallNode::ExpressionError(Id, M.str());
  } break;
  case ASTTypeDefcal: {
    std::stringstream M;
    M << "An ASTFunctionCallExpressionNode cannot materialize "
      << "a Defcal call.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTFunctionCallNode::ExpressionError(Id, M.str());
  } break;
  default: {
    std::stringstream M;
    M << "Object '" << Id->GetName() << "' of type "
      << PrintTypeEnum(STE->GetValueType()) << " is not callable.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTFunctionCallNode::ExpressionError(Id, M.str());
  } break;
  }

  if (!FCN) {
    std::stringstream M;
    M << "Could not create a valid ASTFunctionCallExpressionNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTFunctionCallNode::ExpressionError(Id, M.str());
  }

  FCN->SetLocation(TK->GetLocation());
  FCN->Mangle();
  return FCN;
}

ASTFunctionCallStatementNode *
ASTProductionFactory::ProductionRule_2700(const ASTToken *TK,
                                          const ASTFunctionCallNode *FC) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(FC && "Invalid ASTFunctionCallNode argument!");

  ASTFunctionCallStatementNode *FCS = new ASTFunctionCallStatementNode(FC);
  if (!FCS) {
    std::stringstream M;
    M << "Could not create a valid ASTFunctionCallStatementNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTFunctionCallStatementNode::StatementError(FC->GetIdentifier(),
                                                        M.str());
  }

  FCS->SetLocation(TK->GetLocation());
  FCS->Mangle();
  return FCS;
}

ASTIfStatementNode *ASTProductionFactory::ProductionRule_3000(
    const ASTToken *TK, ASTExpressionNode *EN, ASTStatementNode *SN) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(EN && "Invalid ASTExpressionNode argument!");
  assert(SN && "Invalid ASTStatementNode argument!");

  QasmFeatureTester::Instance().ValidateFeature("if");
  ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  switch (SN->GetASTType()) {
  case ASTTypeElseIfStatement:
  case ASTTypeElseStatement: {
    std::stringstream M;
    M << "Expression expected before " << PrintTypeEnum(SN->GetASTType())
      << '.';
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(SN), M.str(), DiagLevel::Error);
    return ASTIfStatementNode::StatementError(M.str());
  } break;
  default:
    break;
  }

  CTX->SetContextType(ASTTypeIfStatement);

  const ASTDeclarationContext *PCTX = CTX->GetParentContext();
  assert(PCTX && "Could not obtain a valid ASTDeclarationContext!");

  ASTStatementList *SL = ASTIfStatementBuilder::Instance().NewList();
  assert(SL && "Could not create a valid ASTStatementList!");

  SL->SetLocation(SN->GetLocation());
  EN->SetDeclarationContext(CTX);
  SN->SetDeclarationContext(CTX);
  SL->SetDeclarationContext(CTX);
  ASTScopeController::Instance().SetDeclarationContext(SL, CTX);
  SL->SetLocalScope();
  SL->Append(SN);

  ASTIfStatementNode *ISN = new ASTIfStatementNode(EN, SL);
  assert(ISN && "Failed to create the ASTIfStatementNode!");

  ISN->SetLocation(TK->GetLocation());
  ISN->SetDeclarationContext(CTX->GetParentContext());
  unsigned ISC = ASTIfStatementBuilder::Instance().GetLastISC();
  assert(ISC != static_cast<unsigned>(~0x0) && "Invalid ISC!");

  ISN->SetISC(ISC);

  const ASTToken *ITK = ASTIfStatementBuilder::Instance().GetToken(ISC);
  assert(ITK && "Could not obtain a valid IfStatementNode ASTToken!");

  if (ASTIfStatementTracker::Instance().HasPendingElseIf()) {
    ISN->SetPendingElseIf(true);
    ASTIfStatementTracker::Instance().SetPendingElseIf(false);
  }

  if (ASTIfStatementTracker::Instance().HasPendingElse()) {
    ISN->SetPendingElse(true);
    ASTIfStatementTracker::Instance().SetPendingElse(false);
  }

  ISN->SetBraces(false);
  ASTIfStatementNode *CIF = ASTIfStatementTracker::Instance().GetCurrentIf();

  switch (PCTX->GetContextType()) {
  case ASTTypeGlobal:
  case ASTTypeFunction:
  case ASTTypeForLoop:
  case ASTTypeWhileLoop:
  case ASTTypeDoWhileLoop:
  case ASTTypeCaseStatement:
  case ASTTypeDefaultStatement:
  case ASTTypeGate:
  case ASTTypeCXGate:
  case ASTTypeCCXGate:
  case ASTTypeCNotGate:
  case ASTTypeHadamardGate:
  case ASTTypeUGate:
  case ASTTypeDefcal:
  case ASTTypeKernel:
  case ASTTypeExtern:
    ISN->SetParentIf(nullptr);
    break;
  default:
    ISN->SetParentIf(CIF);
    break;
  }

  SL->TransferDeclarations(ISN->GetSymbolTable());
  SL->TransferStatements(ISN->GetSymbolTable());
  ASTSymbolTable::Instance().TransferLocalContextSymbols(CTX,
                                                         ISN->GetSymbolTable());

  ASTIfStatementTracker::Instance().Push(ISN);
  ASTElseIfStatementTracker::Instance().SetCurrentIf(ISN);
  ASTElseStatementTracker::Instance().SetCurrentIf(ISN);

  switch (SN->GetASTType()) {
  case ASTTypeIfStatement: {
    if (ASTIfStatementNode *SISN = dynamic_cast<ASTIfStatementNode *>(SN)) {
      SISN->SetParentIf(ISN);
    } else {
      std::stringstream M;
      M << "Could not dynamic_cast to a valid IfStatementNode.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(SN), M.str(),
          DiagLevel::Error);
      return ASTIfStatementNode::StatementError(M.str());
    }
  } break;
  case ASTTypeElseStatement: {
    std::stringstream M;
    M << "Invalid IfNode Dominator for contained ElseNode (else without if).";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(SN), M.str(), DiagLevel::Error);
    return ASTIfStatementNode::StatementError(M.str());
  } break;
  default:
    break;
  }

  ASTElseIfStatementTracker::Instance().ClearCurrentElseIf();

  uint32_t TIX = ASTTokenFactory::GetCurrentIndex();
  const ASTToken *CTK = ASTTokenFactory::GetToken(TIX - 1U);
  assert(CTK && "Could not obtain a valid ASTToken!");

  ASTIfStatementBuilder::Instance().Pop(ISC, ITK, false);
  ASTDeclarationContextTracker::Instance().PopCurrentContext();
  return ISN;
}

ASTIfStatementNode *ASTProductionFactory::ProductionRule_3001(
    const ASTToken *TK, ASTExpressionNode *EN, ASTStatementList *SL,
    bool HasBraces) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(EN && "Invalid ASTExpressionNode argument!");
  assert(SL && "Invalid ASTStatementList argument!");

  QasmFeatureTester::Instance().ValidateFeature("if");
  ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  const ASTDeclarationContext *PCTX = CTX->GetParentContext();
  assert(PCTX && "Could not obtain a valid ASTDeclarationContext!");

  CTX->SetContextType(ASTTypeIfStatement);

  if (!HasBraces && SL->Size() > 1) {
    std::stringstream M;
    M << "An If Conditional without braces can only contain one Statement.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(SL), M.str(), DiagLevel::Error);
    return ASTIfStatementNode::StatementError(M.str());
  }

  const ASTIfStatementNode *TISN = nullptr;
  const ASTElseIfStatementNode *TEISN = nullptr;
  const ASTElseStatementNode *TESN = nullptr;
  const std::vector<ASTElseIfStatementNode *> *TEIV = nullptr;
  uint32_t EIC = 0U;

  for (ASTStatementList::iterator LI = SL->begin(); LI != SL->end(); ++LI) {
    switch ((*LI)->GetASTType()) {
    case ASTTypeIfStatement: {
      if (ASTIfStatementNode *ISN = dynamic_cast<ASTIfStatementNode *>(*LI)) {
        TISN = ISN;
        TESN = ISN->HasElse() ? ISN->GetElse() : nullptr;
        TEIV = ISN->HasElseIf() ? ISN->GetElseIfPointer() : nullptr;
        EIC = 0U;
      } else {
        std::stringstream M;
        M << "Could not dynamic_cast to an ASTIfStatementNode." << std::endl;
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(*LI), M.str(),
            DiagLevel::ICE);
        return ASTIfStatementNode::StatementError(M.str());
      }
    } break;
    case ASTTypeElseIfStatement: {
      if (ASTElseIfStatementNode *EISN =
              dynamic_cast<ASTElseIfStatementNode *>(*LI)) {
        if (!TISN->HasElseIf()) {
          std::stringstream M;
          M << "Invalid IfNode Dominator for the current ElseIfNode "
            << "(else-if without if).";
          QasmDiagnosticEmitter::Instance().EmitDiagnostic(
              DIAGLineCounter::Instance().GetLocation(EISN), M.str(),
              DiagLevel::Error);
          return ASTIfStatementNode::StatementError(M.str());
        }

        TEIV = TISN->GetElseIfPointer();
        if (!TEIV) {
          std::stringstream M;
          M << "Invalid ElseIfStatement vector for an IfStatement that should "
            << "have one.";
          QasmDiagnosticEmitter::Instance().EmitDiagnostic(
              DIAGLineCounter::Instance().GetLocation(EISN), M.str(),
              DiagLevel::Error);
          return ASTIfStatementNode::StatementError(M.str());
        }

        if (EIC >= TEIV->size()) {
          std::stringstream M;
          M << "ElseIfStatement index " << EIC << " is attempting an out-of-"
            << "bounds access.";
          QasmDiagnosticEmitter::Instance().EmitDiagnostic(
              DIAGLineCounter::Instance().GetLocation(EISN), M.str(),
              DiagLevel::ICE);
          return ASTIfStatementNode::StatementError(M.str());
        }

        try {
          TEISN = TEIV->at(EIC);
        } catch (const std::out_of_range &E) {
          std::stringstream M;
          M << "ElseIfStatement " << EIC
            << " caught an out-of-bounds access: " << E.what() << '.';
          QasmDiagnosticEmitter::Instance().EmitDiagnostic(
              DIAGLineCounter::Instance().GetLocation(EISN), M.str(),
              DiagLevel::ICE);
          return ASTIfStatementNode::StatementError(M.str());
        } catch (...) {
          std::stringstream M;
          M << "ElseIfStatement " << EIC << " access caught an exception.";
          QasmDiagnosticEmitter::Instance().EmitDiagnostic(
              DIAGLineCounter::Instance().GetLocation(EISN), M.str(),
              DiagLevel::ICE);
          return ASTIfStatementNode::StatementError(M.str());
        }

        if (TEISN != EISN || TISN != EISN->GetIfStatement()) {
          std::stringstream M;
          M << "Invalid IfNode Dominator for the current ElseIfNode "
            << "(else-if without if).";
          QasmDiagnosticEmitter::Instance().EmitDiagnostic(
              DIAGLineCounter::Instance().GetLocation(EISN), M.str(),
              DiagLevel::Error);
          return ASTIfStatementNode::StatementError(M.str());
        }

        ++EIC;
      } else {
        std::stringstream M;
        M << "Could not dynamic_cast to an ASTElseIfStatementNode."
          << std::endl;
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(*LI), M.str(),
            DiagLevel::ICE);
        return ASTIfStatementNode::StatementError(M.str());
      }
    } break;
    case ASTTypeElseStatement: {
      if (ASTElseStatementNode *ESN =
              dynamic_cast<ASTElseStatementNode *>(*LI)) {
        if (TESN != ESN || ESN->GetIfStatement() != TISN) {
          std::stringstream M;
          M << "Invalid IfNode Dominator for the current ElseNode (else "
               "without if).";
          QasmDiagnosticEmitter::Instance().EmitDiagnostic(
              DIAGLineCounter::Instance().GetLocation(ESN), M.str(),
              DiagLevel::Error);
          return ASTIfStatementNode::StatementError(M.str());
        }

        TISN = nullptr;
        TEISN = nullptr;
        TESN = nullptr;
        TEIV = nullptr;
        EIC = 0U;
      } else {
        std::stringstream M;
        M << "Could not dynamic_cast to an ASTElseStatementNode.";
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(*LI), M.str(),
            DiagLevel::ICE);
        return ASTIfStatementNode::StatementError(M.str());
      }
    } break;
    default:
      break;
    }
  }

  EN->SetDeclarationContext(CTX);
  SL->SetDeclarationContext(CTX);
  ASTScopeController::Instance().SetDeclarationContext(SL, CTX);
  SL->SetLocalScope();
  ASTArgumentNodeBuilder::Instance().Clear();

  ASTIfStatementNode *ISN = new ASTIfStatementNode(EN, SL);
  assert(ISN && "Failed to create the ASTIfStatementNode!");

  ISN->SetLocation(TK->GetLocation());
  ISN->SetDeclarationContext(CTX->GetParentContext());

  unsigned ISC = ASTIfStatementBuilder::Instance().GetLastISC();
  assert(ISC != static_cast<unsigned>(~0x0) && "Invalid ISC!");

  ISN->SetISC(ISC);

  if (ASTIfStatementTracker::Instance().HasPendingElseIf()) {
    ISN->SetPendingElseIf(true);
    ASTIfStatementTracker::Instance().SetPendingElseIf(false);
  }

  if (ASTIfStatementTracker::Instance().HasPendingElse()) {
    ISN->SetPendingElse(true);
    ASTIfStatementTracker::Instance().SetPendingElse(false);
  }

  ISN->SetBraces(HasBraces);
  ASTIfStatementNode *CIF = ASTIfStatementTracker::Instance().GetCurrentIf();

  switch (PCTX->GetContextType()) {
  case ASTTypeGlobal:
  case ASTTypeFunction:
  case ASTTypeForLoop:
  case ASTTypeWhileLoop:
  case ASTTypeDoWhileLoop:
  case ASTTypeCaseStatement:
  case ASTTypeDefaultStatement:
  case ASTTypeGate:
  case ASTTypeCXGate:
  case ASTTypeCCXGate:
  case ASTTypeCNotGate:
  case ASTTypeHadamardGate:
  case ASTTypeUGate:
  case ASTTypeDefcal:
  case ASTTypeKernel:
  case ASTTypeExtern:
    ISN->SetParentIf(nullptr);
    break;
  default:
    ISN->SetParentIf(CIF);
    break;
  }

  SL->TransferDeclarations(ISN->GetSymbolTable());
  SL->TransferStatements(ISN->GetSymbolTable());
  ASTSymbolTable::Instance().TransferLocalContextSymbols(CTX,
                                                         ISN->GetSymbolTable());

  ASTIfStatementTracker::Instance().Push(ISN);
  ASTElseIfStatementTracker::Instance().SetCurrentIf(ISN);
  ASTElseStatementTracker::Instance().SetCurrentIf(ISN);

  ASTIfStatementNode *IFN = nullptr;
  ASTElseStatementNode *ELN = nullptr;

  for (ASTStatementList::iterator LI = SL->begin(); LI != SL->end(); ++LI) {
    switch ((*LI)->GetASTType()) {
    case ASTTypeIfStatement: {
      if ((IFN = dynamic_cast<ASTIfStatementNode *>(*LI))) {
        IFN->SetParentIf(ISN);
      } else {
        std::stringstream M;
        M << "Could not dynamic_cast to a valid IfStatementNode.";
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(*LI), M.str(),
            DiagLevel::Error);
        return ASTIfStatementNode::StatementError(M.str());
      }
    } break;
    case ASTTypeElseStatement: {
      if ((ELN = dynamic_cast<ASTElseStatementNode *>(*LI))) {
        if (!IFN) {
          std::stringstream M;
          M << "Invalid IfNode Dominator for the current ElseNode "
            << "(else without if).";
          QasmDiagnosticEmitter::Instance().EmitDiagnostic(
              DIAGLineCounter::Instance().GetLocation(*LI), M.str(),
              DiagLevel::Error);
          return ASTIfStatementNode::StatementError(M.str());
        }

        if (ELN->GetIfStatement())
          continue;
        else
          ELN->AttachTo(IFN);
      } else {
        std::stringstream M;
        M << "Could not dynamic_cast to a valid ASTElseStatementNode.";
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(*LI), M.str(),
            DiagLevel::Error);
        return ASTIfStatementNode::StatementError(M.str());
      }
    } break;
    default:
      break;
    }
  }

  std::map<ASTIfStatementNode *, ASTElseStatementNode *> MIE;
  std::set<ASTElseStatementNode *> SEL;

  for (ASTStatementList::iterator LI = SL->begin(); LI != SL->end(); ++LI) {
    switch ((*LI)->GetASTType()) {
    case ASTTypeIfStatement: {
      if (ASTIfStatementNode *SIF = dynamic_cast<ASTIfStatementNode *>(*LI)) {
        if (!MIE.insert(std::make_pair(SIF, SIF->GetElse())).second) {
          std::stringstream M;
          M << "Failure inserting an IfStatementNode in the control map.";
          QasmDiagnosticEmitter::Instance().EmitDiagnostic(
              DIAGLineCounter::Instance().GetLocation(*LI), M.str(),
              DiagLevel::Error);
          return ASTIfStatementNode::StatementError(M.str());
        }
      }
    } break;
    case ASTTypeElseStatement: {
      if (ASTElseStatementNode *SEN =
              dynamic_cast<ASTElseStatementNode *>(*LI)) {
        if (!(SEL.insert(SEN)).second) {
          std::stringstream M;
          M << "Failure inserting an ElseStatementNode in the control set.";
          QasmDiagnosticEmitter::Instance().EmitDiagnostic(
              DIAGLineCounter::Instance().GetLocation(*LI), M.str(),
              DiagLevel::Error);
          return ASTIfStatementNode::StatementError(M.str());
        }
      }
    } break;
    default:
      break;
    }
  }

  for (std::map<ASTIfStatementNode *, ASTElseStatementNode *>::const_iterator
           MI = MIE.begin();
       MI != MIE.end(); ++MI) {
    std::set<ASTElseStatementNode *>::const_iterator SI =
        SEL.find((*MI).second);
    if (!(*MI).first->HasElse())
      continue;

    if (SI == SEL.end()) {
      std::stringstream M;
      M << "IfStatementNode branches to a non-existent ElseStatementNode.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation((*MI).first), M.str(),
          DiagLevel::Error);
      return ASTIfStatementNode::StatementError(M.str());
    }

    if ((*SI)->GetIfStatement() != (*MI).first) {
      std::stringstream M;
      M << "Inconsistent ElseStatementNode <-> IfStatementNode graph edge.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation((*MI).first), M.str(),
          DiagLevel::Error);
      return ASTIfStatementNode::StatementError(M.str());
    }

    if ((*MI).second != *SI) {
      std::stringstream M;
      M << "Inconsistent IfStatementNode <-> ElseStatementNode graph edge.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation((*MI).first), M.str(),
          DiagLevel::Error);
      return ASTIfStatementNode::StatementError(M.str());
    }
  }

  ASTElseIfStatementTracker::Instance().ClearCurrentElseIf();
  ASTDeclarationContextTracker::Instance().PopCurrentContext();
  return ISN;
}

ASTElseIfStatementNode *ASTProductionFactory::ProductionRule_3010(
    const ASTToken *TK, ASTExpressionNode *EN, ASTStatementNode *SN) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(EN && "Invalid ASTExpressionNode argument!");
  assert(SN && "Invalid ASTStatementNode argument!");

  QasmFeatureTester::Instance().ValidateFeature("else if");
  ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  switch (SN->GetASTType()) {
  case ASTTypeElseIfStatement:
  case ASTTypeElseStatement: {
    std::stringstream M;
    M << "Expression expected before " << PrintTypeEnum(SN->GetASTType())
      << '.';
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(SN), M.str(), DiagLevel::Error);
    return ASTElseIfStatementNode::StatementError(M.str());
  } break;
  default:
    break;
  }

  CTX->SetContextType(ASTTypeElseIfStatement);
  ASTArgumentNodeBuilder::Instance().Clear();
  ASTIfStatementNode *CIF = ASTIfStatementTracker::Instance().GetCurrentIf();

  if (!CIF) {
    std::stringstream M;
    M << "Invalid IfNode Dominator for the current ElseIfNode "
      << "(else-if without if).";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTElseIfStatementNode::StatementError(M.str());
  } else if (CIF->GetDeclarationContext() == CTX) {
    std::stringstream M;
    M << "Invalid IfNode Dominator for the current ElseIfNode "
      << "(else-if without if).";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTElseIfStatementNode::StatementError(M.str());
  }

  ASTStatementList *SL = ASTElseIfStatementBuilder::Instance().NewList();
  assert(SL && "Could not create a valid ASTStatementList!");

  SL->SetLocation(SN->GetLocation());
  EN->SetDeclarationContext(CTX);
  SN->SetDeclarationContext(CTX);
  SL->SetDeclarationContext(CTX);
  SL->Append(SN);
  ASTScopeController::Instance().SetDeclarationContext(SL, CTX);
  SL->SetLocalScope();

  ASTElseIfStatementNode *EIN = new ASTElseIfStatementNode(CIF, EN, SL);
  assert(EIN && "Failed to create a valid ASTElseIfStatementNode!");

  EIN->SetLocation(TK->GetLocation());
  EIN->SetDeclarationContext(CTX->GetParentContext());
  SL->TransferDeclarations(EIN->GetSymbolTable());
  SL->TransferStatements(EIN->GetSymbolTable());
  ASTSymbolTable::Instance().TransferLocalContextSymbols(CTX,
                                                         EIN->GetSymbolTable());

  if (const ASTElseIfStatementNode *CEIN =
          ASTElseIfStatementTracker::Instance().GetCurrentElseIf()) {
    const_cast<ASTElseIfStatementNode *>(CEIN)->SetNextElseIf(EIN);
  }

  ASTElseIfStatementTracker::Instance().SetCurrentElseIf(EIN);
  assert(CIF->GetISC() == EIN->GetISC() &&
         "Inconsistent ASTIfStatementNode <-> ASTElseStatementNode!");
  assert(CIF->GetStackFrame() == EIN->GetStackFrame() &&
         "Inconsistent ASTIfStatementNode <-> "
         "ASTElseStatementNode! StackFrame!");

  if (ASTElseIfStatementTracker::Instance().HasPendingElse()) {
    ASTElseIfStatementTracker::Instance().Pop(CIF);
    ASTElseStatementTracker::Instance().SetCurrentIf(CIF);
  }

  ASTDeclarationContextTracker::Instance().PopCurrentContext();
  return EIN;
}

ASTElseIfStatementNode *ASTProductionFactory::ProductionRule_3011(
    const ASTToken *TK, ASTExpressionNode *EN, ASTStatementList *SL,
    bool HasBraces) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(EN && "Invalid ASTExpressionNode argument!");
  assert(SL && "Invalid ASTStatementList argument!");

  QasmFeatureTester::Instance().ValidateFeature("else if");
  ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  if (!HasBraces && SL->Size() > 1) {
    std::stringstream M;
    M << "An ElseIf Conditional without braces can only contain one Statement.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(SL), M.str(), DiagLevel::Error);
    return ASTElseIfStatementNode::StatementError(M.str());
  }

  CTX->SetContextType(ASTTypeElseIfStatement);

  const ASTIfStatementNode *TISN = nullptr;
  const ASTElseIfStatementNode *TEISN = nullptr;
  const ASTElseStatementNode *TESN = nullptr;
  const std::vector<ASTElseIfStatementNode *> *TEIV = nullptr;
  uint32_t EIC = 0U;

  for (ASTStatementList::iterator LI = SL->begin(); LI != SL->end(); ++LI) {
    switch ((*LI)->GetASTType()) {
    case ASTTypeIfStatement: {
      if (ASTIfStatementNode *ISN = dynamic_cast<ASTIfStatementNode *>(*LI)) {
        TISN = ISN;
        TESN = ISN->HasElse() ? ISN->GetElse() : nullptr;
        TEIV = ISN->HasElseIf() ? ISN->GetElseIfPointer() : nullptr;
        EIC = 0U;
      } else {
        std::stringstream M;
        M << "Could not dynamic_cast to an ASTIfStatementNode." << std::endl;
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(*LI), M.str(),
            DiagLevel::ICE);
        return ASTElseIfStatementNode::StatementError(M.str());
      }
    } break;
    case ASTTypeElseIfStatement: {
      if (ASTElseIfStatementNode *EISN =
              dynamic_cast<ASTElseIfStatementNode *>(*LI)) {
        if (!TISN->HasElseIf()) {
          std::stringstream M;
          M << "Invalid IfNode Dominator for the current ElseIfNode "
            << "(else-if without if).";
          QasmDiagnosticEmitter::Instance().EmitDiagnostic(
              DIAGLineCounter::Instance().GetLocation(EISN), M.str(),
              DiagLevel::Error);
          return ASTElseIfStatementNode::StatementError(M.str());
        }

        TEIV = TISN->GetElseIfPointer();
        if (!TEIV) {
          std::stringstream M;
          M << "Invalid ElseIfStatement vector for an IfStatement that should "
            << "have one.";
          QasmDiagnosticEmitter::Instance().EmitDiagnostic(
              DIAGLineCounter::Instance().GetLocation(EISN), M.str(),
              DiagLevel::Error);
          return ASTElseIfStatementNode::StatementError(M.str());
        }

        if (EIC >= TEIV->size()) {
          std::stringstream M;
          M << "ElseIfStatement index " << EIC << " is attempting an out-of-"
            << "bounds access.";
          QasmDiagnosticEmitter::Instance().EmitDiagnostic(
              DIAGLineCounter::Instance().GetLocation(EISN), M.str(),
              DiagLevel::ICE);
          return ASTElseIfStatementNode::StatementError(M.str());
        }

        try {
          TEISN = TEIV->at(EIC);
        } catch (const std::out_of_range &E) {
          std::stringstream M;
          M << "ElseIfStatement " << EIC
            << " caught an out-of-bounds access: " << E.what() << '.';
          QasmDiagnosticEmitter::Instance().EmitDiagnostic(
              DIAGLineCounter::Instance().GetLocation(EISN), M.str(),
              DiagLevel::ICE);
          return ASTElseIfStatementNode::StatementError(M.str());
        } catch (...) {
          std::stringstream M;
          M << "ElseIfStatement " << EIC << " access caught an exception.";
          QasmDiagnosticEmitter::Instance().EmitDiagnostic(
              DIAGLineCounter::Instance().GetLocation(EISN), M.str(),
              DiagLevel::ICE);
          return ASTElseIfStatementNode::StatementError(M.str());
        }

        if (TEISN != EISN || TISN != EISN->GetIfStatement()) {
          std::stringstream M;
          M << "Invalid IfNode Dominator for the current ElseIfNode "
            << "(else-if without if).";
          QasmDiagnosticEmitter::Instance().EmitDiagnostic(
              DIAGLineCounter::Instance().GetLocation(EISN), M.str(),
              DiagLevel::Error);
          return ASTElseIfStatementNode::StatementError(M.str());
        }

        ++EIC;
      } else {
        std::stringstream M;
        M << "Could not dynamic_cast to an ASTElseIfStatementNode."
          << std::endl;
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(*LI), M.str(),
            DiagLevel::ICE);
        return ASTElseIfStatementNode::StatementError(M.str());
      }
    } break;
    case ASTTypeElseStatement: {
      if (ASTElseStatementNode *ESN =
              dynamic_cast<ASTElseStatementNode *>(*LI)) {
        if (TESN != ESN || ESN->GetIfStatement() != TISN) {
          std::stringstream M;
          M << "Invalid IfNode Dominator for the current ElseNode (else "
               "without if).";
          QasmDiagnosticEmitter::Instance().EmitDiagnostic(
              DIAGLineCounter::Instance().GetLocation(ESN), M.str(),
              DiagLevel::Error);
          return ASTElseIfStatementNode::StatementError(M.str());
        }

        TISN = nullptr;
        TEISN = nullptr;
        TESN = nullptr;
        TEIV = nullptr;
        EIC = 0U;
      } else {
        std::stringstream M;
        M << "Could not dynamic_cast to an ASTElseStatementNode.";
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(*LI), M.str(),
            DiagLevel::ICE);
        return ASTElseIfStatementNode::StatementError(M.str());
      }
    } break;
    default:
      break;
    }
  }

  ASTArgumentNodeBuilder::Instance().Clear();
  ASTIfStatementNode *CIF = ASTIfStatementTracker::Instance().GetCurrentIf();
  ASTIfStatementNode *SCIF = nullptr;

  if (!CIF) {
    std::stringstream M;
    M << "Invalid IfNode Dominator for the current ElseIfNode "
      << "(else-if without if).";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTElseIfStatementNode::StatementError(M.str());
  } else {
    if (!CIF->HasPendingElseIf() && !CIF->HasPendingElse()) {
      SCIF = CIF->GetParentIf();

      while (SCIF && !SCIF->HasPendingElseIf() && !SCIF->HasPendingElse()) {
        ASTElseIfStatementTracker::Instance().Pop(SCIF);
        ASTElseStatementTracker::Instance().Pop(SCIF);
        SCIF = SCIF->GetParentIf();
      }
    }

    if (CIF->GetDeclarationContext() == CTX) {
      if (!CIF) {
        std::stringstream M;
        M << "Invalid IfNode Dominator for the current ElseIfNode "
          << "(else-if without if).";
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(TK), M.str(),
            DiagLevel::Error);
        return ASTElseIfStatementNode::StatementError(M.str());
      }

      ASTElseIfStatementTracker::Instance().SetCurrentIf(CIF);
      ASTElseStatementTracker::Instance().SetCurrentIf(CIF);
    }
  }

  EN->SetDeclarationContext(CTX);
  SL->SetDeclarationContext(CTX);
  ASTScopeController::Instance().SetDeclarationContext(SL, CTX);
  SL->SetLocalScope();

  ASTElseIfStatementNode *EIN = new ASTElseIfStatementNode(CIF, EN, SL);
  assert(EIN && "Failed to create a valid ASTElseIfStatementNode!");

  EIN->SetDeclarationContext(CTX->GetParentContext());
  EIN->SetLocation(TK->GetLocation());
  SL->TransferDeclarations(EIN->GetSymbolTable());
  SL->TransferStatements(EIN->GetSymbolTable());
  ASTSymbolTable::Instance().TransferLocalContextSymbols(CTX,
                                                         EIN->GetSymbolTable());

  CIF->NormalizeElseIf();
  EIN->SetPendingElseIf(CIF->HasPendingElseIf());
  EIN->SetPendingElse(CIF->HasPendingElse());

  if (const ASTElseIfStatementNode *CEIN =
          ASTElseIfStatementTracker::Instance().GetCurrentElseIf()) {
    if (CEIN->GetIfStatement() == CIF)
      const_cast<ASTElseIfStatementNode *>(CEIN)->SetNextElseIf(EIN);
  }

  ASTElseIfStatementTracker::Instance().SetCurrentElseIf(EIN);
  assert(CIF->GetISC() == EIN->GetISC() &&
         "Inconsistent ASTIfStatementNode <-> ASTElseStatementNode ISC!");
  assert(CIF->GetStackFrame() == EIN->GetStackFrame() &&
         "Inconsistent ASTIfStatementNode <-> "
         "ASTElseStatementNode! StackFrame!");

  if (ASTElseIfStatementTracker::Instance().HasPendingElse())
    ASTElseStatementTracker::Instance().SetCurrentIf(CIF);

  if (SCIF) {
    EIN->SetPendingElseIf(false);
    EIN->SetPendingElse(false);
    EIN->SetNextElseIf(nullptr);

    ASTIfStatementTracker::Instance().SetPendingElseIf(false);
    ASTIfStatementTracker::Instance().SetPendingElse(false);
    ASTIfStatementTracker::Instance().SetCurrentIf(SCIF);

    ASTElseIfStatementTracker::Instance().SetPendingElseIf(false);
    ASTElseIfStatementTracker::Instance().SetPendingElse(false);
    ASTElseIfStatementTracker::Instance().SetCurrentIf(SCIF);

    ASTElseStatementTracker::Instance().SetCurrentIf(SCIF);
  }

  ASTDeclarationContextTracker::Instance().PopCurrentContext();
  return EIN;
}

ASTElseStatementNode *
ASTProductionFactory::ProductionRule_3020(const ASTToken *TK,
                                          ASTStatementNode *SN) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(SN && "Invalid ASTStatementNode argument!");

  QasmFeatureTester::Instance().ValidateFeature("else");
  ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  switch (SN->GetASTType()) {
  case ASTTypeElseIfStatement:
  case ASTTypeElseStatement: {
    std::stringstream M;
    M << "Expression expected before " << PrintTypeEnum(SN->GetASTType())
      << '.';
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(SN), M.str(), DiagLevel::Error);
    return ASTElseStatementNode::StatementError(M.str());
  } break;
  default:
    break;
  }

  CTX->SetContextType(ASTTypeElseStatement);

  ASTArgumentNodeBuilder::Instance().Clear();
  ASTIfStatementNode *CIF = ASTElseStatementTracker::Instance().GetCurrentIf();

  if (!CIF) {
    std::stringstream M;
    M << "Invalid IfNode Dominator for the current ElseNode (else without if).";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTElseStatementNode::StatementError(M.str());
  } else if (CIF->GetDeclarationContext() == CTX) {
    std::stringstream M;
    M << "Invalid IfNode Dominator for the current ElseNode (else without if).";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTElseStatementNode::StatementError(M.str());
  }

  if (SN->GetASTType() == ASTTypeIfStatement) {
    ASTIfStatementNode *SCIF = dynamic_cast<ASTIfStatementNode *>(SN);
    assert(SCIF && "Could not dynamic_cast to a valid ASTIfStatementNode!");

    if (CIF == SCIF) {
      CIF = CIF->GetParentIf();
      assert(CIF && "Invalid parent ASTIfStatementNode!");

      SCIF->SetParentIf(CIF);
    }
  }

  ASTStatementList *SL = ASTElseStatementBuilder::Instance().NewList();
  assert(SL && "Could not create a valid ASTStatementList!");

  SL->SetLocation(SN->GetLocation());
  SL->SetDeclarationContext(CTX);
  ASTScopeController::Instance().SetDeclarationContext(SL, CTX);
  SL->SetLocalScope();
  SL->Append(SN);

  const ASTDeclarationContext *ICTX = CIF->GetDeclarationContext();
  assert(ICTX && "Could not obtain a valid ASTDeclarationContext!");

  ASTElseStatementNode *ESN = new ASTElseStatementNode(CIF, SL);
  assert(ESN && "Failed to create the ElseNode from the IfNode Dominator!");
  assert(CIF->GetISC() == ESN->GetISC() &&
         "Inconsistent ASTIfStatementNode <-> ASTElseStatementNode ISC!");
  assert(CIF->GetStackFrame() == ESN->GetStackFrame() &&
         "Inconsistent ASTIfStatementNode <-> "
         "ASTElseStatementNode! StackFrame!");

  ESN->SetLocation(TK->GetLocation());
  ESN->SetDeclarationContext(CTX->GetParentContext());

  SL->TransferDeclarations(ESN->GetSymbolTable());
  SL->TransferStatements(ESN->GetSymbolTable());
  ASTSymbolTable::Instance().TransferLocalContextSymbols(CTX,
                                                         ESN->GetSymbolTable());

  ASTIfStatementTracker::Instance().Pop(CIF);
  ASTElseIfStatementTracker::Instance().Pop(CIF);
  ASTElseStatementTracker::Instance().Pop(CIF);
  ASTDeclarationContextTracker::Instance().PopCurrentContext();
  return ESN;
}

ASTElseStatementNode *ASTProductionFactory::ProductionRule_3021(
    const ASTToken *TK, ASTStatementList *SL, bool HasBraces) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(SL && "Invalid ASTStatementList argument!");

  QasmFeatureTester::Instance().ValidateFeature("else");
  ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  if (!HasBraces && SL->Size() > 1) {
    std::stringstream M;
    M << "An Else clause without braces may only contain one Statement.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(SL), M.str(), DiagLevel::Error);
    return ASTElseStatementNode::StatementError(M.str());
  }

  CTX->SetContextType(ASTTypeElseStatement);

  const ASTIfStatementNode *TISN = nullptr;
  const ASTElseIfStatementNode *TEISN = nullptr;
  const ASTElseStatementNode *TESN = nullptr;
  const std::vector<ASTElseIfStatementNode *> *TEIV = nullptr;
  uint32_t EIC = 0U;

  for (ASTStatementList::iterator LI = SL->begin(); LI != SL->end(); ++LI) {
    switch ((*LI)->GetASTType()) {
    case ASTTypeIfStatement: {
      if (ASTIfStatementNode *ISN = dynamic_cast<ASTIfStatementNode *>(*LI)) {
        TISN = ISN;
        TESN = ISN->HasElse() ? ISN->GetElse() : nullptr;
        TEIV = ISN->HasElseIf() ? ISN->GetElseIfPointer() : nullptr;
        EIC = 0U;
      } else {
        std::stringstream M;
        M << "Could not dynamic_cast to an ASTIfStatementNode." << std::endl;
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(*LI), M.str(),
            DiagLevel::ICE);
        return ASTElseStatementNode::StatementError(M.str());
      }
    } break;
    case ASTTypeElseIfStatement: {
      if (ASTElseIfStatementNode *EISN =
              dynamic_cast<ASTElseIfStatementNode *>(*LI)) {
        if (!TISN->HasElseIf()) {
          std::stringstream M;
          M << "Invalid IfNode Dominator for the current ElseIfNode "
            << "(else-if without if).";
          QasmDiagnosticEmitter::Instance().EmitDiagnostic(
              DIAGLineCounter::Instance().GetLocation(EISN), M.str(),
              DiagLevel::Error);
          return ASTElseStatementNode::StatementError(M.str());
        }

        TEIV = TISN->GetElseIfPointer();
        if (!TEIV) {
          std::stringstream M;
          M << "Invalid ElseIfStatement vector for an IfStatement that should "
            << "have one.";
          QasmDiagnosticEmitter::Instance().EmitDiagnostic(
              DIAGLineCounter::Instance().GetLocation(EISN), M.str(),
              DiagLevel::Error);
          return ASTElseStatementNode::StatementError(M.str());
        }

        if (EIC >= TEIV->size()) {
          std::stringstream M;
          M << "ElseIfStatement index " << EIC << " is attempting an out-of-"
            << "bounds access.";
          QasmDiagnosticEmitter::Instance().EmitDiagnostic(
              DIAGLineCounter::Instance().GetLocation(EISN), M.str(),
              DiagLevel::ICE);
          return ASTElseStatementNode::StatementError(M.str());
        }

        try {
          TEISN = TEIV->at(EIC);
        } catch (const std::out_of_range &E) {
          std::stringstream M;
          M << "ElseIfStatement " << EIC
            << " caught an out-of-bounds access: " << E.what() << '.';
          QasmDiagnosticEmitter::Instance().EmitDiagnostic(
              DIAGLineCounter::Instance().GetLocation(EISN), M.str(),
              DiagLevel::ICE);
          return ASTElseStatementNode::StatementError(M.str());
        } catch (...) {
          std::stringstream M;
          M << "ElseIfStatement " << EIC << " access caught an exception.";
          QasmDiagnosticEmitter::Instance().EmitDiagnostic(
              DIAGLineCounter::Instance().GetLocation(EISN), M.str(),
              DiagLevel::ICE);
          return ASTElseStatementNode::StatementError(M.str());
        }

        if (TEISN != EISN || TISN != EISN->GetIfStatement()) {
          std::stringstream M;
          M << "Invalid IfNode Dominator for the current ElseIfNode "
            << "(else-if without if).";
          QasmDiagnosticEmitter::Instance().EmitDiagnostic(
              DIAGLineCounter::Instance().GetLocation(EISN), M.str(),
              DiagLevel::Error);
          return ASTElseStatementNode::StatementError(M.str());
        }

        ++EIC;
      } else {
        std::stringstream M;
        M << "Could not dynamic_cast to an ASTElseIfStatementNode."
          << std::endl;
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(*LI), M.str(),
            DiagLevel::ICE);
        return ASTElseStatementNode::StatementError(M.str());
      }
    } break;
    case ASTTypeElseStatement: {
      if (ASTElseStatementNode *ESN =
              dynamic_cast<ASTElseStatementNode *>(*LI)) {
        if (TESN != ESN || ESN->GetIfStatement() != TISN) {
          std::stringstream M;
          M << "Invalid IfNode Dominator for the current ElseNode (else "
               "without if).";
          QasmDiagnosticEmitter::Instance().EmitDiagnostic(
              DIAGLineCounter::Instance().GetLocation(ESN), M.str(),
              DiagLevel::Error);
          return ASTElseStatementNode::StatementError(M.str());
        }

        TISN = nullptr;
        TEISN = nullptr;
        TESN = nullptr;
        TEIV = nullptr;
        EIC = 0U;
      } else {
        std::stringstream M;
        M << "Could not dynamic_cast to an ASTElseStatementNode.";
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(*LI), M.str(),
            DiagLevel::ICE);
        return ASTElseStatementNode::StatementError(M.str());
      }
    } break;
    default:
      break;
    }
  }

  ASTArgumentNodeBuilder::Instance().Clear();
  ASTIfStatementNode *CIF = ASTIfStatementTracker::Instance().GetCurrentIf();
  ASTIfStatementNode *SCIF = nullptr;

  if (!CIF) {
    std::stringstream M;
    M << "Invalid IfNode Dominator for the current ElseNode (else without if).";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTElseStatementNode::StatementError(M.str());
  }

  unsigned CL = ASTIfBraceMatcher::Instance().GetLeft();
  unsigned CR = ASTIfBraceMatcher::Instance().GetRight();

  if (CL != CR) {
    if ((CL < CR) && (CL & 0x01) && CIF->HasElse() && CIF->GetParentIf())
      CIF = CIF->GetParentIf();
    else if ((CL < CR) && (CR & 0x01) && !CIF->HasElse() && CIF->GetParentIf())
      CIF = CIF->GetParentIf();
  } else {
    const ASTDeclarationContext *ICTX = CIF->GetDeclarationContext();
    assert(ICTX && "Could not obtain a valid ASTDeclarationContext!");

    if (!CIF->HasPendingElseIf() && !CIF->HasPendingElse()) {
      SCIF = CIF->GetParentIf();

      while (SCIF && !SCIF->HasPendingElseIf() && !SCIF->HasPendingElse()) {
        ASTElseIfStatementTracker::Instance().Pop(SCIF);
        ASTElseStatementTracker::Instance().Pop(SCIF);
        SCIF = SCIF->GetParentIf();
      }

      if (!SCIF) {
        std::stringstream M;
        M << "Invalid IfNode Dominator for the current ElseNode "
          << "(else without if).";
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(TK), M.str(),
            DiagLevel::Error);
        return ASTElseStatementNode::StatementError(M.str());
      }
    }
  }

  if (!CIF) {
    std::stringstream M;
    M << "Invalid IfNode Dominator for the current ElseNode (else without if).";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTElseStatementNode::StatementError(M.str());
  }

  SL->SetDeclarationContext(CTX);
  ASTScopeController::Instance().SetDeclarationContext(SL, CTX);
  SL->SetLocalScope();

  ASTElseStatementNode *ESN = new ASTElseStatementNode(CIF, SL);
  assert(ESN && "Failed to create the ElseNode for the IfNode Dominator!");
  assert(CIF->GetISC() == ESN->GetISC() &&
         "Inconsistent ASTIfStatementNode <-> ASTElseStatementNode ISC!");
  assert(CIF->GetStackFrame() == ESN->GetStackFrame() &&
         "Inconsistent ASTIfStatementNode <-> "
         "ASTElseStatementNode StackFrame!");

  ESN->SetLocation(TK->GetLocation());
  ESN->SetDeclarationContext(CTX->GetParentContext());
  SL->TransferDeclarations(ESN->GetSymbolTable());
  SL->TransferStatements(ESN->GetSymbolTable());
  ASTSymbolTable::Instance().TransferLocalContextSymbols(CTX,
                                                         ESN->GetSymbolTable());
  CIF->NormalizeElseIf();

  if (CIF->HasPendingElseIf())
    ASTElseIfStatementTracker::Instance().Pop();

  ASTElseStatementTracker::Instance().Pop();
  ASTElseIfStatementTracker::Instance().Pop(CIF);
  ASTElseStatementTracker::Instance().Pop(CIF);

  if (SCIF) {
    ASTIfStatementTracker::Instance().SetPendingElseIf(false);
    ASTIfStatementTracker::Instance().SetPendingElse(false);
    ASTIfStatementTracker::Instance().SetCurrentIf(SCIF);

    ASTElseIfStatementTracker::Instance().SetPendingElseIf(false);
    ASTElseIfStatementTracker::Instance().SetPendingElse(false);
    ASTElseIfStatementTracker::Instance().SetCurrentIf(SCIF);

    ASTElseStatementTracker::Instance().SetCurrentIf(SCIF);
  } else {
    SCIF = CIF->GetParentIf();

    while (SCIF && (!SCIF->HasPendingElseIf() && !SCIF->HasPendingElse()))
      SCIF = SCIF->GetParentIf();

    ASTIfStatementTracker::Instance().SetCurrentIf(SCIF);
    ASTElseIfStatementTracker::Instance().SetCurrentIf(SCIF);
    ASTElseStatementTracker::Instance().SetCurrentIf(SCIF);
  }

  CIF->SetPendingElseIf(false);
  ASTDeclarationContextTracker::Instance().PopCurrentContext();
  return ESN;
}

ASTCaseStatementNode *
ASTProductionFactory::ProductionRule_3110(const ASTToken *TK,
                                          ASTExpressionNode *EN,
                                          ASTStatementList *SL, bool SC) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(SL && "Invalid ASTStatementList argument!");
  assert(EN && "Invalid ASTExpressionNode argument!");

  QasmFeatureTester::Instance().ValidateFeature("case");

  int64_t CIX;
  bool CR = false;

  switch (EN->GetASTType()) {
  case ASTTypeInt: {
    if (ASTIntNode *IN = dynamic_cast<ASTIntNode *>(EN)) {
      CIX = IN->IsSigned() ? IN->GetSignedValue()
                           : static_cast<int64_t>(IN->GetUnsignedValue());
      CR = true;
    }
  } break;
  case ASTTypeMPInteger: {
    if (ASTMPIntegerNode *MPI = dynamic_cast<ASTMPIntegerNode *>(EN)) {
      CIX = MPI->IsSigned() ? MPI->ToSignedLong()
                            : static_cast<int64_t>(MPI->ToUnsignedLong());
      CR = true;
    }
  } break;
  default: {
    std::stringstream M;
    M << "Case label does not resolve to an integer constant.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTCaseStatementNode::StatementError(M.str(), -1LL);
  } break;
  }

  if (!CR) {
    std::stringstream M;
    M << "Case label does not resolve to an integer constant.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTCaseStatementNode::StatementError(M.str(), CIX);
  }

  const ASTDeclarationContext *CTX =
      SC ? ASTDeclarationContextTracker::Instance().CreateContext(
               ASTTypeCaseStatement)
         : ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  ASTCaseStatementNode *CSN =
      new ASTCaseStatementNode(CIX, static_cast<unsigned>(~0x0), SL, SC);
  assert(CSN && "Could not create a valid ASTCaseStatementNode!");

  CSN->SetDeclarationContext(CTX);
  CSN->SetLocation(TK->GetLocation());

  if (!SC) {
    if (!CSN->CheckDeclarations()) {
      std::stringstream M;
      M << "Validation failure for declarations at case statement scope.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(TK), M.str(),
          DiagLevel::Error);
      return ASTCaseStatementNode::StatementError(M.str(), CIX);
    }
  } else {
    std::map<std::string, const ASTSymbolTableEntry *> &STM =
        CSN->GetSymbolTable();
    SL->SetLocalScope();
    ASTScopeController::Instance().SetDeclarationContext(SL, CTX);
    ASTScopeController::Instance().SetLocalScope(SL);
    SL->TransferDeclarations(STM);
    SL->TransferStatements(STM);
    ASTSymbolTable::Instance().TransferLocalContextSymbols(CTX, STM);
  }

  ASTIfStatementTracker::Instance().CheckDeclarationContext(SL);
  ASTElseIfStatementTracker::Instance().CheckDeclarationContext(SL);
  ASTElseStatementTracker::Instance().CheckDeclarationContext(SL);

  if (SC)
    ASTDeclarationContextTracker::Instance().PopCurrentContext();

  return CSN;
}

ASTCaseStatementNode *ASTProductionFactory::ProductionRule_3111(
    const ASTToken *TK, ASTExpressionNode *EN, ASTStatementList *SL,
    ASTBreakStatementNode *BK, bool SC) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(EN && "Invalid ASTExpressionNode argument!");
  assert(SL && "Invalid ASTStatementList argument!");
  assert(BK && "Invalid ASTBreakStatementNode argument!");

  QasmFeatureTester::Instance().ValidateFeature("case");

  int64_t CIX;
  bool CR = false;

  switch (EN->GetASTType()) {
  case ASTTypeInt: {
    if (ASTIntNode *IN = dynamic_cast<ASTIntNode *>(EN)) {
      CIX = IN->IsSigned() ? IN->GetSignedValue()
                           : static_cast<int64_t>(IN->GetUnsignedValue());
      CR = true;
    }
  } break;
  case ASTTypeMPInteger: {
    if (ASTMPIntegerNode *MPI = dynamic_cast<ASTMPIntegerNode *>(EN)) {
      CIX = MPI->IsSigned() ? MPI->ToSignedLong()
                            : static_cast<int64_t>(MPI->ToUnsignedLong());
      CR = true;
    }
  } break;
  default: {
    std::stringstream M;
    M << "Case label does not resolve to an integer constant.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTCaseStatementNode::StatementError(M.str(), -1LL);
  } break;
  }

  if (!CR) {
    std::stringstream M;
    M << "Case label does not resolve to an integer constant.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTCaseStatementNode::StatementError(M.str(), CIX);
  }

  const ASTDeclarationContext *CTX =
      SC ? ASTDeclarationContextTracker::Instance().CreateContext(
               ASTTypeCaseStatement)
         : ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  ASTCaseStatementNode *CSN =
      new ASTCaseStatementNode(CIX, static_cast<unsigned>(~0x0), SL, BK, SC);
  assert(CSN && "Could not create a valid ASTCaseStatementNode!");

  CSN->SetDeclarationContext(CTX);
  CSN->SetLocation(TK->GetLocation());

  if (!SC) {
    if (!CSN->CheckDeclarations()) {
      std::stringstream M;
      M << "Validation failure for declarations at case label scope.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(TK), M.str(),
          DiagLevel::Error);
      return ASTCaseStatementNode::StatementError(M.str(), CIX);
    }
  } else {
    std::map<std::string, const ASTSymbolTableEntry *> &STM =
        CSN->GetSymbolTable();
    SL->SetLocalScope();
    ASTScopeController::Instance().SetDeclarationContext(SL, CTX);
    ASTScopeController::Instance().SetLocalScope(SL);
    SL->TransferDeclarations(STM);
    SL->TransferStatements(STM);
    ASTSymbolTable::Instance().TransferLocalContextSymbols(CTX, STM);
  }

  ASTIfStatementTracker::Instance().CheckDeclarationContext(SL);
  ASTElseIfStatementTracker::Instance().CheckDeclarationContext(SL);
  ASTElseStatementTracker::Instance().CheckDeclarationContext(SL);

  if (SC)
    ASTDeclarationContextTracker::Instance().PopCurrentContext();

  return CSN;
}

ASTDefaultStatementNode *
ASTProductionFactory::ProductionRule_3120(const ASTToken *TK,
                                          ASTStatementList *SL, bool SC) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(SL && "Invalid ASTStatementList argument!");

  QasmFeatureTester::Instance().ValidateFeature("default");

  const ASTDeclarationContext *CTX =
      SC ? ASTDeclarationContextTracker::Instance().CreateContext(
               ASTTypeDefaultStatement)
         : ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  ASTDefaultStatementNode *DSN =
      new ASTDefaultStatementNode(static_cast<unsigned>(~0x0), SL, SC);
  assert(DSN && "Could not create a valid ASTDefaultStatementNode!");

  DSN->SetDeclarationContext(CTX);
  DSN->SetLocation(TK->GetLocation());

  if (!SC) {
    if (!DSN->CheckDeclarations()) {
      std::stringstream M;
      M << "Validation failure for declarations at default label scope.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(TK), M.str(),
          DiagLevel::Error);
      return ASTDefaultStatementNode::StatementError(M.str());
    }
  } else {
    std::map<std::string, const ASTSymbolTableEntry *> &STM =
        DSN->GetSymbolTable();
    SL->SetLocalScope();
    ASTScopeController::Instance().SetDeclarationContext(SL, CTX);
    ASTScopeController::Instance().SetLocalScope(SL);
    SL->TransferDeclarations(STM);
    SL->TransferStatements(STM);
  }

  ASTIfStatementTracker::Instance().CheckDeclarationContext(SL);
  ASTElseIfStatementTracker::Instance().CheckDeclarationContext(SL);
  ASTElseStatementTracker::Instance().CheckDeclarationContext(SL);

  if (SC)
    ASTDeclarationContextTracker::Instance().PopCurrentContext();

  return DSN;
}

ASTDefaultStatementNode *ASTProductionFactory::ProductionRule_3121(
    const ASTToken *TK, ASTStatementList *SL, ASTBreakStatementNode *BK,
    bool SC) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(SL && "Invalid ASTStatementList argument!");
  assert(BK && "Invalid ASTBreakStatementNode argument!");

  QasmFeatureTester::Instance().ValidateFeature("default");

  const ASTDeclarationContext *CTX =
      SC ? ASTDeclarationContextTracker::Instance().CreateContext(
               ASTTypeDefaultStatement)
         : ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  ASTDefaultStatementNode *DSN =
      new ASTDefaultStatementNode(static_cast<unsigned>(~0x0), SL, BK, SC);
  assert(DSN && "Could not create a valid ASTDefaultStatementNode!");

  DSN->SetDeclarationContext(CTX);
  DSN->SetLocation(TK->GetLocation());

  if (!SC) {
    if (!DSN->CheckDeclarations()) {
      std::stringstream M;
      M << "Validation failure for declarations at default label scope.";
      QasmDiagnosticEmitter::Instance().EmitDiagnostic(
          DIAGLineCounter::Instance().GetLocation(TK), M.str(),
          DiagLevel::Error);
      return ASTDefaultStatementNode::StatementError(M.str());
    }
  } else {
    std::map<std::string, const ASTSymbolTableEntry *> &STM =
        DSN->GetSymbolTable();
    SL->SetLocalScope();
    ASTScopeController::Instance().SetDeclarationContext(SL, CTX);
    ASTScopeController::Instance().SetLocalScope(SL);
    SL->TransferDeclarations(STM);
    SL->TransferStatements(STM);
  }

  ASTIfStatementTracker::Instance().CheckDeclarationContext(SL);
  ASTElseIfStatementTracker::Instance().CheckDeclarationContext(SL);
  ASTElseStatementTracker::Instance().CheckDeclarationContext(SL);

  if (SC)
    ASTDeclarationContextTracker::Instance().PopCurrentContext();

  return DSN;
}

ASTBreakStatementNode *
ASTProductionFactory::ProductionRule_3150(const ASTToken *TK) const {
  assert(TK && "Invalid ASTToken argument!");

  std::stringstream BKS;
  BKS << "ast-break-statement-"
      << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      BKS.str(), ASTBreakStatementNode::BreakBits, ASTTypeBreak);
  assert(Id && "Could not create a BreakStmt ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());
  ASTBreakStatementNode *BKN = new ASTBreakStatementNode(Id);
  assert(BKN && "Could not create a valid ASTBreakStatementNode!");

  BKN->SetLocation(TK->GetLocation());
  BKN->Mangle();
  return BKN;
}

ASTContinueStatementNode *
ASTProductionFactory::ProductionRule_3151(const ASTToken *TK) const {
  assert(TK && "Invalid ASTToken argument!");

  std::stringstream CTS;
  CTS << "ast-continue-statement-"
      << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      CTS.str(), ASTContinueStatementNode::ContinueBits, ASTTypeContinue);
  assert(Id && "Could not create a ContinueStmt ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());
  ASTContinueStatementNode *CTN = new ASTContinueStatementNode(Id);
  assert(CTN && "Could not create a valid ASTContinueStatementNode!");

  CTN->SetLocation(TK->GetLocation());
  CTN->Mangle();
  return CTN;
}

ASTSwitchStatementNode *ASTProductionFactory::ProductionRule_3100(
    const ASTToken *TK, const ASTIntNode *DI, ASTStatementList *SL) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DI && "Invalid ASTIntNode argument!");
  assert(SL && "Invalid ASTStatementList argument!");

  QasmFeatureTester::Instance().ValidateFeature("switch");

  if (DI->IsString()) {
    ASTMPIntegerNode *MPI =
        new ASTMPIntegerNode(ASTIdentifierNode::MPInt.Clone(), DI->GetSignBit(),
                             128U, DI->GetString().c_str());
    assert(MPI && "Could not create a valid ASTMPIntegerNode!");

    return ProductionRule_3105(TK, MPI, SL);
  }

  const ASTDeclarationContext *DCX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(DCX && "Could not obtain a valid ASTDeclarationContext!");
  assert(DCX->GetContextType() == ASTTypeSwitchStatement &&
         "Declaration Context is not a switch context!");

  const ASTDeclarationContext *PCX = DCX->GetParentContext();
  assert(PCX && "Could not obtain a valid parent ASTDeclarationContext!");

  std::stringstream SSI;
  SSI << "ast-switch-statement-"
      << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *SId = new ASTIdentifierNode(
      SSI.str(), ASTTypeSwitchStatement, ASTSwitchStatementNode::SwitchBits);
  assert(SId && "Could not create a valid ASTIdentifierNode!");

  SId->SetLocation(TK->GetLocation());
  SId->SetDeclarationContext(PCX);

  if (ASTDeclarationContextTracker::Instance().IsGlobalContext(PCX))
    SId->SetGlobalScope();
  else
    SId->SetLocalScope();

  ASTScopeController::Instance().SetDeclarationContext(SL, DCX);
  ASTScopeController::Instance().SetLocalScope(SL);

  ASTSwitchStatementNode *SN = new ASTSwitchStatementNode(SId, DI, SL);
  assert(SN && "Could not create a valid ASTSwitchStatementNode!");

  if (!SN->CheckValidLabels()) {
    std::stringstream M;
    M << "At least one case label or a default label is required "
      << "in a switch statement.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTSwitchStatementNode::StatementError(M.str());
  }

  SN->SetDeclarationContext(PCX);
  SN->SetLocation(TK->GetLocation());

  SL->TransferDeclarations(SN->GetSymbolTable());
  SL->TransferStatements(SN->GetSymbolTable());

  ASTIdentifierTypeController::Instance().Reset();
  ASTIdentifierTypeController::Instance().SetCurrentType(ASTTypeUndefined);
  ASTDeclarationContextTracker::Instance().PopCurrentContext();
  return SN;
}

ASTSwitchStatementNode *
ASTProductionFactory::ProductionRule_3101(const ASTToken *TK,
                                          const ASTBinaryOpNode *BOP,
                                          ASTStatementList *SL) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(BOP && "Invalid ASTBinaryOpNode argument!");
  assert(SL && "Invalid ASTStatementList argument!");

  QasmFeatureTester::Instance().ValidateFeature("switch");

  const ASTDeclarationContext *DCX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(DCX && "Could not obtain a valid ASTDeclarationContext!");
  assert(DCX->GetContextType() == ASTTypeSwitchStatement &&
         "Declaration Context is not a switch context!");

  const ASTDeclarationContext *PCX = DCX->GetParentContext();
  assert(PCX && "Could not obtain a valid parent ASTDeclarationContext!");

  std::stringstream SSI;
  SSI << "ast-switch-statement-"
      << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *SId = new ASTIdentifierNode(
      SSI.str(), ASTTypeSwitchStatement, ASTSwitchStatementNode::SwitchBits);
  assert(SId && "Could not create a valid ASTIdentifierNode!");

  SId->SetLocation(TK->GetLocation());
  SId->SetDeclarationContext(PCX);

  if (ASTDeclarationContextTracker::Instance().IsGlobalContext(PCX))
    SId->SetGlobalScope();
  else
    SId->SetLocalScope();

  ASTScopeController::Instance().SetDeclarationContext(SL, DCX);
  ASTScopeController::Instance().SetLocalScope(SL);

  ASTSwitchStatementNode *SN = new ASTSwitchStatementNode(SId, BOP, SL);
  assert(SN && "Could not create a valid ASTSwitchStatementNode!");

  if (!SN->CheckValidLabels()) {
    std::stringstream M;
    M << "At least one case label or a default label is required "
      << "in a switch statement.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTSwitchStatementNode::StatementError(M.str());
  }

  SN->SetDeclarationContext(PCX);
  SN->SetLocation(TK->GetLocation());

  SL->TransferDeclarations(SN->GetSymbolTable());
  SL->TransferStatements(SN->GetSymbolTable());

  ASTIdentifierTypeController::Instance().Reset();
  ASTIdentifierTypeController::Instance().SetCurrentType(ASTTypeUndefined);
  ASTDeclarationContextTracker::Instance().PopCurrentContext();
  return SN;
}

ASTSwitchStatementNode *ASTProductionFactory::ProductionRule_3102(
    const ASTToken *TK, const ASTUnaryOpNode *UOP, ASTStatementList *SL) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(UOP && "Invalid ASTUnaryOpNode argument!");
  assert(SL && "Invalid ASTStatementList argument!");

  QasmFeatureTester::Instance().ValidateFeature("switch");

  const ASTDeclarationContext *DCX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(DCX && "Could not obtain a valid ASTDeclarationContext!");
  assert(DCX->GetContextType() == ASTTypeSwitchStatement &&
         "Declaration Context is not a switch context!");

  const ASTDeclarationContext *PCX = DCX->GetParentContext();
  assert(PCX && "Could not obtain a valid parent ASTDeclarationContext!");

  std::stringstream SSI;
  SSI << "ast-switch-statement-"
      << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *SId = new ASTIdentifierNode(
      SSI.str(), ASTTypeSwitchStatement, ASTSwitchStatementNode::SwitchBits);
  assert(SId && "Could not create a valid ASTIdentifierNode!");

  SId->SetLocation(TK->GetLocation());
  SId->SetDeclarationContext(PCX);

  if (ASTDeclarationContextTracker::Instance().IsGlobalContext(PCX))
    SId->SetGlobalScope();
  else
    SId->SetLocalScope();

  ASTScopeController::Instance().SetDeclarationContext(SL, DCX);
  ASTScopeController::Instance().SetLocalScope(SL);

  ASTSwitchStatementNode *SN = new ASTSwitchStatementNode(SId, UOP, SL);
  assert(SN && "Could not create a valid ASTSwitchStatementNode!");

  if (!SN->CheckValidLabels()) {
    std::stringstream M;
    M << "At least one case label or a default label is required "
      << "in a switch statement.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTSwitchStatementNode::StatementError(M.str());
  }

  SN->SetDeclarationContext(PCX);
  SN->SetLocation(TK->GetLocation());

  SL->TransferDeclarations(SN->GetSymbolTable());
  SL->TransferStatements(SN->GetSymbolTable());

  ASTIdentifierTypeController::Instance().Reset();
  ASTIdentifierTypeController::Instance().SetCurrentType(ASTTypeUndefined);
  ASTDeclarationContextTracker::Instance().PopCurrentContext();
  return SN;
}

ASTSwitchStatementNode *
ASTProductionFactory::ProductionRule_3103(const ASTToken *TK,
                                          const ASTIdentifierNode *DId,
                                          ASTStatementList *SL) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DId && "Invalid ASTIdentifierNode argument!");
  assert(SL && "Invalid ASTStatementList argument!");

  QasmFeatureTester::Instance().ValidateFeature("switch");

  const ASTDeclarationContext *DCX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(DCX && "Could not obtain a valid ASTDeclarationContext!");
  assert(DCX->GetContextType() == ASTTypeSwitchStatement &&
         "Declaration Context is not a switch context!");

  const ASTDeclarationContext *PCX = DCX->GetParentContext();
  assert(PCX && "Could not obtain a valid parent ASTDeclarationContext!");

  std::stringstream SSI;
  SSI << "ast-switch-statement-"
      << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *SId = new ASTIdentifierNode(
      SSI.str(), ASTTypeSwitchStatement, ASTSwitchStatementNode::SwitchBits);
  assert(SId && "Could not create a valid ASTIdentifierNode!");

  SId->SetLocation(TK->GetLocation());
  SId->SetDeclarationContext(PCX);

  if (ASTDeclarationContextTracker::Instance().IsGlobalContext(PCX))
    SId->SetGlobalScope();
  else
    SId->SetLocalScope();

  ASTScopeController::Instance().SetDeclarationContext(SL, DCX);
  ASTScopeController::Instance().SetLocalScope(SL);

  ASTSwitchStatementNode *SN = new ASTSwitchStatementNode(SId, DId, SL);
  assert(SN && "Could not create a valid ASTSwitchStatementNode!");

  if (!SN->CheckValidLabels()) {
    std::stringstream M;
    M << "At least one case label or a default label is required "
      << "in a switch statement.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTSwitchStatementNode::StatementError(M.str());
  }

  SN->SetDeclarationContext(PCX);
  SN->SetLocation(TK->GetLocation());

  SL->TransferDeclarations(SN->GetSymbolTable());
  SL->TransferStatements(SN->GetSymbolTable());

  ASTIdentifierTypeController::Instance().Reset();
  ASTIdentifierTypeController::Instance().SetCurrentType(ASTTypeUndefined);
  ASTDeclarationContextTracker::Instance().PopCurrentContext();
  return SN;
}

ASTSwitchStatementNode *
ASTProductionFactory::ProductionRule_3104(const ASTToken *TK,
                                          const ASTFunctionCallNode *FC,
                                          ASTStatementList *SL) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(FC && "Invalid ASTFunctionCallNode argument!");
  assert(SL && "Invalid ASTStatementList argument!");

  QasmFeatureTester::Instance().ValidateFeature("switch");

  const ASTDeclarationContext *DCX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(DCX && "Could not obtain a valid ASTDeclarationContext!");
  assert(DCX->GetContextType() == ASTTypeSwitchStatement &&
         "Declaration Context is not a switch context!");

  const ASTDeclarationContext *PCX = DCX->GetParentContext();
  assert(PCX && "Could not obtain a valid parent ASTDeclarationContext!");

  std::stringstream SSI;
  SSI << "ast-switch-statement-"
      << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *SId = new ASTIdentifierNode(
      SSI.str(), ASTTypeSwitchStatement, ASTSwitchStatementNode::SwitchBits);
  assert(SId && "Could not create a valid ASTIdentifierNode!");

  SId->SetLocation(TK->GetLocation());
  SId->SetDeclarationContext(PCX);

  if (ASTDeclarationContextTracker::Instance().IsGlobalContext(PCX))
    SId->SetGlobalScope();
  else
    SId->SetLocalScope();

  ASTScopeController::Instance().SetDeclarationContext(SL, DCX);
  ASTScopeController::Instance().SetLocalScope(SL);

  ASTSwitchStatementNode *SN = new ASTSwitchStatementNode(SId, FC, SL);
  assert(SN && "Could not create a valid ASTSwitchStatementNode!");

  if (!SN->CheckValidLabels()) {
    std::stringstream M;
    M << "At least one case label or a default label is required "
      << "in a switch statement.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTSwitchStatementNode::StatementError(M.str());
  }

  SN->SetDeclarationContext(PCX);
  SN->SetLocation(TK->GetLocation());

  SL->TransferDeclarations(SN->GetSymbolTable());
  SL->TransferStatements(SN->GetSymbolTable());

  ASTIdentifierTypeController::Instance().Reset();
  ASTIdentifierTypeController::Instance().SetCurrentType(ASTTypeUndefined);
  ASTDeclarationContextTracker::Instance().PopCurrentContext();
  return SN;
}

ASTSwitchStatementNode *
ASTProductionFactory::ProductionRule_3105(const ASTToken *TK,
                                          const ASTMPIntegerNode *DI,
                                          ASTStatementList *SL) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DI && "Invalid ASTMPIntegerNode argument!");
  assert(SL && "Invalid ASTStatementList argument!");

  QasmFeatureTester::Instance().ValidateFeature("switch");

  const ASTDeclarationContext *DCX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(DCX && "Could not obtain a valid ASTDeclarationContext!");
  assert(DCX->GetContextType() == ASTTypeSwitchStatement &&
         "Declaration Context is not a switch context!");

  const ASTDeclarationContext *PCX = DCX->GetParentContext();
  assert(PCX && "Could not obtain a valid parent ASTDeclarationContext!");

  std::stringstream SSI;
  SSI << "ast-switch-statement-"
      << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *SId = new ASTIdentifierNode(
      SSI.str(), ASTTypeSwitchStatement, ASTSwitchStatementNode::SwitchBits);
  assert(SId && "Could not create a valid ASTIdentifierNode!");

  SId->SetLocation(TK->GetLocation());
  SId->SetDeclarationContext(PCX);

  if (ASTDeclarationContextTracker::Instance().IsGlobalContext(PCX))
    SId->SetGlobalScope();
  else
    SId->SetLocalScope();

  ASTScopeController::Instance().SetDeclarationContext(SL, DCX);
  ASTScopeController::Instance().SetLocalScope(SL);

  ASTSwitchStatementNode *SN = new ASTSwitchStatementNode(SId, DI, SL);
  assert(SN && "Could not create a valid ASTSwitchStatementNode!");

  if (!SN->CheckValidLabels()) {
    std::stringstream M;
    M << "At least one case label or a default label is required "
      << "in a switch statement.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTSwitchStatementNode::StatementError(M.str());
  }

  SN->SetDeclarationContext(PCX);
  SN->SetLocation(TK->GetLocation());

  SL->TransferDeclarations(SN->GetSymbolTable());
  SL->TransferStatements(SN->GetSymbolTable());

  ASTIdentifierTypeController::Instance().Reset();
  ASTIdentifierTypeController::Instance().SetCurrentType(ASTTypeUndefined);
  ASTDeclarationContextTracker::Instance().PopCurrentContext();
  return SN;
}

ASTSwitchStatementNode *
ASTProductionFactory::ProductionRule_3106(const ASTToken *TK,
                                          const ASTExpressionNode *DE,
                                          ASTStatementList *SL) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(DE && "Invalid ASTExpressionNode argument!");
  assert(SL && "Invalid ASTStatementList argument!");

  QasmFeatureTester::Instance().ValidateFeature("switch");

  switch (DE->GetASTType()) {
  case ASTTypeInt:
  case ASTTypeUInt:
    if (const ASTIntNode *DI = dynamic_cast<const ASTIntNode *>(DE))
      return ProductionRule_3100(TK, DI, SL);
    break;
  case ASTTypeMPInteger:
  case ASTTypeMPUInteger:
    if (const ASTMPIntegerNode *MPI =
            dynamic_cast<const ASTMPIntegerNode *>(DE))
      return ProductionRule_3105(TK, MPI, SL);
    break;
  case ASTTypeBinaryOp:
    if (const ASTBinaryOpNode *BOP = dynamic_cast<const ASTBinaryOpNode *>(DE))
      return ProductionRule_3101(TK, BOP, SL);
    break;
  case ASTTypeUnaryOp:
    if (const ASTUnaryOpNode *UOP = dynamic_cast<const ASTUnaryOpNode *>(DE))
      return ProductionRule_3102(TK, UOP, SL);
    break;
  case ASTTypeIdentifier:
    if (const ASTIdentifierNode *DId =
            dynamic_cast<const ASTIdentifierNode *>(DE->GetIdentifier()))
      return ProductionRule_3103(TK, DId, SL);
    break;
  case ASTTypeFunctionCall:
    if (const ASTFunctionCallNode *FC =
            dynamic_cast<const ASTFunctionCallNode *>(DE))
      return ProductionRule_3104(TK, FC, SL);
    break;
  default: {
    ASTIdentifierTypeController::Instance().Reset();
    ASTIdentifierTypeController::Instance().SetCurrentType(ASTTypeUndefined);

    std::stringstream M;
    M << "Switch statement quantity is not an integer type ("
      << PrintTypeEnum(DE->GetASTType()) << ").";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(DE), M.str(), DiagLevel::Error);
    return ASTSwitchStatementNode::StatementError(M.str());
  }
  }

  ASTIdentifierTypeController::Instance().Reset();
  ASTIdentifierTypeController::Instance().SetCurrentType(ASTTypeUndefined);
  ASTDeclarationContextTracker::Instance().PopCurrentContext();

  std::stringstream M;
  M << "Switch statement production rule fall-through. "
    << "This should never happen.";
  QasmDiagnosticEmitter::Instance().EmitDiagnostic(
      DIAGLineCounter::Instance().GetLocation(DE), M.str(), DiagLevel::ICE);
  return ASTSwitchStatementNode::StatementError(M.str());
}

ASTForStatementNode *ASTProductionFactory::ProductionRule_3200(
    const ASTToken *TK, ASTIdentifierNode *LId, ASTIntegerList *IL,
    ASTStatementList *SL) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(LId && "Invalid ASTIdentifierNode argument!");
  assert(IL && "Invalid ASTIdentifierList argument!");
  assert(SL && "Invalid ASTStatementList argument!");

  QasmFeatureTester::Instance().ValidateFeature("for");
  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  const_cast<ASTDeclarationContext *>(CTX)->SetContextType(ASTTypeForStatement);

  ASTScopeController::Instance().CheckOutOfScope(LId);
  if (!ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
          LId, ASTIntNode::IntBits, ASTTypeInt)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeInt.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(LId), M.str(), DiagLevel::ICE);
    return ASTForStatementNode::StatementError(M.str());
  }

  ASTSymbolTable::Instance().EraseUndefinedSymbol(LId->GetName());
  ASTScopeController::Instance().CheckOutOfScope(LId);
  LId->SetLocalScope();
  LId->SetDeclarationContext(CTX);

  ASTSymbolTableEntry *ISTE = ASTSymbolTable::Instance().Lookup(
      LId, LId->GetBits(), LId->GetSymbolType());
  assert(ISTE && "Invalid Loop Induction Variable SymbolTable Entry!");

  if (!ISTE->HasValue()) {
    ASTIntNode *IV = new ASTIntNode(LId, int32_t(0));
    assert(IV && "Could not create a valid ASTIntNode induction variable!");

    ISTE->ResetValue();
    ISTE->SetValue(new ASTValue<>(IV, ASTTypeInt), ASTTypeInt);
    assert(ISTE->HasValue() && "Loop induction variable has no Value!");
  }

  SL->SetDeclarationContext(CTX);
  SL->SetLocalScope();
  ASTScopeController::Instance().SetDeclarationContext(SL, CTX);
  ASTDeclarationBuilder::Instance().CheckLoopInductionVariable(LId, SL, CTX);

  std::stringstream FLS;
  FLS << "ast-for-statement-"
      << DIAGLineCounter::Instance().GetIdentifierLocation();
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      FLS.str(), ASTForLoopNode::ForLoopBits, ASTTypeForLoop);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());

  ASTSymbolTableEntry *STE =
      ASTSymbolTable::Instance().Lookup(Id, Id->GetBits(), Id->GetSymbolType());
  assert(STE && "Could not retrieve a valid ForLoop SymbolTable Entry!");
  assert(STE->GetValueType() == ASTTypeForLoop &&
         "Invalid ASTType for the ForLoop SymbolTable Entry!");

  ASTIntNode *LIV = ISTE->GetValue()->GetValue<ASTIntNode *>();
  assert(LIV && "Loop Induction Variable has a SymbolTable Entry with "
                "an invalid Type!");

  ASTForLoopNode *FL = new ASTForLoopNode(Id, *IL, *SL, LIV);
  assert(FL && "Could not create a valid ASTForLoopNode!");

  FL->SetLocation(TK->GetLocation());
  SL->TransferDeclarations(FL->GetSymbolTable());
  ASTSymbolTable::Instance().TransferLocalContextSymbols(CTX,
                                                         FL->GetSymbolTable());
  FL->SetDeclarationContext(CTX->GetParentContext());
  FL->Mangle();

  STE->ResetValue();
  STE->SetValue(new ASTValue<>(FL, ASTTypeForLoop), ASTTypeForLoop);
  assert(STE->HasValue() &&
         "Could not create a Value for the ForLoop SymbolTable Entry!");

  ASTForStatementBuilder::Instance().Clear();
  ASTForStatementNode *FSN = new ASTForStatementNode(FL);
  assert(FSN && "Could not create a valid ASTForStatementNode!");

  FSN->SetDeclarationContext(CTX->GetParentContext());
  FSN->SetLocation(TK->GetLocation());
  FSN->Mangle();

  ASTSymbolTable::Instance().EraseLocalSymbol(LId, LId->GetBits(),
                                              LId->GetSymbolType());
  ASTDeclarationContextTracker::Instance().PopCurrentContext();
  return FSN;
}

ASTForStatementNode *ASTProductionFactory::ProductionRule_3201(
    const ASTToken *TK, ASTIdentifierNode *LId, ASTIntegerList *IL,
    ASTStatement *ST) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(LId && "Invalid ASTIdentifierNode argument!");
  assert(IL && "Invalid ASTIdentifierList argument!");
  assert(ST && "Invalid ASTStatement argument!");

  QasmFeatureTester::Instance().ValidateFeature("for");

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  const_cast<ASTDeclarationContext *>(CTX)->SetContextType(ASTTypeForStatement);

  ASTScopeController::Instance().CheckOutOfScope(LId);
  if (!ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
          LId, ASTIntNode::IntBits, ASTTypeInt)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeInt.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(LId), M.str(), DiagLevel::ICE);
    return ASTForStatementNode::StatementError(M.str());
  }

  ASTSymbolTable::Instance().EraseUndefinedSymbol(LId->GetName());
  ASTScopeController::Instance().CheckOutOfScope(LId);
  LId->SetLocalScope();
  LId->SetDeclarationContext(CTX);

  ASTSymbolTableEntry *ISTE = ASTSymbolTable::Instance().Lookup(
      LId, LId->GetBits(), LId->GetSymbolType());
  assert(ISTE && "Invalid Loop Induction Variable SymbolTable Entry!");

  if (!ISTE->HasValue()) {
    ASTIntNode *IV = new ASTIntNode(LId, int32_t(0));
    assert(IV && "Could not create a valid ASTIntNode induction variable!");
    ISTE->ResetValue();
    ISTE->SetValue(new ASTValue<>(IV, ASTTypeInt), ASTTypeInt);
    assert(ISTE->HasValue() && "Loop induction variable has no Value!");
  }

  ASTStatementList *SL = new ASTStatementList();
  assert(SL && "Could not create a valid ASTStatementList!");

  SL->Append(ST);
  SL->SetDeclarationContext(CTX);
  SL->SetLocalScope();
  ASTScopeController::Instance().SetDeclarationContext(SL, CTX);
  ASTDeclarationBuilder::Instance().CheckLoopInductionVariable(LId, SL, CTX);

  std::stringstream FLS;
  FLS << "ast-for-statement-"
      << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      FLS.str(), ASTForLoopNode::ForLoopBits, ASTTypeForLoop);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());

  ASTSymbolTableEntry *STE =
      ASTSymbolTable::Instance().Lookup(Id, Id->GetBits(), Id->GetSymbolType());
  assert(STE && "Could not retrieve a valid ForLoop SymbolTable Entry!");
  assert(STE->GetValueType() == ASTTypeForLoop &&
         "Invalid ASTType for the ForLoop SymbolTable Entry!");

  ISTE->SetLocalScope();

  ASTIntNode *LIV = ISTE->GetValue()->GetValue<ASTIntNode *>();
  assert(LIV && "Loop Induction Variable has a SymbolTable Entry with "
                "an invalid Type!");

  ASTForLoopNode *FL = new ASTForLoopNode(Id, *IL, *SL, LIV);
  assert(FL && "Could not create a valid ASTForLoopNode!");

  FL->SetLocation(TK->GetLocation());
  SL->TransferDeclarations(FL->GetSymbolTable());
  ASTSymbolTable::Instance().TransferLocalContextSymbols(CTX,
                                                         FL->GetSymbolTable());
  FL->SetDeclarationContext(CTX->GetParentContext());
  FL->Mangle();

  STE->ResetValue();
  STE->SetValue(new ASTValue<>(FL, ASTTypeForLoop), ASTTypeForLoop);
  assert(STE->HasValue() &&
         "Could not create a Value for the ForLoop SymbolTable Entry!");

  ASTForStatementBuilder::Instance().Clear();
  ASTForStatementNode *FSN = new ASTForStatementNode(FL);
  assert(FSN && "Could not create a valid ASTForStatementNode!");

  FSN->SetLocation(TK->GetLocation());
  FSN->SetDeclarationContext(CTX->GetParentContext());
  FSN->Mangle();

  ASTSymbolTable::Instance().EraseLocalSymbol(LId, LId->GetBits(),
                                              LId->GetSymbolType());
  ASTDeclarationContextTracker::Instance().PopCurrentContext();
  return FSN;
}

ASTForStatementNode *ASTProductionFactory::ProductionRule_3202(
    const ASTToken *TK, ASTIdentifierNode *LId, ASTIntegerList *IL,
    ASTStatement *ST) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(LId && "Invalid ASTIdentifierNode argument!");
  assert(IL && "Invalid ASTIdentifierList argument!");
  assert(ST && "Invalid ASTStatement argument!");

  QasmFeatureTester::Instance().ValidateFeature("for");

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  const_cast<ASTDeclarationContext *>(CTX)->SetContextType(ASTTypeForStatement);

  ASTScopeController::Instance().CheckOutOfScope(LId);
  if (!ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
          LId, ASTIntNode::IntBits, ASTTypeInt)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeInt.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(LId), M.str(), DiagLevel::ICE);
    return ASTForStatementNode::StatementError(M.str());
  }

  ASTSymbolTable::Instance().EraseUndefinedSymbol(LId->GetName());
  ASTScopeController::Instance().CheckOutOfScope(LId);
  LId->SetLocalScope();
  LId->SetDeclarationContext(CTX);

  ASTStatementList *SL = new ASTStatementList();
  assert(SL && "Could not create a valid ASTStatementList!");

  SL->SetLocation(ST->GetLocation());
  SL->Append(ST);
  SL->SetDeclarationContext(CTX);
  SL->SetLocalScope();
  ASTScopeController::Instance().SetDeclarationContext(SL, CTX);
  ASTDeclarationBuilder::Instance().CheckLoopInductionVariable(LId, SL, CTX);

  std::stringstream FLS;
  FLS << "ast-for-statement-"
      << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      FLS.str(), ASTForLoopNode::ForLoopBits, ASTTypeForLoop);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());

  ASTSymbolTableEntry *STE =
      ASTSymbolTable::Instance().Lookup(Id, Id->GetBits(), Id->GetSymbolType());
  assert(STE && "Could not retrieve a valid ForLoop SymbolTable Entry!");
  assert(STE->GetValueType() == ASTTypeForLoop &&
         "Invalid ASTType for the ForLoop SymbolTable Entry!");

  ASTSymbolTableEntry *ISTE = ASTSymbolTable::Instance().Lookup(
      LId, LId->GetBits(), LId->GetSymbolType());
  assert(ISTE && "Invalid Loop Induction Variable SymbolTable Entry!");

  if (!ISTE->HasValue()) {
    ASTIntNode *IV = new ASTIntNode(LId, int32_t(0));
    assert(IV && "Could not create a valid ASTIntNode induction variable!");
    ISTE->ResetValue();
    ISTE->SetValue(new ASTValue<>(IV, ASTTypeInt), ASTTypeInt);
    assert(ISTE->HasValue() && "Loop induction variable has no Value!");
  }

  ASTIntNode *LIV = ISTE->GetValue()->GetValue<ASTIntNode *>();
  assert(LIV && "Loop Induction Variable has a SymbolTable Entry with "
                "an invalid Type!");

  ASTForLoopNode *FL =
      new ASTForLoopNode(Id, *IL, *SL, LIV, ASTForLoopNode::IVDiscrete);
  assert(FL && "Could not create a valid ASTForLoopNode!");

  FL->SetLocation(TK->GetLocation());
  SL->TransferDeclarations(FL->GetSymbolTable());
  ASTSymbolTable::Instance().TransferLocalContextSymbols(CTX,
                                                         FL->GetSymbolTable());
  FL->SetDeclarationContext(CTX->GetParentContext());
  FL->Mangle();

  STE->ResetValue();
  STE->SetValue(new ASTValue<>(FL, ASTTypeForLoop), ASTTypeForLoop);
  assert(STE->HasValue() &&
         "Could not create a Value for the ForLoop SymbolTable Entry!");

  ASTForStatementBuilder::Instance().Clear();
  ASTForStatementNode *FSN = new ASTForStatementNode(FL);
  assert(FSN && "Could not create a valid ASTForStatementNode!");

  FSN->SetLocation(TK->GetLocation());
  FSN->SetDeclarationContext(CTX->GetParentContext());
  FSN->Mangle();

  ASTSymbolTable::Instance().EraseLocalSymbol(LId, LId->GetBits(),
                                              LId->GetSymbolType());
  ASTDeclarationContextTracker::Instance().PopCurrentContext();
  return FSN;
}

ASTForStatementNode *ASTProductionFactory::ProductionRule_3203(
    const ASTToken *TK, ASTIdentifierNode *LId, ASTIntegerList *IL,
    ASTStatementList *SL) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(LId && "Invalid ASTIdentifierNode argument!");
  assert(IL && "Invalid ASTIdentifierList argument!");
  assert(SL && "Invalid ASTStatementList argument!");

  QasmFeatureTester::Instance().ValidateFeature("for");

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  const_cast<ASTDeclarationContext *>(CTX)->SetContextType(ASTTypeForStatement);

  ASTScopeController::Instance().CheckOutOfScope(LId);
  if (!ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
          LId, ASTIntNode::IntBits, ASTTypeInt)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeInt.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(LId), M.str(), DiagLevel::ICE);
    return ASTForStatementNode::StatementError(M.str());
  }

  ASTSymbolTable::Instance().EraseUndefinedSymbol(LId->GetName());
  ASTScopeController::Instance().CheckOutOfScope(LId);
  LId->SetLocalScope();
  LId->SetDeclarationContext(CTX);

  ASTSymbolTableEntry *ISTE = ASTSymbolTable::Instance().Lookup(
      LId, LId->GetBits(), LId->GetSymbolType());
  assert(ISTE && "Invalid Loop Induction Variable SymbolTable Entry!");

  if (!ISTE->HasValue()) {
    ASTIntNode *IV = new ASTIntNode(LId, int32_t(0));
    assert(IV && "Could not create a valid ASTIntNode induction variable!");
    ISTE->ResetValue();
    ISTE->SetValue(new ASTValue<>(IV, ASTTypeInt), ASTTypeInt);
    assert(ISTE->HasValue() && "Loop induction variable has no Value!");
  }

  SL->SetDeclarationContext(CTX);
  SL->SetLocalScope();
  ASTScopeController::Instance().SetDeclarationContext(SL, CTX);
  ASTDeclarationBuilder::Instance().CheckLoopInductionVariable(LId, SL, CTX);

  std::stringstream FLS;
  FLS << "ast-for-statement-"
      << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      FLS.str(), ASTForLoopNode::ForLoopBits, ASTTypeForLoop);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  ASTSymbolTableEntry *STE =
      ASTSymbolTable::Instance().Lookup(Id, Id->GetBits(), Id->GetSymbolType());
  assert(STE && "Could not retrieve a valid ForLoop SymbolTable Entry!");
  assert(STE->GetValueType() == ASTTypeForLoop &&
         "Invalid ASTType for the ForLoop SymbolTable Entry!");

  ASTIntNode *LIV = ISTE->GetValue()->GetValue<ASTIntNode *>();
  assert(LIV && "Loop Induction Variable has a SymbolTable Entry with "
                "an invalid Type!");

  ASTForLoopNode *FL =
      new ASTForLoopNode(Id, *IL, *SL, LIV, ASTForLoopNode::IVDiscrete);
  assert(FL && "Could not create a valid ASTForLoopNode!");

  FL->SetLocation(TK->GetLocation());
  SL->TransferDeclarations(FL->GetSymbolTable());
  ASTSymbolTable::Instance().TransferLocalContextSymbols(CTX,
                                                         FL->GetSymbolTable());
  FL->SetDeclarationContext(CTX->GetParentContext());
  FL->Mangle();

  STE->ResetValue();
  STE->SetValue(new ASTValue<>(FL, ASTTypeForLoop), ASTTypeForLoop);
  assert(STE->HasValue() &&
         "Could not create a Value for the ForLoop SymbolTable Entry!");

  ASTForStatementBuilder::Instance().Clear();
  ASTForStatementNode *FSN = new ASTForStatementNode(FL);
  assert(FSN && "Could not create a valid ASTForStatementNode!");

  FSN->SetLocation(TK->GetLocation());
  FSN->SetDeclarationContext(CTX->GetParentContext());
  FSN->Mangle();

  ASTSymbolTable::Instance().EraseLocalSymbol(LId, LId->GetBits(),
                                              LId->GetSymbolType());
  ASTDeclarationContextTracker::Instance().PopCurrentContext();
  return FSN;
}

ASTForStatementNode *ASTProductionFactory::ProductionRule_3204(
    const ASTToken *TK, ASTIdentifierNode *LId,
    ASTForLoopRangeExpressionNode *FLR, ASTStatementList *SL) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(LId && "Invalid ASTIdentifierNode argument!");
  assert(FLR && "Invalid ASTForLoopRangeExpressionNode argument!");
  assert(SL && "Invalid ASTStatementList argument!");

  QasmFeatureTester::Instance().ValidateFeature("for");

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  const_cast<ASTDeclarationContext *>(CTX)->SetContextType(ASTTypeForStatement);

  ASTScopeController::Instance().CheckOutOfScope(LId);
  if (!ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
          LId, ASTIntNode::IntBits, ASTTypeInt)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeInt.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(LId), M.str(), DiagLevel::ICE);
    return ASTForStatementNode::StatementError(M.str());
  }

  ASTSymbolTable::Instance().EraseUndefinedSymbol(LId->GetName());
  ASTScopeController::Instance().CheckOutOfScope(LId);
  LId->SetLocalScope();
  LId->SetDeclarationContext(CTX);

  ASTSymbolTableEntry *ISTE = ASTSymbolTable::Instance().Lookup(
      LId, LId->GetBits(), LId->GetSymbolType());
  assert(ISTE && "Invalid Loop Induction Variable SymbolTable Entry!");

  if (!ISTE->HasValue()) {
    ASTIntNode *IV = new ASTIntNode(LId, int32_t(0));
    assert(IV && "Could not create a valid ASTIntNode induction variable!");
    ISTE->ResetValue();
    ISTE->SetValue(new ASTValue<>(IV, ASTTypeInt), ASTTypeInt);
    assert(ISTE->HasValue() && "Loop induction variable has no Value!");
  }

  std::stringstream FLS;
  FLS << "ast-for-statement-"
      << DIAGLineCounter::Instance().GetIdentifierLocation();

  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      FLS.str(), ASTForLoopNode::ForLoopBits, ASTTypeForLoop);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());

  ASTSymbolTableEntry *STE =
      ASTSymbolTable::Instance().Lookup(Id, Id->GetBits(), Id->GetSymbolType());
  assert(STE && "Could not retrieve a valid ForLoop SymbolTable Entry!");
  assert(STE->GetValueType() == ASTTypeForLoop &&
         "Invalid ASTType for the ForLoop SymbolTable Entry!");

  ASTIntNode *LIV = ISTE->GetValue()->GetValue<ASTIntNode *>();
  assert(LIV && "Loop Induction Variable has a SymbolTable Entry with "
                "an invalid Type!");

  ASTForLoopNode *FL = new ASTForLoopNode(Id, FLR, *SL, LIV);
  assert(FL && "Could not create a valid ASTForLoopNode!");

  FL->SetLocation(TK->GetLocation());
  SL->TransferDeclarations(FL->GetSymbolTable());
  ASTSymbolTable::Instance().TransferLocalContextSymbols(CTX,
                                                         FL->GetSymbolTable());
  FL->SetDeclarationContext(CTX->GetParentContext());
  FL->Mangle();

  STE->ResetValue();
  STE->SetValue(new ASTValue<>(FL, ASTTypeForLoop), ASTTypeForLoop);
  assert(STE->HasValue() &&
         "Could not create a Value for the ForLoop SymbolTable Entry!");

  ASTForStatementBuilder::Instance().Clear();
  ASTForStatementNode *FSN = new ASTForStatementNode(FL);
  assert(FSN && "Could not create a valid ASTForStatementNode!");

  FSN->SetLocation(TK->GetLocation());
  FSN->SetDeclarationContext(CTX->GetParentContext());
  FSN->Mangle();

  ASTSymbolTable::Instance().EraseLocalSymbol(LId, LId->GetBits(),
                                              LId->GetSymbolType());
  ASTDeclarationContextTracker::Instance().PopCurrentContext();
  return FSN;
}

ASTForStatementNode *ASTProductionFactory::ProductionRule_3205(
    const ASTToken *TK, ASTIdentifierNode *LId,
    ASTForLoopRangeExpressionNode *FLR, ASTStatement *ST) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(LId && "Invalid ASTIdentifierNode argument!");
  assert(FLR && "Invalid ASTForLoopRangeExpressionNode argument!");
  assert(ST && "Invalid ASTStatement argument!");

  QasmFeatureTester::Instance().ValidateFeature("for");

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  const_cast<ASTDeclarationContext *>(CTX)->SetContextType(ASTTypeForStatement);

  ASTScopeController::Instance().CheckOutOfScope(LId);
  if (!ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
          LId, ASTIntNode::IntBits, ASTTypeInt)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeInt.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(LId), M.str(), DiagLevel::ICE);
    return ASTForStatementNode::StatementError(M.str());
  }

  ASTSymbolTable::Instance().EraseUndefinedSymbol(LId->GetName());
  ASTScopeController::Instance().CheckOutOfScope(LId);
  LId->SetLocalScope();
  LId->SetDeclarationContext(CTX);

  ASTSymbolTableEntry *ISTE = ASTSymbolTable::Instance().Lookup(
      LId, LId->GetBits(), LId->GetSymbolType());
  assert(ISTE && "Invalid Loop Induction Variable SymbolTable Entry!");

  if (!ISTE->HasValue()) {
    ASTIntNode *IV = new ASTIntNode(LId, int32_t(0));
    assert(IV && "Could not create a valid ASTIntNode induction variable!");
    ISTE->ResetValue();
    ISTE->SetValue(new ASTValue<>(IV, ASTTypeInt), ASTTypeInt);
    assert(ISTE->HasValue() && "Loop induction variable has no Value!");
  }

  ASTStatementList *SL = new ASTStatementList();
  assert(SL && "Could not create a valid ASTStatementList!");

  SL->Append(ST);
  SL->SetDeclarationContext(CTX);
  SL->SetLocalScope();
  ASTScopeController::Instance().SetDeclarationContext(SL, CTX);
  ASTDeclarationBuilder::Instance().CheckLoopInductionVariable(LId, SL, CTX);

  std::stringstream FLS;
  FLS << "ast-for-statement-"
      << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      FLS.str(), ASTForLoopNode::ForLoopBits, ASTTypeForLoop);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());

  ASTSymbolTableEntry *STE =
      ASTSymbolTable::Instance().Lookup(Id, Id->GetBits(), Id->GetSymbolType());
  assert(STE && "Could not retrieve a valid ForLoop SymbolTable Entry!");
  assert(STE->GetValueType() == ASTTypeForLoop &&
         "Invalid ASTType for the ForLoop SymbolTable Entry!");

  ASTIntNode *LIV = ISTE->GetValue()->GetValue<ASTIntNode *>();
  assert(LIV && "Loop Induction Variable has a SymbolTable Entry with "
                "an invalid Type!");

  ASTForLoopNode *FL = new ASTForLoopNode(Id, FLR, *SL, LIV);
  assert(FL && "Could not create a valid ASTForLoopNode!");

  FL->SetLocation(TK->GetLocation());
  SL->TransferDeclarations(FL->GetSymbolTable());
  ASTSymbolTable::Instance().TransferLocalContextSymbols(CTX,
                                                         FL->GetSymbolTable());
  FL->SetDeclarationContext(CTX->GetParentContext());
  FL->Mangle();

  STE->ResetValue();
  STE->SetValue(new ASTValue<>(FL, ASTTypeForLoop), ASTTypeForLoop);
  assert(STE->HasValue() &&
         "Could not create a Value for the ForLoop SymbolTable Entry!");

  ASTForStatementBuilder::Instance().Clear();
  ASTForStatementNode *FSN = new ASTForStatementNode(FL);
  assert(FSN && "Could not create a valid ASTForStatementNode!");

  FSN->SetLocation(TK->GetLocation());
  FSN->SetDeclarationContext(CTX->GetParentContext());
  FSN->Mangle();

  ASTSymbolTable::Instance().EraseLocalSymbol(LId, LId->GetBits(),
                                              LId->GetSymbolType());
  ASTDeclarationContextTracker::Instance().PopCurrentContext();
  return FSN;
}

ASTForStatementNode *ASTProductionFactory::ProductionRule_3206(
    const ASTToken *TK, ASTIntNode *IVT, ASTIdentifierNode *LId,
    ASTIntegerList *IL, ASTStatementList *SL) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(IVT && "Invalid ASTIntNode argument!");
  assert(LId && "Invalid ASTIdentifierNode argument!");
  assert(IL && "Invalid ASTIdentifierList argument!");
  assert(SL && "Invalid ASTStatementList argument!");

  QasmFeatureTester::Instance().ValidateFeature("for");

  ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  const_cast<ASTDeclarationContext *>(CTX)->SetContextType(ASTTypeForStatement);

  ASTScopeController::Instance().CheckOutOfScope(LId);
  if (!ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
          LId, ASTIntNode::IntBits, ASTTypeInt)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeInt.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(LId), M.str(), DiagLevel::ICE);
    return ASTForStatementNode::StatementError(M.str());
  }

  ASTSymbolTable::Instance().EraseUndefinedSymbol(LId->GetName());
  ASTScopeController::Instance().CheckOutOfScope(LId);
  LId->SetLocalScope();
  LId->SetDeclarationContext(CTX);

  ASTSymbolTableEntry *ISTE = ASTSymbolTable::Instance().Lookup(
      LId, LId->GetBits(), LId->GetSymbolType());
  assert(ISTE && "Invalid Loop Induction Variable SymbolTable Entry!");

  ISTE->ResetValue();
  ISTE->SetValue(new ASTValue<>(IVT, ASTTypeInt), ASTTypeInt);
  assert(ISTE->HasValue() && "Loop induction variable has no Value!");

  SL->SetDeclarationContext(CTX);
  SL->SetLocalScope();
  ASTScopeController::Instance().SetDeclarationContext(SL, CTX);
  ASTDeclarationBuilder::Instance().CheckLoopInductionVariable(LId, SL, CTX);

  std::stringstream FLS;
  FLS << "ast-for-statement-"
      << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      FLS.str(), ASTForLoopNode::ForLoopBits, ASTTypeForLoop);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());

  ASTSymbolTableEntry *STE =
      ASTSymbolTable::Instance().Lookup(Id, Id->GetBits(), Id->GetSymbolType());
  assert(STE && "Could not retrieve a valid ForLoop SymbolTable Entry!");
  assert(STE->GetValueType() == ASTTypeForLoop &&
         "Invalid ASTType for the ForLoop SymbolTable Entry!");

  ASTIntNode *LIV = ISTE->GetValue()->GetValue<ASTIntNode *>();
  assert(LIV && "Loop Induction Variable has a SymbolTable Entry with "
                "an invalid Type!");

  ASTForLoopNode *FL = new ASTForLoopNode(Id, *IL, *SL, LIV);
  assert(FL && "Could not create an ASTForLoopNode!");

  SL->TransferDeclarations(FL->GetSymbolTable());
  ASTSymbolTable::Instance().TransferLocalContextSymbols(CTX,
                                                         FL->GetSymbolTable());
  FL->SetLocation(TK->GetLocation());
  FL->SetDeclarationContext(CTX->GetParentContext());
  FL->Mangle();

  STE->ResetValue();
  STE->SetValue(new ASTValue<>(FL, ASTTypeForLoop), ASTTypeForLoop);
  assert(STE->HasValue() &&
         "Could not create a Value for the ForLoop SymbolTable Entry!");

  ASTForStatementBuilder::Instance().Clear();
  ASTForStatementNode *FSN = new ASTForStatementNode(FL);
  assert(FSN && "Could not create an ASTForStatementNode!");

  FSN->SetLocation(TK->GetLocation());
  FSN->SetDeclarationContext(CTX->GetParentContext());
  FSN->Mangle();

  ASTSymbolTable::Instance().EraseLocalSymbol(LId, LId->GetBits(),
                                              LId->GetSymbolType());
  ASTDeclarationContextTracker::Instance().PopCurrentContext();
  return FSN;
}

ASTForStatementNode *ASTProductionFactory::ProductionRule_3207(
    const ASTToken *TK, ASTIntNode *IVT, ASTIdentifierNode *LId,
    ASTIntegerList *IL, ASTStatement *ST) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(IVT && "Invalid ASTIntNode argument!");
  assert(LId && "Invalid ASTIdentifierNode argument!");
  assert(IL && "Invalid ASTIdentifierList argument!");
  assert(ST && "Invalid ASTStatement argument!");

  QasmFeatureTester::Instance().ValidateFeature("for");

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  const_cast<ASTDeclarationContext *>(CTX)->SetContextType(ASTTypeForStatement);

  ASTScopeController::Instance().CheckOutOfScope(LId);
  if (!ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
          LId, ASTIntNode::IntBits, ASTTypeInt)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeInt.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(LId), M.str(), DiagLevel::ICE);
    return ASTForStatementNode::StatementError(M.str());
  }

  ASTSymbolTable::Instance().EraseUndefinedSymbol(LId->GetName());
  ASTScopeController::Instance().CheckOutOfScope(LId);
  LId->SetLocalScope();
  LId->SetDeclarationContext(CTX);

  ASTSymbolTableEntry *ISTE = ASTSymbolTable::Instance().Lookup(
      LId, LId->GetBits(), LId->GetSymbolType());
  assert(ISTE && "Invalid Loop Induction Variable SymbolTable Entry!");

  ISTE->ResetValue();
  ISTE->SetValue(new ASTValue<>(IVT, ASTTypeInt), ASTTypeInt);
  assert(ISTE->HasValue() && "Loop induction variable has no Value!");

  ASTStatementList *SL = new ASTStatementList();
  assert(SL && "Could not create a valid ASTStatementList!");

  SL->Append(ST);
  SL->SetLocalScope();
  SL->SetDeclarationContext(CTX);
  ASTScopeController::Instance().SetDeclarationContext(SL, CTX);
  ASTDeclarationBuilder::Instance().CheckLoopInductionVariable(LId, SL, CTX);

  std::stringstream FLS;
  FLS << "ast-for-statement-"
      << DIAGLineCounter::Instance().GetIdentifierLocation();
  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      FLS.str(), ASTForLoopNode::ForLoopBits, ASTTypeForLoop);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());

  ASTSymbolTableEntry *STE =
      ASTSymbolTable::Instance().Lookup(Id, Id->GetBits(), Id->GetSymbolType());
  assert(STE && "Could not retrieve a valid ForLoop SymbolTable Entry!");
  assert(STE->GetValueType() == ASTTypeForLoop &&
         "Invalid ASTType for the ForLoop SymbolTable Entry!");

  ASTIntNode *LIV = ISTE->GetValue()->GetValue<ASTIntNode *>();
  assert(LIV && "Loop Induction Variable has a SymbolTable Entry with "
                "an invalid Type!");

  ASTForLoopNode *FL = new ASTForLoopNode(Id, *IL, *SL, LIV);
  assert(FL && "Could not create an ASTForLoopNode!");

  FL->SetLocation(TK->GetLocation());
  SL->TransferDeclarations(FL->GetSymbolTable());
  ASTSymbolTable::Instance().TransferLocalContextSymbols(CTX,
                                                         FL->GetSymbolTable());
  FL->SetDeclarationContext(CTX->GetParentContext());
  FL->Mangle();

  STE->ResetValue();
  STE->SetValue(new ASTValue<>(FL, ASTTypeForLoop), ASTTypeForLoop);
  assert(STE->HasValue() &&
         "Could not create a Value for the ForLoop SymbolTable Entry!");

  ASTForStatementBuilder::Instance().Clear();
  ASTForStatementNode *FSN = new ASTForStatementNode(FL);
  assert(FSN && "Could not create an ASTForStatementNode!");

  FSN->SetLocation(TK->GetLocation());
  FSN->SetDeclarationContext(CTX->GetParentContext());
  FSN->Mangle();

  ASTSymbolTable::Instance().EraseLocalSymbol(LId, LId->GetBits(),
                                              LId->GetSymbolType());
  ASTDeclarationContextTracker::Instance().PopCurrentContext();
  return FSN;
}

ASTForStatementNode *ASTProductionFactory::ProductionRule_3208(
    const ASTToken *TK, ASTIntNode *IVT, ASTIdentifierNode *LId,
    ASTIntegerList *IL, ASTStatementList *SL) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(IVT && "Invalid ASTIntNode argument!");
  assert(LId && "Invalid ASTIdentifierNode argument!");
  assert(IL && "Invalid ASTIdentifierList argument!");
  assert(SL && "Invalid ASTStatementList argument!");

  QasmFeatureTester::Instance().ValidateFeature("for");

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  const_cast<ASTDeclarationContext *>(CTX)->SetContextType(ASTTypeForStatement);

  ASTScopeController::Instance().CheckOutOfScope(LId);
  if (!ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
          LId, ASTIntNode::IntBits, ASTTypeInt)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeInt.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(LId), M.str(), DiagLevel::ICE);
    return ASTForStatementNode::StatementError(M.str());
  }

  ASTSymbolTable::Instance().EraseUndefinedSymbol(LId->GetName());
  ASTScopeController::Instance().CheckOutOfScope(LId);
  LId->SetLocalScope();
  LId->SetDeclarationContext(CTX);

  ASTSymbolTableEntry *ISTE = ASTSymbolTable::Instance().Lookup(
      LId, LId->GetBits(), LId->GetSymbolType());
  assert(ISTE && "Invalid Loop Induction Variable SymbolTable Entry!");

  ISTE->ResetValue();
  ISTE->SetValue(new ASTValue<>(IVT, ASTTypeInt), ASTTypeInt);
  assert(ISTE->HasValue() && "Loop induction variable has no Value!");

  SL->SetDeclarationContext(CTX);
  SL->SetLocalScope();
  ASTScopeController::Instance().SetDeclarationContext(SL, CTX);
  ASTDeclarationBuilder::Instance().CheckLoopInductionVariable(LId, SL, CTX);

  std::stringstream FLS;
  FLS << "ast-for-statement-"
      << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      FLS.str(), ASTForLoopNode::ForLoopBits, ASTTypeForLoop);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());

  ASTSymbolTableEntry *STE =
      ASTSymbolTable::Instance().Lookup(Id, Id->GetBits(), Id->GetSymbolType());
  assert(STE && "Could not retrieve a valid ForLoop SymbolTable Entry!");
  assert(STE->GetValueType() == ASTTypeForLoop &&
         "Invalid ASTType for the ForLoop SymbolTable Entry!");

  ASTIntNode *LIV = ISTE->GetValue()->GetValue<ASTIntNode *>();
  assert(LIV && "Loop Induction Variable has a SymbolTable Entry with "
                "an invalid Type!");

  ASTForLoopNode *FL =
      new ASTForLoopNode(Id, *IL, *SL, LIV, ASTForLoopNode::IVDiscrete);
  assert(FL && "Could not create an ASTForLoopNode!");

  FL->SetLocation(TK->GetLocation());
  FL->SetDeclarationContext(CTX->GetParentContext());
  FL->Mangle();
  SL->TransferDeclarations(FL->GetSymbolTable());
  ASTSymbolTable::Instance().TransferLocalContextSymbols(CTX,
                                                         FL->GetSymbolTable());

  STE->ResetValue();
  STE->SetValue(new ASTValue<>(FL, ASTTypeForLoop), ASTTypeForLoop);
  assert(STE->HasValue() &&
         "Could not create a Value for the ForLoop SymbolTable Entry!");

  ASTForStatementBuilder::Instance().Clear();
  ASTForStatementNode *FSN = new ASTForStatementNode(FL);
  assert(FSN && "Could not create an ASTForStatementNode!");

  FSN->SetLocation(TK->GetLocation());
  FSN->SetDeclarationContext(CTX->GetParentContext());
  FSN->Mangle();

  ASTSymbolTable::Instance().EraseLocalSymbol(LId, LId->GetBits(),
                                              LId->GetSymbolType());
  ASTDeclarationContextTracker::Instance().PopCurrentContext();
  return FSN;
}

ASTForStatementNode *ASTProductionFactory::ProductionRule_3209(
    const ASTToken *TK, ASTIntNode *IVT, ASTIdentifierNode *LId,
    ASTIntegerList *IL, ASTStatement *ST) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(IVT && "Invalid ASTIntNode argument!");
  assert(LId && "Invalid ASTIdentifierNode argument!");
  assert(IL && "Invalid ASTIdentifierList argument!");
  assert(ST && "Invalid ASTStatement argument!");

  QasmFeatureTester::Instance().ValidateFeature("for");

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  const_cast<ASTDeclarationContext *>(CTX)->SetContextType(ASTTypeForStatement);

  ASTScopeController::Instance().CheckOutOfScope(LId);
  if (!ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
          LId, ASTIntNode::IntBits, ASTTypeInt)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeInt.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(LId), M.str(), DiagLevel::ICE);
    return ASTForStatementNode::StatementError(M.str());
  }

  ASTSymbolTable::Instance().EraseUndefinedSymbol(LId->GetName());
  ASTScopeController::Instance().CheckOutOfScope(LId);
  LId->SetLocalScope();
  LId->SetDeclarationContext(CTX);

  ASTStatementList *SL = new ASTStatementList();
  assert(SL && "Could not create a valid ASTStatementList!");

  SL->Append(ST);
  SL->SetDeclarationContext(CTX);
  SL->SetLocalScope();
  ASTScopeController::Instance().SetDeclarationContext(SL, CTX);
  ASTDeclarationBuilder::Instance().CheckLoopInductionVariable(LId, SL, CTX);

  std::stringstream FLS;
  FLS << "ast-for-statement-"
      << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      FLS.str(), ASTForLoopNode::ForLoopBits, ASTTypeForLoop);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());

  ASTSymbolTableEntry *STE =
      ASTSymbolTable::Instance().Lookup(Id, Id->GetBits(), Id->GetSymbolType());
  assert(STE && "Could not retrieve a valid ForLoop SymbolTable Entry!");
  assert(STE->GetValueType() == ASTTypeForLoop &&
         "Invalid ASTType for the ForLoop SymbolTable Entry!");

  ASTSymbolTableEntry *ISTE = ASTSymbolTable::Instance().Lookup(
      LId, LId->GetBits(), LId->GetSymbolType());
  assert(ISTE && "Invalid Loop Induction Variable SymbolTable Entry!");

  ISTE->ResetValue();
  ISTE->SetValue(new ASTValue<>(IVT, ASTTypeInt), ASTTypeInt);
  assert(ISTE->HasValue() && "Loop induction variable has no Value!");

  ASTIntNode *LIV = ISTE->GetValue()->GetValue<ASTIntNode *>();
  assert(LIV && "Loop Induction Variable has a SymbolTable Entry with "
                "an invalid Type!");

  ASTForLoopNode *FL =
      new ASTForLoopNode(Id, *IL, *SL, LIV, ASTForLoopNode::IVDiscrete);
  assert(FL && "Could not create an ASTForLoopNode!");

  FL->SetLocation(TK->GetLocation());
  FL->SetDeclarationContext(CTX->GetParentContext());
  SL->TransferDeclarations(FL->GetSymbolTable());
  ASTSymbolTable::Instance().TransferLocalContextSymbols(CTX,
                                                         FL->GetSymbolTable());
  FL->Mangle();

  STE->ResetValue();
  STE->SetValue(new ASTValue<>(FL, ASTTypeForLoop), ASTTypeForLoop);
  assert(STE->HasValue() &&
         "Could not create a Value for the ForLoop SymbolTable Entry!");

  ASTForStatementBuilder::Instance().Clear();
  ASTForStatementNode *FSN = new ASTForStatementNode(FL);
  assert(FSN && "Could not create an ASTForStatementNode!");

  FSN->SetLocation(TK->GetLocation());
  FSN->SetDeclarationContext(CTX->GetParentContext());
  FSN->Mangle();

  ASTSymbolTable::Instance().EraseLocalSymbol(LId, LId->GetBits(),
                                              LId->GetSymbolType());
  ASTDeclarationContextTracker::Instance().PopCurrentContext();
  return FSN;
}

ASTForStatementNode *ASTProductionFactory::ProductionRule_3210(
    const ASTToken *TK, ASTIntNode *IVT, ASTIdentifierNode *LId,
    ASTForLoopRangeExpressionNode *FLR, ASTStatementList *SL) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(IVT && "Invalid ASTIntNode argument!");
  assert(LId && "Invalid ASTIdentifierNode argument!");
  assert(FLR && "Invalid ASTForLoopRangeExpressionNode argument!");
  assert(SL && "Invalid ASTStatementList argument!");

  QasmFeatureTester::Instance().ValidateFeature("for");

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  const_cast<ASTDeclarationContext *>(CTX)->SetContextType(ASTTypeForStatement);

  ASTScopeController::Instance().CheckOutOfScope(LId);
  if (!ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
          LId, ASTIntNode::IntBits, ASTTypeInt)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeInt.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(LId), M.str(), DiagLevel::ICE);
    return ASTForStatementNode::StatementError(M.str());
  }

  ASTSymbolTable::Instance().EraseUndefinedSymbol(LId->GetName());
  ASTScopeController::Instance().CheckOutOfScope(LId);
  LId->SetLocalScope();
  LId->SetDeclarationContext(CTX);

  ASTSymbolTableEntry *ISTE = ASTSymbolTable::Instance().Lookup(
      LId, LId->GetBits(), LId->GetSymbolType());
  assert(ISTE && "Invalid Loop Induction Variable SymbolTable Entry!");

  ISTE->ResetValue();
  ISTE->SetValue(new ASTValue<>(IVT, ASTTypeInt), ASTTypeInt);
  assert(ISTE->HasValue() && "Loop induction variable has no Value!");

  SL->SetDeclarationContext(CTX);
  SL->SetLocalScope();
  ASTScopeController::Instance().SetDeclarationContext(SL, CTX);
  ASTDeclarationBuilder::Instance().CheckLoopInductionVariable(LId, SL, CTX);

  std::stringstream FLS;
  FLS << "ast-for-statement-"
      << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      FLS.str(), ASTForLoopNode::ForLoopBits, ASTTypeForLoop);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());

  ASTSymbolTableEntry *STE =
      ASTSymbolTable::Instance().Lookup(Id, Id->GetBits(), Id->GetSymbolType());
  assert(STE && "Could not retrieve a valid ForLoop SymbolTable Entry!");
  assert(STE->GetValueType() == ASTTypeForLoop &&
         "Invalid ASTType for the ForLoop SymbolTable Entry!");

  ASTIntNode *LIV = ISTE->GetValue()->GetValue<ASTIntNode *>();
  assert(LIV && "Loop Induction Variable has a SymbolTable Entry with "
                "an invalid Type!");

  ASTForLoopNode *FL = new ASTForLoopNode(Id, FLR, *SL, LIV);
  assert(FL && "Could not create an ASTForLoopNode!");

  FL->SetLocation(TK->GetLocation());
  FL->SetDeclarationContext(CTX->GetParentContext());
  SL->TransferDeclarations(FL->GetSymbolTable());
  ASTSymbolTable::Instance().TransferLocalContextSymbols(CTX,
                                                         FL->GetSymbolTable());
  FL->Mangle();

  STE->ResetValue();
  STE->SetValue(new ASTValue<>(FL, ASTTypeForLoop), ASTTypeForLoop);
  assert(STE->HasValue() &&
         "Could not create a Value for the ForLoop SymbolTable Entry!");

  ASTForStatementBuilder::Instance().Clear();
  ASTForStatementNode *FSN = new ASTForStatementNode(FL);
  assert(FSN && "Could not create an ASTForStatementNode!");

  FSN->SetLocation(TK->GetLocation());
  FSN->SetDeclarationContext(CTX->GetParentContext());
  FSN->Mangle();

  ASTSymbolTable::Instance().EraseLocalSymbol(LId, LId->GetBits(),
                                              LId->GetSymbolType());
  ASTDeclarationContextTracker::Instance().PopCurrentContext();
  return FSN;
}

ASTForStatementNode *ASTProductionFactory::ProductionRule_3211(
    const ASTToken *TK, ASTIntNode *IVT, ASTIdentifierNode *LId,
    ASTForLoopRangeExpressionNode *FLR, ASTStatement *ST) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(IVT && "Invalid ASTIntNode argument!");
  assert(LId && "Invalid ASTIdentifierNode argument!");
  assert(FLR && "Invalid ASTForLoopRangeExpressionNode argument!");
  assert(ST && "Invalid ASTStatement argument!");

  QasmFeatureTester::Instance().ValidateFeature("for");

  const ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  const_cast<ASTDeclarationContext *>(CTX)->SetContextType(ASTTypeForStatement);

  ASTScopeController::Instance().CheckOutOfScope(LId);
  if (!ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
          LId, ASTIntNode::IntBits, ASTTypeInt)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeInt.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(LId), M.str(), DiagLevel::ICE);
    return ASTForStatementNode::StatementError(M.str());
  }

  ASTSymbolTable::Instance().EraseUndefinedSymbol(LId->GetName());
  ASTScopeController::Instance().CheckOutOfScope(LId);
  LId->SetLocalScope();
  LId->SetDeclarationContext(CTX);

  ASTSymbolTableEntry *ISTE = ASTSymbolTable::Instance().Lookup(
      LId, LId->GetBits(), LId->GetSymbolType());
  assert(ISTE && "Invalid Loop Induction Variable SymbolTable Entry!");

  ISTE->ResetValue();
  ISTE->SetValue(new ASTValue<>(IVT, ASTTypeInt), ASTTypeInt);
  assert(ISTE->HasValue() && "Loop induction variable has no Value!");

  ASTStatementList *SL = new ASTStatementList();
  assert(SL && "Could not create a valid ASTStatementList!");

  SL->SetDeclarationContext(CTX);
  SL->SetLocalScope();
  ASTScopeController::Instance().SetDeclarationContext(SL, CTX);
  ASTDeclarationBuilder::Instance().CheckLoopInductionVariable(LId, SL, CTX);

  std::stringstream FLS;
  FLS << "ast-for-statement-"
      << DIAGLineCounter::Instance().GetIdentifierLocation();

  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      FLS.str(), ASTForLoopNode::ForLoopBits, ASTTypeForLoop);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());

  ASTSymbolTableEntry *STE =
      ASTSymbolTable::Instance().Lookup(Id, Id->GetBits(), Id->GetSymbolType());
  assert(STE && "Could not retrieve a valid ForLoop SymbolTable Entry!");
  assert(STE->GetValueType() == ASTTypeForLoop &&
         "Invalid ASTType for the ForLoop SymbolTable Entry!");

  ASTIntNode *LIV = ISTE->GetValue()->GetValue<ASTIntNode *>();
  assert(LIV && "Loop Induction Variable has a SymbolTable Entry with "
                "an invalid Type!");

  ASTForLoopNode *FL = new ASTForLoopNode(Id, FLR, *SL, LIV);
  assert(FL && "Could not create an ASTForLoopNode!");

  FL->SetLocation(TK->GetLocation());
  FL->SetDeclarationContext(CTX->GetParentContext());
  SL->TransferDeclarations(FL->GetSymbolTable());
  ASTSymbolTable::Instance().TransferLocalContextSymbols(CTX,
                                                         FL->GetSymbolTable());
  FL->Mangle();

  STE->ResetValue();
  STE->SetValue(new ASTValue<>(FL, ASTTypeForLoop), ASTTypeForLoop);
  assert(STE->HasValue() &&
         "Could not create a Value for the ForLoop SymbolTable Entry!");

  ASTForStatementBuilder::Instance().Clear();
  ASTForStatementNode *FSN = new ASTForStatementNode(FL);
  assert(FSN && "Could not create an ASTForStatementNode!");

  FSN->SetLocation(TK->GetLocation());
  FSN->SetDeclarationContext(CTX->GetParentContext());
  FSN->Mangle();

  ASTSymbolTable::Instance().EraseLocalSymbol(LId, LId->GetBits(),
                                              LId->GetSymbolType());
  ASTDeclarationContextTracker::Instance().PopCurrentContext();
  return FSN;
}

ASTWhileStatementNode *ASTProductionFactory::ProductionRule_3300(
    const ASTToken *TK, ASTExpressionNode *EN, ASTStatementList *SL) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(EN && "Invalid ASTExpressionNode argument!");
  assert(SL && "Invalid ASTStatementList argument!");

  QasmFeatureTester::Instance().ValidateFeature("while");
  ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  CTX->SetContextType(ASTTypeWhileStatement);

  std::stringstream WLS;
  WLS << "ast-while-statement-"
      << DIAGLineCounter::Instance().GetIdentifierLocation();

  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      WLS.str(), ASTWhileLoopNode::WhileLoopBits, ASTTypeWhileLoop);
  assert(Id && "Could not create a valid WhileLoop ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());

  if (!ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
          Id, ASTWhileLoopNode::WhileLoopBits, ASTTypeWhileLoop)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeWhileLoop.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTWhileStatementNode::StatementError(M.str());
  }

  ASTSymbolTableEntry *STE =
      ASTSymbolTable::Instance().Lookup(Id, Id->GetBits(), Id->GetSymbolType());
  assert(STE && "Could not retrieve a valid WhileLoop SymbolTable Entry!");
  assert(STE->GetValueType() == ASTTypeWhileLoop &&
         "Invalid ASTType for the WhileLoop SymbolTable Entry!");

  SL->SetDeclarationContext(CTX);
  ASTScopeController::Instance().SetDeclarationContext(SL, CTX);
  SL->SetLocalScope();

  ASTWhileLoopNode *WL = new ASTWhileLoopNode(Id, EN, SL);
  assert(WL && "Could not create a valid ASTWhileLoopNode!");

  WL->SetLocation(TK->GetLocation());
  WL->SetDeclarationContext(CTX->GetParentContext());
  SL->TransferDeclarations(WL->GetSymbolTable());
  ASTSymbolTable::Instance().TransferLocalContextSymbols(CTX,
                                                         WL->GetSymbolTable());
  WL->Mangle();

  STE->ResetValue();
  STE->SetValue(new ASTValue<>(WL, ASTTypeWhileLoop), ASTTypeWhileLoop);
  assert(STE->HasValue() && "WhileLoop SymbolTable Entry has no Value!");

  ASTWhileStatementNode *WSN = new ASTWhileStatementNode(WL);
  assert(WSN && "Could not create a valid ASTWhileStatementNode!");

  WSN->SetLocation(TK->GetLocation());
  WSN->SetDeclarationContext(CTX->GetParentContext());
  WSN->Mangle();

  ASTDeclarationContextTracker::Instance().PopCurrentContext();
  ASTIdentifierTypeController::Instance().Reset();
  ASTWhileBraceMatcher::Instance().Reset();
  return WSN;
}

ASTDoWhileStatementNode *ASTProductionFactory::ProductionRule_3400(
    const ASTToken *TK, ASTExpressionNode *EN, ASTStatementList *SL) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(EN && "Invalid ASTExpressionNode argument!");
  assert(SL && "Invalid ASTStatementList argument!");

  QasmFeatureTester::Instance().ValidateFeature("dowhile");
  ASTDeclarationContext *CTX =
      ASTDeclarationContextTracker::Instance().GetCurrentContext();
  assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

  CTX->SetContextType(ASTTypeDoWhileStatement);

  std::stringstream WLS;
  WLS << "ast-do-while-statement-"
      << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      WLS.str(), ASTDoWhileLoopNode::DoWhileLoopBits, ASTTypeDoWhileLoop);
  assert(Id && "Could not create a valid DoWhileLoop ASTIdentifierNode!");

  Id->SetLocation(TK->GetLocation());
  Id->SetDeclarationContext(CTX);

  if (!ASTSymbolTable::Instance().TransferLocalUndefinedSymbol(
          Id, ASTWhileLoopNode::WhileLoopBits, ASTTypeWhileLoop)) {
    std::stringstream M;
    M << "Could not transfer Symbol Table Entry for ASTTypeDoWhileLoop.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTDoWhileStatementNode::StatementError(M.str());
  }

  ASTSymbolTableEntry *STE =
      ASTSymbolTable::Instance().Lookup(Id, Id->GetBits(), Id->GetSymbolType());
  assert(STE && "Could not retrieve a valid DoWhileLoop SymbolTable Entry!");
  assert(STE->GetValueType() == ASTTypeDoWhileLoop &&
         "Invalid ASTType for the DoWhileLoop SymbolTable Entry!");

  SL->SetDeclarationContext(CTX);
  ASTScopeController::Instance().SetDeclarationContext(SL, CTX);
  SL->SetLocalScope();

  ASTDoWhileLoopNode *DWL = new ASTDoWhileLoopNode(Id, EN, SL);
  assert(DWL && "Could not create a valid ASTDoWhileLoopNode!");

  DWL->SetLocation(TK->GetLocation());
  DWL->SetDeclarationContext(CTX->GetParentContext());
  SL->TransferDeclarations(DWL->GetSymbolTable());
  ASTSymbolTable::Instance().TransferLocalContextSymbols(CTX,
                                                         DWL->GetSymbolTable());

  STE->ResetValue();
  STE->SetValue(new ASTValue<>(DWL, ASTTypeDoWhileLoop), ASTTypeDoWhileLoop);
  assert(STE->HasValue() && "DoWhileLoop SymbolTable Entry has no Value!");

  ASTDoWhileStatementNode *DWSN = new ASTDoWhileStatementNode(DWL);
  assert(DWSN && "Could not create a valid ASTDoWhileStatementNode!");

  DWSN->SetLocation(TK->GetLocation());
  DWSN->SetDeclarationContext(CTX->GetParentContext());
  ASTDeclarationContextTracker::Instance().PopCurrentContext();
  ASTIdentifierTypeController::Instance().Reset();
  ASTDoWhileBraceMatcher::Instance().Reset();

  return DWSN;
}

static bool TransferGateQubitParams(const ASTAnyTypeList &ATL) {
  for (unsigned I = 0; I < ATL.Size(); ++I) {
    const ASTIdentifierNode *AId = nullptr;
    if (ATL.IsIdentifier(I) && (AId = ATL.GetIdentifier(I)) != nullptr) {
      switch (AId->GetSymbolType()) {
      case ASTTypeGateQubitParam:
        if (!ASTSymbolTable::Instance().TransferGateQubitParam(AId))
          return false;
        break;
      default:
        break;
      }
    }
  }

  return true;
}

static bool ValidateQubitArgs(const ASTIdentifierNode *Id,
                              const ASTAnyTypeList *ATL) {
  const ASTSymbolTableEntry *STE = Id->GetSymbolTableEntry();
  if (!STE) {
    std::stringstream M;
    M << "Identifier '" << Id->GetName() << "' does not have a valid "
      << "SymbolTable Entry.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
    return false;
  }

  switch (Id->GetSymbolType()) {
  case ASTTypeGate: {
    ASTGateNode *G = STE->GetValue()->GetValue<ASTGateNode *>();
    assert(G && "Could not obtain a valid ASTGateNode!");
    ASTTypeDiscovery::Instance().ValidateGateQubitArgs(ATL, G);
  } break;
  case ASTTypeCNotGate: {
    ASTGateNode *G = STE->GetValue()->GetValue<ASTGateNode *>();
    assert(G && "Could not obtain a valid ASTCNotGateNode!");
    ASTTypeDiscovery::Instance().ValidateGateQubitArgs(ATL, G);
  } break;
  case ASTTypeCXGate: {
    ASTGateNode *G = STE->GetValue()->GetValue<ASTGateNode *>();
    assert(G && "Could not obtain a valid ASTCXGateNode!");
    ASTTypeDiscovery::Instance().ValidateGateQubitArgs(ATL, G);
  } break;
  case ASTTypeCCXGate: {
    ASTGateNode *G = STE->GetValue()->GetValue<ASTGateNode *>();
    assert(G && "Could not obtain a valid ASTCCXGateNode!");
    ASTTypeDiscovery::Instance().ValidateGateQubitArgs(ATL, G);
  } break;
  case ASTTypeHadamardGate: {
    ASTGateNode *G = STE->GetValue()->GetValue<ASTGateNode *>();
    assert(G && "Could not obtain a valid ASTHadamardGateNode!");
    ASTTypeDiscovery::Instance().ValidateGateQubitArgs(ATL, G);
  } break;
  case ASTTypeUGate: {
    ASTUGateNode *G = STE->GetValue()->GetValue<ASTUGateNode *>();
    assert(G && "Could not obtain a valid ASTUGateNode!");
    ASTTypeDiscovery::Instance().ValidateGateQubitArgs(ATL, G);
  } break;
  case ASTTypeDefcalGroup: {
    ASTDefcalGroupNode *DG = STE->GetValue()->GetValue<ASTDefcalGroupNode *>();
    assert(DG && "Could not obtain a valid ASTDefcalGroupNode!");
    DG->Mangle();
    ASTTypeDiscovery::Instance().ValidateDefcalQubitArgs(ATL, DG);
  } break;
  default:
    break;
  }

  return true;
}

ASTGateQOpNode *ValidateQubitArgs(const ASTAnyTypeList &ATL) {
  for (unsigned I = 0; I < ATL.Size(); ++I) {
    const ASTIdentifierNode *AId = nullptr;
    const ASTIdentifierRefNode *AIdR = nullptr;

    if (ATL.IsIdentifier(I) && (AId = ATL.GetIdentifier(I)) != nullptr) {
      ASTSymbolTableEntry *ASTE = ASTSymbolTable::Instance().Lookup(
          AId, AId->GetBits(), AId->GetSymbolType());
      assert(ASTE && "Invalid SymbolTable Entry for Gate Qubit argument!");

      if (!ASTE->HasValue() && ASTIdentifierNode::InvalidBits(AId->GetBits())) {
        const_cast<ASTIdentifierNode *>(AId)->SetLocalScope();
        const_cast<ASTIdentifierNode *>(AId)->SetGateLocal(true);
      } else {
        switch (ASTE->GetValueType()) {
        case ASTTypeQubit: {
          if (ASTE->HasValue()) {
            ASTQubitNode *QN = ASTE->GetValue()->GetValue<ASTQubitNode *>();
            assert(QN && "Invalid ASTQubitNode obtained from the SymbolTable!");

            if (!QN) {
              std::stringstream M;
              M << "ASTQubitNode without a valid SymbolTable Entry.";
              QasmDiagnosticEmitter::Instance().EmitDiagnostic(
                  DIAGLineCounter::Instance().GetLocation(AId), M.str(),
                  DiagLevel::ICE);
              return ASTGateQOpNode::StatementError(AId, M.str());
            }
          }
        } break;
        case ASTTypeQubitContainer: {
          if (ASTE->HasValue()) {
            ASTQubitContainerNode *QCN =
                ASTE->GetValue()->GetValue<ASTQubitContainerNode *>();
            assert(
                QCN &&
                "Invalid ASTQubitContainerNode obtained from the SymbolTable!");

            if (!QCN) {
              std::stringstream M;
              M << "ASTQubitContainerNode without a valid SymbolTable Entry.";
              QasmDiagnosticEmitter::Instance().EmitDiagnostic(
                  DIAGLineCounter::Instance().GetLocation(AId), M.str(),
                  DiagLevel::ICE);
              return ASTGateQOpNode::StatementError(AId, M.str());
            }
          }
        } break;
        case ASTTypeGateQubitParam: {
          if (!ASTSymbolTable::Instance().TransferGateQubitParam(AId)) {
            std::stringstream M;
            M << "Failure transferring scope of Gate Qubit Parameter.";
            QasmDiagnosticEmitter::Instance().EmitDiagnostic(
                DIAGLineCounter::Instance().GetLocation(AId), M.str(),
                DiagLevel::ICE);
            return ASTGateQOpNode::StatementError(AId, M.str());
          }
        } break;
        default:
          break;
        }
      }
    } else if (ATL.IsIdentifierRef(I) &&
               (AIdR = ATL.GetIdentifierRef(I)) != nullptr) {
      ASTSymbolTableEntry *ASTE = ASTSymbolTable::Instance().Lookup(
          AIdR, AIdR->GetBits(), AIdR->GetSymbolType());
      if (!ASTE) {
        ASTE = ASTSymbolTable::Instance().LookupLocal(
            AIdR->GetName(), AIdR->GetBits(), AIdR->GetSymbolType());
        if (!ASTE && (AIdR->GetSymbolType() == ASTTypeQubitContainer ||
                      AIdR->GetSymbolType() == ASTTypeQubitContainerAlias)) {
          ASTE = ASTSymbolTable::Instance().LookupLocal(
              AIdR->GetName(), AIdR->GetBits(), ASTTypeQubit);
        }

        if (!ASTE) {
          std::stringstream M;
          M << "ASTIdentifierRefNode without a valid SymbolTable Entry.";
          QasmDiagnosticEmitter::Instance().EmitDiagnostic(
              DIAGLineCounter::Instance().GetLocation(AIdR), M.str(),
              DiagLevel::ICE);
          return ASTGateQOpNode::StatementError(AIdR->GetIdentifier(), M.str());
        }
      }

      assert(ASTE && "Invalid SymbolTable Entry for Gate Qubit argument!");

      if (!ASTE->HasValue() &&
          ASTIdentifierNode::InvalidBits(AIdR->GetBits())) {
        const_cast<ASTIdentifierNode *>(AId)->SetLocalScope();
        const_cast<ASTIdentifierNode *>(AId)->SetGateLocal(true);
      } else {
        switch (ASTE->GetValueType()) {
        case ASTTypeQubit: {
          if (ASTE->HasValue()) {
            ASTQubitNode *QN = ASTE->GetValue()->GetValue<ASTQubitNode *>();
            assert(QN && "Invalid ASTQubitNode obtained from the SymbolTable!");

            if (!QN) {
              std::stringstream M;
              M << "ASTQubitNode without a valid SymbolTable Entry.";
              QasmDiagnosticEmitter::Instance().EmitDiagnostic(
                  DIAGLineCounter::Instance().GetLocation(AIdR), M.str(),
                  DiagLevel::ICE);
              return ASTGateQOpNode::StatementError(AIdR->GetIdentifier(),
                                                    M.str());
            }
          }
        } break;
        case ASTTypeQubitContainer: {
          if (ASTE->HasValue()) {
            ASTQubitContainerNode *QCN =
                ASTE->GetValue()->GetValue<ASTQubitContainerNode *>();
            assert(
                QCN &&
                "Invalid ASTQubitContainerNode obtained from the SymbolTable!");

            if (!QCN) {
              std::stringstream M;
              M << "ASTQubitContainerNode without a valid SymbolTable Entry.";
              QasmDiagnosticEmitter::Instance().EmitDiagnostic(
                  DIAGLineCounter::Instance().GetLocation(AIdR), M.str(),
                  DiagLevel::ICE);
              return ASTGateQOpNode::StatementError(AIdR->GetIdentifier(),
                                                    M.str());
            }

            ASTQubitNode *QN = QCN->GetQubit(AIdR->GetIndex());
            assert(QN && "Invalid ASTQubitNode obtained from the "
                         "ASTQubitContainerNode!");
            if (!QN) {
              std::stringstream M;
              M << "Invalid ASTQubitNode obtained from the "
                   "ASTQubitContainerNode.";
              QasmDiagnosticEmitter::Instance().EmitDiagnostic(
                  DIAGLineCounter::Instance().GetLocation(AIdR), M.str(),
                  DiagLevel::ICE);
              return ASTGateQOpNode::StatementError(AIdR->GetIdentifier(),
                                                    M.str());
            }
          }
        } break;
        case ASTTypeGateQubitParam:
          break;
        default:
          break;
        }
      }
    }
  }

  return nullptr;
}

static ASTGateQOpNode *CreateCXGateCall(const ASTToken *TK,
                                        const ASTIdentifierNode *Id,
                                        const ASTArgumentNodeList &ANL,
                                        const ASTAnyTypeList &ATL) {
  if (Id->GetName() != "cx") {
    std::stringstream M;
    M << "Invalid cx Gate call construction function called.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return nullptr;
  }

  const ASTSymbolTableEntry *STE = ASTSymbolTable::Instance().FindGate(Id);
  if (!STE) {
    std::stringstream M;
    M << "Gate " << Id->GetName() << " definition has no SymbolTable Entry.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return nullptr;
  }

  if (!STE->HasValue()) {
    std::stringstream M;
    M << "SymbolTable Entry for Gate " << Id->GetName() << " has no Value.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return nullptr;
  }

  ASTCXGateNode *GN =
      dynamic_cast<ASTCXGateNode *>(STE->GetValue()->GetValue<ASTGateNode *>());
  assert(GN && "Invalid cx ASTGateNode obtained from the SymbolTable!");

  ASTCXGateNode *CXGN = GN->CloneCall(Id, ANL, ATL);
  assert(CXGN && "Could not create a valid ASTCXGateNode!");

  CXGN->SetLocation(TK->GetLocation());
  CXGN->Mangle();
  ASTGateNodeBuilder::Instance().Append(CXGN);

  ASTGateQOpNode *RG =
      ASTGateOpBuilder::Instance().CreateASTCXGateOpNode(Id, CXGN);
  assert(RG && "Could not create a valid ASTCXGateOpNode!");

  RG->SetLocation(TK->GetLocation());
  RG->Mangle();
  return RG;
}

static ASTGateQOpNode *CreateCCXGateCall(const ASTToken *TK,
                                         const ASTIdentifierNode *Id,
                                         const ASTArgumentNodeList &ANL,
                                         const ASTAnyTypeList &ATL) {
  if (Id->GetName() != "ccx") {
    std::stringstream M;
    M << "Invalid ccx Gate call construction function called.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return nullptr;
  }

  const ASTSymbolTableEntry *STE = ASTSymbolTable::Instance().FindGate(Id);
  if (!STE) {
    std::stringstream M;
    M << "Gate " << Id->GetName() << " definition has no SymbolTable Entry.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return nullptr;
  }

  if (!STE->HasValue()) {
    std::stringstream M;
    M << "SymbolTable Entry for Gate " << Id->GetName() << " has no Value.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return nullptr;
  }

  ASTCCXGateNode *GN = dynamic_cast<ASTCCXGateNode *>(
      STE->GetValue()->GetValue<ASTGateNode *>());
  assert(GN && "Invalid ccx ASTGateNode obtained from the SymbolTable!");

  ASTCCXGateNode *CCXGN = GN->CloneCall(Id, ANL, ATL);
  assert(CCXGN && "Could not create a valid ASTCCXGateNode!");

  CCXGN->SetLocation(TK->GetLocation());
  CCXGN->Mangle();
  ASTGateNodeBuilder::Instance().Append(CCXGN);

  ASTGateQOpNode *RG =
      ASTGateOpBuilder::Instance().CreateASTCCXGateOpNode(Id, CCXGN);
  assert(RG && "Failed to create a valid ASTCCXGateOpNode!");

  RG->SetLocation(TK->GetLocation());
  RG->Mangle();
  return RG;
}

static ASTGateQOpNode *CreateCNOTGateCall(const ASTToken *TK,
                                          const ASTIdentifierNode *Id,
                                          const ASTArgumentNodeList &ANL,
                                          const ASTAnyTypeList &ATL) {
  if (Id->GetName() != "cnot") {
    std::stringstream M;
    M << "Invalid cnot Gate call construction function called.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return nullptr;
  }

  const ASTSymbolTableEntry *STE = ASTSymbolTable::Instance().FindGate(Id);
  if (!STE) {
    std::stringstream M;
    M << "Gate " << Id->GetName() << " definition has no SymbolTable Entry.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return nullptr;
  }

  if (!STE->HasValue()) {
    std::stringstream M;
    M << "SymbolTable Entry for Gate " << Id->GetName() << " has no Value.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return nullptr;
  }

  ASTCNotGateNode *GN = dynamic_cast<ASTCNotGateNode *>(
      STE->GetValue()->GetValue<ASTGateNode *>());
  assert(GN && "Invalid cnot ASTGateNode obtained from the SymbolTable!");

  ASTCNotGateNode *CNGN = GN->CloneCall(Id, ANL, ATL);
  assert(CNGN && "Could not create a valid ASTCNotGateNode!");

  CNGN->SetLocation(TK->GetLocation());
  CNGN->Mangle();
  ASTGateNodeBuilder::Instance().Append(CNGN);

  ASTGateQOpNode *RG =
      ASTGateOpBuilder::Instance().CreateASTCNotGateOpNode(Id, CNGN);
  assert(RG && "Failed to create a valid ASTCCXGateOpNode!");

  RG->SetLocation(TK->GetLocation());
  RG->Mangle();
  return RG;
}

static ASTGateQOpNode *CreateHadamardGateCall(const ASTToken *TK,
                                              const ASTIdentifierNode *Id,
                                              const ASTArgumentNodeList &ANL,
                                              const ASTAnyTypeList &ATL) {
  if (Id->GetName() != "h") {
    std::stringstream M;
    M << "Invalid h Gate call construction function called.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return nullptr;
  }

  const ASTSymbolTableEntry *STE = ASTSymbolTable::Instance().FindGate(Id);
  if (!STE) {
    std::stringstream M;
    M << "Gate " << Id->GetName() << " definition has no SymbolTable Entry.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return nullptr;
  }

  if (!STE->HasValue()) {
    std::stringstream M;
    M << "SymbolTable Entry for Gate " << Id->GetName() << " has no Value.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return nullptr;
  }

  ASTHadamardGateNode *GN = dynamic_cast<ASTHadamardGateNode *>(
      STE->GetValue()->GetValue<ASTGateNode *>());
  assert(GN && "Invalid h ASTGateNode obtained from the SymbolTable!");

  ASTHadamardGateNode *HGN = GN->CloneCall(Id, ANL, ATL);
  assert(HGN && "Could not create a valid ASTHadamardGateNode!");

  HGN->SetLocation(TK->GetLocation());
  HGN->Mangle();
  ASTGateNodeBuilder::Instance().Append(HGN);

  ASTGateQOpNode *RG =
      ASTGateOpBuilder::Instance().CreateASTHGateOpNode(Id, HGN);
  assert(RG && "Failed to create a valid ASTHGateOpNode!");

  RG->SetLocation(TK->GetLocation());
  RG->Mangle();
  return RG;
}

static ASTGateQOpNode *CreateUGateCall(const ASTToken *TK,
                                       const ASTIdentifierNode *Id,
                                       const ASTArgumentNodeList &ANL,
                                       const ASTAnyTypeList &ATL) {
  if (Id->GetName() != "U") {
    std::stringstream M;
    M << "Invalid U Gate call construction function called.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return nullptr;
  }

  const ASTSymbolTableEntry *STE = ASTSymbolTable::Instance().FindGate(Id);
  if (!STE) {
    std::stringstream M;
    M << "Gate " << Id->GetName() << " definition has no SymbolTable Entry.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return nullptr;
  }

  if (!STE->HasValue()) {
    std::stringstream M;
    M << "SymbolTable Entry for Gate " << Id->GetName() << " has no Value.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return nullptr;
  }

  ASTUGateNode *GN =
      dynamic_cast<ASTUGateNode *>(STE->GetValue()->GetValue<ASTGateNode *>());
  assert(GN && "Invalid h ASTGateNode obtained from the SymbolTable!");

  ASTUGateNode *UGN = GN->CloneCall(Id, ANL, ATL);
  assert(UGN && "Could not create a valid ASTHadamardGateNode!");

  UGN->SetLocation(TK->GetLocation());
  UGN->Mangle();
  ASTGateNodeBuilder::Instance().Append(UGN);

  ASTGateQOpNode *RG =
      ASTGateOpBuilder::Instance().CreateASTUGateOpNode(Id, UGN);
  assert(RG && "Failed to create a valid ASTHGateOpNode!");

  RG->SetLocation(TK->GetLocation());
  RG->Mangle();
  return RG;
}

static ASTGateQOpNode *CreateDefcalCall(const ASTToken *TK,
                                        const ASTSymbolTableEntry *STE,
                                        const ASTIdentifierNode *Id,
                                        const ASTArgumentNodeList &ANL,
                                        const ASTAnyTypeList &ATL) {
  ASTDefcalNode *DN = STE->GetValue()->GetValue<ASTDefcalNode *>();
  if (!DN) {
    std::stringstream M;
    M << "Invalid ASTDefcalNode " << Id->GetName() << " obtained from "
      << "the SymbolTable.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return nullptr;
  }

  ASTDefcalNode *RDN = DN->CloneCall(Id, ANL, ATL);
  assert(RDN && "Could not create a valid ASTDefcalNode!");

  RDN->SetLocation(TK->GetLocation());
  RDN->SetDefcalCall(true);
  RDN->Mangle();

  ASTGateQOpNode *RD =
      ASTGateOpBuilder::Instance().CreateASTGenericDefcalOpNode(Id, RDN);
  assert(RD && "Failed to create an ASTGenericGateOpNode!");

  RD->SetLocation(TK->GetLocation());
  RD->Mangle();
  return RD;
}

static ASTGateQOpNode *CreateDefcalGroupCall(const ASTToken *TK,
                                             const ASTIdentifierNode *Id,
                                             const ASTArgumentNodeList &ANL,
                                             const ASTAnyTypeList &ATL) {
  std::vector<const ASTSymbolTableEntry *> DGV =
      ASTSymbolTable::Instance().GetDefcalGroup(Id->GetName());
  if (DGV.empty()) {
    std::stringstream M;
    M << "Defcal Group " << Id->GetName()
      << " contains no "
         "callable Defcals.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return nullptr;
  }

  // FIXME: This needs Defcal Overload Resolution.
  const ASTSymbolTableEntry *DSTE = DGV.back();
  if (!DSTE) {
    std::stringstream M;
    M << "Invalid Defcal SymbolTable Entry obtained from Defcal Group.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return nullptr;
  }

  ASTDefcalNode *DN = DSTE->GetValue()->GetValue<ASTDefcalNode *>();
  if (!DN) {
    std::stringstream M;
    M << "Invalid ASTDefcalNode " << Id->GetName() << " obtained from "
      << "the SymbolTable.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::Error);
    return nullptr;
  }

  ASTDefcalNode *RDN = DN->CloneCall(Id, ANL, ATL);
  assert(RDN && "Could not create a valid ASTDefcalNode!");

  RDN->SetLocation(TK->GetLocation());
  RDN->SetDefcalCall(true);
  RDN->Mangle();

  ASTGateQOpNode *RD =
      ASTGateOpBuilder::Instance().CreateASTGenericDefcalOpNode(Id, RDN);
  assert(RD && "Failed to create a valid Defcal ASGateQOpNode!");

  RD->SetLocation(TK->GetLocation());
  RD->Mangle();
  return RD;
}

static ASTGateQOpNode *CreateGateCall(const ASTToken *TK,
                                      const ASTSymbolTableEntry *STE,
                                      const ASTIdentifierNode *Id,
                                      const ASTArgumentNodeList &ANL,
                                      const ASTAnyTypeList &ATL) {
  ASTGateNode *GN = STE->GetValue()->GetValue<ASTGateNode *>();
  if (!GN) {
    std::stringstream M;
    M << "Invalid ASTGateNode " << Id->GetName() << " used in constructing "
      << " a Gate call.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return nullptr;
  }

  ASTGateNode *GGN = GN->CloneCall(Id, ANL, ATL);
  assert(GGN && "Could not create a valid ASTGateNode call!");

  ASTGateNodeBuilder::Instance().Append(GGN);
  ASTGateQOpNode *RG =
      ASTGateOpBuilder::Instance().CreateASTGenericGateOpNode(Id, GGN);
  assert(RG && "Failed to create a valid ASTGenericGateOpNode!");

  RG->SetLocation(TK->GetLocation());
  RG->Mangle();
  return RG;
}

static ASTGateQOpNode *CreateQOpNodeCall(const ASTToken *TK,
                                         const ASTIdentifierNode *Id,
                                         const ASTArgumentNodeList &ANL,
                                         const ASTAnyTypeList &ATL) {
  const ASTSymbolTableEntry *STE =
      ASTSymbolTable::Instance().Lookup(Id, Id->GetBits(), Id->GetSymbolType());
  if (!STE) {
    std::stringstream M;
    M << "Callable object has no SymbolTable Entry.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTGateQOpNode::StatementError(Id, M.str());
  }

  if (!STE->HasValue()) {
    std::stringstream M;
    M << "Callable object has no SymbolTable Entry Value.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTGateQOpNode::StatementError(Id, M.str());
  }

  ASTGateQOpNode *RQO = nullptr;

  switch (STE->GetValueType()) {
  case ASTTypeDefcal:
    RQO = CreateDefcalCall(TK, STE, Id, ANL, ATL);
    break;
  case ASTTypeDefcalGroup:
    RQO = CreateDefcalGroupCall(TK, Id, ANL, ATL);
    break;
  case ASTTypeGate:
    RQO = CreateGateCall(TK, STE, Id, ANL, ATL);
    break;
  case ASTTypeCXGate:
    RQO = CreateCXGateCall(TK, Id, ANL, ATL);
    break;
  case ASTTypeCCXGate:
    RQO = CreateCCXGateCall(TK, Id, ANL, ATL);
    break;
  case ASTTypeCNotGate:
    RQO = CreateCNOTGateCall(TK, Id, ANL, ATL);
    break;
  case ASTTypeHadamardGate:
    RQO = CreateHadamardGateCall(TK, Id, ANL, ATL);
    break;
  case ASTTypeUGate:
    RQO = CreateUGateCall(TK, Id, ANL, ATL);
    break;
  case ASTTypeFunction: {
    std::stringstream M;
    M << "A GateQOpNode cannot materialize a function call.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTGateQOpNode::StatementError(Id, M.str());
  } break;
  default: {
    std::stringstream M;
    M << "Unexpected type " << PrintTypeEnum(Id->GetSymbolType())
      << " used in materializing a GateEOp call expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTGateQOpNode::StatementError(Id, M.str());
  } break;
  }

  return RQO;
}

ASTGateQOpNode *ASTProductionFactory::ProductionRule_3500(
    const ASTToken *TK, const ASTIdentifierNode *Id,
    const ASTArgumentNodeList *ANL, const ASTAnyTypeList *ATL) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(Id && "Invalid ASTIdentifierNode argument!");
  assert(ANL && "Invalid ASTArgumentNodeList argument!");
  assert(ATL && "Invalid ASTAnyTypeList argument!");

  ASTIdentifierTypeController::Instance().SetCurrentType(ASTTypeGateCall);
  ASTScopeController::Instance().CheckOutOfScope(Id);
  ASTIdentifierTypeController::Instance().CheckIsCallable(Id);

  if (!TransferGateQubitParams(*ATL)) {
    std::stringstream M;
    M << "Failure transferring scope of Gate Qubit Parameter.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(Id), M.str(), DiagLevel::ICE);
    return ASTGateQOpNode::StatementError(Id, M.str());
  }

  if (ASTGateQOpNode *QOp = ValidateQubitArgs(*ATL)) {
    std::stringstream M;
    M << "Failure validating Qubit arguments.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return QOp;
  }

  ASTGateQOpNode *RQO = nullptr;
  ASTType CTy = ASTTypeGate;

  if (Id->GetName() == "cx") {
    RQO = CreateCXGateCall(TK, Id, *ANL, *ATL);
  } else if (Id->GetName() == "ccx") {
    RQO = CreateCCXGateCall(TK, Id, *ANL, *ATL);
  } else if (Id->GetName() == "cnot") {
    RQO = CreateCNOTGateCall(TK, Id, *ANL, *ATL);
  } else if (Id->GetName() == "h") {
    RQO = CreateHadamardGateCall(TK, Id, *ANL, *ATL);
  } else {
    RQO = CreateQOpNodeCall(TK, Id, *ANL, *ATL);
    CTy = Id->GetSymbolType();
  }

  assert(RQO && "Could not create a valid Gate Call!");

  if (!ValidateQubitArgs(Id, ATL)) {
    std::stringstream M;
    M << "Failure validating Qubit arguments.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTGateQOpNode::StatementError(Id, M.str());
  }

  RQO->SetLocation(TK->GetLocation());

  if (!RQO->IsError())
    RQO->Mangle();

  if (CTy == ASTTypeGate)
    ASTGateContextBuilder::Instance().CloseContext();
  else if (CTy == ASTTypeDefcal || CTy == ASTTypeDefcalGroup)
    ASTDefcalContextBuilder::Instance().CloseContext();

  ASTIdentifierTypeController::Instance().Reset();
  return RQO;
}

ASTGateQOpNode *
ASTProductionFactory::ProductionRule_3502(const ASTToken *TK,
                                          const ASTArgumentNodeList *ANL,
                                          const ASTAnyTypeList *ATL) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(ANL && "Invalid ASTArgumentNodeList argument!");
  assert(ATL && "Invalid ASTAnyTypeList argument!");

  ASTIdentifierTypeController::Instance().SetCurrentType(ASTTypeGateCall);

  if (ANL->Size() != 3U) {
    std::stringstream M;
    M << "The U Gate accepts exactly 3 angle arguments.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTGateQOpNode::StatementError(M.str());
  }

  if (ATL->Size() < 1U && ATL->Size() > 2U) {
    std::stringstream M;
    M << "The U Gate accepts either one or two qubit parameter.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTGateQOpNode::StatementError(M.str());
  }

  for (unsigned I = 0; I < ATL->Size(); ++I) {
    if (ATL->IsIdentifier(I)) {
      const ASTIdentifierNode *QId = ATL->GetIdentifier(I);
      assert(QId && "Invalid Qubit ASTIdentifierNode from ASTAnyTypeList!");

      if (!ASTStringUtils::Instance().IsBoundQubit(QId->GetName()))
        QId->SetGateLocal(true);
    }
  }

  ASTIdentifierNode *Id = ASTBuilder::Instance().FindASTIdentifierNode(
      TK->GetString(), ASTGateNode::GateBits, ASTTypeUGate);
  if (!Id) {
    std::stringstream M;
    M << "A Gate (" << TK->GetString() << ") without a definition "
      << "cannot materialize a Gate call expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTGateQOpNode::StatementError(M.str());
  }

  const ASTSymbolTableEntry *STE = ASTSymbolTable::Instance().FindGate(Id);
  if (!STE) {
    std::stringstream M;
    M << TK->GetString() << " Gate has no SymbolTable Entry.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTGateQOpNode::StatementError(Id, M.str());
  }

  if (!STE->HasValue()) {
    std::stringstream M;
    M << TK->GetString() << " Gate SymbolTable Entry has no Value.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTGateQOpNode::StatementError(Id, M.str());
  }

  ASTUGateNode *UGN =
      dynamic_cast<ASTUGateNode *>(STE->GetValue()->GetValue<ASTGateNode *>());
  assert(UGN && "Could not obtain a valid U-Gate ASTGateNode!");

  ASTUGateNode *UGA = UGN->CloneCall(Id, *ANL, *ATL);
  assert(UGA && "Failed to create an ASTUGateNode!");

  UGA->SetLocation(TK->GetLocation());
  UGA->Mangle();

  ASTGateQOpNode *RG =
      ASTGateOpBuilder::Instance().CreateASTUGateOpNode(Id, UGA);
  assert(RG && "Failed to create a valid ASTUGateOpNode!");

  RG->SetLocation(TK->GetLocation());
  RG->Mangle();

  ASTGateContextBuilder::Instance().CloseContext();
  ASTIdentifierTypeController::Instance().Reset();
  return RG;
}

ASTGateQOpNode *
ASTProductionFactory::ProductionRule_3503(const ASTToken *TK,
                                          const ASTIdentifierList *IL) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(IL && "Invalid ASTIdentifierList argument!");

  ASTIdentifierTypeController::Instance().SetCurrentType(ASTTypeGateCall);

  if (IL->Size() != 2U) {
    std::stringstream M;
    M << "The cx Gate accepts exactly two qubit parameters.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTGateQOpNode::StatementError(M.str());
  }

  ASTIdentifierNode *Id = ASTBuilder::Instance().FindASTIdentifierNode(
      TK->GetString(), ASTGateNode::GateBits, ASTTypeCXGate);
  if (!Id) {
    std::stringstream M;
    M << "A Gate (" << TK->GetString() << ") without a definition "
      << "cannot materialize a Gate call expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTGateQOpNode::StatementError(M.str());
  }

  const ASTSymbolTableEntry *STE = ASTSymbolTable::Instance().FindGate(Id);
  if (!STE) {
    std::stringstream M;
    M << TK->GetString() << " Gate has no SymbolTable Entry.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTGateQOpNode::StatementError(Id, M.str());
  }

  if (!STE->HasValue()) {
    std::stringstream M;
    M << TK->GetString() << " Gate SymbolTable Entry has no Value.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTGateQOpNode::StatementError(Id, M.str());
  }

  for (ASTIdentifierList::const_iterator I = IL->begin(); I != IL->end(); ++I)
    if (!ASTStringUtils::Instance().IsBoundQubit((*I)->GetName()))
      const_cast<ASTIdentifierNode *>(*I)->SetGateLocal(true);

  ASTCXGateNode *CXG =
      dynamic_cast<ASTCXGateNode *>(STE->GetValue()->GetValue<ASTGateNode *>());
  assert(CXG && "Could not obtain a valid CX Gate ASTCXGateNode!");

  ASTParameterList PL;
  ASTCXGateNode *CXGC = CXG->CloneCall(Id, PL, *IL);
  assert(CXGC && "Could not obtain a valid CX Gate ASTGateNode!");

  CXGC->SetLocation(TK->GetLocation());
  CXGC->Mangle();

  ASTGateQOpNode *RG =
      ASTGateOpBuilder::Instance().CreateASTCXGateOpNode(Id, CXGC);
  assert(RG && "Could not create a valid ASTCXGateOpNode!");

  RG->SetLocation(TK->GetLocation());
  RG->Mangle();

  const_cast<ASTIdentifierList *>(IL)->Clear();
  ASTGateContextBuilder::Instance().CloseContext();
  ASTIdentifierTypeController::Instance().Reset();
  return RG;
}

ASTGateQOpNode *
ASTProductionFactory::ProductionRule_3504(const ASTToken *TK,
                                          const ASTArgumentNodeList *ANL,
                                          const ASTAnyTypeList *ATL) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(ANL && "Invalid ASTArgumentNodeList argument!");
  assert(ATL && "Invalid ASTAnyTypeList argument!");

  ASTIdentifierTypeController::Instance().SetCurrentType(ASTTypeGateCall);

  for (unsigned I = 0; I < ATL->Size(); ++I) {
    if (ATL->IsIdentifier(I)) {
      const ASTIdentifierNode *QId = ATL->GetIdentifier(I);
      assert(QId && "Invalid Qubit ASTIdentifierNode from ASTAnyTypeList!");

      if (!ASTStringUtils::Instance().IsBoundQubit(QId->GetName()))
        QId->SetGateLocal(true);
    }
  }

  ASTIdentifierNode *Id = ASTBuilder::Instance().FindASTIdentifierNode(
      TK->GetString(), ASTGateNode::GateBits, ASTTypeCCXGate);
  if (!Id) {
    std::stringstream M;
    M << "A Gate (" << TK->GetString() << ") without a definition "
      << "cannot materialize a Gate call expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTGateQOpNode::StatementError(M.str());
  }

  const ASTSymbolTableEntry *STE = ASTSymbolTable::Instance().FindGate(Id);
  if (!STE) {
    std::stringstream M;
    M << TK->GetString() << " Gate has no SymbolTable Entry.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTGateQOpNode::StatementError(Id, M.str());
  }

  if (!STE->HasValue()) {
    std::stringstream M;
    M << TK->GetString() << " Gate SymbolTable Entry has no Value.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTGateQOpNode::StatementError(Id, M.str());
  }

  ASTCCXGateNode *CCXG = dynamic_cast<ASTCCXGateNode *>(
      STE->GetValue()->GetValue<ASTGateNode *>());
  assert(CCXG && "Could not obtain a valid CCX Gate ASTCCXGateNode!");

  ASTCCXGateNode *CCXGC = CCXG->CloneCall(Id, *ANL, *ATL);
  assert(CCXGC && "Could not obtain a valid CCX Gate ASTCCXGateNode!");

  CCXGC->SetLocation(TK->GetLocation());
  CCXGC->Mangle();

  ASTGateQOpNode *RG =
      ASTGateOpBuilder::Instance().CreateASTCCXGateOpNode(Id, CCXGC);
  assert(RG && "Could not create a valid ASTCCXGateOpNode!");

  RG->SetLocation(TK->GetLocation());
  RG->Mangle();

  ASTGateContextBuilder::Instance().CloseContext();
  ASTIdentifierTypeController::Instance().Reset();
  return RG;
}

ASTGateQOpNode *
ASTProductionFactory::ProductionRule_3505(const ASTToken *TK,
                                          const ASTArgumentNodeList *ANL,
                                          const ASTAnyTypeList *ATL) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(ANL && "Invalid ASTArgumentNodeList argument!");
  assert(ATL && "Invalid ASTAnyTypeList argument!");

  ASTIdentifierTypeController::Instance().SetCurrentType(ASTTypeGateCall);

  for (unsigned I = 0; I < ATL->Size(); ++I) {
    if (ATL->IsIdentifier(I)) {
      const ASTIdentifierNode *QId = ATL->GetIdentifier(I);
      assert(QId && "Invalid Qubit ASTIdentifierNode from ASTAnyTypeList!");

      if (!ASTStringUtils::Instance().IsBoundQubit(QId->GetName()))
        QId->SetGateLocal(true);
    }
  }

  ASTIdentifierNode *Id = ASTBuilder::Instance().FindASTIdentifierNode(
      TK->GetString(), ASTGateNode::GateBits, ASTTypeCCXGate);
  if (!Id) {
    std::stringstream M;
    M << "A Gate (" << TK->GetString() << ") without a definition "
      << "cannot materialize a Gate call expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTGateQOpNode::StatementError(M.str());
  }

  const ASTSymbolTableEntry *STE = ASTSymbolTable::Instance().FindGate(Id);
  if (!STE) {
    std::stringstream M;
    M << TK->GetString() << " Gate has no SymbolTable Entry.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTGateQOpNode::StatementError(Id, M.str());
  }

  if (!STE->HasValue()) {
    std::stringstream M;
    M << TK->GetString() << " Gate SymbolTable Entry has no Value.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTGateQOpNode::StatementError(Id, M.str());
  }

  ASTCNotGateNode *CNG = dynamic_cast<ASTCNotGateNode *>(
      STE->GetValue()->GetValue<ASTGateNode *>());
  assert(CNG && "Could not obtain a valid CNot Gate ASTCNotGateNode!");

  ASTCNotGateNode *CNGC = CNG->CloneCall(Id, *ANL, *ATL);
  assert(CNGC && "Could not obtain a valid CNot Gate ASTCNotGateNode!");

  CNGC->SetLocation(TK->GetLocation());
  CNGC->Mangle();

  ASTGateQOpNode *RG =
      ASTGateOpBuilder::Instance().CreateASTCNotGateOpNode(Id, CNGC);
  assert(RG && "Could not create a valid ASTCNotGateOpNode!");

  RG->SetLocation(TK->GetLocation());
  RG->Mangle();

  ASTGateContextBuilder::Instance().CloseContext();
  ASTIdentifierTypeController::Instance().Reset();
  return RG;
}

ASTGateQOpNode *
ASTProductionFactory::ProductionRule_3506(const ASTToken *TK,
                                          const ASTArgumentNodeList *ANL,
                                          const ASTAnyTypeList *ATL) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(ANL && "Invalid ASTArgumentNodeList argument!");
  assert(ATL && "Invalid ASTAnyTypeList argument!");

  ASTIdentifierTypeController::Instance().SetCurrentType(ASTTypeGateCall);

  if (ATL->Size() != 1U) {
    std::stringstream M;
    M << "The h gate accepts exactly one qubit parameter.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTGateQOpNode::StatementError(M.str());
  }

  for (unsigned I = 0; I < ATL->Size(); ++I) {
    if (ATL->IsIdentifier(I)) {
      const ASTIdentifierNode *QId = ATL->GetIdentifier(I);
      assert(QId && "Invalid Qubit ASTIdentifierNode from ASTAnyTypeList!");

      if (!ASTStringUtils::Instance().IsBoundQubit(QId->GetName()))
        QId->SetGateLocal(true);
    }
  }

  ASTIdentifierNode *Id = ASTBuilder::Instance().FindASTIdentifierNode(
      TK->GetString(), ASTGateNode::GateBits, ASTTypeCCXGate);
  if (!Id) {
    std::stringstream M;
    M << "A Gate (" << TK->GetString() << ") without a definition "
      << "cannot materialize a Gate call expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTGateQOpNode::StatementError(M.str());
  }

  const ASTSymbolTableEntry *STE = ASTSymbolTable::Instance().FindGate(Id);
  if (!STE) {
    std::stringstream M;
    M << TK->GetString() << " Gate has no SymbolTable Entry.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTGateQOpNode::StatementError(Id, M.str());
  }

  if (!STE->HasValue()) {
    std::stringstream M;
    M << TK->GetString() << " Gate SymbolTable Entry has no Value.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
    return ASTGateQOpNode::StatementError(Id, M.str());
  }

  ASTHadamardGateNode *HDG = dynamic_cast<ASTHadamardGateNode *>(
      STE->GetValue()->GetValue<ASTGateNode *>());
  assert(HDG && "Could not obtain a valid H Gate ASTHadamardGateNode!");

  ASTHadamardGateNode *CHDG = HDG->CloneCall(Id, *ANL, *ATL);
  assert(CHDG && "Could not obtain a valid H Gate ASTHadamardGateNode!");

  CHDG->SetLocation(TK->GetLocation());
  CHDG->Mangle();

  ASTGateQOpNode *RG =
      ASTGateOpBuilder::Instance().CreateASTHGateOpNode(Id, CHDG);
  assert(RG && "Could not create a valid ASTCNotGateOpNode!");

  RG->SetLocation(TK->GetLocation());
  RG->Mangle();

  ASTGateContextBuilder::Instance().CloseContext();
  ASTIdentifierTypeController::Instance().Reset();
  return RG;
}

ASTGateQOpNode *ASTProductionFactory::ProductionRule_3507(
    const ASTToken *TK, const ASTGPhaseExpressionNode *GPE) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(GPE && "Invalid ASTGPhaseExpressionNode argument!");

  ASTGateQOpNode *GQO = new ASTGateQOpNode(GPE->GetIdentifier(), GPE);
  assert(GQO && "Could not create a valid GPhase ASTGateQOpNode!");

  if (!GQO) {
    std::stringstream M;
    M << "Could not create a valid GPhase ASTGateQOpNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTGateQOpNode::StatementError(GPE->GetIdentifier(), M.str());
  }

  GQO->SetLocation(TK->GetLocation());
  GQO->Mangle();
  return GQO;
}

ASTCastExpressionNode *ASTProductionFactory::ProductionRule_3600(
    const ASTToken *TK, const ASTExpressionNode *EXN, ASTType Ty) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(EXN && "Invalid ASTExpressionNode argument!");

  if (!ASTTypeCastController::Instance().CanCast(EXN, Ty)) {
    ASTType FTy = EXN->GetASTType();
    if (FTy == ASTTypeIdentifier || FTy == ASTTypeIdentifierRef)
      FTy = EXN->GetIdentifier()->GetSymbolType();

    std::stringstream M;
    M << "Impossible cast from an " << PrintTypeEnum(FTy) << " to an "
      << PrintTypeEnum(Ty) << '.' << std::endl;
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EXN), M.str(),
        DiagLevel::Error);
    return ASTCastExpressionNode::ExpressionError(M.str());
  }

  ASTCastExpressionNode *CXN =
      ASTBuilder::Instance().CreateASTCastExpressionNode(EXN, Ty);
  if (!CXN) {
    std::stringstream M;
    M << "Failure creating an ASTCastExpressionNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EXN), M.str(), DiagLevel::ICE);
    return ASTCastExpressionNode::ExpressionError(M.str());
  }

  CXN->SetLocation(TK->GetLocation());
  CXN->Mangle();
  return CXN;
}

ASTCastExpressionNode *ASTProductionFactory::ProductionRule_3600(
    const ASTToken *TK,
    const std::variant<const ASTIntNode *, const ASTIdentifierNode *> &II,
    const ASTExpressionNode *EXN, ASTType Ty) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(EXN && "Invalid ASTExpressionNode argument!");

  if (!ASTTypeCastController::Instance().CanCast(EXN, Ty)) {
    ASTType FTy = EXN->GetASTType();
    if (FTy == ASTTypeIdentifier || FTy == ASTTypeIdentifierRef)
      FTy = EXN->GetIdentifier()->GetSymbolType();

    std::stringstream M;
    M << "Impossible cast from an " << PrintTypeEnum(FTy) << " to an "
      << PrintTypeEnum(Ty) << '.' << std::endl;
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EXN), M.str(),
        DiagLevel::Error);
    return ASTCastExpressionNode::ExpressionError(M.str());
  }

  unsigned Bits = ASTProductionFactory::Instance().GetVariantBits(II);
  if (ASTIdentifierNode::InvalidBits(Bits)) {
    std::stringstream M;
    M << "Invalid number of bits for cast expression.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EXN), M.str(),
        DiagLevel::Error);
    return ASTCastExpressionNode::ExpressionError(M.str());
  }

  ASTCastExpressionNode *CXN =
      ASTBuilder::Instance().CreateASTCastExpressionNode(EXN, Ty, Bits);
  if (!CXN) {
    std::stringstream M;
    M << "Failure creating an ASTCastExpressionNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(EXN), M.str(), DiagLevel::ICE);
    return ASTCastExpressionNode::ExpressionError(M.str());
  }

  CXN->SetLocation(TK->GetLocation());
  CXN->Mangle();
  return CXN;
}

ASTGateQOpNode *
ASTProductionFactory::ProductionRule_3850(const ASTToken *TK,
                                          const ASTGateControlNode *GCN,
                                          bool UseASTBuilder) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(GCN && "Invalid ASTGateControlNode argument!");

  std::stringstream IDS;
  ASTGateQOpNode *GQOP = nullptr;

  if (UseASTBuilder) {
    IDS << "ast-gate-ctrl-stmt-"
        << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
    ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
        IDS.str(), ASTGateOpNode::GateOpBits, ASTTypeGateControlStatement);
    assert(Id && "Could not create a valid ASTIdentifierNode!");
    GQOP = ASTBuilder::Instance().CreateASTGateControlStatement(Id, GCN);
  } else {
    IDS << "ast-gate-ctrl-expr-stmt-"
        << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
    ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
        IDS.str(), ASTGateOpNode::GateOpBits, ASTTypeGateControlStatement);
    assert(Id && "Could not create a valid ASTIdentifierNode!");
    GQOP = new ASTGateQOpNode(Id, GCN);
  }

  assert(GQOP && "Could not create a valid ASTGateControlStmtNode!");

  GQOP->Mangle();
  GQOP->SetLocation(TK->GetLocation());
  return GQOP;
}

ASTGateQOpNode *
ASTProductionFactory::ProductionRule_3851(const ASTToken *TK,
                                          const ASTGateNegControlNode *GNCN,
                                          bool UseASTBuilder) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(GNCN && "Invalid ASTGateNegControlNode argument!");

  std::stringstream IDS;
  ASTGateQOpNode *GQOP = nullptr;

  if (UseASTBuilder) {
    IDS << "ast-gate-neg-ctrl-stmt-"
        << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
    ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
        IDS.str(), ASTGateOpNode::GateOpBits, ASTTypeGateNegControlStatement);
    assert(Id && "Could not create a valid ASTIdentifierNode!");
    GQOP = ASTBuilder::Instance().CreateASTGateNegControlStatement(Id, GNCN);
  } else {
    IDS << "ast-gate-neg-ctrl-expr-stmt-"
        << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
    ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
        IDS.str(), ASTGateOpNode::GateOpBits, ASTTypeGateNegControlStatement);
    assert(Id && "Could not create a valid ASTIdentifierNode!");
    GQOP = new ASTGateQOpNode(Id, GNCN);
  }

  assert(GQOP && "Could not create a valid ASTGateNegControlStmtNode!");

  GQOP->Mangle();
  GQOP->SetLocation(TK->GetLocation());
  return GQOP;
}

ASTGateQOpNode *ASTProductionFactory::ProductionRule_3852(
    const ASTToken *TK, const ASTGatePowerNode *GPN, bool UseASTBuilder) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(GPN && "Invalid ASTGatePowerNode argument!");

  std::stringstream IDS;
  ASTGateQOpNode *GQOP = nullptr;

  if (UseASTBuilder) {
    IDS << "ast-gate-power-stmt-"
        << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
    ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
        IDS.str(), ASTGateOpNode::GateOpBits, ASTTypeGatePowerStatement);
    assert(Id && "Could not create a valid ASTIdentifierNode!");
    GQOP = ASTBuilder::Instance().CreateASTGatePowerStatement(Id, GPN);
  } else {
    IDS << "ast-gate-power-expr-stmt-"
        << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
    ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
        IDS.str(), ASTGateOpNode::GateOpBits, ASTTypeGatePowerStatement);
    assert(Id && "Could not create a valid ASTIdentifierNode!");
    GQOP = new ASTGateQOpNode(Id, GPN);
  }

  assert(GQOP && "Could not create a valid ASTGatePowerStmtNode!");

  GQOP->Mangle();
  GQOP->SetLocation(TK->GetLocation());
  return GQOP;
}

ASTGateQOpNode *
ASTProductionFactory::ProductionRule_3853(const ASTToken *TK,
                                          const ASTGateInverseNode *GIN,
                                          bool UseASTBuilder) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(GIN && "Invalid ASTGateInverseNode argument!");

  std::stringstream IDS;
  ASTGateQOpNode *GQOP = nullptr;

  if (UseASTBuilder) {
    IDS << "ast-gate-inverse-stmt-"
        << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
    ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
        IDS.str(), ASTGateOpNode::GateOpBits, ASTTypeGateInverseStatement);
    assert(Id && "Could not create a valid ASTIdentifierNode!");
    GQOP = ASTBuilder::Instance().CreateASTGateInverseStatement(Id, GIN);
  } else {
    IDS << "ast-gate-inverse-expr-stmt-"
        << DIAGLineCounter::Instance().GetIdentifierLocation(TK);
    ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
        IDS.str(), ASTGateOpNode::GateOpBits, ASTTypeGateInverseStatement);
    assert(Id && "Could not create a valid ASTIdentifierNode!");
    GQOP = new ASTGateQOpNode(Id, GIN);
  }

  assert(GQOP && "Could not create a valid ASTGateInverseStmtNode!");

  GQOP->Mangle();
  GQOP->SetLocation(TK->GetLocation());
  return GQOP;
}

ASTGateQOpNode *ASTProductionFactory::ProductionRule_3854(
    const ASTToken *TK, const ASTGateGPhaseExpressionNode *GEN) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(GEN && "Invalid ASTGateGPhaseExpressionNode argument!");

  std::stringstream IDS;
  IDS << "ast-gate-gphase-stmt-"
      << DIAGLineCounter::Instance().GetIdentifierLocation(TK);

  ASTIdentifierNode *Id = ASTBuilder::Instance().CreateASTIdentifierNode(
      IDS.str(), ASTGPhaseStatementNode::GPhaseStmtBits,
      ASTTypeGateGPhaseStatement);
  assert(Id && "Could not create a valid ASTIdentifierNode!");

  ASTGateQOpNode *GQOP =
      ASTBuilder::Instance().CreateASTGateGPhaseStatement(Id, GEN);
  assert(GQOP && "Could not create a valid ASTGateGPhaseStmtNode!");

  GQOP->Mangle();
  GQOP->SetLocation(TK->GetLocation());
  return GQOP;
}

ASTGateGPhaseExpressionNode *
ASTProductionFactory::ProductionRule_3854(const ASTToken *TK,
                                          const ASTGPhaseExpressionNode *GPN,
                                          const ASTIdentifierList *IL) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(GPN && "Invalid ASTGPhaseExpressionNode argument!");
  assert(IL && "Invalid ASTIdentifierList argument!");

  ASTGateControlNode *GCN = new ASTGateControlNode(GPN);
  assert(GCN && "Could not create a valid ASTGateControlNode!");

  if (!GCN) {
    std::stringstream M;
    M << "Could not create a valid ASTGateControlNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTGateGPhaseExpressionNode::ExpressionError(M.str());
  }

  GCN->SetLocation(TK->GetLocation());
  GCN->Mangle();

  if (!IL->Empty()) {
    unsigned QIX = 0;

    const ASTDeclarationContext *CTX =
        ASTDeclarationContextTracker::Instance().GetCurrentContext();
    assert(CTX && "Could not obtain a valid ASTDeclarationContext!");

    for (ASTIdentifierList::const_iterator I = IL->begin(); I != IL->end();
         ++I) {
      const ASTIdentifierNode *QId = *I;
      assert(QId && "Could not obtain a valid ASTIdentifierNode!");

      ASTSymbolTableEntry *QSTE = ASTSymbolTable::Instance().Lookup(
          QId, QId->GetBits(), QId->GetSymbolType());
      assert(QSTE && "Could not obtain a valid SymbolTable Entry!");
      if (!QSTE) {
        std::stringstream M;
        M << "Could not obtain a valid ASTGateQubitParam SymbolTable Entry.";
        QasmDiagnosticEmitter::Instance().EmitDiagnostic(
            DIAGLineCounter::Instance().GetLocation(TK), M.str(),
            DiagLevel::ICE);
        return ASTGateGPhaseExpressionNode::ExpressionError(M.str());
      }

      QId->SetDeclarationContext(CTX);
      const_cast<ASTIdentifierNode *>(QId)->SetLocalScope();
      QSTE->SetContext(CTX);
      QSTE->SetLocalScope();

      if (!QSTE->HasValue()) {
        ASTGateQubitParamNode *QPN = new ASTGateQubitParamNode(
            QId, QIX++, QId->GetBits(), QId->GetName());
        assert(QPN && "Could not create a valid ASTGateQubitParamNode!");
        if (!QPN) {
          std::stringstream M;
          M << "Could not create a valid ASTGateQubitParamNode.";
          QasmDiagnosticEmitter::Instance().EmitDiagnostic(
              DIAGLineCounter::Instance().GetLocation(TK), M.str(),
              DiagLevel::ICE);
          return ASTGateGPhaseExpressionNode::ExpressionError(M.str());
        }

        QPN->SetDeclarationContext(CTX);
        QSTE->ResetValue();
        QSTE->SetValue(new ASTValue<>(QPN, ASTTypeGateQubitParam),
                       ASTTypeGateQubitParam);
        assert(QSTE->HasValue() && "SymbolTable Entry has no Value!");
        if (!QSTE->HasValue()) {
          std::stringstream M;
          M << "ASTGateQubitParam SymbolTable Entry has no Value.";
          QasmDiagnosticEmitter::Instance().EmitDiagnostic(
              DIAGLineCounter::Instance().GetLocation(TK), M.str(),
              DiagLevel::ICE);
          return ASTGateGPhaseExpressionNode::ExpressionError(M.str());
        }
      }
    }
  }

  ASTGateGPhaseExpressionNode *GEN = new ASTGateGPhaseExpressionNode(GCN, *IL);
  assert(GEN && "Could not create a valid ASTGateGPhaseExpressionNode!");

  if (!GEN) {
    std::stringstream M;
    M << "Could not create a valid ASTGateGPhaseExpressionNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTGateGPhaseExpressionNode::ExpressionError(M.str());
  }

  GEN->SetLocation(TK->GetLocation());
  GEN->Mangle();
  return GEN;
}

// Line Directive
ASTDirectiveStatementNode *
ASTProductionFactory::ProductionRule_5300(const ASTToken *TK,
                                          const std::string *S) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(S && "Invalid std::string argument!");

  uint32_t LN = static_cast<uint32_t>(std::stoi(*S));
  DIAGLineCounter::Instance().SetLineCount(LN);
  ASTDirectiveStatementNode *DSN = new ASTDirectiveStatementNode(LN);
  assert(DSN && "Could not create a valid ASTDirectiveStatementNode!");

  DSN->SetLocation(TK->GetLocation());
  return DSN;
}

// File Directive
ASTDirectiveStatementNode *
ASTProductionFactory::ProductionRule_5301(const ASTToken *TK,
                                          const std::string *S) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(S && "Invalid std::string argument!");

  DIAGLineCounter::Instance().SetTranslationUnit(*S);
  ASTDirectiveStatementNode *DSN = new ASTDirectiveStatementNode(*S);
  assert(DSN && "Could not create a valid ASTDirectiveStatementNode!");

  DSN->SetLocation(TK->GetLocation());
  return DSN;
}

void ASTProductionFactory::ProductionRule_6000(
    const ASTStatementNode *SN) const {
  assert(SN && "Invalid ASTStatementNode* argument!");

  std::stringstream M;
  M << "This statement will never execute.";
  QasmDiagnosticEmitter::Instance().EmitDiagnostic(
      DIAGLineCounter::Instance().GetLocation(SN), M.str(), DiagLevel::Warning);
}

void ASTProductionFactory::ProductionRule_6001(const ASTStatement *SN) const {
  assert(SN && "Invalid ASTStatement* argument!");

  std::stringstream M;
  M << "This statement will never execute.";
  QasmDiagnosticEmitter::Instance().EmitDiagnostic(
      DIAGLineCounter::Instance().GetLocation(SN), M.str(), DiagLevel::Warning);
}

ASTDeclarationNode *
ASTProductionFactory::ProductionRule_7000(const ASTDeclarationNode *DN) const {
  assert(DN && "Invalid ASTDeclarationNode argument!");

  std::stringstream M;
  M << "A declaration is not allowed inside an unscoped switch case label.";
  QasmDiagnosticEmitter::Instance().EmitDiagnostic(
      DIAGLineCounter::Instance().GetLocation(DN), M.str(), DiagLevel::Error);

  return ASTDeclarationNode::DeclarationError(DN->GetIdentifier(), M.str());
}

ASTBinaryOpNode *
ASTProductionFactory::ProductionRule_7001(const ASTToken *TK,
                                          const ASTExpressionNode *EN) const {
  assert(TK && "Invalid ASTToken argument!");
  assert(EN && "Invalid ASTExpressionNode argument!");

  std::stringstream M;
  M << "A Constant Expression cannot be assigned to.";
  QasmDiagnosticEmitter::Instance().EmitDiagnostic(
      DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
  return ASTBinaryOpNode::ExpressionError(M.str(), ASTOpTypeAssign);
}

ASTBinaryOpNode *
ASTProductionFactory::ProductionRule_7002(const ASTToken *TK) const {
  assert(TK && "Invalid ASTToken argument!");

  std::stringstream M;
  M << "Nonsensical assignment expression.";
  QasmDiagnosticEmitter::Instance().EmitDiagnostic(
      DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
  return ASTBinaryOpNode::ExpressionError(M.str(), ASTOpTypeAssign);
}

ASTBinaryOpNode *
ASTProductionFactory::ProductionRule_7003(const ASTToken *TK) const {
  assert(TK && "Invalid ASTToken argument!");

  std::stringstream M;
  M << "Left operand cannot be assigned to.";
  QasmDiagnosticEmitter::Instance().EmitDiagnostic(
      DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
  return ASTBinaryOpNode::ExpressionError(M.str(), ASTOpTypeAssign);
}

ASTMPIntegerNode *
ASTProductionFactory::ProductionRule_7004(const ASTToken *TK) const {
  assert(TK && "Invalid ASTToken argument!");

  std::stringstream M;
  M << "ASTMPIntegerNode widths must be expressed as compile-time "
    << "constants.";
  QasmDiagnosticEmitter::Instance().EmitDiagnostic(
      DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
  return ASTMPIntegerNode::ExpressionError(M.str());
}

ASTMPDecimalNode *
ASTProductionFactory::ProductionRule_7005(const ASTToken *TK) const {
  assert(TK && "Invalid ASTToken argument!");

  std::stringstream M;
  M << "ASTMPDecimalNode widths must be expressed as compile-time "
    << "constants.";
  QasmDiagnosticEmitter::Instance().EmitDiagnostic(
      DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::Error);
  return ASTMPDecimalNode::ExpressionError(M.str());
}

ASTArrayNode *
ASTProductionFactory::ProductionRule_7006(const ASTToken *TK) const {
  assert(TK && "Invalid ASTToken argument!");

  std::string ERM = "Feature not yet implemented.";
  ASTInvalidArrayNode *IVN = new ASTInvalidArrayNode(ERM, TK);
  assert(IVN && "Could not create a valid ASTInvalidArrayNode!");
  return IVN;
}

ASTExpressionNode *
ASTProductionFactory::ProductionRule_8000(const ASTToken *TK,
                                          ASTExpressionNode *EXN) const {
  assert(EXN && "Invalid ASTExpressionNode argument!");

  if (!EXN) {
    std::stringstream M;
    M << "Invalid ASTExpressionNode argument.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTExpressionNode::ExpressionError(
        ASTIdentifierNode::Expression.Clone(), M.str());
  }

  ASTType ETy = EXN->GetASTType();
  switch (ETy) {
  case ASTTypeBinaryOp: {
    if (ASTBinaryOpNode *BOP = dynamic_cast<ASTBinaryOpNode *>(EXN))
      BOP->AddParens();
  } break;
  case ASTTypeUnaryOp: {
    if (ASTUnaryOpNode *UOP = dynamic_cast<ASTUnaryOpNode *>(EXN))
      UOP->AddParens();
  } break;
  default:
    break;
  }

  return EXN;
}

ASTExpressionNode *
ASTProductionFactory::ProductionRule_8001(const ASTToken *TK,
                                          const ASTIdentifierNode *Id) const {
  assert(Id && "Invalid ASTIdentifierNode argument!");

  ASTExpressionNode *EN = ASTBuilder::Instance().CreateASTExpressionNode(
      Id->GetName(), Id, ASTTypeIdentifier);
  if (!EN) {
    std::stringstream M;
    M << "Could not create a valid ASTIdentifierNode ASTExpressionNode.";
    QasmDiagnosticEmitter::Instance().EmitDiagnostic(
        DIAGLineCounter::Instance().GetLocation(TK), M.str(), DiagLevel::ICE);
    return ASTExpressionNode::ExpressionError(Id, M.str());
  }

  return EN;
}

} // namespace QASM
