<commit_before>/**
@file
IE to represent generic integral value

@copyright Denis Priyomov 2016-2017
Distributed under the MIT License
(See accompanying file LICENSE or visit https://github.com/cppden/med)
*/

#pragma once

#include <type_traits>

#include "units.hpp"
#include "ie_type.hpp"
#include "name.hpp"
#include "exception.hpp"

namespace med {

//traits representing a fixed value of particular size (in bits/bytes/int)
//which is predefined during encode and decode
template <std::size_t VAL, typename T, class... EXT_TRAITS>
struct fixed : value_traits<T, EXT_TRAITS...>
{
	static constexpr bool is_const = true;
	static constexpr typename value_traits<T, EXT_TRAITS...>::value_type value = VAL;
};

//traits representing a fixed value with default
template <std::size_t VAL, class T, class... EXT_TRAITS>
struct defaults : value_traits<T, EXT_TRAITS...>
{
	static constexpr typename value_traits<T, EXT_TRAITS...>::value_type default_value = VAL;
};

//traits representing initialized value which is encoded with the fixed value
//but can have any value when decoded
template <std::size_t VAL, class T, class... EXT_TRAITS>
struct init : fixed<VAL, T, EXT_TRAITS...>
{
	static constexpr bool is_const = false;
};

namespace detail {

/**
 * plain numeric value
 */
template <class TRAITS>
struct numeric_value : IE<IE_VALUE>
{
	using traits     = TRAITS;
	using value_type = typename traits::value_type;
	using base_t     = numeric_value;

	value_type get() const                          { return get_encoded(); }
	auto set(value_type v)                          { return set_encoded(v); }

	//NOTE: do not override!
	static constexpr bool is_const = false;
	value_type get_encoded() const                  { return m_value; }
	void set_encoded(value_type v)                  { m_value = v; m_set = true; }
	void clear()                                    { m_set = false; }
	bool is_set() const                             { return m_set; }
	explicit operator bool() const                  { return is_set(); }
	template <class... ARGS>
	void copy(base_t const& from, ARGS&&...)        { m_value = from.m_value; m_set = from.m_set; }

#if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ < 9)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#endif
	bool operator==(numeric_value const& rhs) const { return is_set() == rhs.is_set() && (!is_set() || get() == rhs.get()); }
#if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ < 9)
#pragma GCC diagnostic pop
#endif

	bool operator!=(numeric_value const& rhs) const { return !this->operator==(rhs); }

private:
	bool       m_set{false};
	value_type m_value{};
};

/**
 * plain fixed integral value
 * gives error if decoded value doesn't match the fixed one
 */
template <class TRAITS>
struct const_integer : IE<IE_VALUE>
{
	using traits     = TRAITS;
	using value_type = typename traits::value_type;
	using base_t = const_integer;
	using writable = numeric_value<traits>;

	static constexpr void clear()                       { }
	static constexpr value_type get()                   { return get_encoded(); }

	//NOTE: do not override!
	static constexpr bool is_const = true;
	explicit operator bool() const                      { return is_set(); }
	static constexpr value_type get_encoded()           { return traits::value; }
	static constexpr bool set_encoded(value_type v)     { return traits::value == v; }
	static constexpr bool is_set()                      { return true; }
	static constexpr bool match(value_type v)           { return traits::value == v; }
	template <class... ARGS>
	static constexpr void copy(base_t const&, ARGS&&...){ }

	bool operator==(const_integer const&) const         { return true; } //equal to itself by definition
	bool operator!=(const_integer const&) const         { return false; }
};

/**
 * plain initialized/set field
 * decoded even if doesn't match initial value
 */
template <class TRAITS>
struct init_integer : IE<IE_VALUE>
{
	using traits     = TRAITS;
	using value_type = typename traits::value_type;
	using base_t     = init_integer;

	static constexpr void clear()                       { }
	explicit operator bool() const                      { return is_set(); }
	//NOTE: do not override!
	static constexpr bool is_const = true;
	static constexpr value_type get_encoded()           { return traits::value; }
	static constexpr void set_encoded(value_type)       { }
	static constexpr bool is_set()                      { return true; }
	template <class... ARGS>
	static constexpr void copy(base_t const&, ARGS&&...){ }
	bool operator==(init_integer const&) const          { return true; }
	bool operator!=(init_integer const&) const          { return false; }
};

/**
 * integer with a default value
 */
template <class TRAITS>
struct def_integer : numeric_value<TRAITS>
{
	using traits     = TRAITS;
	using value_type = typename traits::value_type;
	using base_t     = def_integer;

	//NOTE: do not override!
	value_type get_encoded() const
	{
		return this->is_set() ? numeric_value<TRAITS>::get_encoded() : traits::default_value;
	}
};

//meta-function to select proper implementation of numeric value
template <class T, typename Enable = void>
struct value_selector;

template <class T>
struct value_selector<T,
	std::enable_if_t<
		std::is_same_v<typename T::value_type, std::remove_const_t<decltype(T::value)>>
		&& T::is_const
	>
>
{
	using type = const_integer<T>;
};

template <class T>
struct value_selector<T,
	std::enable_if_t<
		std::is_same_v<typename T::value_type, std::remove_const_t<decltype(T::value)>>
		&& !T::is_const
	>
>
{
	using type = init_integer<T>;
};

template <class T>
struct value_selector<T,
	std::enable_if_t<
		std::is_same_v<typename T::value_type, std::remove_const_t<decltype(T::default_value)>>
	>
>
{
	using type = def_integer<T>;
};

template <class T, class Enable, class... EXT_TRAITS>
struct value;

template <class T>
struct value<T, std::enable_if_t<is_value_traits<T>::value>>
		: value_selector<T>::type {};

template<class T, class... EXT_TRAITS>
struct value<T, std::enable_if_t<std::is_arithmetic_v<T>>, EXT_TRAITS...>
		: numeric_value<value_traits<T, EXT_TRAITS...>> {};

template<std::size_t N, class... EXT_TRAITS>
struct value<bytes<N>, void, EXT_TRAITS...>
		: numeric_value<value_traits<bytes<N>, EXT_TRAITS...>> {};

template<std::size_t N, class... EXT_TRAITS>
struct value<bits<N>, void, EXT_TRAITS...>
		: numeric_value<value_traits<bits<N>, EXT_TRAITS...>> {};

} //end: namespace detail

/**
 * generic value - a facade for numeric_values above
 */
template <class T, class... EXT_TRAITS>
struct value : detail::value<T, void, EXT_TRAITS...> {};

} //namespace med
<commit_msg>fix builds<commit_after>/**
@file
IE to represent generic integral value

@copyright Denis Priyomov 2016-2017
Distributed under the MIT License
(See accompanying file LICENSE or visit https://github.com/cppden/med)
*/

#pragma once

#include <type_traits>

#include "units.hpp"
#include "ie_type.hpp"
#include "name.hpp"
#include "exception.hpp"

namespace med {

//traits representing a fixed value of particular size (in bits/bytes/int)
//which is predefined during encode and decode
template <std::size_t VAL, typename T, class... EXT_TRAITS>
struct fixed : value_traits<T, EXT_TRAITS...>
{
	static constexpr bool is_const = true;
	static constexpr typename value_traits<T, EXT_TRAITS...>::value_type value = VAL;
};

//traits representing a fixed value with default
template <std::size_t VAL, class T, class... EXT_TRAITS>
struct defaults : value_traits<T, EXT_TRAITS...>
{
	static constexpr typename value_traits<T, EXT_TRAITS...>::value_type default_value = VAL;
};

//traits representing initialized value which is encoded with the fixed value
//but can have any value when decoded
template <std::size_t VAL, class T, class... EXT_TRAITS>
struct init : fixed<VAL, T, EXT_TRAITS...>
{
	static constexpr bool is_const = false;
};

namespace detail {

/**
 * plain numeric value
 */
template <class TRAITS>
struct numeric_value : IE<IE_VALUE>
{
	using traits     = TRAITS;
	using value_type = typename traits::value_type;
	using base_t     = numeric_value;

	value_type get() const                          { return get_encoded(); }
	auto set(value_type v)                          { return set_encoded(v); }

	//NOTE: do not override!
	static constexpr bool is_const = false;
	value_type get_encoded() const                  { return m_value; }
	void set_encoded(value_type v)                  { m_value = v; m_set = true; }
	void clear()                                    { m_set = false; }
	bool is_set() const                             { return m_set; }
	explicit operator bool() const                  { return is_set(); }
	template <class... ARGS>
	void copy(base_t const& from, ARGS&&...)        { m_value = from.m_value; m_set = from.m_set; }

#if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ < 9)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#endif

	bool operator==(numeric_value const& rhs) const { return is_set() == rhs.is_set() && (!is_set() || get() == rhs.get()); }

#if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ < 9)
#pragma GCC diagnostic pop
#endif

	bool operator!=(numeric_value const& rhs) const { return !this->operator==(rhs); }

private:
	bool       m_set{false};
	value_type m_value{};
};

/**
 * plain fixed integral value
 * gives error if decoded value doesn't match the fixed one
 */
template <class TRAITS>
struct const_integer : IE<IE_VALUE>
{
	using traits     = TRAITS;
	using value_type = typename traits::value_type;
	using base_t = const_integer;
	using writable = numeric_value<traits>;

	static constexpr void clear()                       { }
	static constexpr value_type get()                   { return get_encoded(); }

	//NOTE: do not override!
	static constexpr bool is_const = true;
	explicit operator bool() const                      { return is_set(); }
	static constexpr value_type get_encoded()           { return traits::value; }
	static constexpr bool set_encoded(value_type v)     { return traits::value == v; }
	static constexpr bool is_set()                      { return true; }
	static constexpr bool match(value_type v)           { return traits::value == v; }
	template <class... ARGS>
	static constexpr void copy(base_t const&, ARGS&&...){ }

	bool operator==(const_integer const&) const         { return true; } //equal to itself by definition
	bool operator!=(const_integer const&) const         { return false; }
};

/**
 * plain initialized/set field
 * decoded even if doesn't match initial value
 */
template <class TRAITS>
struct init_integer : IE<IE_VALUE>
{
	using traits     = TRAITS;
	using value_type = typename traits::value_type;
	using base_t     = init_integer;

	static constexpr void clear()                       { }
	explicit operator bool() const                      { return is_set(); }
	//NOTE: do not override!
	static constexpr bool is_const = true;
	static constexpr value_type get_encoded()           { return traits::value; }
	static constexpr void set_encoded(value_type)       { }
	static constexpr bool is_set()                      { return true; }
	template <class... ARGS>
	static constexpr void copy(base_t const&, ARGS&&...){ }
	bool operator==(init_integer const&) const          { return true; }
	bool operator!=(init_integer const&) const          { return false; }
};

/**
 * integer with a default value
 */
template <class TRAITS>
struct def_integer : numeric_value<TRAITS>
{
	using traits     = TRAITS;
	using value_type = typename traits::value_type;
	using base_t     = def_integer;

