<commit_before>#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <pthread.h>
#include <vector>

#define NXP_HW_SELF_TEST
#include "linux_nfc_factory_api.h"
#include "linux_nfc_api.h"

#define MAX_UID_LENGTH 32
#define MAIN_SLEEP 10000

static int do_poll = 1;
static std::vector <nfc_tag_info_t*> v_tags;
static pthread_mutex_t mutex;

static void interrupted(int signal)
{
    do_poll = 0;
}

void tagArrived(nfc_tag_info_t *p_taginfo)
{
    pthread_mutex_lock(&mutex);

    nfc_tag_info_t *temp = (nfc_tag_info_t *) malloc(sizeof(nfc_tag_info_t));
    memcpy(temp, p_taginfo, sizeof(nfc_tag_info_t));
    v_tags.push_back(temp);

    pthread_mutex_unlock(&mutex);
}

void tagDeparted() { }

void printTagUID(nfc_tag_info_t *p_tag)
{
    char uid[3*MAX_UID_LENGTH+1];
    int len = p_tag->uid_length;
    if(len > MAX_UID_LENGTH)
        len = MAX_UID_LENGTH;

    for(int i = 0; i < len; i++) {
        sprintf(uid + (i*3), "%02x ", p_tag->uid[i]);
    }
    uid[len*3] = '\0';

    printf("UID: %s\n", uid);
}

