<commit_before>//
// Matirx.hpp
// ~~~~~~~~~~
//
// Copyright (c) 2014 Rick Yang (rick68 at gmail dot com)
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
//

#ifndef EIGENJS_MATRIX_HPP
#define EIGENJS_MATRIX_HPP

#include <node.h>
#include <v8.h>

#include <nan.h>

#include <eigen3/Eigen/Dense>

#include <sstream>

#define EIGENJS_MATRIX_BINARY_OPERATOR( NAME, OP )                             \
static NAN_METHOD( NAME ) {                                                    \
  const Matrix* obj = node::ObjectWrap::Unwrap<Matrix>( args.This() );         \
  NanScope();                                                                  \
                                                                               \
  if ( args.Length() == 1 && HasInstance( args[0] ) ) {                        \
    const Matrix* rhs_obj =                                                    \
        node::ObjectWrap::Unwrap<Matrix>( args[0]->ToObject() );               \
                                                                               \
    if ( is_nonconformate_arguments( obj, rhs_obj ) ) {                        \
      NanReturnUndefined();                                                    \
    }                                                                          \
                                                                               \
    const typename matrix_type::Index& rows = obj->matrix_.rows();             \
    const typename matrix_type::Index& cols = obj->matrix_.cols();             \
                                                                               \
    v8::Local<v8::Function> ctr = NanNew( constructor );                       \
    v8::Local<v8::Value> argv[] = {                                            \
        NanNew<v8::Integer>( rows )                                            \
      , NanNew<v8::Integer>( cols )                                            \
    };                                                                         \
                                                                               \
    v8::Local<v8::Object> new_matrix = ctr->NewInstance(                       \
        sizeof( argv ) / sizeof( v8::Local<v8::Value> )                        \
      , argv                                                                   \
    );                                                                         \
                                                                               \
    Matrix* new_obj = node::ObjectWrap::Unwrap<Matrix>( new_matrix );          \
    new_obj->matrix_ = obj->matrix_ OP rhs_obj->matrix_;                       \
                                                                               \
    NanReturnValue( new_matrix );                                              \
  }                                                                            \
                                                                               \
  NanReturnUndefined();                                                        \
}                                                                              \
/**/

#define EIGENJS_MATRIX_BINARY_OPERATOR_COMMUTATIVE( NAME, OP )                 \
static NAN_METHOD( NAME ) {                                                    \
  Matrix* obj = node::ObjectWrap::Unwrap<Matrix>( args.This() );               \
  NanScope();                                                                  \
                                                                               \
  if ( args.Length() == 1 && HasInstance( args[0] ) ) {                        \
    const Matrix* rhs_obj =                                                    \
        node::ObjectWrap::Unwrap<Matrix>( args[0]->ToObject() );               \
                                                                               \
    if ( is_nonconformate_arguments( obj, rhs_obj ) ) {                        \
      NanReturnUndefined();                                                    \
    }                                                                          \
                                                                               \
    obj->matrix_ OP##= rhs_obj->matrix_;                                       \
                                                                               \
    NanReturnValue( args.This() );                                             \
  }                                                                            \
                                                                               \
  NanReturnUndefined();                                                        \
}                                                                              \
/**/

namespace EigenJS {

template <typename ValueType, const char* ClassName>
class Matrix : public node::ObjectWrap {
  typedef ValueType element_type;

  typedef Eigen::Matrix<
      element_type
    , Eigen::Dynamic
    , Eigen::Dynamic
  > matrix_type;

 public:
  static void Init(v8::Handle<v8::Object> exports) {
    NanScope();

    v8::Local<v8::FunctionTemplate> tpl = NanNew<v8::FunctionTemplate>(New);
    tpl->SetClassName(NanNew(ClassName));
    tpl->InstanceTemplate()->SetInternalFieldCount(1);

    NODE_SET_PROTOTYPE_METHOD(tpl, "rows", rows);
    NODE_SET_PROTOTYPE_METHOD(tpl, "cols", cols);
    NODE_SET_PROTOTYPE_METHOD(tpl, "set", set);
    NODE_SET_PROTOTYPE_METHOD(tpl, "get", get);

    NODE_SET_PROTOTYPE_METHOD(tpl, "add", add);
    NODE_SET_PROTOTYPE_METHOD(tpl, "adda", adda);
    NODE_SET_PROTOTYPE_METHOD(tpl, "sub", sub);
    NODE_SET_PROTOTYPE_METHOD(tpl, "suba", suba);

    NODE_SET_PROTOTYPE_METHOD(tpl, "mul", mul);
    NODE_SET_PROTOTYPE_METHOD(tpl, "mula", mula);

    NODE_SET_PROTOTYPE_METHOD(tpl, "div", div);
    NODE_SET_PROTOTYPE_METHOD(tpl, "diva", diva);

    NODE_SET_PROTOTYPE_METHOD(tpl, "toString", toString);

    NanAssignPersistent(constructor, tpl->GetFunction());
    exports->Set(NanNew(ClassName), tpl->GetFunction());

    NanAssignPersistent(function_template, tpl);
  }

  static NAN_METHOD(rows) {
    const Matrix* obj = node::ObjectWrap::Unwrap<Matrix>(args.This());
    NanScope();

    NanReturnValue(NanNew<v8::Integer>(obj->matrix_.rows()));
  }

  static NAN_METHOD(cols) {
    const Matrix* obj = node::ObjectWrap::Unwrap<Matrix>(args.This());
    NanScope();

    NanReturnValue(NanNew<v8::Integer>(obj->matrix_.cols()));
  }

  static NAN_METHOD(set) {
    Matrix* obj = node::ObjectWrap::Unwrap<Matrix>(args.This());
    NanScope();

    if (args.Length() == 1 && args[0]->IsArray()) {
      v8::Local<v8::Array> array = args[0].As<v8::Array>();
      uint32_t len = array->Length();
      const typename matrix_type::Index& rows = obj->matrix_.rows();
      const typename matrix_type::Index& cols = obj->matrix_.cols();
      const typename matrix_type::Index& elems = rows * cols;

      if (len != elems) {
        len < rows * cols
          ? NanThrowError("Too few coefficients passed to Matrix")
          : NanThrowError("Too many coefficients passed to Matrix");
        NanReturnUndefined();
      }

      for (uint32_t i = 0; i < len; ++i) {
        v8::Local<v8::Value> elem = array->Get(i);
        obj->matrix_(i / cols, i % cols) = elem->NumberValue();
      }
    } else if (
        args.Length() == 3 &&
        args[0]->IsNumber() &&
        args[1]->IsNumber() &&
        args[2]->IsNumber()) {
      const typename matrix_type::Index& row = args[0]->Uint32Value();
      const typename matrix_type::Index& col = args[1]->Uint32Value();
      const element_type& value = args[2]->NumberValue();

      if (is_out_of_range(obj->matrix_, row, col))
        NanReturnUndefined();

      obj->matrix_(row, col) = value;
    }

    NanReturnValue(args.This());
  }

  static NAN_METHOD(get) {
    const Matrix* obj = node::ObjectWrap::Unwrap<Matrix>(args.This());
    NanScope();

    if (args.Length() == 2 &&
        args[0]->IsNumber() &&
        args[1]->IsNumber()) {
      typename matrix_type::Index row = args[0]->Uint32Value();
      typename matrix_type::Index col = args[1]->Uint32Value();

      if (is_out_of_range(obj->matrix_, row, col))
        NanReturnUndefined();

      element_type value = obj->matrix_(row, col);
      NanReturnValue(NanNew(value));
    }

    NanReturnUndefined();
  }

  EIGENJS_MATRIX_BINARY_OPERATOR(add, +)
  EIGENJS_MATRIX_BINARY_OPERATOR_COMMUTATIVE(adda, +)

  EIGENJS_MATRIX_BINARY_OPERATOR(sub, -)
  EIGENJS_MATRIX_BINARY_OPERATOR_COMMUTATIVE(suba, -)

  static NAN_METHOD(mul) {
    const Matrix* obj = node::ObjectWrap::Unwrap<Matrix>( args.This() );
    const typename matrix_type::Index& rows = obj->matrix_.rows();
    const typename matrix_type::Index& cols = obj->matrix_.cols();
    NanScope();

    if (args.Length() == 1 && HasInstance(args[0])) {
      const Matrix* rhs_obj =
          node::ObjectWrap::Unwrap<Matrix>(args[0]->ToObject());

      if (is_invalid_matrix_product(obj, rhs_obj)) {
        NanReturnUndefined();
      }

      v8::Local<v8::Function> ctr = NanNew(constructor);
      v8::Local<v8::Value> argv[] = {
          NanNew<v8::Integer>(rows)
        , NanNew<v8::Integer>(cols)
      };

      v8::Local<v8::Object> new_matrix = ctr->NewInstance(
          sizeof(argv) / sizeof(v8::Local<v8::Value>)
        , argv
      );

      Matrix* new_obj = node::ObjectWrap::Unwrap<Matrix>(new_matrix);
      new_obj->matrix_ = obj->matrix_ * rhs_obj->matrix_;

      NanReturnValue(new_matrix);
    } else if (args.Length() == 1 && args[0]->IsNumber()) {
      v8::Local<v8::Function> ctr = NanNew(constructor);
      v8::Local<v8::Value> argv[] = {
          NanNew<v8::Integer>(rows)
        , NanNew<v8::Integer>(cols)
      };

      v8::Local<v8::Object> new_matrix = ctr->NewInstance(
          sizeof(argv) / sizeof(v8::Local<v8::Value>)
        , argv
      );

      Matrix* new_obj = node::ObjectWrap::Unwrap<Matrix>(new_matrix);
      new_obj->matrix_ = obj->matrix_ * args[0]->NumberValue();

      NanReturnValue(new_matrix);
    }

    NanReturnUndefined();
  }

  static NAN_METHOD(mula) {
    Matrix* obj = node::ObjectWrap::Unwrap<Matrix>(args.This());
    NanScope();

    if (args.Length() == 1 && HasInstance(args[0])) {
      const Matrix* rhs_obj =
          node::ObjectWrap::Unwrap<Matrix>(args[0]->ToObject());

      if (is_invalid_matrix_product(obj, rhs_obj)) {
        NanReturnUndefined();
      }

      obj->matrix_ *= rhs_obj->matrix_;

      NanReturnValue(args.This());
    } else if (args.Length() == 1 && args[0]->IsNumber()) {
      obj->matrix_ *= args[0]->NumberValue();

      NanReturnValue(args.This());
    }

    NanReturnUndefined();
  }

  static NAN_METHOD(div) {
    const Matrix* obj = node::ObjectWrap::Unwrap<Matrix>( args.This() );
    const typename matrix_type::Index& rows = obj->matrix_.rows();
    const typename matrix_type::Index& cols = obj->matrix_.cols();
    NanScope();

    if (args.Length() == 1 && args[0]->IsNumber()) {
      v8::Local<v8::Function> ctr = NanNew(constructor);
      v8::Local<v8::Value> argv[] = {
          NanNew<v8::Integer>(rows)
        , NanNew<v8::Integer>(cols)
      };

      v8::Local<v8::Object> new_matrix = ctr->NewInstance(
          sizeof(argv) / sizeof(v8::Local<v8::Value>)
        , argv
      );

      Matrix* new_obj = node::ObjectWrap::Unwrap<Matrix>(new_matrix);
      new_obj->matrix_ = obj->matrix_ / args[0]->NumberValue();

      NanReturnValue(new_matrix);
    }

    NanReturnUndefined();
  }

  static NAN_METHOD(diva) {
    Matrix* obj = node::ObjectWrap::Unwrap<Matrix>(args.This());
    NanScope();

    if (args.Length() == 1 && args[0]->IsNumber()) {
      obj->matrix_ /= args[0]->NumberValue();

      NanReturnValue(args.This());
    }

    NanReturnUndefined();
  }