	//NOTE: do not override!
	value_type get_encoded() const
	{
		return this->is_set() ? numeric_value<TRAITS>::get_encoded() : traits::default_value;
	}
};

//meta-function to select proper implementation of numeric value
template <class T, typename Enable = void>
struct value_selector;

template <class T>
struct value_selector<T,
	std::enable_if_t<
		std::is_same_v<typename T::value_type, std::remove_const_t<decltype(T::value)>>
		&& T::is_const
	>
>
{
	using type = const_integer<T>;
};

template <class T>
struct value_selector<T,
	std::enable_if_t<
		std::is_same_v<typename T::value_type, std::remove_const_t<decltype(T::value)>>
		&& !T::is_const
	>
>
{
	using type = init_integer<T>;
};

template <class T>
struct value_selector<T,
	std::enable_if_t<
		std::is_same_v<typename T::value_type, std::remove_const_t<decltype(T::default_value)>>
	>
>
{
	using type = def_integer<T>;
};

template <class T, class Enable, class... EXT_TRAITS>
struct value;

template <class T>
struct value<T, std::enable_if_t<is_value_traits<T>::value>>
		: value_selector<T>::type {};

template<class T, class... EXT_TRAITS>
struct value<T, std::enable_if_t<std::is_arithmetic_v<T>>, EXT_TRAITS...>
		: numeric_value<value_traits<T, EXT_TRAITS...>> {};

template<std::size_t N, class... EXT_TRAITS>
struct value<bytes<N>, void, EXT_TRAITS...>
		: numeric_value<value_traits<bytes<N>, EXT_TRAITS...>> {};

template<std::size_t N, class... EXT_TRAITS>
struct value<bits<N>, void, EXT_TRAITS...>
		: numeric_value<value_traits<bits<N>, EXT_TRAITS...>> {};

} //end: namespace detail

/**
 * generic value - a facade for numeric_values above
 */
template <class T, class... EXT_TRAITS>
struct value : detail::value<T, void, EXT_TRAITS...> {};

} //namespace med
<|endoftext|>


<commit_before>/*****************************************************************************
 * xmlparser.cpp
 *****************************************************************************
 * Copyright (C) 2004 the VideoLAN team
 * $Id$
 *
 * Authors: Cyril Deguet     <asmax@via.ecp.fr>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#include "xmlparser.hpp"
#include "../src/os_factory.hpp"
#include <vlc_url.h>

#include <sys/stat.h>
#include <vlc_fs.h>

XMLParser::XMLParser( intf_thread_t *pIntf, const std::string &rFileName )
    : SkinObject( pIntf ), m_pXML( NULL ), m_pReader( NULL ), m_pStream( NULL )
{
    m_pXML = xml_Create( pIntf );
    if( !m_pXML )
    {
        msg_Err( getIntf(), "cannot initialize xml" );
        return;
    }

    LoadCatalog();

    char *psz_uri = vlc_path2uri( rFileName.c_str(), NULL );
    m_pStream = stream_UrlNew( pIntf, psz_uri );
    free( psz_uri );
    if( !m_pStream )
    {
        msg_Err( getIntf(), "failed to open %s for reading",
                 rFileName.c_str() );
        return;
    }

    m_pReader = xml_ReaderCreate( m_pXML, m_pStream );
    if( !m_pReader )
    {
        msg_Err( getIntf(), "failed to open %s for parsing",
                 rFileName.c_str() );
        return;
    }

    xml_ReaderUseDTD( m_pReader );
}

XMLParser::~XMLParser()
{
    if( m_pReader ) xml_ReaderDelete( m_pReader );
    if( m_pXML ) xml_Delete( m_pXML );
    if( m_pStream ) stream_Delete( m_pStream );
}

void XMLParser::LoadCatalog()
{
    // Get the resource path and look for the DTD
    OSFactory *pOSFactory = OSFactory::instance( getIntf() );
    const std::list<std::string> &resPath = pOSFactory->getResourcePath();
    const std::string &sep = pOSFactory->getDirSeparator();
    std::list<std::string>::const_iterator it;

    struct stat statBuf;

    // Try to load the catalog first (needed at least on win32 where
    // we don't have a default catalog)
    for( it = resPath.begin(); it != resPath.end(); ++it )
    {
        std::string catalog_path = (*it) + sep + "skin.catalog";
        if( !vlc_stat( catalog_path.c_str(), &statBuf ) )
        {
            msg_Dbg( getIntf(), "Using catalog %s", catalog_path.c_str() );
            xml_CatalogLoad( m_pXML, catalog_path.c_str() );
            break;
        }
    }
    if( it == resPath.end() )
    {
        // Ok, try the default one
        xml_CatalogLoad( m_pXML, NULL );
    }

    for( it = resPath.begin(); it != resPath.end(); ++it )
    {
        std::string path = (*it) + sep + "skin.dtd";
        if( !vlc_stat( path.c_str(), &statBuf ) )
        {
            // DTD found
            msg_Dbg( getIntf(), "using DTD %s", path.c_str() );

            // Add an entry in the default catalog
            xml_CatalogAdd( m_pXML, "public",
                            "-//VideoLAN//DTD VLC Skins V"
                            SKINS_DTD_VERSION "//EN", path.c_str() );
            break;
        }
    }
    if( it == resPath.end() )
    {
        msg_Err( getIntf(), "cannot find the skins DTD");
    }
}

bool XMLParser::parse()
{
    const char *node;
    int type;

    if( !m_pReader ) return false;

    m_errors = false;

    while( (type = xml_ReaderNextNode( m_pReader, &node )) > 0 )
    {
        if( m_errors ) return false;

        switch( type )
        {
            case XML_READER_STARTELEM:
            {
                // Read the attributes
                AttrList_t attributes;
                const char *name, *value;
                while( (name = xml_ReaderNextAttr( m_pReader, &value )) != NULL )
                    attributes[strdup(name)] = strdup(value);

                handleBeginElement( node, attributes );

                std::map<const char*, const char*, ltstr> ::iterator it =
                    attributes.begin();
                while( it != attributes.end() )
                {
                    free( (char *)it->first );
                    free( (char *)it->second );
                    ++it;
                }
                break;
            }

            // End element
            case XML_READER_ENDELEM:
            {
                handleEndElement( node );
                break;
            }
        }
    }
    return (type == 0 && !m_errors );
}
<commit_msg>skins2: uninitialized member (cid #1346980)<commit_after>/*****************************************************************************
 * xmlparser.cpp
 *****************************************************************************
 * Copyright (C) 2004 the VideoLAN team
 * $Id$
 *
 * Authors: Cyril Deguet     <asmax@via.ecp.fr>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#include "xmlparser.hpp"
#include "../src/os_factory.hpp"
#include <vlc_url.h>

#include <sys/stat.h>
#include <vlc_fs.h>

XMLParser::XMLParser( intf_thread_t *pIntf, const std::string &rFileName )
    : SkinObject( pIntf ), m_pXML( NULL ), m_pReader( NULL ), m_pStream( NULL )
{
    m_errors = false;
    m_pXML = xml_Create( pIntf );
    if( !m_pXML )
    {
        msg_Err( getIntf(), "cannot initialize xml" );
        return;
    }

    LoadCatalog();

    char *psz_uri = vlc_path2uri( rFileName.c_str(), NULL );
    m_pStream = stream_UrlNew( pIntf, psz_uri );
    free( psz_uri );
    if( !m_pStream )
    {
        msg_Err( getIntf(), "failed to open %s for reading",
                 rFileName.c_str() );
        return;
    }

    m_pReader = xml_ReaderCreate( m_pXML, m_pStream );
    if( !m_pReader )
    {
        msg_Err( getIntf(), "failed to open %s for parsing",
                 rFileName.c_str() );
        return;
    }

    xml_ReaderUseDTD( m_pReader );
}

XMLParser::~XMLParser()
{
    if( m_pReader ) xml_ReaderDelete( m_pReader );
    if( m_pXML ) xml_Delete( m_pXML );
    if( m_pStream ) stream_Delete( m_pStream );
}

void XMLParser::LoadCatalog()
{
    // Get the resource path and look for the DTD
    OSFactory *pOSFactory = OSFactory::instance( getIntf() );
    const std::list<std::string> &resPath = pOSFactory->getResourcePath();
    const std::string &sep = pOSFactory->getDirSeparator();
    std::list<std::string>::const_iterator it;

    struct stat statBuf;

    // Try to load the catalog first (needed at least on win32 where
    // we don't have a default catalog)
    for( it = resPath.begin(); it != resPath.end(); ++it )
    {
        std::string catalog_path = (*it) + sep + "skin.catalog";
        if( !vlc_stat( catalog_path.c_str(), &statBuf ) )
        {
            msg_Dbg( getIntf(), "Using catalog %s", catalog_path.c_str() );
            xml_CatalogLoad( m_pXML, catalog_path.c_str() );
            break;
        }
    }
    if( it == resPath.end() )
    {
        // Ok, try the default one
        xml_CatalogLoad( m_pXML, NULL );
    }

    for( it = resPath.begin(); it != resPath.end(); ++it )
    {
        std::string path = (*it) + sep + "skin.dtd";
        if( !vlc_stat( path.c_str(), &statBuf ) )
        {
            // DTD found
            msg_Dbg( getIntf(), "using DTD %s", path.c_str() );

            // Add an entry in the default catalog
            xml_CatalogAdd( m_pXML, "public",
                            "-//VideoLAN//DTD VLC Skins V"
                            SKINS_DTD_VERSION "//EN", path.c_str() );
            break;
        }
    }
    if( it == resPath.end() )
    {
        msg_Err( getIntf(), "cannot find the skins DTD");
    }
}

bool XMLParser::parse()
{
    const char *node;
    int type;

    if( !m_pReader ) return false;

    m_errors = false;

    while( (type = xml_ReaderNextNode( m_pReader, &node )) > 0 )
    {
        if( m_errors ) return false;

        switch( type )
        {
            case XML_READER_STARTELEM:
            {
                // Read the attributes
                AttrList_t attributes;
                const char *name, *value;
                while( (name = xml_ReaderNextAttr( m_pReader, &value )) != NULL )
                    attributes[strdup(name)] = strdup(value);

                handleBeginElement( node, attributes );

                std::map<const char*, const char*, ltstr> ::iterator it =
                    attributes.begin();
                while( it != attributes.end() )
                {
                    free( (char *)it->first );
                    free( (char *)it->second );
                    ++it;
                }
                break;
            }

            // End element
            case XML_READER_ENDELEM:
            {
                handleEndElement( node );
                break;
            }
        }
    }
    return (type == 0 && !m_errors );
}
<|endoftext|>


<commit_before>/**
    ddb.hpp

    Main include file.

    Part of Disc Data Base.

    Copyright (c) 2010 Wincent Balin

    Based upon ddb.pl, created years before and serving faithfully until today.

    Uses SQLite database version 3.

    Published under MIT license. See LICENSE file for further information.
*/

#ifndef DDB_HPP
#define DDB_HPP

#include <string>

#include <sqlite3.h>

using namespace std;

// Name of the database
#define DATABASE_NAME "discdb"

// Name of the table
#define TABLE_NAME "ddb"