int main(int argc, char ** argv)
{
    struct sigaction act;
    memset(&act, '\0', sizeof(act));
    act.sa_handler = &interrupted;

    if (sigaction(SIGINT, &act, NULL) < 0 || sigaction(SIGTERM, &act, NULL)) {
        perror("sigaction");
        exit(1);
    }

    pthread_mutex_init(&mutex, NULL);

    // initialize nfcManager
    int result = nfcManager_doInitialize();
    if(result != 0)
    {
        printf("nfcManager_doInitialize failed with error code %d", result);
        exit(result);
    }

    // try to get versions
    #ifdef NXP_HW_SELF_TEST
    printf("nfcFactory_GetMwVersion:\t0x%x\n", nfcFactory_GetMwVersion());
    #endif
    printf("nfcManager_getFwVersion:\t0x%x\n\n", nfcManager_getFwVersion());

    // set up tag-callback
    nfcTagCallback_t cb_tag;
    cb_tag.onTagArrival = tagArrived;
    cb_tag.onTagDeparture = tagDeparted;
    nfcManager_registerTagCallback(&cb_tag);

    // start tag-discovery
    nfcManager_enableDiscovery(DEFAULT_NFA_TECH_MASK, 0x00, 0x00, 0);

    // main loop, performs handling of read tags
    while(do_poll)
    {
        nfc_tag_info_t *tag = NULL;

        pthread_mutex_lock(&mutex);

        int tagcount = v_tags.size();
        if(tagcount)
        {
            tag = v_tags.front();
            v_tags.erase(v_tags.begin());
        }

        pthread_mutex_unlock(&mutex);

        if(tag)
        {
            printTagUID(tag);
            free(tag);
        }

        usleep(MAIN_SLEEP);
    }

    pthread_mutex_destroy(&mutex);

    printf("\n\nExiting...\n");
    return 0;
}
<commit_msg>added license and todos<commit_after>/*
 * Copyright 2015 Pascal Mainini
 * Licensed under MIT license, see included file LICENSE or
 * http://opensource.org/licenses/MIT
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <pthread.h>
#include <vector>

#define NXP_HW_SELF_TEST
#include "linux_nfc_factory_api.h"
#include "linux_nfc_api.h"

#define MAX_UID_LENGTH 32
#define MAIN_SLEEP 10000

static int do_poll = 1;
static std::vector <nfc_tag_info_t*> v_tags;
static pthread_mutex_t mutex;

static void interrupted(int signal)
{
    do_poll = 0;
}

void tagArrived(nfc_tag_info_t *p_taginfo)
{
    pthread_mutex_lock(&mutex);

    nfc_tag_info_t *temp = (nfc_tag_info_t *) malloc(sizeof(nfc_tag_info_t));
    memcpy(temp, p_taginfo, sizeof(nfc_tag_info_t));
    v_tags.push_back(temp);

    pthread_mutex_unlock(&mutex);
}

void tagDeparted() { }

void printTagUID(nfc_tag_info_t *p_tag)
{
    char uid[3*MAX_UID_LENGTH+1];
    int len = p_tag->uid_length;
    if(len > MAX_UID_LENGTH)
        len = MAX_UID_LENGTH;

    for(int i = 0; i < len; i++) {
        sprintf(uid + (i*3), "%02x ", p_tag->uid[i]);
    }
    uid[len*3] = '\0';

    printf("UID: %s\n", uid);
}

int main(int argc, char ** argv)
{
    struct sigaction act;
    memset(&act, '\0', sizeof(act));
    act.sa_handler = &interrupted;

    if (sigaction(SIGINT, &act, NULL) < 0 || sigaction(SIGTERM, &act, NULL)) {
        perror("sigaction");
        exit(1);
    }

    pthread_mutex_init(&mutex, NULL);

    // initialize nfcManager
    int result = nfcManager_doInitialize();
    if(result != 0)
    {
        printf("nfcManager_doInitialize failed with error code %d", result);
        exit(result);
    }

    // try to get versions
    #ifdef NXP_HW_SELF_TEST
    printf("nfcFactory_GetMwVersion:\t0x%x\n", nfcFactory_GetMwVersion());
    #endif
    printf("nfcManager_getFwVersion:\t0x%x\n\n", nfcManager_getFwVersion());

    // set up tag-callback
    nfcTagCallback_t cb_tag;
    cb_tag.onTagArrival = tagArrived;
    cb_tag.onTagDeparture = tagDeparted;
    nfcManager_registerTagCallback(&cb_tag);

    // start tag-discovery
    // TODO is it possible to look for multiple tags "at the same time"?
    nfcManager_enableDiscovery(DEFAULT_NFA_TECH_MASK, 0x00, 0x00, 0);

    // main loop, performs handling of read tags
    while(do_poll)
    {
        nfc_tag_info_t *tag = NULL;

        pthread_mutex_lock(&mutex);

        int tagcount = v_tags.size();
        if(tagcount)
        {
            tag = v_tags.front();
            v_tags.erase(v_tags.begin());
        }

        pthread_mutex_unlock(&mutex);

        if(tag)
        {
            printTagUID(tag);
            free(tag);
        }

        usleep(MAIN_SLEEP);
    }

    // TODO:
    // - free remaining tags
    // - shutdown PN7120 ?

    pthread_mutex_destroy(&mutex);

    printf("\n\nExiting...\n");
    return 0;
}
<|endoftext|>


<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2011-2016.
// Distributed under the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include "cpp_utils/assert.hpp"

#include "logging.hpp"
#include "Options.hpp"
#include "SemanticalException.hpp"
#include "TerminationException.hpp"
#include "GlobalContext.hpp"

#include "ast/PassManager.hpp"
#include "ast/Pass.hpp"
#include "ast/SourceFile.hpp"
#include "ast/TemplateEngine.hpp"

//The passes
#include "ast/TransformerEngine.hpp"
#include "ast/TemplateCollectionPass.hpp"
#include "ast/ContextAnnotator.hpp"
#include "ast/structure_check.hpp"
#include "ast/structure_collection.hpp"
#include "ast/structure_inheritance.hpp"
#include "ast/structure_member_collection.hpp"
#include "ast/DefaultValues.hpp"
#include "ast/member_function_collection.hpp"
#include "ast/function_collection.hpp"
#include "ast/function_generation.hpp"
#include "ast/function_check.hpp"
#include "ast/VariablesAnnotator.hpp"
#include "ast/StringChecker.hpp"
#include "ast/TypeChecker.hpp"
#include "ast/WarningsEngine.hpp"

using namespace eddic;

namespace {

void apply_pass(std::shared_ptr<ast::Pass> pass, ast::struct_definition& struct_){
    pass->apply_struct(struct_, false);

    for(auto& block : struct_.blocks){
        if(auto* ptr = boost::get<ast::TemplateFunctionDeclaration>(&block)){
            if(!ptr->is_template()){
                pass->apply_struct_function(*ptr);
            }
        } else if(auto* ptr = boost::get<ast::Destructor>(&block)){
            pass->apply_struct_destructor(*ptr);
        } else if(auto* ptr = boost::get<ast::Constructor>(&block)){
            pass->apply_struct_constructor(*ptr);
        }
    }
}

void apply_pass(std::shared_ptr<ast::Pass> pass, ast::SourceFile& program, std::shared_ptr<Configuration> configuration){
    LOG<Info>("Passes") << "Run pass \"" << pass->name() << "\"" << log::endl;
    program.context->stats().inc_counter("passes");

    for(unsigned int i = 0; i < pass->passes(); ++i){
        pass->set_current_pass(i);
        pass->apply_program(program, false);

        bool valid = true;

        std::vector<ast::SourceFileBlock> blocks = program.blocks;
        for(auto& block : blocks){
            try {
                if(auto* ptr = boost::get<ast::TemplateFunctionDeclaration>(&block)){
                    if(ptr->is_template()){
                        pass->apply_function(*ptr);
                    }
                } else if(auto* ptr = boost::get<ast::struct_definition>(&block)){
                    if(!ptr->is_template_declaration()){
                        apply_pass(pass, *ptr);
                    }
                }
            } catch (const SemanticalException& e){
                if(!configuration->option_defined("quiet")){
                    output_exception(e, program.context);
                }

                valid = false;
            }
        }

        if(!valid){
            throw TerminationException();
        }
    }
}

template<typename Pass>
std::shared_ptr<Pass> make_pass(const std::string& name, std::shared_ptr<ast::TemplateEngine> template_engine,
            Platform platform, std::shared_ptr<Configuration> configuration, std::shared_ptr<StringPool> pool){
    auto pass = std::make_shared<Pass>();

    pass->set_name(name);
    pass->set_template_engine(template_engine);
    pass->set_platform(platform);
    pass->set_configuration(configuration);
    pass->set_string_pool(pool);

    return pass;
}

} //end of anonymous namespace

ast::PassManager::PassManager(Platform platform, std::shared_ptr<Configuration> configuration, ast::SourceFile& program, std::shared_ptr<StringPool> pool) :
        platform(platform), configuration(configuration), program(program), pool(pool) {
    template_engine = std::make_shared<ast::TemplateEngine>(*this);
}

void ast::PassManager::init_passes(){
    //Clean pass
    passes.push_back(make_pass<ast::CleanPass>("clean", template_engine, platform, configuration, pool));

    //Context annotation pass
    passes.push_back(make_pass<ast::ContextAnnotationPass>("context annotation", template_engine, platform, configuration, pool));

    //Structures collection pass
    passes.push_back(make_pass<ast::StructureCollectionPass>("structures collection", template_engine, platform, configuration, pool));

    //Structures inheritance pass
    passes.push_back(make_pass<ast::StructureInheritancePass>("structures inheritance", template_engine, platform, configuration, pool));

    //Template Collection pass
    passes.push_back(make_pass<ast::TemplateCollectionPass>("templates collection", template_engine, platform, configuration, pool));

    //Structures member collection pass
    passes.push_back(make_pass<ast::StructureMemberCollectionPass>("structures member collection", template_engine, platform, configuration, pool));

    //Function Generation Pass
    passes.push_back(make_pass<ast::FunctionGenerationPass>("function generation", template_engine, platform, configuration, pool));

    //Structures check pass
    passes.push_back(make_pass<ast::StructureCheckPass>("structure check", template_engine, platform, configuration, pool));

    //Add default values to declarations
    passes.push_back(make_pass<ast::DefaultValuesPass>("default values", template_engine, platform, configuration, pool));

    //Member function collection pass
    passes.push_back(make_pass<ast::MemberFunctionCollectionPass>("member function collection", template_engine, platform, configuration, pool));

    //Function collection pass
    passes.push_back(make_pass<ast::FunctionCollectionPass>("function collection", template_engine, platform, configuration, pool));

    //Function check pass
    passes.push_back(make_pass<ast::VariableAnnotationPass>("variables annotation", template_engine, platform, configuration, pool));

    //Function check pass
    passes.push_back(make_pass<ast::FunctionCheckPass>("function check", template_engine, platform, configuration, pool));

    //String collection pass
    passes.push_back(make_pass<ast::StringCollectionPass>("string collection", template_engine, platform, configuration, pool));

    //Type checking pass
    passes.push_back(make_pass<ast::TypeCheckingPass>("Type checking", template_engine, platform, configuration, pool));

    //Transform pass
    passes.push_back(make_pass<ast::TransformPass>("Transform", template_engine, platform, configuration, pool));

    //Transform pass
    passes.push_back(make_pass<ast::WarningsPass>("Warnings", template_engine, platform, configuration, pool));
}

void ast::PassManager::function_instantiated(ast::TemplateFunctionDeclaration& function, const std::string& context){
    LOG<Info>("Passes") << "Apply passes to instantiated function \"" << function.functionName << "\"" << " in context " << context << log::endl;

    for(auto& pass : applied_passes){
        for(unsigned int i = 0; i < pass->passes(); ++i){
            LOG<Info>("Passes") << "Run pass \"" << pass->name() << "\":" << i << log::endl;
            program.context->stats().inc_counter("passes");

            pass->set_current_pass(i);
            pass->apply_program(program, true);

            if(context.empty()){
                pass->apply_function(function);
            } else {
                for(auto& block : program.blocks){
                    if(auto* struct_type = boost::get<ast::struct_definition>(&block)){
                        if(!struct_type->is_template_declaration() && struct_type->struct_type->mangle() == context){
                            pass->apply_struct(*struct_type, true);
                            pass->apply_struct_function(function);

                            break;
                        }
                    }
                }
            }
        }
    }

    LOG<Info>("Passes") << "Passes applied to instantiated function \"" << function.functionName << "\"" << " in context " << context << log::endl;

    functions_instantiated.push_back(std::make_pair(context, function));
}

void ast::PassManager::struct_instantiated(ast::struct_definition& struct_){
    cpp_assert(struct_.is_template_instantation(), "Must be called with a template instantiation");

    LOG<Info>("Passes") << "Apply passes to instantiated struct \"" << struct_.name << "\"" << log::endl;

    inc_depth();

    for(auto& pass : applied_passes){
        for(unsigned int i = 0; i < pass->passes(); ++i){
            LOG<Info>("Passes") << "Run pass \"" << pass->name() << "\":" << i << log::endl;
            program.context->stats().inc_counter("passes");

            pass->set_current_pass(i);
            pass->apply_program(program, true);
            apply_pass(pass, struct_);
        }
    }

    dec_depth();

    LOG<Info>("Passes") << "Passes applied to instantiated struct \"" << struct_.name << "\"" << log::endl;

    class_instantiated.push_back(struct_);
}

void ast::PassManager::inc_depth(){
    ++template_depth;

    if(template_depth > static_cast<unsigned int>(configuration->option_int_value("template-depth"))){
        throw SemanticalException("Recursive template-instantiation depth limit reached");
    }
}

void ast::PassManager::dec_depth(){
    --template_depth;
}

void ast::PassManager::run_passes(){
    timing_timer timer(program.context->timing(), "ast_passes");

    for(auto& pass : passes){
        //A simple pass is only applied once to the whole program
        //They won't be applied on later instantiated function templates and class templates
        if(pass->is_simple()){
            LOG<Info>("Passes") << "Run simple pass \"" << pass->name() << "\"" << log::endl;

            for(unsigned int i = 0; i < pass->passes(); ++i){
                pass->set_current_pass(i);

                //It is up to the simple pass to recurse into the program
                pass->apply_program(program, false);
            }
        }
        //Normal pass are applied until all function and structures have been handled
        else {
            //The next passes will have to apply it again to fresh functions
            applied_passes.push_back(pass);

            apply_pass(pass, program, configuration);

            //Add the instantiated class and function templates to the actual program

            for(auto& struct_ : class_instantiated){
                program.blocks.emplace_back(struct_);
            }

            for(auto& function_pair : functions_instantiated){
                auto& context = function_pair.first;
                auto& function = function_pair.second;

                if(context.empty()){
                    program.blocks.emplace_back(function);
                } else {
                    for(auto& block : program.blocks){
                        if(auto* struct_type = boost::get<ast::struct_definition>(&block)){
                            if(!struct_type->is_template_declaration() && struct_type->struct_type->mangle() == context){
                                struct_type->blocks.emplace_back(function);
                                break;
                            }
                        }
                    }
                }
            }

            class_instantiated.clear();
            functions_instantiated.clear();
        }
    }
}
<commit_msg>Don't do copy<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2011-2016.
// Distributed under the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include "cpp_utils/assert.hpp"

#include "logging.hpp"
#include "Options.hpp"
#include "SemanticalException.hpp"
#include "TerminationException.hpp"
#include "GlobalContext.hpp"

#include "ast/PassManager.hpp"
#include "ast/Pass.hpp"
#include "ast/SourceFile.hpp"
#include "ast/TemplateEngine.hpp"

//The passes
#include "ast/TransformerEngine.hpp"
#include "ast/TemplateCollectionPass.hpp"
#include "ast/ContextAnnotator.hpp"
#include "ast/structure_check.hpp"
#include "ast/structure_collection.hpp"
#include "ast/structure_inheritance.hpp"
#include "ast/structure_member_collection.hpp"
#include "ast/DefaultValues.hpp"
#include "ast/member_function_collection.hpp"
#include "ast/function_collection.hpp"
#include "ast/function_generation.hpp"
#include "ast/function_check.hpp"
#include "ast/VariablesAnnotator.hpp"
#include "ast/StringChecker.hpp"
#include "ast/TypeChecker.hpp"
#include "ast/WarningsEngine.hpp"

using namespace eddic;

namespace {

void apply_pass(std::shared_ptr<ast::Pass> pass, ast::struct_definition& struct_){
    pass->apply_struct(struct_, false);

    for(auto& block : struct_.blocks){
        if(auto* ptr = boost::get<ast::TemplateFunctionDeclaration>(&block)){
            if(!ptr->is_template()){
                pass->apply_struct_function(*ptr);
            }
        } else if(auto* ptr = boost::get<ast::Destructor>(&block)){
            pass->apply_struct_destructor(*ptr);
        } else if(auto* ptr = boost::get<ast::Constructor>(&block)){
            pass->apply_struct_constructor(*ptr);
        }
    }
}

void apply_pass(std::shared_ptr<ast::Pass> pass, ast::SourceFile& program, std::shared_ptr<Configuration> configuration){
    LOG<Info>("Passes") << "Run pass \"" << pass->name() << "\"" << log::endl;
    program.context->stats().inc_counter("passes");

    for(unsigned int i = 0; i < pass->passes(); ++i){
        pass->set_current_pass(i);
        pass->apply_program(program, false);

        bool valid = true;

        for(auto& block : program.blocks){
            try {
                if(auto* ptr = boost::get<ast::TemplateFunctionDeclaration>(&block)){
                    if(ptr->is_template()){
                        pass->apply_function(*ptr);
                    }
                } else if(auto* ptr = boost::get<ast::struct_definition>(&block)){
                    if(!ptr->is_template_declaration()){
                        apply_pass(pass, *ptr);
                    }
                }
            } catch (const SemanticalException& e){
                if(!configuration->option_defined("quiet")){
                    output_exception(e, program.context);
                }

                valid = false;
            }
        }

        if(!valid){
            throw TerminationException();
        }
    }
}

template<typename Pass>
std::shared_ptr<Pass> make_pass(const std::string& name, std::shared_ptr<ast::TemplateEngine> template_engine,
            Platform platform, std::shared_ptr<Configuration> configuration, std::shared_ptr<StringPool> pool){
    auto pass = std::make_shared<Pass>();

    pass->set_name(name);
    pass->set_template_engine(template_engine);
    pass->set_platform(platform);
    pass->set_configuration(configuration);
    pass->set_string_pool(pool);

    return pass;
}

} //end of anonymous namespace

ast::PassManager::PassManager(Platform platform, std::shared_ptr<Configuration> configuration, ast::SourceFile& program, std::shared_ptr<StringPool> pool) :
        platform(platform), configuration(configuration), program(program), pool(pool) {
    template_engine = std::make_shared<ast::TemplateEngine>(*this);
}

void ast::PassManager::init_passes(){
    //Clean pass
    passes.push_back(make_pass<ast::CleanPass>("clean", template_engine, platform, configuration, pool));

    //Context annotation pass
    passes.push_back(make_pass<ast::ContextAnnotationPass>("context annotation", template_engine, platform, configuration, pool));

    //Structures collection pass
    passes.push_back(make_pass<ast::StructureCollectionPass>("structures collection", template_engine, platform, configuration, pool));

    //Structures inheritance pass
    passes.push_back(make_pass<ast::StructureInheritancePass>("structures inheritance", template_engine, platform, configuration, pool));

    //Template Collection pass
    passes.push_back(make_pass<ast::TemplateCollectionPass>("templates collection", template_engine, platform, configuration, pool));

    //Structures member collection pass
    passes.push_back(make_pass<ast::StructureMemberCollectionPass>("structures member collection", template_engine, platform, configuration, pool));

    //Function Generation Pass
    passes.push_back(make_pass<ast::FunctionGenerationPass>("function generation", template_engine, platform, configuration, pool));

    //Structures check pass
    passes.push_back(make_pass<ast::StructureCheckPass>("structure check", template_engine, platform, configuration, pool));

    //Add default values to declarations
    passes.push_back(make_pass<ast::DefaultValuesPass>("default values", template_engine, platform, configuration, pool));

    //Member function collection pass
    passes.push_back(make_pass<ast::MemberFunctionCollectionPass>("member function collection", template_engine, platform, configuration, pool));

    //Function collection pass
    passes.push_back(make_pass<ast::FunctionCollectionPass>("function collection", template_engine, platform, configuration, pool));

    //Function check pass
    passes.push_back(make_pass<ast::VariableAnnotationPass>("variables annotation", template_engine, platform, configuration, pool));

    //Function check pass
    passes.push_back(make_pass<ast::FunctionCheckPass>("function check", template_engine, platform, configuration, pool));

    //String collection pass
    passes.push_back(make_pass<ast::StringCollectionPass>("string collection", template_engine, platform, configuration, pool));

    //Type checking pass
    passes.push_back(make_pass<ast::TypeCheckingPass>("Type checking", template_engine, platform, configuration, pool));

    //Transform pass
    passes.push_back(make_pass<ast::TransformPass>("Transform", template_engine, platform, configuration, pool));

    //Transform pass
    passes.push_back(make_pass<ast::WarningsPass>("Warnings", template_engine, platform, configuration, pool));
}

void ast::PassManager::function_instantiated(ast::TemplateFunctionDeclaration& function, const std::string& context){
    LOG<Info>("Passes") << "Apply passes to instantiated function \"" << function.functionName << "\"" << " in context " << context << log::endl;

    for(auto& pass : applied_passes){
        for(unsigned int i = 0; i < pass->passes(); ++i){
            LOG<Info>("Passes") << "Run pass \"" << pass->name() << "\":" << i << log::endl;
            program.context->stats().inc_counter("passes");

            pass->set_current_pass(i);
            pass->apply_program(program, true);

            if(context.empty()){
                pass->apply_function(function);
            } else {
                for(auto& block : program.blocks){
                    if(auto* struct_type = boost::get<ast::struct_definition>(&block)){
                        if(!struct_type->is_template_declaration() && struct_type->struct_type->mangle() == context){
                            pass->apply_struct(*struct_type, true);
                            pass->apply_struct_function(function);

                            break;
                        }
                    }
                }
            }
        }
    }

    LOG<Info>("Passes") << "Passes applied to instantiated function \"" << function.functionName << "\"" << " in context " << context << log::endl;

    functions_instantiated.push_back(std::make_pair(context, function));
}

void ast::PassManager::struct_instantiated(ast::struct_definition& struct_){
    cpp_assert(struct_.is_template_instantation(), "Must be called with a template instantiation");

    LOG<Info>("Passes") << "Apply passes to instantiated struct \"" << struct_.name << "\"" << log::endl;

    inc_depth();

    for(auto& pass : applied_passes){
        for(unsigned int i = 0; i < pass->passes(); ++i){
            LOG<Info>("Passes") << "Run pass \"" << pass->name() << "\":" << i << log::endl;
            program.context->stats().inc_counter("passes");

            pass->set_current_pass(i);
            pass->apply_program(program, true);
            apply_pass(pass, struct_);
        }
    }

    dec_depth();

    LOG<Info>("Passes") << "Passes applied to instantiated struct \"" << struct_.name << "\"" << log::endl;

    class_instantiated.push_back(struct_);
}

void ast::PassManager::inc_depth(){
    ++template_depth;

    if(template_depth > static_cast<unsigned int>(configuration->option_int_value("template-depth"))){
        throw SemanticalException("Recursive template-instantiation depth limit reached");
    }
}

void ast::PassManager::dec_depth(){
    --template_depth;
}

void ast::PassManager::run_passes(){
    timing_timer timer(program.context->timing(), "ast_passes");

    for(auto& pass : passes){
        //A simple pass is only applied once to the whole program
        //They won't be applied on later instantiated function templates and class templates
        if(pass->is_simple()){
            LOG<Info>("Passes") << "Run simple pass \"" << pass->name() << "\"" << log::endl;

            for(unsigned int i = 0; i < pass->passes(); ++i){
                pass->set_current_pass(i);

                //It is up to the simple pass to recurse into the program
                pass->apply_program(program, false);
            }
        }
        //Normal pass are applied until all function and structures have been handled
        else {
            //The next passes will have to apply it again to fresh functions
            applied_passes.push_back(pass);

            apply_pass(pass, program, configuration);

            //Add the instantiated class and function templates to the actual program

            for(auto& struct_ : class_instantiated){
                program.blocks.emplace_back(struct_);
            }

            for(auto& function_pair : functions_instantiated){
                auto& context = function_pair.first;
                auto& function = function_pair.second;

                if(context.empty()){
                    program.blocks.emplace_back(function);
                } else {
                    for(auto& block : program.blocks){
                        if(auto* struct_type = boost::get<ast::struct_definition>(&block)){
                            if(!struct_type->is_template_declaration() && struct_type->struct_type->mangle() == context){
                                struct_type->blocks.emplace_back(function);
                                break;
                            }
                        }
                    }
                }
            }

            class_instantiated.clear();
            functions_instantiated.clear();
        }
    }
}
<|endoftext|>


<commit_before>#include "asyncserialport.h"

#include <QDebug>
#include <QMetaEnum>
#include <QSerialPortInfo>

AsyncPort::AsyncPort(QObject *parent) :
    QObject(parent),
    m_serialConnectionCheckTimer(Q_NULLPTR),
    m_serialPort(Q_NULLPTR),
    m_localShell(Q_NULLPTR),
    m_port(Q_NULLPTR)
{
}

QString AsyncPort::convertStatusToQString(AsyncPort::Status st)
{
    //
    // (c) http://stackoverflow.com/a/34281989/6895308
    //

    const QMetaObject &mo = AsyncPort::staticMetaObject;
    int index = mo.indexOfEnumerator("Status");
    QMetaEnum metaEnum = mo.enumerator(index);
    return metaEnum.valueToKey(st);
}

void AsyncPort::initialize()
{
    m_serialConnectionCheckTimer = new QTimer(this);
    connect(m_serialConnectionCheckTimer, SIGNAL(timeout()), this, SLOT(checkSerialPort()));

    m_serialPort = new QSerialPort(this);
    connect(m_serialPort, SIGNAL(error(QSerialPort::SerialPortError)), this, SLOT(serialPortError(QSerialPort::SerialPortError)));

    m_localShell = new QProcess(this);
    QProcessEnvironment env = m_localShell->processEnvironment();
    env.insert("TERM", "vt100");
    m_localShell->setProcessEnvironment(env);
    m_localShell->setProcessChannelMode(QProcess::MergedChannels);

    updateStatus(Offline);
}

void AsyncPort::openSerialPort(const QString &pn, qint32 br)
{
    if (pn.isEmpty())
    {
        return;
    }

    if (m_port == m_localShell)
    {
        closePort(); // shut down local shell
        Q_ASSERT(m_port == Q_NULLPTR);
    }

    if (m_port != m_serialPort)
    {
        m_port = m_serialPort;
    }

    if (m_serialPort->isOpen())
    {
        if (m_serialPort->portName() != pn)
        {
            m_serialPort->close();
            qDebug() << "port" << m_serialPort->portName() << "closed";
        }
        else if (m_serialPort->baudRate() != br)
        {
            m_serialPort->setBaudRate(br);
            qDebug() << "port" << m_serialPort->portName() << "@" << m_serialPort->baudRate() << "opened";

            updateStatus(Online);
        }
    }

    if (!m_serialPort->isOpen())
    {
        m_serialPort->setPortName(pn);

        if (!m_serialPort->open(QSerialPort::ReadWrite))
        {
            qDebug() << "ERROR Can't open" << pn;

            updateStatus(Error);
        }
        else
        {
            m_serialPort->setParity(QSerialPort::NoParity); // todo if
            m_serialPort->setDataBits(QSerialPort::Data8); // todo if
            m_serialPort->setParity(QSerialPort::NoParity); // todo if
            m_serialPort->setStopBits(QSerialPort::OneStop); // todo if
            m_serialPort->setFlowControl(QSerialPort::NoFlowControl); // todo if

            m_serialPort->setBaudRate(br);

            m_serialPort->clear();

            qDebug() << "port" << m_serialPort->portName() << "@" << m_serialPort->baudRate() << "opened";

            connect(m_serialPort, SIGNAL(readyRead()), this, SLOT(readPort()));

            updateStatus(Online);

            m_serialConnectionCheckTimer->start(1000);
        }
    }
}

void AsyncPort::openLocalShell()
{
    if (m_port == m_serialPort)
    {
        closePort(); // shut down serial port
        Q_ASSERT(m_port == Q_NULLPTR);
    }

    if (m_port != m_localShell)
    {
        m_port = m_localShell;
    }

    connect(m_localShell, SIGNAL(readyRead()), this, SLOT(readPort()));

    connect(m_localShell, SIGNAL(started()), this, SLOT(startedLocalShell()));
    connect(m_localShell, SIGNAL(error(QProcess::ProcessError)), this, SLOT(errorLocalShell(QProcess::ProcessError)));
    connect(m_localShell, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(finishedLocalShell(int,QProcess::ExitStatus)));
    connect(m_localShell, SIGNAL(stateChanged(QProcess::ProcessState)), this, SLOT(stateChangedLocalShell(QProcess::ProcessState)));

    m_localShell->start("sh", QStringList("-i"), QIODevice::ReadWrite);

    updateStatus(Online);
}

void AsyncPort::closePort(AsyncPort::Status st)
{
    Q_ASSERT(st != Online);

    if (m_port)
    {
        disconnect(m_port, SIGNAL(readyRead()), this, SLOT(readPort()));
    }

    if (m_port == m_serialPort)
    {
        if (m_serialPort->isOpen())
        {
            m_serialPort->close();
            qDebug() << "port" << m_serialPort->portName() << "closed";
        }
        m_serialConnectionCheckTimer->stop();
        m_serialPort->clearError();
    }
    else if (m_port == m_localShell)
    {
        if (m_localShell->isOpen())
        {
            disconnect(m_localShell, SIGNAL(started()), this, SLOT(startedLocalShell()));
            disconnect(m_localShell, SIGNAL(error(QProcess::ProcessError)), this, SLOT(errorLocalShell(QProcess::ProcessError)));
            disconnect(m_localShell, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(finishedLocalShell(int,QProcess::ExitStatus)));
            disconnect(m_localShell, SIGNAL(stateChanged(QProcess::ProcessState)), this, SLOT(stateChangedLocalShell(QProcess::ProcessState)));

            m_localShell->close();
            qDebug() << "local shell closed"; // XXX wait for finish?
        }
    }

    m_port = Q_NULLPTR;
}

void AsyncPort::sendData(QByteArray data)
{
    //qDebug() << __FUNCTION__;

    if (!m_port)
    {
        qDebug() << "Warning:" << __FUNCTION__ << ": no port is opened";
        return;
    }

    if (!m_port->isOpen())
    {
        qDebug() << "Warning:" << __FUNCTION__ << ": port" << portName() << "is not opened";
    }
    else
    {
        m_port->write(data);
    }
}

void AsyncPort::readPort()
{
    //qDebug() << __FUNCTION__;

    if (!m_port)
    {
        qDebug() << "Warning:" << __FUNCTION__ << ": no port is opened";
        return;
    }

    QByteArray data = m_port->readAll();
    emit dataReceived(data, m_port == m_localShell);
}

void AsyncPort::checkSerialPort()
{
    Q_ASSERT(m_port == m_serialPort);

    if (m_serialPort->isOpen())
    {
        QSerialPortInfo info(*m_serialPort);
        if (!info.isValid())
        {
            qDebug() << "Warning: port" << m_serialPort->portName() << "is invalid, closing...";
            closePort(Disconnected);
        }
    }
}

void AsyncPort::serialPortError(QSerialPort::SerialPortError serialPortError)
{
    Q_ASSERT(m_port == m_serialPort);

    if (serialPortError != QSerialPort::NoError)
    {
        qDebug() << "Serial port error:" << serialPortError << ", closing...";
        closePort(Error);
    }
}

void AsyncPort::startedLocalShell()
{
    //qDebug() << __FUNCTION__;
}

void AsyncPort::errorLocalShell(QProcess::ProcessError e)
{
    qDebug() << __FUNCTION__ << e;
}

void AsyncPort::finishedLocalShell(int r, QProcess::ExitStatus es)
{
    qDebug() << __FUNCTION__ << r << es;
}

void AsyncPort::stateChangedLocalShell(QProcess::ProcessState state)
{
    switch (state)
    {
    case QProcess::NotRunning:
        updateStatus(Offline);
        break;

    case QProcess::Starting:
        updateStatus(Opening);
        break;

    case QProcess::Running:
        updateStatus(Online);
        break;
    }
}

void AsyncPort::updateStatus(AsyncPort::Status st)
{
    m_status = st;
    emit statusChanged(m_status, portName(), baudRate());
}

const QString AsyncPort::portName()
{
    if (m_port == m_serialPort)
    {
        return m_serialPort->portName();
    }

    if (m_port == m_localShell)
    {
        return m_localShell->program();
    }

    return "";
}

qint32 AsyncPort::baudRate()
{
    if (m_port == m_serialPort)
    {
        return m_serialPort->baudRate();
    }

    return 0;
}
<commit_msg>try to configure serial port before opening<commit_after>#include "asyncserialport.h"

#include <QDebug>
#include <QMetaEnum>
#include <QSerialPortInfo>

AsyncPort::AsyncPort(QObject *parent) :
    QObject(parent),
    m_serialConnectionCheckTimer(Q_NULLPTR),
    m_serialPort(Q_NULLPTR),
    m_localShell(Q_NULLPTR),
    m_port(Q_NULLPTR)
{
}

QString AsyncPort::convertStatusToQString(AsyncPort::Status st)
{
    //
    // (c) http://stackoverflow.com/a/34281989/6895308
    //

    const QMetaObject &mo = AsyncPort::staticMetaObject;
    int index = mo.indexOfEnumerator("Status");
    QMetaEnum metaEnum = mo.enumerator(index);
    return metaEnum.valueToKey(st);
}

void AsyncPort::initialize()
{
    m_serialConnectionCheckTimer = new QTimer(this);
    connect(m_serialConnectionCheckTimer, SIGNAL(timeout()), this, SLOT(checkSerialPort()));

    m_serialPort = new QSerialPort(this);

    m_localShell = new QProcess(this);
    QProcessEnvironment env = m_localShell->processEnvironment();
    env.insert("TERM", "vt100");
    m_localShell->setProcessEnvironment(env);
    m_localShell->setProcessChannelMode(QProcess::MergedChannels);

    updateStatus(Offline);
}

void AsyncPort::openSerialPort(const QString &pn, qint32 br)
{
    if (pn.isEmpty())
    {
        return;
    }

    if (m_port == m_localShell)
    {
        closePort(); // shut down local shell
        Q_ASSERT(m_port == Q_NULLPTR);
    }

    if (m_port != m_serialPort)
    {
        m_port = m_serialPort;
    }

    if (m_serialPort->isOpen())
    {
        if (m_serialPort->portName() != pn)
        {
            m_serialPort->close();
            qDebug() << "port" << m_serialPort->portName() << "closed";
        }
        else if (m_serialPort->baudRate() != br)
        {
            m_serialPort->setBaudRate(br);
            qDebug() << "port" << m_serialPort->portName() << "@" << m_serialPort->baudRate() << "opened";

            updateStatus(Online);
        }
    }

    if (!m_serialPort->isOpen())
    {
        m_serialPort->setPortName(pn);

        bool portInited = (m_serialPort->setParity(QSerialPort::NoParity) &&
                           m_serialPort->setDataBits(QSerialPort::Data8) &&
                           m_serialPort->setStopBits(QSerialPort::OneStop) &&
                           m_serialPort->setFlowControl(QSerialPort::NoFlowControl) &&
                           m_serialPort->setBaudRate(br));

        if (!m_serialPort->open(QSerialPort::ReadWrite))
        {
            qDebug() << "ERROR Can't open" << pn;

            updateStatus(Error);
        }
        else
        {
            if (!portInited)
            {
                portInited = (m_serialPort->setParity(QSerialPort::NoParity) &&
                              m_serialPort->setDataBits(QSerialPort::Data8) &&
                              m_serialPort->setStopBits(QSerialPort::OneStop) &&
                              m_serialPort->setFlowControl(QSerialPort::NoFlowControl) &&
                              m_serialPort->setBaudRate(br));
            }

            if (!portInited)
            {
                qDebug() << "ERROR Can't init" << pn;
                updateStatus(Error);
            }
            else
            {
                m_serialPort->clear();
                m_serialPort->clearError();

                qDebug() << "port" << m_serialPort->portName() << "@" << m_serialPort->baudRate() << "opened";

                connect(m_serialPort, SIGNAL(readyRead()), this, SLOT(readPort()));

                updateStatus(Online);

                m_serialConnectionCheckTimer->start(1000);

                connect(m_serialPort, SIGNAL(error(QSerialPort::SerialPortError)), this, SLOT(serialPortError(QSerialPort::SerialPortError)));
            }
        }
    }
}

void AsyncPort::openLocalShell()
{
    if (m_port == m_serialPort)
    {
        closePort(); // shut down serial port
        Q_ASSERT(m_port == Q_NULLPTR);
    }

    if (m_port != m_localShell)
    {
        m_port = m_localShell;
    }

    connect(m_localShell, SIGNAL(readyRead()), this, SLOT(readPort()));

    connect(m_localShell, SIGNAL(started()), this, SLOT(startedLocalShell()));
    connect(m_localShell, SIGNAL(error(QProcess::ProcessError)), this, SLOT(errorLocalShell(QProcess::ProcessError)));
    connect(m_localShell, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(finishedLocalShell(int,QProcess::ExitStatus)));
    connect(m_localShell, SIGNAL(stateChanged(QProcess::ProcessState)), this, SLOT(stateChangedLocalShell(QProcess::ProcessState)));

    m_localShell->start("sh", QStringList("-i"), QIODevice::ReadWrite);

    updateStatus(Online);
}

void AsyncPort::closePort(AsyncPort::Status st)
{
    Q_ASSERT(st != Online);

    if (m_port)
    {
        disconnect(m_port, SIGNAL(readyRead()), this, SLOT(readPort()));
    }

    if (m_port == m_serialPort)
    {
        if (m_serialPort->isOpen())
        {
            m_serialPort->close();
            qDebug() << "port" << m_serialPort->portName() << "closed";
        }
        m_serialConnectionCheckTimer->stop();
        m_serialPort->clearError();
        connect(m_serialPort, SIGNAL(error(QSerialPort::SerialPortError)), this, SLOT(serialPortError(QSerialPort::SerialPortError)));
    }
    else if (m_port == m_localShell)
    {
        if (m_localShell->isOpen())
        {
            disconnect(m_localShell, SIGNAL(started()), this, SLOT(startedLocalShell()));
            disconnect(m_localShell, SIGNAL(error(QProcess::ProcessError)), this, SLOT(errorLocalShell(QProcess::ProcessError)));
            disconnect(m_localShell, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(finishedLocalShell(int,QProcess::ExitStatus)));
            disconnect(m_localShell, SIGNAL(stateChanged(QProcess::ProcessState)), this, SLOT(stateChangedLocalShell(QProcess::ProcessState)));

            m_localShell->close();
            qDebug() << "local shell closed"; // XXX wait for finish?
        }
    }

    m_port = Q_NULLPTR;
}

void AsyncPort::sendData(QByteArray data)
{
    //qDebug() << __FUNCTION__;

    if (!m_port)
    {
        qDebug() << "Warning:" << __FUNCTION__ << ": no port is opened";
        return;
    }

    if (!m_port->isOpen())
    {
        qDebug() << "Warning:" << __FUNCTION__ << ": port" << portName() << "is not opened";
    }
    else
    {
        m_port->write(data);
    }
}

void AsyncPort::readPort()
{
    //qDebug() << __FUNCTION__;

    if (!m_port)
    {
        qDebug() << "Warning:" << __FUNCTION__ << ": no port is opened";
        return;
    }

    QByteArray data = m_port->readAll();
    emit dataReceived(data, m_port == m_localShell);
}

void AsyncPort::checkSerialPort()
{
    Q_ASSERT(m_port == m_serialPort);

    if (m_serialPort->isOpen())
    {
        QSerialPortInfo info(*m_serialPort);
        if (!info.isValid())
        {
            qDebug() << "Warning: port" << m_serialPort->portName() << "is invalid, closing...";
            closePort(Disconnected);
        }
    }
}

void AsyncPort::serialPortError(QSerialPort::SerialPortError serialPortError)
{
    Q_ASSERT(m_port == m_serialPort);

    if (serialPortError != QSerialPort::NoError)
    {
        qDebug() << "Serial port error:" << serialPortError << ", closing...";
        closePort(Error);
    }
}

void AsyncPort::startedLocalShell()
{
    //qDebug() << __FUNCTION__;
}

void AsyncPort::errorLocalShell(QProcess::ProcessError e)
{
    qDebug() << __FUNCTION__ << e;
}

void AsyncPort::finishedLocalShell(int r, QProcess::ExitStatus es)
{
    qDebug() << __FUNCTION__ << r << es;
}

void AsyncPort::stateChangedLocalShell(QProcess::ProcessState state)
{
    switch (state)
    {
    case QProcess::NotRunning:
        updateStatus(Offline);
        break;

    case QProcess::Starting:
        updateStatus(Opening);
        break;

    case QProcess::Running:
        updateStatus(Online);
        break;
    }
}

void AsyncPort::updateStatus(AsyncPort::Status st)
{
    m_status = st;
    emit statusChanged(m_status, portName(), baudRate());
}

const QString AsyncPort::portName()
{
    if (m_port == m_serialPort)
    {
        return m_serialPort->portName();
    }

    if (m_port == m_localShell)
    {
        return m_localShell->program();
    }

    return "";
}

qint32 AsyncPort::baudRate()
{
    if (m_port == m_serialPort)
    {
        return m_serialPort->baudRate();
    }

    return 0;
}
<|endoftext|>


<commit_before>//
// Created by mpolovyi on 25/01/16.
//

#include "CMonteCarloSimCtrl.h"

bool CMonteCarloSimCtrl::AcceptMove(double energy, double oldEnergy) {
    bool ret = energy <= oldEnergy;

    if (!ret) {
        auto ex = exp(-(energy - oldEnergy) / SimulationParameters.KbT);
        ret = uniformDistributionAcceptance(rnd_gen) < ex;
    }

    return ret;
}

void CMonteCarloSimCtrl::DoTestMove(size_t ptIndex) {
    auto beforeEnergy = GetParticlePotentialEnergy(ptIndex);

    oldParticleCoordinates = particles_old[ptIndex].Coordinates;

    double move = uniformDistributionMove(rnd_gen);

    particles_old[ptIndex].Coordinates += move;
    AccountForBorderAfterMove(particles_old[ptIndex]);

    auto afterEnergy = GetParticlePotentialEnergy(ptIndex);

    if (AcceptMove(afterEnergy, beforeEnergy)) {
        return;
    }
    else {
        particles_old[ptIndex].Coordinates = oldParticleCoordinates;
    }
}

void CMonteCarloSimCtrl::DoTestRotation(size_t ptIndex) {
    auto beforeEnergy = GetParticlePotentialEnergy(GetPrevious(ptIndex));

    oldParticleRotation = particles_old[ptIndex].GetRotation();

    particles_old[ptIndex].SetRotation(GetRandomUnitQuaternion());

    auto afterEnergy = GetParticlePotentialEnergy(GetPrevious(ptIndex));

    if (AcceptMove(afterEnergy, beforeEnergy)) {
        return;
    }
    else {
        particles_old[ptIndex].SetRotation(oldParticleRotation);
    }
}

#include <cereal/types/polymorphic.hpp>
#include <cereal/archives/json.hpp>

CEREAL_REGISTER_TYPE(CMonteCarloSimCtrl);<commit_msg>Repaired bug with MC acceptance<commit_after>//
// Created by mpolovyi on 25/01/16.
//

#include "CMonteCarloSimCtrl.h"

bool CMonteCarloSimCtrl::AcceptMove(double energy, double oldEnergy) {
    bool ret = energy <= oldEnergy;

    if (!ret) {
        auto ex = exp(-(energy - oldEnergy) / SimulationParameters.KbT);
        ret = uniformDistributionAcceptance(rnd_gen) < ex;
    }

    return ret;
}

void CMonteCarloSimCtrl::DoTestMove(size_t ptIndex) {
    auto beforeEnergy = GetParticlePotentialEnergy(ptIndex);

    oldParticleCoordinates = particles_old[ptIndex].Coordinates;

    double move = uniformDistributionMove(rnd_gen);

    particles_old[ptIndex].Coordinates += move;
    AccountForBorderAfterMove(particles_old[ptIndex]);

    auto afterEnergy = GetParticlePotentialEnergy(ptIndex);

    if (AcceptMove(afterEnergy, beforeEnergy)) {
        return;
    }
    else {
        particles_old[ptIndex].Coordinates = oldParticleCoordinates;
    }
}

void CMonteCarloSimCtrl::DoTestRotation(size_t ptIndex) {
    auto beforeEnergy = GetParticlePotentialEnergy(ptIndex);

    oldParticleRotation = particles_old[ptIndex].GetRotation();

    particles_old[ptIndex].SetRotation(GetRandomUnitQuaternion());

    auto afterEnergy = GetParticlePotentialEnergy(ptIndex);

    if (AcceptMove(afterEnergy, beforeEnergy)) {
        return;
    }
    else {
        particles_old[ptIndex].SetRotation(oldParticleRotation);
    }
}

#include <cereal/types/polymorphic.hpp>
#include <cereal/archives/json.hpp>

CEREAL_REGISTER_TYPE(CMonteCarloSimCtrl);<|endoftext|>


<commit_before>/*
    Copyright (C) 2001 by Christopher Nelson

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "cssysdef.h"
#include "csgeom/csrectrg.h"

csRectRegion::csRectRegion() : region(0), region_count(0), region_max(0) {}
csRectRegion::~csRectRegion()
{
  if (region != 0)
    free(region);
}

void csRectRegion::pushRect(csRect const& r)
{
  if (region_count >= region_max)
  {
    region_max += 64;
    int const nbytes = region_max * sizeof(region[0]);
    if (region == 0)
      region = (csRect*)malloc(nbytes);
    else
      region = (csRect*)realloc(region, nbytes);
  }
  region[region_count++] = r;
}

void csRectRegion::deleteRect(int i)
{
  if (region_count > 0 && i >= 0 && i < --region_count)
    memmove(region + i, region + i + 1, region_count - i);
}

//  This operation takes a rect r1 which completely contains rect r2
// and turns it into as many rects as it takes to exclude r2 from the
// area controlled by r1.
void
csRectRegion::fragmentContainedRect(csRect &r1, csRect &r2)
{
  // Edge flags
  const unsigned int LX=1, TY=2, RX=4, BY=8;
  unsigned int edges=0;

  // First check for edging.
  edges |= (r1.xmin == r2.xmin ? LX : 0);
  edges |= (r1.ymin == r2.ymin ? TY : 0);
  edges |= (r1.xmax == r2.xmax ? RX : 0);
  edges |= (r1.ymax == r2.ymax ? BY : 0);

  switch(edges)
  {
  case 0:
    // This is the easy case. Split the r1 into four pieces that exclude r2.
    // The include function pre-checks for this case and exits, so it is
    // properly handled.

    pushRect(csRect(r1.xmin,   r1.ymin,   r2.xmin-1, r1.ymax));   //left
    pushRect(csRect(r2.xmax+1, r1.ymin,   r1.xmax,   r1.ymax));   //right
    pushRect(csRect(r2.xmin,   r1.ymin,   r2.xmax,   r1.ymin-1)); //top
    pushRect(csRect(r2.xmin,   r2.ymax+1, r2.xmax,   r1.ymax));   //bottom

    return;

  case 1:
    // Three rects (top, right, bottom) [rect on left side, middle]

    pushRect(csRect(r1.xmin,   r1.ymin,   r1.xmax,   r2.ymin-1)); //top
    pushRect(csRect(r2.xmax+1, r2.ymin,   r1.xmax,   r2.ymax));   //right
    pushRect(csRect(r1.xmin,   r2.ymax+1, r1.xmax,   r1.ymax));   //bot

    return;

  case 2:
    // Three rects (bot, left, right)   [rect on top side, middle]

    pushRect(csRect(r1.xmin,   r2.ymax+1, r1.xmax,   r1.ymax));   //bot
    pushRect(csRect(r1.xmin,   r1.ymin,   r2.xmin-1, r2.ymax));   //left
    pushRect(csRect(r2.xmax+1, r1.ymin,   r1.xmax,   r2.ymax));   //right

    return;

  case 3:
    // Two rects (right, bottom)        [rect on top left corner]

    pushRect(csRect(r2.xmax+1, r1.ymin, r1.xmax,   r2.ymax)); //right
    pushRect(csRect(r1.xmin, r2.ymax+1, r1.xmax,   r1.ymax)); //bot

    return;

  case 4:
    // Three rects (top, left, bottom)  [rect on right side, middle]

    pushRect(csRect(r1.xmin, r1.ymin,   r1.xmax,   r2.ymin-1)); //top
    pushRect(csRect(r1.xmin, r2.ymin,   r2.xmax-1, r2.ymax));   //left
    pushRect(csRect(r1.xmin, r2.ymax+1, r1.xmax,   r1.ymax));   //bot

    return;

  case 5:
    // Two rects (top, bottom)          [rect in middle, horizontally touches left and right sides]

    pushRect(csRect(r1.xmin, r1.ymin,   r1.xmax,   r2.ymin-1)); //top
    pushRect(csRect(r1.xmin, r2.ymax+1, r1.xmax,   r1.ymax));   //bot

    return;

  case 6:
    // Two rects (left, bottom)         [rect on top, right corner]

    pushRect(csRect(r1.xmin, r1.ymin,   r2.xmin-1, r1.ymax));   //left
    pushRect(csRect(r2.xmin, r2.ymax+1, r1.xmax,   r1.ymax));   //bot

    return;

  case 7:
    // One rect (bottom)                [rect covers entire top]

    pushRect(csRect(r1.xmin, r2.ymax+1, r1.xmax,   r1.ymax));   //bot

    return;

  case 8:
    // Three rects (top, left, right)   [rect on bottom side, middle]

    pushRect(csRect(r1.xmin,   r1.ymin, r1.xmax,   r2.ymin-1)); //top
    pushRect(csRect(r1.xmin,   r2.ymin, r2.xmin-1, r1.ymax));   //left
    pushRect(csRect(r2.xmax+1, r2.ymin, r1.xmax,   r2.ymax));   //right

    return;

  case 9:
    // Two rects (right, top)           [rect on bottom, left corner]

    pushRect(csRect(r2.xmax+1, r2.ymin, r1.xmax, r1.ymax));   //right
    pushRect(csRect(r1.xmin,   r1.ymin, r1.xmax, r2.ymin-1)); //top

    return;

  case 10:
    // Two rects (left, right)          [rect in middle, vertically touches top and bottom sides]

    pushRect(csRect(r1.xmin,   r1.ymin, r2.xmin-1, r1.ymax)); //left
    pushRect(csRect(r2.xmax+1, r2.ymin, r1.xmax,   r1.ymax)); //right

    return;

  case 11:
    // One rect (right)                 [rect on left, vertically touches top and bottom sides]

    pushRect(csRect(r2.xmax+1, r1.ymin, r1.xmax,   r1.ymax)); //right

    return;

  case 12:
    // Two rects (left, top)            [rect on bottom, right corner]

    pushRect(csRect(r1.xmin, r1.ymin, r2.xmin-1, r1.ymax));   //left
    pushRect(csRect(r2.xmin, r1.ymin, r1.xmax,   r2.ymin-1)); //top

    return;

  case 13:
    // One rect (top)                   [rect on bottom, horizontally touches left and right sides]

    pushRect(csRect(r1.xmin, r1.ymin, r2.xmax,   r2.ymin-1)); //top

    return;

  case 14:
    // One rect (bot)                   [rect on top, horizontally touches left and right sides]

    pushRect(csRect(r1.xmin, r2.ymax+1, r1.xmax,   r1.ymax)); //bottom

    return;

  case 15:
    // No rects
    // In this case, the rects cancel themselves out.

    return;

  }

}

// The purpose of this function is to take r1 and fragment it around r2,
// removing the area that overlaps.  This function can be used by either
// Include() or Exclude(), since it simply fragments r1.
void csRectRegion::fragmentRect(
  csRect &r1, csRect &r2, bool testedContains, bool testedEdge)
{
  // We may have to fragment r1 into four pieces if r2 is totally inside r1
  if (!testedContains)
  {
    csRect tr1(r1), tr2(r2);

    tr2.Exclude(tr1);

    if (tr2.IsEmpty())
    {
      // It now becomes irritating.  Not only do we have to possibly split it into two
      // rectangles, we may have to split it into as few as one.  Call a separate
      // function to handle this business.

      fragmentContainedRect(r1, r2);
    }

  }

  // We may have to fragment r1 into three pieces if an entire edge of r2 is
  // inside r1.
  if (!testedEdge)
  {

  }

  // If we've gotten here then we should only have to break the rect into 2
  // pieces.
  if (r1.Contains(r2.xmin, r2.ymin))
  {
    // Break r1 into left, top since top left corner of r2 is inside.
    pushRect(csRect(r1.xmin, r2.ymin, r2.xmin-1, r1.ymax));   //left
    pushRect(csRect(r1.xmin, r1.ymin, r1.xmax,   r2.ymin-1)); //top
  }
  else if (r1.Contains(r2.xmin, r2.ymax))
  {
    // Break r1 into left, bot since bot left corner of r2 is inside.
    pushRect(csRect(r1.xmin, r1.ymin,   r2.xmin-1, r2.ymax));  //left
    pushRect(csRect(r1.xmin, r2.ymax+1, r1.xmax,   r1.ymax));  //bot
  }
  else if (r1.Contains(r2.xmax, r2.ymin))
  {
    // Break r1 into right, top since top right corner of r2 is inside.
    pushRect(csRect(r2.xmax+1, r1.ymin, r1.xmax, r1.ymax));    //right
    pushRect(csRect(r1.xmin,   r1.ymin, r2.xmax, r2.ymin-1));  //top
  }
  else
  {
    // Break r1 into right, bot since bot right corner of r2 is inside.
    pushRect(csRect(r2.xmax+1, r1.ymin,   r1.xmax, r1.ymax)); //right
    pushRect(csRect(r1.xmin,   r2.ymax+1, r2.xmax, r1.ymax)); //bot
  }
}

// Chop the intersection of rect1 and rect2 off of rect1 (the smaller rect)
// Tests to make sure the intersection happens on an edge and not a corner.
// Returns false if it is unable to process the chop because of bad
// intersections
bool csRectRegion::chopEdgeIntersection(csRect &rect1, csRect &rect2)
{
  if ((rect1.xmax <= rect2.xmax && rect1.xmin >= rect2.xmin) ||
      (rect1.ymax <= rect2.ymax && rect1.ymin >= rect2.ymin))
  {
    csRect i(rect1);
    i.Intersect(rect2);
    rect1.Subtract(i);
    return true;
  }
  return false;
}

void csRectRegion::Include(csRect &rect)
{
  // If there are no rects in the region, add this and leave.
  if (region_count == 0)
  {
    pushRect(rect);
    return;
  }

  // Otherwise, we have to see if this rect creates a union with any other
  // rectangles.
  int i;
  for(i = 0; i < region_count; i++)
  {
    csRect &r1 = region[i];
    csRect r2(rect);

    // Check to see if these even touch
    if (r2.Intersects(r1)==false)
      continue;

    // If r1 totally contains rect, then we leave.
    r2.Exclude(r1);
    if (r2.IsEmpty())
      return;

    // If rect totally contains r1, then we kill r1 from the list.
    r2.Set(r1);
    r2.Exclude(rect);

    if (r2.IsEmpty())
    {
      // Kill from list
      deleteRect(i);
      // Iterate
      continue;
    }

    // We know that the two rects intersect, but neither of them completely
    // contains each other.  Therefore, we must now see what to chop off of
    // what.  It may be more efficient to chop part off of one or the other.
    // Usually, it's easier to chop up the smaller one.

    bool edgeChopWorked;

    if (!(edgeChopWorked = chopEdgeIntersection(r1, r2)))
      edgeChopWorked = chopEdgeIntersection(r2, r1);

    // If we were able to chop the edge off of one of them, cool.
    if (edgeChopWorked)
      continue;

    // Otherwise we have to do the most irritating part: A full split operation
    // that may create other rects that need to be tested against the database
    // recursively.  For this algorithm, we fragment the one that is already in
    // the database, that way we don't cause more tests: we already know that
    // that rect is good.

    // Kill rect from list
    deleteRect(i);

    // Fragment it
    fragmentRect(r1, r2, true, true);
  } // end for
}

void
csRectRegion::Exclude(csRect &rect)
{

}

<commit_msg>Updated to Exclude to actually do something useful.  This code is still untested, and incomplete since the inverse edge intersection part is still unwritten.  This means that it does not generate correct regions for some cases.<commit_after>/*
    Copyright (C) 2001 by Christopher Nelson

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "cssysdef.h"
#include "csgeom/csrectrg.h"

csRectRegion::csRectRegion() : region(0), region_count(0), region_max(0) {}
csRectRegion::~csRectRegion()
{
  if (region != 0)
    free(region);
}

void csRectRegion::pushRect(csRect const& r)
{
  if (region_count >= region_max)
  {
    region_max += 64;
    int const nbytes = region_max * sizeof(region[0]);
    if (region == 0)
      region = (csRect*)malloc(nbytes);
    else
      region = (csRect*)realloc(region, nbytes);
  }
  region[region_count++] = r;
}

void csRectRegion::deleteRect(int i)
{
  if (region_count > 0 && i >= 0 && i < --region_count)
    memmove(region + i, region + i + 1, region_count - i);
}

//  This operation takes a rect r1 which completely contains rect r2
// and turns it into as many rects as it takes to exclude r2 from the
// area controlled by r1.
void
csRectRegion::fragmentContainedRect(csRect &r1, csRect &r2)
{
  // Edge flags
  const unsigned int LX=1, TY=2, RX=4, BY=8;
  unsigned int edges=0;

  // First check for edging.
  edges |= (r1.xmin == r2.xmin ? LX : 0);
  edges |= (r1.ymin == r2.ymin ? TY : 0);
  edges |= (r1.xmax == r2.xmax ? RX : 0);
  edges |= (r1.ymax == r2.ymax ? BY : 0);

  switch(edges)
  {
  case 0:
    // This is the easy case. Split the r1 into four pieces that exclude r2.
    // The include function pre-checks for this case and exits, so it is
    // properly handled.

    pushRect(csRect(r1.xmin,   r1.ymin,   r2.xmin-1, r1.ymax));   //left
    pushRect(csRect(r2.xmax+1, r1.ymin,   r1.xmax,   r1.ymax));   //right
    pushRect(csRect(r2.xmin,   r1.ymin,   r2.xmax,   r1.ymin-1)); //top
    pushRect(csRect(r2.xmin,   r2.ymax+1, r2.xmax,   r1.ymax));   //bottom

    return;

  case 1:
    // Three rects (top, right, bottom) [rect on left side, middle]

    pushRect(csRect(r1.xmin,   r1.ymin,   r1.xmax,   r2.ymin-1)); //top
    pushRect(csRect(r2.xmax+1, r2.ymin,   r1.xmax,   r2.ymax));   //right
    pushRect(csRect(r1.xmin,   r2.ymax+1, r1.xmax,   r1.ymax));   //bot

    return;

  case 2:
    // Three rects (bot, left, right)   [rect on top side, middle]

    pushRect(csRect(r1.xmin,   r2.ymax+1, r1.xmax,   r1.ymax));   //bot
    pushRect(csRect(r1.xmin,   r1.ymin,   r2.xmin-1, r2.ymax));   //left
    pushRect(csRect(r2.xmax+1, r1.ymin,   r1.xmax,   r2.ymax));   //right

    return;

  case 3:
    // Two rects (right, bottom)        [rect on top left corner]

    pushRect(csRect(r2.xmax+1, r1.ymin, r1.xmax,   r2.ymax)); //right
    pushRect(csRect(r1.xmin, r2.ymax+1, r1.xmax,   r1.ymax)); //bot

    return;

  case 4:
    // Three rects (top, left, bottom)  [rect on right side, middle]

    pushRect(csRect(r1.xmin, r1.ymin,   r1.xmax,   r2.ymin-1)); //top
    pushRect(csRect(r1.xmin, r2.ymin,   r2.xmax-1, r2.ymax));   //left
    pushRect(csRect(r1.xmin, r2.ymax+1, r1.xmax,   r1.ymax));   //bot

    return;

  case 5:
    // Two rects (top, bottom)          [rect in middle, horizontally touches left and right sides]

    pushRect(csRect(r1.xmin, r1.ymin,   r1.xmax,   r2.ymin-1)); //top
    pushRect(csRect(r1.xmin, r2.ymax+1, r1.xmax,   r1.ymax));   //bot

    return;

  case 6:
    // Two rects (left, bottom)         [rect on top, right corner]

    pushRect(csRect(r1.xmin, r1.ymin,   r2.xmin-1, r1.ymax));   //left
    pushRect(csRect(r2.xmin, r2.ymax+1, r1.xmax,   r1.ymax));   //bot

    return;

  case 7:
    // One rect (bottom)                [rect covers entire top]

    pushRect(csRect(r1.xmin, r2.ymax+1, r1.xmax,   r1.ymax));   //bot

    return;

  case 8:
    // Three rects (top, left, right)   [rect on bottom side, middle]

    pushRect(csRect(r1.xmin,   r1.ymin, r1.xmax,   r2.ymin-1)); //top
    pushRect(csRect(r1.xmin,   r2.ymin, r2.xmin-1, r1.ymax));   //left
    pushRect(csRect(r2.xmax+1, r2.ymin, r1.xmax,   r2.ymax));   //right

    return;

  case 9:
    // Two rects (right, top)           [rect on bottom, left corner]

    pushRect(csRect(r2.xmax+1, r2.ymin, r1.xmax, r1.ymax));   //right
    pushRect(csRect(r1.xmin,   r1.ymin, r1.xmax, r2.ymin-1)); //top

    return;

  case 10:
    // Two rects (left, right)          [rect in middle, vertically touches top and bottom sides]

    pushRect(csRect(r1.xmin,   r1.ymin, r2.xmin-1, r1.ymax)); //left
    pushRect(csRect(r2.xmax+1, r2.ymin, r1.xmax,   r1.ymax)); //right

    return;

  case 11:
    // One rect (right)                 [rect on left, vertically touches top and bottom sides]

    pushRect(csRect(r2.xmax+1, r1.ymin, r1.xmax,   r1.ymax)); //right

    return;

  case 12:
    // Two rects (left, top)            [rect on bottom, right corner]

    pushRect(csRect(r1.xmin, r1.ymin, r2.xmin-1, r1.ymax));   //left
    pushRect(csRect(r2.xmin, r1.ymin, r1.xmax,   r2.ymin-1)); //top

    return;

  case 13:
    // One rect (top)                   [rect on bottom, horizontally touches left and right sides]

    pushRect(csRect(r1.xmin, r1.ymin, r2.xmax,   r2.ymin-1)); //top

    return;

  case 14:
    // One rect (bot)                   [rect on top, horizontally touches left and right sides]

    pushRect(csRect(r1.xmin, r2.ymax+1, r1.xmax,   r1.ymax)); //bottom

    return;

  case 15:
    // No rects
    // In this case, the rects cancel themselves out.

    return;

  }

}

// The purpose of this function is to take r1 and fragment it around r2,
// removing the area that overlaps.  This function can be used by either
// Include() or Exclude(), since it simply fragments r1.
void csRectRegion::fragmentRect(
  csRect &r1, csRect &r2, bool testedContains, bool testedEdge)
{
  // We may have to fragment r1 into four pieces if r2 is totally inside r1
  if (!testedContains)
  {
    csRect tr1(r1), tr2(r2);

    tr2.Exclude(tr1);

    if (tr2.IsEmpty())
    {
      // It now becomes irritating.  Not only do we have to possibly split it into two
      // rectangles, we may have to split it into as few as one.  Call a separate
      // function to handle this business.

      fragmentContainedRect(r1, r2);
    }

  }

  // We may have to fragment r1 into three pieces if an entire edge of r2 is
  // inside r1.
  if (!testedEdge)
  {

    //Fix me:  this code needs to be written!!

  }

  // If we've gotten here then we should only have to break the rect into 2
  // pieces.
  if (r1.Contains(r2.xmin, r2.ymin))
  {
    // Break r1 into left, top since top left corner of r2 is inside.
    pushRect(csRect(r1.xmin, r2.ymin, r2.xmin-1, r1.ymax));   //left
    pushRect(csRect(r1.xmin, r1.ymin, r1.xmax,   r2.ymin-1)); //top
  }
  else if (r1.Contains(r2.xmin, r2.ymax))
  {
    // Break r1 into left, bot since bot left corner of r2 is inside.
    pushRect(csRect(r1.xmin, r1.ymin,   r2.xmin-1, r2.ymax));  //left
    pushRect(csRect(r1.xmin, r2.ymax+1, r1.xmax,   r1.ymax));  //bot
  }
  else if (r1.Contains(r2.xmax, r2.ymin))
  {
    // Break r1 into right, top since top right corner of r2 is inside.
    pushRect(csRect(r2.xmax+1, r1.ymin, r1.xmax, r1.ymax));    //right
    pushRect(csRect(r1.xmin,   r1.ymin, r2.xmax, r2.ymin-1));  //top
  }
  else
  {
    // Break r1 into right, bot since bot right corner of r2 is inside.
    pushRect(csRect(r2.xmax+1, r1.ymin,   r1.xmax, r1.ymax)); //right
    pushRect(csRect(r1.xmin,   r2.ymax+1, r2.xmax, r1.ymax)); //bot
  }
}

// Chop the intersection of rect1 and rect2 off of rect1 (the smaller rect)
// Tests to make sure the intersection happens on an edge and not a corner.
// Returns false if it is unable to process the chop because of bad
// intersections
bool csRectRegion::chopEdgeIntersection(csRect &rect1, csRect &rect2)
{
  if ((rect1.xmax <= rect2.xmax && rect1.xmin >= rect2.xmin) ||
      (rect1.ymax <= rect2.ymax && rect1.ymin >= rect2.ymin))
  {
    csRect i(rect1);
    i.Intersect(rect2);
    rect1.Subtract(i);
    return true;
  }
  return false;
}

void csRectRegion::Include(csRect &rect)
{
  // If there are no rects in the region, add this and leave.
  if (region_count == 0)
  {
    pushRect(rect);
    return;
  }

  // Otherwise, we have to see if this rect creates a union with any other
  // rectangles.
  int i;
  for(i = 0; i < region_count; i++)
  {
    csRect &r1 = region[i];
    csRect r2(rect);

    // Check to see if these even touch
    if (r2.Intersects(r1)==false)
      continue;

    // If r1 totally contains rect, then we leave.
    r2.Exclude(r1);
    if (r2.IsEmpty())
      return;

    // If rect totally contains r1, then we kill r1 from the list.
    r2.Set(r1);
    r2.Exclude(rect);

    if (r2.IsEmpty())
    {
      // Kill from list
      deleteRect(i);
      // Iterate
      continue;
    }

    // We know that the two rects intersect, but neither of them completely
    // contains each other.  Therefore, we must now see what to chop off of
    // what.  It may be more efficient to chop part off of one or the other.
    // Usually, it's easier to chop up the smaller one.

    bool edgeChopWorked;

    if (!(edgeChopWorked = chopEdgeIntersection(r1, r2)))
      edgeChopWorked = chopEdgeIntersection(r2, r1);

    // If we were able to chop the edge off of one of them, cool.
    if (edgeChopWorked)
      continue;

    // Otherwise we have to do the most irritating part: A full split operation
    // that may create other rects that need to be tested against the database
    // recursively.  For this algorithm, we fragment the one that is already in
    // the database, that way we don't cause more tests: we already know that
    // that rect is good.

    r2.Set(rect);

    // Kill rect from list
    deleteRect(i);

    // Fragment it
    fragmentRect(r1, r2, true, true);
  } // end for
}

void
csRectRegion::Exclude(csRect &rect)
{
  // If there are no rects in the region, just leave.
  if (region_count == 0)
    return;

  // Otherwise, we have to see if this rect overlaps or touches any other.
  int i;
  for(i = 0; i < region_count; i++)
  {
    csRect &r1 = region[i];
    csRect r2(rect);

    // Check to see if these even touch
    if (r2.Intersects(r1)==false)
      continue;

    // If r1 totally contains rect, then we call the fragment contained rect function.
    r2.Exclude(r1);
    if (r2.IsEmpty())
    {
      csRect rc1(region[i]);
      deleteRect(i);

      fragmentContainedRect(rc1, rect);
      continue;
    }

    // If rect totally contains r1, then we kill r1 from the list.
    r2.Set(r1);
    r2.Exclude(rect);

    if (r2.IsEmpty())
    {
      // Kill from list
      deleteRect(i);
      // Iterate
      continue;
    }

    // This part is similiar to Include, except that we are trying to remove a portion.  Instead
    //  of calling chopEdgeIntersection, we actually have to fragment rect1 and chop off an edge
    //  of the excluding rect.  This code should be handled inside fragment rect.

    r2.Set(rect);

    // Kill rect from list
    deleteRect(i);

    // Fragment it
    fragmentRect(r1, r2, true, false);
  } // end for

}

<|endoftext|>


<commit_before>/*
    Crystal Space input library
    Copyright (C) 2000 by Andrew Zabolotny <bit@eltech.ru>
    Copyright (C) 2002 by Mathew Sutcliffe <oktal@gmx.co.uk>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "cssysdef.h"
#include "iutil/event.h"
#include "csutil/csevent.h"
#include "csutil/inpnames.h"

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

static struct csKeyCodeDef
{
  const char *key;
  int code;
} KeyDefs [] =
{
  { "Esc",	CSKEY_ESC	},
  { "Enter",	CSKEY_ENTER	},
  { "Tab",	CSKEY_TAB	},
  { "Back",	CSKEY_BACKSPACE },
  { "BackSpace",CSKEY_BACKSPACE },
  { "Up",	CSKEY_UP	},
  { "Down",	CSKEY_DOWN	},
  { "Left",	CSKEY_LEFT	},
  { "Right",	CSKEY_RIGHT	},
  { "PgUp",	CSKEY_PGUP	},
  { "PageUp",	CSKEY_PGUP	},
  { "PgDn",	CSKEY_PGDN	},
  { "PageDown",	CSKEY_PGDN	},
  { "Home",	CSKEY_HOME	},
  { "End",	CSKEY_END	},
  { "Ins",	CSKEY_INS	},
  { "Insert",	CSKEY_INS	},
  { "Del",	CSKEY_DEL	},
  { "Delete",	CSKEY_DEL	},
  { "Ctrl",	CSKEY_CTRL	},
  { "Control",	CSKEY_CTRL	},
  { "Alt",	CSKEY_ALT	},
  { "Shift",	CSKEY_SHIFT	},
  { "Center",	CSKEY_CENTER	},
  { "F1",	CSKEY_F1	},
  { "F2",	CSKEY_F2	},
  { "F3",	CSKEY_F3	},
  { "F4",	CSKEY_F4	},
  { "F5",	CSKEY_F5	},
  { "F6",	CSKEY_F6	},
  { "F7",	CSKEY_F7	},
  { "F8",	CSKEY_F8	},
  { "F9",	CSKEY_F9	},
  { "F10",	CSKEY_F10	},
  { "F11",	CSKEY_F11	},
  { "F12",	CSKEY_F12	},
  { "PAD+",	CSKEY_PADPLUS	},
  { "PAD-",	CSKEY_PADMINUS	},
  { "PAD*",	CSKEY_PADMULT	},
  { "PAD/",	CSKEY_PADDIV	},
  { NULL,	0		}
};

static struct csKeyMaskDef
{
  const char *key;
  int mask;
} KeyMasks [] =
{
  { "Ctrl+",	CSMASK_CTRL	},
  { "Alt+",	CSMASK_ALT	},
  { "Shift+",	CSMASK_SHIFT	},
  { NULL,	0		}
};

bool csParseInputDef (const char *name, iEvent* ev, bool use_shift)
{
  int mod = 0;
  bool ismask;
  do
  {
    ismask = false;
    for (csKeyMaskDef *m = KeyMasks; m->key; m++)
      if (! strncasecmp (m->key, name, strlen (m->key)))
      {
        if (use_shift) mod |= m->mask;
        name += strlen (m->key);
        ismask = true;
      }
  } while (ismask);

  if (! strncasecmp (name, "Mouse", 5))
  {
    name += 5;
    if (*name == 'X' || *name == 'x')
      *ev = csEvent (0, csevMouseMove, 1, 0, 0, 0);
    else if (*name == 'Y' || *name == 'y')
      *ev = csEvent (0, csevMouseMove, 0, 1, 0, 0);
    else *ev = csEvent (0, csevMouseDown, 0, 0, atoi (name), mod);
  }
  else if (! strncasecmp (name, "Joystick", 8))
  {
    name += 8;
    if (*name == 'X' || *name == 'x')
      *ev = csEvent (0, csevJoystickMove, 1, 1, 0, 0, 0);
    else if (*name == 'Y' || *name == 'y')
      *ev = csEvent (0, csevJoystickMove, 1, 0, 1, 0, 0);
    else *ev = csEvent (0, csevJoystickDown, 1, 0, 0, atoi (name), mod);
  }
  else
  {
    int code = 0;

    for (csKeyCodeDef *c = KeyDefs; c->key; c++)
      if (! strcasecmp (c->key, name)) code = c->code;

    if	(code)
      *ev = csEvent (0, csevKeyDown, code, 0, mod);
    else if (strlen (name) != 1)
      return false;
    else
      *ev = csEvent (0, csevKeyDown, 0, (int)*name, mod);
  }
  return true;
}

bool csParseInputDef (const char* name, csEvent& ev, bool use_shift)
{
  return csParseInputDef (name, &ev, use_shift);
}

bool csParseKeyDef (const char *name, int &key, int &shift, bool use_shift)
{
  csEvent ev;
  bool ret = csParseInputDef (name, ev, use_shift);
  if (ret)
  {
    if (ev.Key.Code >= CSKEY_FIRST && ev.Key.Code <= CSKEY_LAST)
      key = ev.Key.Char;
    else if (ev.Key.Char < 256 && ev.Key.Char > 0)
      key = ev.Key.Char;
    else return false;
    shift = ev.Key.Modifiers;
  }
  return ret;
}

bool csParseMouseDef (const char *name, int &button, int &shift, bool use_shift)
{
  csEvent ev;
  bool ret = csParseInputDef (name, ev, use_shift);
  if (ret)
  {
    if (ev.Type == csevMouseMove)
      button = ev.Mouse.x > ev.Mouse.y ? CSAXIS_X : CSAXIS_Y;
    else button = ev.Mouse.Button;
    shift = ev.Mouse.Modifiers;
  }
  return ret;
}

bool csParseJoyDef (const char *name, int &button, int &shift, bool use_shift)
{
  csEvent ev;
  bool ret = csParseInputDef (name, ev, use_shift);
  if (ret)
  {
    if (ev.Type == csevJoystickMove)
      button = ev.Joystick.x > ev.Joystick.y ? CSAXIS_X : CSAXIS_Y;
    else button = ev.Joystick.Button;
    shift = ev.Joystick.Modifiers;
  }
  return ret;
}

bool csGetInputDesc (iEvent *ev, char *buf, bool use_shift)
{
  if (use_shift)
  {
    int mod = 0;
    switch (ev->Type)
    {
      case csevKeyUp:
      case csevKeyDown:
        mod = ev->Key.Modifiers;
        break;

      case csevMouseUp:
      case csevMouseDown:
        mod = ev->Mouse.Modifiers;
        break;

      case csevJoystickUp:
      case csevJoystickDown:
        mod = ev->Joystick.Modifiers;
        break;

      default:
        break;
    }
    for (csKeyMaskDef *mask = KeyMasks; mask->key; mask++)
    {
      if (mod & mask->mask)
      {
        strcpy (buf, mask->key);
        buf = strchr (buf, 0);
      }
    }
  }

  const char *key = NULL;
  switch (ev->Type)
  {
    case csevKeyUp:
    case csevKeyDown:
    {
      for (csKeyCodeDef *k = KeyDefs; k->key; k++)
        if (k->code == ev->Key.Code) key = k->key;
      if (key)
      {
        strcpy (buf, key);
        return true;
      }
      else if (ev->Key.Char < 256 && ev->Key.Char > 0)
      {
        *buf = (char)ev->Key.Char;
        *++buf = 0;
        return true;
      }
    }  break;

    case csevMouseUp:
    case csevMouseDown:
      strcpy (buf, "Mouse");
      sprintf (strchr (buf, 0), "%i", ev->Mouse.Button);
      return true;

    case csevJoystickUp:
    case csevJoystickDown:
      strcpy (buf, "Joystick");
      sprintf (strchr (buf, 0), "%i", ev->Joystick.Button);
      return true;

    case csevMouseMove:
      strcpy (buf, "Mouse");
      buf = strchr (buf, 0);
      if (ev->Mouse.x > ev->Mouse.y) *buf++ = 'X';
      else if (ev->Mouse.x < ev->Mouse.y) *buf++ = 'Y';
      *buf = 0;
      return true;

    case csevJoystickMove:
      strcpy (buf, "Joystick");
      buf = strchr (buf, 0);
      if (ev->Joystick.x > ev->Joystick.y) *buf++ = 'X';
      else if (ev->Joystick.x < ev->Joystick.y) *buf++ = 'Y';
      *buf = 0;
      return true;

    default:
      break;
  }
  return false;
}

bool csGetInputDesc (csEvent &ev, char *buf, bool use_shift)
{
  return csGetInputDesc (&ev, buf, use_shift);
}

bool csGetKeyDesc (int key, int shift, char *buf, bool use_shift)
{
  csEvent ev (0, csevKeyDown,
    key >= CSKEY_FIRST && key <= CSKEY_LAST ? key : 0,
    key < 256 && key > 0 ? 0 : key,
    shift);
  return csGetInputDesc (ev, buf, use_shift);
}

bool csGetMouseDesc (int button, int shift, char *buf, bool use_shift)
{
  csEvent ev (0,
    button == CSAXIS_X || button == CSAXIS_Y ? csevMouseMove : csevMouseDown,
    button == CSAXIS_X ? 1 : 0,
    button == CSAXIS_Y ? 1 : 0,
    button, shift);
  return csGetInputDesc (ev, buf, use_shift);
}

bool csGetJoyDesc (int button, int shift, char *buf, bool use_shift)
{
  csEvent ev (0,
    button == CSAXIS_X || button == CSAXIS_Y ? csevJoystickMove : csevJoystickDown,
    button == CSAXIS_X ? 1 : 0,
    button == CSAXIS_Y ? 1 : 0,
    button, shift);
  return csGetInputDesc (ev, buf, use_shift);
}

<commit_msg>fixed a small bug in the key definition parser<commit_after>/*
    Crystal Space input library
    Copyright (C) 2000 by Andrew Zabolotny <bit@eltech.ru>
    Copyright (C) 2002 by Mathew Sutcliffe <oktal@gmx.co.uk>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "cssysdef.h"
#include "iutil/event.h"
#include "csutil/csevent.h"
#include "csutil/inpnames.h"

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

static struct csKeyCodeDef
{
  const char *key;
  int code;
} KeyDefs [] =
{
  { "Esc",	CSKEY_ESC	},
  { "Enter",	CSKEY_ENTER	},
  { "Tab",	CSKEY_TAB	},
  { "Back",	CSKEY_BACKSPACE },
  { "BackSpace",CSKEY_BACKSPACE },
  { "Up",	CSKEY_UP	},
  { "Down",	CSKEY_DOWN	},
  { "Left",	CSKEY_LEFT	},
  { "Right",	CSKEY_RIGHT	},
  { "PgUp",	CSKEY_PGUP	},
  { "PageUp",	CSKEY_PGUP	},
  { "PgDn",	CSKEY_PGDN	},
  { "PageDown",	CSKEY_PGDN	},
  { "Home",	CSKEY_HOME	},
  { "End",	CSKEY_END	},
  { "Ins",	CSKEY_INS	},
  { "Insert",	CSKEY_INS	},
  { "Del",	CSKEY_DEL	},
  { "Delete",	CSKEY_DEL	},
  { "Ctrl",	CSKEY_CTRL	},
  { "Control",	CSKEY_CTRL	},
  { "Alt",	CSKEY_ALT	},
  { "Shift",	CSKEY_SHIFT	},
  { "Center",	CSKEY_CENTER	},
  { "F1",	CSKEY_F1	},
  { "F2",	CSKEY_F2	},
  { "F3",	CSKEY_F3	},
  { "F4",	CSKEY_F4	},
  { "F5",	CSKEY_F5	},
  { "F6",	CSKEY_F6	},
  { "F7",	CSKEY_F7	},
  { "F8",	CSKEY_F8	},
  { "F9",	CSKEY_F9	},
  { "F10",	CSKEY_F10	},
  { "F11",	CSKEY_F11	},
  { "F12",	CSKEY_F12	},
  { "PAD+",	CSKEY_PADPLUS	},
  { "PAD-",	CSKEY_PADMINUS	},
  { "PAD*",	CSKEY_PADMULT	},
  { "PAD/",	CSKEY_PADDIV	},
  { NULL,	0		}
};

static struct csKeyMaskDef
{
  const char *key;
  int mask;
} KeyMasks [] =
{
  { "Ctrl+",	CSMASK_CTRL	},
  { "Alt+",	CSMASK_ALT	},
  { "Shift+",	CSMASK_SHIFT	},
  { NULL,	0		}
};

bool csParseInputDef (const char *name, iEvent* ev, bool use_shift)
{
  int mod = 0;
  bool ismask;
  do
  {
    ismask = false;
    for (csKeyMaskDef *m = KeyMasks; m->key; m++)
      if (! strncasecmp (m->key, name, strlen (m->key)))
      {
        if (use_shift) mod |= m->mask;
        name += strlen (m->key);
        ismask = true;
      }
  } while (ismask);

  if (! strncasecmp (name, "Mouse", 5))
  {
    name += 5;
    if (*name == 'X' || *name == 'x')
      *ev = csEvent (0, csevMouseMove, 1, 0, 0, 0);
    else if (*name == 'Y' || *name == 'y')
      *ev = csEvent (0, csevMouseMove, 0, 1, 0, 0);
    else *ev = csEvent (0, csevMouseDown, 0, 0, atoi (name), mod);
  }
  else if (! strncasecmp (name, "Joystick", 8))
  {
    name += 8;
    if (*name == 'X' || *name == 'x')
      *ev = csEvent (0, csevJoystickMove, 1, 1, 0, 0, 0);
    else if (*name == 'Y' || *name == 'y')
      *ev = csEvent (0, csevJoystickMove, 1, 0, 1, 0, 0);
    else *ev = csEvent (0, csevJoystickDown, 1, 0, 0, atoi (name), mod);
  }
  else
  {
    int code = 0;

    for (csKeyCodeDef *c = KeyDefs; c->key; c++)
      if (! strcasecmp (c->key, name)) code = c->code;

    if	(code)
      *ev = csEvent (0, csevKeyDown, code, 0, mod);
    else if (strlen (name) != 1)
      return false;
    else
      *ev = csEvent (0, csevKeyDown, 0, (int)*name, mod);
  }
  return true;
}

bool csParseInputDef (const char* name, csEvent& ev, bool use_shift)
{
  return csParseInputDef (name, &ev, use_shift);
}

bool csParseKeyDef (const char *name, int &key, int &shift, bool use_shift)
{
  csEvent ev;
  bool ret = csParseInputDef (name, ev, use_shift);
  if (ret)
  {
    if (ev.Key.Code >= CSKEY_FIRST && ev.Key.Code <= CSKEY_LAST)
      key = ev.Key.Code;
    else if (ev.Key.Char < 256 && ev.Key.Char > 0)
      key = ev.Key.Char;
    else return false;
    shift = ev.Key.Modifiers;
  }
  return ret;
}

bool csParseMouseDef (const char *name, int &button, int &shift, bool use_shift)
{
  csEvent ev;
  bool ret = csParseInputDef (name, ev, use_shift);
  if (ret)
  {
    if (ev.Type == csevMouseMove)
      button = ev.Mouse.x > ev.Mouse.y ? CSAXIS_X : CSAXIS_Y;
    else button = ev.Mouse.Button;
    shift = ev.Mouse.Modifiers;
  }
  return ret;
}

bool csParseJoyDef (const char *name, int &button, int &shift, bool use_shift)
{
  csEvent ev;
  bool ret = csParseInputDef (name, ev, use_shift);
  if (ret)
  {
    if (ev.Type == csevJoystickMove)
      button = ev.Joystick.x > ev.Joystick.y ? CSAXIS_X : CSAXIS_Y;
    else button = ev.Joystick.Button;
    shift = ev.Joystick.Modifiers;
  }
  return ret;
}

bool csGetInputDesc (iEvent *ev, char *buf, bool use_shift)
{
  if (use_shift)
  {
    int mod = 0;
    switch (ev->Type)
    {
      case csevKeyUp:
      case csevKeyDown:
        mod = ev->Key.Modifiers;
        break;

      case csevMouseUp:
      case csevMouseDown:
        mod = ev->Mouse.Modifiers;
        break;

      case csevJoystickUp:
      case csevJoystickDown:
        mod = ev->Joystick.Modifiers;
        break;

      default:
        break;
    }
    for (csKeyMaskDef *mask = KeyMasks; mask->key; mask++)
    {
      if (mod & mask->mask)
      {
        strcpy (buf, mask->key);
        buf = strchr (buf, 0);
      }
    }
  }

  const char *key = NULL;
  switch (ev->Type)
  {
    case csevKeyUp:
    case csevKeyDown:
    {
      for (csKeyCodeDef *k = KeyDefs; k->key; k++)
        if (k->code == ev->Key.Code) key = k->key;
      if (key)
      {
        strcpy (buf, key);
        return true;
      }
      else if (ev->Key.Char < 256 && ev->Key.Char > 0)
      {
        *buf = (char)ev->Key.Char;
        *++buf = 0;
        return true;
      }
    }  break;

    case csevMouseUp:
    case csevMouseDown:
      strcpy (buf, "Mouse");
      sprintf (strchr (buf, 0), "%i", ev->Mouse.Button);
      return true;

    case csevJoystickUp:
    case csevJoystickDown:
      strcpy (buf, "Joystick");
      sprintf (strchr (buf, 0), "%i", ev->Joystick.Button);
      return true;

    case csevMouseMove:
      strcpy (buf, "Mouse");
      buf = strchr (buf, 0);
      if (ev->Mouse.x > ev->Mouse.y) *buf++ = 'X';
      else if (ev->Mouse.x < ev->Mouse.y) *buf++ = 'Y';
      *buf = 0;
      return true;

    case csevJoystickMove:
      strcpy (buf, "Joystick");
      buf = strchr (buf, 0);
      if (ev->Joystick.x > ev->Joystick.y) *buf++ = 'X';
      else if (ev->Joystick.x < ev->Joystick.y) *buf++ = 'Y';
      *buf = 0;
      return true;

    default:
      break;
  }
  return false;
}

bool csGetInputDesc (csEvent &ev, char *buf, bool use_shift)
{
  return csGetInputDesc (&ev, buf, use_shift);
}

bool csGetKeyDesc (int key, int shift, char *buf, bool use_shift)
{
  csEvent ev (0, csevKeyDown,
    key >= CSKEY_FIRST && key <= CSKEY_LAST ? key : 0,
    key < 256 && key > 0 ? 0 : key,
    shift);
  return csGetInputDesc (ev, buf, use_shift);
}

bool csGetMouseDesc (int button, int shift, char *buf, bool use_shift)
{
  csEvent ev (0,
    button == CSAXIS_X || button == CSAXIS_Y ? csevMouseMove : csevMouseDown,
    button == CSAXIS_X ? 1 : 0,
    button == CSAXIS_Y ? 1 : 0,
    button, shift);
  return csGetInputDesc (ev, buf, use_shift);
}

bool csGetJoyDesc (int button, int shift, char *buf, bool use_shift)
{
  csEvent ev (0,
    button == CSAXIS_X || button == CSAXIS_Y ? csevJoystickMove : csevJoystickDown,
    button == CSAXIS_X ? 1 : 0,
    button == CSAXIS_Y ? 1 : 0,
    button, shift);
  return csGetInputDesc (ev, buf, use_shift);
}

<|endoftext|>


<commit_before>#include <plasp/pddl/expressions/PrimitiveType.h>

#include <algorithm>

#include <boost/assert.hpp>

#include <plasp/pddl/Context.h>
#include <plasp/pddl/Domain.h>
#include <plasp/pddl/ExpressionContext.h>
#include <plasp/pddl/ExpressionVisitor.h>

namespace plasp
{
namespace pddl
{
namespace expressions
{

////////////////////////////////////////////////////////////////////////////////////////////////////
//
// PrimitiveType
//
////////////////////////////////////////////////////////////////////////////////////////////////////

PrimitiveType::PrimitiveType()
:	m_isDirty{true}
{
}

////////////////////////////////////////////////////////////////////////////////////////////////////

PrimitiveType::PrimitiveType(std::string name)
:	m_isDirty{true},
	m_name{name}
{
	BOOST_ASSERT(!m_name.empty());
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void PrimitiveType::parseDeclaration(Context &context, Domain &domain)
{
	auto &types = domain.types();

	context.parser.skipWhiteSpace();

	const auto typeName = context.parser.parseIdentifier(isIdentifier);

	const auto match = std::find_if(types.cbegin(), types.cend(),
		[&](const auto &primitiveType)
		{
			return primitiveType->name() == typeName;
		});

	// Return existing primitive type
	if (match != types.cend())
	{
		auto *type = match->get();

		type->setDirty();

		return;
	}

	types.emplace_back(std::make_unique<PrimitiveType>(typeName));
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void PrimitiveType::parseTypedDeclaration(Context &context, Domain &domain)
{
	auto &types = domain.types();

	// Parse and store type
	parseDeclaration(context, domain);

	context.parser.skipWhiteSpace();

	// Check for type inheritance
	if (!context.parser.probe('-'))
		return;

	domain.checkRequirement(Requirement::Type::Typing);

	// If existing, parse and store parent type
	auto *parentType = parseAndFind(context, domain);

	parentType->setDirty(false);

	// Assign parent type to all types that were previously flagged
	std::for_each(types.begin(), types.end(),
		[&](auto &childType)
		{
			if (!childType->isDirty())
				return;

			childType->m_parentTypes.push_back(parentType);
			childType->setDirty(false);
		});
}

////////////////////////////////////////////////////////////////////////////////////////////////////

PrimitiveType *PrimitiveType::parseAndFind(Context &context, Domain &domain)
{
	auto &types = domain.types();

	context.parser.skipWhiteSpace();

	const auto typeName = context.parser.parseIdentifier(isIdentifier);

	BOOST_ASSERT(!typeName.empty());

	const auto match = std::find_if(types.cbegin(), types.cend(),
		[&](const auto &primitiveType)
		{
			return primitiveType->name() == typeName;
		});

	if (match == types.cend())
	{
		// Only "object" is allowed as an implicit type
		if (typeName == "object")
			types.emplace_back(std::make_unique<expressions::PrimitiveType>(typeName));
		else
			throw utils::ParserException(context.parser, "Type \"" + typeName + "\" used but never declared");

		return types.back().get();
	}

	auto *type = match->get();
	type->setDirty();

	return type;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void PrimitiveType::accept(plasp::pddl::ExpressionVisitor &expressionVisitor) const
{
	expressionVisitor.visit(*this);
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void PrimitiveType::setDirty(bool isDirty)
{
	m_isDirty = isDirty;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

bool PrimitiveType::isDirty() const
{
	return m_isDirty;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

const std::string &PrimitiveType::name() const
{
	return m_name;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

const std::vector<const PrimitiveType *> &PrimitiveType::parentTypes() const
{
	return m_parentTypes;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

}
}
}
<commit_msg>Checking that type declarations are not missing.<commit_after>#include <plasp/pddl/expressions/PrimitiveType.h>

#include <algorithm>

#include <boost/assert.hpp>

#include <plasp/pddl/Context.h>
#include <plasp/pddl/Domain.h>
#include <plasp/pddl/ExpressionContext.h>
#include <plasp/pddl/ExpressionVisitor.h>

namespace plasp
{
namespace pddl
{
namespace expressions
{

////////////////////////////////////////////////////////////////////////////////////////////////////
//
// PrimitiveType
//
////////////////////////////////////////////////////////////////////////////////////////////////////

PrimitiveType::PrimitiveType()
:	m_isDirty{true}
{
}

////////////////////////////////////////////////////////////////////////////////////////////////////

PrimitiveType::PrimitiveType(std::string name)
:	m_isDirty{true},
	m_name{name}
{
	BOOST_ASSERT(!m_name.empty());
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void PrimitiveType::parseDeclaration(Context &context, Domain &domain)
{
	auto &types = domain.types();

	context.parser.skipWhiteSpace();

	const auto typeName = context.parser.parseIdentifier(isIdentifier);

	const auto match = std::find_if(types.cbegin(), types.cend(),
		[&](const auto &primitiveType)
		{
			return primitiveType->name() == typeName;
		});

	// Return existing primitive type
	if (match != types.cend())
	{
		auto *type = match->get();

		type->setDirty();

		return;
	}

	types.emplace_back(std::make_unique<PrimitiveType>(typeName));
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void PrimitiveType::parseTypedDeclaration(Context &context, Domain &domain)
{
	auto &types = domain.types();

	// Parse and store type
	parseDeclaration(context, domain);

	context.parser.skipWhiteSpace();

	// Check for type inheritance
	if (!context.parser.probe('-'))
		return;

	domain.checkRequirement(Requirement::Type::Typing);

	// If existing, parse and store parent type
	auto *parentType = parseAndFind(context, domain);

	parentType->setDirty(false);

	// Assign parent type to all types that were previously flagged
	std::for_each(types.begin(), types.end(),
		[&](auto &childType)
		{
			if (!childType->isDirty())
				return;

			childType->m_parentTypes.push_back(parentType);
			childType->setDirty(false);
		});
}

////////////////////////////////////////////////////////////////////////////////////////////////////

PrimitiveType *PrimitiveType::parseAndFind(Context &context, Domain &domain)
{
	auto &types = domain.types();

	context.parser.skipWhiteSpace();

	const auto typeName = context.parser.parseIdentifier(isIdentifier);

	if (typeName.empty())
		throw utils::ParserException(context.parser, "No type supplied");

	const auto match = std::find_if(types.cbegin(), types.cend(),
		[&](const auto &primitiveType)
		{
			return primitiveType->name() == typeName;
		});

	if (match == types.cend())
	{
		// Only "object" is allowed as an implicit type
		if (typeName == "object")
			types.emplace_back(std::make_unique<expressions::PrimitiveType>(typeName));
		else
			throw utils::ParserException(context.parser, "Type \"" + typeName + "\" used but never declared");

		return types.back().get();
	}

	auto *type = match->get();
	type->setDirty();

	return type;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void PrimitiveType::accept(plasp::pddl::ExpressionVisitor &expressionVisitor) const
{
	expressionVisitor.visit(*this);
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void PrimitiveType::setDirty(bool isDirty)
{
	m_isDirty = isDirty;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

bool PrimitiveType::isDirty() const
{
	return m_isDirty;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

const std::string &PrimitiveType::name() const
{
	return m_name;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

const std::vector<const PrimitiveType *> &PrimitiveType::parentTypes() const
{
	return m_parentTypes;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

}
}
}
<|endoftext|>