  static NAN_METHOD(toString) {
    const Matrix* obj = node::ObjectWrap::Unwrap<Matrix>(args.This());
    NanScope();

    std::ostringstream result;
    result << obj->matrix_;

    NanReturnValue(NanNew(result.str().c_str()));
  }

 private:
  Matrix(
      const typename matrix_type::Index& rows
    , const typename matrix_type::Index& cols)
    : matrix_(matrix_type::Zero(rows, cols))
  {}
  ~Matrix() {}

  static NAN_METHOD(New) {
    NanScope();

    if (args.Length() < 2) {
      NanThrowError("Tried creating matrix without rows and columns arguments");
      NanReturnUndefined();
    }

    if (args.IsConstructCall()) {
      typename matrix_type::Index rows = args[0]->Uint32Value();
      typename matrix_type::Index columns = args[1]->Uint32Value();
      Matrix* obj = new Matrix(rows, columns);
      obj->Wrap(args.This());
      NanReturnValue(args.This());
    } else {
      v8::Local<v8::Function> ctr = NanNew(constructor);
      v8::Local<v8::Value> argv[] = {args[0], args[1]};
      NanReturnValue(
        ctr->NewInstance(
            sizeof(argv) / sizeof(v8::Local<v8::Value>)
          , argv
        )
      );
    }
  }

  static bool HasInstance(const v8::Handle<v8::Value>& value) {
    NanScope();
    v8::Local<v8::FunctionTemplate> tpl = NanNew(function_template);
    return tpl->HasInstance(value);
  }

  static v8::Persistent<v8::FunctionTemplate> function_template;
  static v8::Persistent<v8::Function> constructor;

 private:
  static bool is_out_of_range(
      const matrix_type& matrix
    , const typename matrix_type::Index& row
    , const typename matrix_type::Index& col) {
    return row < 0 || row >= matrix.rows() || col < 0 || col >= matrix.cols()
      ? NanThrowError("Row or column numbers are out of range"), true
      : false;
  }

  static bool is_nonconformate_arguments(
      const Matrix* const& op1
    , const Matrix* const& op2) {
    return op1->matrix_.rows() != op2->matrix_.rows() ||
           op1->matrix_.cols() != op2->matrix_.cols()
      ? NanThrowError("Nonconformant arguments"), true
      : false;
  }

  static bool is_invalid_matrix_product(
      const Matrix* const& op1
    , const Matrix* const& op2) {
    return op1->matrix_.cols() != op2->matrix_.rows()
      ? NanThrowError("Invalid matrix product"), true
      : false;
  }

 private:
  matrix_type matrix_;
};

template<typename ValueType, const char* ClassName>
v8::Persistent<v8::FunctionTemplate>
Matrix<ValueType, ClassName>::function_template;

template<typename ValueType, const char* ClassName>
v8::Persistent<v8::Function> Matrix<ValueType, ClassName>::constructor;

}  // namespace EigenJS

#undef EIGENJS_MATRIX_BINARY_OPERATOR
#undef EIGENJS_MATRIX_BINARY_OPERATOR_COMMUTATIVE

#endif  // EIGENJS_MATRIX_HPP
<commit_msg>src: inherited 'struct base'<commit_after>//
// Matirx.hpp
// ~~~~~~~~~~
//
// Copyright (c) 2014 Rick Yang (rick68 at gmail dot com)
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
//

#ifndef EIGENJS_MATRIX_HPP
#define EIGENJS_MATRIX_HPP

#include <node.h>
#include <v8.h>

#include <nan.h>

#include <eigen3/Eigen/Dense>

#include <sstream>

#include "base.hpp"
#include "Complex.hpp"

#define EIGENJS_MATRIX_BINARY_OPERATOR( NAME, OP )                             \
static NAN_METHOD( NAME ) {                                                    \
  const Matrix* obj = node::ObjectWrap::Unwrap<Matrix>( args.This() );         \
  NanScope();                                                                  \
                                                                               \
  if ( args.Length() == 1 && HasInstance( args[0] ) ) {                        \
    const Matrix* rhs_obj =                                                    \
        node::ObjectWrap::Unwrap<Matrix>( args[0]->ToObject() );               \
                                                                               \
    if ( is_nonconformate_arguments( obj, rhs_obj ) ) {                        \
      NanReturnUndefined();                                                    \
    }                                                                          \
                                                                               \
    const typename matrix_type::Index& rows = obj->matrix_.rows();             \
    const typename matrix_type::Index& cols = obj->matrix_.cols();             \
                                                                               \
    v8::Local<v8::Function> ctr = NanNew( constructor );                       \
    v8::Local<v8::Value> argv[] = {                                            \
        NanNew<v8::Integer>( rows )                                            \
      , NanNew<v8::Integer>( cols )                                            \
    };                                                                         \
                                                                               \
    v8::Local<v8::Object> new_matrix = ctr->NewInstance(                       \
        sizeof( argv ) / sizeof( v8::Local<v8::Value> )                        \
      , argv                                                                   \
    );                                                                         \
                                                                               \
    Matrix* new_obj = node::ObjectWrap::Unwrap<Matrix>( new_matrix );          \
    new_obj->matrix_ = obj->matrix_ OP rhs_obj->matrix_;                       \
                                                                               \
    NanReturnValue( new_matrix );                                              \
  }                                                                            \
                                                                               \
  NanReturnUndefined();                                                        \
}                                                                              \
/**/

#define EIGENJS_MATRIX_BINARY_OPERATOR_COMMUTATIVE( NAME, OP )                 \
static NAN_METHOD( NAME ) {                                                    \
  Matrix* obj = node::ObjectWrap::Unwrap<Matrix>( args.This() );               \
  NanScope();                                                                  \
                                                                               \
  if ( args.Length() == 1 && HasInstance( args[0] ) ) {                        \
    const Matrix* rhs_obj =                                                    \
        node::ObjectWrap::Unwrap<Matrix>( args[0]->ToObject() );               \
                                                                               \
    if ( is_nonconformate_arguments( obj, rhs_obj ) ) {                        \
      NanReturnUndefined();                                                    \
    }                                                                          \
                                                                               \
    obj->matrix_ OP##= rhs_obj->matrix_;                                       \
                                                                               \
    NanReturnValue( args.This() );                                             \
  }                                                                            \
                                                                               \
  NanReturnUndefined();                                                        \
}                                                                              \
/**/

namespace EigenJS {

template <typename ValueType, const char* ClassName>
class Matrix : public node::ObjectWrap, base<ValueType> {
 public:
  typedef base<ValueType> base_type;
  typedef typename base_type::element_type element_type;
  typedef typename base_type::complex_type complex_type;
  typedef typename base_type::matrix_type matrix_type;

 public:
  static void Init(v8::Handle<v8::Object> exports) {
    NanScope();

    v8::Local<v8::FunctionTemplate> tpl = NanNew<v8::FunctionTemplate>(New);
    tpl->SetClassName(NanNew(ClassName));
    tpl->InstanceTemplate()->SetInternalFieldCount(1);

    NODE_SET_PROTOTYPE_METHOD(tpl, "rows", rows);
    NODE_SET_PROTOTYPE_METHOD(tpl, "cols", cols);
    NODE_SET_PROTOTYPE_METHOD(tpl, "set", set);
    NODE_SET_PROTOTYPE_METHOD(tpl, "get", get);

    NODE_SET_PROTOTYPE_METHOD(tpl, "add", add);
    NODE_SET_PROTOTYPE_METHOD(tpl, "adda", adda);
    NODE_SET_PROTOTYPE_METHOD(tpl, "sub", sub);
    NODE_SET_PROTOTYPE_METHOD(tpl, "suba", suba);

    NODE_SET_PROTOTYPE_METHOD(tpl, "mul", mul);
    NODE_SET_PROTOTYPE_METHOD(tpl, "mula", mula);

    NODE_SET_PROTOTYPE_METHOD(tpl, "div", div);
    NODE_SET_PROTOTYPE_METHOD(tpl, "diva", diva);

    NODE_SET_PROTOTYPE_METHOD(tpl, "toString", toString);

    NanAssignPersistent(constructor, tpl->GetFunction());
    exports->Set(NanNew(ClassName), tpl->GetFunction());

    NanAssignPersistent(function_template, tpl);
  }

  static NAN_METHOD(rows) {
    const Matrix* obj = node::ObjectWrap::Unwrap<Matrix>(args.This());
    NanScope();

    NanReturnValue(NanNew<v8::Integer>(obj->matrix_.rows()));
  }

  static NAN_METHOD(cols) {
    const Matrix* obj = node::ObjectWrap::Unwrap<Matrix>(args.This());
    NanScope();

    NanReturnValue(NanNew<v8::Integer>(obj->matrix_.cols()));
  }

  static NAN_METHOD(set) {
    Matrix* obj = node::ObjectWrap::Unwrap<Matrix>(args.This());
    NanScope();

    if (args.Length() == 1 && args[0]->IsArray()) {
      v8::Local<v8::Array> array = args[0].As<v8::Array>();
      uint32_t len = array->Length();
      const typename matrix_type::Index& rows = obj->matrix_.rows();
      const typename matrix_type::Index& cols = obj->matrix_.cols();
      const typename matrix_type::Index& elems = rows * cols;

      if (len != elems) {
        len < rows * cols
          ? NanThrowError("Too few coefficients passed to Matrix")
          : NanThrowError("Too many coefficients passed to Matrix");
        NanReturnUndefined();
      }

      for (uint32_t i = 0; i < len; ++i) {
        v8::Local<v8::Value> elem = array->Get(i);
        obj->matrix_(i / cols, i % cols) = elem->NumberValue();
      }
    } else if (
        args.Length() == 3 &&
        args[0]->IsNumber() &&
        args[1]->IsNumber() &&
        args[2]->IsNumber()) {
      const typename matrix_type::Index& row = args[0]->Uint32Value();
      const typename matrix_type::Index& col = args[1]->Uint32Value();
      const element_type& value = args[2]->NumberValue();

      if (is_out_of_range(obj->matrix_, row, col))
        NanReturnUndefined();

      obj->matrix_(row, col) = value;
    }

    NanReturnValue(args.This());
  }

  static NAN_METHOD(get) {
    const Matrix* obj = node::ObjectWrap::Unwrap<Matrix>(args.This());
    NanScope();

    if (args.Length() == 2 &&
        args[0]->IsNumber() &&
        args[1]->IsNumber()) {
      typename matrix_type::Index row = args[0]->Uint32Value();
      typename matrix_type::Index col = args[1]->Uint32Value();

      if (is_out_of_range(obj->matrix_, row, col))
        NanReturnUndefined();

      element_type value = obj->matrix_(row, col);
      NanReturnValue(NanNew(value));
    }

    NanReturnUndefined();
  }

  EIGENJS_MATRIX_BINARY_OPERATOR(add, +)
  EIGENJS_MATRIX_BINARY_OPERATOR_COMMUTATIVE(adda, +)

  EIGENJS_MATRIX_BINARY_OPERATOR(sub, -)
  EIGENJS_MATRIX_BINARY_OPERATOR_COMMUTATIVE(suba, -)