class DDB
{
public:
    DDB(int argc, char** argv);
    ~DDB(void);
    bool run(void);
    // Constants
    const static char* discdb_schema;
private:
    bool is_discdb(void);
    bool is_disc_present(string& name);
    bool is_directory(string& filename);
    inline bool add_disc(void);
    inline bool remove_disc(void);
    inline bool list_contents(void);
    inline bool list_discs(void);
    inline bool list_directories(void);
    inline bool list_files(void);
    inline bool initialize_database(void);
    inline bool search_text(void);
    void print_help(void);
    void msg(int min_verbosity, const char* message);
    // Database handle
    sqlite3* db;
    // Configuration flags
    string db_filename;
    string disc_name;
    string argument;
    bool do_initialize;
    bool do_add;
    bool do_list;
    bool do_remove;
    bool directories_only;
    int verbosity;
};

// discdb schema
const char* DDB::discdb_schema =
    "CREATE TABLE "TABLE_NAME" "
    "(directory TEXT NOT NULL, file TEXT, disc TEXT NOT NULL)";

#endif /* DDB_HPP */
<commit_msg>Small code style update<commit_after>/**
    ddb.hpp

    Main include file.

    Part of Disc Data Base.

    Copyright (c) 2010 Wincent Balin

    Based upon ddb.pl, created years before and serving faithfully until today.

    Uses SQLite database version 3.

    Published under MIT license. See LICENSE file for further information.
*/

#ifndef DDB_HPP
#define DDB_HPP

#include <string>

#include <sqlite3.h>

using namespace std;

// Name of the database
#define DATABASE_NAME "discdb"

// Name of the table
#define TABLE_NAME "ddb"

class DDB
{
public:
    DDB(int argc, char** argv);
    ~DDB(void);
    bool run(void);
    // Constants
    const static char* discdb_schema;
private:
    bool is_discdb(void);
    bool is_disc_present(string& name);
    bool is_directory(string& filename);
    inline bool add_disc(void);
    inline bool remove_disc(void);
    inline bool list_contents(void);
    inline bool list_discs(void);
    inline bool list_directories(void);
    inline bool list_files(void);
    inline bool initialize_database(void);
    inline bool search_text(void);
    void print_help(void);
    void msg(int min_verbosity, const char* message);
    // Database handle
    sqlite3* db;
    // Configuration flags
    string db_filename;
    string disc_name;
    string argument;
    bool do_initialize;
    bool do_add;
    bool do_list;
    bool do_remove;
    bool directories_only;
    int verbosity;
};

// discdb schema
const char* DDB::discdb_schema =
    "CREATE TABLE "TABLE_NAME" "
    "(directory TEXT NOT NULL, file TEXT, disc TEXT NOT NULL)";

#endif /* DDB_HPP */
<|endoftext|>


<commit_before>#include <b9/ExecutionContext.hpp>
#include <b9/VirtualMachine.hpp>
#include <b9/compiler/Compiler.hpp>

#include <omrgc.h>
#include <OMR/Om/Allocator.inl.hpp>
#include <OMR/Om/ArrayBuffer.inl.hpp>
#include <OMR/Om/ArrayBufferMap.inl.hpp>
#include <OMR/Om/Map.inl.hpp>
#include <OMR/Om/Object.inl.hpp>
#include <OMR/Om/ObjectMap.inl.hpp>
#include <OMR/Om/RootRef.inl.hpp>
#include <OMR/Om/Value.hpp>
#include "Jit.hpp"

#include <sys/time.h>
#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <sstream>
#include <string>

namespace b9 {

ExecutionContext::ExecutionContext(VirtualMachine &virtualMachine,
                                   const Config &cfg)
    : omContext_(virtualMachine.memoryManager()),
      virtualMachine_(&virtualMachine),
      cfg_(&cfg) {
  omContext().userRoots().push_back(
      [this](Om::Context &cx, Om::Visitor &v) { this->visit(cx, v); });
}

void ExecutionContext::reset() {
  stack_.reset();
  programCounter_ = 0;
}

Om::Value ExecutionContext::callJitFunction(JitFunction jitFunction,
                                            std::size_t nargs) {
  if (cfg_->verbose) {
    std::cout << "Int: transition to jit: " << jitFunction << std::endl;
  }

  Om::RawValue result = 0;

  if (cfg_->passParam) {
    switch (nargs) {
      case 0: {
        result = jitFunction(this);
      } break;
      case 1: {
        StackElement p1 = pop();
        result = jitFunction(this, p1.raw());
      } break;
      case 2: {
        StackElement p2 = pop();
        StackElement p1 = pop();
        result = jitFunction(this, p1.raw(), p2.raw());
      } break;
      case 3: {
        StackElement p3 = pop();
        StackElement p2 = pop();
        StackElement p1 = pop();
        result = (*jitFunction)(this, p1.raw(), p2.raw(), p3.raw());
      } break;
      default:
        throw std::runtime_error{"Need to add handlers for more parameters"};
        break;
    }
  } else {
    result = jitFunction(this);
  }

  return Om::Value(Om::FROM_RAW, result);
}

StackElement ExecutionContext::interpret(const std::size_t functionIndex) {
  auto function = virtualMachine_->getFunction(functionIndex);
  auto argsCount = function->nargs;
  auto jitFunction = virtualMachine_->getJitAddress(functionIndex);

  if (jitFunction) {
    return callJitFunction(jitFunction, argsCount);
  }

  // interpret the method otherwise
  const Instruction *instructionPointer = function->instructions.data();

  StackElement *args = stack_.top() - function->nargs;
  stack_.pushn(function->nregs);

  while (*instructionPointer != END_SECTION) {
    switch (instructionPointer->byteCode()) {
      case ByteCode::FUNCTION_CALL:
        doFunctionCall(instructionPointer->parameter());
        break;
      case ByteCode::FUNCTION_RETURN: {
        auto result = stack_.pop();
        stack_.restore(args);
        return result;
        break;
      }
      case ByteCode::PRIMITIVE_CALL:
        doPrimitiveCall(instructionPointer->parameter());
        break;
      case ByteCode::JMP:
        instructionPointer += instructionPointer->parameter();
        break;
      case ByteCode::DUPLICATE:
        doDuplicate();
        break;
      case ByteCode::DROP:
        doDrop();
        break;
      case ByteCode::PUSH_FROM_VAR:
        doPushFromVar(args, instructionPointer->parameter());
        break;
      case ByteCode::POP_INTO_VAR:
        // TODO bad name, push or pop?
        doPushIntoVar(args, instructionPointer->parameter());
        break;
      case ByteCode::INT_ADD:
        doIntAdd();
        break;
      case ByteCode::INT_SUB:
        doIntSub();
        break;
      case ByteCode::INT_MUL:
        doIntMul();
        break;
      case ByteCode::INT_DIV:
        doIntDiv();
        break;
      case ByteCode::INT_PUSH_CONSTANT:
        doIntPushConstant(instructionPointer->parameter());
        break;
      case ByteCode::INT_NOT:
        doIntNot();
        break;
      case ByteCode::INT_JMP_EQ:
        instructionPointer += doIntJmpEq(instructionPointer->parameter());
        break;
      case ByteCode::INT_JMP_NEQ:
        instructionPointer += doIntJmpNeq(instructionPointer->parameter());
        break;
      case ByteCode::INT_JMP_GT:
        instructionPointer += doIntJmpGt(instructionPointer->parameter());
        break;
      case ByteCode::INT_JMP_GE:
        instructionPointer += doIntJmpGe(instructionPointer->parameter());
        break;
      case ByteCode::INT_JMP_LT:
        instructionPointer += doIntJmpLt(instructionPointer->parameter());
        break;
      case ByteCode::INT_JMP_LE:
        instructionPointer += doIntJmpLe(instructionPointer->parameter());
        break;
      case ByteCode::STR_PUSH_CONSTANT:
        doStrPushConstant(instructionPointer->parameter());
        break;
      case ByteCode::STR_JMP_EQ:
        // TODO
        break;
      case ByteCode::STR_JMP_NEQ:
        // TODO
        break;
      case ByteCode::NEW_OBJECT:
        doNewObject();
        break;
      case ByteCode::PUSH_FROM_OBJECT:
        doPushFromObject(OMR::Om::Id(instructionPointer->parameter()));
        break;
      case ByteCode::POP_INTO_OBJECT:
        doPopIntoObject(OMR::Om::Id(instructionPointer->parameter()));
        break;
      case ByteCode::CALL_INDIRECT:
        doCallIndirect();
        break;
      case ByteCode::SYSTEM_COLLECT:
        doSystemCollect();
        break;
      default:
        assert(false);
        break;
    }
    instructionPointer++;
    programCounter_++;
  }
  throw std::runtime_error("Reached end of function");
}

void ExecutionContext::push(StackElement value) { stack_.push(value); }

StackElement ExecutionContext::pop() { return stack_.pop(); }

void ExecutionContext::doFunctionCall(Parameter value) {
  auto f = virtualMachine_->getFunction((std::size_t)value);
  auto result = interpret(value);
  push(result);
}

void ExecutionContext::doFunctionReturn(StackElement returnVal) {
  // TODO
}

void ExecutionContext::doPrimitiveCall(Parameter value) {
  PrimitiveFunction *primitive = virtualMachine_->getPrimitive(value);
  (*primitive)(this);
}

Parameter ExecutionContext::doJmp(Parameter offset) { return offset; }

void ExecutionContext::doDuplicate() {
  auto x = pop();
  push(x);
  push(x);
}

void ExecutionContext::doDrop() { stack_.pop(); }

void ExecutionContext::doPushFromVar(StackElement *args, Parameter offset) {
  stack_.push(args[offset]);
}

void ExecutionContext::doPushIntoVar(StackElement *args, Parameter offset) {
  args[offset] = stack_.pop();
}

void ExecutionContext::doIntAdd() {
  std::int32_t right = stack_.pop().getInteger();
  std::int32_t left = stack_.pop().getInteger();
  StackElement result;
  result.setInteger(left + right);
  push(result);
}

void ExecutionContext::doIntSub() {
  std::int32_t right = stack_.pop().getInteger();
  std::int32_t left = stack_.pop().getInteger();
  StackElement result;
  result.setInteger(left - right);
  push(result);
}

void ExecutionContext::doIntMul() {
  std::int32_t right = stack_.pop().getInteger();
  std::int32_t left = stack_.pop().getInteger();
  StackElement result;
  result.setInteger(left * right);
  push(result);
}

void ExecutionContext::doIntDiv() {
  std::int32_t right = stack_.pop().getInteger();
  std::int32_t left = stack_.pop().getInteger();
  StackElement result;
  result.setInteger(left / right);
  push(result);
}

void ExecutionContext::doIntPushConstant(Parameter value) {
  stack_.push(StackElement().setInteger(value));
}

void ExecutionContext::doIntNot() {
  std::int32_t i = stack_.pop().getInteger();
  StackElement v;
  v.setInteger(!i);
  push(v);
}

Parameter ExecutionContext::doIntJmpEq(Parameter delta) {
  std::int32_t right = stack_.pop().getInteger();
  std::int32_t left = stack_.pop().getInteger();
  if (left == right) {
    return delta;
  }
  return 0;
}

Parameter ExecutionContext::doIntJmpNeq(Parameter delta) {
  std::int32_t right = stack_.pop().getInteger();
  std::int32_t left = stack_.pop().getInteger();
  if (left != right) {
    return delta;
  }
  return 0;
}

Parameter ExecutionContext::doIntJmpGt(Parameter delta) {
  std::int32_t right = stack_.pop().getInteger();
  std::int32_t left = stack_.pop().getInteger();
  if (left > right) {
    return delta;
  }
  return 0;
}

// ( left right -- )
Parameter ExecutionContext::doIntJmpGe(Parameter delta) {
  std::int32_t right = stack_.pop().getInteger();
  std::int32_t left = stack_.pop().getInteger();
  if (left >= right) {
    return delta;
  }
  return 0;
}

// ( left right -- )
Parameter ExecutionContext::doIntJmpLt(Parameter delta) {
  std::int32_t right = stack_.pop().getInteger();
  std::int32_t left = stack_.pop().getInteger();
  if (left < right) {
    return delta;
  }
  return 0;
}

// ( left right -- )
Parameter ExecutionContext::doIntJmpLe(Parameter delta) {
  std::int32_t right = stack_.pop().getInteger();
  std::int32_t left = stack_.pop().getInteger();
  if (left <= right) {
    return delta;
  }
  return 0;
}

// ( -- string )
void ExecutionContext::doStrPushConstant(Parameter param) {
  stack_.push(OMR::Om::Value().setInteger(param));
}

// ( -- object )
void ExecutionContext::doNewObject() {
  auto ref = OMR::Om::Object::allocate(*this);
  stack_.push(OMR::Om::Value(ref));
}

// ( object -- value )
void ExecutionContext::doPushFromObject(Om::Id slotId) {
  auto value = stack_.pop();
  if (!value.isPtr()) {
    throw std::runtime_error("Accessing non-object value as an object.");
  }
  auto obj = value.getPtr<Om::Object>();
  Om::SlotDescriptor descriptor;
  auto found = Om::Object::lookup(*this, obj, slotId, descriptor);
  if (found) {
    Om::Value result;
    result = Om::Object::getValue(*this, obj, descriptor);
    stack_.push(result);
  } else {
    throw std::runtime_error("Accessing an object's field that doesn't exist.");
  }
}

// ( object value -- )
void ExecutionContext::doPopIntoObject(Om::Id slotId) {
  if (!stack_.peek().isPtr()) {
    throw std::runtime_error("Accessing non-object as an object");
  }

  std::size_t offset = 0;
  auto object = stack_.pop().getPtr<Om::Object>();

  Om::SlotDescriptor descriptor;
  bool found = Om::Object::lookup(*this, object, slotId, descriptor);

  if (!found) {
    static constexpr Om::SlotType type(Om::Id(0), Om::CoreType::VALUE);

    Om::RootRef<Om::Object> root(*this, object);
    auto map = Om::Object::transition(*this, root, {{type, slotId}});
    assert(map != nullptr);

    // TODO: Get the descriptor fast after a single-slot transition.
    Om::Object::lookup(*this, object, slotId, descriptor);
    object = root.get();
  }

  auto val = pop();
  Om::Object::setValue(*this, object, descriptor, val);
  // TODO: Write barrier the object on store.
}

void ExecutionContext::doCallIndirect() {
  assert(0);  // TODO: Implement call indirect
}

void ExecutionContext::doSystemCollect() {
  std::cout << "SYSTEM COLLECT!!!" << std::endl;
  OMR_GC_SystemCollect(omContext_.omrVmThread(), 0);
}

}  // namespace b9
<commit_msg>Dont pop while handling BC_DUPLICATE<commit_after>#include <b9/ExecutionContext.hpp>
#include <b9/VirtualMachine.hpp>
#include <b9/compiler/Compiler.hpp>

