<commit_before>#include "config.h"
#include "release.h"
#include "vm.hpp"
#include "call_frame.hpp"
#include "environment.hpp"
#include "signal.hpp"
#include "configuration.hpp"

#include "builtin/module.hpp"
#include "builtin/array.hpp"

#include "builtin/array.hpp"
#include "builtin/class.hpp"
#include "builtin/constant_scope.hpp"
#include "builtin/jit.hpp"
#include "builtin/module.hpp"
#include "builtin/module.hpp"
#include "builtin/native_method.hpp"
#include "builtin/string.hpp"
#include "builtin/thread.hpp"

#include <string>
#include <iostream>
#include <fcntl.h>

#include "util/logger.hpp"

#include "dtrace/dtrace.h"

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>

#ifdef USE_EXECINFO
#include <execinfo.h>
#endif

#ifdef RBX_WINDOWS
#include "windows_compat.h"
#else
#include <dlfcn.h>
#include <sys/utsname.h>
#include <sys/select.h>
#endif

namespace rubinius {
  using namespace utilities;

  static SignalThread* signal_thread_ = 0;

  // Used by the segfault reporter. Calculated up front to avoid
  // crashing inside the crash handler.
  static struct utsname machine_info;

  SignalThread::SignalThread(STATE, Configuration& config)
    : InternalThread(state, "rbx.signal")
    , shared_(state->shared())
    , target_(state->vm())
    , queued_signals_(0)
  {
    signal_thread_ = this;
    shared_.set_signal_handler(this);

    setup_default_handlers();
  }

  void SignalThread::initialize(STATE) {
    InternalThread::initialize(state);

    for(int i = 0; i < NSIG; i++) {
      pending_signals_[i] = 0;
    }

    worker_lock_.init();
    worker_cond_.init();
  }

  void SignalThread::wakeup(STATE) {
    InternalThread::wakeup(state);

    worker_cond_.signal();
  }

  void SignalThread::stop(STATE) {
    for(std::list<int>::iterator i = watched_signals_.begin();
        i != watched_signals_.end();
        ++i) {
      signal(*i, SIG_DFL);
    }

    InternalThread::stop(state);
  }

  void SignalThread::print_machine_info(PrintFunction function) {
    function("sysname: %s", machine_info.sysname);
    function("nodename: %s", machine_info.nodename);
    function("release: %s", machine_info.release);
    function("version: %s", machine_info.version);
    function("machine: %s", machine_info.machine);
  }

  void SignalThread::print_process_info(PrintFunction function) {
    function("user: %s", signal_thread_->shared().username.c_str());
    function("pid: %s", signal_thread_->shared().pid.c_str());
    function("program name: %s", RBX_PROGRAM_NAME);
    function("version: %s", RBX_VERSION);
    function("ruby version: %s", RBX_RUBY_VERSION);
    function("release date: %s", RBX_RELEASE_DATE);
    function("build revision: %s", RBX_BUILD_REV);
    function("llvm version: %s", RBX_LLVM_VERSION);
    function("jit status: %s",
        CBOOL(signal_thread_->shared().env()->state->globals().jit.get()->enabled())
        ? "enabled" : "disabled");
  }

  void SignalThread::run(STATE) {
#ifndef RBX_WINDOWS
    sigset_t set;
    sigfillset(&set);
    pthread_sigmask(SIG_BLOCK, &set, NULL);
#endif

    GCTokenImpl gct;

    metrics().init(metrics::eRubyMetrics);

    while(!thread_exit_) {
      {
        utilities::thread::Mutex::LockGuard lg(worker_lock_);
        if(thread_exit_) break;
        state->gc_independent(gct, 0);
        worker_cond_.wait(worker_lock_);
        // If we should exit now, don't try to become
        // dependent first but break and exit the thread
        if(thread_exit_) break;
      }
      state->gc_dependent(gct, 0);
      {
        utilities::thread::Mutex::LockGuard lg(worker_lock_);
        if(thread_exit_) break;
      }

      target_->wakeup(state, gct, 0);
    }
  }

  void SignalThread::signal_handler(int sig) {
    signal_thread_->handle_signal(sig);
  }

  void SignalThread::handle_signal(int sig) {
    if(thread_exit_) return;

    target_->metrics().system_metrics.os_signals_received++;

    queued_signals_ = 1;
    pending_signals_[sig] = 1;

    target_->set_check_local_interrupts();

    if(target_->should_interrupt_with_signal()) {
      if(!pthread_equal(pthread_self(), target_->os_thread())) {
#ifdef RBX_WINDOWS
        // TODO: Windows
#else
        pthread_kill(target_->os_thread(), SIGVTALRM);
#endif
      }
    }

    worker_cond_.signal();
  }

  void SignalThread::add_signal(STATE, int sig, HandlerType type) {
    SYNC(state);
    utilities::thread::Mutex::LockGuard lg(worker_lock_);

#ifndef RBX_WINDOWS
    struct sigaction action;

    if(type == eDefault) {
      action.sa_handler = SIG_DFL;
      watched_signals_.remove(sig);
    } else if(type == eIgnore) {
      action.sa_handler = SIG_IGN;
      watched_signals_.push_back(sig);
    } else {
      action.sa_handler = signal_handler;
      watched_signals_.push_back(sig);
    }

    action.sa_flags = 0;
    sigfillset(&action.sa_mask);

    sigaction(sig, &action, NULL);
#endif
  }

  bool SignalThread::deliver_signals(STATE, CallFrame* call_frame) {
    queued_signals_ = 0;

    for(int i = 0; i < NSIG; i++) {
      if(pending_signals_[i] > 0) {
        pending_signals_[i] = 0;

        target_->metrics().system_metrics.os_signals_processed++;

        Array* args = Array::create(state, 1);
        args->set(state, 0, Fixnum::from(i));

        // Check whether the send raised an exception and
        // stop running the handlers if that happens
        if(!G(rubinius)->send(state, call_frame,
               state->symbol("received_signal"), args, cNil)) {
          if(state->thread_state()->raise_reason() == cException ||
             state->thread_state()->raise_reason() == cExit) {
            return false;
          }
        }
      }
    }

    return true;
  }

  void SignalThread::print_backtraces() {
    STATE = shared_.env()->state;
    ThreadList* threads = shared_.threads();

    for(ThreadList::iterator i = threads->begin(); i != threads->end(); ++i) {
      VM* vm = (*i)->as_vm();
      if(!vm) continue;

      if(vm->saved_call_frame()) {
        utilities::logger::fatal("--- Thread %d backtrace ---", vm->thread_id());
      }

      for(CallFrame* frame = vm->saved_call_frame(); frame; frame = frame->previous) {
        std::ostringstream stream;

        if(NativeMethodFrame* nmf = frame->native_method_frame()) {
          stream << static_cast<void*>(frame) << ": ";
          NativeMethod* nm = try_as<NativeMethod>(nmf->get_object(nmf->method()));
          if(nm && nm->name()->symbol_p()) {
            stream << "capi:" << nm->name()->debug_str(state) << " at ";
            stream << nm->file()->c_str(state);
          } else {
            stream << "unknown capi";
          }
        } else if(frame->compiled_code) {
          if(frame->is_block_p(state)) {
            stream << "__block__";
          } else {
            if(SingletonClass* sc = try_as<SingletonClass>(frame->module())) {
              Object* obj = sc->singleton();

              if(Module* mod = try_as<Module>(obj)) {
                stream << mod->debug_str(state) << ".";
              } else {
                if(obj == G(main)) {
                  stream << "MAIN.";
                } else {
                  stream << "#<" << obj->class_object(state)->debug_str(state) <<
                            ":" << (void*)obj->id(state)->to_native() << ">.";
                }
              }
            } else if(IncludedModule* im = try_as<IncludedModule>(frame->module())) {
              stream <<  im->module()->debug_str(state) << "#";
            } else {
              Symbol* name;
              std::string mod_name;

              if(frame->module()->nil_p()) {
                mod_name = frame->constant_scope()->module()->debug_str(state);
              } else {
                if((name = try_as<Symbol>(frame->module()->module_name()))) {
                  mod_name = name->debug_str(state);
                } else if((name = try_as<Symbol>(
                          frame->constant_scope()->module()->module_name()))) {
                  mod_name = name->debug_str(state);
                } else {
                  mod_name = "<anonymous module>";
                }
              }
              stream << mod_name << "#";
            }

            Symbol* name = try_as<Symbol>(frame->name());
            if(name) {
              stream << name->debug_str(state);
            } else {
              stream << frame->compiled_code->name()->debug_str(state);
            }
          }

          stream << " in ";
          if(Symbol* file_sym = try_as<Symbol>(frame->compiled_code->file())) {
            stream << file_sym->debug_str(state) << ":" << frame->line(state);
          } else {
            stream << "<unknown>";
          }

          stream << " (+" << frame->ip();
          if(frame->is_inline_frame()) {
            stream << " inline";
          } else if(frame->jitted_p()) {
            stream << " jit";
          }
          stream << ")";
        }

        utilities::logger::fatal(stream.str().c_str());
      }
    }
  }

  static void null_func(int sig) {}

#ifdef USE_EXECINFO
  static const char* rbx_signal_string(int sig) {
    switch(sig) {
    case SIGSEGV:
      return "SIGSEGV";
    case SIGBUS:
      return "SIGBUS";
    case SIGILL:
      return "SIGILL";
    case SIGABRT:
      return "SIGABRT";
    case SIGFPE:
      return "SIGFPE";
    default:
      return "UNKNOWN";
    }
  }

  static void abandon_ship_handler(int sig) {
    struct sigaction action;

    // Unset our handler for this signal.
    action.sa_handler = SIG_DFL;
    action.sa_flags = 0;
    sigaction(sig, &action, NULL);

    char* pause_env = getenv("RBX_PAUSE_ON_CRASH");

    if(pause_env) {
      long timeout = strtol(pause_env, NULL, 10);
      if(timeout <= 0) {
        timeout = 60;
      } else {
        timeout *= 60;
      }
      std::cerr << "\n========== CRASH (" << getpid();
      std::cerr << "), pausing for " << timeout << " seconds to attach debugger\n";
      sleep(timeout);
    }

    signal_thread_->shared().env()->atexit();

#define RBX_ABORT_CALLSTACK_SIZE    128
    void* callstack[RBX_ABORT_CALLSTACK_SIZE];
    int i, frames = backtrace(callstack, RBX_ABORT_CALLSTACK_SIZE);
    char** symbols = backtrace_symbols(callstack, frames);

    logger::fatal("The Rubinius process is aborting with signal: %s",
                  rbx_signal_string(sig));
    logger::fatal("--- begin system info ---");
    signal_thread_->print_machine_info(logger::fatal);
    logger::fatal("--- end system info ---");

    logger::fatal("--- begin rubinius info ---");
    signal_thread_->print_process_info(logger::fatal);
    logger::fatal("--- end rubinius info ---");

    logger::fatal("--- begin system backtrace ---");
    for(i = 0; i < frames; i++) {
      logger::fatal("%s", symbols[i]);
    }
    logger::fatal("--- end system backtrace ---");

    logger::fatal("--- begin Ruby backtraces ---");
    signal_thread_->print_backtraces();
    logger::fatal("--- end Ruby backtraces ---");

    raise(sig);
  }
#endif