  static NAN_METHOD(mul) {
    const Matrix* obj = node::ObjectWrap::Unwrap<Matrix>( args.This() );
    const typename matrix_type::Index& rows = obj->matrix_.rows();
    const typename matrix_type::Index& cols = obj->matrix_.cols();
    NanScope();

    if (args.Length() == 1 && HasInstance(args[0])) {
      const Matrix* rhs_obj =
          node::ObjectWrap::Unwrap<Matrix>(args[0]->ToObject());

      if (is_invalid_matrix_product(obj, rhs_obj)) {
        NanReturnUndefined();
      }

      v8::Local<v8::Function> ctr = NanNew(constructor);
      v8::Local<v8::Value> argv[] = {
          NanNew<v8::Integer>(rows)
        , NanNew<v8::Integer>(cols)
      };

      v8::Local<v8::Object> new_matrix = ctr->NewInstance(
          sizeof(argv) / sizeof(v8::Local<v8::Value>)
        , argv
      );

      Matrix* new_obj = node::ObjectWrap::Unwrap<Matrix>(new_matrix);
      new_obj->matrix_ = obj->matrix_ * rhs_obj->matrix_;

      NanReturnValue(new_matrix);
    } else if (args.Length() == 1 && args[0]->IsNumber()) {
      v8::Local<v8::Function> ctr = NanNew(constructor);
      v8::Local<v8::Value> argv[] = {
          NanNew<v8::Integer>(rows)
        , NanNew<v8::Integer>(cols)
      };

      v8::Local<v8::Object> new_matrix = ctr->NewInstance(
          sizeof(argv) / sizeof(v8::Local<v8::Value>)
        , argv
      );

      Matrix* new_obj = node::ObjectWrap::Unwrap<Matrix>(new_matrix);
      new_obj->matrix_ = obj->matrix_ * args[0]->NumberValue();

      NanReturnValue(new_matrix);
    }

    NanReturnUndefined();
  }

  static NAN_METHOD(mula) {
    Matrix* obj = node::ObjectWrap::Unwrap<Matrix>(args.This());
    NanScope();

    if (args.Length() == 1 && HasInstance(args[0])) {
      const Matrix* rhs_obj =
          node::ObjectWrap::Unwrap<Matrix>(args[0]->ToObject());

      if (is_invalid_matrix_product(obj, rhs_obj)) {
        NanReturnUndefined();
      }

      obj->matrix_ *= rhs_obj->matrix_;

      NanReturnValue(args.This());
    } else if (args.Length() == 1 && args[0]->IsNumber()) {
      obj->matrix_ *= args[0]->NumberValue();

      NanReturnValue(args.This());
    }

    NanReturnUndefined();
  }

  static NAN_METHOD(div) {
    const Matrix* obj = node::ObjectWrap::Unwrap<Matrix>( args.This() );
    const typename matrix_type::Index& rows = obj->matrix_.rows();
    const typename matrix_type::Index& cols = obj->matrix_.cols();
    NanScope();

    if (args.Length() == 1 && args[0]->IsNumber()) {
      v8::Local<v8::Function> ctr = NanNew(constructor);
      v8::Local<v8::Value> argv[] = {
          NanNew<v8::Integer>(rows)
        , NanNew<v8::Integer>(cols)
      };

      v8::Local<v8::Object> new_matrix = ctr->NewInstance(
          sizeof(argv) / sizeof(v8::Local<v8::Value>)
        , argv
      );

      Matrix* new_obj = node::ObjectWrap::Unwrap<Matrix>(new_matrix);
      new_obj->matrix_ = obj->matrix_ / args[0]->NumberValue();

      NanReturnValue(new_matrix);
    }

    NanReturnUndefined();
  }

  static NAN_METHOD(diva) {
    Matrix* obj = node::ObjectWrap::Unwrap<Matrix>(args.This());
    NanScope();

    if (args.Length() == 1 && args[0]->IsNumber()) {
      obj->matrix_ /= args[0]->NumberValue();

      NanReturnValue(args.This());
    }

    NanReturnUndefined();
  }

  static NAN_METHOD(toString) {
    const Matrix* obj = node::ObjectWrap::Unwrap<Matrix>(args.This());
    NanScope();

    std::ostringstream result;
    result << obj->matrix_;

    NanReturnValue(NanNew(result.str().c_str()));
  }

 private:
  Matrix(
      const typename matrix_type::Index& rows
    , const typename matrix_type::Index& cols)
    : matrix_(matrix_type::Zero(rows, cols))
  {}
  ~Matrix() {}

  static NAN_METHOD(New) {
    NanScope();

    if (args.Length() < 2) {
      NanThrowError("Tried creating matrix without rows and columns arguments");
      NanReturnUndefined();
    }

    if (args.IsConstructCall()) {
      typename matrix_type::Index rows = args[0]->Uint32Value();
      typename matrix_type::Index columns = args[1]->Uint32Value();
      Matrix* obj = new Matrix(rows, columns);
      obj->Wrap(args.This());
      NanReturnValue(args.This());
    } else {
      v8::Local<v8::Function> ctr = NanNew(constructor);
      v8::Local<v8::Value> argv[] = {args[0], args[1]};
      NanReturnValue(
        ctr->NewInstance(
            sizeof(argv) / sizeof(v8::Local<v8::Value>)
          , argv
        )
      );
    }
  }

  static bool HasInstance(const v8::Handle<v8::Value>& value) {
    NanScope();
    v8::Local<v8::FunctionTemplate> tpl = NanNew(function_template);
    return tpl->HasInstance(value);
  }

  static v8::Persistent<v8::FunctionTemplate> function_template;
  static v8::Persistent<v8::Function> constructor;

 private:
  static bool is_out_of_range(
      const matrix_type& matrix
    , const typename matrix_type::Index& row
    , const typename matrix_type::Index& col) {
    return row < 0 || row >= matrix.rows() || col < 0 || col >= matrix.cols()
      ? NanThrowError("Row or column numbers are out of range"), true
      : false;
  }

  static bool is_nonconformate_arguments(
      const Matrix* const& op1
    , const Matrix* const& op2) {
    return op1->matrix_.rows() != op2->matrix_.rows() ||
           op1->matrix_.cols() != op2->matrix_.cols()
      ? NanThrowError("Nonconformant arguments"), true
      : false;
  }

  static bool is_invalid_matrix_product(
      const Matrix* const& op1
    , const Matrix* const& op2) {
    return op1->matrix_.cols() != op2->matrix_.rows()
      ? NanThrowError("Invalid matrix product"), true
      : false;
  }

 private:
  matrix_type matrix_;
};

template<typename ValueType, const char* ClassName>
v8::Persistent<v8::FunctionTemplate>
Matrix<ValueType, ClassName>::function_template;

template<typename ValueType, const char* ClassName>
v8::Persistent<v8::Function> Matrix<ValueType, ClassName>::constructor;

}  // namespace EigenJS

#undef EIGENJS_MATRIX_BINARY_OPERATOR
#undef EIGENJS_MATRIX_BINARY_OPERATOR_COMMUTATIVE

#endif  // EIGENJS_MATRIX_HPP
<|endoftext|>


<commit_before>/*
 * @file opencog/cython/PythonEval.cc
 * @author Zhenhua Cai <czhedu@gmail.com> Ramin Barati <rekino@gmail.com>
 *         Keyvan Mir Mohammad Sadeghi <keyvan@opencog.org>
 * @date 2011-09-20
 *
 * Reference:
 *   http://www.linuxjournal.com/article/3641?page=0,2
 *   http://www.codeproject.com/KB/cpp/embedpython_1.aspx
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <boost/filesystem/operations.hpp>

#include <opencog/util/exceptions.h>
#include <opencog/util/Logger.h>
#include <opencog/util/misc.h>
#include <opencog/util/oc_assert.h>

#include <opencog/server/CogServer.h>

#include "PythonEval.h"
#include "opencog/atomspace_api.h"

using std::string;
using std::vector;

using namespace opencog;

//#define DPRINTF printf
#define DPRINTF(...)

PythonEval* PythonEval::singletonInstance = NULL;

static void global_python_init()
{
    static bool already_inited = false;

    // Avoid hard crash if already inited.
    if (already_inited) return;
    already_inited = true;

    // Start up Python (this init method skips registering signal
    // handlers)
    if (not Py_IsInitialized())
        Py_InitializeEx(0);
    if (not PyEval_ThreadsInitialized()) {
        PyEval_InitThreads();
        // Without this, pyshell hangs and does nothing.
        PyEval_ReleaseLock();
    }
}

void PythonEval::init(void)
{
    static bool eval_already_inited = false;

    // Avoid hard crash if already inited.
    if (eval_already_inited) return;
    eval_already_inited = true;

    global_python_init();
    import_opencog__atomspace();

    logger().info("PythonEval::%s Initialising python evaluator.",
        __FUNCTION__);

    // Save a pointer to the main PyThreadState object
    this->mainThreadState = PyThreadState_Get();

    // Get a reference to the PyInterpreterState
    this->mainInterpreterState = this->mainThreadState->interp;

    // Getting the __main__ module
    this->pyRootModule = PyImport_AddModule("__main__");
    PyModule_AddStringConstant(this->pyRootModule, "__file__", "");

    PyRun_SimpleString(
                "import sys\n"
                "import StringIO\n"
                );

    // Define the user function executer
    // XXX FIXME ... this should probably be defined in some py file
    // that is loaded up by opencog.conf
    PyRun_SimpleString(
        "from opencog.atomspace import Handle, Atom\n"
        "import inspect\n"
        "def execute_user_defined_function(func, handle_uuid):\n"
        "    handle = Handle(handle_uuid)\n"
        "    args_list_link = ATOMSPACE[handle]\n"
        "    no_of_arguments_in_pattern = len(args_list_link.out)\n"
        "    no_of_arguments_in_user_fn = len(inspect.getargspec(func).args)\n"
        "    if no_of_arguments_in_pattern != no_of_arguments_in_user_fn:\n"
        "        raise Exception('Number of arguments in the function (' + "
        "str(no_of_arguments_in_user_fn) + ') does not match that of the "
        "corresponding pattern (' + str(no_of_arguments_in_pattern) + ').')\n"
        "    atom = func(*args_list_link.out)\n"
        "    if atom is None:\n"
        "        return\n"
        "    assert(type(atom) == Atom)\n"
        "    return atom.h.value()\n\n");

    // Add ATOMSPACE to __main__ module
    PyDict_SetItem(PyModule_GetDict(this->pyRootModule),
                   PyBytes_FromString("ATOMSPACE"),
                   this->getPyAtomspace());

    // These are needed for calling Python/C API functions, define
    // them once and for all
    pyGlobal = PyDict_New();
    pyLocal = PyDict_New();

    // Getting sys.path and keeping the refrence, used in this->addSysPath()
    sys_path = PySys_GetObject((char*)"path");

    logger().info("PythonEval::%s Finished initialising python evaluator.",
        __FUNCTION__);
}

PyObject* PythonEval::getPyAtomspace(AtomSpace* atomspace)
{
    init();
    PyObject * pAtomSpace;

    if (atomspace)
        pAtomSpace = py_atomspace(atomspace);
    else
        pAtomSpace = py_atomspace(this->_atomspace);

    if (pAtomSpace != NULL)
        logger().debug("PythonEval::%s Get atomspace wrapped with python object",
                       __FUNCTION__);
    else {
        if (PyErr_Occurred())
            PyErr_Print();

        logger().error("PythonEval::%s Failed to get atomspace "
                       "wrapped with python object", __FUNCTION__);
    }

    return pAtomSpace;
}

void PythonEval::printDict(PyObject* obj)
{
    if (!PyDict_Check(obj))
        return;

    PyObject *k, *keys;
    keys = PyDict_Keys(obj);
    for (int i = 0; i < PyList_GET_SIZE(keys); i++) {
        k = PyList_GET_ITEM(keys, i);
        char* c_name = PyBytes_AsString(k);
        printf("%s\n", c_name);
    }
}

PythonEval::~PythonEval()
{
    logger().info("PythonEval::%s destructor", __FUNCTION__);
    Py_Finalize();

    delete pyLocal;
    delete pyRootModule;

    delete sys_path;
    delete pyGlobal;
}

/**
* Use a singleton instance to avoid initializing python interpreter
* twice.
*/
PythonEval& PythonEval::instance(AtomSpace* atomspace)
{
    if (!singletonInstance)
    {
        if (!atomspace)
            throw (RuntimeException(TRACE_INFO, "Null Atomspace!"));
        singletonInstance = new PythonEval(atomspace);
    }
    else if (atomspace and singletonInstance->_atomspace != atomspace)
    {
        // Someone is trying to initialize the Python interpreter on a
        // different AtomSpace.  Because of the singleton design of the
        // the CosgServer+AtomSpace, there is no easy way to support this...
        throw RuntimeException(TRACE_INFO, "Trying to re-initialize"
                " python interpreter with different AtomSpace ptr!");
    }
    return *singletonInstance;
}