#include <omrgc.h>
#include <OMR/Om/Allocator.inl.hpp>
#include <OMR/Om/ArrayBuffer.inl.hpp>
#include <OMR/Om/ArrayBufferMap.inl.hpp>
#include <OMR/Om/Map.inl.hpp>
#include <OMR/Om/Object.inl.hpp>
#include <OMR/Om/ObjectMap.inl.hpp>
#include <OMR/Om/RootRef.inl.hpp>
#include <OMR/Om/Value.hpp>
#include "Jit.hpp"

#include <sys/time.h>
#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <sstream>
#include <string>

namespace b9 {

ExecutionContext::ExecutionContext(VirtualMachine &virtualMachine,
                                   const Config &cfg)
    : omContext_(virtualMachine.memoryManager()),
      virtualMachine_(&virtualMachine),
      cfg_(&cfg) {
  omContext().userRoots().push_back(
      [this](Om::Context &cx, Om::Visitor &v) { this->visit(cx, v); });
}

void ExecutionContext::reset() {
  stack_.reset();
  programCounter_ = 0;
}

Om::Value ExecutionContext::callJitFunction(JitFunction jitFunction,
                                            std::size_t nargs) {
  if (cfg_->verbose) {
    std::cout << "Int: transition to jit: " << jitFunction << std::endl;
  }

  Om::RawValue result = 0;

  if (cfg_->passParam) {
    switch (nargs) {
      case 0: {
        result = jitFunction(this);
      } break;
      case 1: {
        StackElement p1 = pop();
        result = jitFunction(this, p1.raw());
      } break;
      case 2: {
        StackElement p2 = pop();
        StackElement p1 = pop();
        result = jitFunction(this, p1.raw(), p2.raw());
      } break;
      case 3: {
        StackElement p3 = pop();
        StackElement p2 = pop();
        StackElement p1 = pop();
        result = (*jitFunction)(this, p1.raw(), p2.raw(), p3.raw());
      } break;
      default:
        throw std::runtime_error{"Need to add handlers for more parameters"};
        break;
    }
  } else {
    result = jitFunction(this);
  }

  return Om::Value(Om::FROM_RAW, result);
}

StackElement ExecutionContext::interpret(const std::size_t functionIndex) {
  auto function = virtualMachine_->getFunction(functionIndex);
  auto argsCount = function->nargs;
  auto jitFunction = virtualMachine_->getJitAddress(functionIndex);

  if (jitFunction) {
    return callJitFunction(jitFunction, argsCount);
  }

  // interpret the method otherwise
  const Instruction *instructionPointer = function->instructions.data();

  StackElement *args = stack_.top() - function->nargs;
  stack_.pushn(function->nregs);

  while (*instructionPointer != END_SECTION) {
    switch (instructionPointer->byteCode()) {
      case ByteCode::FUNCTION_CALL:
        doFunctionCall(instructionPointer->parameter());
        break;
      case ByteCode::FUNCTION_RETURN: {
        auto result = stack_.pop();
        stack_.restore(args);
        return result;
        break;
      }
      case ByteCode::PRIMITIVE_CALL:
        doPrimitiveCall(instructionPointer->parameter());
        break;
      case ByteCode::JMP:
        instructionPointer += instructionPointer->parameter();
        break;
      case ByteCode::DUPLICATE:
        doDuplicate();
        break;
      case ByteCode::DROP:
        doDrop();
        break;
      case ByteCode::PUSH_FROM_VAR:
        doPushFromVar(args, instructionPointer->parameter());
        break;
      case ByteCode::POP_INTO_VAR:
        // TODO bad name, push or pop?
        doPushIntoVar(args, instructionPointer->parameter());
        break;
      case ByteCode::INT_ADD:
        doIntAdd();
        break;
      case ByteCode::INT_SUB:
        doIntSub();
        break;
      case ByteCode::INT_MUL:
        doIntMul();
        break;
      case ByteCode::INT_DIV:
        doIntDiv();
        break;
      case ByteCode::INT_PUSH_CONSTANT:
        doIntPushConstant(instructionPointer->parameter());
        break;
      case ByteCode::INT_NOT:
        doIntNot();
        break;
      case ByteCode::INT_JMP_EQ:
        instructionPointer += doIntJmpEq(instructionPointer->parameter());
        break;
      case ByteCode::INT_JMP_NEQ:
        instructionPointer += doIntJmpNeq(instructionPointer->parameter());
        break;
      case ByteCode::INT_JMP_GT:
        instructionPointer += doIntJmpGt(instructionPointer->parameter());
        break;
      case ByteCode::INT_JMP_GE:
        instructionPointer += doIntJmpGe(instructionPointer->parameter());
        break;
      case ByteCode::INT_JMP_LT:
        instructionPointer += doIntJmpLt(instructionPointer->parameter());
        break;
      case ByteCode::INT_JMP_LE:
        instructionPointer += doIntJmpLe(instructionPointer->parameter());
        break;
      case ByteCode::STR_PUSH_CONSTANT:
        doStrPushConstant(instructionPointer->parameter());
        break;
      case ByteCode::STR_JMP_EQ:
        // TODO
        break;
      case ByteCode::STR_JMP_NEQ:
        // TODO
        break;
      case ByteCode::NEW_OBJECT:
        doNewObject();
        break;
      case ByteCode::PUSH_FROM_OBJECT:
        doPushFromObject(OMR::Om::Id(instructionPointer->parameter()));
        break;
      case ByteCode::POP_INTO_OBJECT:
        doPopIntoObject(OMR::Om::Id(instructionPointer->parameter()));
        break;
      case ByteCode::CALL_INDIRECT:
        doCallIndirect();
        break;
      case ByteCode::SYSTEM_COLLECT:
        doSystemCollect();
        break;
      default:
        assert(false);
        break;
    }
    instructionPointer++;
    programCounter_++;
  }
  throw std::runtime_error("Reached end of function");
}

void ExecutionContext::push(StackElement value) { stack_.push(value); }

StackElement ExecutionContext::pop() { return stack_.pop(); }

void ExecutionContext::doFunctionCall(Parameter value) {
  auto f = virtualMachine_->getFunction((std::size_t)value);
  auto result = interpret(value);
  push(result);
}

void ExecutionContext::doFunctionReturn(StackElement returnVal) {
  // TODO
}

void ExecutionContext::doPrimitiveCall(Parameter value) {
  PrimitiveFunction *primitive = virtualMachine_->getPrimitive(value);
  (*primitive)(this);
}

Parameter ExecutionContext::doJmp(Parameter offset) { return offset; }

void ExecutionContext::doDuplicate() {
  push(stack_.peek());
}

void ExecutionContext::doDrop() { stack_.pop(); }

void ExecutionContext::doPushFromVar(StackElement *args, Parameter offset) {
  stack_.push(args[offset]);
}

void ExecutionContext::doPushIntoVar(StackElement *args, Parameter offset) {
  args[offset] = stack_.pop();
}

void ExecutionContext::doIntAdd() {
  std::int32_t right = stack_.pop().getInteger();
  std::int32_t left = stack_.pop().getInteger();
  StackElement result;
  result.setInteger(left + right);
  push(result);
}

void ExecutionContext::doIntSub() {
  std::int32_t right = stack_.pop().getInteger();
  std::int32_t left = stack_.pop().getInteger();
  StackElement result;
  result.setInteger(left - right);
  push(result);
}

void ExecutionContext::doIntMul() {
  std::int32_t right = stack_.pop().getInteger();
  std::int32_t left = stack_.pop().getInteger();
  StackElement result;
  result.setInteger(left * right);
  push(result);
}

void ExecutionContext::doIntDiv() {
  std::int32_t right = stack_.pop().getInteger();
  std::int32_t left = stack_.pop().getInteger();
  StackElement result;
  result.setInteger(left / right);
  push(result);
}

void ExecutionContext::doIntPushConstant(Parameter value) {
  stack_.push(StackElement().setInteger(value));
}

void ExecutionContext::doIntNot() {
  std::int32_t i = stack_.pop().getInteger();
  StackElement v;
  v.setInteger(!i);
  push(v);
}

Parameter ExecutionContext::doIntJmpEq(Parameter delta) {
  std::int32_t right = stack_.pop().getInteger();
  std::int32_t left = stack_.pop().getInteger();
  if (left == right) {
    return delta;
  }
  return 0;
}

Parameter ExecutionContext::doIntJmpNeq(Parameter delta) {
  std::int32_t right = stack_.pop().getInteger();
  std::int32_t left = stack_.pop().getInteger();
  if (left != right) {
    return delta;
  }
  return 0;
}

Parameter ExecutionContext::doIntJmpGt(Parameter delta) {
  std::int32_t right = stack_.pop().getInteger();
  std::int32_t left = stack_.pop().getInteger();
  if (left > right) {
    return delta;
  }
  return 0;
}

// ( left right -- )
Parameter ExecutionContext::doIntJmpGe(Parameter delta) {
  std::int32_t right = stack_.pop().getInteger();
  std::int32_t left = stack_.pop().getInteger();
  if (left >= right) {
    return delta;
  }
  return 0;
}

// ( left right -- )
Parameter ExecutionContext::doIntJmpLt(Parameter delta) {
  std::int32_t right = stack_.pop().getInteger();
  std::int32_t left = stack_.pop().getInteger();
  if (left < right) {
    return delta;
  }
  return 0;
}

// ( left right -- )
Parameter ExecutionContext::doIntJmpLe(Parameter delta) {
  std::int32_t right = stack_.pop().getInteger();
  std::int32_t left = stack_.pop().getInteger();
  if (left <= right) {
    return delta;
  }
  return 0;
}

// ( -- string )
void ExecutionContext::doStrPushConstant(Parameter param) {
  stack_.push(OMR::Om::Value().setInteger(param));
}

// ( -- object )
void ExecutionContext::doNewObject() {
  auto ref = OMR::Om::Object::allocate(*this);
  stack_.push(OMR::Om::Value(ref));
}

// ( object -- value )
void ExecutionContext::doPushFromObject(Om::Id slotId) {
  auto value = stack_.pop();
  if (!value.isPtr()) {
    throw std::runtime_error("Accessing non-object value as an object.");
  }
  auto obj = value.getPtr<Om::Object>();
  Om::SlotDescriptor descriptor;
  auto found = Om::Object::lookup(*this, obj, slotId, descriptor);
  if (found) {
    Om::Value result;
    result = Om::Object::getValue(*this, obj, descriptor);
    stack_.push(result);
  } else {
    throw std::runtime_error("Accessing an object's field that doesn't exist.");
  }
}

// ( object value -- )
void ExecutionContext::doPopIntoObject(Om::Id slotId) {
  if (!stack_.peek().isPtr()) {
    throw std::runtime_error("Accessing non-object as an object");
  }

  std::size_t offset = 0;
  auto object = stack_.pop().getPtr<Om::Object>();

  Om::SlotDescriptor descriptor;
  bool found = Om::Object::lookup(*this, object, slotId, descriptor);

  if (!found) {
    static constexpr Om::SlotType type(Om::Id(0), Om::CoreType::VALUE);

    Om::RootRef<Om::Object> root(*this, object);
    auto map = Om::Object::transition(*this, root, {{type, slotId}});
    assert(map != nullptr);

    // TODO: Get the descriptor fast after a single-slot transition.
    Om::Object::lookup(*this, object, slotId, descriptor);
    object = root.get();
  }

  auto val = pop();
  Om::Object::setValue(*this, object, descriptor, val);
  // TODO: Write barrier the object on store.
}

void ExecutionContext::doCallIndirect() {
  assert(0);  // TODO: Implement call indirect
}

void ExecutionContext::doSystemCollect() {
  std::cout << "SYSTEM COLLECT!!!" << std::endl;
  OMR_GC_SystemCollect(omContext_.omrVmThread(), 0);
}

}  // namespace b9
<|endoftext|>