  void SignalThread::setup_default_handlers() {
#ifndef RBX_WINDOWS
    // Get the machine info.
    uname(&machine_info);

    struct sigaction action;
    action.sa_handler = null_func;
    action.sa_flags = 0;
    sigfillset(&action.sa_mask);
    sigaction(SIGVTALRM, &action, NULL);

    // Some extensions expect SIGALRM to be defined, because MRI does.
    // We'll just use a noop for it.
    action.sa_handler = null_func;
    sigaction(SIGALRM, &action, NULL);

    // Ignore sigpipe.
    action.sa_handler = SIG_IGN;
    sigaction(SIGPIPE, &action, NULL);

#ifdef USE_EXECINFO
    // If we have execinfo, setup some crash handlers
    if(!getenv("DISABLE_SEGV")) {
      action.sa_handler = abandon_ship_handler;
      sigaction(SIGSEGV, &action, NULL);
      sigaction(SIGBUS,  &action, NULL);
      sigaction(SIGILL,  &action, NULL);
      sigaction(SIGFPE,  &action, NULL);
      sigaction(SIGABRT, &action, NULL);
    }
#endif  // USE_EXEC_INFO
#else
    signal(SIGTERM, quit_handler);
#endif  // ifndef RBX_WINDOWS
  }
}
<commit_msg>Add guard around reference to RBX_LLVM_VERSION. Patch by @ff2000.<commit_after>#include "config.h"
#include "release.h"
#include "vm.hpp"
#include "call_frame.hpp"
#include "environment.hpp"
#include "signal.hpp"
#include "configuration.hpp"

#include "builtin/module.hpp"
#include "builtin/array.hpp"

#include "builtin/array.hpp"
#include "builtin/class.hpp"
#include "builtin/constant_scope.hpp"
#include "builtin/jit.hpp"
#include "builtin/module.hpp"
#include "builtin/module.hpp"
#include "builtin/native_method.hpp"
#include "builtin/string.hpp"
#include "builtin/thread.hpp"

#include <string>
#include <iostream>
#include <fcntl.h>

#include "util/logger.hpp"

#include "dtrace/dtrace.h"

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>

#ifdef USE_EXECINFO
#include <execinfo.h>
#endif

#ifdef RBX_WINDOWS
#include "windows_compat.h"
#else
#include <dlfcn.h>
#include <sys/utsname.h>
#include <sys/select.h>
#endif

namespace rubinius {
  using namespace utilities;

  static SignalThread* signal_thread_ = 0;

  // Used by the segfault reporter. Calculated up front to avoid
  // crashing inside the crash handler.
  static struct utsname machine_info;

  SignalThread::SignalThread(STATE, Configuration& config)
    : InternalThread(state, "rbx.signal")
    , shared_(state->shared())
    , target_(state->vm())
    , queued_signals_(0)
  {
    signal_thread_ = this;
    shared_.set_signal_handler(this);

    setup_default_handlers();
  }

  void SignalThread::initialize(STATE) {
    InternalThread::initialize(state);

    for(int i = 0; i < NSIG; i++) {
      pending_signals_[i] = 0;
    }

    worker_lock_.init();
    worker_cond_.init();
  }

  void SignalThread::wakeup(STATE) {
    InternalThread::wakeup(state);

    worker_cond_.signal();
  }

  void SignalThread::stop(STATE) {
    for(std::list<int>::iterator i = watched_signals_.begin();
        i != watched_signals_.end();
        ++i) {
      signal(*i, SIG_DFL);
    }

    InternalThread::stop(state);
  }

  void SignalThread::print_machine_info(PrintFunction function) {
    function("sysname: %s", machine_info.sysname);
    function("nodename: %s", machine_info.nodename);
    function("release: %s", machine_info.release);
    function("version: %s", machine_info.version);
    function("machine: %s", machine_info.machine);
  }

  void SignalThread::print_process_info(PrintFunction function) {
    function("user: %s", signal_thread_->shared().username.c_str());
    function("pid: %s", signal_thread_->shared().pid.c_str());
    function("program name: %s", RBX_PROGRAM_NAME);
    function("version: %s", RBX_VERSION);
    function("ruby version: %s", RBX_RUBY_VERSION);
    function("release date: %s", RBX_RELEASE_DATE);
    function("build revision: %s", RBX_BUILD_REV);
#if ENABLE_LLVM
    function("llvm version: %s", RBX_LLVM_VERSION);
#endif
    function("jit status: %s",
        CBOOL(signal_thread_->shared().env()->state->globals().jit.get()->enabled())
        ? "enabled" : "disabled");
  }

  void SignalThread::run(STATE) {
#ifndef RBX_WINDOWS
    sigset_t set;
    sigfillset(&set);
    pthread_sigmask(SIG_BLOCK, &set, NULL);
#endif

    GCTokenImpl gct;

    metrics().init(metrics::eRubyMetrics);

    while(!thread_exit_) {
      {
        utilities::thread::Mutex::LockGuard lg(worker_lock_);
        if(thread_exit_) break;
        state->gc_independent(gct, 0);
        worker_cond_.wait(worker_lock_);
        // If we should exit now, don't try to become
        // dependent first but break and exit the thread
        if(thread_exit_) break;
      }
      state->gc_dependent(gct, 0);
      {
        utilities::thread::Mutex::LockGuard lg(worker_lock_);
        if(thread_exit_) break;
      }

      target_->wakeup(state, gct, 0);
    }
  }

  void SignalThread::signal_handler(int sig) {
    signal_thread_->handle_signal(sig);
  }

  void SignalThread::handle_signal(int sig) {
    if(thread_exit_) return;

    target_->metrics().system_metrics.os_signals_received++;

    queued_signals_ = 1;
    pending_signals_[sig] = 1;

    target_->set_check_local_interrupts();

    if(target_->should_interrupt_with_signal()) {
      if(!pthread_equal(pthread_self(), target_->os_thread())) {
#ifdef RBX_WINDOWS
        // TODO: Windows
#else
        pthread_kill(target_->os_thread(), SIGVTALRM);
#endif
      }
    }

    worker_cond_.signal();
  }

  void SignalThread::add_signal(STATE, int sig, HandlerType type) {
    SYNC(state);
    utilities::thread::Mutex::LockGuard lg(worker_lock_);

#ifndef RBX_WINDOWS
    struct sigaction action;

    if(type == eDefault) {
      action.sa_handler = SIG_DFL;
      watched_signals_.remove(sig);
    } else if(type == eIgnore) {
      action.sa_handler = SIG_IGN;
      watched_signals_.push_back(sig);
    } else {
      action.sa_handler = signal_handler;
      watched_signals_.push_back(sig);
    }

    action.sa_flags = 0;
    sigfillset(&action.sa_mask);

    sigaction(sig, &action, NULL);
#endif
  }

  bool SignalThread::deliver_signals(STATE, CallFrame* call_frame) {
    queued_signals_ = 0;

    for(int i = 0; i < NSIG; i++) {
      if(pending_signals_[i] > 0) {
        pending_signals_[i] = 0;

        target_->metrics().system_metrics.os_signals_processed++;

        Array* args = Array::create(state, 1);
        args->set(state, 0, Fixnum::from(i));

        // Check whether the send raised an exception and
        // stop running the handlers if that happens
        if(!G(rubinius)->send(state, call_frame,
               state->symbol("received_signal"), args, cNil)) {
          if(state->thread_state()->raise_reason() == cException ||
             state->thread_state()->raise_reason() == cExit) {
            return false;
          }
        }
      }
    }

    return true;
  }

  void SignalThread::print_backtraces() {
    STATE = shared_.env()->state;
    ThreadList* threads = shared_.threads();

    for(ThreadList::iterator i = threads->begin(); i != threads->end(); ++i) {
      VM* vm = (*i)->as_vm();
      if(!vm) continue;

      if(vm->saved_call_frame()) {
        utilities::logger::fatal("--- Thread %d backtrace ---", vm->thread_id());
      }

      for(CallFrame* frame = vm->saved_call_frame(); frame; frame = frame->previous) {
        std::ostringstream stream;

        if(NativeMethodFrame* nmf = frame->native_method_frame()) {
          stream << static_cast<void*>(frame) << ": ";
          NativeMethod* nm = try_as<NativeMethod>(nmf->get_object(nmf->method()));
          if(nm && nm->name()->symbol_p()) {
            stream << "capi:" << nm->name()->debug_str(state) << " at ";
            stream << nm->file()->c_str(state);
          } else {
            stream << "unknown capi";
          }
        } else if(frame->compiled_code) {
          if(frame->is_block_p(state)) {
            stream << "__block__";
          } else {
            if(SingletonClass* sc = try_as<SingletonClass>(frame->module())) {
              Object* obj = sc->singleton();

              if(Module* mod = try_as<Module>(obj)) {
                stream << mod->debug_str(state) << ".";
              } else {
                if(obj == G(main)) {
                  stream << "MAIN.";
                } else {
                  stream << "#<" << obj->class_object(state)->debug_str(state) <<
                            ":" << (void*)obj->id(state)->to_native() << ">.";
                }
              }
            } else if(IncludedModule* im = try_as<IncludedModule>(frame->module())) {
              stream <<  im->module()->debug_str(state) << "#";
            } else {
              Symbol* name;
              std::string mod_name;

              if(frame->module()->nil_p()) {
                mod_name = frame->constant_scope()->module()->debug_str(state);
              } else {
                if((name = try_as<Symbol>(frame->module()->module_name()))) {
                  mod_name = name->debug_str(state);
                } else if((name = try_as<Symbol>(
                          frame->constant_scope()->module()->module_name()))) {
                  mod_name = name->debug_str(state);
                } else {
                  mod_name = "<anonymous module>";
                }
              }
              stream << mod_name << "#";
            }

            Symbol* name = try_as<Symbol>(frame->name());
            if(name) {
              stream << name->debug_str(state);
            } else {
              stream << frame->compiled_code->name()->debug_str(state);
            }
          }

          stream << " in ";
          if(Symbol* file_sym = try_as<Symbol>(frame->compiled_code->file())) {
            stream << file_sym->debug_str(state) << ":" << frame->line(state);
          } else {
            stream << "<unknown>";
          }

          stream << " (+" << frame->ip();
          if(frame->is_inline_frame()) {
            stream << " inline";
          } else if(frame->jitted_p()) {
            stream << " jit";
          }
          stream << ")";
        }

        utilities::logger::fatal(stream.str().c_str());
      }
    }
  }

  static void null_func(int sig) {}

#ifdef USE_EXECINFO
  static const char* rbx_signal_string(int sig) {
    switch(sig) {
    case SIGSEGV:
      return "SIGSEGV";
    case SIGBUS:
      return "SIGBUS";
    case SIGILL:
      return "SIGILL";
    case SIGABRT:
      return "SIGABRT";
    case SIGFPE:
      return "SIGFPE";
    default:
      return "UNKNOWN";
    }
  }

  static void abandon_ship_handler(int sig) {
    struct sigaction action;

    // Unset our handler for this signal.
    action.sa_handler = SIG_DFL;
    action.sa_flags = 0;
    sigaction(sig, &action, NULL);

    char* pause_env = getenv("RBX_PAUSE_ON_CRASH");

    if(pause_env) {
      long timeout = strtol(pause_env, NULL, 10);
      if(timeout <= 0) {
        timeout = 60;
      } else {
        timeout *= 60;
      }
      std::cerr << "\n========== CRASH (" << getpid();
      std::cerr << "), pausing for " << timeout << " seconds to attach debugger\n";
      sleep(timeout);
    }

    signal_thread_->shared().env()->atexit();

#define RBX_ABORT_CALLSTACK_SIZE    128
    void* callstack[RBX_ABORT_CALLSTACK_SIZE];
    int i, frames = backtrace(callstack, RBX_ABORT_CALLSTACK_SIZE);
    char** symbols = backtrace_symbols(callstack, frames);

    logger::fatal("The Rubinius process is aborting with signal: %s",
                  rbx_signal_string(sig));
    logger::fatal("--- begin system info ---");
    signal_thread_->print_machine_info(logger::fatal);
    logger::fatal("--- end system info ---");

    logger::fatal("--- begin rubinius info ---");
    signal_thread_->print_process_info(logger::fatal);
    logger::fatal("--- end rubinius info ---");

    logger::fatal("--- begin system backtrace ---");
    for(i = 0; i < frames; i++) {
      logger::fatal("%s", symbols[i]);
    }
    logger::fatal("--- end system backtrace ---");

    logger::fatal("--- begin Ruby backtraces ---");
    signal_thread_->print_backtraces();
    logger::fatal("--- end Ruby backtraces ---");

    raise(sig);
  }
#endif