Handle PythonEval::apply(const std::string& func, Handle varargs)
{
    PyObject *pError, *pyModule, *pFunc, *pExecFunc;
    PyObject *pArgs, *pUUID, *pValue = NULL;
    string moduleName;
    string funcName;

    init();

    // Get the correct module and extract the function name
    int index = func.find_first_of('.');
    if(index < 0){
        pyModule = this->pyRootModule;
        funcName = func;
        moduleName = "__main__";
    }
    else{
        moduleName = func.substr(0,index);
        pyModule = this->modules[moduleName];
        funcName = func.substr(index+1);
    }

    //    PyGILState_STATE _state = PyGILState_Ensure();
    // Get a refrence to the function
    pFunc = PyDict_GetItem(PyModule_GetDict(pyModule),
                           PyBytes_FromString(funcName.c_str()));

    OC_ASSERT(pFunc != NULL);
    if(!PyCallable_Check(pFunc))
    {
        logger().error() << "Member " << func << " is not callable.";
        return Handle::UNDEFINED;
    }

    // Get a refrence to our executer function
    pExecFunc = PyDict_GetItem(PyModule_GetDict(this->pyRootModule),
                    PyBytes_FromString("execute_user_defined_function"));
    OC_ASSERT(pExecFunc != NULL);

    // Create the argument list
    pArgs = PyTuple_New(2);
    pUUID = PyLong_FromLong(varargs.value());
    OC_ASSERT(pUUID != NULL);

    PyTuple_SetItem(pArgs, 0, pFunc);
    PyTuple_SetItem(pArgs, 1, pUUID);

    // Call the executer function and store its return value
    pValue = PyObject_CallObject(pExecFunc, pArgs);
    pError = PyErr_Occurred();

    if (pError) {
        PyErr_Print();
        logger().error() << PyBytes_AsString(PyObject_GetAttrString(pError, "message"));
        return Handle::UNDEFINED;
    }

    UUID uuid = static_cast<unsigned long>(PyLong_AsLong(pValue));

    // Cleaning up
    Py_DECREF(pArgs);
    Py_DECREF(pUUID);
    Py_DECREF(pFunc);
    Py_DECREF(pExecFunc);

    //    PyGILState_Release(_state);

    return Handle(uuid);
}

std::string PythonEval::apply_script(const std::string& script)
{
    init();

    std::string result;
//    PyObject* pError;
    //    PyGILState_STATE _state = PyGILState_Ensure();
    PyRun_SimpleString("_opencog_output_stream = StringIO.StringIO()\n"
                       "_python_output_stream = sys.stdout\n"
                       "sys.stdout = _opencog_output_stream\n"
                       "sys.stderr = _opencog_output_stream\n");

    PyRun_SimpleString(script.c_str());

    PyObject *catcher = PyObject_GetAttrString(this->pyRootModule,"_opencog_output_stream");
    PyObject *output = PyObject_CallMethod(catcher, (char*)"getvalue", NULL);

//    pError = PyErr_Occurred();

//    if(pError){
//        logger().error() << PyString_AsString(PyObject_GetAttrString(pError, "message")) << std::endl;
//        result = PyString_AsString(PyObject_GetAttrString(pError, "message"));
//    }
//    else
//    {
        result = PyBytes_AsString(output);
//    }

    PyRun_SimpleString("sys.stdout = _python_output_stream\n"
                       "sys.stderr = _python_output_stream\n"
                       "_opencog_output_stream.close()\n");
    //    PyGILState_Release(_state);

    // XXX TODO FIXME: we should check for error, and throw.  Without
    // this, python scripts can silently fail, and you'd never now it.

    // printf("Python says that: %s\n", result.c_str());
    return result;
}

void PythonEval::addSysPath(std::string path)
{
    init();

    PyList_Append(this->sys_path, PyBytes_FromString(path.c_str()));
    //    PyRun_SimpleString(("sys.path += ['" + path + "']").c_str());
}

/**
* Add all the .py files in the given directory as modules to __main__ and keeping the refrences
* in a dictionary (this->modules)
*/
void PythonEval::add_module_directory(const boost::filesystem::path &p)
{
    init();

    vector<boost::filesystem::path> files;
    vector<boost::filesystem::path> pyFiles;

    copy(boost::filesystem::directory_iterator(p), boost::filesystem::directory_iterator(), back_inserter(files));

    for(vector<boost::filesystem::path>::const_iterator it(files.begin()); it != files.end(); ++it){
        if(it->extension() == boost::filesystem::path(".py"))
            pyFiles.push_back(*it);
    }

    this->addSysPath(p.c_str());

    string name;
    PyObject* mod;
    PyObject* pyList = PyList_New(0);
    for(vector<boost::filesystem::path>::const_iterator it(pyFiles.begin()); it != pyFiles.end(); ++it){
        name = it->filename().c_str();
        name = name.substr(0, name.length()-3);
        mod = PyImport_ImportModuleLevel((char *)name.c_str(), pyGlobal, pyLocal, pyList, 0);

        if(mod){
            PyDict_SetItem(PyModule_GetDict(mod), PyBytes_FromString("ATOMSPACE"), this->getPyAtomspace());
            PyModule_AddObject(this->pyRootModule, name.c_str(), mod);
            this->modules[name] = mod;
        }
        else{
            if(PyErr_Occurred())
                PyErr_Print();
            logger().warn() << "Couldn't import " << name << " module from folder " << p.c_str();
        }
    }
    Py_DECREF(pyList);
}

/**
* Add the .py file in the given path as a module to __main__ and keeping the refrences
* in a dictionary (this->modules)
*/
void PythonEval::add_module_file(const boost::filesystem::path &p)
{
    init();

    this->addSysPath(p.parent_path().c_str());

    string name;
    PyObject* mod;
    PyObject* pyList = PyList_New(0);

    name = p.filename().c_str();
    name = name.substr(0, name.length()-3);
    mod = PyImport_ImportModuleLevel((char *)name.c_str(), pyGlobal, pyLocal, pyList, 0);

    PyDict_SetItem(PyModule_GetDict(mod), PyBytes_FromString("ATOMSPACE"), this->getPyAtomspace());
    if(mod){
        PyDict_SetItem(PyModule_GetDict(mod), PyBytes_FromString("ATOMSPACE"), this->getPyAtomspace());
        PyModule_AddObject(this->pyRootModule, name.c_str(), mod);
        this->modules[name] = mod;
    }
    else{
        if(PyErr_Occurred())
            PyErr_Print();
        logger().warn() << "Couldn't import " << name << " module";
    }
    Py_DECREF(pyList);
}

/**
* Get a path from the user and call the coresponding function for directories and files
*/
void PythonEval::addModuleFromPath(std::string path)
{
    boost::filesystem::path p(path);

    if(boost::filesystem::exists(p)){
        if(boost::filesystem::is_directory(p))
            this->add_module_directory(p);
        else
            this->add_module_file(p);
    }
    else{
        logger().error() << path << " doesn't exists";
    }

}

void PythonEval::eval_expr(const std::string& partial_expr)
{
    init();

    _result = "";
    if (partial_expr == "\n")
    {
        _pending_input = false;
        _result = this->apply_script(_input_line);
        _input_line = "";
    }
    else
    {
        // If the line ends with a colon, its not a complete expression,
        // and we must wait for more input.
        // XXX FIXME TODO: the same might be true if there was an open
        // parenthesis, and no close parentheis.  This neds to be
        // scanned for and fixed.
        size_t size = partial_expr.size();
        size_t colun = partial_expr.find_last_of(':');
        if (size-2 == colun)
            _pending_input = true;

        _input_line += partial_expr;

        if (not _pending_input)
        {
            _result = this->apply_script(_input_line);
            _input_line = "";
        }
    }
}