<commit_before>/* -*-Mode: c++;-*-
   Copyright (c) 2004-2010 John Plevyak, All Rights Reserved
*/
#include "ifadefs.h"
#include "fail.h"
#include "ifa.h"
#include "pattern.h"
#include "prim.h"
#include "if1.h"
#include "builtin.h"
#include "pdb.h"
#include "fun.h"
#include "pnode.h"
#include "fa.h"
#include "ast.h"
#include "var.h"
#include "dom.h"

/*
  It is intended that this file contain 2 implementations,
  one based on the AVars and another based on Vars (post concretize_program()).
  Only the former is currently extent.
*/

static int mark_live_again = 0;

static void
print_dead(FA *fa) {
  int ndead_pnodes = 0, ndead_vars = 0;
  forv_Fun(f, fa->funs) {
    forv_PNode(p, f->fa_all_PNodes)
      if (!p->live) {
        ndead_pnodes++;
        printf("PNode %d DEAD\n", p->id);
      }
    forv_Var(v, f->fa_all_Vars)
      if (!v->live) {
        ndead_vars++;
        printf("Var %d:%d %s DEAD\n", v->sym->id, v->id, v->sym->name ? v->sym->name : "");
      }
  }
  printf("%d PNodes DEAD\n", ndead_pnodes);
  printf("%d Vars DEAD\n", ndead_vars);
}

static void
mark_live_avar(AVar *av) {
  if (av->var->sym->is_fake)
    return;
  av->live = 1;
  av->var->live = 1;
  mark_live_again = 1;
  if (av->var->def)
    av->var->def->live = 1;
  forv_AVar(aav, av->backward) if (aav) {
    if (!aav->live) {
      Vec<Sym *> consts;
      if (constant_info(aav->var, consts) != 1)
        mark_live_avar(aav);
    }
  }
}

static void
mark_live_avars(FA *fa) {
  forv_Fun(f, fa->funs) {
    forv_PNode(p, f->fa_all_PNodes) {
      // if a pnode is live, and it is not a function call, it's inputs (rvals) must be live
      if (p->live && !f->calls.get(p)) {
        forv_Var(v, p->rvals) {
          Vec<Sym *> consts;
          if (constant_info(v, consts) != 1) {
            form_AVarMapElem(x, v->avars) {
              AVar *av = x->value;
              if (!av->live)
                mark_live_avar(av);
            }
          }
        }
      }
    }
    forv_Var(v, f->fa_all_Vars) {
      form_AVarMapElem(x, v->avars) {
        // if an instance variable is live, then the containing object must be live
        AVar *av = x->value;
        if (!av->live) {
          forv_CreationSet(cs, *av->out) if (cs) {
            forv_AVar(iv, cs->vars) {
              if (iv->live && !av->live)
                mark_live_avar(av);
            }
          }
        }
      }
    }
  }
}

static bool
forward_live(Var *v, int dist = 2) {
  if (dist < 0)
    return false;
  form_AVarMapElem(x, v->avars)
    forv_AVar(av, x->value->forward) if (av) {
      if (av->live)
        return true;
      if (forward_live(av->var, dist-1))
        return true;
    }
  return false;
}

static void
mark_live_pnodes(FA *fa) {
  forv_Fun(f, fa->funs) {
    forv_PNode(p, f->fa_all_PNodes) {
      if (!p->live) {
        forv_Var(v, p->lvals)
          if (v->live)
            goto Live;
        if (p->code)
          switch (p->code->kind) {
            default: break;
            case Code_LABEL:
              if (p->cfg_pred.n != 1)
                forv_PNode(x, p->cfg_pred)
                  if (x->live)
                    goto Live;
              break;
            case Code_GOTO:
              if (p->cfg_succ[0]->cfg_pred.n != 1)
                forv_PNode(x, f->fa_all_PNodes) // potentially expensive
                  if (x->live || x == f->exit)
                    if (p->dom->is_dominated_by(x->dom))
                      goto Live;
              break;
            case Code_SEND:
              if (p->prim) {
                switch (p->prim->index) { // handle side effects
                  default: break;
                  case P_prim_reply:
                    forv_Var(v, f->rets)
                      if (v->live)
                        goto Live;
                    break;
                  case P_prim_setter: {
                    if (forward_live(p->tvals.v[0]))
                      goto Live;
                    break;
                  }
                  case P_prim_set_index_object: {
                    if (forward_live(p->tvals.v[0]))
                      goto Live;
                    break;
                  }
                }
              } else {
                Vec<Fun *> *calls = f->calls.get(p);
                if (calls)
                  forv_Fun(x, *calls)
                    if (x->live)
                      goto Live;
              }
              break;
            case Code_IF:
              forv_PNode(x, f->fa_all_PNodes) // potentially expensive
                if (x->live)
                  if (x->dom->is_dominated_by(p->dom))
                    forv_PNode(s, p->cfg_succ)
                      if (!x->dom->is_dominated_by(s->dom))
                        goto Live;
              break;
          }
        continue; // handle fall through non-live
      Live:
        p->live = 1;
        f->live = 1;
        mark_live_again = 1;
      } else
        f->live = 1;
    }
  }
}

static void
mark_initial_dead_and_alive(FA *fa, int init = 0) {
  forv_Fun(f, fa->funs) {
    f->live = init;
    forv_Var(v, f->fa_all_Vars) {
      v->live = init;
      for (int i = 0; i < v->avars.n; i++)
        if (v->avars[i].key)
          v->avars[i].value->live = false;
      if (v->type) { // mark all instance variables not live
        forv_CreationSet(cs, v->type->creators) if (cs) {
          forv_AVar(iv, cs->vars)
            iv->var->live = init;
        }
      }
    }
    forv_PNode(p, f->fa_all_PNodes) {
      p->live = init;
      if (p->code && p->code->kind == Code_SEND && p->prim && p->prim->index == P_prim_primitive) {
        cchar *name = p->code->rvals[1]->name;
        RegisteredPrim *rp = prim_get(name);
        if (rp && rp->is_visible)
          p->live = 1;
      }
    }
  }
}

void
mark_live_types(FA *fa) {
  forv_CreationSet(cs, fa->css)
    cs->type->type_live = 0;
  forv_CreationSet(cs, fa->css)
    if (cs->type && cs->type->creators.n) {
      forv_CreationSet(x, cs->type->creators) {
        forv_AVar(av, x->defs) if (av)
          if (av->var->live && !cs->type->type_live)
            cs->type->type_live = 1;
      }
    }
}

int
mark_live_code(FA *fa) {
  mark_initial_dead_and_alive(fa);
  do {
    mark_live_again = 0;
    mark_live_avars(fa);
    mark_live_pnodes(fa);
  } while (mark_live_again);
  mark_live_types(fa);
  if (ifa_verbose > 2)
    print_dead(fa);
  return 0;
}

void
mark_live_funs(FA *fa) {
  forv_Fun(f, fa->funs)
    f->live = 0;
  if1->top->fun->live = 1;
  int changed = 1;
  while (changed) {
    changed = 0;
    forv_Fun(f, fa->funs) {
      if (f->live) {
        forv_PNode(p, f->fa_all_PNodes)
          if (p->live) {
            Vec<Fun *> *fns = f->calls.get(p);
            if (fns)
              forv_Fun(x, *fns) if (!x->live) {
                x->live = 1;
                changed = 1;
              }
          }
      }
    }
  }
}