  void SignalThread::setup_default_handlers() {
#ifndef RBX_WINDOWS
    // Get the machine info.
    uname(&machine_info);

    struct sigaction action;
    action.sa_handler = null_func;
    action.sa_flags = 0;
    sigfillset(&action.sa_mask);
    sigaction(SIGVTALRM, &action, NULL);

    // Some extensions expect SIGALRM to be defined, because MRI does.
    // We'll just use a noop for it.
    action.sa_handler = null_func;
    sigaction(SIGALRM, &action, NULL);

    // Ignore sigpipe.
    action.sa_handler = SIG_IGN;
    sigaction(SIGPIPE, &action, NULL);

#ifdef USE_EXECINFO
    // If we have execinfo, setup some crash handlers
    if(!getenv("DISABLE_SEGV")) {
      action.sa_handler = abandon_ship_handler;
      sigaction(SIGSEGV, &action, NULL);
      sigaction(SIGBUS,  &action, NULL);
      sigaction(SIGILL,  &action, NULL);
      sigaction(SIGFPE,  &action, NULL);
      sigaction(SIGABRT, &action, NULL);
    }
#endif  // USE_EXEC_INFO
#else
    signal(SIGTERM, quit_handler);
#endif  // ifndef RBX_WINDOWS
  }
}
<|endoftext|>


<commit_before>//===-- BitWriter.cpp -----------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by Gordon Henriksen and is distributed under the
// University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "llvm-c/BitWriter.h"
#include "llvm/Bitcode/ReaderWriter.h"
#include <fstream>

using namespace llvm;

/*===-- Operations on modules ---------------------------------------------===*/

int LLVMWriteBitcodeToFile(LLVMModuleRef M, const char *Path) {
  std::ofstream OS(Path);

  if (!OS.fail())
    WriteBitcodeToFile(unwrap(M), OS);

  if (OS.fail())
    return -1;

  return 0;
}

#ifdef __GNUC__
#include <ext/stdio_filebuf.h>

// FIXME: Control this with configure? Provide some portable abstraction in
// libSystem? As is, the user will just get a linker error if they use this on
// non-GCC. Some C++ stdlibs even have ofstream::ofstream(int fd).
int LLVMWriteBitcodeToFileHandle(LLVMModuleRef M, int FileHandle) {
  __gnu_cxx::stdio_filebuf<char> Buffer(FileHandle, std::ios_base::out |
                                                    std::ios::trunc |
                                                    std::ios::binary);
  std::ostream OS(&Buffer);

  if (!OS.fail())
    WriteBitcodeToFile(unwrap(M), OS);

  if (OS.fail())
    return -1;

  return 0;
}

#endif
<commit_msg>Applying Anton's binmode fix to the other ofstream too.<commit_after>//===-- BitWriter.cpp -----------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by Gordon Henriksen and is distributed under the
// University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "llvm-c/BitWriter.h"
#include "llvm/Bitcode/ReaderWriter.h"
#include <fstream>

using namespace llvm;

/*===-- Operations on modules ---------------------------------------------===*/

int LLVMWriteBitcodeToFile(LLVMModuleRef M, const char *Path) {
  std::ofstream OS(Path, std::ios_base::out|std::ios::trunc|std::ios::binary);

  if (!OS.fail())
    WriteBitcodeToFile(unwrap(M), OS);

  if (OS.fail())
    return -1;

  return 0;
}

#ifdef __GNUC__
#include <ext/stdio_filebuf.h>

// FIXME: Control this with configure? Provide some portable abstraction in
// libSystem? As is, the user will just get a linker error if they use this on
// non-GCC. Some C++ stdlibs even have ofstream::ofstream(int fd).
int LLVMWriteBitcodeToFileHandle(LLVMModuleRef M, int FileHandle) {
  __gnu_cxx::stdio_filebuf<char> Buffer(FileHandle, std::ios_base::out |
                                                    std::ios::trunc |
                                                    std::ios::binary);
  std::ostream OS(&Buffer);

  if (!OS.fail())
    WriteBitcodeToFile(unwrap(M), OS);

  if (OS.fail())
    return -1;

  return 0;
}

#endif
<|endoftext|>


<commit_before>//===--- DerivedConformances.cpp - Derived conformance utilities ----------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#include "TypeChecker.h"
#include "swift/AST/Decl.h"
#include "swift/AST/Stmt.h"
#include "swift/AST/Expr.h"
#include "swift/AST/Pattern.h"
#include "swift/AST/ParameterList.h"
#include "swift/AST/Types.h"
#include "swift/ClangImporter/ClangModule.h"
#include "DerivedConformances.h"

using namespace swift;
using namespace DerivedConformance;

bool DerivedConformance::derivesProtocolConformance(TypeChecker &tc,
                                                    NominalTypeDecl *nominal,
                                                    ProtocolDecl *protocol) {
  // Only known protocols can be derived.
  auto knownProtocol = protocol->getKnownProtocolKind();
  if (!knownProtocol)
    return false;

  if (auto *enumDecl = dyn_cast<EnumDecl>(nominal)) {
    switch (*knownProtocol) {
        // The presence of a raw type is an explicit declaration that
        // the compiler should derive a RawRepresentable conformance.
      case KnownProtocolKind::RawRepresentable:
        return enumDecl->hasRawType();

        // Enums without associated values can implicitly derive Equatable and
        // Hashable conformance.
      case KnownProtocolKind::Equatable:
        return canDeriveEquatable(tc, enumDecl, protocol);
      case KnownProtocolKind::Hashable:
        return canDeriveHashable(tc, enumDecl, protocol);

        // @objc enums can explicitly derive their _BridgedNSError conformance.
      case KnownProtocolKind::BridgedNSError:
        return enumDecl->isObjC() && enumDecl->hasCases()
            && enumDecl->hasOnlyCasesWithoutAssociatedValues();

        // Enums without associated values and enums with a raw type of String
        // or Int can explicitly derive CodingKey conformance.
      case KnownProtocolKind::CodingKey: {
        Type rawType = enumDecl->getRawType();
        if (rawType) {
          auto parentDC = enumDecl->getDeclContext();
          ASTContext &C = parentDC->getASTContext();

          auto nominal = rawType->getAnyNominal();
          return nominal == C.getStringDecl() || nominal == C.getIntDecl();
        }

        // hasOnlyCasesWithoutAssociatedValues will return true for empty enums;
        // empty enumas are allowed to conform as well.
        return enumDecl->hasOnlyCasesWithoutAssociatedValues();
      }

      default:
        return false;
    }
  } else if (isa<StructDecl>(nominal) || isa<ClassDecl>(nominal)) {
    // Structs and classes can explicitly derive Encodable and Decodable
    // conformance (explicitly meaning we can synthesize an implementation if
    // a type conforms manually).
    if (*knownProtocol == KnownProtocolKind::Encodable ||
        *knownProtocol == KnownProtocolKind::Decodable) {
      // FIXME: This is not actually correct. We cannot promise to always
      // provide a witness here for all structs and classes. Unfortunately,
      // figuring out whether this is actually possible requires much more
      // context -- a TypeChecker and the parent decl context at least -- and is
      // tightly coupled to the logic within DerivedConformance.
      // This unfortunately means that we expect a witness even if one will not
      // be produced, which requires DerivedConformance::deriveCodable to output
      // its own diagnostics.
      return true;
    }

    // Structs can explicitly derive Equatable and Hashable conformance.
    if (auto structDecl = dyn_cast<StructDecl>(nominal)) {
      switch (*knownProtocol) {
        case KnownProtocolKind::Equatable:
          return canDeriveEquatable(tc, structDecl, protocol);
        case KnownProtocolKind::Hashable:
          return canDeriveHashable(tc, structDecl, protocol);
        default:
          return false;
      }
    }
  }
  return false;
}

ValueDecl *DerivedConformance::getDerivableRequirement(TypeChecker &tc,
                                                       NominalTypeDecl *nominal,
                                                       ValueDecl *requirement) {
  // Note: whenever you update this function, also update
  // TypeChecker::deriveProtocolRequirement.
  ASTContext &ctx = nominal->getASTContext();
  auto name = requirement->getFullName();

  // Local function that retrieves the requirement with the same name as
  // the provided requirement, but within the given known protocol.
  auto getRequirement = [&](KnownProtocolKind kind) -> ValueDecl * {
    // Dig out the protocol.
    auto proto = ctx.getProtocol(kind);
    if (!proto) return nullptr;

    // Check whether this nominal type derives conformances to the protocol.
    if (!derivesProtocolConformance(tc, nominal, proto)) return nullptr;

    // Retrieve the requirement.
    auto results = proto->lookupDirect(name);
    return results.empty() ? nullptr : results.front();
  };

  // Properties.
  if (isa<VarDecl>(requirement)) {
    // RawRepresentable.rawValue
    if (name.isSimpleName(ctx.Id_rawValue))
      return getRequirement(KnownProtocolKind::RawRepresentable);

    // Hashable.hashValue
    if (name.isSimpleName(ctx.Id_hashValue))
      return getRequirement(KnownProtocolKind::Hashable);

    // _BridgedNSError._nsErrorDomain
    if (name.isSimpleName(ctx.Id_nsErrorDomain))
      return getRequirement(KnownProtocolKind::BridgedNSError);

    // CodingKey.stringValue
    if (name.isSimpleName(ctx.Id_stringValue))
      return getRequirement(KnownProtocolKind::CodingKey);

    // CodingKey.intValue
    if (name.isSimpleName(ctx.Id_intValue))
      return getRequirement(KnownProtocolKind::CodingKey);

    return nullptr;
  }

  // Functions.
  if (auto func = dyn_cast<FuncDecl>(requirement)) {
    if (func->isOperator() && name.getBaseName() == "==")
      return getRequirement(KnownProtocolKind::Equatable);

    // Encodable.encode(to: Encoder)
    if (name.isCompoundName() && name.getBaseName() == ctx.Id_encode) {
      auto argumentNames = name.getArgumentNames();
      if (argumentNames.size() == 1 && argumentNames[0] == ctx.Id_to)
        return getRequirement(KnownProtocolKind::Encodable);
    }

    return nullptr;
  }

  // Initializers.
  if (auto ctor = dyn_cast<ConstructorDecl>(requirement)) {
    auto argumentNames = name.getArgumentNames();
    if (argumentNames.size() == 1) {
      if (argumentNames[0] == ctx.Id_rawValue)
        return getRequirement(KnownProtocolKind::RawRepresentable);

      // CodingKey.init?(stringValue:), CodingKey.init?(intValue:)
      if (ctor->getFailability() == OTK_Optional &&
          (argumentNames[0] == ctx.Id_stringValue ||
           argumentNames[0] == ctx.Id_intValue))
        return getRequirement(KnownProtocolKind::CodingKey);

      // Decodable.init(from: Decoder)
      if (argumentNames[0] == ctx.Id_from)
        return getRequirement(KnownProtocolKind::Decodable);
    }

    return nullptr;
  }

  // Associated types.
  if (isa<AssociatedTypeDecl>(requirement)) {
    // RawRepresentable.RawValue
    if (name.isSimpleName(ctx.Id_RawValue))
      return getRequirement(KnownProtocolKind::RawRepresentable);

    return nullptr;
  }

  return nullptr;
}

DeclRefExpr *
DerivedConformance::createSelfDeclRef(AbstractFunctionDecl *fn) {
  ASTContext &C = fn->getASTContext();

  auto selfDecl = fn->getImplicitSelfDecl();
  return new (C) DeclRefExpr(selfDecl, DeclNameLoc(), /*implicit*/true);
}