std::string PythonEval::poll_result()
{
	std::string r = _result;
	_result.clear();
	return r;
}
<commit_msg>Fixed bug with GIL not being grabbed in PyEval<commit_after>/*
 * @file opencog/cython/PythonEval.cc
 * @author Zhenhua Cai <czhedu@gmail.com> Ramin Barati <rekino@gmail.com>
 *         Keyvan Mir Mohammad Sadeghi <keyvan@opencog.org>
 * @date 2011-09-20
 *
 * Reference:
 *   http://www.linuxjournal.com/article/3641?page=0,2
 *   http://www.codeproject.com/KB/cpp/embedpython_1.aspx
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <boost/filesystem/operations.hpp>

#include <opencog/util/exceptions.h>
#include <opencog/util/Logger.h>
#include <opencog/util/misc.h>
#include <opencog/util/oc_assert.h>

#include <opencog/server/CogServer.h>

#include "PythonEval.h"
#include "opencog/atomspace_api.h"

using std::string;
using std::vector;

using namespace opencog;

//#define DPRINTF printf
#define DPRINTF(...)

PythonEval* PythonEval::singletonInstance = NULL;

static void global_python_init()
{
    static bool already_inited = false;

    // Avoid hard crash if already inited.
    if (already_inited) return;
    already_inited = true;

    // Start up Python (this init method skips registering signal
    // handlers)
    if (not Py_IsInitialized())
        Py_InitializeEx(0);
    if (not PyEval_ThreadsInitialized()) {
        PyEval_InitThreads();
        // Without this, pyshell hangs and does nothing.
        PyEval_ReleaseLock();
    }
}

void PythonEval::init(void)
{
    static bool eval_already_inited = false;

    // Avoid hard crash if already inited.
    if (eval_already_inited) return;
    eval_already_inited = true;

    global_python_init();
    import_opencog__atomspace();

    logger().info("PythonEval::%s Initialising python evaluator.",
        __FUNCTION__);

    // Save a pointer to the main PyThreadState object
    this->mainThreadState = PyThreadState_Get();

    // Get a reference to the PyInterpreterState
    this->mainInterpreterState = this->mainThreadState->interp;

    // Grab the GIL
    PyGILState_STATE gstate;
    gstate = PyGILState_Ensure();

    // Getting the __main__ module
    this->pyRootModule = PyImport_AddModule("__main__");
    PyModule_AddStringConstant(this->pyRootModule, "__file__", "");

    PyRun_SimpleString(
                "import sys\n"
                "import StringIO\n"
                );

    // Define the user function executer
    // XXX FIXME ... this should probably be defined in some py file
    // that is loaded up by opencog.conf
    PyRun_SimpleString(
        "from opencog.atomspace import Handle, Atom\n"
        "import inspect\n"
        "def execute_user_defined_function(func, handle_uuid):\n"
        "    handle = Handle(handle_uuid)\n"
        "    args_list_link = ATOMSPACE[handle]\n"
        "    no_of_arguments_in_pattern = len(args_list_link.out)\n"
        "    no_of_arguments_in_user_fn = len(inspect.getargspec(func).args)\n"
        "    if no_of_arguments_in_pattern != no_of_arguments_in_user_fn:\n"
        "        raise Exception('Number of arguments in the function (' + "
        "str(no_of_arguments_in_user_fn) + ') does not match that of the "
        "corresponding pattern (' + str(no_of_arguments_in_pattern) + ').')\n"
        "    atom = func(*args_list_link.out)\n"
        "    if atom is None:\n"
        "        return\n"
        "    assert(type(atom) == Atom)\n"
        "    return atom.h.value()\n\n");

    // Add ATOMSPACE to __main__ module
    PyDict_SetItem(PyModule_GetDict(this->pyRootModule),
                   PyBytes_FromString("ATOMSPACE"),
                   this->getPyAtomspace());

    // These are needed for calling Python/C API functions, define
    // them once and for all
    pyGlobal = PyDict_New();
    pyLocal = PyDict_New();

    // Getting sys.path and keeping the refrence, used in this->addSysPath()
    sys_path = PySys_GetObject((char*)"path");

    // Release the GIL. No Python API allowed beyond this point.
    PyGILState_Release(gstate);

    logger().info("PythonEval::%s Finished initialising python evaluator.",
        __FUNCTION__);
}

PyObject* PythonEval::getPyAtomspace(AtomSpace* atomspace)
{
    init();
    PyObject * pAtomSpace;

    if (atomspace)
        pAtomSpace = py_atomspace(atomspace);
    else
        pAtomSpace = py_atomspace(this->_atomspace);

    if (pAtomSpace != NULL)
        logger().debug("PythonEval::%s Get atomspace wrapped with python object",
                       __FUNCTION__);
    else {
        if (PyErr_Occurred())
            PyErr_Print();

        logger().error("PythonEval::%s Failed to get atomspace "
                       "wrapped with python object", __FUNCTION__);
    }

    return pAtomSpace;
}

void PythonEval::printDict(PyObject* obj)
{
    if (!PyDict_Check(obj))
        return;

    PyObject *k, *keys;
    keys = PyDict_Keys(obj);
    for (int i = 0; i < PyList_GET_SIZE(keys); i++) {
        k = PyList_GET_ITEM(keys, i);
        char* c_name = PyBytes_AsString(k);
        printf("%s\n", c_name);
    }
}

PythonEval::~PythonEval()
{
    logger().info("PythonEval::%s destructor", __FUNCTION__);
    Py_Finalize();

    delete pyLocal;
    delete pyRootModule;

    delete sys_path;
    delete pyGlobal;
}

/**
* Use a singleton instance to avoid initializing python interpreter
* twice.
*/
PythonEval& PythonEval::instance(AtomSpace* atomspace)
{
    if (!singletonInstance)
    {
        if (!atomspace)
            throw (RuntimeException(TRACE_INFO, "Null Atomspace!"));
        singletonInstance = new PythonEval(atomspace);
    }
    else if (atomspace and singletonInstance->_atomspace != atomspace)
    {
        // Someone is trying to initialize the Python interpreter on a
        // different AtomSpace.  Because of the singleton design of the
        // the CosgServer+AtomSpace, there is no easy way to support this...
        throw RuntimeException(TRACE_INFO, "Trying to re-initialize"
                " python interpreter with different AtomSpace ptr!");
    }
    return *singletonInstance;
}

Handle PythonEval::apply(const std::string& func, Handle varargs)
{
    PyObject *pError, *pyModule, *pFunc, *pExecFunc;
    PyObject *pArgs, *pUUID, *pValue = NULL;
    string moduleName;
    string funcName;

    init();

    // Get the correct module and extract the function name
    int index = func.find_first_of('.');
    if(index < 0){
        pyModule = this->pyRootModule;
        funcName = func;
        moduleName = "__main__";
    }
    else{
        moduleName = func.substr(0,index);
        pyModule = this->modules[moduleName];
        funcName = func.substr(index+1);
    }

    // Grab the GIL
    PyGILState_STATE gstate;
    gstate = PyGILState_Ensure();

    // Get a refrence to the function
    pFunc = PyDict_GetItem(PyModule_GetDict(pyModule),
                           PyBytes_FromString(funcName.c_str()));

    OC_ASSERT(pFunc != NULL);
    if(!PyCallable_Check(pFunc))
    {
        logger().error() << "Member " << func << " is not callable.";
        return Handle::UNDEFINED;
    }

    // Get a refrence to our executer function
    pExecFunc = PyDict_GetItem(PyModule_GetDict(this->pyRootModule),
                    PyBytes_FromString("execute_user_defined_function"));
    OC_ASSERT(pExecFunc != NULL);

    // Create the argument list
    pArgs = PyTuple_New(2);
    pUUID = PyLong_FromLong(varargs.value());
    OC_ASSERT(pUUID != NULL);

    PyTuple_SetItem(pArgs, 0, pFunc);
    PyTuple_SetItem(pArgs, 1, pUUID);

    // Call the executer function and store its return value
    pValue = PyObject_CallObject(pExecFunc, pArgs);
    pError = PyErr_Occurred();

    if (pError) {
        PyErr_Print();
        logger().error() << PyBytes_AsString(PyObject_GetAttrString(pError, "message"));
        return Handle::UNDEFINED;
    }

    UUID uuid = static_cast<unsigned long>(PyLong_AsLong(pValue));

    // Cleaning up
    Py_DECREF(pArgs);
    Py_DECREF(pUUID);
    Py_DECREF(pFunc);
    Py_DECREF(pExecFunc);

    // Release the GIL. No Python API allowed beyond this point.
    PyGILState_Release(gstate);

    return Handle(uuid);
}

std::string PythonEval::apply_script(const std::string& script)
{
    init();

    std::string result;

    // Grab the GIL
    PyGILState_STATE gstate;
    gstate = PyGILState_Ensure();

    PyRun_SimpleString("_opencog_output_stream = StringIO.StringIO()\n"
                       "_python_output_stream = sys.stdout\n"
                       "sys.stdout = _opencog_output_stream\n"
                       "sys.stderr = _opencog_output_stream\n");

    PyRun_SimpleString(script.c_str());

    PyObject *catcher = PyObject_GetAttrString(this->pyRootModule,"_opencog_output_stream");
    PyObject *output = PyObject_CallMethod(catcher, (char*)"getvalue", NULL);

//    pError = PyErr_Occurred();

//    if(pError){
//        logger().error() << PyString_AsString(PyObject_GetAttrString(pError, "message")) << std::endl;
//        result = PyString_AsString(PyObject_GetAttrString(pError, "message"));
//    }
//    else
//    {
        result = PyBytes_AsString(output);
//    }

    PyRun_SimpleString("sys.stdout = _python_output_stream\n"
                       "sys.stderr = _python_output_stream\n"
                       "_opencog_output_stream.close()\n");

    // Release the GIL. No Python API allowed beyond this point.
    PyGILState_Release(gstate);

    // XXX TODO FIXME: we should check for error, and throw.  Without
    // this, python scripts can silently fail, and you'd never now it.

    // printf("Python says that: %s\n", result.c_str());
    return result;
}

void PythonEval::addSysPath(std::string path)
{
    init();

    PyList_Append(this->sys_path, PyBytes_FromString(path.c_str()));
    //    PyRun_SimpleString(("sys.path += ['" + path + "']").c_str());
}

/**
* Add all the .py files in the given directory as modules to __main__ and keeping the refrences
* in a dictionary (this->modules)
*/
void PythonEval::add_module_directory(const boost::filesystem::path &p)
{
    init();

    vector<boost::filesystem::path> files;
    vector<boost::filesystem::path> pyFiles;

    copy(boost::filesystem::directory_iterator(p), boost::filesystem::directory_iterator(), back_inserter(files));

    for(vector<boost::filesystem::path>::const_iterator it(files.begin()); it != files.end(); ++it){
        if(it->extension() == boost::filesystem::path(".py"))
            pyFiles.push_back(*it);
    }

    this->addSysPath(p.c_str());

    string name;
    PyObject* mod;
    PyObject* pyList = PyList_New(0);
    for(vector<boost::filesystem::path>::const_iterator it(pyFiles.begin()); it != pyFiles.end(); ++it){
        name = it->filename().c_str();
        name = name.substr(0, name.length()-3);
        mod = PyImport_ImportModuleLevel((char *)name.c_str(), pyGlobal, pyLocal, pyList, 0);

        if(mod){
            PyDict_SetItem(PyModule_GetDict(mod), PyBytes_FromString("ATOMSPACE"), this->getPyAtomspace());
            PyModule_AddObject(this->pyRootModule, name.c_str(), mod);
            this->modules[name] = mod;
        }
        else{
            if(PyErr_Occurred())
                PyErr_Print();
            logger().warn() << "Couldn't import " << name << " module from folder " << p.c_str();
        }
    }
    Py_DECREF(pyList);
}

/**
* Add the .py file in the given path as a module to __main__ and keeping the refrences
* in a dictionary (this->modules)
*/
void PythonEval::add_module_file(const boost::filesystem::path &p)
{
    init();

    this->addSysPath(p.parent_path().c_str());

    string name;
    PyObject* mod;
    PyObject* pyList = PyList_New(0);

    name = p.filename().c_str();
    name = name.substr(0, name.length()-3);
    mod = PyImport_ImportModuleLevel((char *)name.c_str(), pyGlobal, pyLocal, pyList, 0);

    PyDict_SetItem(PyModule_GetDict(mod), PyBytes_FromString("ATOMSPACE"), this->getPyAtomspace());
    if(mod){
        PyDict_SetItem(PyModule_GetDict(mod), PyBytes_FromString("ATOMSPACE"), this->getPyAtomspace());
        PyModule_AddObject(this->pyRootModule, name.c_str(), mod);
        this->modules[name] = mod;
    }
    else{
        if(PyErr_Occurred())
            PyErr_Print();
        logger().warn() << "Couldn't import " << name << " module";
    }
    Py_DECREF(pyList);
}

/**
* Get a path from the user and call the coresponding function for directories and files
*/
void PythonEval::addModuleFromPath(std::string path)
{
    boost::filesystem::path p(path);

    if(boost::filesystem::exists(p)){
        if(boost::filesystem::is_directory(p))
            this->add_module_directory(p);
        else
            this->add_module_file(p);
    }
    else{
        logger().error() << path << " doesn't exists";
    }

}

void PythonEval::eval_expr(const std::string& partial_expr)
{
    init();

    _result = "";
    if (partial_expr == "\n")
    {
        _pending_input = false;
        _result = this->apply_script(_input_line);
        _input_line = "";
    }
    else
    {
        // If the line ends with a colon, its not a complete expression,
        // and we must wait for more input.
        // XXX FIXME TODO: the same might be true if there was an open
        // parenthesis, and no close parentheis.  This neds to be
        // scanned for and fixed.
        size_t size = partial_expr.size();
        size_t colun = partial_expr.find_last_of(':');
        if (size-2 == colun)
            _pending_input = true;

        _input_line += partial_expr;

        if (not _pending_input)
        {
            _result = this->apply_script(_input_line);
            _input_line = "";
        }
    }
}

std::string PythonEval::poll_result()
{
	std::string r = _result;
	_result.clear();
	return r;
}
<|endoftext|>


<commit_before>// dui-demo.cpp : main source file
//

#include "stdafx.h"
#include <helper/MenuWndHook.h>
#include <helper/mybuffer.h>
#include "httpsvr/HTTPServer.h"
#include "MemFlash.h"
#include "../controls.extend/propgrid/SPropertyGrid.h"

#if defined(_DEBUG) && !defined(_WIN64)
// #include <vld.h>//ʹVitural Leaker Detectorڴй©Դhttp://vld.codeplex.com/
#endif

#include "MainDlg.h"