/*
  INCOMPLETE VAR BASED VERSION
*/

#if 0
static void
mark_live_vars(FA *fa) {
  forv_Fun(f, fa->funs) {
    forv_PNode(p, f->fa_all_PNodes) {
      // if a pnode is live, it's inputs (rvals) must be live
      if (p->live) {
        forv_Var(v, p->rvals) {
          if (!v->live) {
            v->live = 1;
            mark_live_again = 1;
          }
        }
    }
    forv_Var(v, f->fa_all_Vars) {
      // if an instance variable is live, then the containing object must be live
      if (!v->live && v->type)
        forv_CreationSet(cs, v->type->creators) if (cs) {
          forv_AVar(iv, cs->vars) {
            if (iv->var->live) {
              v->live = 1;
              mark_live_again = 1;
            }
          }
        }
      }
    }
  }
}

static void
mark_types_live(FA *fa) {
  forv_CreationSet(cs, fa->css)
    if (cs->type && cs->type->creators.n) {
      forv_CreationSet(x, cs->type->creators) {
        forv_AVar(av, x->defs) if (av)
          if (av->var->live)
            cs->type->type_live = 1;
      }
    }
}

static void
mark_initial_dead_and_alive(FA *fa, int init = 0) {
  forv_Fun(f, fa->funs) {
    f->live = init;
    forv_Var(v, f->fa_all_Vars) {
      v->live = INIT;
      if (v->type) { // mark all instance variables not live
        forv_CreationSet(cs, v->type->creators) if (cs) {
          forv_AVar(iv, cs->vars)
            iv->var->live = init;
        }
      }
    }
    forv_PNode(p, f->fa_all_PNodes) {
      p->live = init;
      if (p->code && p->code->kind == Code_SEND && p->prim && p->prim->index == P_prim_primitive) {
        cchar *name = p->code->rvals[1]->name;
        RegisteredPrim *rp = pdb->fa->primitive_transfer_functions.get(name);
        if (rp && rp->is_visible)
          p->live = 1;
      }
    }
  }
  forv_CreationSet(cs, fa->css)
    cs->type->type_live = init;
}

int
mark_dead_code(FA *fa) {
  mark_initial_dead_and_alive(fa);
  do {
    mark_live_again = 0;
    mark_live_vars(fa);
    mark_live_pnodes(fa);
  } while (mark_live_again);
  mark_types_live(fa);
  if (ifa_verbose > 2)
    print_dead(fa);
  return 0;
}
#endif
<commit_msg>interm<commit_after>/* -*-Mode: c++;-*-
   Copyright (c) 2004-2010 John Plevyak, All Rights Reserved
*/
#include "ifadefs.h"
#include "fail.h"
#include "ifa.h"
#include "pattern.h"
#include "prim.h"
#include "if1.h"
#include "builtin.h"
#include "pdb.h"
#include "fun.h"
#include "pnode.h"
#include "fa.h"
#include "ast.h"
#include "var.h"
#include "dom.h"

/*
  It is intended that this file contain 2 implementations,
  one based on the AVars and another based on Vars (post concretize_program()).
  Only the former is currently extent.
*/

static int mark_live_again = 0;

static void
print_dead(FA *fa) {
  int ndead_pnodes = 0, ndead_vars = 0;
  int nlive_pnodes = 0, nlive_vars = 0;
  forv_Fun(f, fa->funs) {
    forv_PNode(p, f->fa_all_PNodes)
      if (!p->live) {
        ndead_pnodes++;
        printf("PNode %d DEAD\n", p->id);
      } else nlive_pnodes++;
    forv_Var(v, f->fa_all_Vars)
      if (!v->live) {
        ndead_vars++;
        printf("Var %d:%d %s DEAD\n", v->sym->id, v->id, v->sym->name ? v->sym->name : "");
      } else nlive_vars++;
  }
  printf("%d PNodes DEAD\n", ndead_pnodes);
  printf("%d Vars DEAD\n", ndead_vars);
  printf("%d PNodes LIVE\n", nlive_pnodes);
  printf("%d Vars LIVE\n", nlive_vars);
}

static void
mark_live_avar(AVar *av) {
  if (av->var->sym->is_fake)
    return;
  av->live = 1;
  av->var->live = 1;
  mark_live_again = 1;
  if (av->var->def)
    av->var->def->live = 1;
  forv_AVar(aav, av->backward) if (aav) {
    if (!aav->live) {
      Vec<Sym *> consts;
      if (constant_info(aav->var, consts) != 1)
        mark_live_avar(aav);
    }
  }
}

static void
mark_live_avars(FA *fa) {
  forv_Fun(f, fa->funs) {
    forv_PNode(p, f->fa_all_PNodes) {
      // if a pnode is live, and it is not a function call, it's inputs (rvals) must be live
      if (p->live && !f->calls.get(p)) {
        forv_Var(v, p->rvals) {
          Vec<Sym *> consts;
          if (constant_info(v, consts) != 1) {
            form_AVarMapElem(x, v->avars) {
              AVar *av = x->value;
              if (!av->live)
                mark_live_avar(av);
            }
          }
        }
      }
    }
    forv_Var(v, f->fa_all_Vars) {
      form_AVarMapElem(x, v->avars) {
        // if an instance variable is live, then the containing object must be live
        AVar *av = x->value;
        if (!av->live) {
          forv_CreationSet(cs, *av->out) if (cs) {
            forv_AVar(iv, cs->vars) {
              if (iv->live && !av->live)
                mark_live_avar(av);
            }
          }
        }
      }
    }
  }
}

static bool
forward_live(Var *v, int dist = 2) {
  if (dist < 0)
    return false;
  form_AVarMapElem(x, v->avars)
    forv_AVar(av, x->value->forward) if (av) {
      if (av->live)
        return true;
      if (forward_live(av->var, dist-1))
        return true;
    }
  return false;
}

static void
mark_live_pnodes(FA *fa) {
  forv_Fun(f, fa->funs) {
    forv_PNode(p, f->fa_all_PNodes) {
      if (!p->live) {
        forv_Var(v, p->lvals)
          if (v->live)
            goto Live;
        if (p->code)
          switch (p->code->kind) {
            default: break;
            case Code_LABEL:
              if (p->cfg_pred.n != 1)
                forv_PNode(x, p->cfg_pred)
                  if (x->live)
                    goto Live;
              break;
            case Code_GOTO:
              if (p->cfg_succ[0]->cfg_pred.n != 1)
                forv_PNode(x, f->fa_all_PNodes) // potentially expensive
                  if (x->live || x == f->exit)
                    if (p->dom->is_dominated_by(x->dom))
                      goto Live;
              break;
            case Code_SEND:
              if (p->prim) {
                switch (p->prim->index) { // handle side effects
                  default: break;
                  case P_prim_reply:
                    forv_Var(v, f->rets)
                      if (v->live)
                        goto Live;
                    break;
                  case P_prim_setter: {
                    if (forward_live(p->tvals.v[0]))
                      goto Live;
                    break;
                  }
                  case P_prim_set_index_object: {
                    if (forward_live(p->tvals.v[0]))
                      goto Live;
                    break;
                  }
                }
              } else {
                Vec<Fun *> *calls = f->calls.get(p);
                if (calls)
                  forv_Fun(x, *calls)
                    if (x->live)
                      goto Live;
              }
              break;
            case Code_IF:
              forv_PNode(x, f->fa_all_PNodes) // potentially expensive
                if (x->live)
                  if (x->dom->is_dominated_by(p->dom))
                    forv_PNode(s, p->cfg_succ)
                      if (!x->dom->is_dominated_by(s->dom))
                        goto Live;
              break;
          }
        continue; // handle fall through non-live
      Live:
        p->live = 1;
        f->live = 1;
        mark_live_again = 1;
      } else
        f->live = 1;
    }
  }
}

static void
mark_initial_dead_and_alive(FA *fa, int init = 0) {
  forv_Fun(f, fa->funs) {
    f->live = init;
    forv_Var(v, f->fa_all_Vars) {
      v->live = init;
      for (int i = 0; i < v->avars.n; i++)
        if (v->avars[i].key)
          v->avars[i].value->live = false;
      if (v->type) { // mark all instance variables not live
        forv_CreationSet(cs, v->type->creators) if (cs) {
          forv_AVar(iv, cs->vars)
            iv->var->live = init;
        }
      }
    }
    forv_PNode(p, f->fa_all_PNodes) {
      p->live = init;
      if (p->code && p->code->kind == Code_SEND && p->prim && p->prim->index == P_prim_primitive) {
        cchar *name = p->code->rvals[1]->name;
        RegisteredPrim *rp = prim_get(name);
        if (rp && rp->is_visible)
          p->live = 1;
      }
    }
  }
}

void
mark_live_types(FA *fa) {
  forv_CreationSet(cs, fa->css)
    cs->type->type_live = 0;
  forv_CreationSet(cs, fa->css)
    if (cs->type && cs->type->creators.n) {
      forv_CreationSet(x, cs->type->creators) {
        forv_AVar(av, x->defs) if (av)
          if (av->var->live && !cs->type->type_live)
            cs->type->type_live = 1;
      }
    }
}

int
mark_live_code(FA *fa) {
  mark_initial_dead_and_alive(fa);
  do {
    mark_live_again = 0;
    mark_live_avars(fa);
    mark_live_pnodes(fa);
  } while (mark_live_again);
  mark_live_types(fa);
  if (ifa_verbose > 2)
    print_dead(fa);
  return 0;
}

void
mark_live_funs(FA *fa) {
  forv_Fun(f, fa->funs)
    f->live = 0;
  if1->top->fun->live = 1;
  int changed = 1;
  while (changed) {
    changed = 0;
    forv_Fun(f, fa->funs) {
      if (f->live) {
        forv_PNode(p, f->fa_all_PNodes)
          if (p->live) {
            Vec<Fun *> *fns = f->calls.get(p);
            if (fns)
              forv_Fun(x, *fns) if (!x->live) {
                x->live = 1;
                changed = 1;
              }
          }
      }
    }
  }
}

/*
  INCOMPLETE VAR BASED VERSION
*/

#if 0
static void
mark_live_vars(FA *fa) {
  forv_Fun(f, fa->funs) {
    forv_PNode(p, f->fa_all_PNodes) {
      // if a pnode is live, it's inputs (rvals) must be live
      if (p->live) {
        forv_Var(v, p->rvals) {
          if (!v->live) {
            v->live = 1;
            mark_live_again = 1;
          }
        }
    }
    forv_Var(v, f->fa_all_Vars) {
      // if an instance variable is live, then the containing object must be live
      if (!v->live && v->type)
        forv_CreationSet(cs, v->type->creators) if (cs) {
          forv_AVar(iv, cs->vars) {
            if (iv->var->live) {
              v->live = 1;
              mark_live_again = 1;
            }
          }
        }
      }
    }
  }
}

static void
mark_types_live(FA *fa) {
  forv_CreationSet(cs, fa->css)
    if (cs->type && cs->type->creators.n) {
      forv_CreationSet(x, cs->type->creators) {
        forv_AVar(av, x->defs) if (av)
          if (av->var->live)
            cs->type->type_live = 1;
      }
    }
}