AccessorDecl *DerivedConformance::
addGetterToReadOnlyDerivedProperty(TypeChecker &tc,
                                   VarDecl *property,
                                   Type propertyContextType) {
  auto getter =
    declareDerivedPropertyGetter(tc, property, propertyContextType);

  property->makeComputed(SourceLoc(), getter, nullptr, nullptr, SourceLoc());

  return getter;
}

AccessorDecl *
DerivedConformance::declareDerivedPropertyGetter(TypeChecker &tc,
                                                 VarDecl *property,
                                                 Type propertyContextType) {
  bool isStatic = property->isStatic();
  bool isFinal = property->isFinal();

  auto &C = tc.Context;
  auto parentDC = property->getDeclContext();
  auto selfDecl = ParamDecl::createSelf(SourceLoc(), parentDC, isStatic);
  ParameterList *params[] = {
    ParameterList::createWithoutLoc(selfDecl),
    ParameterList::createEmpty(C)
  };

  Type propertyInterfaceType = property->getInterfaceType();

  auto getterDecl = AccessorDecl::create(C,
    /*FuncLoc=*/SourceLoc(), /*AccessorKeywordLoc=*/SourceLoc(),
    AccessorKind::IsGetter, AddressorKind::NotAddressor, property,
    /*StaticLoc=*/SourceLoc(), StaticSpellingKind::None,
    /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(),
    /*GenericParams=*/nullptr, params,
    TypeLoc::withoutLoc(propertyInterfaceType), parentDC);
  getterDecl->setImplicit();
  getterDecl->setStatic(isStatic);

  // If this is supposed to be a final method, mark it as such.
  assert(isFinal || !parentDC->getAsClassOrClassExtensionContext());
  if (isFinal && parentDC->getAsClassOrClassExtensionContext() &&
      !getterDecl->isFinal())
    getterDecl->getAttrs().add(new (C) FinalAttr(/*IsImplicit=*/true));

  // Compute the interface type of the getter.
  Type interfaceType = FunctionType::get(TupleType::getEmpty(C),
                                         propertyInterfaceType);
  auto selfParam = computeSelfParam(getterDecl);
  if (auto sig = parentDC->getGenericSignatureOfContext()) {
    getterDecl->setGenericEnvironment(
        parentDC->getGenericEnvironmentOfContext());
    interfaceType = GenericFunctionType::get(sig, {selfParam},
                                             interfaceType,
                                             FunctionType::ExtInfo());
  } else
    interfaceType = FunctionType::get({selfParam}, interfaceType,
                                      FunctionType::ExtInfo());
  getterDecl->setInterfaceType(interfaceType);
  getterDecl->copyFormalAccessAndVersionedAttrFrom(property);

  // If the enum was not imported, the derived conformance is either from the
  // enum itself or an extension, in which case we will emit the declaration
  // normally.
  if (isa<ClangModuleUnit>(parentDC->getModuleScopeContext()))
    tc.Context.addExternalDecl(getterDecl);

  return getterDecl;
}

std::pair<VarDecl *, PatternBindingDecl *>
DerivedConformance::declareDerivedProperty(TypeChecker &tc, Decl *parentDecl,
                                           NominalTypeDecl *typeDecl,
                                           Identifier name,
                                           Type propertyInterfaceType,
                                           Type propertyContextType,
                                           bool isStatic,
                                           bool isFinal) {
  auto &C = tc.Context;
  auto parentDC = cast<DeclContext>(parentDecl);

  VarDecl *propDecl = new (C) VarDecl(/*IsStatic*/isStatic, VarDecl::Specifier::Var,
                                      /*IsCaptureList*/false, SourceLoc(), name,
                                      propertyContextType, parentDC);
  propDecl->setImplicit();
  propDecl->copyFormalAccessAndVersionedAttrFrom(typeDecl);
  propDecl->setInterfaceType(propertyInterfaceType);

  // If this is supposed to be a final property, mark it as such.
  assert(isFinal || !parentDC->getAsClassOrClassExtensionContext());
  if (isFinal && parentDC->getAsClassOrClassExtensionContext() &&
      !propDecl->isFinal())
    propDecl->getAttrs().add(new (C) FinalAttr(/*IsImplicit=*/true));

  Pattern *propPat = new (C) NamedPattern(propDecl, /*implicit*/ true);
  propPat->setType(propertyContextType);
  propPat = new (C) TypedPattern(propPat,
                                 TypeLoc::withoutLoc(propertyContextType),
                                 /*implicit*/ true);

  auto pbDecl = PatternBindingDecl::create(C, SourceLoc(),
                                           StaticSpellingKind::None,
                                           SourceLoc(), propPat, nullptr,
                                           parentDC);
  pbDecl->setImplicit();

  return {propDecl, pbDecl};
}
<commit_msg>Fix a typo in DerivedConformances<commit_after>//===--- DerivedConformances.cpp - Derived conformance utilities ----------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#include "TypeChecker.h"
#include "swift/AST/Decl.h"
#include "swift/AST/Stmt.h"
#include "swift/AST/Expr.h"
#include "swift/AST/Pattern.h"
#include "swift/AST/ParameterList.h"
#include "swift/AST/Types.h"
#include "swift/ClangImporter/ClangModule.h"
#include "DerivedConformances.h"

using namespace swift;
using namespace DerivedConformance;

bool DerivedConformance::derivesProtocolConformance(TypeChecker &tc,
                                                    NominalTypeDecl *nominal,
                                                    ProtocolDecl *protocol) {
  // Only known protocols can be derived.
  auto knownProtocol = protocol->getKnownProtocolKind();
  if (!knownProtocol)
    return false;

  if (auto *enumDecl = dyn_cast<EnumDecl>(nominal)) {
    switch (*knownProtocol) {
        // The presence of a raw type is an explicit declaration that
        // the compiler should derive a RawRepresentable conformance.
      case KnownProtocolKind::RawRepresentable:
        return enumDecl->hasRawType();

        // Enums without associated values can implicitly derive Equatable and
        // Hashable conformance.
      case KnownProtocolKind::Equatable:
        return canDeriveEquatable(tc, enumDecl, protocol);
      case KnownProtocolKind::Hashable:
        return canDeriveHashable(tc, enumDecl, protocol);

        // @objc enums can explicitly derive their _BridgedNSError conformance.
      case KnownProtocolKind::BridgedNSError:
        return enumDecl->isObjC() && enumDecl->hasCases()
            && enumDecl->hasOnlyCasesWithoutAssociatedValues();

        // Enums without associated values and enums with a raw type of String
        // or Int can explicitly derive CodingKey conformance.
      case KnownProtocolKind::CodingKey: {
        Type rawType = enumDecl->getRawType();
        if (rawType) {
          auto parentDC = enumDecl->getDeclContext();
          ASTContext &C = parentDC->getASTContext();

          auto nominal = rawType->getAnyNominal();
          return nominal == C.getStringDecl() || nominal == C.getIntDecl();
        }

        // hasOnlyCasesWithoutAssociatedValues will return true for empty enums;
        // empty enums are allowed to conform as well.
        return enumDecl->hasOnlyCasesWithoutAssociatedValues();
      }

      default:
        return false;
    }
  } else if (isa<StructDecl>(nominal) || isa<ClassDecl>(nominal)) {
    // Structs and classes can explicitly derive Encodable and Decodable
    // conformance (explicitly meaning we can synthesize an implementation if
    // a type conforms manually).
    if (*knownProtocol == KnownProtocolKind::Encodable ||
        *knownProtocol == KnownProtocolKind::Decodable) {
      // FIXME: This is not actually correct. We cannot promise to always
      // provide a witness here for all structs and classes. Unfortunately,
      // figuring out whether this is actually possible requires much more
      // context -- a TypeChecker and the parent decl context at least -- and is
      // tightly coupled to the logic within DerivedConformance.
      // This unfortunately means that we expect a witness even if one will not
      // be produced, which requires DerivedConformance::deriveCodable to output
      // its own diagnostics.
      return true;
    }

    // Structs can explicitly derive Equatable and Hashable conformance.
    if (auto structDecl = dyn_cast<StructDecl>(nominal)) {
      switch (*knownProtocol) {
        case KnownProtocolKind::Equatable:
          return canDeriveEquatable(tc, structDecl, protocol);
        case KnownProtocolKind::Hashable:
          return canDeriveHashable(tc, structDecl, protocol);
        default:
          return false;
      }
    }
  }
  return false;
}

ValueDecl *DerivedConformance::getDerivableRequirement(TypeChecker &tc,
                                                       NominalTypeDecl *nominal,
                                                       ValueDecl *requirement) {
  // Note: whenever you update this function, also update
  // TypeChecker::deriveProtocolRequirement.
  ASTContext &ctx = nominal->getASTContext();
  auto name = requirement->getFullName();

  // Local function that retrieves the requirement with the same name as
  // the provided requirement, but within the given known protocol.
  auto getRequirement = [&](KnownProtocolKind kind) -> ValueDecl * {
    // Dig out the protocol.
    auto proto = ctx.getProtocol(kind);
    if (!proto) return nullptr;

    // Check whether this nominal type derives conformances to the protocol.
    if (!derivesProtocolConformance(tc, nominal, proto)) return nullptr;

    // Retrieve the requirement.
    auto results = proto->lookupDirect(name);
    return results.empty() ? nullptr : results.front();
  };

  // Properties.
  if (isa<VarDecl>(requirement)) {
    // RawRepresentable.rawValue
    if (name.isSimpleName(ctx.Id_rawValue))
      return getRequirement(KnownProtocolKind::RawRepresentable);

    // Hashable.hashValue
    if (name.isSimpleName(ctx.Id_hashValue))
      return getRequirement(KnownProtocolKind::Hashable);

    // _BridgedNSError._nsErrorDomain
    if (name.isSimpleName(ctx.Id_nsErrorDomain))
      return getRequirement(KnownProtocolKind::BridgedNSError);

    // CodingKey.stringValue
    if (name.isSimpleName(ctx.Id_stringValue))
      return getRequirement(KnownProtocolKind::CodingKey);

    // CodingKey.intValue
    if (name.isSimpleName(ctx.Id_intValue))
      return getRequirement(KnownProtocolKind::CodingKey);

    return nullptr;
  }

  // Functions.
  if (auto func = dyn_cast<FuncDecl>(requirement)) {
    if (func->isOperator() && name.getBaseName() == "==")
      return getRequirement(KnownProtocolKind::Equatable);

    // Encodable.encode(to: Encoder)
    if (name.isCompoundName() && name.getBaseName() == ctx.Id_encode) {
      auto argumentNames = name.getArgumentNames();
      if (argumentNames.size() == 1 && argumentNames[0] == ctx.Id_to)
        return getRequirement(KnownProtocolKind::Encodable);
    }

    return nullptr;
  }

  // Initializers.
  if (auto ctor = dyn_cast<ConstructorDecl>(requirement)) {
    auto argumentNames = name.getArgumentNames();
    if (argumentNames.size() == 1) {
      if (argumentNames[0] == ctx.Id_rawValue)
        return getRequirement(KnownProtocolKind::RawRepresentable);

      // CodingKey.init?(stringValue:), CodingKey.init?(intValue:)
      if (ctor->getFailability() == OTK_Optional &&
          (argumentNames[0] == ctx.Id_stringValue ||
           argumentNames[0] == ctx.Id_intValue))
        return getRequirement(KnownProtocolKind::CodingKey);

      // Decodable.init(from: Decoder)
      if (argumentNames[0] == ctx.Id_from)
        return getRequirement(KnownProtocolKind::Decodable);
    }

    return nullptr;
  }

  // Associated types.
  if (isa<AssociatedTypeDecl>(requirement)) {
    // RawRepresentable.RawValue
    if (name.isSimpleName(ctx.Id_RawValue))
      return getRequirement(KnownProtocolKind::RawRepresentable);

    return nullptr;
  }

  return nullptr;
}