#define RES_TYPE 0   //ļмԴ
// #define RES_TYPE 1   //PEԴмUIԴ
// #define RES_TYPE 2   //zipмԴ

#include "../components/resprovider-zip/zipresprovider-param.h"

#ifdef _DEBUG
#define SYS_NAMED_RESOURCE _T("soui-sys-resourced.dll")
#else
#define SYS_NAMED_RESOURCE _T("soui-sys-resource.dll")
#endif

int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR /*lpstrCmdLine*/, int /*nCmdShow*/)
{
    //ҪOleInitializeʼл
    HRESULT hRes = OleInitialize(NULL);
    SASSERT(SUCCEEDED(hRes));

    int nRet = 0;

    SComMgr *pComMgr = new SComMgr;

    //·޸ĵdemoڵĿ¼
    TCHAR szCurrentDir[MAX_PATH]={0};
    GetModuleFileName( NULL, szCurrentDir, sizeof(szCurrentDir) );
    LPTSTR lpInsertPos = _tcsrchr( szCurrentDir, _T('\\') );
    _tcscpy(lpInsertPos,_T("\\..\\demo"));
    SetCurrentDirectory(szCurrentDir);

    {
        //һSOUIϵͳʹõCOM
        //CAutoRefPtrһSOUIϵͳʹõָ
        CAutoRefPtr<IImgDecoderFactory> pImgDecoderFactory; //ͼƬimagedecoder-wid.dllģṩ
        CAutoRefPtr<IRenderFactory> pRenderFactory;         //UIȾģ飬render-gdi.dllrender-skia.dllṩ
        CAutoRefPtr<ITranslatorMgr> trans;                  //Էģ飬translator.dllṩ
        CAutoRefPtr<IScriptModule> pScriptLua;              //luaűģ飬scriptmodule-lua.dllṩ

        BOOL bLoaded=FALSE;
        int nType=MessageBox(GetActiveWindow(),_T("ѡȾͣ\n[yes]: Skia\n[no]:GDI\n[cancel]:Quit"),_T("select a render"),MB_ICONQUESTION|MB_YESNOCANCEL);
        if(nType == IDCANCEL) return -1;
        //Ӹʾ

        if(nType == IDYES)
            bLoaded = pComMgr->CreateRender_Skia((IObjRef**)&pRenderFactory);
        else
            bLoaded = pComMgr->CreateRender_GDI((IObjRef**)&pRenderFactory);
        SASSERT_FMT(bLoaded,_T("load interface [%s] failed!"),nType==IDYES?_T("render_skia"):_T("render_gdi"));
        bLoaded=pComMgr->CreateImgDecoder((IObjRef**)&pImgDecoderFactory);
        SASSERT_FMT(bLoaded,_T("load interface [%s] failed!"),_T("imgdecoder"));
        bLoaded=pComMgr->CreateTranslator((IObjRef**)&trans);
        SASSERT_FMT(bLoaded,_T("load interface [%s] failed!"),_T("translator"));

        //ΪȾģҪõͼƬģ
        pRenderFactory->SetImgDecoderFactory(pImgDecoderFactory);
        //һΨһSApplicationSApplicationӦóԴ
        SApplication *theApp=new SApplication(pRenderFactory,hInstance);

        //һ˸Դṩ,SOUIϵͳʵ3ԴطʽֱǴļأEXEԴؼZIPѹ
        CAutoRefPtr<IResProvider>   pResProvider;
#if (RES_TYPE == 0)//ļ
        CreateResProvider(RES_FILE,(IObjRef**)&pResProvider);
        if(!pResProvider->Init((LPARAM)_T("uires"),0))
        {
            SASSERT(0);
            return 1;
        }
#elif (RES_TYPE==1)//EXEԴ
        CreateResProvider(RES_PE,(IObjRef**)&pResProvider);
        pResProvider->Init((WPARAM)hInstance,0);
#elif (RES_TYPE==2)//ZIP
        bLoaded=pComMgr->CreateResProvider_ZIP((IObjRef**)&pResProvider);
        SASSERT_FMT(bLoaded,_T("load interface [%s] failed!"),_T("resprovider_zip"));

        ZIPRES_PARAM param;
        param.ZipFile(pRenderFactory, _T("uires.zip"),"souizip");
        bLoaded = pResProvider->Init((WPARAM)&param,0);
        SASSERT(bLoaded);
#endif
        //IResProviderSApplication
        theApp->AddResProvider(pResProvider);

		//һhttpԴмflash
		CMemFlash   memFlash;
		CHTTPServer flashSvr(&memFlash);
		flashSvr.Start(CMemFlash::HomeDir(), "", 82, 0);

        if(trans)
        {//Է
            theApp->SetTranslator(trans);
            pugi::xml_document xmlLang;
            if(theApp->LoadXmlDocment(xmlLang,_T("lang_cn"),_T("translator")))
            {
                CAutoRefPtr<ITranslator> langCN;
                trans->CreateTranslator(&langCN);
                langCN->Load(&xmlLang.child(L"language"),1);//1=LD_XML
                trans->InstallTranslator(langCN);
            }
        }
#ifdef DLL_CORE
        //LUAűģ飬ע⣬űģֻSOUIںDLLʽʱʹá
        bLoaded=pComMgr->CreateScrpit_Lua((IObjRef**)&pScriptLua);
        SASSERT_FMT(bLoaded,_T("load interface [%s] failed!"),_T("scirpt_lua"));

        if(pScriptLua)
        {
            theApp->SetScriptModule(pScriptLua);
            size_t sz=pResProvider->GetRawBufferSize(_T("script"),_T("lua_test"));
            if(sz)
            {
                CMyBuffer<char> lua;
                lua.Allocate(sz);
                pResProvider->GetRawBuffer(_T("script"),_T("lua_test"),lua,sz);
                pScriptLua->executeScriptBuffer(lua,sz);
            }
        }
#endif//DLL_CORE

        //SApplicationϵͳעⲿչĿؼSkinObj
        SWkeLoader wkeLoader;
        if(wkeLoader.Init(_T("wke.dll")))
        {
            theApp->RegisterWndFactory(TplSWindowFactory<SWkeWebkit>());//עWKE
        }
        theApp->RegisterWndFactory(TplSWindowFactory<SGifPlayer>());//עGIFPlayer
        theApp->RegisterSkinFactory(TplSkinFactory<SSkinGif>());//עSkinGif
        theApp->RegisterSkinFactory(TplSkinFactory<SSkinAPNG>());//עSkinGif

        theApp->RegisterWndFactory(TplSWindowFactory<SIPAddressCtrl>());//עIPؼ
        theApp->RegisterWndFactory(TplSWindowFactory<SPropertyGrid>());//עԱؼ
        SSkinGif::Gdiplus_Startup();

        //ϵͳԴ
        HMODULE hSysResource=LoadLibrary(SYS_NAMED_RESOURCE);
        if(hSysResource)
        {
            CAutoRefPtr<IResProvider> sysSesProvider;
            CreateResProvider(RES_PE,(IObjRef**)&sysSesProvider);
            sysSesProvider->Init((WPARAM)hSysResource,0);
            theApp->LoadSystemNamedResource(sysSesProvider);
        }
        //hookƲ˵ı߿
        CMenuWndHook::InstallHook(hInstance,L"_skin.sys.menu.border");

        //ȫԴXML
        theApp->Init(_T("xml_init"));

        {
            //ʾʹSOUIӦó򴰿,Ϊ˱洰ڶ󣬰һ㡣
            CMainDlg dlgMain;
            dlgMain.Create(GetActiveWindow(),0,0,800,600);
            dlgMain.GetNative()->SendMessage(WM_INITDIALOG);
            dlgMain.CenterWindow();
            dlgMain.ShowWindow(SW_SHOWNORMAL);
            nRet=theApp->Run(dlgMain.m_hWnd);
        }

        //Ӧó˳
        delete theApp;

        flashSvr.Shutdown();

        //жز˵߿hook
        CMenuWndHook::UnInstallHook();

        SSkinGif::Gdiplus_Shutdown();
    }
    delete pComMgr;
    OleUninitialize();

    return nRet;
}

<commit_msg><commit_after>// dui-demo.cpp : main source file
//

#include "stdafx.h"
#include <helper/MenuWndHook.h>
#include <helper/mybuffer.h>
#include "httpsvr/HTTPServer.h"
#include "MemFlash.h"
#include "../controls.extend/propgrid/SPropertyGrid.h"

#if defined(_DEBUG) && !defined(_WIN64)
// #include <vld.h>//ʹVitural Leaker Detectorڴй©Դhttp://vld.codeplex.com/
#endif

#include "MainDlg.h"

#define RES_TYPE 0   //ļмԴ
// #define RES_TYPE 1   //PEԴмUIԴ
// #define RES_TYPE 2   //zipмԴ

#include "../components/resprovider-zip/zipresprovider-param.h"

#ifdef _DEBUG
#define SYS_NAMED_RESOURCE _T("soui-sys-resourced.dll")
#else
#define SYS_NAMED_RESOURCE _T("soui-sys-resource.dll")
#endif