static void
mark_initial_dead_and_alive(FA *fa, int init = 0) {
  forv_Fun(f, fa->funs) {
    f->live = init;
    forv_Var(v, f->fa_all_Vars) {
      v->live = INIT;
      if (v->type) { // mark all instance variables not live
        forv_CreationSet(cs, v->type->creators) if (cs) {
          forv_AVar(iv, cs->vars)
            iv->var->live = init;
        }
      }
    }
    forv_PNode(p, f->fa_all_PNodes) {
      p->live = init;
      if (p->code && p->code->kind == Code_SEND && p->prim && p->prim->index == P_prim_primitive) {
        cchar *name = p->code->rvals[1]->name;
        RegisteredPrim *rp = pdb->fa->primitive_transfer_functions.get(name);
        if (rp && rp->is_visible)
          p->live = 1;
      }
    }
  }
  forv_CreationSet(cs, fa->css)
    cs->type->type_live = init;
}

int
mark_dead_code(FA *fa) {
  mark_initial_dead_and_alive(fa);
  do {
    mark_live_again = 0;
    mark_live_vars(fa);
    mark_live_pnodes(fa);
  } while (mark_live_again);
  mark_types_live(fa);
  if (ifa_verbose > 2)
    print_dead(fa);
  return 0;
}
#endif
<|endoftext|>


<commit_before>/*
 * Copyright (c) 1998-1999 Stephen Williams (steve@icarus.com)
 *
 *    This source code is free software; you can redistribute it
 *    and/or modify it in source code form under the terms of the GNU
 *    General Public License as published by the Free Software
 *    Foundation; either version 2 of the License, or (at your option)
 *    any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with this program; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 */
#ifdef HAVE_CVS_IDENT
#ident "$Id: eval.cc,v 1.40 2006/04/10 00:37:42 steve Exp $"
#endif

# include "config.h"

# include  <iostream>

# include  "PExpr.h"
# include  "netlist.h"
# include  "netmisc.h"
# include  "compiler.h"

verinum* PExpr::eval_const(const Design*, NetScope*) const
{
      return 0;
}

verinum* PEBinary::eval_const(const Design*des, NetScope*scope) const
{
      verinum*l = left_->eval_const(des, scope);
      if (l == 0) return 0;
      verinum*r = right_->eval_const(des, scope);
      if (r == 0) {
	    delete l;
	    return 0;
      }
      verinum*res;

      switch (op_) {
	  case '+': {
		if (l->is_defined() && r->is_defined()) {
		      res = new verinum(*l + *r);
		} else {
		      res = new verinum(verinum::Vx, l->len());
		}
		break;
	  }
	  case '-': {
		if (l->is_defined() && r->is_defined()) {
		      res = new verinum(*l - *r);
		} else {
		      res = new verinum(verinum::Vx, l->len());
		}
		break;
	  }
	  case '*': {
		if (l->is_defined() && r->is_defined()) {
		      res = new verinum(*l * *r);
		} else {
		      res = new verinum(verinum::Vx, l->len());
		}
		break;
	  }
	  case '/': {
		if (l->is_defined() && r->is_defined()) {
		      long lv = l->as_long();
		      long rv = r->as_long();
		      res = new verinum(lv / rv, l->len());
		} else {
		      res = new verinum(verinum::Vx, l->len());
		}
		break;
	  }
	  case '%': {
		if (l->is_defined() && r->is_defined()) {
		      long lv = l->as_long();
		      long rv = r->as_long();
		      res = new verinum(lv % rv, l->len());
		} else {
		      res = new verinum(verinum::Vx, l->len());
		}
		break;
	  }
	  case '>': {
		if (l->is_defined() && r->is_defined()) {
		      long lv = l->as_long();
		      long rv = r->as_long();
		      res = new verinum(lv > rv, l->len());
		} else {
		      res = new verinum(verinum::Vx, l->len());
		}
		break;
	  }
	  case '<': {
		if (l->is_defined() && r->is_defined()) {
		      long lv = l->as_long();
		      long rv = r->as_long();
		      res = new verinum(lv < rv, l->len());
		} else {
		      res = new verinum(verinum::Vx, l->len());
		}
		break;
	  }
	  case 'l': { // left shift (<<)
		assert(r->is_defined());
		unsigned long rv = r->as_ulong();
		res = new verinum(verinum::V0, l->len());
		if (rv < res->len()) {
		      unsigned cnt = res->len() - rv;
		      for (unsigned idx = 0 ;  idx < cnt ;  idx += 1)
			    res->set(idx+rv, l->get(idx));
		}
		break;
	  }
	  case 'r': { // right shift (>>)
		assert(r->is_defined());
		unsigned long rv = r->as_ulong();
		res = new verinum(verinum::V0, l->len());
		if (rv < res->len()) {
		      unsigned cnt = res->len() - rv;
		      for (unsigned idx = 0 ;  idx < cnt ;  idx += 1)
			    res->set(idx, l->get(idx+rv));
		}
		break;
	  }

	  default:
	    delete l;
	    delete r;
	    return 0;
      }

      delete l;
      delete r;
      return res;
}
verinum* PEConcat::eval_const(const Design*des, NetScope*scope) const
{
      verinum*accum = parms_[0]->eval_const(des, scope);
      if (accum == 0)
	    return 0;

      for (unsigned idx = 1 ;  idx < parms_.count() ;  idx += 1) {
	    verinum*tmp = parms_[idx]->eval_const(des, scope);
	    assert(tmp);

	    *accum = concat(*accum, *tmp);
	    delete tmp;
      }

      return accum;
}

/*
 * Evaluate an identifier as a constant expression. This is only
 * possible if the identifier is that of a parameter.
 */
verinum* PEIdent::eval_const(const Design*des, NetScope*scope) const
{
      assert(scope);
      NetNet*net;
      NetMemory*mem;
      NetEvent*eve;
      const NetExpr*expr;

	// Handle the special case that this ident is a genvar
	// variable name. In that case, the genvar meaning preempts
	// everything and we just return that value immediately.
      if (scope->genvar_tmp
	  && strcmp(path_.peek_tail_name(),scope->genvar_tmp) == 0) {
	    return new verinum(scope->genvar_tmp_val);
      }

      NetScope*found_in = symbol_search(des, scope, path_,
					net, mem, expr, eve);

      if (expr == 0)
	    return 0;

      const NetEConst*eval = dynamic_cast<const NetEConst*>(expr);
      if (eval == 0) {
	    cerr << get_line() << ": internal error: Unable to evaluate "
		 << "constant expression (parameter=" << path_
		 << "): " << *expr << endl;
	    return 0;
      }

      assert(eval);

      if (msb_ || lsb_)
	    return 0;

      return new verinum(eval->value());
}

verinum* PEFNumber::eval_const(const Design*, NetScope*) const
{
      long val = value_->as_long();
      return new verinum(val);
}

verinum* PENumber::eval_const(const Design*, NetScope*) const
{
      return new verinum(value());
}

verinum* PEString::eval_const(const Design*, NetScope*) const
{
      return new verinum(string(text_));
}

verinum* PETernary::eval_const(const Design*des, NetScope*scope) const
{
      verinum*test = expr_->eval_const(des, scope);
      if (test == 0)
	    return 0;

      verinum::V bit = test->get(0);
      delete test;
      switch (bit) {
	  case verinum::V0:
	    return fal_->eval_const(des, scope);
	  case verinum::V1:
	    return tru_->eval_const(des, scope);
	  default:
	    return 0;
	      // XXXX It is possible to handle this case if both fal_
	      // and tru_ are constant. Someday...
      }
}

verinum* PEUnary::eval_const(const Design*des, NetScope*scope) const
{
      verinum*val = expr_->eval_const(des, scope);
      if (val == 0)
	    return 0;

      switch (op_) {
	  case '+':
	    return val;

	  case '-': {
		  /* We need to expand the value a bit if we are
		     taking the 2's complement so that we are
		     guaranteed to not overflow. */
		verinum tmp (0UL, val->len()+1);
		for (unsigned idx = 0 ;  idx < val->len() ;  idx += 1)
		      tmp.set(idx, val->get(idx));

		*val = v_not(tmp) + verinum(verinum::V1, 1);
		val->has_sign(true);
		return val;
	  }

      }
	    delete val;
      return 0;
}

/*
 * $Log: eval.cc,v $
 * Revision 1.40  2006/04/10 00:37:42  steve
 *  Add support for generate loops w/ wires and gates.
 *
 * Revision 1.39  2005/12/07 04:04:23  steve
 *  Allow constant concat expressions.
 *
 * Revision 1.38  2005/11/27 17:01:57  steve
 *  Fix for stubborn compiler.
 *
 * Revision 1.37  2005/11/27 05:56:20  steve
 *  Handle bit select of parameter with ranges.
 *
 * Revision 1.36  2003/06/21 01:21:43  steve
 *  Harmless fixup of warnings.
 *
 * Revision 1.35  2003/04/14 03:40:21  steve
 *  Make some effort to preserve bits while
 *  operating on constant values.
 *
 * Revision 1.34  2003/03/26 06:16:18  steve
 *  Evaluate > and < in constant expressions.
 *
 * Revision 1.33  2003/03/10 23:40:53  steve
 *  Keep parameter constants for the ivl_target API.
 *
 * Revision 1.32  2002/10/19 22:59:49  steve
 *  Redo the parameter vector support to allow
 *  parameter names in range expressions.
 *
 * Revision 1.31  2002/10/13 05:01:07  steve
 *  More verbose eval_const assert message.
 *
 * Revision 1.30  2002/08/12 01:34:59  steve
 *  conditional ident string using autoconfig.
 *
 * Revision 1.29  2002/06/07 02:57:54  steve
 *  Simply give up on constants with indices.
 *
 * Revision 1.28  2002/06/06 18:57:04  steve
 *  Better error for identifier index eval.
 *
 * Revision 1.27  2002/05/23 03:08:51  steve
 *  Add language support for Verilog-2001 attribute
 *  syntax. Hook this support into existing $attribute
 *  handling, and add number and void value types.
 *
 *  Add to the ivl_target API new functions for access
 *  of complex attributes attached to gates.
 *
 * Revision 1.26  2001/12/29 22:10:10  steve
 *  constant eval of arithmetic with x and z.
 *
 * Revision 1.25  2001/12/29 00:43:55  steve
 *  Evaluate constant right shifts.
 *
 * Revision 1.24  2001/12/03 04:47:15  steve
 *  Parser and pform use hierarchical names as hname_t
 *  objects instead of encoded strings.
 *
 * Revision 1.23  2001/11/07 04:01:59  steve
 *  eval_const uses scope instead of a string path.
 *
 * Revision 1.22  2001/11/06 06:11:55  steve
 *  Support more real arithmetic in delay constants.
 *
 * Revision 1.21  2001/07/25 03:10:49  steve
 *  Create a config.h.in file to hold all the config
 *  junk, and support gcc 3.0. (Stephan Boettcher)
 *
 * Revision 1.20  2001/02/09 02:49:59  steve
 *  Be more clear about scope of failure.
 *
 * Revision 1.19  2001/01/27 05:41:48  steve
 *  Fix sign extension of evaluated constants. (PR#91)
 *
 * Revision 1.18  2001/01/14 23:04:56  steve
 *  Generalize the evaluation of floating point delays, and
 *  get it working with delay assignment statements.
 *
 *  Allow parameters to be referenced by hierarchical name.
 *
 * Revision 1.17  2001/01/04 04:47:51  steve
 *  Add support for << is signal indices.
 *
 * Revision 1.16  2000/12/10 22:01:36  steve
 *  Support decimal constants in behavioral delays.
 *
 * Revision 1.15  2000/09/07 22:38:13  steve
 *  Support unary + and - in constants.
 */