DeclRefExpr *
DerivedConformance::createSelfDeclRef(AbstractFunctionDecl *fn) {
  ASTContext &C = fn->getASTContext();

  auto selfDecl = fn->getImplicitSelfDecl();
  return new (C) DeclRefExpr(selfDecl, DeclNameLoc(), /*implicit*/true);
}

AccessorDecl *DerivedConformance::
addGetterToReadOnlyDerivedProperty(TypeChecker &tc,
                                   VarDecl *property,
                                   Type propertyContextType) {
  auto getter =
    declareDerivedPropertyGetter(tc, property, propertyContextType);

  property->makeComputed(SourceLoc(), getter, nullptr, nullptr, SourceLoc());

  return getter;
}

AccessorDecl *
DerivedConformance::declareDerivedPropertyGetter(TypeChecker &tc,
                                                 VarDecl *property,
                                                 Type propertyContextType) {
  bool isStatic = property->isStatic();
  bool isFinal = property->isFinal();

  auto &C = tc.Context;
  auto parentDC = property->getDeclContext();
  auto selfDecl = ParamDecl::createSelf(SourceLoc(), parentDC, isStatic);
  ParameterList *params[] = {
    ParameterList::createWithoutLoc(selfDecl),
    ParameterList::createEmpty(C)
  };

  Type propertyInterfaceType = property->getInterfaceType();

  auto getterDecl = AccessorDecl::create(C,
    /*FuncLoc=*/SourceLoc(), /*AccessorKeywordLoc=*/SourceLoc(),
    AccessorKind::IsGetter, AddressorKind::NotAddressor, property,
    /*StaticLoc=*/SourceLoc(), StaticSpellingKind::None,
    /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(),
    /*GenericParams=*/nullptr, params,
    TypeLoc::withoutLoc(propertyInterfaceType), parentDC);
  getterDecl->setImplicit();
  getterDecl->setStatic(isStatic);

  // If this is supposed to be a final method, mark it as such.
  assert(isFinal || !parentDC->getAsClassOrClassExtensionContext());
  if (isFinal && parentDC->getAsClassOrClassExtensionContext() &&
      !getterDecl->isFinal())
    getterDecl->getAttrs().add(new (C) FinalAttr(/*IsImplicit=*/true));

  // Compute the interface type of the getter.
  Type interfaceType = FunctionType::get(TupleType::getEmpty(C),
                                         propertyInterfaceType);
  auto selfParam = computeSelfParam(getterDecl);
  if (auto sig = parentDC->getGenericSignatureOfContext()) {
    getterDecl->setGenericEnvironment(
        parentDC->getGenericEnvironmentOfContext());
    interfaceType = GenericFunctionType::get(sig, {selfParam},
                                             interfaceType,
                                             FunctionType::ExtInfo());
  } else
    interfaceType = FunctionType::get({selfParam}, interfaceType,
                                      FunctionType::ExtInfo());
  getterDecl->setInterfaceType(interfaceType);
  getterDecl->copyFormalAccessAndVersionedAttrFrom(property);

  // If the enum was not imported, the derived conformance is either from the
  // enum itself or an extension, in which case we will emit the declaration
  // normally.
  if (isa<ClangModuleUnit>(parentDC->getModuleScopeContext()))
    tc.Context.addExternalDecl(getterDecl);

  return getterDecl;
}

std::pair<VarDecl *, PatternBindingDecl *>
DerivedConformance::declareDerivedProperty(TypeChecker &tc, Decl *parentDecl,
                                           NominalTypeDecl *typeDecl,
                                           Identifier name,
                                           Type propertyInterfaceType,
                                           Type propertyContextType,
                                           bool isStatic,
                                           bool isFinal) {
  auto &C = tc.Context;
  auto parentDC = cast<DeclContext>(parentDecl);

  VarDecl *propDecl = new (C) VarDecl(/*IsStatic*/isStatic, VarDecl::Specifier::Var,
                                      /*IsCaptureList*/false, SourceLoc(), name,
                                      propertyContextType, parentDC);
  propDecl->setImplicit();
  propDecl->copyFormalAccessAndVersionedAttrFrom(typeDecl);
  propDecl->setInterfaceType(propertyInterfaceType);

  // If this is supposed to be a final property, mark it as such.
  assert(isFinal || !parentDC->getAsClassOrClassExtensionContext());
  if (isFinal && parentDC->getAsClassOrClassExtensionContext() &&
      !propDecl->isFinal())
    propDecl->getAttrs().add(new (C) FinalAttr(/*IsImplicit=*/true));

  Pattern *propPat = new (C) NamedPattern(propDecl, /*implicit*/ true);
  propPat->setType(propertyContextType);
  propPat = new (C) TypedPattern(propPat,
                                 TypeLoc::withoutLoc(propertyContextType),
                                 /*implicit*/ true);

  auto pbDecl = PatternBindingDecl::create(C, SourceLoc(),
                                           StaticSpellingKind::None,
                                           SourceLoc(), propPat, nullptr,
                                           parentDC);
  pbDecl->setImplicit();

  return {propDecl, pbDecl};
}
<|endoftext|>


<commit_before>/*-
 * Copyright (c) 2016 Frederic Culot <culot@FreeBSD.org>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer
 *    in this position and unchanged.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <thread>
#include <chrono>
#include <stdexcept>
#include <sstream>
#include <vector>
#include <set>

#include <curses.h>

#include "pkg.h"
#include "point.h"
#include "size.h"
#include "popup.h"
#include "prompt.h"
#include "ui.h"

namespace portal {

const std::string markerCategory("---");
const std::string markerFolded("-");
const std::string markerUnfolded("\\");

Ui::Ui() {
  initscr();

  // XXX Need more elegant color definitions (enum?)
  if (has_colors() && start_color() == OK) {
    init_pair(1, COLOR_CYAN, COLOR_BLUE);

    init_pair(2, COLOR_CYAN, 0);
    init_pair(4, COLOR_MAGENTA, 0);
    init_pair(5, COLOR_RED, 0);
    init_pair(6, COLOR_YELLOW, 0);
    init_pair(7, COLOR_BLUE, 0);
  } else {
    // XXX Need to deal with B&W terminals
    throw std::runtime_error("Sorry, B&W terminals not supported yet");
  }

  cbreak();
  noecho();
  keypad(stdscr, TRUE);
  curs_set(0);
  refresh();  // A refresh might seem unnecessary here, but user input is
              // gathered from stdscr via a call to getch, which does an
              // implicit refresh first (don't ask me why...). Hence doing
              // this refresh explicitly avoids a black screen when portal
              // starts. The black screen does not appear afterwards as
              // stdscr is never touched by portal, so curses detects it
              // does not need any subsequent refreshes.
  createInterface();
  updatePanes();
}

Ui::~Ui() {
  clear();
  endwin();
}

void Ui::display() {
  for (const auto& pane : pane_) {
    pane->draw();
  }
  tray_->draw();
  doupdate();
}

void Ui::handleEvent(const Event& event) {
  switch (event.type()) {
    case Event::Type::nextMode:
      selectNextMode();
      if (currentMode_ == Mode::browse) {
        Pkg::instance().resetFilter();
        updatePanes();
      }
      updateTray();
    break;

    case Event::Type::select: {
      if (!Pkg::instance().isRepositoryEmpty()) {
        if (gotCategorySelected()) {
          std::string category = getSelectedItemName();
          toggleCategoryFolding(category);
          updatePanes();
        } else {
          registerPkgChange(event.type());
          updatePkgListPane();
        }
      }
      break;
    }

    case Event::Type::deselect:
      if (!Pkg::instance().isRepositoryEmpty()) {
        registerPkgChange(event.type());
        updatePkgListPane();
      }
      break;

    case Event::Type::keyUp:
    case Event::Type::keyDown:
    case Event::Type::pageUp:
    case Event::Type::pageDown:
      if (!Pkg::instance().isRepositoryEmpty()) {
        if (event.type() == Event::Type::keyUp) {
          pane_[pkgList]->moveCursorUp();
        } else if (event.type() == Event::Type::keyDown) {
          pane_[pkgList]->moveCursorDown();
        }
        // XXX Implement scroll up and down
        updatePkgDescrPane();
      }
      break;

    case Event::Type::keyShiftUp:
    case Event::Type::keyShiftDown:
      if (!Pkg::instance().isRepositoryEmpty()) {
        if (event.type() == Event::Type::keyShiftUp) {
          pane_[pkgDescr]->moveCursorUp();
        } else if (event.type() == Event::Type::keyShiftDown) {
          pane_[pkgDescr]->moveCursorDown();
        }
        updatePkgDescrPane();
      }
      break;

    case Event::Type::character:
      switch (currentMode_) {
      case Mode::browse :
        // DO NOTHING
        break;
      case Mode::search :
        pane_[pkgList]->resetCursorPosition();
        promptSearch(event.character());
        updatePanes();
        break;
      case Mode::filter :
        pane_[pkgList]->resetCursorPosition();
        promptFilter(event.character());
        updatePanes();
        break;
      }
      break;

    case Event::Type::go:
      if (!Pkg::instance().gotRootPrivileges()) {
        gfx::Popup("Insufficient privileges, please retry as root", gfx::Popup::Type::warning);
      } else {
        performPending();
        closeAllFolds();
        updatePkgListPane();
      }
      break;

    case Event::Type::redraw:
      display();
      break;

    default:
      break;
  }
}

/*
    +------------------------------+
    |                              | \
    |                              | |
    |                              | | pane_[pkgList]
    |                              | |
    |                              | /
    +------------------------------+
    |                              | \ <-- comment
    |                              | |
    |                              | / pane_[pkgDescr]
    +------------------------------+
 */
void Ui::createInterface() {
  int pkgPaneHeight = LINES * .6;
  int descrPaneHeight = LINES - pkgPaneHeight - 1;

  gfx::Size listSize, descrSize;
  listSize.setWidth(COLS);
  listSize.setHeight(pkgPaneHeight);
  descrSize.setWidth(COLS);
  descrSize.setHeight(descrPaneHeight);

  gfx::Point listPos, descrPos;
  descrPos.setY(pkgPaneHeight);

  pane_[pkgList] = std::unique_ptr<gfx::Pane>(new gfx::Pane(listSize, listPos));
  pane_[pkgDescr] = std::unique_ptr<gfx::Pane>(new gfx::Pane(descrSize, descrPos));
  pane_[pkgDescr]->borders(false);
  pane_[pkgDescr]->cursorLineHighlight(false);

  gfx::Point trayPos;
  trayPos.setY(pkgPaneHeight);
  trayPos.setX(COLS / 2);
  tray_ = std::unique_ptr<gfx::Tray>(new gfx::Tray(trayPos, Mode::nbModes));
}

void Ui::updatePanes() {
  if (Pkg::instance().isRepositoryEmpty()) {
    for (auto& pane : pane_) {
      pane->clear();
      pane->resetCursorPosition();
    }
  } else {
    updatePkgListPane();
    updatePkgDescrPane();
  }
}

void Ui::buildPkgList() {
  pkgList_.clear();
  std::vector<std::string> categories = Pkg::instance().getPkgCategories();
  for (const auto& category : categories) {
    pkgList_.push_back({pkgListItemType::category, category});
    if (!isCategoryFolded(category)) {
      std::vector<std::string> origins = Pkg::instance().getPkgOrigins(category);
      for (const auto& origin : origins) {
        pkgList_.push_back({pkgListItemType::pkg, origin});
      }
    }
  }
}

