<commit_before>//
// Copyright (C) 2006-2007 SIPfoundry Inc.
// Licensed by SIPfoundry under the LGPL license.
//
// Copyright (C) 2006-2007 SIPez LLC.
// Licensed to SIPfoundry under a Contributor Agreement.
//
// $$
///////////////////////////////////////////////////////////////////////////////

// Author: Dan Petrie <dpetrie AT SIPez DOT com>

// SYSTEM INCLUDES
// APPLICATION INCLUDES
#include <utl/UtlString.h>
#include <utl/UtlDListIterator.h>
#include <utl/UtlHashBag.h>
#include <utl/UtlHashBagIterator.h>
#include <mp/MpResourceTopology.h>
#include <mp/MpResourceFactory.h>

// EXTERNAL FUNCTIONS
// EXTERNAL VARIABLES
// CONSTANTS
// STATIC VARIABLE INITIALIZATIONS
// PRIVATE CLASS DEFINITIONS
class MpResourceDefinition : public UtlString
{
public:
    MpResourceDefinition(const UtlString& resourceType,
        const UtlString& resourceName) :
    UtlString(resourceName),
        mResourceType(resourceType)
    {
    };

    virtual ~MpResourceDefinition(){};

    UtlString mResourceType;

private:
    // Disable the following
    MpResourceDefinition();
    MpResourceDefinition(const MpResourceDefinition& ref);
    MpResourceDefinition& operator=(const MpResourceDefinition& ref);
};

class MpResourceConnectionDefinition : public UtlString
{
public:
    MpResourceConnectionDefinition(const UtlString& outputResourceName,
                                   int outputPortIndex,
                                   const UtlString& inputResourceName,
                                   int inputPortIndex) :
    UtlString(outputResourceName),
    mInputResourceName(inputResourceName),
    mOutputPortIndex(outputPortIndex),
    mInputPortIndex(inputPortIndex)
    {
    };

    virtual ~MpResourceConnectionDefinition(){};

    UtlString mInputResourceName;
    int mOutputPortIndex;
    int mInputPortIndex;

private:
    // Disable the following
    MpResourceConnectionDefinition();
    MpResourceConnectionDefinition(const MpResourceConnectionDefinition& ref);
    MpResourceConnectionDefinition& operator=(const MpResourceConnectionDefinition& ref);
};

/* //////////////////////////// PUBLIC //////////////////////////////////// */

/* ============================ CREATORS ================================== */

// Constructor
MpResourceTopology::MpResourceTopology() :
mPriorLogicalPort(MP_TOPOLOGY_NEXT_AVAILABLE_PORT)
{
}

// Destructor
MpResourceTopology::~MpResourceTopology()
{
    mResources.destroyAll();
    mConnections.destroyAll();
}

/* ============================ MANIPULATORS ============================== */
OsStatus MpResourceTopology::addResource(const UtlString& resourceType,
                                         const UtlString& resourceName)
{
    OsStatus result;

    if(mResources.find(&resourceName))
    {
        result = OS_NAME_IN_USE;
    }
    else
    {
        mResources.append(new MpResourceDefinition(resourceType, resourceName));
        result = OS_SUCCESS;
    }
    return(result);
}

    /// Add a new connection definition to the topology
OsStatus MpResourceTopology::addConnection(const UtlString& outputResourceName,
                                           int outputPortIndex,
                                           const UtlString& inputResourceName,
                                           int inputPortIndex)
{
    mConnections.append(new MpResourceConnectionDefinition(outputResourceName,
                                                           outputPortIndex,
                                                           inputResourceName,
                                                           inputPortIndex));
    return(OS_SUCCESS);
}

OsStatus MpResourceTopology::validateConnections(UtlString& firstUnconnectedResourceName,
                                                 UtlString&  firstDanglingResourceName,
                                                 UtlBoolean allowExternalResources) const
{
    // First make sure every resource has a connection
    // This test must be true whether this is a full topology or an
    // incremental topology or we would have dangling resources
    UtlHashBag resourcesWithoutOutputConnections;
    UtlDListIterator resourceIterator(mResources);
    MpResourceDefinition* resourceDef = NULL;
    firstUnconnectedResourceName = "";
    firstDanglingResourceName = "";
    OsStatus result = OS_SUCCESS;
    while((resourceDef = (MpResourceDefinition*) resourceIterator()))
    {
        // Add resources with no output connection to the hash
        if(mConnections.find(resourceDef) == NULL)
        {
            resourcesWithoutOutputConnections.insert(resourceDef);
        }
    }

    // Of the resources with no output connection remove those with input
    // connections and we have the resources with no connections
    UtlDListIterator connectionIterator(mConnections);
    MpResourceConnectionDefinition* connectionDef = NULL;
    while((connectionDef = (MpResourceConnectionDefinition*) connectionIterator()))
    {
        resourcesWithoutOutputConnections.remove(&(connectionDef->mInputResourceName));
    }

    if(resourcesWithoutOutputConnections.entries())
    {
        result = OS_INVALID;
        resourceIterator.reset();
        while((resourceDef = (MpResourceDefinition*) resourceIterator()))
        {
            if(resourcesWithoutOutputConnections.find(resourceDef))
            {
                firstUnconnectedResourceName = *resourceDef;
                break;
            }
        }
    }

    // If everything is valid so far and we have a full topology
    if(!allowExternalResources && result == OS_SUCCESS)
    {
        // In the following code we will traverse the topology starting
        // at one resource following its connections and the resouces
        // connected by those connections.  As we find connections to
        // resources we will eliminate the resources from the danglingResource
        // list.  At the end after we have pursued all the connections
        // and resources left in the dangling list are not connection.
        // There should be no dangling resources in a full topology
        // definition, hense an invalid topology if there are resources
        // left.

        // Start with a list of all resources, we will remove these
        // as we find connections
        UtlDList danglingResources;
        resourceIterator.reset();
        while((resourceDef = (MpResourceDefinition*) resourceIterator()))
        {
            danglingResources.append(resourceDef);
        }

        // Create a list to contain connections that we need to traverse
        UtlDList connectionsToTraverse;

        // Prime the connection list with the connections for the first
        // resource
        resourceDef = (MpResourceDefinition*) danglingResources.at(0);
        if(resourceDef)
        {
            findResourceConnections(*resourceDef, connectionsToTraverse);

            // Get the first connection
            while((connectionDef = (MpResourceConnectionDefinition*) connectionsToTraverse.get()))
            {
                // If the output resource for the connection is still in the list
                // add its connections to the connection list to traverse and
                // reomve the resource from the list.
                if(danglingResources.remove(connectionDef))
                {
                    findResourceConnections(*connectionDef, connectionsToTraverse);
                }

                //  Do the same for the input resource for this connection
                if(danglingResources.remove(&(connectionDef->mInputResourceName)))
                {
                    findResourceConnections(connectionDef->mInputResourceName,
                                            connectionsToTraverse);
                }
            } // end while we have connections in the list
        }

        // If all is well we remove all the resources for the set of connections
        // that we collected and traversed.
        assert(connectionsToTraverse.entries() == 0);

        // If we still have resources left in the danglingResources list,
        // they were not connected to the rest
        if(danglingResources.entries())
        {
            result = OS_NOT_FOUND;
            firstDanglingResourceName = *((MpResourceDefinition*)danglingResources.get());
        }

    }

    return(result);
}

OsStatus MpResourceTopology::validateResourceTypes(MpResourceFactory& resourceFactory,
                                                   int& firstInvalidResourceIndex) const
{
    UtlDListIterator iterator(mResources);
    MpResourceDefinition* resourceDef = NULL;
    int resourceIndex = 0;
    firstInvalidResourceIndex = -1;
    OsStatus result = OS_SUCCESS;
    while((resourceDef = (MpResourceDefinition*) iterator()))
    {
        if(!resourceFactory.constructorExists(resourceDef->mResourceType))
        {
            result = OS_NOT_FOUND;
            firstInvalidResourceIndex = resourceIndex;
            break;
        }
        resourceIndex++;
    }
    return(result);
}

/* ============================ ACCESSORS ================================= */

OsStatus MpResourceTopology::getResource(int resourceIndex,
                                         UtlString& resourceType,
                                         UtlString& resourceName) const
{
    MpResourceDefinition* resourceDef =
        (MpResourceDefinition*) mResources.at(resourceIndex);
    OsStatus result;
    if(resourceDef)
    {
        result = OS_SUCCESS;
        resourceName = *resourceDef;
        resourceType = resourceDef->mResourceType;
    }
    else
    {
        result = OS_NOT_FOUND;
    }
    return(result);
}

    /// Get the connection definition indicated by the connectionIndex
OsStatus MpResourceTopology::getConnection(int connectionIndex,
                                           UtlString& outputResourceName,
                                           int& outputPortIndex,
                                           UtlString& inputResourceName,
                                           int& inputPortIndex)
{
    MpResourceConnectionDefinition* connectionDef =
        (MpResourceConnectionDefinition*) mConnections.at(connectionIndex);
    OsStatus result;

    if(connectionDef)
    {
        result = OS_SUCCESS;
        outputResourceName = *connectionDef;
        inputResourceName = connectionDef->mInputResourceName;
        outputPortIndex = connectionDef->mOutputPortIndex;
        inputPortIndex = connectionDef->mInputPortIndex;
    }
    else
    {
        result = OS_NOT_FOUND;
    }
    return(result);
}

int MpResourceTopology::getNextLogicalPortNumber()
{
    return((--mPriorLogicalPort));
}

/* ============================ INQUIRY =================================== */

/* //////////////////////////// PROTECTED ///////////////////////////////// */

/* //////////////////////////// PRIVATE /////////////////////////////////// */

void MpResourceTopology::replaceNumInName(UtlString& resourceName,
                                          int resourceNum)
{
    int stringIndex = resourceName.index("%d");
    if(stringIndex >= 0)
    {
        char numBuf[20];
        sprintf(numBuf, "%d", resourceNum);
        resourceName.replace(stringIndex, 2, numBuf);
    }
}

int MpResourceTopology::findResourceConnections(const UtlString& resourceName,
                                                UtlContainer& connections) const
{
    UtlDListIterator iterator(mConnections);
    MpResourceConnectionDefinition* connectionDef = NULL;
    int connectionsFound = 0;
    while((connectionDef = (MpResourceConnectionDefinition*) iterator()))
    {
        // if the connections input or output resource match
        if(resourceName.compareTo(*connectionDef) == 0 ||
           resourceName.compareTo(connectionDef->mInputResourceName) == 0)
        {
            connections.insert(connectionDef);
            connectionsFound++;
        }
    }
    return(connectionsFound);
}

/* ============================ FUNCTIONS ================================= */

<commit_msg>Reformat MpResourceTopology.cpp to follow style guidelines.<commit_after>//
// Copyright (C) 2006-2007 SIPfoundry Inc.
// Licensed by SIPfoundry under the LGPL license.
//
// Copyright (C) 2006-2007 SIPez LLC.
// Licensed to SIPfoundry under a Contributor Agreement.
//
// $$
///////////////////////////////////////////////////////////////////////////////

// Author: Dan Petrie <dpetrie AT SIPez DOT com>

// SYSTEM INCLUDES
// APPLICATION INCLUDES
#include <utl/UtlString.h>
#include <utl/UtlDListIterator.h>
#include <utl/UtlHashBag.h>
#include <utl/UtlHashBagIterator.h>
#include <mp/MpResourceTopology.h>
#include <mp/MpResourceFactory.h>

// EXTERNAL FUNCTIONS
// EXTERNAL VARIABLES
// CONSTANTS
// STATIC VARIABLE INITIALIZATIONS
// PRIVATE CLASS DEFINITIONS
class MpResourceDefinition : public UtlString
{
public:
   MpResourceDefinition(const UtlString& resourceType,
                        const UtlString& resourceName)
   : UtlString(resourceName)
   , mResourceType(resourceType)
   {
   }