<commit_msg> Error message if concat expression cannot evaluate.<commit_after>/*
 * Copyright (c) 1998-1999 Stephen Williams (steve@icarus.com)
 *
 *    This source code is free software; you can redistribute it
 *    and/or modify it in source code form under the terms of the GNU
 *    General Public License as published by the Free Software
 *    Foundation; either version 2 of the License, or (at your option)
 *    any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with this program; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 */
#ifdef HAVE_CVS_IDENT
#ident "$Id: eval.cc,v 1.41 2006/05/17 16:49:30 steve Exp $"
#endif

# include "config.h"

# include  <iostream>

# include  "PExpr.h"
# include  "netlist.h"
# include  "netmisc.h"
# include  "compiler.h"

verinum* PExpr::eval_const(const Design*, NetScope*) const
{
      return 0;
}

verinum* PEBinary::eval_const(const Design*des, NetScope*scope) const
{
      verinum*l = left_->eval_const(des, scope);
      if (l == 0) return 0;
      verinum*r = right_->eval_const(des, scope);
      if (r == 0) {
	    delete l;
	    return 0;
      }
      verinum*res;

      switch (op_) {
	  case '+': {
		if (l->is_defined() && r->is_defined()) {
		      res = new verinum(*l + *r);
		} else {
		      res = new verinum(verinum::Vx, l->len());
		}
		break;
	  }
	  case '-': {
		if (l->is_defined() && r->is_defined()) {
		      res = new verinum(*l - *r);
		} else {
		      res = new verinum(verinum::Vx, l->len());
		}
		break;
	  }
	  case '*': {
		if (l->is_defined() && r->is_defined()) {
		      res = new verinum(*l * *r);
		} else {
		      res = new verinum(verinum::Vx, l->len());
		}
		break;
	  }
	  case '/': {
		if (l->is_defined() && r->is_defined()) {
		      long lv = l->as_long();
		      long rv = r->as_long();
		      res = new verinum(lv / rv, l->len());
		} else {
		      res = new verinum(verinum::Vx, l->len());
		}
		break;
	  }
	  case '%': {
		if (l->is_defined() && r->is_defined()) {
		      long lv = l->as_long();
		      long rv = r->as_long();
		      res = new verinum(lv % rv, l->len());
		} else {
		      res = new verinum(verinum::Vx, l->len());
		}
		break;
	  }
	  case '>': {
		if (l->is_defined() && r->is_defined()) {
		      long lv = l->as_long();
		      long rv = r->as_long();
		      res = new verinum(lv > rv, l->len());
		} else {
		      res = new verinum(verinum::Vx, l->len());
		}
		break;
	  }
	  case '<': {
		if (l->is_defined() && r->is_defined()) {
		      long lv = l->as_long();
		      long rv = r->as_long();
		      res = new verinum(lv < rv, l->len());
		} else {
		      res = new verinum(verinum::Vx, l->len());
		}
		break;
	  }
	  case 'l': { // left shift (<<)
		assert(r->is_defined());
		unsigned long rv = r->as_ulong();
		res = new verinum(verinum::V0, l->len());
		if (rv < res->len()) {
		      unsigned cnt = res->len() - rv;
		      for (unsigned idx = 0 ;  idx < cnt ;  idx += 1)
			    res->set(idx+rv, l->get(idx));
		}
		break;
	  }
	  case 'r': { // right shift (>>)
		assert(r->is_defined());
		unsigned long rv = r->as_ulong();
		res = new verinum(verinum::V0, l->len());
		if (rv < res->len()) {
		      unsigned cnt = res->len() - rv;
		      for (unsigned idx = 0 ;  idx < cnt ;  idx += 1)
			    res->set(idx, l->get(idx+rv));
		}
		break;
	  }

	  default:
	    delete l;
	    delete r;
	    return 0;
      }

      delete l;
      delete r;
      return res;
}
verinum* PEConcat::eval_const(const Design*des, NetScope*scope) const
{
      verinum*accum = parms_[0]->eval_const(des, scope);
      if (accum == 0)
	    return 0;

      for (unsigned idx = 1 ;  idx < parms_.count() ;  idx += 1) {

	    verinum*tmp = parms_[idx]->eval_const(des, scope);
	    if (tmp == 0) {
		  cerr << get_line() << ": error: "
		       << "Unable to evaluate constant expression in concat: "
		       << *parms_[idx] << endl;
		  delete accum;
		  return 0;
	    }
	    assert(tmp);

	    *accum = concat(*accum, *tmp);
	    delete tmp;
      }

      return accum;
}

/*
 * Evaluate an identifier as a constant expression. This is only
 * possible if the identifier is that of a parameter.
 */
verinum* PEIdent::eval_const(const Design*des, NetScope*scope) const
{
      assert(scope);
      NetNet*net;
      NetMemory*mem;
      NetEvent*eve;
      const NetExpr*expr;

	// Handle the special case that this ident is a genvar
	// variable name. In that case, the genvar meaning preempts
	// everything and we just return that value immediately.
      if (scope->genvar_tmp
	  && strcmp(path_.peek_tail_name(),scope->genvar_tmp) == 0) {
	    return new verinum(scope->genvar_tmp_val);
      }

      NetScope*found_in = symbol_search(des, scope, path_,
					net, mem, expr, eve);

      if (expr == 0)
	    return 0;

      const NetEConst*eval = dynamic_cast<const NetEConst*>(expr);
      if (eval == 0) {
	    cerr << get_line() << ": internal error: Unable to evaluate "
		 << "constant expression (parameter=" << path_
		 << "): " << *expr << endl;
	    return 0;
      }

      assert(eval);

      if (msb_ || lsb_)
	    return 0;

      return new verinum(eval->value());
}

verinum* PEFNumber::eval_const(const Design*, NetScope*) const
{
      long val = value_->as_long();
      return new verinum(val);
}

verinum* PENumber::eval_const(const Design*, NetScope*) const
{
      return new verinum(value());
}

verinum* PEString::eval_const(const Design*, NetScope*) const
{
      return new verinum(string(text_));
}

verinum* PETernary::eval_const(const Design*des, NetScope*scope) const
{
      verinum*test = expr_->eval_const(des, scope);
      if (test == 0)
	    return 0;

      verinum::V bit = test->get(0);
      delete test;
      switch (bit) {
	  case verinum::V0:
	    return fal_->eval_const(des, scope);
	  case verinum::V1:
	    return tru_->eval_const(des, scope);
	  default:
	    return 0;
	      // XXXX It is possible to handle this case if both fal_
	      // and tru_ are constant. Someday...
      }
}

verinum* PEUnary::eval_const(const Design*des, NetScope*scope) const
{
      verinum*val = expr_->eval_const(des, scope);
      if (val == 0)
	    return 0;

      switch (op_) {
	  case '+':
	    return val;

	  case '-': {
		  /* We need to expand the value a bit if we are
		     taking the 2's complement so that we are
		     guaranteed to not overflow. */
		verinum tmp (0UL, val->len()+1);
		for (unsigned idx = 0 ;  idx < val->len() ;  idx += 1)
		      tmp.set(idx, val->get(idx));

		*val = v_not(tmp) + verinum(verinum::V1, 1);
		val->has_sign(true);
		return val;
	  }

      }
	    delete val;
      return 0;
}

/*
 * $Log: eval.cc,v $
 * Revision 1.41  2006/05/17 16:49:30  steve
 *  Error message if concat expression cannot evaluate.
 *
 * Revision 1.40  2006/04/10 00:37:42  steve
 *  Add support for generate loops w/ wires and gates.
 *
 * Revision 1.39  2005/12/07 04:04:23  steve
 *  Allow constant concat expressions.
 *
 * Revision 1.38  2005/11/27 17:01:57  steve
 *  Fix for stubborn compiler.
 *
 * Revision 1.37  2005/11/27 05:56:20  steve
 *  Handle bit select of parameter with ranges.
 *
 * Revision 1.36  2003/06/21 01:21:43  steve
 *  Harmless fixup of warnings.
 *
 * Revision 1.35  2003/04/14 03:40:21  steve
 *  Make some effort to preserve bits while
 *  operating on constant values.
 *
 * Revision 1.34  2003/03/26 06:16:18  steve
 *  Evaluate > and < in constant expressions.
 *
 * Revision 1.33  2003/03/10 23:40:53  steve
 *  Keep parameter constants for the ivl_target API.
 *
 * Revision 1.32  2002/10/19 22:59:49  steve
 *  Redo the parameter vector support to allow
 *  parameter names in range expressions.
 *
 * Revision 1.31  2002/10/13 05:01:07  steve
 *  More verbose eval_const assert message.
 *
 * Revision 1.30  2002/08/12 01:34:59  steve
 *  conditional ident string using autoconfig.
 *
 * Revision 1.29  2002/06/07 02:57:54  steve
 *  Simply give up on constants with indices.
 *
 * Revision 1.28  2002/06/06 18:57:04  steve
 *  Better error for identifier index eval.
 *
 * Revision 1.27  2002/05/23 03:08:51  steve
 *  Add language support for Verilog-2001 attribute
 *  syntax. Hook this support into existing $attribute
 *  handling, and add number and void value types.
 *
 *  Add to the ivl_target API new functions for access
 *  of complex attributes attached to gates.
 *
 * Revision 1.26  2001/12/29 22:10:10  steve
 *  constant eval of arithmetic with x and z.
 *
 * Revision 1.25  2001/12/29 00:43:55  steve
 *  Evaluate constant right shifts.
 *
 * Revision 1.24  2001/12/03 04:47:15  steve
 *  Parser and pform use hierarchical names as hname_t
 *  objects instead of encoded strings.
 *
 * Revision 1.23  2001/11/07 04:01:59  steve
 *  eval_const uses scope instead of a string path.
 *
 * Revision 1.22  2001/11/06 06:11:55  steve
 *  Support more real arithmetic in delay constants.
 *
 * Revision 1.21  2001/07/25 03:10:49  steve
 *  Create a config.h.in file to hold all the config
 *  junk, and support gcc 3.0. (Stephan Boettcher)
 *
 * Revision 1.20  2001/02/09 02:49:59  steve
 *  Be more clear about scope of failure.
 *
 * Revision 1.19  2001/01/27 05:41:48  steve
 *  Fix sign extension of evaluated constants. (PR#91)
 *
 * Revision 1.18  2001/01/14 23:04:56  steve
 *  Generalize the evaluation of floating point delays, and
 *  get it working with delay assignment statements.
 *
 *  Allow parameters to be referenced by hierarchical name.
 *
 * Revision 1.17  2001/01/04 04:47:51  steve
 *  Add support for << is signal indices.
 *
 * Revision 1.16  2000/12/10 22:01:36  steve
 *  Support decimal constants in behavioral delays.
 *
 * Revision 1.15  2000/09/07 22:38:13  steve
 *  Support unary + and - in constants.
 */

<|endoftext|>