// Build a hierarchy of categories and ports:
//
// ---- category1
// ---\ category2
// -    port1
// +    port2
// ---- category3
void Ui::updatePkgListPane() {
  buildPkgList();
  pane_[pkgList]->clear();
  for (const auto& item : pkgList_) {
    switch (item.type) {
    case pkgListItemType::category: {
      std::string categoryString = getStringForCategory(item.name);
      pane_[pkgList]->print(categoryString);
    }
    break;
    case pkgListItemType::pkg: {
      std::string pkgString = getStringForPkg(item.name);
      pane_[pkgList]->print(pkgString);
      std::string pkgVersions = getVersionsForPkg(item.name);
      pane_[pkgList]->print(pkgVersions, gfx::Pane::Align::right);
      //if (Pkg::instance().hasPendingActions(item.name)) {
        // XXX change attributes
        //pane_[pkgList].addRowAttributes(dataGrid.height() - 1, gfx::ATTR_BOLD);
      //}
    }
    break;
    default:
      break;
    }
    pane_[pkgList]->newline();
  }
}

void Ui::updatePkgDescrPane() {
  pane_[pkgDescr]->clear();

  if (!gotCategorySelected()) {
    std::string origin = getSelectedItemName();
    std::string comment = Pkg::instance().getPkgAttr(origin, Pkg::Attr::comment);
    pane_[pkgDescr]->print(comment);
    pane_[pkgDescr]->colorizeCurrentLine(1);

    std::string desc = Pkg::instance().getPkgAttr(origin, Pkg::Attr::description);
    std::stringstream commentStream(desc);
    std::string descLine;
    while (std::getline(commentStream, descLine, '\n')) {
      pane_[pkgDescr]->newline();
      pane_[pkgDescr]->print(descLine);
    }
  }

  //pane_[pkgDescr].requestRefresh();
}

const Ui::pkgListItem& Ui::getCurrentPkgListItem() const {
  int index = pane_[pkgList]->getCursorRowNum();
  return pkgList_[index];
}

std::string Ui::getSelectedItemName() const {
  const pkgListItem& item = getCurrentPkgListItem();
  return item.name;
}

bool Ui::gotCategorySelected() {
  const pkgListItem& item = getCurrentPkgListItem();
  return isCategory(item);
}

bool Ui::isCategory(const pkgListItem& item) const {
  return item.type == pkgListItemType::category;
}

void Ui::toggleCategoryFolding(const std::string& category) {
  if (unfolded_.find(category) != unfolded_.end()) {
    unfolded_[category] = unfolded_[category] == true ? false : true;
  } else {
    unfolded_[category] = true;
  }
}

void Ui::closeAllFolds() {
  unfolded_.clear();
  pane_[pkgList]->resetCursorPosition();
}

void Ui::registerPkgChange(Event::Type event) {
  if (!gotCategorySelected()) {
    std::string origin = getSelectedItemName();

    switch (event) {
      case Event::Type::select:
        Pkg::instance().registerInstall(origin);
        break;

      case Event::Type::deselect:
        Pkg::instance().registerRemoval(origin);
        break;

      default:
        break;
    }
  }
}

void Ui::performPending() {
  busy_ = true;
  // XXX implement busy status
//  std::thread uiHint([this]() {busyStatus(pane_[pkgList]);});
//  uiHint.detach();

  std::thread pendingActions(&Pkg::performPending, &Pkg::instance());
  pendingActions.join();
  busy_ = false;
//  pane_[pkgList].clearStatus();
}

void Ui::promptFilter(int character) {
  switch (character) {
  case 'n':
    Pkg::instance().resetFilter();
    break;

  case 'i':
  case '+':
//          pane_[pkgList].status("Installed");
    Pkg::instance().filterInstalled();
    break;

  case '-':
  case 'a':
//          pane_[pkgList].status("Available");
    Pkg::instance().filterAvailable();
    break;

  case 'p':
//          pane_[pkgList].status("Pending");
    Pkg::instance().filterPending();
    break;

  case 'u':
//          pane_[pkgList].status("Upgradable");
    Pkg::instance().filterUpgradable();
    break;

  default:
    // DO NOTHING
    break;
  }
}

void Ui::promptSearch(int character) const {
  gfx::Point pos = gfx::Point::Label::center;
  gfx::Prompt prompt(pos, 40);
  prompt.setContent(std::string(1, static_cast<char>(character)));
  std::string query = prompt.getInput();
  Pkg::instance().search(query);
  pane_[pkgList]->clearStatus();
  pane_[pkgList]->printStatus(query, 2);
}

  // XXX implement busy status
void Ui::setBusyStatus(gfx::Pane& pane, const std::string& status) {
  /*
  pane.status(status);
  pane.refreshStatus();
  std::this_thread::sleep_for(std::chrono::milliseconds(500));
  */
}

void Ui::busyStatus(gfx::Pane& pane) {
  /*
  while (busy_) {
    setBusyStatus(pane, "Please wait.  ");
    if (!busy_)
      return;
    setBusyStatus(pane, "Please wait.. ");
    if (!busy_)
      return;
    setBusyStatus(pane, "Please wait...");
    if (!busy_)
      return;
    setBusyStatus(pane, "Please wait ..");
    if (!busy_)
      return;
    setBusyStatus(pane, "Please wait  .");
    if (!busy_)
      return;
  }
  */
}

void Ui::warningStatus(gfx::Pane& pane, const std::string& status) {
  /*
  std::string oldStatus = pane.getStatus();
  pane.status(status, gfx::color::RED);
  pane.refreshStatus();
  std::this_thread::sleep_for(std::chrono::milliseconds(1500));
  pane.status(oldStatus);
  pane.requestRefresh();
  */
}

bool Ui::isCategoryFolded(const std::string& category) const {
  return unfolded_.find(category) == unfolded_.end() || unfolded_.at(category) == false;
}

std::string Ui::getStringForCategory(const std::string& category) const {
  std::string categoryString(markerCategory);
  if (isCategoryFolded(category)) {
    categoryString.append(markerFolded);
  } else {
    categoryString.append(markerUnfolded);
  }
  categoryString.append(" ");
  categoryString.append(category);
  categoryString.append(" (");
  categoryString.append(std::to_string(Pkg::instance().getCategorySize(category)));
  categoryString.append(")");

  return categoryString;
}

std::string Ui::getStringForPkg(const std::string& origin) const {
  std::string pkgString = Pkg::instance().getCurrentStatusAsString(origin);
  if (Pkg::instance().hasPendingActions(origin)) {
    pkgString.append("[");
    pkgString.append(Pkg::instance().getPendingStatusAsString(origin));
    pkgString.append("] ");
  } else if (Pkg::instance().isUpgradable(origin)) {
    pkgString.append("[^] ");
  } else {
    pkgString.append("    ");
  }
  pkgString.append(Pkg::instance().getNameFromOrigin(origin));

  return pkgString;
}

std::string Ui::getVersionsForPkg(const std::string& origin) const {
  std::string pkgVersions = Pkg::instance().getLocalVersion(origin);
  if (!pkgVersions.empty()) {
    pkgVersions.append("    ");
  }
  pkgVersions.append(Pkg::instance().getRemoteVersion(origin));

  return pkgVersions;
}

void Ui::selectNextMode() {
  ++currentMode_;
  if (currentMode_ == Mode::nbModes) {
    currentMode_ = 0;
  }
}

void Ui::updateTray() {
  tray_->selectSlot(currentMode_);
  gfx::Point center;
  center.setX(COLS / 2);
  center.setY(pane_[pkgList]->size().height() - 2);
  gfx::Popup(modeName_[currentMode_], gfx::Popup::Type::brief, center);
}

}
<commit_msg>Make use of the new Style class<commit_after>/*-
 * Copyright (c) 2016 Frederic Culot <culot@FreeBSD.org>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer
 *    in this position and unchanged.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <thread>
#include <chrono>
#include <stdexcept>
#include <sstream>
#include <vector>
#include <set>

#include <curses.h>

#include "pkg.h"
#include "point.h"
#include "size.h"
#include "popup.h"
#include "prompt.h"
#include "style.h"
#include "ui.h"

namespace portal {

const std::string markerCategory("---");
const std::string markerFolded("-");
const std::string markerUnfolded("\\");

Ui::Ui() {
  initscr();

  if (has_colors() && start_color() == OK) {
    init_pair(gfx::Style::Color::cyan, COLOR_CYAN, 0);
    init_pair(gfx::Style::Color::magenta, COLOR_MAGENTA, 0);
    init_pair(gfx::Style::Color::red, COLOR_RED, 0);
    init_pair(gfx::Style::Color::yellow, COLOR_YELLOW, 0);
    init_pair(gfx::Style::Color::blue, COLOR_BLUE, 0);
    init_pair(gfx::Style::Color::cyanOnBlue, COLOR_CYAN, COLOR_BLUE);
  } else {
    // XXX Need to deal with B&W terminals
    throw std::runtime_error("Sorry, B&W terminals not supported yet");
  }

  cbreak();
  noecho();
  keypad(stdscr, TRUE);
  curs_set(0);
  refresh();  // A refresh might seem unnecessary here, but user input is
              // gathered from stdscr via a call to getch, which does an
              // implicit refresh first (don't ask me why...). Hence doing
              // this refresh explicitly avoids a black screen when portal
              // starts. The black screen does not appear afterwards as
              // stdscr is never touched by portal, so curses detects it
              // does not need any subsequent refreshes.
  createInterface();
  updatePanes();
}

Ui::~Ui() {
  clear();
  endwin();
}

void Ui::display() {
  for (const auto& pane : pane_) {
    pane->draw();
  }
  tray_->draw();
  doupdate();
}

void Ui::handleEvent(const Event& event) {
  switch (event.type()) {
    case Event::Type::nextMode:
      selectNextMode();
      if (currentMode_ == Mode::browse) {
        Pkg::instance().resetFilter();
        updatePanes();
      }
      updateTray();
    break;

    case Event::Type::select: {
      if (!Pkg::instance().isRepositoryEmpty()) {
        if (gotCategorySelected()) {
          std::string category = getSelectedItemName();
          toggleCategoryFolding(category);
          updatePanes();
        } else {
          registerPkgChange(event.type());
          updatePkgListPane();
        }
      }
      break;
    }

    case Event::Type::deselect:
      if (!Pkg::instance().isRepositoryEmpty()) {
        registerPkgChange(event.type());
        updatePkgListPane();
      }
      break;

    case Event::Type::keyUp:
    case Event::Type::keyDown:
    case Event::Type::pageUp:
    case Event::Type::pageDown:
      if (!Pkg::instance().isRepositoryEmpty()) {
        if (event.type() == Event::Type::keyUp) {
          pane_[pkgList]->moveCursorUp();
        } else if (event.type() == Event::Type::keyDown) {
          pane_[pkgList]->moveCursorDown();
        }
        // XXX Implement scroll up and down
        updatePkgDescrPane();
      }
      break;

    case Event::Type::keyShiftUp:
    case Event::Type::keyShiftDown:
      if (!Pkg::instance().isRepositoryEmpty()) {
        if (event.type() == Event::Type::keyShiftUp) {
          pane_[pkgDescr]->moveCursorUp();
        } else if (event.type() == Event::Type::keyShiftDown) {
          pane_[pkgDescr]->moveCursorDown();
        }
        updatePkgDescrPane();
      }
      break;

    case Event::Type::character:
      switch (currentMode_) {
      case Mode::browse :
        // DO NOTHING
        break;
      case Mode::search :
        pane_[pkgList]->resetCursorPosition();
        promptSearch(event.character());
        updatePanes();
        break;
      case Mode::filter :
        pane_[pkgList]->resetCursorPosition();
        promptFilter(event.character());
        updatePanes();
        break;
      }
      break;

    case Event::Type::go:
      if (!Pkg::instance().gotRootPrivileges()) {
        gfx::Popup("Insufficient privileges, please retry as root", gfx::Popup::Type::warning);
      } else {
        performPending();
        closeAllFolds();
        updatePkgListPane();
      }
      break;

    case Event::Type::redraw:
      display();
      break;

    default:
      break;
  }
}

/*
    +------------------------------+
    |                              | \
    |                              | |
    |                              | | pane_[pkgList]
    |                              | |
    |                              | /
    +------------------------------+
    |                              | \ <-- comment
    |                              | |
    |                              | / pane_[pkgDescr]
    +------------------------------+
 */