   virtual ~MpResourceDefinition(){};

   UtlString mResourceType;

private:
   // Disable the following
   MpResourceDefinition();
   MpResourceDefinition(const MpResourceDefinition& ref);
   MpResourceDefinition& operator=(const MpResourceDefinition& ref);
};

class MpResourceConnectionDefinition : public UtlString
{
public:
   MpResourceConnectionDefinition(const UtlString& outputResourceName,
                                  int outputPortIndex,
                                  const UtlString& inputResourceName,
                                  int inputPortIndex)
   : UtlString(outputResourceName)
   , mInputResourceName(inputResourceName)
   , mOutputPortIndex(outputPortIndex)
   , mInputPortIndex(inputPortIndex)
   {
   };

   virtual ~MpResourceConnectionDefinition(){};

   UtlString mInputResourceName;
   int mOutputPortIndex;
   int mInputPortIndex;

private:
   // Disable the following
   MpResourceConnectionDefinition();
   MpResourceConnectionDefinition(const MpResourceConnectionDefinition& ref);
   MpResourceConnectionDefinition& operator=(const MpResourceConnectionDefinition& ref);
};

/* //////////////////////////// PUBLIC //////////////////////////////////// */

/* ============================ CREATORS ================================== */

// Constructor
MpResourceTopology::MpResourceTopology() :
mPriorLogicalPort(MP_TOPOLOGY_NEXT_AVAILABLE_PORT)
{
}

// Destructor
MpResourceTopology::~MpResourceTopology()
{
   mResources.destroyAll();
   mConnections.destroyAll();
}

/* ============================ MANIPULATORS ============================== */
OsStatus MpResourceTopology::addResource(const UtlString& resourceType,
                                         const UtlString& resourceName)
{
   OsStatus result;

   if(mResources.find(&resourceName))
   {
      result = OS_NAME_IN_USE;
   }
   else
   {
      mResources.append(new MpResourceDefinition(resourceType, resourceName));
      result = OS_SUCCESS;
   }
   return result;
}

    /// Add a new connection definition to the topology
OsStatus MpResourceTopology::addConnection(const UtlString& outputResourceName,
                                           int outputPortIndex,
                                           const UtlString& inputResourceName,
                                           int inputPortIndex)
{
   mConnections.append(new MpResourceConnectionDefinition(outputResourceName,
                                                          outputPortIndex,
                                                          inputResourceName,
                                                          inputPortIndex));
   return OS_SUCCESS;
}

OsStatus MpResourceTopology::validateConnections(UtlString& firstUnconnectedResourceName,
                                                 UtlString&  firstDanglingResourceName,
                                                 UtlBoolean allowExternalResources) const
{
   // First make sure every resource has a connection
   // This test must be true whether this is a full topology or an
   // incremental topology or we would have dangling resources
   UtlHashBag resourcesWithoutOutputConnections;
   UtlDListIterator resourceIterator(mResources);
   MpResourceDefinition* resourceDef = NULL;
   firstUnconnectedResourceName = "";
   firstDanglingResourceName = "";
   OsStatus result = OS_SUCCESS;
   while((resourceDef = (MpResourceDefinition*) resourceIterator()))
   {
      // Add resources with no output connection to the hash
      if(mConnections.find(resourceDef) == NULL)
      {
         resourcesWithoutOutputConnections.insert(resourceDef);
      }
   }

   // Of the resources with no output connection remove those with input
   // connections and we have the resources with no connections
   UtlDListIterator connectionIterator(mConnections);
   MpResourceConnectionDefinition* connectionDef = NULL;
   while((connectionDef = (MpResourceConnectionDefinition*) connectionIterator()))
   {
      resourcesWithoutOutputConnections.remove(&(connectionDef->mInputResourceName));
   }

   if(resourcesWithoutOutputConnections.entries())
   {
      result = OS_INVALID;
      resourceIterator.reset();
      while((resourceDef = (MpResourceDefinition*) resourceIterator()))
      {
         if(resourcesWithoutOutputConnections.find(resourceDef))
         {
            firstUnconnectedResourceName = *resourceDef;
            break;
         }
      }
   }

   // If everything is valid so far and we have a full topology
   if(!allowExternalResources && result == OS_SUCCESS)
   {
      // In the following code we will traverse the topology starting
      // at one resource following its connections and the resources
      // connected by those connections.  As we find connections to
      // resources we will eliminate the resources from the danglingResource
      // list.  At the end after we have pursued all the connections
      // and resources left in the dangling list are not connection.
      // There should be no dangling resources in a full topology
      // definition, hence an invalid topology if there are resources
      // left.

      // Start with a list of all resources, we will remove these
      // as we find connections
      UtlDList danglingResources;
      resourceIterator.reset();
      while((resourceDef = (MpResourceDefinition*) resourceIterator()))
      {
         danglingResources.append(resourceDef);
      }

      // Create a list to contain connections that we need to traverse
      UtlDList connectionsToTraverse;

      // Prime the connection list with the connections for the first
      // resource
      resourceDef = (MpResourceDefinition*) danglingResources.at(0);
      if(resourceDef)
      {
         findResourceConnections(*resourceDef, connectionsToTraverse);

         // Get the first connection
         while((connectionDef = (MpResourceConnectionDefinition*) connectionsToTraverse.get()))
         {
            // If the output resource for the connection is still in the list
            // add its connections to the connection list to traverse and
            // remove the resource from the list.
            if(danglingResources.remove(connectionDef))
            {
               findResourceConnections(*connectionDef, connectionsToTraverse);
            }

            //  Do the same for the input resource for this connection
            if(danglingResources.remove(&(connectionDef->mInputResourceName)))
            {
               findResourceConnections(connectionDef->mInputResourceName,
                                       connectionsToTraverse);
            }
         } // end while we have connections in the list
      }

      // If all is well we remove all the resources for the set of connections
      // that we collected and traversed.
      assert(connectionsToTraverse.entries() == 0);

      // If we still have resources left in the danglingResources list,
      // they were not connected to the rest
      if(danglingResources.entries())
      {
         result = OS_NOT_FOUND;
         firstDanglingResourceName = *((MpResourceDefinition*)danglingResources.get());
      }

   }

   return result;
}

OsStatus MpResourceTopology::validateResourceTypes(MpResourceFactory& resourceFactory,
                                                   int& firstInvalidResourceIndex) const
{
   UtlDListIterator iterator(mResources);
   MpResourceDefinition* resourceDef = NULL;
   int resourceIndex = 0;
   firstInvalidResourceIndex = -1;
   OsStatus result = OS_SUCCESS;
   while((resourceDef = (MpResourceDefinition*) iterator()))
   {
      if(!resourceFactory.constructorExists(resourceDef->mResourceType))
      {
         result = OS_NOT_FOUND;
         firstInvalidResourceIndex = resourceIndex;
         break;
      }
      resourceIndex++;
   }
   return result;
}

/* ============================ ACCESSORS ================================= */

OsStatus MpResourceTopology::getResource(int resourceIndex,
                                         UtlString& resourceType,
                                         UtlString& resourceName) const
{
   MpResourceDefinition* resourceDef =
      (MpResourceDefinition*) mResources.at(resourceIndex);
   OsStatus result;
   if(resourceDef)
   {
      result = OS_SUCCESS;
      resourceName = *resourceDef;
      resourceType = resourceDef->mResourceType;
   }
   else
   {
      result = OS_NOT_FOUND;
   }
   return result;
}

    /// Get the connection definition indicated by the connectionIndex
OsStatus MpResourceTopology::getConnection(int connectionIndex,
                                           UtlString& outputResourceName,
                                           int& outputPortIndex,
                                           UtlString& inputResourceName,
                                           int& inputPortIndex)
{
    MpResourceConnectionDefinition* connectionDef =
        (MpResourceConnectionDefinition*) mConnections.at(connectionIndex);
    OsStatus result;

    if(connectionDef)
    {
        result = OS_SUCCESS;
        outputResourceName = *connectionDef;
        inputResourceName = connectionDef->mInputResourceName;
        outputPortIndex = connectionDef->mOutputPortIndex;
        inputPortIndex = connectionDef->mInputPortIndex;
    }
    else
    {
        result = OS_NOT_FOUND;
    }
    return(result);
}

int MpResourceTopology::getNextLogicalPortNumber()
{
    return --mPriorLogicalPort;
}

/* ============================ INQUIRY =================================== */

/* //////////////////////////// PROTECTED ///////////////////////////////// */

/* //////////////////////////// PRIVATE /////////////////////////////////// */

void MpResourceTopology::replaceNumInName(UtlString& resourceName,
                                          int resourceNum)
{
   int stringIndex = resourceName.index("%d");
   if(stringIndex >= 0)
   {
      char numBuf[20];
      sprintf(numBuf, "%d", resourceNum);
      resourceName.replace(stringIndex, 2, numBuf);
   }
}

int MpResourceTopology::findResourceConnections(const UtlString& resourceName,
                                                UtlContainer& connections) const
{
   UtlDListIterator iterator(mConnections);
   MpResourceConnectionDefinition* connectionDef = NULL;
   int connectionsFound = 0;
   while((connectionDef = (MpResourceConnectionDefinition*) iterator()))
   {
      // if the connections input or output resource match
      if(resourceName.compareTo(*connectionDef) == 0 ||
         resourceName.compareTo(connectionDef->mInputResourceName) == 0)
      {
         connections.insert(connectionDef);
         connectionsFound++;
      }
   }
   return connectionsFound;
}

/* ============================ FUNCTIONS ================================= */

<|endoftext|>