int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR /*lpstrCmdLine*/, int /*nCmdShow*/)
{
    //ҪOleInitializeʼл
    HRESULT hRes = OleInitialize(NULL);
    SASSERT(SUCCEEDED(hRes));

    int nRet = 0;

    SComMgr *pComMgr = new SComMgr;

    //·޸ĵdemoڵĿ¼
    TCHAR szCurrentDir[MAX_PATH]={0};
    GetModuleFileName( NULL, szCurrentDir, sizeof(szCurrentDir) );
    LPTSTR lpInsertPos = _tcsrchr( szCurrentDir, _T('\\') );
    _tcscpy(lpInsertPos,_T("\\..\\demo"));
    SetCurrentDirectory(szCurrentDir);

    {
        //һSOUIϵͳʹõCOM
        //CAutoRefPtrһSOUIϵͳʹõָ
        CAutoRefPtr<IImgDecoderFactory> pImgDecoderFactory; //ͼƬimagedecoder-wid.dllģṩ
        CAutoRefPtr<IRenderFactory> pRenderFactory;         //UIȾģ飬render-gdi.dllrender-skia.dllṩ
        CAutoRefPtr<ITranslatorMgr> trans;                  //Էģ飬translator.dllṩ
        CAutoRefPtr<IScriptModule> pScriptLua;              //luaűģ飬scriptmodule-lua.dllṩ

        BOOL bLoaded=FALSE;
        int nType=MessageBox(GetActiveWindow(),_T("ѡȾͣ\n[yes]: Skia\n[no]:GDI\n[cancel]:Quit"),_T("select a render"),MB_ICONQUESTION|MB_YESNOCANCEL);
        if(nType == IDCANCEL) return -1;
        //Ӹʾ

        if(nType == IDYES)
            bLoaded = pComMgr->CreateRender_Skia((IObjRef**)&pRenderFactory);
        else
            bLoaded = pComMgr->CreateRender_GDI((IObjRef**)&pRenderFactory);
        SASSERT_FMT(bLoaded,_T("load interface [%s] failed!"),nType==IDYES?_T("render_skia"):_T("render_gdi"));
        bLoaded=pComMgr->CreateImgDecoder((IObjRef**)&pImgDecoderFactory);
        SASSERT_FMT(bLoaded,_T("load interface [%s] failed!"),_T("imgdecoder"));
        bLoaded=pComMgr->CreateTranslator((IObjRef**)&trans);
        SASSERT_FMT(bLoaded,_T("load interface [%s] failed!"),_T("translator"));

        //ΪȾģҪõͼƬģ
        pRenderFactory->SetImgDecoderFactory(pImgDecoderFactory);
        //һΨһSApplicationSApplicationӦóԴ
        SApplication *theApp=new SApplication(pRenderFactory,hInstance);

        //һ˸Դṩ,SOUIϵͳʵ3ԴطʽֱǴļأEXEԴؼZIPѹ
        CAutoRefPtr<IResProvider>   pResProvider;
#if (RES_TYPE == 0)//ļ
        CreateResProvider(RES_FILE,(IObjRef**)&pResProvider);
        if(!pResProvider->Init((LPARAM)_T("uires"),0))
        {
            SASSERT(0);
            return 1;
        }
#elif (RES_TYPE==1)//EXEԴ
        CreateResProvider(RES_PE,(IObjRef**)&pResProvider);
        pResProvider->Init((WPARAM)hInstance,0);
#elif (RES_TYPE==2)//ZIP
        bLoaded=pComMgr->CreateResProvider_ZIP((IObjRef**)&pResProvider);
        SASSERT_FMT(bLoaded,_T("load interface [%s] failed!"),_T("resprovider_zip"));

        ZIPRES_PARAM param;
        param.ZipFile(pRenderFactory, _T("uires.zip"),"souizip");
        bLoaded = pResProvider->Init((WPARAM)&param,0);
        SASSERT(bLoaded);
#endif
        //IResProviderSApplication
        theApp->AddResProvider(pResProvider);

        //һhttpԴмflash
        CMemFlash   memFlash;

        string str="abcd";//ˣCHTTPServerֻһstringĵòŲᵼ쳣֪ʲôû˰ҽһ£
        CHTTPServer flashSvr(&memFlash);
        flashSvr.Start(CMemFlash::HomeDir(),"",82,0);

        if(trans)
        {//Է
            theApp->SetTranslator(trans);
            pugi::xml_document xmlLang;
            if(theApp->LoadXmlDocment(xmlLang,_T("lang_cn"),_T("translator")))
            {
                CAutoRefPtr<ITranslator> langCN;
                trans->CreateTranslator(&langCN);
                langCN->Load(&xmlLang.child(L"language"),1);//1=LD_XML
                trans->InstallTranslator(langCN);
            }
        }
#ifdef DLL_CORE
        //LUAűģ飬ע⣬űģֻSOUIںDLLʽʱʹá
        bLoaded=pComMgr->CreateScrpit_Lua((IObjRef**)&pScriptLua);
        SASSERT_FMT(bLoaded,_T("load interface [%s] failed!"),_T("scirpt_lua"));

        if(pScriptLua)
        {
            theApp->SetScriptModule(pScriptLua);
            size_t sz=pResProvider->GetRawBufferSize(_T("script"),_T("lua_test"));
            if(sz)
            {
                CMyBuffer<char> lua;
                lua.Allocate(sz);
                pResProvider->GetRawBuffer(_T("script"),_T("lua_test"),lua,sz);
                pScriptLua->executeScriptBuffer(lua,sz);
            }
        }
#endif//DLL_CORE

        //SApplicationϵͳעⲿչĿؼSkinObj
        SWkeLoader wkeLoader;
        if(wkeLoader.Init(_T("wke.dll")))
        {
            theApp->RegisterWndFactory(TplSWindowFactory<SWkeWebkit>());//עWKE
        }
        theApp->RegisterWndFactory(TplSWindowFactory<SGifPlayer>());//עGIFPlayer
        theApp->RegisterSkinFactory(TplSkinFactory<SSkinGif>());//עSkinGif
        theApp->RegisterSkinFactory(TplSkinFactory<SSkinAPNG>());//עSkinGif

        theApp->RegisterWndFactory(TplSWindowFactory<SIPAddressCtrl>());//עIPؼ
        theApp->RegisterWndFactory(TplSWindowFactory<SPropertyGrid>());//עԱؼ
        SSkinGif::Gdiplus_Startup();

        //ϵͳԴ
        HMODULE hSysResource=LoadLibrary(SYS_NAMED_RESOURCE);
        if(hSysResource)
        {
            CAutoRefPtr<IResProvider> sysSesProvider;
            CreateResProvider(RES_PE,(IObjRef**)&sysSesProvider);
            sysSesProvider->Init((WPARAM)hSysResource,0);
            theApp->LoadSystemNamedResource(sysSesProvider);
        }
        //hookƲ˵ı߿
        CMenuWndHook::InstallHook(hInstance,L"_skin.sys.menu.border");

        //ȫԴXML
        theApp->Init(_T("xml_init"));

        {
            //ʾʹSOUIӦó򴰿,Ϊ˱洰ڶ󣬰һ㡣
            CMainDlg dlgMain;
            dlgMain.Create(GetActiveWindow(),0,0,800,600);
            dlgMain.GetNative()->SendMessage(WM_INITDIALOG);
            dlgMain.CenterWindow();
            dlgMain.ShowWindow(SW_SHOWNORMAL);
            nRet=theApp->Run(dlgMain.m_hWnd);
        }

        //Ӧó˳
        delete theApp;

        flashSvr.Shutdown();

        //жز˵߿hook
        CMenuWndHook::UnInstallHook();

        SSkinGif::Gdiplus_Shutdown();
    }
    delete pComMgr;
    OleUninitialize();

    return nRet;
}

<|endoftext|>


<commit_before>#include <Refal2.h>

namespace Refal2 {

CParser::CParser( IErrorHandler* errorHandler ):
	CErrorsHelper( errorHandler ),
	ruleParser( errorHandler ),
	qualifierParser( errorHandler ),
	functionBuilder( errorHandler )
{
	Reset();
}

void CParser::Reset()
{
	ruleParser.Reset();
	qualifierParser.Reset();
	state = S_Initial;
	//storedName.clear();
	entryLabel = InvalidLabel;
	currentFunction = InvalidLabel;
}

bool CParser::wordIs( const std::string& value ) const
{
	if( token.type == TT_Word ) {
		std::string lowerWord( token.value.text );
		MakeLower( lowerWord );
		return ( lowerWord == value );
	}
	return false;
}

void CParser::AddToken()
{
	switch( state ) {
		case S_Initial:
			parsingInitial();
			break;
		case S_IgnoreLine:
			parsingIgnoreLine();
			break;
		case S_Word:
			parsingWord();
			break;
		case S_WordBlank:
			parsingWordBlank();
			break;
		case S_WordBlankS:
			parsingWordBlankS();
			break;
		case S_Blank:
			parsingBlank();
			break;
		case S_Directive:
			parsingDirective();
			break;
		case S_Qualifier:
			parsingQualifier();
			break;
		case S_Rule:
			parsingRule();
			break;
		default:
			assert( false );
			break;
	}
}

void CParser::parsingInitial()
{
	if( token.type == TT_Word ) {
		ruleParser.EndFunction(); // action
		token.Move( savedToken );
		state = S_Word;
	} else if( token.type == TT_Blank ) {
		state = S_Blank;
	} else if( token.type != TT_LineFeed ) {
		ruleParser.EndFunction(); // action
		error( EC_LineShouldBeginWithIdentifierOrSpace );
		state = S_IgnoreLine;
	}
}

void CParser::parsingIgnoreLine()
{
	if( token.type == TT_LineFeed ) {
		state = S_Initial;
	}
}

void CParser::parsingWord()
{
	if( token.type == TT_LineFeed ) {
		ruleParser.BeginFunction( savedToken ); // action
		state = S_Initial;
	} else if( token.type == TT_Blank ) {
		state = S_WordBlank;
	} else {
		ruleParser.BeginFunction( savedToken ); // action
		state = S_Rule;
		AddToken();
	}
}

void CParser::parsingWordBlank()
{
	if( wordIs( "start" ) ) {
		state = S_Directive;
	} else if( wordIs( "s" ) ) {
		state = S_WordBlankS;
	} else {
		ruleParser.BeginFunction( savedToken ); // action
		state = S_Rule;
		AddToken();
	}
}

void CParser::parsingWordBlankS()
{
	if( token.type == TT_Blank ) {
		if( qualifierParser.StartNamedQualifier( savedToken ) ) {
			state = S_Qualifier;
		} else {
			state = S_IgnoreLine;
		}
	} else {
		token.Swap( savedToken );
		ruleParser.BeginFunction( token ); // action
		state = S_Rule;
		AddToken();
		savedToken.Move( token );
		AddToken();
	}
}

void CParser::parsingBlank()
{
	if( token.type == TT_Word ) {
		if( wordIs( "start" )
			|| wordIs( "end" )
			|| wordIs( "entry" )
			|| wordIs( "empty" )
			|| wordIs( "swap" )
			|| wordIs( "extrn" ) )
		{
			ruleParser.EndFunction(); // action
			state = S_Directive;
			return;
		}
	}
	ruleParser.BeginRule();
	state = S_Rule;
	AddToken();
}

void CParser::parsingDirective()
{
	std::ostringstream errorStream;
	errorStream << ":" << token.line << ":" << token.position
		<< ": error in directive: " << "not implemented yet" << ".";
	CErrorsHelper::Error( errorStream.str() );
	state = S_IgnoreLine;
}

void CParser::parsingQualifier()
{
	if( qualifierParser.AddToken( token ) ) {
		if( qualifierParser.HasErrors() ) {
			state = S_IgnoreLine;
			AddToken();
		} else {
			state = S_Initial;
		}
	}
}

void CParser::parsingRule()
{
	if( ruleParser.AddToken( token ) ) {
		if( ruleParser.HasErrors() ) {
			state = S_IgnoreLine;
			AddToken();
		} else {
			state = S_Initial;
		}
	}
}

void CParser::error( TErrorCode errorCode )
{
	std::ostringstream errorStream;
	errorStream << token.line << ":" << token.position << ": error: ";
	switch( errorCode ) {
		case EC_LineShouldBeginWithIdentifierOrSpace:
			errorStream << "line should begin with identifier or space";
			break;
		case EC_NewLineExpected:
			errorStream << "line feed expected";
			break;
		case EC_UnexpectedLexemeAfterIdentifierInTheBeginningOfLine:
			errorStream << "unexpected token after identifier in the beginning of the line";
		case EC_STUB:
			errorStream << "stub" ;
			break;
		default:
			assert( false );
			break;
	}
	errorStream << ".";
	CErrorsHelper::Error( errorStream.str() );
}

void CParser::addDeclarationOfFunction( const std::string& name )
{
	addEndOfFunction();

	currentFunction = LabelTable.AddLabel( name );
	CFunction& tmpFunction = LabelTable.GetLabelFunction( currentFunction );

	if( !tmpFunction.IsDeclared() ) {
		// TODO: error, ignore
		error( EC_STUB );
	} else {
		tmpFunction.SetDefined();
		std::cout << "addDeclarationOfFunction: {" << name << "}\n";
	}
}

void CParser::addEndOfFunction()
{
	if( currentFunction != InvalidLabel ) {
		CFunction& tmpFunction = LabelTable.GetLabelFunction( currentFunction );
		if( tmpFunction.IsDefined() ) {
			functionBuilder.Export( tmpFunction );
			if( tmpFunction.IsParsed() ) {
				PrintFunction( tmpFunction );
			}
			std::cout << "addEndOfFunction: {" <<
				LabelTable.GetLabelText( currentFunction ) << "}\n";
		}
		currentFunction = InvalidLabel;
		functionBuilder.Reset();
	}
}

void CParser::addEmptyFunction( const std::string& name )
{
	std::cout << "Empty: " << name << "\n";
	TLabel emptyLabel = LabelTable.AddLabel( name );
	CFunction& emptyFunction = LabelTable.GetLabelFunction( emptyLabel );
	if( emptyFunction.IsDeclared() ) {
		emptyFunction.SetEmpty();
	} else if( emptyFunction.IsEmpty() ) {
		// TODO: warning, such empty function %function% already defined
	} else if( emptyFunction.IsDefined() || emptyFunction.IsParsed() ) {
		// TODO: error, %function% already defined in program
		error( EC_STUB );
	} else if( emptyFunction.IsExternal() ) {
		// TODO: error, %function% already defined as external function
		error( EC_STUB );
	} else {
		assert( false );
	}
}

void CParser::addEntryFunction( const std::string& name )
{
	std::cout << "Entry: " << name << "\n";
	if( entryLabel == InvalidLabel ) {
		entryLabel = LabelTable.AddLabel( name );
		CFunction& entryFunction = LabelTable.GetLabelFunction( entryLabel );
		if( entryFunction.IsEmpty() ) {
			// TODO: error, entry %function% cannot be empty function
			error( EC_STUB );
		} else if( entryFunction.IsExternal() ) {
			// TODO: error, entry %function% cannot be external function
			error( EC_STUB );
		}
	} else {
		// TODO: error, redeclaration of entry
		error( EC_STUB );
	}
}

bool ExtrnPrint( CUnitList& argument, std::string& errorText );
bool ExtrnPrintm( CUnitList& argument, std::string& errorText );
bool ExtrnProut( CUnitList& argument, std::string& errorText );
bool ExtrnProutm( CUnitList& argument, std::string& errorText );

void CParser::addExtrnFunction( const std::string& name,
	const std::string& standartName )
{
	std::cout << "Extrn: " << name << "(" << standartName << ")\n";
	TLabel externalLabel = LabelTable.AddLabel( name );
	CFunction& externalFunction = LabelTable.GetLabelFunction( externalLabel );
	if( externalFunction.IsDeclared() ) {
		// TODO: add external
		if( standartName == "print" ) {
			externalFunction.SetExternal( ExtrnPrint );
		} else if( standartName == "printm" ) {
			externalFunction.SetExternal( ExtrnPrintm );
		} else if( standartName == "prout" ) {
			externalFunction.SetExternal( ExtrnProut );
		} else if( standartName == "proutm" ) {
			externalFunction.SetExternal( ExtrnProutm );
		} else {
			//error( EC_STUB );
		}
	} else if( externalFunction.IsEmpty() ) {
		// TODO: error, %function% already defined as empty function
		error( EC_STUB );
	} else if( externalFunction.IsDefined() || externalFunction.IsParsed() ) {
		// TODO: error, %function% already defined in program
		error( EC_STUB );
	} else if( externalFunction.IsExternal() ) {
		// TODO: error, %function% already defined as external function
		error( EC_STUB );
	} else {
		assert( false );
	}
}

} // end of namespace Refal2
<commit_msg>remove commented line<commit_after>#include <Refal2.h>