void Ui::createInterface() {
  int pkgPaneHeight = LINES * .6;
  int descrPaneHeight = LINES - pkgPaneHeight - 1;

  gfx::Size listSize, descrSize;
  listSize.setWidth(COLS);
  listSize.setHeight(pkgPaneHeight);
  descrSize.setWidth(COLS);
  descrSize.setHeight(descrPaneHeight);

  gfx::Point listPos, descrPos;
  descrPos.setY(pkgPaneHeight);

  pane_[pkgList] = std::unique_ptr<gfx::Pane>(new gfx::Pane(listSize, listPos));
  pane_[pkgDescr] = std::unique_ptr<gfx::Pane>(new gfx::Pane(descrSize, descrPos));
  pane_[pkgDescr]->borders(false);
  pane_[pkgDescr]->cursorLineHighlight(false);

  gfx::Point trayPos;
  trayPos.setY(pkgPaneHeight);
  trayPos.setX(COLS / 2);
  tray_ = std::unique_ptr<gfx::Tray>(new gfx::Tray(trayPos, Mode::nbModes));
}

void Ui::updatePanes() {
  if (Pkg::instance().isRepositoryEmpty()) {
    for (auto& pane : pane_) {
      pane->clear();
      pane->resetCursorPosition();
    }
  } else {
    updatePkgListPane();
    updatePkgDescrPane();
  }
}

void Ui::buildPkgList() {
  pkgList_.clear();
  std::vector<std::string> categories = Pkg::instance().getPkgCategories();
  for (const auto& category : categories) {
    pkgList_.push_back({pkgListItemType::category, category});
    if (!isCategoryFolded(category)) {
      std::vector<std::string> origins = Pkg::instance().getPkgOrigins(category);
      for (const auto& origin : origins) {
        pkgList_.push_back({pkgListItemType::pkg, origin});
      }
    }
  }
}

// Build a hierarchy of categories and ports:
//
// ---- category1
// ---\ category2
// -    port1
// +    port2
// ---- category3
void Ui::updatePkgListPane() {
  buildPkgList();
  pane_[pkgList]->clear();
  for (const auto& item : pkgList_) {
    switch (item.type) {
    case pkgListItemType::category: {
      std::string categoryString = getStringForCategory(item.name);
      pane_[pkgList]->print(categoryString);
    }
    break;
    case pkgListItemType::pkg: {
      std::string pkgString = getStringForPkg(item.name);
      pane_[pkgList]->print(pkgString);
      std::string pkgVersions = getVersionsForPkg(item.name);
      pane_[pkgList]->print(pkgVersions, gfx::Pane::Align::right);
      //if (Pkg::instance().hasPendingActions(item.name)) {
        // XXX change attributes
        //pane_[pkgList].addRowAttributes(dataGrid.height() - 1, gfx::ATTR_BOLD);
      //}
    }
    break;
    default:
      break;
    }
    pane_[pkgList]->newline();
  }
}

void Ui::updatePkgDescrPane() {
  pane_[pkgDescr]->clear();

  if (!gotCategorySelected()) {
    std::string origin = getSelectedItemName();
    std::string comment = Pkg::instance().getPkgAttr(origin, Pkg::Attr::comment);
    pane_[pkgDescr]->print(comment);
    pane_[pkgDescr]->colorizeCurrentLine(1);

    std::string desc = Pkg::instance().getPkgAttr(origin, Pkg::Attr::description);
    std::stringstream commentStream(desc);
    std::string descLine;
    while (std::getline(commentStream, descLine, '\n')) {
      pane_[pkgDescr]->newline();
      pane_[pkgDescr]->print(descLine);
    }
  }

  //pane_[pkgDescr].requestRefresh();
}

const Ui::pkgListItem& Ui::getCurrentPkgListItem() const {
  int index = pane_[pkgList]->getCursorRowNum();
  return pkgList_[index];
}

std::string Ui::getSelectedItemName() const {
  const pkgListItem& item = getCurrentPkgListItem();
  return item.name;
}

bool Ui::gotCategorySelected() {
  const pkgListItem& item = getCurrentPkgListItem();
  return isCategory(item);
}

bool Ui::isCategory(const pkgListItem& item) const {
  return item.type == pkgListItemType::category;
}

void Ui::toggleCategoryFolding(const std::string& category) {
  if (unfolded_.find(category) != unfolded_.end()) {
    unfolded_[category] = unfolded_[category] == true ? false : true;
  } else {
    unfolded_[category] = true;
  }
}

void Ui::closeAllFolds() {
  unfolded_.clear();
  pane_[pkgList]->resetCursorPosition();
}

void Ui::registerPkgChange(Event::Type event) {
  if (!gotCategorySelected()) {
    std::string origin = getSelectedItemName();

    switch (event) {
      case Event::Type::select:
        Pkg::instance().registerInstall(origin);
        break;

      case Event::Type::deselect:
        Pkg::instance().registerRemoval(origin);
        break;

      default:
        break;
    }
  }
}

void Ui::performPending() {
  busy_ = true;
  // XXX implement busy status
//  std::thread uiHint([this]() {busyStatus(pane_[pkgList]);});
//  uiHint.detach();

  std::thread pendingActions(&Pkg::performPending, &Pkg::instance());
  pendingActions.join();
  busy_ = false;
//  pane_[pkgList].clearStatus();
}

void Ui::promptFilter(int character) {
  switch (character) {
  case 'n':
    Pkg::instance().resetFilter();
    break;

  case 'i':
  case '+':
//          pane_[pkgList].status("Installed");
    Pkg::instance().filterInstalled();
    break;

  case '-':
  case 'a':
//          pane_[pkgList].status("Available");
    Pkg::instance().filterAvailable();
    break;

  case 'p':
//          pane_[pkgList].status("Pending");
    Pkg::instance().filterPending();
    break;

  case 'u':
//          pane_[pkgList].status("Upgradable");
    Pkg::instance().filterUpgradable();
    break;

  default:
    // DO NOTHING
    break;
  }
}

void Ui::promptSearch(int character) const {
  gfx::Point pos = gfx::Point::Label::center;
  gfx::Prompt prompt(pos, 40);
  prompt.setContent(std::string(1, static_cast<char>(character)));
  std::string query = prompt.getInput();
  Pkg::instance().search(query);
  pane_[pkgList]->clearStatus();
  pane_[pkgList]->printStatus(query, 2);
}

  // XXX implement busy status
void Ui::setBusyStatus(gfx::Pane& pane, const std::string& status) {
  /*
  pane.status(status);
  pane.refreshStatus();
  std::this_thread::sleep_for(std::chrono::milliseconds(500));
  */
}

void Ui::busyStatus(gfx::Pane& pane) {
  /*
  while (busy_) {
    setBusyStatus(pane, "Please wait.  ");
    if (!busy_)
      return;
    setBusyStatus(pane, "Please wait.. ");
    if (!busy_)
      return;
    setBusyStatus(pane, "Please wait...");
    if (!busy_)
      return;
    setBusyStatus(pane, "Please wait ..");
    if (!busy_)
      return;
    setBusyStatus(pane, "Please wait  .");
    if (!busy_)
      return;
  }
  */
}

void Ui::warningStatus(gfx::Pane& pane, const std::string& status) {
  /*
  std::string oldStatus = pane.getStatus();
  pane.status(status, gfx::color::RED);
  pane.refreshStatus();
  std::this_thread::sleep_for(std::chrono::milliseconds(1500));
  pane.status(oldStatus);
  pane.requestRefresh();
  */
}

bool Ui::isCategoryFolded(const std::string& category) const {
  return unfolded_.find(category) == unfolded_.end() || unfolded_.at(category) == false;
}

std::string Ui::getStringForCategory(const std::string& category) const {
  std::string categoryString(markerCategory);
  if (isCategoryFolded(category)) {
    categoryString.append(markerFolded);
  } else {
    categoryString.append(markerUnfolded);
  }
  categoryString.append(" ");
  categoryString.append(category);
  categoryString.append(" (");
  categoryString.append(std::to_string(Pkg::instance().getCategorySize(category)));
  categoryString.append(")");

  return categoryString;
}

std::string Ui::getStringForPkg(const std::string& origin) const {
  std::string pkgString = Pkg::instance().getCurrentStatusAsString(origin);
  if (Pkg::instance().hasPendingActions(origin)) {
    pkgString.append("[");
    pkgString.append(Pkg::instance().getPendingStatusAsString(origin));
    pkgString.append("] ");
  } else if (Pkg::instance().isUpgradable(origin)) {
    pkgString.append("[^] ");
  } else {
    pkgString.append("    ");
  }
  pkgString.append(Pkg::instance().getNameFromOrigin(origin));

  return pkgString;
}

std::string Ui::getVersionsForPkg(const std::string& origin) const {
  std::string pkgVersions = Pkg::instance().getLocalVersion(origin);
  if (!pkgVersions.empty()) {
    pkgVersions.append("    ");
  }
  pkgVersions.append(Pkg::instance().getRemoteVersion(origin));

  return pkgVersions;
}

void Ui::selectNextMode() {
  ++currentMode_;
  if (currentMode_ == Mode::nbModes) {
    currentMode_ = 0;
  }
}

void Ui::updateTray() {
  tray_->selectSlot(currentMode_);
  gfx::Point center;
  center.setX(COLS / 2);
  center.setY(pane_[pkgList]->size().height() - 4);
  gfx::Popup(modeName_[currentMode_], gfx::Popup::Type::brief, center);
}

}
<|endoftext|>