<commit_before>/*
 *  yosys -- Yosys Open SYnthesis Suite
 *
 *  Copyright (C) 2020  Alberto Gonzalez <boqwxp@airmail.cc>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#include "kernel/register.h"
#include "kernel/rtlil.h"
#include "kernel/log.h"

USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN

struct GliftPass : public Pass {
	private:

	bool opt_create, opt_taintconstants;
	std::vector<std::string> args;
	std::vector<std::string>::size_type argidx;
	RTLIL::Module *module;

	void parse_args() {
		for (argidx = 1; argidx < args.size(); argidx++) {
			if (args[argidx] == "-create") {
				opt_create = true;
				continue;
			}
			if (args[argidx] == "-taint-constants") {
				opt_taintconstants = true;
				continue;
			}
			break;
		}
	}

	RTLIL::SigSpec get_corresponding_taint_signal(RTLIL::SigSpec sig) {
		RTLIL::SigSpec ret;

		//Get the connected wire for the cell port:
		log_assert(sig.is_wire() || sig.is_fully_const());
		log_assert(sig.is_wire() || sig.is_fully_const());

		//Get a SigSpec for the corresponding taint signal for the cell port, creating one if necessary:
		if (sig.is_wire()) {
			RTLIL::Wire *w = module->wire(sig.as_wire()->name.str() + "_t");
			if (w == nullptr) w = module->addWire(sig.as_wire()->name.str() + "_t", 1);
			ret = w;
		}
		else if (sig.is_fully_const() && opt_taintconstants)
			ret = RTLIL::State::S1;
		else if (sig.is_fully_const())
			ret = RTLIL::State::S0;
		else
			log_cmd_error("Cell port SigSpec has unexpected type.\n");

		//Finally, if the cell port was a module input or output, make sure the corresponding taint signal is marked, too:
		if(sig.is_wire() && sig.as_wire()->port_input)
			ret.as_wire()->port_input = true;
		if(sig.is_wire() && sig.as_wire()->port_output)
			ret.as_wire()->port_output = true;

		return ret;
	}

	void create_precise_glift_logic() {
		std::vector<RTLIL::SigSig> connections(module->connections());
		std::vector<RTLIL::SigSig> new_connections;

		for(auto &cell : module->cells().to_vector()) {
			if (!cell->type.in("$_AND_", "$_OR_", "$_NOT_", "$anyconst", "$allconst", "$assume", "$assert")) {
				log_cmd_error("Invalid cell type \"%s\" found.  Module must be techmapped.\n", cell->type.c_str());
			}
			if (cell->type.in("$_AND_", "$_OR_")) {
				const unsigned int A = 0, B = 1, Y = 2;
				const unsigned int NUM_PORTS = 3;
				RTLIL::SigSpec ports[NUM_PORTS] = {cell->getPort(ID::A), cell->getPort(ID::B), cell->getPort(ID::Y)};
				RTLIL::SigSpec port_taints[NUM_PORTS];

				if (ports[A].size() != 1 || ports[B].size() != 1 || ports[Y].size() != 1)
					log_cmd_error("Multi-bit signal found.  Run `splitnets` first.\n");
				for (unsigned int i = 0; i < NUM_PORTS; ++i)
					port_taints[i] = get_corresponding_taint_signal(ports[i]);

				if (cell->type == "$_AND_") {
					//We are basically trying to replace each AND cell with an AN2_SH2 cell:
					//module AN2_SH2(A, A_t, B, B_t, Y, Y_t);
					//  input A, A_t, B, B_t;
					//  output Y, Y_t;
					//
					//  assign Y = A & B;
					//  assign Y_t = A & B_t | B & A_t | A_t & B_t;
					//endmodule
					auto subexpr1 = module->And(cell->name.str() + "_t_1", ports[A], port_taints[B], false, cell->get_src_attribute());
					auto subexpr2 = module->And(cell->name.str() + "_t_2", ports[B], port_taints[A], false, cell->get_src_attribute());
					auto subexpr3 = module->And(cell->name.str() + "_t_3", port_taints[A], port_taints[B], false, cell->get_src_attribute());
					auto subexpr4 = module->Or(cell->name.str() + "_t_4", subexpr1, subexpr2, false, cell->get_src_attribute());
					module->addOr(cell->name.str() + "_t_5", subexpr4, subexpr3, port_taints[Y], false, cell->get_src_attribute());
				}

				else if (cell->type == "$_OR_") {
					//We are basically trying to replace each OR cell with an OR2_SH2 cell:
					//module OR2_SH2(A, A_t, B, B_t, Y, Y_t);
					//  input A, A_t, B, B_t;
					//  output Y, Y_t;
					//
					//  assign Y = A | B;
					//  assign Y_t = ~A & B_t | ~B & A_t | A_t & B_t;
					//endmodule
					RTLIL::SigSpec n_port_a = module->LogicNot(cell->name.str() + "_t_1", ports[A], false, cell->get_src_attribute());
					RTLIL::SigSpec n_port_b = module->LogicNot(cell->name.str() + "_t_2", ports[B], false, cell->get_src_attribute());
					auto subexpr1 = module->And(cell->name.str() + "_t_3", n_port_a, port_taints[B], false, cell->get_src_attribute());
					auto subexpr2 = module->And(cell->name.str() + "_t_4", n_port_b, port_taints[A], false, cell->get_src_attribute());
					auto subexpr3 = module->And(cell->name.str() + "_t_5", port_taints[A], port_taints[B], false, cell->get_src_attribute());
					auto subexpr4 = module->Or(cell->name.str() + "_t_6", subexpr1, subexpr2, false, cell->get_src_attribute());
					module->addOr(cell->name.str() + "_t_7", subexpr4, subexpr3, port_taints[Y], false, cell->get_src_attribute());
				}

				else log_cmd_error("This is a bug (1).\n");
			}
			else if (cell->type.in("$_NOT_")) {
				const unsigned int A = 0, Y = 1;
				const unsigned int NUM_PORTS = 2;
				RTLIL::SigSpec ports[NUM_PORTS] = {cell->getPort(ID::A), cell->getPort(ID::Y)};
				RTLIL::SigSpec port_taints[NUM_PORTS];

				if (ports[A].size() != 1 || ports[Y].size() != 1)
					log_cmd_error("Multi-bit signal found.  Run `splitnets` first.\n");
				for (unsigned int i = 0; i < NUM_PORTS; ++i)
					port_taints[i] = get_corresponding_taint_signal(ports[i]);

				if (cell->type == "$_NOT_") {
					//We are basically trying to replace each NOT cell with an IV_SH2 cell:
					//module IV_SH2(A, A_t, Y, Y_t);
					//  input A, A_t;
					//  output Y, Y_t;
					//
					//  assign Y = ~A;
					//  assign Y_t = A_t;
					//endmodule
					new_connections.emplace_back(port_taints[Y], port_taints[A]);
				}
				else log_cmd_error("This is a bug (1).\n");
			}
		} //end foreach cell in cells

		for (auto &conn : connections) {
			RTLIL::SigSpec first = get_corresponding_taint_signal(conn.first);
			RTLIL::SigSpec second = get_corresponding_taint_signal(conn.second);

			module->connect(get_corresponding_taint_signal(conn.first), get_corresponding_taint_signal(conn.second));

			if(conn.second.is_wire() && conn.second.as_wire()->port_input)
				second.as_wire()->port_input = true;
			if(conn.first.is_wire() && conn.first.as_wire()->port_output)
				first.as_wire()->port_output = true;
		} //end foreach conn in connections

		for (auto &conn : new_connections)
			module->connect(conn);

		module->fixup_ports(); //we have some new taint signals in the module interface
	}

	public:

	GliftPass() : Pass("glift", "create and transform GLIFT models"), opt_create(false), opt_taintconstants(false), module(nullptr) { }
	void help() YS_OVERRIDE
	{
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
		log("\n");
		log("    glift [options] [selection]\n");
		log("\n");
		log("Adds, removes, or manipulates gate-level information flow tracking (GLIFT) logic\n");
		log("to the current or specified module.\n");
		log("\n");
		log("Options:");
		log("\n");
		log("  -create");
		log("    Replaces the current or specified module with one that has additional \"taint\"\n");
		log("    inputs, outputs, and internal nets along with precise taint-tracking logic.\n");
		log("\n");
		log("  -taint-constants");
		log("    Constant values in the design are labeled as tainted.\n");
		log("    (default: label constants as un-tainted)\n");
		log("\n");
	}
	void execute(std::vector<std::string> _args, RTLIL::Design *design) YS_OVERRIDE
	{
		log_header(design, "Executing GLIFT pass (creating and manipulating GLIFT models).\n");

		args = _args;
		parse_args();
		extra_args(args, argidx, design);

		for (auto mod : design->selected_modules()) {
			if (module)
				log_cmd_error("Only one module may be selected for the glift pass! Flatten the design if necessary. (selected: %s and %s)\n", log_id(module), log_id(mod));
			module = mod;
		}
		if (module == nullptr)
			log_cmd_error("Can't operate on an empty selection!\n");

		if (opt_create)
			create_precise_glift_logic();
	}
} GliftPass;

PRIVATE_NAMESPACE_END
<commit_msg>glift: Initial implementation of the `-sketchify` option.<commit_after>/*
 *  yosys -- Yosys Open SYnthesis Suite
 *
 *  Copyright (C) 2020  Alberto Gonzalez <boqwxp@airmail.cc>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#include "kernel/register.h"
#include "kernel/rtlil.h"
#include "kernel/log.h"

USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN

struct GliftPass : public Pass {
	private:

	bool opt_create, opt_sketchify, opt_taintconstants;
	std::vector<std::string> args;
	std::vector<std::string>::size_type argidx;
	RTLIL::Module *module;

	void parse_args() {
		for (argidx = 1; argidx < args.size(); argidx++) {
			if (args[argidx] == "-create") {
				opt_create = true;
				continue;
			}
			if (args[argidx] == "-sketchify") {
				opt_sketchify = true;
				continue;
			}
			if (args[argidx] == "-taint-constants") {
				opt_taintconstants = true;
				continue;
			}
			break;
		}
		if(!opt_create && !opt_sketchify) log_cmd_error("One of `-create` or `-sketchify` must be specified.\n");
		if(opt_create && opt_sketchify) log_cmd_error("Only one of `-create` or `-sketchify` may be specified.\n");
	}

	RTLIL::SigSpec get_corresponding_taint_signal(RTLIL::SigSpec sig) {
		RTLIL::SigSpec ret;

		//Get the connected wire for the cell port:
		log_assert(sig.is_wire() || sig.is_fully_const());
		log_assert(sig.is_wire() || sig.is_fully_const());

		//Get a SigSpec for the corresponding taint signal for the cell port, creating one if necessary:
		if (sig.is_wire()) {
			RTLIL::Wire *w = module->wire(sig.as_wire()->name.str() + "_t");
			if (w == nullptr) w = module->addWire(sig.as_wire()->name.str() + "_t", 1);
			ret = w;
		}
		else if (sig.is_fully_const() && opt_taintconstants)
			ret = RTLIL::State::S1;
		else if (sig.is_fully_const())
			ret = RTLIL::State::S0;
		else
			log_cmd_error("Cell port SigSpec has unexpected type.\n");

		//Finally, if the cell port was a module input or output, make sure the corresponding taint signal is marked, too:
		if(sig.is_wire() && sig.as_wire()->port_input)
			ret.as_wire()->port_input = true;
		if(sig.is_wire() && sig.as_wire()->port_output)
			ret.as_wire()->port_output = true;

		return ret;
	}

	void add_precise_GLIFT_logic(const RTLIL::Cell *cell, RTLIL::SigSpec &port_a, RTLIL::SigSpec &port_a_taint, RTLIL::SigSpec &port_b, RTLIL::SigSpec &port_b_taint, RTLIL::SigSpec &port_y_taint) {
		//AKA AN2_SH2 or OR2_SH2
		RTLIL::SigSpec n_port_a = module->LogicNot(cell->name.str() + "_t_1_1", port_a, false, cell->get_src_attribute());
		RTLIL::SigSpec n_port_b = module->LogicNot(cell->name.str() + "_t_1_2", port_b, false, cell->get_src_attribute());
		auto subexpr1 = module->And(cell->name.str() + "_t_1_3", (cell->type == "$_AND_")? port_a : n_port_a, port_b_taint, false, cell->get_src_attribute());
		auto subexpr2 = module->And(cell->name.str() + "_t_1_4", (cell->type == "$_AND_")? port_b : n_port_b, port_a_taint, false, cell->get_src_attribute());
		auto subexpr3 = module->And(cell->name.str() + "_t_1_5", port_a_taint, port_b_taint, false, cell->get_src_attribute());
		auto subexpr4 = module->Or(cell->name.str() + "_t_1_6", subexpr1, subexpr2, false, cell->get_src_attribute());
		module->addOr(cell->name.str() + "_t_1_7", subexpr4, subexpr3, port_y_taint, false, cell->get_src_attribute());
	}

	void add_imprecise_GLIFT_logic_1(const RTLIL::Cell *cell, RTLIL::SigSpec &port_a, RTLIL::SigSpec &port_a_taint, RTLIL::SigSpec &port_b, RTLIL::SigSpec &port_b_taint, RTLIL::SigSpec &port_y_taint) {
		//AKA AN2_SH3 or OR2_SH3
		RTLIL::SigSpec n_port_a = module->LogicNot(cell->name.str() + "_t_2_1", port_a, false, cell->get_src_attribute());
		auto subexpr1 = module->And(cell->name.str() + "_t_2_2", (cell->type == "$_AND_")? port_b : n_port_a, (cell->type == "$_AND_")? port_a_taint : port_b_taint, false, cell->get_src_attribute());
		module->addOr(cell->name.str() + "_t_2_3", (cell->type == "$_AND_")? port_b_taint : port_a_taint, subexpr1, port_y_taint, false, cell->get_src_attribute());
	}

	void add_imprecise_GLIFT_logic_2(const RTLIL::Cell *cell, RTLIL::SigSpec &port_a, RTLIL::SigSpec &port_a_taint, RTLIL::SigSpec &port_b, RTLIL::SigSpec &port_b_taint, RTLIL::SigSpec &port_y_taint) {
		//AKA AN2_SH4 or OR2_SH4
		RTLIL::SigSpec n_port_b = module->LogicNot(cell->name.str() + "_t_3_1", port_b, false, cell->get_src_attribute());
		auto subexpr1 = module->And(cell->name.str() + "_t_3_2", (cell->type == "$_AND_")? port_a : n_port_b, (cell->type == "$_AND_")? port_b_taint : port_a_taint, false, cell->get_src_attribute());
		module->addOr(cell->name.str() + "_t_3_3", (cell->type == "$_AND_")? port_a_taint : port_b_taint, subexpr1, port_y_taint, false, cell->get_src_attribute());
	}

	void add_imprecise_GLIFT_logic_3(const RTLIL::Cell *cell, RTLIL::SigSpec &port_a_taint, RTLIL::SigSpec &port_b_taint, RTLIL::SigSpec &port_y_taint) {
		//AKA AN2_SH5 or OR2_SH5
		module->addOr(cell->name.str() + "_t_4_1", port_a_taint, port_b_taint, port_y_taint, false, cell->get_src_attribute());
	}

	void create_glift_logic() {
		std::vector<RTLIL::SigSig> connections(module->connections());
		std::vector<RTLIL::SigSig> new_connections;

		for(auto &cell : module->cells().to_vector()) {
			if (!cell->type.in("$_AND_", "$_OR_", "$_NOT_", "$anyconst", "$allconst", "$assume", "$assert")) {
				log_cmd_error("Invalid cell type \"%s\" found.  Module must be techmapped.\n", cell->type.c_str());
			}
			if (cell->type.in("$_AND_", "$_OR_")) {
				const unsigned int A = 0, B = 1, Y = 2;
				const unsigned int NUM_PORTS = 3;
				RTLIL::SigSpec ports[NUM_PORTS] = {cell->getPort(ID::A), cell->getPort(ID::B), cell->getPort(ID::Y)};
				RTLIL::SigSpec port_taints[NUM_PORTS];

				if (ports[A].size() != 1 || ports[B].size() != 1 || ports[Y].size() != 1)
					log_cmd_error("Multi-bit signal found.  Run `splitnets` first.\n");
				for (unsigned int i = 0; i < NUM_PORTS; ++i)
					port_taints[i] = get_corresponding_taint_signal(ports[i]);

				if (opt_create)
					add_precise_GLIFT_logic(cell, ports[A], port_taints[A], ports[B], port_taints[B], port_taints[Y]);
				else if (opt_sketchify) {
					RTLIL::SigSpec precise_y(module->addWire(cell->name.str() + "_y1", 1)),
							imprecise_1_y(module->addWire(cell->name.str() + "_y2", 1)),
							imprecise_2_y(module->addWire(cell->name.str() + "_y3", 1)),
							imprecise_3_y(module->addWire(cell->name.str() + "_y4", 1));

					add_precise_GLIFT_logic(cell, ports[A], port_taints[A], ports[B], port_taints[B], precise_y);
					add_imprecise_GLIFT_logic_1(cell, ports[A], port_taints[A], ports[B], port_taints[B], imprecise_1_y);
					add_imprecise_GLIFT_logic_2(cell, ports[A], port_taints[A], ports[B], port_taints[B], imprecise_2_y);
					add_imprecise_GLIFT_logic_3(cell, port_taints[A], port_taints[B], imprecise_3_y);

					RTLIL::SigSpec meta_mux_select(module->addWire(cell->name.str() + "_sel", 2));
					meta_mux_select.as_wire()->set_bool_attribute("\\maximize");
					new_connections.emplace_back(meta_mux_select, module->Anyconst(cell->name.str() + "_hole", 2, cell->get_src_attribute()));
					RTLIL::SigSpec meta_mux1(module->Mux(cell->name.str() + "_mux1", precise_y, imprecise_1_y, meta_mux_select[1]));
					RTLIL::SigSpec meta_mux2(module->Mux(cell->name.str() + "_mux2", imprecise_2_y, imprecise_3_y, meta_mux_select[1]));
					module->addMux(cell->name.str() + "_mux3", meta_mux1, meta_mux2, meta_mux_select[0], port_taints[Y]);
				}
				else log_cmd_error("This is a bug (2).\n");
			}
			else if (cell->type.in("$_NOT_")) {
				const unsigned int A = 0, Y = 1;
				const unsigned int NUM_PORTS = 2;
				RTLIL::SigSpec ports[NUM_PORTS] = {cell->getPort(ID::A), cell->getPort(ID::Y)};
				RTLIL::SigSpec port_taints[NUM_PORTS];

				if (ports[A].size() != 1 || ports[Y].size() != 1)
					log_cmd_error("Multi-bit signal found.  Run `splitnets` first.\n");
				for (unsigned int i = 0; i < NUM_PORTS; ++i)
					port_taints[i] = get_corresponding_taint_signal(ports[i]);

				if (cell->type == "$_NOT_") {
					new_connections.emplace_back(port_taints[Y], port_taints[A]);
				}
				else log_cmd_error("This is a bug (3).\n");
			}
		} //end foreach cell in cells

		for (auto &conn : connections) {
			RTLIL::SigSpec first = get_corresponding_taint_signal(conn.first);
			RTLIL::SigSpec second = get_corresponding_taint_signal(conn.second);

			module->connect(get_corresponding_taint_signal(conn.first), get_corresponding_taint_signal(conn.second));

			if(conn.second.is_wire() && conn.second.as_wire()->port_input)
				second.as_wire()->port_input = true;
			if(conn.first.is_wire() && conn.first.as_wire()->port_output)
				first.as_wire()->port_output = true;
		} //end foreach conn in connections

		for (auto &conn : new_connections)
			module->connect(conn);

		module->fixup_ports(); //we have some new taint signals in the module interface
	}

	public:

	GliftPass() : Pass("glift", "create and transform GLIFT models"), opt_create(false), opt_sketchify(false), opt_taintconstants(false), module(nullptr) { }
	void help() YS_OVERRIDE
	{
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
		log("\n");
		log("    glift -create|-sketchify [options] [selection]\n");
		log("\n");
		log("Adds, removes, or manipulates gate-level information flow tracking (GLIFT) logic\n");
		log("to the current or specified module.\n");
		log("\n");
		log("Commands:");
		log("\n");
		log("  -create");
		log("    Replaces the current or specified module with one that has additional \"taint\"\n");
		log("    inputs, outputs, and internal nets along with precise taint-tracking logic.\n");
		log("\n");
		log("  -sketchify");
		log("    Replaces the current or specified module with one that has additional \"taint\"\n");
		log("    inputs, outputs, and internal nets along with varying-precision taint-tracking logic.\n");
		log("    Which version of taint tracking logic is used at a given cell is determined by a MUX\n");
		log("    selected by an $anyconst cell.\n");
		log("\n");
		log("Options:");
		log("\n");
		log("  -taint-constants");
		log("    Constant values in the design are labeled as tainted.\n");
		log("    (default: label constants as un-tainted)\n");
		log("\n");
	}
	void execute(std::vector<std::string> _args, RTLIL::Design *design) YS_OVERRIDE
	{
		log_header(design, "Executing GLIFT pass (creating and manipulating GLIFT models).\n");

		args = _args;
		parse_args();
		extra_args(args, argidx, design);

		for (auto mod : design->selected_modules()) {
			if (module)
				log_cmd_error("Only one module may be selected for the glift pass! Flatten the design if necessary. (selected: %s and %s)\n", log_id(module), log_id(mod));
			module = mod;
		}
		if (module == nullptr)
			log_cmd_error("Can't operate on an empty selection!\n");

		create_glift_logic();
	}
} GliftPass;

PRIVATE_NAMESPACE_END
<|endoftext|>


<commit_before>#include "rdb_protocol/terms/terms.hpp"

#include <string>
#include <utility>
#include <vector>

#include "rdb_protocol/error.hpp"
#include "rdb_protocol/func.hpp"
#include "rdb_protocol/op.hpp"
#include "rdb_protocol/pb_utils.hpp"

namespace ql {

// Most of the real logic for these is in datum_stream.cc.

class count_term_t : public op_term_t {
public:
    count_term_t(env_t *env, const protob_t<const Term> &term)
        : op_term_t(env, term, argspec_t(1, 2)) { }
private:
    virtual counted_t<val_t> eval_impl(env_t *env, UNUSED eval_flags_t flags) {
        if (num_args() == 1) {
            return new_val(arg(env, 0)->as_seq(env)->count(env));
        } else if (arg(env, 1)->get_type().is_convertible(val_t::type_t::FUNC)) {
            return new_val(arg(env, 0)->as_seq(env)->filter(env, arg(env, 1)->as_func(env), counted_t<func_t>())->count(env));
        } else {
            counted_t<func_t> f =
                func_t::new_eq_comparison_func(env, arg(env, 1)->as_datum(), backtrace());
            return new_val(arg(env, 0)->as_seq(env)->filter(env, f, counted_t<func_t>())->count(env));
        }
    }
    virtual const char *name() const { return "count"; }
};

class map_term_t : public op_term_t {
public:
    map_term_t(env_t *env, const protob_t<const Term> &term)
        : op_term_t(env, term, argspec_t(2)) { }
private:
    virtual counted_t<val_t> eval_impl(env_t *env, UNUSED eval_flags_t flags) {
        return new_val(env, arg(env, 0)->as_seq(env)->map(env, arg(env, 1)->as_func(env)));
    }
    virtual const char *name() const { return "map"; }
};

class concatmap_term_t : public op_term_t {
public:
    concatmap_term_t(env_t *env, const protob_t<const Term> &term)
        : op_term_t(env, term, argspec_t(2)) { }
private:
    virtual counted_t<val_t> eval_impl(env_t *env, UNUSED eval_flags_t flags) {
        return new_val(env, arg(env, 0)->as_seq(env)->concatmap(env, arg(env, 1)->as_func(env)));
    }
    virtual const char *name() const { return "concatmap"; }
};

class filter_term_t : public op_term_t {
public:
    filter_term_t(env_t *env, const protob_t<const Term> &term)
        : op_term_t(env, term, argspec_t(2), optargspec_t({"default"})),
          default_filter_val(lazy_literal_optarg(env, "default")) { }
private:
    virtual counted_t<val_t> eval_impl(env_t *env, UNUSED eval_flags_t flags) {
        counted_t<val_t> v0 = arg(env, 0);
        counted_t<val_t> v1 = arg(env, 1, LITERAL_OK);
        counted_t<func_t> f = v1->as_func(env, CONSTANT_SHORTCUT);
        if (v0->get_type().is_convertible(val_t::type_t::SELECTION)) {
            std::pair<counted_t<table_t>, counted_t<datum_stream_t> > ts
                = v0->as_selection(env);
            return new_val(ts.second->filter(env, f, default_filter_val), ts.first);
        } else {
            return new_val(env, v0->as_seq(env)->filter(env, f, default_filter_val));
        }
    }
    counted_t<func_t> default_filter_val;
    virtual const char *name() const { return "filter"; }
};

class reduce_term_t : public op_term_t {
public:
    reduce_term_t(env_t *env, const protob_t<const Term> &term) :
        op_term_t(env, term, argspec_t(2), optargspec_t({ "base" })) { }
private:
    virtual counted_t<val_t> eval_impl(env_t *env, UNUSED eval_flags_t flags) {
        return new_val(arg(env, 0)->as_seq(env)->reduce(env,
                                                   optarg(env, "base"),
                                                   arg(env, 1)->as_func(env)));
    }
    virtual const char *name() const { return "reduce"; }
};

// TODO: this sucks.  Change to use the same macros as rewrites.hpp?
class between_term_t : public bounded_op_term_t {
public:
    between_term_t(env_t *env, const protob_t<const Term> &term)
        : bounded_op_term_t(env, term, argspec_t(3), optargspec_t({"index"})) { }
private:
    virtual counted_t<val_t> eval_impl(env_t *env, UNUSED eval_flags_t flags) {
        counted_t<table_t> tbl = arg(env, 0)->as_table();
        counted_t<const datum_t> lb = arg(env, 1)->as_datum();
        if (lb->get_type() == datum_t::R_NULL) {
            lb.reset();
        }
        counted_t<const datum_t> rb = arg(env, 2)->as_datum();
        if (rb->get_type() == datum_t::R_NULL) {
            rb.reset();
        }

        if (lb.has() && rb.has()) {
            if (*lb > *rb || ((left_open(env) || right_open(env)) && *lb == *rb)) {
                counted_t<const datum_t> arr = make_counted<datum_t>(datum_t::R_ARRAY);
                counted_t<datum_stream_t> ds(
                    new array_datum_stream_t(arr, backtrace()));
                return new_val(ds, tbl);
            }
        }

        counted_t<val_t> sindex = optarg(env, "index");
        std::string sid = (sindex.has() ? sindex->as_str() : tbl->get_pkey());

        tbl->add_bounds(lb, left_open(env), rb, right_open(env), sid, this);
        return new_val(tbl);
    }
    virtual const char *name() const { return "between"; }

    protob_t<Term> filter_func;
};

class union_term_t : public op_term_t {
public:
    union_term_t(env_t *env, const protob_t<const Term> &term)
        : op_term_t(env, term, argspec_t(0, -1)) { }
private:
    virtual counted_t<val_t> eval_impl(env_t *env, UNUSED eval_flags_t flags) {
        std::vector<counted_t<datum_stream_t> > streams;
        for (size_t i = 0; i < num_args(); ++i) {
            streams.push_back(arg(env, i)->as_seq(env));
        }
        counted_t<datum_stream_t> union_stream
            = make_counted<union_datum_stream_t>(streams, backtrace());
        return new_val(env, union_stream);
    }
    virtual const char *name() const { return "union"; }
};

class zip_term_t : public op_term_t {
public:
    zip_term_t(env_t *env, const protob_t<const Term> &term)
        : op_term_t(env, term, argspec_t(1)) { }
private:
    virtual counted_t<val_t> eval_impl(env_t *env, UNUSED eval_flags_t flags) {
        return new_val(env, arg(env, 0)->as_seq(env)->zip());
    }
    virtual const char *name() const { return "zip"; }
};

counted_t<term_t> make_between_term(env_t *env, const protob_t<const Term> &term) {
    return make_counted<between_term_t>(env, term);
}
counted_t<term_t> make_reduce_term(env_t *env, const protob_t<const Term> &term) {
    return make_counted<reduce_term_t>(env, term);
}
counted_t<term_t> make_map_term(env_t *env, const protob_t<const Term> &term) {
    return make_counted<map_term_t>(env, term);
}
counted_t<term_t> make_filter_term(env_t *env, const protob_t<const Term> &term) {
    return make_counted<filter_term_t>(env, term);
}
counted_t<term_t> make_concatmap_term(env_t *env, const protob_t<const Term> &term) {
    return make_counted<concatmap_term_t>(env, term);
}
counted_t<term_t> make_count_term(env_t *env, const protob_t<const Term> &term) {
    return make_counted<count_term_t>(env, term);
}
counted_t<term_t> make_union_term(env_t *env, const protob_t<const Term> &term) {
    return make_counted<union_term_t>(env, term);
}
counted_t<term_t> make_zip_term(env_t *env, const protob_t<const Term> &term) {
    return make_counted<zip_term_t>(env, term);
}

} // namespace ql
<commit_msg>Made us not compute default_filter_val until the eval_impl in filter_term_t.<commit_after>#include "rdb_protocol/terms/terms.hpp"

#include <string>
#include <utility>
#include <vector>

#include "rdb_protocol/error.hpp"
#include "rdb_protocol/func.hpp"
#include "rdb_protocol/op.hpp"
#include "rdb_protocol/pb_utils.hpp"

namespace ql {

// Most of the real logic for these is in datum_stream.cc.

class count_term_t : public op_term_t {
public:
    count_term_t(env_t *env, const protob_t<const Term> &term)
        : op_term_t(env, term, argspec_t(1, 2)) { }
private:
    virtual counted_t<val_t> eval_impl(env_t *env, UNUSED eval_flags_t flags) {
        if (num_args() == 1) {
            return new_val(arg(env, 0)->as_seq(env)->count(env));
        } else if (arg(env, 1)->get_type().is_convertible(val_t::type_t::FUNC)) {
            return new_val(arg(env, 0)->as_seq(env)->filter(env, arg(env, 1)->as_func(env), counted_t<func_t>())->count(env));
        } else {
            counted_t<func_t> f =
                func_t::new_eq_comparison_func(env, arg(env, 1)->as_datum(), backtrace());
            return new_val(arg(env, 0)->as_seq(env)->filter(env, f, counted_t<func_t>())->count(env));
        }
    }
    virtual const char *name() const { return "count"; }
};

class map_term_t : public op_term_t {
public:
    map_term_t(env_t *env, const protob_t<const Term> &term)
        : op_term_t(env, term, argspec_t(2)) { }
private:
    virtual counted_t<val_t> eval_impl(env_t *env, UNUSED eval_flags_t flags) {
        return new_val(env, arg(env, 0)->as_seq(env)->map(env, arg(env, 1)->as_func(env)));
    }
    virtual const char *name() const { return "map"; }
};

class concatmap_term_t : public op_term_t {
public:
    concatmap_term_t(env_t *env, const protob_t<const Term> &term)
        : op_term_t(env, term, argspec_t(2)) { }
private:
    virtual counted_t<val_t> eval_impl(env_t *env, UNUSED eval_flags_t flags) {
        return new_val(env, arg(env, 0)->as_seq(env)->concatmap(env, arg(env, 1)->as_func(env)));
    }
    virtual const char *name() const { return "concatmap"; }
};

class filter_term_t : public op_term_t {
public:
    filter_term_t(env_t *env, const protob_t<const Term> &term)
        : op_term_t(env, term, argspec_t(2), optargspec_t({"default"})) { }

private:
    virtual counted_t<val_t> eval_impl(env_t *env, UNUSED eval_flags_t flags) {
        counted_t<val_t> v0 = arg(env, 0);
        counted_t<val_t> v1 = arg(env, 1, LITERAL_OK);
        counted_t<func_t> f = v1->as_func(env, CONSTANT_SHORTCUT);
        counted_t<func_t> default_filter_val = lazy_literal_optarg(env, "default");
        if (v0->get_type().is_convertible(val_t::type_t::SELECTION)) {
            std::pair<counted_t<table_t>, counted_t<datum_stream_t> > ts
                = v0->as_selection(env);
            return new_val(ts.second->filter(env, f, default_filter_val), ts.first);
        } else {
            return new_val(env, v0->as_seq(env)->filter(env, f, default_filter_val));
        }
    }

    virtual const char *name() const { return "filter"; }
};

class reduce_term_t : public op_term_t {
public:
    reduce_term_t(env_t *env, const protob_t<const Term> &term) :
        op_term_t(env, term, argspec_t(2), optargspec_t({ "base" })) { }
private:
    virtual counted_t<val_t> eval_impl(env_t *env, UNUSED eval_flags_t flags) {
        return new_val(arg(env, 0)->as_seq(env)->reduce(env,
                                                   optarg(env, "base"),
                                                   arg(env, 1)->as_func(env)));
    }
    virtual const char *name() const { return "reduce"; }
};

// TODO: this sucks.  Change to use the same macros as rewrites.hpp?
class between_term_t : public bounded_op_term_t {
public:
    between_term_t(env_t *env, const protob_t<const Term> &term)
        : bounded_op_term_t(env, term, argspec_t(3), optargspec_t({"index"})) { }
private:
    virtual counted_t<val_t> eval_impl(env_t *env, UNUSED eval_flags_t flags) {
        counted_t<table_t> tbl = arg(env, 0)->as_table();
        counted_t<const datum_t> lb = arg(env, 1)->as_datum();
        if (lb->get_type() == datum_t::R_NULL) {
            lb.reset();
        }
        counted_t<const datum_t> rb = arg(env, 2)->as_datum();
        if (rb->get_type() == datum_t::R_NULL) {
            rb.reset();
        }

        if (lb.has() && rb.has()) {
            if (*lb > *rb || ((left_open(env) || right_open(env)) && *lb == *rb)) {
                counted_t<const datum_t> arr = make_counted<datum_t>(datum_t::R_ARRAY);
                counted_t<datum_stream_t> ds(
                    new array_datum_stream_t(arr, backtrace()));
                return new_val(ds, tbl);
            }
        }

        counted_t<val_t> sindex = optarg(env, "index");
        std::string sid = (sindex.has() ? sindex->as_str() : tbl->get_pkey());

        tbl->add_bounds(lb, left_open(env), rb, right_open(env), sid, this);
        return new_val(tbl);
    }
    virtual const char *name() const { return "between"; }

    protob_t<Term> filter_func;
};

class union_term_t : public op_term_t {
public:
    union_term_t(env_t *env, const protob_t<const Term> &term)
        : op_term_t(env, term, argspec_t(0, -1)) { }
private:
    virtual counted_t<val_t> eval_impl(env_t *env, UNUSED eval_flags_t flags) {
        std::vector<counted_t<datum_stream_t> > streams;
        for (size_t i = 0; i < num_args(); ++i) {
            streams.push_back(arg(env, i)->as_seq(env));
        }
        counted_t<datum_stream_t> union_stream
            = make_counted<union_datum_stream_t>(streams, backtrace());
        return new_val(env, union_stream);
    }
    virtual const char *name() const { return "union"; }
};

class zip_term_t : public op_term_t {
public:
    zip_term_t(env_t *env, const protob_t<const Term> &term)
        : op_term_t(env, term, argspec_t(1)) { }
private:
    virtual counted_t<val_t> eval_impl(env_t *env, UNUSED eval_flags_t flags) {
        return new_val(env, arg(env, 0)->as_seq(env)->zip());
    }
    virtual const char *name() const { return "zip"; }
};

counted_t<term_t> make_between_term(env_t *env, const protob_t<const Term> &term) {
    return make_counted<between_term_t>(env, term);
}
counted_t<term_t> make_reduce_term(env_t *env, const protob_t<const Term> &term) {
    return make_counted<reduce_term_t>(env, term);
}
counted_t<term_t> make_map_term(env_t *env, const protob_t<const Term> &term) {
    return make_counted<map_term_t>(env, term);
}
counted_t<term_t> make_filter_term(env_t *env, const protob_t<const Term> &term) {
    return make_counted<filter_term_t>(env, term);
}
counted_t<term_t> make_concatmap_term(env_t *env, const protob_t<const Term> &term) {
    return make_counted<concatmap_term_t>(env, term);
}
counted_t<term_t> make_count_term(env_t *env, const protob_t<const Term> &term) {
    return make_counted<count_term_t>(env, term);
}
counted_t<term_t> make_union_term(env_t *env, const protob_t<const Term> &term) {
    return make_counted<union_term_t>(env, term);
}
counted_t<term_t> make_zip_term(env_t *env, const protob_t<const Term> &term) {
    return make_counted<zip_term_t>(env, term);
}

} // namespace ql
<|endoftext|>


<commit_before>// @(#)root/gui:$Name:  $:$Id: TRootContextMenu.cxx,v 1.7 2004/02/18 15:06:30 brun Exp $
// Author: Fons Rademakers   12/02/98

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TRootContextMenu                                                     //
//                                                                      //
// This class provides an interface to context sensitive popup menus.   //
// These menus pop up when the user hits the right mouse button, and    //
// are destroyed when the menu pops downs.                              //
// The picture below shows a canvas with a pop-up menu.                 //
//                                                                      //
//Begin_Html  End_Html                      //
//                                                                      //
// The picture below shows a canvas with a pop-up menu and a dialog box.//
//                                                                      //
//Begin_Html  End_Html                    //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TRootContextMenu.h"
#include "TROOT.h"
#include "TGClient.h"
#include "TList.h"
#include "TContextMenu.h"
#include "TMethod.h"
#include "TMethodArg.h"
#include "TClass.h"
#include "TVirtualX.h"
#include "TCanvas.h"
#include "TDataMember.h"
#include "TToggle.h"
#include "TRootDialog.h"
#include "TDataType.h"
#include "TCanvas.h"
#include "TBrowser.h"
#include "TRootCanvas.h"
#include "TRootBrowser.h"
#include "TClassMenuItem.h"

enum {
   kToggleStart       = 1000, // first id of toggle menu items
   kToggleListStart   = 2000, // first id of toggle list menu items
   kUserFunctionStart = 3000  // first id of user added functions/methods, etc...
};

ClassImp(TRootContextMenu)

//______________________________________________________________________________
TRootContextMenu::TRootContextMenu(TContextMenu *c, const char *)
    : TGPopupMenu(gClient->GetDefaultRoot()), TContextMenuImp(c)
{
   // Create context menu.

   fDialog  = 0;
   fCleanup = new TList;

   // Context menu handles its own messages
   Associate(this);
}

//______________________________________________________________________________
TRootContextMenu::~TRootContextMenu()
{
   // Delete a context menu.

   delete fDialog;
   if (fCleanup) fCleanup->Delete();
   delete fCleanup;
}

//______________________________________________________________________________
void TRootContextMenu::DisplayPopup(Int_t x, Int_t y)
{
   // Display context popup menu for currently selected object.

   // delete menu items releated to previous object and reset menu size
   if (fEntryList) fEntryList->Delete();
   if (fCleanup)   fCleanup->Delete();
   fMenuHeight = 6;
   fMenuWidth  = 8;

   // delete previous dialog
   if (fDialog) {
      delete fDialog;
      fDialog = 0;
   }

   // add menu items to popup menu
   CreateMenu(fContextMenu->GetSelectedObject());

   int    xx, yy, topx = 0, topy = 0;
   UInt_t w, h;

   if (fContextMenu->GetSelectedCanvas())
      gVirtualX->GetGeometry(fContextMenu->GetSelectedCanvas()->GetCanvasID(),
                        topx, topy, w, h);

   xx = topx + x + 1;
   yy = topy + y + 1;

   PlaceMenu(xx, yy, kFALSE, kTRUE);
}

//______________________________________________________________________________
void TRootContextMenu::CreateMenu(TObject *object)
{
   // Create the context menu depending on the selected object.

   int entry = 0, toggle = kToggleStart, togglelist = kToggleListStart;
   int userfunction = kUserFunctionStart;

   // Add a title
   AddLabel(fContextMenu->CreatePopupTitle(object));
   AddSeparator();

   // Get list of menu items from the selected object's class
   TList *menuItemList = object->IsA()->GetMenuList();

   TClassMenuItem *menuItem;
   TIter nextItem(menuItemList);

   while ((menuItem = (TClassMenuItem*) nextItem())) {
      switch (menuItem->GetType()) {
         case TClassMenuItem::kPopupSeparator:
            AddSeparator();
            break;
         case TClassMenuItem::kPopupStandardList:
            {
               // Standard list of class methods. Rebuild from scratch.
               // Get linked list of objects menu items (i.e. member functions
               // with the token *MENU in their comment fields.
               TList *methodList = new TList;
               object->IsA()->GetMenuItems(methodList);

               TMethod *method;
               TClass  *classPtr = 0;
               TIter next(methodList);

               while ((method = (TMethod*) next())) {
                  if (classPtr != method->GetClass()) {
                     AddSeparator();
                     classPtr = method->GetClass();
                  }

                  TDataMember *m;
                  EMenuItemKind menuKind = method->IsMenuItem();
                  switch (menuKind) {
                     case kMenuDialog:
                        AddEntry(method->GetName(), entry++, method);
                        break;
                     case kMenuSubMenu:
                        if ((m = method->FindDataMember())) {
                           if (m->GetterMethod()) {
                              TGPopupMenu *r = new TGPopupMenu(gClient->GetDefaultRoot());
                              AddPopup(method->GetName(), r);
                              fCleanup->Add(r);
                              TIter nxt(m->GetOptions());
                              TOptionListItem *it;
                              while ((it = (TOptionListItem*) nxt())) {
                                 char  *name  = it->fOptName;
                                 Long_t val   = it->fValue;

                                 TToggle *t = new TToggle;
                                 t->SetToggledObject(object, method);
                                 t->SetOnValue(val);
                                 fCleanup->Add(t);

                                 r->AddSeparator();
                                 r->AddEntry(name, togglelist++, t);
                                 if (t->GetState()) r->CheckEntry(togglelist-1);

                              }
                           } else {
                              AddEntry(method->GetName(), entry++, method);
                           }
                        }
                        break;

                     case kMenuToggle:
                        {
                           TToggle *t = new TToggle;
                           t->SetToggledObject(object, method);
                           t->SetOnValue(1);
                           fCleanup->Add(t);

                           AddEntry(method->GetName(), toggle++, t);
                           if (t->GetState()) CheckEntry(toggle-1);
                        }
                        break;

                     default:
                        break;
                  }
               }
               delete methodList;
            }
            break;
         case TClassMenuItem::kPopupUserFunction:
            {
               if (menuItem->IsToggle()) {
                  if (object) {
                     TMethod* method =
                           object->IsA()->GetMethodWithPrototype(menuItem->GetFunctionName(),menuItem->GetArgs());
                     TToggle *t = new TToggle;
                     t->SetToggledObject(object, method);
                     t->SetOnValue(1);
                     fCleanup->Add(t);

                     AddEntry(method->GetName(), toggle++, t);
                     if (t->GetState()) CheckEntry(toggle-1);
                  } else {
                     Warning("Dialog","Cannot use toggle for a global function");
                  }
               } else {
                  const char* menuItemTitle = menuItem->GetTitle();
                  if (strlen(menuItemTitle)==0) menuItemTitle = menuItem->GetFunctionName();
                  AddEntry(menuItemTitle,userfunction++,menuItem);
               }
            }
            break;
         default:
            break;
      }
   }
}

//______________________________________________________________________________
void TRootContextMenu::Dialog(TObject *object, TMethod *method)
{
   // Create dialog object with OK and Cancel buttons. This dialog
   // prompts for the arguments of "method".

   Dialog(object,(TFunction*)method);
}

//______________________________________________________________________________
void TRootContextMenu::Dialog(TObject *object, TFunction *function)
{
   // Create dialog object with OK and Cancel buttons. This dialog
   // prompts for the arguments of "function".
   // function may be a global function or a method

   Int_t selfobjpos;

   if (!function) return;

   // Position, if it exists, of the argument that correspond to the object itself
   if (fContextMenu->GetSelectedMenuItem())
      selfobjpos =  fContextMenu->GetSelectedMenuItem()->GetSelfObjectPos();
   else selfobjpos = -1;

   const TGWindow *w;
   if (fContextMenu->GetSelectedCanvas()) {
      TCanvas *c = (TCanvas *) fContextMenu->GetSelectedCanvas();
      // Embedded canvas has no canvasimp that is a TGFrame
      if (c->GetCanvasImp()->IsA()->InheritsFrom(TGFrame::Class()))
         w = (TRootCanvas *) c->GetCanvasImp();
      else
         w = gClient->GetDefaultRoot();
   } else if (fContextMenu->GetBrowser()) {
      TBrowser *b = (TBrowser *) fContextMenu->GetBrowser();
      w = (TRootBrowser *) b->GetBrowserImp();
   } else
      w = gClient->GetDefaultRoot();

   fDialog = new TRootDialog(this, w, fContextMenu->CreateDialogTitle(object, function));

   // iterate through all arguments and create apropriate input-data objects:
   // inputlines, option menus...
   TMethodArg *argument = 0;

   TIter next(function->GetListOfMethodArgs());
   Int_t argpos = 0;

   while ((argument = (TMethodArg *) next())) {
      // Do not input argument for self object
      if (selfobjpos != argpos) {
         Text_t       *argname    = fContextMenu->CreateArgumentTitle(argument);
         const Text_t *type       = argument->GetTypeName();
         TDataType    *datatype   = gROOT->GetType(type);
         const Text_t *charstar   = "char*";
         Text_t        basictype[32];

         if (datatype) {
            strcpy(basictype, datatype->GetTypeName());
         } else {
            TClass *cl = gROOT->GetClass(type);
            if (strncmp(type, "enum", 4) && (cl && !(cl->Property() & kIsEnum)))
               Warning("Dialog", "data type is not basic type, assuming (int)");
            strcpy(basictype, "int");
         }

         if (strchr(argname, '*')) {
            strcat(basictype, "*");
            type = charstar;
         }

         TDataMember *m = argument->GetDataMember();
         if (m && m->GetterMethod(object->IsA())) {

            // Get the current value and form it as a text:

            Text_t val[256];

            if (!strncmp(basictype, "char*", 5)) {
               Text_t *tdefval;
               m->GetterMethod()->Execute(object, "", &tdefval);
               strncpy(val, tdefval, 255);
            } else if (!strncmp(basictype, "float", 5) ||
                       !strncmp(basictype, "double", 6)) {
               Double_t ddefval;
               m->GetterMethod()->Execute(object, "", ddefval);
               sprintf(val, "%g", ddefval);
            } else if (!strncmp(basictype, "char", 4) ||
                       !strncmp(basictype, "bool", 4) ||
                       !strncmp(basictype, "int", 3)  ||
                       !strncmp(basictype, "long", 4) ||
                       !strncmp(basictype, "short", 5)) {
               Long_t ldefval;
               m->GetterMethod()->Execute(object, "", ldefval);
               sprintf(val, "%li", ldefval);
            }

            // Find out whether we have options ...

            TList *opt;
            if ((opt = m->GetOptions())) {
               Warning("Dialog", "option menu not yet implemented", opt);
#if 0
               TMotifOptionMenu *o= new TMotifOptionMenu(argname);
               TIter nextopt(opt);
               TOptionListItem *it = 0;
               while ((it = (TOptionListItem*) nextopt())) {
                  Text_t *name  = it->fOptName;
                  Text_t *label = it->fOptLabel;
                  Long_t value  = it->fValue;
                  if (value != -9999) {
                     Text_t val[256];
                     sprintf(val, "%li", value);
                     o->AddItem(name, val);
                  }else
                     o->AddItem(name, label);
               }
               o->SetData(val);
               fDialog->Add(o);
#endif
            } else {
               // we haven't got options - textfield ...
               fDialog->Add(argname, val, type);
            }
         } else {    // if m not found ...

            char val[256] = "";
            const char *tval = argument->GetDefault();
            if (tval) strncpy(val, tval, 255);
            fDialog->Add(argname, val, type);
         }
      }
      argpos++;
   }

   fDialog->Popup();
}

//______________________________________________________________________________
Bool_t TRootContextMenu::ProcessMessage(Long_t msg, Long_t parm1, Long_t parm2)
{
   // Handle context menu messages.

   switch (GET_MSG(msg)) {

      case kC_COMMAND:

         switch (GET_SUBMSG(msg)) {

            case kCM_MENU:

               if (parm1 < kToggleStart) {
                  TMethod *m = (TMethod *) parm2;
                  GetContextMenu()->Action(m);
               } else if (parm1 >= kToggleStart && parm1 < kToggleListStart) {
                  TToggle *t = (TToggle *) parm2;
                  GetContextMenu()->Action(t);
               } else if (parm1 >= kToggleListStart && parm1<kUserFunctionStart) {
                  TToggle *t = (TToggle *) parm2;
                  if (t->GetState() == 0)
                     t->SetState(1);
               } else {
                  TClassMenuItem *mi = (TClassMenuItem*)parm2;
                  GetContextMenu()->Action(mi);
               }
               break;

            case kCM_BUTTON:
               if (parm1 == 1) {
                  const char *args = fDialog->GetParameters();
                  GetContextMenu()->Execute((char *)args);
                  delete fDialog;
                  fDialog = 0;
               }
               if (parm1 == 2) {
                  const char *args = fDialog->GetParameters();
                  GetContextMenu()->Execute((char *)args);
               }
               if (parm1 == 3) {
                  delete fDialog;
                  fDialog = 0;
               }
               break;

            default:
               break;
         }
         break;

      case kC_TEXTENTRY:

         switch (GET_SUBMSG(msg)) {

            case kTE_ENTER:
               {
                  const char *args = fDialog->GetParameters();
                  GetContextMenu()->Execute((char *)args);
                  delete fDialog;
                  fDialog = 0;
               }
               break;

            default:
               break;
         }
         break;

      default:
         break;
   }

   return kTRUE;
}
<commit_msg>From Valeriy Onuchin:  - fix for placing context menu in case of embedded canvas    The problem was reported at    http://root.cern.ch/phpBB2/viewtopic.php?t=580    Thanks to Andrea Bulgarelli.<commit_after>// @(#)root/gui:$Name:  $:$Id: TRootContextMenu.cxx,v 1.8 2004/03/12 00:31:22 rdm Exp $
// Author: Fons Rademakers   12/02/98

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TRootContextMenu                                                     //
//                                                                      //
// This class provides an interface to context sensitive popup menus.   //
// These menus pop up when the user hits the right mouse button, and    //
// are destroyed when the menu pops downs.                              //
// The picture below shows a canvas with a pop-up menu.                 //
//                                                                      //
//Begin_Html  End_Html                      //
//                                                                      //
// The picture below shows a canvas with a pop-up menu and a dialog box.//
//                                                                      //
//Begin_Html  End_Html                    //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TRootContextMenu.h"
#include "TROOT.h"
#include "TGClient.h"
#include "TList.h"
#include "TContextMenu.h"
#include "TMethod.h"
#include "TMethodArg.h"
#include "TClass.h"
#include "TVirtualX.h"
#include "TCanvas.h"
#include "TDataMember.h"
#include "TToggle.h"
#include "TRootDialog.h"
#include "TDataType.h"
#include "TCanvas.h"
#include "TBrowser.h"
#include "TRootCanvas.h"
#include "TRootBrowser.h"
#include "TClassMenuItem.h"

enum {
   kToggleStart       = 1000, // first id of toggle menu items
   kToggleListStart   = 2000, // first id of toggle list menu items
   kUserFunctionStart = 3000  // first id of user added functions/methods, etc...
};

ClassImp(TRootContextMenu)

//______________________________________________________________________________
TRootContextMenu::TRootContextMenu(TContextMenu *c, const char *)
    : TGPopupMenu(gClient->GetDefaultRoot()), TContextMenuImp(c)
{
   // Create context menu.

   fDialog  = 0;
   fCleanup = new TList;

   // Context menu handles its own messages
   Associate(this);
}

//______________________________________________________________________________
TRootContextMenu::~TRootContextMenu()
{
   // Delete a context menu.

   delete fDialog;
   if (fCleanup) fCleanup->Delete();
   delete fCleanup;
}

//______________________________________________________________________________
void TRootContextMenu::DisplayPopup(Int_t x, Int_t y)
{
   // Display context popup menu for currently selected object.

   // delete menu items releated to previous object and reset menu size
   if (fEntryList) fEntryList->Delete();
   if (fCleanup)   fCleanup->Delete();
   fMenuHeight = 6;
   fMenuWidth  = 8;

   // delete previous dialog
   if (fDialog) {
      delete fDialog;
      fDialog = 0;
   }

   // add menu items to popup menu
   CreateMenu(fContextMenu->GetSelectedObject());

   int    xx, yy, topx = 0, topy = 0;
   UInt_t w, h;

   if (fContextMenu->GetSelectedCanvas())
      gVirtualX->GetGeometry(fContextMenu->GetSelectedCanvas()->GetCanvasID(),
                        topx, topy, w, h);

   xx = topx + x + 1;
   yy = topy + y + 1;

   PlaceMenu(xx, yy, kFALSE, kTRUE);
}

//______________________________________________________________________________
void TRootContextMenu::CreateMenu(TObject *object)
{
   // Create the context menu depending on the selected object.

   int entry = 0, toggle = kToggleStart, togglelist = kToggleListStart;
   int userfunction = kUserFunctionStart;

   // Add a title
   AddLabel(fContextMenu->CreatePopupTitle(object));
   AddSeparator();

   // Get list of menu items from the selected object's class
   TList *menuItemList = object->IsA()->GetMenuList();

   TClassMenuItem *menuItem;
   TIter nextItem(menuItemList);

   while ((menuItem = (TClassMenuItem*) nextItem())) {
      switch (menuItem->GetType()) {
         case TClassMenuItem::kPopupSeparator:
            AddSeparator();
            break;
         case TClassMenuItem::kPopupStandardList:
            {
               // Standard list of class methods. Rebuild from scratch.
               // Get linked list of objects menu items (i.e. member functions
               // with the token *MENU in their comment fields.
               TList *methodList = new TList;
               object->IsA()->GetMenuItems(methodList);

               TMethod *method;
               TClass  *classPtr = 0;
               TIter next(methodList);

               while ((method = (TMethod*) next())) {
                  if (classPtr != method->GetClass()) {
                     AddSeparator();
                     classPtr = method->GetClass();
                  }

                  TDataMember *m;
                  EMenuItemKind menuKind = method->IsMenuItem();
                  switch (menuKind) {
                     case kMenuDialog:
                        AddEntry(method->GetName(), entry++, method);
                        break;
                     case kMenuSubMenu:
                        if ((m = method->FindDataMember())) {
                           if (m->GetterMethod()) {
                              TGPopupMenu *r = new TGPopupMenu(gClient->GetDefaultRoot());
                              AddPopup(method->GetName(), r);
                              fCleanup->Add(r);
                              TIter nxt(m->GetOptions());
                              TOptionListItem *it;
                              while ((it = (TOptionListItem*) nxt())) {
                                 char  *name  = it->fOptName;
                                 Long_t val   = it->fValue;

                                 TToggle *t = new TToggle;
                                 t->SetToggledObject(object, method);
                                 t->SetOnValue(val);
                                 fCleanup->Add(t);

                                 r->AddSeparator();
                                 r->AddEntry(name, togglelist++, t);
                                 if (t->GetState()) r->CheckEntry(togglelist-1);

                              }
                           } else {
                              AddEntry(method->GetName(), entry++, method);
                           }
                        }
                        break;

                     case kMenuToggle:
                        {
                           TToggle *t = new TToggle;
                           t->SetToggledObject(object, method);
                           t->SetOnValue(1);
                           fCleanup->Add(t);

                           AddEntry(method->GetName(), toggle++, t);
                           if (t->GetState()) CheckEntry(toggle-1);
                        }
                        break;

                     default:
                        break;
                  }
               }
               delete methodList;
            }
            break;
         case TClassMenuItem::kPopupUserFunction:
            {
               if (menuItem->IsToggle()) {
                  if (object) {
                     TMethod* method =
                           object->IsA()->GetMethodWithPrototype(menuItem->GetFunctionName(),menuItem->GetArgs());
                     TToggle *t = new TToggle;
                     t->SetToggledObject(object, method);
                     t->SetOnValue(1);
                     fCleanup->Add(t);

                     AddEntry(method->GetName(), toggle++, t);
                     if (t->GetState()) CheckEntry(toggle-1);
                  } else {
                     Warning("Dialog","Cannot use toggle for a global function");
                  }
               } else {
                  const char* menuItemTitle = menuItem->GetTitle();
                  if (strlen(menuItemTitle)==0) menuItemTitle = menuItem->GetFunctionName();
                  AddEntry(menuItemTitle,userfunction++,menuItem);
               }
            }
            break;
         default:
            break;
      }
   }
}

//______________________________________________________________________________
void TRootContextMenu::Dialog(TObject *object, TMethod *method)
{
   // Create dialog object with OK and Cancel buttons. This dialog
   // prompts for the arguments of "method".

   Dialog(object,(TFunction*)method);
}

//______________________________________________________________________________
void TRootContextMenu::Dialog(TObject *object, TFunction *function)
{
   // Create dialog object with OK and Cancel buttons. This dialog
   // prompts for the arguments of "function".
   // function may be a global function or a method

   Int_t selfobjpos;

   if (!function) return;

   // Position, if it exists, of the argument that correspond to the object itself
   if (fContextMenu->GetSelectedMenuItem())
      selfobjpos =  fContextMenu->GetSelectedMenuItem()->GetSelfObjectPos();
   else selfobjpos = -1;

   const TGWindow *w;
   if (fContextMenu->GetSelectedCanvas()) {
      TCanvas *c = (TCanvas *) fContextMenu->GetSelectedCanvas();
      // Embedded canvas has no canvasimp that is a TGFrame
      if (c->GetCanvasImp()->IsA()->InheritsFrom(TGFrame::Class())) {
         w = fClient->GetWindowById(gVirtualX->GetWindowID(c->GetCanvasID()));
         if (!w) w = (TRootCanvas *) c->GetCanvasImp();
      } else {
         w = gClient->GetDefaultRoot();
      }
   } else if (fContextMenu->GetBrowser()) {
      TBrowser *b = (TBrowser *) fContextMenu->GetBrowser();
      w = (TRootBrowser *) b->GetBrowserImp();
   } else {
      w = gClient->GetDefaultRoot();
   }
   fDialog = new TRootDialog(this, w, fContextMenu->CreateDialogTitle(object, function));

   // iterate through all arguments and create apropriate input-data objects:
   // inputlines, option menus...
   TMethodArg *argument = 0;

   TIter next(function->GetListOfMethodArgs());
   Int_t argpos = 0;

   while ((argument = (TMethodArg *) next())) {
      // Do not input argument for self object
      if (selfobjpos != argpos) {
         Text_t       *argname    = fContextMenu->CreateArgumentTitle(argument);
         const Text_t *type       = argument->GetTypeName();
         TDataType    *datatype   = gROOT->GetType(type);
         const Text_t *charstar   = "char*";
         Text_t        basictype[32];

         if (datatype) {
            strcpy(basictype, datatype->GetTypeName());
         } else {
            TClass *cl = gROOT->GetClass(type);
            if (strncmp(type, "enum", 4) && (cl && !(cl->Property() & kIsEnum)))
               Warning("Dialog", "data type is not basic type, assuming (int)");
            strcpy(basictype, "int");
         }

         if (strchr(argname, '*')) {
            strcat(basictype, "*");
            type = charstar;
         }

         TDataMember *m = argument->GetDataMember();
         if (m && m->GetterMethod(object->IsA())) {

            // Get the current value and form it as a text:

            Text_t val[256];

            if (!strncmp(basictype, "char*", 5)) {
               Text_t *tdefval;
               m->GetterMethod()->Execute(object, "", &tdefval);
               strncpy(val, tdefval, 255);
            } else if (!strncmp(basictype, "float", 5) ||
                       !strncmp(basictype, "double", 6)) {
               Double_t ddefval;
               m->GetterMethod()->Execute(object, "", ddefval);
               sprintf(val, "%g", ddefval);
            } else if (!strncmp(basictype, "char", 4) ||
                       !strncmp(basictype, "bool", 4) ||
                       !strncmp(basictype, "int", 3)  ||
                       !strncmp(basictype, "long", 4) ||
                       !strncmp(basictype, "short", 5)) {
               Long_t ldefval;
               m->GetterMethod()->Execute(object, "", ldefval);
               sprintf(val, "%li", ldefval);
            }

            // Find out whether we have options ...

            TList *opt;
            if ((opt = m->GetOptions())) {
               Warning("Dialog", "option menu not yet implemented", opt);
#if 0
               TMotifOptionMenu *o= new TMotifOptionMenu(argname);
               TIter nextopt(opt);
               TOptionListItem *it = 0;
               while ((it = (TOptionListItem*) nextopt())) {
                  Text_t *name  = it->fOptName;
                  Text_t *label = it->fOptLabel;
                  Long_t value  = it->fValue;
                  if (value != -9999) {
                     Text_t val[256];
                     sprintf(val, "%li", value);
                     o->AddItem(name, val);
                  }else
                     o->AddItem(name, label);
               }
               o->SetData(val);
               fDialog->Add(o);
#endif
            } else {
               // we haven't got options - textfield ...
               fDialog->Add(argname, val, type);
            }
         } else {    // if m not found ...

            char val[256] = "";
            const char *tval = argument->GetDefault();
            if (tval) strncpy(val, tval, 255);
            fDialog->Add(argname, val, type);
         }
      }
      argpos++;
   }

   fDialog->Popup();
}

//______________________________________________________________________________
Bool_t TRootContextMenu::ProcessMessage(Long_t msg, Long_t parm1, Long_t parm2)
{
   // Handle context menu messages.

   switch (GET_MSG(msg)) {

      case kC_COMMAND:

         switch (GET_SUBMSG(msg)) {

            case kCM_MENU:

               if (parm1 < kToggleStart) {
                  TMethod *m = (TMethod *) parm2;
                  GetContextMenu()->Action(m);
               } else if (parm1 >= kToggleStart && parm1 < kToggleListStart) {
                  TToggle *t = (TToggle *) parm2;
                  GetContextMenu()->Action(t);
               } else if (parm1 >= kToggleListStart && parm1<kUserFunctionStart) {
                  TToggle *t = (TToggle *) parm2;
                  if (t->GetState() == 0)
                     t->SetState(1);
               } else {
                  TClassMenuItem *mi = (TClassMenuItem*)parm2;
                  GetContextMenu()->Action(mi);
               }
               break;

            case kCM_BUTTON:
               if (parm1 == 1) {
                  const char *args = fDialog->GetParameters();
                  GetContextMenu()->Execute((char *)args);
                  delete fDialog;
                  fDialog = 0;
               }
               if (parm1 == 2) {
                  const char *args = fDialog->GetParameters();
                  GetContextMenu()->Execute((char *)args);
               }
               if (parm1 == 3) {
                  delete fDialog;
                  fDialog = 0;
               }
               break;

            default:
               break;
         }
         break;

      case kC_TEXTENTRY:

         switch (GET_SUBMSG(msg)) {

            case kTE_ENTER:
               {
                  const char *args = fDialog->GetParameters();
                  GetContextMenu()->Execute((char *)args);
                  delete fDialog;
                  fDialog = 0;
               }
               break;

            default:
               break;
         }
         break;

      default:
         break;
   }

   return kTRUE;
}
<|endoftext|>


<commit_before>//=====================================================================//
/*! @file
    @brief  RX24T CNC ドライバー @n
			・ステッピングモーターパルス出力 @n
			・リミットスイッチによる制御 @n
			・P00(4) ピンに赤色LED（VF:1.9V）を吸い込みで接続する
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2018 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include "common/cmt_io.hpp"
#include "common/fifo.hpp"
#include "common/sci_io.hpp"
#include "common/format.hpp"
#include "common/command.hpp"

namespace {

	device::cmt_io<device::CMT0, utils::null_task>  cmt_;

	typedef utils::fifo<uint8_t, 1024> RBF;
	typedef utils::fifo<uint8_t, 128> SBF;
	typedef device::sci_io<device::SCI1, RBF, SBF> SCI;
	SCI		sci_;

	utils::command<256> command_;
}

extern "C" {

	void sci_putch(char ch)
	{
		sci_.putch(ch);
	}

	void sci_puts(const char* str)
	{
		sci_.puts(str);
	}

	char sci_getch(void)
	{
		return sci_.getch();
	}

	uint16_t sci_length()
	{
		return sci_.recv_length();
	}

}

int main(int argc, char** argv);

int main(int argc, char** argv)
{
	device::SYSTEM::PRCR = 0xA50B;	// クロック、低消費電力、関係書き込み許可

	device::SYSTEM::MEMWAIT = 0b10; // 80MHz 動作 wait 設定

	while(device::SYSTEM::OPCCR.OPCMTSF() != 0) asm("nop");
	device::SYSTEM::OPCCR = 0;  // 高速モード選択
	while(device::SYSTEM::OPCCR.OPCMTSF() != 0) asm("nop");

	// clock osc 10MHz
	device::SYSTEM::MOSCWTCR = 9;	// 4ms wait
	// メインクロック・ドライブ能力設定、内部発信
	device::SYSTEM::MOFCR = device::SYSTEM::MOFCR.MODRV21.b(1);
	device::SYSTEM::MOSCCR.MOSTP = 0;  // メインクロック発振器動作
	while(device::SYSTEM::OSCOVFSR.MOOVF() == 0) asm("nop");

	device::SYSTEM::PLLCR.STC = 0b001111;		// PLL input: 1, PLL 8 倍(80MHz)
	device::SYSTEM::PLLCR2.PLLEN = 0;			// PLL 動作
	while(device::SYSTEM::OSCOVFSR.PLOVF() == 0) asm("nop");

	device::SYSTEM::SCKCR = device::SYSTEM::SCKCR.FCK.b(2)		// 1/4 (80/4=20)
						  | device::SYSTEM::SCKCR.ICK.b(0)		// 1/1 (80/1=80)
						  | device::SYSTEM::SCKCR.PCKA.b(0)		// 1/1 (80/1=80)
						  | device::SYSTEM::SCKCR.PCKB.b(1)		// 1/2 (80/2=40)
						  | device::SYSTEM::SCKCR.PCKD.b(1);	// 1/2 (80/2=40)
	device::SYSTEM::SCKCR3.CKSEL = 0b100;	///< PLL 選択

	// タイマー設定（６０Ｈｚ）
	uint8_t cmt_irq_level = 4;
	cmt_.start(60, cmt_irq_level);

	// SCI 設定
	static const uint8_t sci_level = 2;
	sci_.start(115200, sci_level);

	utils::format("RX24T CNC Driver\n");

	command_.set_prompt("# ");

	device::PORT0::PDR.B0 = 1; // output

	uint32_t cnt = 0;
	while(1) {
		cmt_.sync();

		// コマンド入力と、コマンド解析
		if(command_.service()) {

		}

		++cnt;
		if(cnt >= 30) {
			cnt = 0;
		}
		device::PORT0::PODR.B0 = (cnt < 10) ? 0 : 1;
	}
}
<commit_msg>update: CNC main/sub<commit_after>//=====================================================================//
/*! @file
    @brief  RX24T CNC ドライバー @n
			・ステッピングモーターパルス出力 @n
			・リミットスイッチによる制御 @n
			・P00(4) ピンに赤色LED（VF:1.9V）を吸い込みで接続する
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2018 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include "common/renesas.hpp"
#include "common/cmt_io.hpp"
#include "common/fixed_fifo.hpp"
#include "common/sci_io.hpp"
#include "common/format.hpp"
#include "common/command.hpp"

#include "cnc_pulse.hpp"

namespace {

	typedef device::PORT<device::PORT0, device::bitpos::B0> LED;

	device::cmt_io<device::CMT0, utils::null_task>  cmt_;

	typedef utils::fixed_fifo<char, 1024> RBF;
	typedef utils::fixed_fifo<char,  128> SBF;
	typedef device::sci_io<device::SCI1, RBF, SBF> SCI;
	SCI		sci_;

	typedef utils::command<256> COMMAND;
	COMMAND command_;

	typedef cnc::pulse<COMMAND>	CNC;
	CNC		cnc_(command_);

}

extern "C" {

	void sci_putch(char ch)
	{
		sci_.putch(ch);
	}

	void sci_puts(const char* str)
	{
		sci_.puts(str);
	}

	char sci_getch(void)
	{
		return sci_.getch();
	}

	uint16_t sci_length()
	{
		return sci_.recv_length();
	}

}

int main(int argc, char** argv);

int main(int argc, char** argv)
{
	device::SYSTEM::PRCR = 0xA50B;	// クロック、低消費電力、関係書き込み許可

	device::SYSTEM::MEMWAIT = 0b10; // 80MHz 動作 wait 設定

	while(device::SYSTEM::OPCCR.OPCMTSF() != 0) asm("nop");
	device::SYSTEM::OPCCR = 0;  // 高速モード選択
	while(device::SYSTEM::OPCCR.OPCMTSF() != 0) asm("nop");

	// clock osc 10MHz
	device::SYSTEM::MOSCWTCR = 9;	// 4ms wait
	// メインクロック・ドライブ能力設定、内部発信
	device::SYSTEM::MOFCR = device::SYSTEM::MOFCR.MODRV21.b(1);
	device::SYSTEM::MOSCCR.MOSTP = 0;  // メインクロック発振器動作
	while(device::SYSTEM::OSCOVFSR.MOOVF() == 0) asm("nop");

	device::SYSTEM::PLLCR.STC = 0b001111;		// PLL input: 1, PLL 8 倍(80MHz)
	device::SYSTEM::PLLCR2.PLLEN = 0;			// PLL 動作
	while(device::SYSTEM::OSCOVFSR.PLOVF() == 0) asm("nop");

	device::SYSTEM::SCKCR = device::SYSTEM::SCKCR.FCK.b(2)		// 1/4 (80/4=20)
						  | device::SYSTEM::SCKCR.ICK.b(0)		// 1/1 (80/1=80)
						  | device::SYSTEM::SCKCR.PCKA.b(0)		// 1/1 (80/1=80)
						  | device::SYSTEM::SCKCR.PCKB.b(1)		// 1/2 (80/2=40)
						  | device::SYSTEM::SCKCR.PCKD.b(1);	// 1/2 (80/2=40)
	device::SYSTEM::SCKCR3.CKSEL = 0b100;	///< PLL 選択

	// タイマー設定（６０Ｈｚ）
	{
		uint8_t intr = 4;
		cmt_.start(60, intr);
	}

	// SCI 設定
	static const uint8_t sci_level = 2;
	sci_.start(115200, sci_level);

	utils::format("RX24T CNC Driver\n");

	cnc_.start();

	command_.set_prompt("# ");

	LED::DIR = 1;

	uint32_t cnt = 0;
	while(1) {
		cmt_.sync();

		// コマンド入力と、コマンド解析
		if(command_.service()) {
			auto f = cnc_.service_command();
			if(!f) {
				utils::format("Error: '%s'\n") % command_.get_command();
			}
		}

		++cnt;
		if(cnt >= 30) {
			cnt = 0;
		}
		LED::P = (cnt < 10) ? 0 : 1;
	}
}
<|endoftext|>