namespace Refal2 {

CParser::CParser( IErrorHandler* errorHandler ):
	CErrorsHelper( errorHandler ),
	ruleParser( errorHandler ),
	qualifierParser( errorHandler ),
	functionBuilder( errorHandler )
{
	Reset();
}

void CParser::Reset()
{
	ruleParser.Reset();
	qualifierParser.Reset();
	state = S_Initial;
	entryLabel = InvalidLabel;
	currentFunction = InvalidLabel;
}

bool CParser::wordIs( const std::string& value ) const
{
	if( token.type == TT_Word ) {
		std::string lowerWord( token.value.text );
		MakeLower( lowerWord );
		return ( lowerWord == value );
	}
	return false;
}

void CParser::AddToken()
{
	switch( state ) {
		case S_Initial:
			parsingInitial();
			break;
		case S_IgnoreLine:
			parsingIgnoreLine();
			break;
		case S_Word:
			parsingWord();
			break;
		case S_WordBlank:
			parsingWordBlank();
			break;
		case S_WordBlankS:
			parsingWordBlankS();
			break;
		case S_Blank:
			parsingBlank();
			break;
		case S_Directive:
			parsingDirective();
			break;
		case S_Qualifier:
			parsingQualifier();
			break;
		case S_Rule:
			parsingRule();
			break;
		default:
			assert( false );
			break;
	}
}

void CParser::parsingInitial()
{
	if( token.type == TT_Word ) {
		ruleParser.EndFunction(); // action
		token.Move( savedToken );
		state = S_Word;
	} else if( token.type == TT_Blank ) {
		state = S_Blank;
	} else if( token.type != TT_LineFeed ) {
		ruleParser.EndFunction(); // action
		error( EC_LineShouldBeginWithIdentifierOrSpace );
		state = S_IgnoreLine;
	}
}

void CParser::parsingIgnoreLine()
{
	if( token.type == TT_LineFeed ) {
		state = S_Initial;
	}
}

void CParser::parsingWord()
{
	if( token.type == TT_LineFeed ) {
		ruleParser.BeginFunction( savedToken ); // action
		state = S_Initial;
	} else if( token.type == TT_Blank ) {
		state = S_WordBlank;
	} else {
		ruleParser.BeginFunction( savedToken ); // action
		state = S_Rule;
		AddToken();
	}
}

void CParser::parsingWordBlank()
{
	if( wordIs( "start" ) ) {
		state = S_Directive;
	} else if( wordIs( "s" ) ) {
		state = S_WordBlankS;
	} else {
		ruleParser.BeginFunction( savedToken ); // action
		state = S_Rule;
		AddToken();
	}
}

void CParser::parsingWordBlankS()
{
	if( token.type == TT_Blank ) {
		if( qualifierParser.StartNamedQualifier( savedToken ) ) {
			state = S_Qualifier;
		} else {
			state = S_IgnoreLine;
		}
	} else {
		token.Swap( savedToken );
		ruleParser.BeginFunction( token ); // action
		state = S_Rule;
		AddToken();
		savedToken.Move( token );
		AddToken();
	}
}

void CParser::parsingBlank()
{
	if( token.type == TT_Word ) {
		if( wordIs( "start" )
			|| wordIs( "end" )
			|| wordIs( "entry" )
			|| wordIs( "empty" )
			|| wordIs( "swap" )
			|| wordIs( "extrn" ) )
		{
			ruleParser.EndFunction(); // action
			state = S_Directive;
			return;
		}
	}
	ruleParser.BeginRule();
	state = S_Rule;
	AddToken();
}

void CParser::parsingDirective()
{
	std::ostringstream errorStream;
	errorStream << ":" << token.line << ":" << token.position
		<< ": error in directive: " << "not implemented yet" << ".";
	CErrorsHelper::Error( errorStream.str() );
	state = S_IgnoreLine;
}

void CParser::parsingQualifier()
{
	if( qualifierParser.AddToken( token ) ) {
		if( qualifierParser.HasErrors() ) {
			state = S_IgnoreLine;
			AddToken();
		} else {
			state = S_Initial;
		}
	}
}

void CParser::parsingRule()
{
	if( ruleParser.AddToken( token ) ) {
		if( ruleParser.HasErrors() ) {
			state = S_IgnoreLine;
			AddToken();
		} else {
			state = S_Initial;
		}
	}
}

void CParser::error( TErrorCode errorCode )
{
	std::ostringstream errorStream;
	errorStream << token.line << ":" << token.position << ": error: ";
	switch( errorCode ) {
		case EC_LineShouldBeginWithIdentifierOrSpace:
			errorStream << "line should begin with identifier or space";
			break;
		case EC_NewLineExpected:
			errorStream << "line feed expected";
			break;
		case EC_UnexpectedLexemeAfterIdentifierInTheBeginningOfLine:
			errorStream << "unexpected token after identifier in the beginning of the line";
		case EC_STUB:
			errorStream << "stub" ;
			break;
		default:
			assert( false );
			break;
	}
	errorStream << ".";
	CErrorsHelper::Error( errorStream.str() );
}

void CParser::addDeclarationOfFunction( const std::string& name )
{
	addEndOfFunction();

	currentFunction = LabelTable.AddLabel( name );
	CFunction& tmpFunction = LabelTable.GetLabelFunction( currentFunction );

	if( !tmpFunction.IsDeclared() ) {
		// TODO: error, ignore
		error( EC_STUB );
	} else {
		tmpFunction.SetDefined();
		std::cout << "addDeclarationOfFunction: {" << name << "}\n";
	}
}

void CParser::addEndOfFunction()
{
	if( currentFunction != InvalidLabel ) {
		CFunction& tmpFunction = LabelTable.GetLabelFunction( currentFunction );
		if( tmpFunction.IsDefined() ) {
			functionBuilder.Export( tmpFunction );
			if( tmpFunction.IsParsed() ) {
				PrintFunction( tmpFunction );
			}
			std::cout << "addEndOfFunction: {" <<
				LabelTable.GetLabelText( currentFunction ) << "}\n";
		}
		currentFunction = InvalidLabel;
		functionBuilder.Reset();
	}
}

void CParser::addEmptyFunction( const std::string& name )
{
	std::cout << "Empty: " << name << "\n";
	TLabel emptyLabel = LabelTable.AddLabel( name );
	CFunction& emptyFunction = LabelTable.GetLabelFunction( emptyLabel );
	if( emptyFunction.IsDeclared() ) {
		emptyFunction.SetEmpty();
	} else if( emptyFunction.IsEmpty() ) {
		// TODO: warning, such empty function %function% already defined
	} else if( emptyFunction.IsDefined() || emptyFunction.IsParsed() ) {
		// TODO: error, %function% already defined in program
		error( EC_STUB );
	} else if( emptyFunction.IsExternal() ) {
		// TODO: error, %function% already defined as external function
		error( EC_STUB );
	} else {
		assert( false );
	}
}

void CParser::addEntryFunction( const std::string& name )
{
	std::cout << "Entry: " << name << "\n";
	if( entryLabel == InvalidLabel ) {
		entryLabel = LabelTable.AddLabel( name );
		CFunction& entryFunction = LabelTable.GetLabelFunction( entryLabel );
		if( entryFunction.IsEmpty() ) {
			// TODO: error, entry %function% cannot be empty function
			error( EC_STUB );
		} else if( entryFunction.IsExternal() ) {
			// TODO: error, entry %function% cannot be external function
			error( EC_STUB );
		}
	} else {
		// TODO: error, redeclaration of entry
		error( EC_STUB );
	}
}

bool ExtrnPrint( CUnitList& argument, std::string& errorText );
bool ExtrnPrintm( CUnitList& argument, std::string& errorText );
bool ExtrnProut( CUnitList& argument, std::string& errorText );
bool ExtrnProutm( CUnitList& argument, std::string& errorText );

void CParser::addExtrnFunction( const std::string& name,
	const std::string& standartName )
{
	std::cout << "Extrn: " << name << "(" << standartName << ")\n";
	TLabel externalLabel = LabelTable.AddLabel( name );
	CFunction& externalFunction = LabelTable.GetLabelFunction( externalLabel );
	if( externalFunction.IsDeclared() ) {
		// TODO: add external
		if( standartName == "print" ) {
			externalFunction.SetExternal( ExtrnPrint );
		} else if( standartName == "printm" ) {
			externalFunction.SetExternal( ExtrnPrintm );
		} else if( standartName == "prout" ) {
			externalFunction.SetExternal( ExtrnProut );
		} else if( standartName == "proutm" ) {
			externalFunction.SetExternal( ExtrnProutm );
		} else {
			//error( EC_STUB );
		}
	} else if( externalFunction.IsEmpty() ) {
		// TODO: error, %function% already defined as empty function
		error( EC_STUB );
	} else if( externalFunction.IsDefined() || externalFunction.IsParsed() ) {
		// TODO: error, %function% already defined in program
		error( EC_STUB );
	} else if( externalFunction.IsExternal() ) {
		// TODO: error, %function% already defined as external function
		error( EC_STUB );
	} else {
		assert( false );
	}
}

} // end of namespace Refal2
<|endoftext|>