<commit_before>/******************************************************************************
 * Copyright 2017 The Apollo Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/

#include "modules/drivers/canbus/can_client/can_client_factory.h"

#include "modules/drivers/canbus/can_client/fake/fake_can_client.h"
#if USE_ESD_CAN
#include "modules/drivers/canbus/can_client/esd/esd_can_client.h"
#endif

#include "modules/drivers/canbus/can_client/socket/socket_can_client_raw.h"

#include "modules/common/log.h"
#include "modules/common/util/util.h"

namespace apollo {
namespace drivers {
namespace canbus {

CanClientFactory::CanClientFactory() {}

void CanClientFactory::RegisterCanClients() {
  AINFO << "CanClientFactory::RegisterCanClients";
  Register(CANCardParameter::FAKE_CAN,
           []() -> CanClient* { return new can::FakeCanClient(); });
#if USE_ESD_CAN
  AINFO << "register can: " << CANCardParameter::ESD_CAN;
  Register(CANCardParameter::ESD_CAN,
           []() -> CanClient* { return new can::EsdCanClient(); });
#endif
  Register(CANCardParameter::SOCKET_CAN_RAW,
           []() -> CanClient* { return new can::SocketCanClientRaw(); });
}

std::unique_ptr<CanClient> CanClientFactory::CreateCANClient(
    const CANCardParameter& parameter) {
  auto factory = CreateObject(parameter.brand());
  if (!factory) {
    AERROR << "Failed to create CAN client with parameter: "
           << parameter.DebugString();
  } else if (!factory->Init(parameter)) {
    AERROR << "Failed to initialize CAN card with parameter: "
           << parameter.DebugString();
  }
  return factory;
}

}  // namespace canbus
}  // namespace drivers
}  // namespace apollo
<commit_msg>Canbus : fix hermes can<commit_after>/******************************************************************************
 * Copyright 2017 The Apollo Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/

#include "modules/drivers/canbus/can_client/can_client_factory.h"

#include "modules/drivers/canbus/can_client/fake/fake_can_client.h"
#if USE_ESD_CAN
#include "modules/drivers/canbus/can_client/esd/esd_can_client.h"
#endif

#include "modules/drivers/canbus/can_client/socket/socket_can_client_raw.h"

#include "modules/drivers/canbus/can_client/hermes_can/hermes_can_client.h"

#include "modules/common/log.h"
#include "modules/common/util/util.h"

namespace apollo {
namespace drivers {
namespace canbus {

CanClientFactory::CanClientFactory() {}

void CanClientFactory::RegisterCanClients() {
  AINFO << "CanClientFactory::RegisterCanClients";
  Register(CANCardParameter::FAKE_CAN,
           []() -> CanClient* { return new can::FakeCanClient(); });
#if USE_ESD_CAN
  AINFO << "register can: " << CANCardParameter::ESD_CAN;
  Register(CANCardParameter::ESD_CAN,
           []() -> CanClient* { return new can::EsdCanClient(); });
#endif
  Register(CANCardParameter::SOCKET_CAN_RAW,
           []() -> CanClient* { return new can::SocketCanClientRaw(); });

  Register(CANCardParameter::SOCKET_CAN_RAW,
           []() -> CanClient* { return new can::HermesCanClient(); });
}

std::unique_ptr<CanClient> CanClientFactory::CreateCANClient(
    const CANCardParameter& parameter) {
  auto factory = CreateObject(parameter.brand());
  if (!factory) {
    AERROR << "Failed to create CAN client with parameter: "
           << parameter.DebugString();
  } else if (!factory->Init(parameter)) {
    AERROR << "Failed to initialize CAN card with parameter: "
           << parameter.DebugString();
  }
  return factory;
}

}  // namespace canbus
}  // namespace drivers
}  // namespace apollo
<|endoftext|>


<commit_before>#include "CLSHPlasticMaterial.h"

#include "SymmIsotropicElasticityTensor.h"
#include <cmath>

template<>
InputParameters validParams<CLSHPlasticMaterial>()
{
   InputParameters params = validParams<SolidModel>();
   params.addRequiredParam<Real>("yield_stress", "The point at which plastic strain begins accumulating");
   params.addRequiredParam<Real>("hardening_constant", "Hardening slope");
   params.addRequiredParam<Real>("c_alpha", "creep constant");
   params.addRequiredParam<Real>("c_beta", "creep constant");
   params.addParam<Real>("tolerance", 1e-5, "Sub-BiLin iteration tolerance");
   params.addParam<unsigned int>("max_its", 10, "Maximum number of Sub-newton iterations");
   params.addParam<bool>("print_debug_info", false, "Whether or not to print debugging information");
   return params;
}

CLSHPlasticMaterial::CLSHPlasticMaterial(std::string name,
                                         InputParameters parameters)
  :SolidModel(name, parameters),
   _yield_stress(parameters.get<Real>("yield_stress")),
   _hardening_constant(parameters.get<Real>("hardening_constant")),
   _c_alpha(parameters.get<Real>("c_alpha")),
   _c_beta(parameters.get<Real>("c_beta")),
   _tolerance(parameters.get<Real>("tolerance")),
   _max_its(parameters.get<unsigned int>("max_its")),
   _print_debug_info(getParam<bool>("print_debug_info")),
   _hardening_variable(declareProperty<Real>("hardening_variable")),
   _hardening_variable_old(declarePropertyOld<Real>("hardening_variable")),
   _plastic_strain(declareProperty<SymmTensor>("plastic_strain")),
   _plastic_strain_old(declarePropertyOld<SymmTensor>("plastic_strain"))
{
  _shear_modulus = _youngs_modulus / ((2*(1+_poissons_ratio)));

  _ebulk3 = _youngs_modulus/(1. - 2.*_poissons_ratio);

  _K = _ebulk3/3.;

}

void
CLSHPlasticMaterial::initQpStatefulProperties()
{
  _hardening_variable[_qp] = 0;
  SolidModel::initQpStatefulProperties();
}

void
CLSHPlasticMaterial::computeStress()
{
// trial stress
  SymmTensor trial_stress = *elasticityTensor() * _strain_increment;
  trial_stress += _stress_old;

// deviatoric trial stress
  SymmTensor dev_trial_stress(trial_stress);
  dev_trial_stress.addDiag( -trial_stress.trace()/3.0 );
// effective trial stress
  Real dts_squared = dev_trial_stress.doubleContraction(dev_trial_stress);
  Real effective_trial_stress = std::sqrt(1.5 * dts_squared);

// determine if yield condition is satisfied
  Real yield_condition = effective_trial_stress - _hardening_variable_old[_qp] - _yield_stress;

  if (yield_condition > 0.)  //then use newton iteration to determine effective plastic strain increment
  {
    unsigned int it = 0;
    Real plastic_residual = 10.;
    Real plastic_strain_increment = 0.;
    Real norm_residual = 10.;
    Real xflow = 1.;
    Real xphi = 1.;
    Real xphidp = 1.;
    Real xphir = 1.;
    Real xresidual = 1.;

    while(it < _max_its && norm_residual > _tolerance)
    {
      xflow = _c_beta*(effective_trial_stress - (3. * _shear_modulus * plastic_strain_increment) - _hardening_variable[_qp] - _yield_stress);
      xphi = _c_alpha*std::sinh(xflow);
      xphidp = -3.*_shear_modulus*_c_alpha*_c_beta*std::cosh(xflow);
      xphir = -_c_alpha*_c_beta*std::cosh(xflow);
      xresidual = xphi - (plastic_strain_increment/_dt);
      plastic_residual = xresidual/((1./_dt) - xphidp - (_hardening_constant*xphir));

      norm_residual = std::abs(plastic_residual);

      plastic_strain_increment = plastic_strain_increment + plastic_residual;

      _hardening_variable[_qp] = _hardening_variable_old[_qp] + (_hardening_constant * plastic_strain_increment);
      it++;

    }

    if(it == _max_its)
      mooseError("Max sub-newton iteration hit during plasticity increment solve!");

    SymmTensor matrix_plastic_strain_increment(dev_trial_stress);
    matrix_plastic_strain_increment *= (1.5*plastic_strain_increment/effective_trial_stress);

    _strain_increment -= matrix_plastic_strain_increment;

    // update stress and plastic strain
    // compute stress increment
    _stress[_qp] =  *elasticityTensor() * _strain_increment;
    _stress[_qp] += _stress_old;

    // update plastic strain
    _plastic_strain[_qp] = matrix_plastic_strain_increment;
    _plastic_strain[_qp] += _plastic_strain_old[_qp];

    _Jacobian_mult[_qp] = *elasticityTensor();

//end of if
  }

  else
  {
    // update stress and plastic strain
    _stress[_qp] = *elasticityTensor() * _strain_increment;
    _stress[_qp] += _stress_old;

    _hardening_variable[_qp] = 0.0;
    _plastic_strain[_qp].zero();
    _Jacobian_mult[_qp] = *elasticityTensor();
  }

}

<commit_msg>Minor cleanup<commit_after>#include "CLSHPlasticMaterial.h"

#include "SymmIsotropicElasticityTensor.h"
#include <cmath>

template<>
InputParameters validParams<CLSHPlasticMaterial>()
{
   InputParameters params = validParams<SolidModel>();
   params.addRequiredParam<Real>("yield_stress", "The point at which plastic strain begins accumulating");
   params.addRequiredParam<Real>("hardening_constant", "Hardening slope");
   params.addRequiredParam<Real>("c_alpha", "creep constant");
   params.addRequiredParam<Real>("c_beta", "creep constant");
   params.addParam<Real>("tolerance", 1e-5, "Sub-BiLin iteration tolerance");
   params.addParam<unsigned int>("max_its", 10, "Maximum number of Sub-newton iterations");
   params.addParam<bool>("print_debug_info", false, "Whether or not to print debugging information");
   return params;
}

CLSHPlasticMaterial::CLSHPlasticMaterial(std::string name,
                                         InputParameters parameters)
  :SolidModel(name, parameters),
   _yield_stress(parameters.get<Real>("yield_stress")),
   _hardening_constant(parameters.get<Real>("hardening_constant")),
   _c_alpha(parameters.get<Real>("c_alpha")),
   _c_beta(parameters.get<Real>("c_beta")),
   _tolerance(parameters.get<Real>("tolerance")),
   _max_its(parameters.get<unsigned int>("max_its")),
   _print_debug_info(getParam<bool>("print_debug_info")),
   _hardening_variable(declareProperty<Real>("hardening_variable")),
   _hardening_variable_old(declarePropertyOld<Real>("hardening_variable")),
   _plastic_strain(declareProperty<SymmTensor>("plastic_strain")),
   _plastic_strain_old(declarePropertyOld<SymmTensor>("plastic_strain"))
{
  _shear_modulus = _youngs_modulus / ((2*(1+_poissons_ratio)));

  _ebulk3 = _youngs_modulus/(1. - 2.*_poissons_ratio);

  _K = _ebulk3/3.;

}

void
CLSHPlasticMaterial::initQpStatefulProperties()
{
  _hardening_variable[_qp] = 0;
  SolidModel::initQpStatefulProperties();
}

void
CLSHPlasticMaterial::computeStress()
{
// trial stress
  SymmTensor trial_stress = *elasticityTensor() * _strain_increment;
  trial_stress += _stress_old;

// deviatoric trial stress
  SymmTensor dev_trial_stress(trial_stress);
  dev_trial_stress.addDiag( -trial_stress.trace()/3.0 );
// effective trial stress
  Real dts_squared = dev_trial_stress.doubleContraction(dev_trial_stress);
  Real effective_trial_stress = std::sqrt(1.5 * dts_squared);

// determine if yield condition is satisfied
  Real yield_condition = effective_trial_stress - _hardening_variable_old[_qp] - _yield_stress;

  if (yield_condition > 0.)  //then use newton iteration to determine effective plastic strain increment
  {
    unsigned int it = 0;
    Real plastic_residual = 10.;
    Real plastic_strain_increment = 0.;
    Real norm_residual = 10.;
    Real xflow = 1.;
    Real xphi = 1.;
    Real xphidp = 1.;
    Real xphir = 1.;
    Real xresidual = 1.;

    while(it < _max_its && norm_residual > _tolerance)
    {
      xflow = _c_beta*(effective_trial_stress - (3. * _shear_modulus * plastic_strain_increment) - _hardening_variable[_qp] - _yield_stress);
      xphi = _c_alpha*std::sinh(xflow);
      xphidp = -3.*_shear_modulus*_c_alpha*_c_beta*std::cosh(xflow);
      xphir = -_c_alpha*_c_beta*std::cosh(xflow);
      xresidual = xphi - (plastic_strain_increment/_dt);
      plastic_residual = xresidual/((1./_dt) - xphidp - (_hardening_constant*xphir));

      norm_residual = std::abs(plastic_residual);

      plastic_strain_increment = plastic_strain_increment + plastic_residual;

      _hardening_variable[_qp] = _hardening_variable_old[_qp] + (_hardening_constant * plastic_strain_increment);
      it++;

    }

    if(it == _max_its)
      mooseError("Max sub-newton iteration hit during plasticity increment solve!");

    SymmTensor matrix_plastic_strain_increment(dev_trial_stress);
    matrix_plastic_strain_increment *= (1.5*plastic_strain_increment/effective_trial_stress);

    _strain_increment -= matrix_plastic_strain_increment;

    // update stress and plastic strain
    // compute stress increment
    _stress[_qp] =  *elasticityTensor() * _strain_increment;
    _stress[_qp] += _stress_old;

    // update plastic strain
    _plastic_strain[_qp] = matrix_plastic_strain_increment;
    _plastic_strain[_qp] += _plastic_strain_old[_qp];

    _Jacobian_mult[_qp] = *elasticityTensor();

//end of if
  }

  else
  {
    // update stress and plastic strain
    _stress[_qp] = trial_stress;

    _hardening_variable[_qp] = 0.0;
    _plastic_strain[_qp].zero();
    _Jacobian_mult[_qp] = *elasticityTensor();
  }

}
<|endoftext|>