<commit_before>/*
 * Copyright 2006-2008 The FLWOR Foundation.
 *
 * 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 "compiler/api/compiler_api.h"

#include <istream>
#include <memory>
#include "system/globalenv.h"
#include "compiler/api/compiler_api_impl.h"
#include "compiler/api/compilercb.h"
#include "context/static_context.h"

#include "types/root_typemanager.h"
#include "types/delegating_typemanager.h"

#include "compiler/parser/xquery_driver.h"
#include "compiler/parsetree/parsenode_base.h"
#include "compiler/expression/expr_base.h"
#include "compiler/translator/translator.h"
#include "compiler/normalizer/normalizer.h"
#include "compiler/rewriter/framework/rewriter_context.h"
#include "compiler/rewriter/framework/rewriter.h"
#include "compiler/codegen/plan_visitor.h"

#include "runtime/api/plan_wrapper.h"
#include "util/properties.h"

#include "compiler/parsetree/parsenode_print_xml_visitor.h"
#include "runtime/visitors/printervisitor.h"
#include "runtime/visitors/iterprinter.h"

#ifdef ZORBA_DEBUGGER
#include "debugger/debugger_server.h"
#include "compiler/dewey/dewey.h"
#endif
#ifdef ZORBA_XQUERYX
#include "compiler/xqueryx/xqueryx_to_xquery.h"
#endif
namespace zorba {

  // static context is in the compilercb
XQueryCompiler::XQueryCompiler(CompilerCB* aCompilerCB)
  :
  theCompilerCB(aCompilerCB)
{
  aCompilerCB->m_sctx->set_typemanager(rchandle<TypeManager>(new DelegatingTypeManager(&GENV_TYPESYSTEM)));
}

XQueryCompiler::~XQueryCompiler()
{
}

static void print_ast_tree (const parsenode *n, std::string name) {
  std::cout << "AST for " << name << "\n";
  print_parsetree_xml (std::cout, n);
  std::cout << std::endl;
}

void XQueryCompiler::parseOnly(std::istream& aXQuery, const xqpString& aFileName)
{
  parsenode_t pn = parse(aXQuery, aFileName);
}

PlanIter_t XQueryCompiler::compile(parsenode_t ast)
{
  expr_t lExpr = normalize(ast);
  lExpr = optimize(lExpr);

  // TODO we might pass the CompilerCB here, however, we also need it in the runtime
  // because codegeneration for udfs is triggered there
  // then however, the compilercb can not be const in the runtime?!
  PlanIter_t plan = codegen ("main query", lExpr, theCompilerCB);

  return plan;
}

PlanIter_t
XQueryCompiler::compile(std::istream& aXQuery, const xqpString & aFileName)
{
  parsenode_t lAST = parse(aXQuery, aFileName);
  return compile (lAST);
}

parsenode_t
XQueryCompiler::parse(std::istream& aXQuery, const xqpString & aFileName)
{
  // TODO: move these out
  if (Properties::instance()->printAst())
    theCompilerCB->m_config.parse_cb = print_ast_tree;

  std::istream  *xquery_stream = &aXQuery;

#ifdef ZORBA_XQUERYX
  char  *converted_xquery_str = NULL;
  std::string   xquery_str;
  bool  is_xqueryx = false;
  {
    char  strtemp[1000];
    int   nr_read = 1;
    do
    {
      strtemp[0] = 0;
      aXQuery.read(strtemp, sizeof(strtemp)-1);
      strtemp[aXQuery.gcount()] = 0;
      xquery_str += strtemp;
    }while(aXQuery.gcount() == (sizeof(strtemp)-1));
  }
  XQueryXConvertor    *xqxconvertor = GENV.getXQueryXConvertor();
  //if(theCompilerCB->xqformat == XQUERYX_2005)
  if(xqxconvertor->isXQueryX((char*)xquery_str.c_str()))//identify XQueryX by content: root tag = "<prefix:module ... xmlns:prefix="http://www.w3.org/2005/XQueryX" ... > "
  {
    is_xqueryx = true;
    //translate from xqueryx to xquery using XSLT
    //read all input stream into std::string

    converted_xquery_str = xqxconvertor->XQueryX2XQuery(xquery_str.c_str());
    //debug
    printf("\n\n");
    printf(converted_xquery_str);
    //end debug
    xquery_stream = new std::istringstream(converted_xquery_str);
  }
  else
  {
    xquery_stream = new std::istringstream(xquery_str);
  }
#endif

  xquery_driver lDriver(&*theCompilerCB);
  lDriver.parse_stream(*xquery_stream, aFileName);
#ifdef ZORBA_XQUERYX
  delete xquery_stream;
  if(is_xqueryx)
  {
    //XQueryXConvertor    *xqxconvertor = GENV.getXQueryXConvertor();
    xqxconvertor->freeResult(converted_xquery_str);
  }
#endif
  parsenode_t node = lDriver.get_expr();
  if (typeid (*node) == typeid (ParseErrorNode)) {
    ParseErrorNode *err = static_cast<ParseErrorNode *> (&*node);
    ZORBA_ERROR_LOC_DESC( XPST0003, err->get_location (), err->msg);
    node = NULL;
  }
  return node;
}

expr_t
XQueryCompiler::normalize(parsenode_t aParsenode)
{
  expr_t lExpr = translate (*aParsenode, theCompilerCB);
  if ( lExpr == NULL ) { // TODO: can this happen?
    ZORBA_ERROR( API0002_COMPILE_FAILED);
    return NULL;
  }
#ifdef ZORBA_DEBUGGER
  if(theCompilerCB->m_debugger != 0)
  {
    ZorbaDebugger* lDebugger = theCompilerCB->m_debugger;
    lDebugger->theClassification = classify(*aParsenode);
    std::list<parsenode_t> lModules = lDebugger->getModules();
    std::list<parsenode_t>::iterator it;
    for(it=lModules.begin(); it!=lModules.end(); ++it)
    {
      Classification_t lClassification = classify(**it);
      lDebugger->theClassification.insert(lClassification.begin(), lClassification.end());
    }

#if 0
    Classification_t lClassification = theCompilerCB->m_debugger->theClassification;
    Classification_t::iterator lIter;
    for(lIter=lClassification.begin(); lIter!=lClassification.end(); ++lIter)
    {
      std::stack<unsigned int> s(lIter->second);
      while(!s.empty())
      {
        std::cerr << s.top();
        s.pop();
      }
      std::cerr << ' ' << lIter->first << ' ' << lIter->first.getFunctionName() << std::endl;
    }
#endif
  }
#endif
  normalize_expr_tree ("query", theCompilerCB, lExpr, NULL);
  return lExpr;
}

expr_t
XQueryCompiler::optimize(expr_t lExpr)
{
  if (theCompilerCB->m_config.opt_level > CompilerCB::config_t::O0) {
    RewriterContext rCtx(theCompilerCB, lExpr);
    GENV_COMPILERSUBSYS.getDefaultOptimizingRewriter()->rewrite(rCtx);
    lExpr = rCtx.getRoot();

    if (theCompilerCB->m_config.optimize_cb != NULL)
      theCompilerCB->m_config.optimize_cb (&*lExpr, "query");
  }

  return lExpr;
}

XQueryCompilerSubsystem::XQueryCompilerSubsystem()
{
}

XQueryCompilerSubsystem::~XQueryCompilerSubsystem() throw ()
{
}

std::auto_ptr<XQueryCompilerSubsystem> XQueryCompilerSubsystem::create()
{
  return std::auto_ptr<XQueryCompilerSubsystem>(new XQueryCompilerSubsystemImpl());
}

}
/* vim:set ts=2 sw=2: */
<commit_msg>Removed XQueryX debug message.<commit_after>/*
 * Copyright 2006-2008 The FLWOR Foundation.
 *
 * 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 "compiler/api/compiler_api.h"

#include <istream>
#include <memory>
#include "system/globalenv.h"
#include "compiler/api/compiler_api_impl.h"
#include "compiler/api/compilercb.h"
#include "context/static_context.h"

#include "types/root_typemanager.h"
#include "types/delegating_typemanager.h"

#include "compiler/parser/xquery_driver.h"
#include "compiler/parsetree/parsenode_base.h"
#include "compiler/expression/expr_base.h"
#include "compiler/translator/translator.h"
#include "compiler/normalizer/normalizer.h"
#include "compiler/rewriter/framework/rewriter_context.h"
#include "compiler/rewriter/framework/rewriter.h"
#include "compiler/codegen/plan_visitor.h"

#include "runtime/api/plan_wrapper.h"
#include "util/properties.h"

#include "compiler/parsetree/parsenode_print_xml_visitor.h"
#include "runtime/visitors/printervisitor.h"
#include "runtime/visitors/iterprinter.h"

#ifdef ZORBA_DEBUGGER
#include "debugger/debugger_server.h"
#include "compiler/dewey/dewey.h"
#endif
#ifdef ZORBA_XQUERYX
#include "compiler/xqueryx/xqueryx_to_xquery.h"
#endif
namespace zorba {

  // static context is in the compilercb
XQueryCompiler::XQueryCompiler(CompilerCB* aCompilerCB)
  :
  theCompilerCB(aCompilerCB)
{
  aCompilerCB->m_sctx->set_typemanager(rchandle<TypeManager>(new DelegatingTypeManager(&GENV_TYPESYSTEM)));
}

XQueryCompiler::~XQueryCompiler()
{
}

static void print_ast_tree (const parsenode *n, std::string name) {
  std::cout << "AST for " << name << "\n";
  print_parsetree_xml (std::cout, n);
  std::cout << std::endl;
}

void XQueryCompiler::parseOnly(std::istream& aXQuery, const xqpString& aFileName)
{
  parsenode_t pn = parse(aXQuery, aFileName);
}

PlanIter_t XQueryCompiler::compile(parsenode_t ast)
{
  expr_t lExpr = normalize(ast);
  lExpr = optimize(lExpr);

  // TODO we might pass the CompilerCB here, however, we also need it in the runtime
  // because codegeneration for udfs is triggered there
  // then however, the compilercb can not be const in the runtime?!
  PlanIter_t plan = codegen ("main query", lExpr, theCompilerCB);

  return plan;
}

PlanIter_t
XQueryCompiler::compile(std::istream& aXQuery, const xqpString & aFileName)
{
  parsenode_t lAST = parse(aXQuery, aFileName);
  return compile (lAST);
}

parsenode_t
XQueryCompiler::parse(std::istream& aXQuery, const xqpString & aFileName)
{
  // TODO: move these out
  if (Properties::instance()->printAst())
    theCompilerCB->m_config.parse_cb = print_ast_tree;

  std::istream  *xquery_stream = &aXQuery;

#ifdef ZORBA_XQUERYX
  char  *converted_xquery_str = NULL;
  std::string   xquery_str;
  bool  is_xqueryx = false;
  {
    char  strtemp[1000];
    int   nr_read = 1;
    do
    {
      strtemp[0] = 0;
      aXQuery.read(strtemp, sizeof(strtemp)-1);
      strtemp[aXQuery.gcount()] = 0;
      xquery_str += strtemp;
    }while(aXQuery.gcount() == (sizeof(strtemp)-1));
  }
  XQueryXConvertor    *xqxconvertor = GENV.getXQueryXConvertor();
  //if(theCompilerCB->xqformat == XQUERYX_2005)
  if(xqxconvertor->isXQueryX((char*)xquery_str.c_str()))//identify XQueryX by content: root tag = "<prefix:module ... xmlns:prefix="http://www.w3.org/2005/XQueryX" ... > "
  {
    is_xqueryx = true;
    //translate from xqueryx to xquery using XSLT
    //read all input stream into std::string

    converted_xquery_str = xqxconvertor->XQueryX2XQuery(xquery_str.c_str());

#ifdef DEBUG
    //debug
    printf("\n\n");
    printf(converted_xquery_str);
    //end debug
#endif
    xquery_stream = new std::istringstream(converted_xquery_str);
  }
  else
  {
    xquery_stream = new std::istringstream(xquery_str);
  }
#endif

  xquery_driver lDriver(&*theCompilerCB);
  lDriver.parse_stream(*xquery_stream, aFileName);
#ifdef ZORBA_XQUERYX
  delete xquery_stream;
  if(is_xqueryx)
  {
    //XQueryXConvertor    *xqxconvertor = GENV.getXQueryXConvertor();
    xqxconvertor->freeResult(converted_xquery_str);
  }
#endif
  parsenode_t node = lDriver.get_expr();
  if (typeid (*node) == typeid (ParseErrorNode)) {
    ParseErrorNode *err = static_cast<ParseErrorNode *> (&*node);
    ZORBA_ERROR_LOC_DESC( XPST0003, err->get_location (), err->msg);
    node = NULL;
  }
  return node;
}

expr_t
XQueryCompiler::normalize(parsenode_t aParsenode)
{
  expr_t lExpr = translate (*aParsenode, theCompilerCB);
  if ( lExpr == NULL ) { // TODO: can this happen?
    ZORBA_ERROR( API0002_COMPILE_FAILED);
    return NULL;
  }
#ifdef ZORBA_DEBUGGER
  if(theCompilerCB->m_debugger != 0)
  {
    ZorbaDebugger* lDebugger = theCompilerCB->m_debugger;
    lDebugger->theClassification = classify(*aParsenode);
    std::list<parsenode_t> lModules = lDebugger->getModules();
    std::list<parsenode_t>::iterator it;
    for(it=lModules.begin(); it!=lModules.end(); ++it)
    {
      Classification_t lClassification = classify(**it);
      lDebugger->theClassification.insert(lClassification.begin(), lClassification.end());
    }

#if 0
    Classification_t lClassification = theCompilerCB->m_debugger->theClassification;
    Classification_t::iterator lIter;
    for(lIter=lClassification.begin(); lIter!=lClassification.end(); ++lIter)
    {
      std::stack<unsigned int> s(lIter->second);
      while(!s.empty())
      {
        std::cerr << s.top();
        s.pop();
      }
      std::cerr << ' ' << lIter->first << ' ' << lIter->first.getFunctionName() << std::endl;
    }
#endif
  }
#endif
  normalize_expr_tree ("query", theCompilerCB, lExpr, NULL);
  return lExpr;
}

expr_t
XQueryCompiler::optimize(expr_t lExpr)
{
  if (theCompilerCB->m_config.opt_level > CompilerCB::config_t::O0) {
    RewriterContext rCtx(theCompilerCB, lExpr);
    GENV_COMPILERSUBSYS.getDefaultOptimizingRewriter()->rewrite(rCtx);
    lExpr = rCtx.getRoot();

    if (theCompilerCB->m_config.optimize_cb != NULL)
      theCompilerCB->m_config.optimize_cb (&*lExpr, "query");
  }

  return lExpr;
}

XQueryCompilerSubsystem::XQueryCompilerSubsystem()
{
}

XQueryCompilerSubsystem::~XQueryCompilerSubsystem() throw ()
{
}

std::auto_ptr<XQueryCompilerSubsystem> XQueryCompilerSubsystem::create()
{
  return std::auto_ptr<XQueryCompilerSubsystem>(new XQueryCompilerSubsystemImpl());
}

}
/* vim:set ts=2 sw=2: */
<|endoftext|>


<commit_before>//
// Created by Lukas Kollmer on 17.04.17.
//

#include <node.h>
#include <string>
#include <iostream>
#include <mach-o/dyld.h>
#include <array>
#include "Proxy.h"
#include "objc_call.h"
#include <typeinfo>

#include "Invocation.h"
#include "utils.h"

extern "C" {
#include <objc/message.h>
#include <objc/runtime.h>
}

SEL resolveSelector(id target, const char *sel) {
    std::string selector(sel);

    std::replace(selector.begin(), selector.end(), '_', ':'); // TODO make this smart and support methods that include an unserscore
    return sel_getUid(selector.c_str());
}

#define HANDLE_RETURN_TYPE(type) \
    type retval; \
    invocation.GetReturnValue(&retval); \
    args.GetReturnValue().Set(retval); \
    return; \

#define HANDLE_RETURN_TYPE_CAST(type, castType) \
    type retval; \
    invocation.GetReturnValue(&retval); \
    args.GetReturnValue().Set((castType)retval); \
    return; \

#define ARGTYPE_NOT_SUPPORTED(type) \
    char *excMessage; \
    asprintf(&excMessage, "Error setting argument: Type '%s' not yet supported. Sorry.", type); \
    isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, excMessage))); \
    free(excMessage); \
    return; \

using namespace v8;

namespace ObjC {

    Persistent<Function> Proxy::constructor;

    Proxy::Proxy(enum Type type, id obj) : type_(type), obj_(obj) {}
    Proxy::~Proxy() {}

    void Proxy::Init(Local<Object> exports) {
        Isolate *isolate = exports->GetIsolate();
        HandleScope scope(isolate);

        Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, New);
        tpl->SetClassName(String::NewFromUtf8(isolate, "Proxy"));
        tpl->InstanceTemplate()->SetInternalFieldCount(1);

        NODE_SET_PROTOTYPE_METHOD(tpl, "call", Call);
        NODE_SET_PROTOTYPE_METHOD(tpl, "description", Description);
        NODE_SET_PROTOTYPE_METHOD(tpl, "type", Type);
        NODE_SET_PROTOTYPE_METHOD(tpl, "returnTypeOfMethod", ReturnTypeOfMethod);

        constructor.Reset(isolate, tpl->GetFunction());
        exports->Set(String::NewFromUtf8(isolate, "Proxy"), tpl->GetFunction());
    }

    void Proxy::New(const FunctionCallbackInfo<Value>& args) {
        Isolate *isolate = args.GetIsolate();
        HandleScope scope(isolate);

        id object;

        enum Type type = static_cast<enum Type>(args[0]->Int32Value());
        switch (type) {
            case Type::klass: {
                auto classname = ValueToChar(isolate, args[1]);
                object = (id)objc_getClass(classname);
                if (object == NULL) {
                    char *excMessage;
                    asprintf(&excMessage, "Error: Class with name '%s' doesn't exist", classname);
                    isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, excMessage)));
                    free(excMessage);
                    return;
                }
                break;
            }
            case Type::instance: {
                object = (id)args[1]->ToObject()->GetAlignedPointerFromInternalField(0);
                break;
            }
        }

        Proxy *proxy = new Proxy(type, object);
        proxy->Wrap(args.This());

        args.GetReturnValue().Set(args.This());

    }

    void Proxy::Type(const FunctionCallbackInfo<Value> &args) {
        Isolate *isolate = args.GetIsolate();
        HandleScope scope(isolate);

        Proxy *obj = ObjectWrap::Unwrap<Proxy>(args.This());

        int type = static_cast<int>(obj->type_);

        args.GetReturnValue().Set(type);
    }

    void Proxy::Description(const FunctionCallbackInfo<Value> &args) {
        Isolate *isolate = args.GetIsolate();
        HandleScope scope(isolate);

        Proxy *object = ObjectWrap::Unwrap<Proxy>(args.This());

        id description = objc_call(id, object->obj_, "description");
        char *desc = objc_call(char*, description, "UTF8String");

        args.GetReturnValue().Set(String::NewFromUtf8(isolate, desc));

    }

    void Proxy::Call(const FunctionCallbackInfo<Value>& args) {
        Isolate *isolate = args.GetIsolate();
        HandleScope scope(isolate);

        Local<ObjectTemplate> TemplateObject = ObjectTemplate::New();
        TemplateObject->SetInternalFieldCount(1);

        Proxy *obj = ObjectWrap::Unwrap<Proxy>(args.This());

        SEL sel = resolveSelector(obj->obj_, ValueToChar(isolate, args[0]));

        Method method;

        switch (obj->type_) {
            case Type::klass: method = class_getClassMethod((Class)obj->obj_, sel); break;
            case Type::instance: method = class_getInstanceMethod(object_getClass(obj->obj_), sel); break;
        }

        //printf("%s - %s\n", sel_getName(sel), method_getTypeEncoding(method));

        auto invocation = ObjC::Invocation(obj->obj_, sel);
        invocation.SetTarget(obj->obj_);
        invocation.SetSelector(sel);

        for (int i = 1; i < args.Length(); ++i) {
            int objcArgumentIndex = i + 1; // +1 bc we already start at 1

            auto expectedType = method_copyArgumentType(method, (unsigned int) objcArgumentIndex);
            Local<Value> arg = args[i];

            if (arg->IsNull() || arg->IsUndefined()) {
                void* nilArgument = nullptr;
                invocation.SetArgumentAtIndex(&nilArgument, objcArgumentIndex);
                continue;
            }

            if (EQUAL(expectedType, "@")) {
                // 1. check if a wrapped object was passed
                if (arg->IsObject()) {
                    // args[i] is the JS Proxy type, we have to fetch the actual ObjC::Proxy wrapper via __ptr
                    Local<Object> wrappedObject = arg->ToObject()->Get(String::NewFromUtf8(isolate, "__ptr"))->ToObject();

                    Proxy *passedProxy = ObjectWrap::Unwrap<Proxy>(wrappedObject);
                    if (passedProxy != nullptr) {
                        id argument = passedProxy->obj_;
                        invocation.SetArgumentAtIndex(&argument, objcArgumentIndex);
                        continue;
                    } else {
                        // TODO set nil as arg
                    }
                // 2. if no wrapped object was passed, but a native type (string, number, bool), convert that
                } else if (arg->IsString()) {
                    const char* stringValue = ValueToChar(isolate, arg);

                    id NSString = (id)objc_getClass("NSString");
                    id string = objc_call(id, NSString, "stringWithUTF8String:", stringValue);

                    invocation.SetArgumentAtIndex(&string, objcArgumentIndex);
                } else if (arg->IsNumber()) {
                    double numberValue = arg->ToNumber()->Value();

                    id NSNumber = (id)objc_getClass("NSNumber");
                    id number = objc_call(id, NSNumber, "numberWithDouble:", numberValue);

                    invocation.SetArgumentAtIndex(&number, objcArgumentIndex);
                } else if (arg->IsBoolean()) {
                    bool boolValue = arg->ToBoolean()->Value();

                    id NSNumber = (id)objc_getClass("NSNumber");
                    id number = objc_call(id, NSNumber, "numberWithBool:", boolValue);

                    invocation.SetArgumentAtIndex(&number, objcArgumentIndex);
                } // TODO Convert array/dict as well?
            } else if (EQUAL(expectedType, "#")) { // Class
                // This will either take a proxy around a `Class` object or a string and convert that to the expected `Class` object
                if (arg->IsString()) {
                    const char *classname = ValueToChar(isolate, arg);
                    Class cls = objc_getClass(classname);
                    invocation.SetArgumentAtIndex(&cls, objcArgumentIndex);
                } else if (arg->IsObject()) {
                    Local<Object> wrappedObject = arg->ToObject()->Get(String::NewFromUtf8(isolate, "__ptr"))->ToObject();

                    Proxy *passedClassProxy = ObjectWrap::Unwrap<Proxy>(wrappedObject);
                    if (passedClassProxy != nullptr) {
                        if (passedClassProxy->type_ == Type::klass) {
                            Class cls = (Class)passedClassProxy->obj_;
                            invocation.SetArgumentAtIndex(&cls, objcArgumentIndex);
                        } else {
                            // TODO ???
                        }
                    } else {
                        // TODO pass nil?
                    }
                }
            } else if (EQUAL(expectedType, "c")) { // char
                ARGTYPE_NOT_SUPPORTED("char");
            } else if (EQUAL(expectedType, "i")) { // int
                int argument = arg->ToNumber()->ToInt32()->Value();
                invocation.SetArgumentAtIndex(&argument, objcArgumentIndex);
            } else if (EQUAL(expectedType, "s")) { // short
                ARGTYPE_NOT_SUPPORTED("short");
            } else if (EQUAL(expectedType, "q")) { // long long
                long long argument = (long long) arg->ToNumber()->Value();
                invocation.SetArgumentAtIndex(&argument, objcArgumentIndex);
            } else if (EQUAL(expectedType, "C")) { // unsigned char
                ARGTYPE_NOT_SUPPORTED("unsigned char");
            } else if (EQUAL(expectedType, "I")) { // unsigned int
                ARGTYPE_NOT_SUPPORTED("unsigned int");
            } else if (EQUAL(expectedType, "S")) { // unsigned short
                ARGTYPE_NOT_SUPPORTED("unsigned short");
            } else if (EQUAL(expectedType, "L")) { // unsigned long
                ARGTYPE_NOT_SUPPORTED("unsigned long");
            } else if (EQUAL(expectedType, "Q")) { // unsigned long long
                ARGTYPE_NOT_SUPPORTED("unsigned long long");
            } else if (EQUAL(expectedType, "f")) { // float
                float argument = (float) arg->ToNumber()->Value();
                invocation.SetArgumentAtIndex(&argument, objcArgumentIndex);
            } else if (EQUAL(expectedType, "d")) { // double
                double argument = arg->ToNumber()->Value();
                invocation.SetArgumentAtIndex(&argument, objcArgumentIndex);
            } else if (EQUAL(expectedType, "B")) { // bool
                bool argument = arg->ToBoolean()->Value();
                invocation.SetArgumentAtIndex(&argument, objcArgumentIndex);
            } else if (EQUAL(expectedType, "v")) { // void
                ARGTYPE_NOT_SUPPORTED("void");
            } else if (EQUAL(expectedType, "*") || EQUAL(expectedType, "r*")) { // char*, const char*
                ARGTYPE_NOT_SUPPORTED("char*");
            } else if (EQUAL(expectedType, ":")) { // SEL
                // selectors can be passed as strings.
                SEL _sel = sel_getUid(ValueToChar(isolate, arg));
                invocation.SetArgumentAtIndex(&_sel, objcArgumentIndex);
            } else if (EQUAL(expectedType, "^v") || EQUAL(expectedType, "r^v")) { // void*, const void*
                ARGTYPE_NOT_SUPPORTED("void*");
            }
        }

        //
        // Invoke
        //

        invocation.Invoke();

        //
        // Handle return value
        //

        const char *returnType = method_copyReturnType(method);
        //printf("%s - %s\n", returnType, sel_getName(sel));

        if (EQUAL(returnType, "@")) {
            id retval;
            invocation.GetReturnValue(&retval);

            auto isKindOfClass = [](id object, const char *classname) -> bool {
                return false; // TODO Re-enable this
                return objc_call(bool, object, "isKindOfClass:", objc_getClass(classname));
            };

            if (isKindOfClass(retval, "NSString")) {
                char *charValue = objc_call(char*, retval, "UTF8String");
                args.GetReturnValue().Set(String::NewFromUtf8(isolate, charValue));
                return;
            }

            if (isKindOfClass(retval, "NSNumber")) {
                double value = objc_call(double, retval, "doubleValue");
                args.GetReturnValue().Set(value);
                return;
            }

            // TODO convert other types like NSArray, NSDictionary, NSURL, etc to native objects

            Local<Object> object = TemplateObject->NewInstance();
            object->SetAlignedPointerInInternalField(0, retval);
            // TODO ^^ This sometimes crashes w/ a "pointer not aligned" error message (seems to happem at random, try to fix eventually)

            const unsigned argc = 2;
            Local<Value> argv[argc] = {Number::New(isolate, 1), object};
            Local<Function> cons = Local<Function>::New(isolate, constructor);
            Local<Context> context = isolate->GetCurrentContext();
            Local<Object> instance = cons->NewInstance(context, argc, argv).ToLocalChecked();
            args.GetReturnValue().Set(instance);
            return;
        } else if (EQUAL(returnType, "c")) { // char
            HANDLE_RETURN_TYPE(char);
        } else if (EQUAL(returnType, "i")) { // int
            HANDLE_RETURN_TYPE(int);
        } else if (EQUAL(returnType, "s")) { // short
            HANDLE_RETURN_TYPE(short);
        } else if (EQUAL(returnType, "q")) { // long long
            HANDLE_RETURN_TYPE_CAST(long long, int32_t);
        } else if (EQUAL(returnType, "C")) { // unsigned char
            HANDLE_RETURN_TYPE(unsigned char);
        } else if (EQUAL(returnType, "I")) { // unsigned int
            HANDLE_RETURN_TYPE(unsigned int);
        } else if (EQUAL(returnType, "S")) { // unsigned short
            HANDLE_RETURN_TYPE(unsigned short);
        } else if (EQUAL(returnType, "L")) { // unsigned long
            HANDLE_RETURN_TYPE_CAST(unsigned long, int32_t);
        } else if (EQUAL(returnType, "Q")) { // unsigned long long
            HANDLE_RETURN_TYPE_CAST(unsigned long long, int32_t);
        } else if (EQUAL(returnType, "f")) { // float
            HANDLE_RETURN_TYPE(float);
        } else if (EQUAL(returnType, "d")) { // double
            HANDLE_RETURN_TYPE(double);
        } else if (EQUAL(returnType, "B")) { // bool
            HANDLE_RETURN_TYPE(bool);
            //void* retval;
            //invocation.GetReturnValue(&retval);
            //args.GetReturnValue().Set((bool)retval);
            //return;
        } else if (EQUAL(returnType, "v")) { // void
            args.GetReturnValue().Set(Undefined(isolate));
        } else if (EQUAL(returnType, "*") || EQUAL(returnType, "r*")) { // char*, const char*
            char* retval;
            invocation.GetReturnValue(&retval);
            Local<Value> string = String::NewFromUtf8(isolate, retval);
            args.GetReturnValue().Set(string);
            return;
        } else if (EQUAL(returnType, "#")) { // Class
            // TODO
            args.GetReturnValue().Set(Undefined(isolate));
        } else if (EQUAL(returnType, ":")) { // SEL
            // TODO
            args.GetReturnValue().Set(Undefined(isolate));
        }

        return;
    }

    void Proxy::ReturnTypeOfMethod(const FunctionCallbackInfo<Value> &args) {
        Isolate *isolate = args.GetIsolate();
        HandleScope scope(isolate);

        Proxy *obj = ObjectWrap::Unwrap<Proxy>(args.This());
        SEL sel = resolveSelector(obj->obj_, ValueToChar(isolate, args[0]));

        Method method;

        switch (obj->type_) {
            case Type::klass: method = class_getClassMethod((Class)obj->obj_, sel); break;
            case Type::instance: method = class_getInstanceMethod(object_getClass(obj->obj_), sel); break;
        }

        const char *returnType = method_copyReturnType(method);

        args.GetReturnValue().Set(String::NewFromUtf8(isolate, returnType));
    }
}
<commit_msg>throw an error if the retval pointer isn't aligned<commit_after>//
// Created by Lukas Kollmer on 17.04.17.
//

#include <node.h>
#include <string>
#include <iostream>
#include <mach-o/dyld.h>
#include <array>
#include "Proxy.h"
#include "objc_call.h"
#include <typeinfo>

#include "Invocation.h"
#include "utils.h"

extern "C" {
#include <objc/message.h>
#include <objc/runtime.h>
}

SEL resolveSelector(id target, const char *sel) {
    std::string selector(sel);

    std::replace(selector.begin(), selector.end(), '_', ':'); // TODO make this smart and support methods that include an unserscore
    return sel_getUid(selector.c_str());
}

template< typename T >
inline bool is_aligned( T*p, size_t n = alignof(T) ){
    return 0 == reinterpret_cast<uintptr_t>(p) % n ;
}

#define HANDLE_RETURN_TYPE(type) \
    type retval; \
    invocation.GetReturnValue(&retval); \
    args.GetReturnValue().Set(retval); \
    return; \

#define HANDLE_RETURN_TYPE_CAST(type, castType) \
    type retval; \
    invocation.GetReturnValue(&retval); \
    args.GetReturnValue().Set((castType)retval); \
    return; \

#define ARGTYPE_NOT_SUPPORTED(type) \
    char *excMessage; \
    asprintf(&excMessage, "Error setting argument: Type '%s' not yet supported. Sorry.", type); \
    isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, excMessage))); \
    free(excMessage); \
    return; \

using namespace v8;

namespace ObjC {

    Persistent<Function> Proxy::constructor;

    Proxy::Proxy(enum Type type, id obj) : type_(type), obj_(obj) {}
    Proxy::~Proxy() {}

    void Proxy::Init(Local<Object> exports) {
        Isolate *isolate = exports->GetIsolate();
        HandleScope scope(isolate);

        Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, New);
        tpl->SetClassName(String::NewFromUtf8(isolate, "Proxy"));
        tpl->InstanceTemplate()->SetInternalFieldCount(1);

        NODE_SET_PROTOTYPE_METHOD(tpl, "call", Call);
        NODE_SET_PROTOTYPE_METHOD(tpl, "description", Description);
        NODE_SET_PROTOTYPE_METHOD(tpl, "type", Type);
        NODE_SET_PROTOTYPE_METHOD(tpl, "returnTypeOfMethod", ReturnTypeOfMethod);

        constructor.Reset(isolate, tpl->GetFunction());
        exports->Set(String::NewFromUtf8(isolate, "Proxy"), tpl->GetFunction());
    }

    void Proxy::New(const FunctionCallbackInfo<Value>& args) {
        Isolate *isolate = args.GetIsolate();
        HandleScope scope(isolate);

        id object;

        enum Type type = static_cast<enum Type>(args[0]->Int32Value());
        switch (type) {
            case Type::klass: {
                auto classname = ValueToChar(isolate, args[1]);
                object = (id)objc_getClass(classname);
                if (object == NULL) {
                    char *excMessage;
                    asprintf(&excMessage, "Error: Class with name '%s' doesn't exist", classname);
                    isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, excMessage)));
                    free(excMessage);
                    return;
                }
                break;
            }
            case Type::instance: {
                object = (id)args[1]->ToObject()->GetAlignedPointerFromInternalField(0);
                break;
            }
        }

        Proxy *proxy = new Proxy(type, object);
        proxy->Wrap(args.This());

        args.GetReturnValue().Set(args.This());

    }

    void Proxy::Type(const FunctionCallbackInfo<Value> &args) {
        Isolate *isolate = args.GetIsolate();
        HandleScope scope(isolate);

        Proxy *obj = ObjectWrap::Unwrap<Proxy>(args.This());

        int type = static_cast<int>(obj->type_);

        args.GetReturnValue().Set(type);
    }

    void Proxy::Description(const FunctionCallbackInfo<Value> &args) {
        Isolate *isolate = args.GetIsolate();
        HandleScope scope(isolate);

        Proxy *object = ObjectWrap::Unwrap<Proxy>(args.This());

        id description = objc_call(id, object->obj_, "description");
        char *desc = objc_call(char*, description, "UTF8String");

        args.GetReturnValue().Set(String::NewFromUtf8(isolate, desc));

    }

    void Proxy::Call(const FunctionCallbackInfo<Value>& args) {
        Isolate *isolate = args.GetIsolate();
        HandleScope scope(isolate);

        Local<ObjectTemplate> TemplateObject = ObjectTemplate::New();
        TemplateObject->SetInternalFieldCount(1);

        Proxy *obj = ObjectWrap::Unwrap<Proxy>(args.This());

        SEL sel = resolveSelector(obj->obj_, ValueToChar(isolate, args[0]));

        Method method;

        switch (obj->type_) {
            case Type::klass: method = class_getClassMethod((Class)obj->obj_, sel); break;
            case Type::instance: method = class_getInstanceMethod(object_getClass(obj->obj_), sel); break;
        }

        //printf("%s - %s\n", sel_getName(sel), method_getTypeEncoding(method));

        auto invocation = ObjC::Invocation(obj->obj_, sel);
        invocation.SetTarget(obj->obj_);
        invocation.SetSelector(sel);

        for (int i = 1; i < args.Length(); ++i) {
            int objcArgumentIndex = i + 1; // +1 bc we already start at 1

            auto expectedType = method_copyArgumentType(method, (unsigned int) objcArgumentIndex);
            Local<Value> arg = args[i];

            if (arg->IsNull() || arg->IsUndefined()) {
                void* nilArgument = nullptr;
                invocation.SetArgumentAtIndex(&nilArgument, objcArgumentIndex);
                continue;
            }

            if (EQUAL(expectedType, "@")) {
                // 1. check if a wrapped object was passed
                if (arg->IsObject()) {
                    // args[i] is the JS Proxy type, we have to fetch the actual ObjC::Proxy wrapper via __ptr
                    Local<Object> wrappedObject = arg->ToObject()->Get(String::NewFromUtf8(isolate, "__ptr"))->ToObject();

                    Proxy *passedProxy = ObjectWrap::Unwrap<Proxy>(wrappedObject);
                    if (passedProxy != nullptr) {
                        id argument = passedProxy->obj_;
                        invocation.SetArgumentAtIndex(&argument, objcArgumentIndex);
                        continue;
                    } else {
                        // TODO set nil as arg
                    }
                // 2. if no wrapped object was passed, but a native type (string, number, bool), convert that
                } else if (arg->IsString()) {
                    const char* stringValue = ValueToChar(isolate, arg);

                    id NSString = (id)objc_getClass("NSString");
                    id string = objc_call(id, NSString, "stringWithUTF8String:", stringValue);

                    invocation.SetArgumentAtIndex(&string, objcArgumentIndex);
                } else if (arg->IsNumber()) {
                    double numberValue = arg->ToNumber()->Value();

                    id NSNumber = (id)objc_getClass("NSNumber");
                    id number = objc_call(id, NSNumber, "numberWithDouble:", numberValue);

                    invocation.SetArgumentAtIndex(&number, objcArgumentIndex);
                } else if (arg->IsBoolean()) {
                    bool boolValue = arg->ToBoolean()->Value();

                    id NSNumber = (id)objc_getClass("NSNumber");
                    id number = objc_call(id, NSNumber, "numberWithBool:", boolValue);

                    invocation.SetArgumentAtIndex(&number, objcArgumentIndex);
                } // TODO Convert array/dict as well?
            } else if (EQUAL(expectedType, "#")) { // Class
                // This will either take a proxy around a `Class` object or a string and convert that to the expected `Class` object
                if (arg->IsString()) {
                    const char *classname = ValueToChar(isolate, arg);
                    Class cls = objc_getClass(classname);
                    invocation.SetArgumentAtIndex(&cls, objcArgumentIndex);
                } else if (arg->IsObject()) {
                    Local<Object> wrappedObject = arg->ToObject()->Get(String::NewFromUtf8(isolate, "__ptr"))->ToObject();

                    Proxy *passedClassProxy = ObjectWrap::Unwrap<Proxy>(wrappedObject);
                    if (passedClassProxy != nullptr) {
                        if (passedClassProxy->type_ == Type::klass) {
                            Class cls = (Class)passedClassProxy->obj_;
                            invocation.SetArgumentAtIndex(&cls, objcArgumentIndex);
                        } else {
                            // TODO ???
                        }
                    } else {
                        // TODO pass nil?
                    }
                }
            } else if (EQUAL(expectedType, "c")) { // char
                ARGTYPE_NOT_SUPPORTED("char");
            } else if (EQUAL(expectedType, "i")) { // int
                int argument = arg->ToNumber()->ToInt32()->Value();
                invocation.SetArgumentAtIndex(&argument, objcArgumentIndex);
            } else if (EQUAL(expectedType, "s")) { // short
                ARGTYPE_NOT_SUPPORTED("short");
            } else if (EQUAL(expectedType, "q")) { // long long
                long long argument = (long long) arg->ToNumber()->Value();
                invocation.SetArgumentAtIndex(&argument, objcArgumentIndex);
            } else if (EQUAL(expectedType, "C")) { // unsigned char
                ARGTYPE_NOT_SUPPORTED("unsigned char");
            } else if (EQUAL(expectedType, "I")) { // unsigned int
                ARGTYPE_NOT_SUPPORTED("unsigned int");
            } else if (EQUAL(expectedType, "S")) { // unsigned short
                ARGTYPE_NOT_SUPPORTED("unsigned short");
            } else if (EQUAL(expectedType, "L")) { // unsigned long
                ARGTYPE_NOT_SUPPORTED("unsigned long");
            } else if (EQUAL(expectedType, "Q")) { // unsigned long long
                ARGTYPE_NOT_SUPPORTED("unsigned long long");
            } else if (EQUAL(expectedType, "f")) { // float
                float argument = (float) arg->ToNumber()->Value();
                invocation.SetArgumentAtIndex(&argument, objcArgumentIndex);
            } else if (EQUAL(expectedType, "d")) { // double
                double argument = arg->ToNumber()->Value();
                invocation.SetArgumentAtIndex(&argument, objcArgumentIndex);
            } else if (EQUAL(expectedType, "B")) { // bool
                bool argument = arg->ToBoolean()->Value();
                invocation.SetArgumentAtIndex(&argument, objcArgumentIndex);
            } else if (EQUAL(expectedType, "v")) { // void
                ARGTYPE_NOT_SUPPORTED("void");
            } else if (EQUAL(expectedType, "*") || EQUAL(expectedType, "r*")) { // char*, const char*
                ARGTYPE_NOT_SUPPORTED("char*");
            } else if (EQUAL(expectedType, ":")) { // SEL
                // selectors can be passed as strings.
                SEL _sel = sel_getUid(ValueToChar(isolate, arg));
                invocation.SetArgumentAtIndex(&_sel, objcArgumentIndex);
            } else if (EQUAL(expectedType, "^v") || EQUAL(expectedType, "r^v")) { // void*, const void*
                ARGTYPE_NOT_SUPPORTED("void*");
            }
        }

        //
        // Invoke
        //

        invocation.Invoke();

        //
        // Handle return value
        //

        const char *returnType = method_copyReturnType(method);
        //printf("%s - %s\n", returnType, sel_getName(sel));

        if (EQUAL(returnType, "@")) {
            id retval;
            invocation.GetReturnValue(&retval);

            auto isKindOfClass = [](id object, const char *classname) -> bool {
                return false; // TODO Re-enable this
                return objc_call(bool, object, "isKindOfClass:", objc_getClass(classname));
            };

            if (isKindOfClass(retval, "NSString")) {
                char *charValue = objc_call(char*, retval, "UTF8String");
                args.GetReturnValue().Set(String::NewFromUtf8(isolate, charValue));
                return;
            }

            if (isKindOfClass(retval, "NSNumber")) {
                double value = objc_call(double, retval, "doubleValue");
                args.GetReturnValue().Set(value);
                return;
            }

            // TODO convert other types like NSArray, NSDictionary, NSURL, etc to native objects

            if (!is_aligned(retval)) {
                isolate->ThrowException(Exception::Error(String::NewFromUtf8(isolate, "Internal Error: Unable to align pointer")));
                return;
            }

            Local<Object> object = TemplateObject->NewInstance();
            object->SetAlignedPointerInInternalField(0, retval);
            // TODO ^^ This sometimes crashes w/ a "pointer not aligned" error message (seems to happem at random, try to fix eventually)

            const unsigned argc = 2;
            Local<Value> argv[argc] = {Number::New(isolate, 1), object};
            Local<Function> cons = Local<Function>::New(isolate, constructor);
            Local<Context> context = isolate->GetCurrentContext();
            Local<Object> instance = cons->NewInstance(context, argc, argv).ToLocalChecked();
            args.GetReturnValue().Set(instance);
            return;
        } else if (EQUAL(returnType, "c")) { // char
            HANDLE_RETURN_TYPE(char);
        } else if (EQUAL(returnType, "i")) { // int
            HANDLE_RETURN_TYPE(int);
        } else if (EQUAL(returnType, "s")) { // short
            HANDLE_RETURN_TYPE(short);
        } else if (EQUAL(returnType, "q")) { // long long
            HANDLE_RETURN_TYPE_CAST(long long, int32_t);
        } else if (EQUAL(returnType, "C")) { // unsigned char
            HANDLE_RETURN_TYPE(unsigned char);
        } else if (EQUAL(returnType, "I")) { // unsigned int
            HANDLE_RETURN_TYPE(unsigned int);
        } else if (EQUAL(returnType, "S")) { // unsigned short
            HANDLE_RETURN_TYPE(unsigned short);
        } else if (EQUAL(returnType, "L")) { // unsigned long
            HANDLE_RETURN_TYPE_CAST(unsigned long, int32_t);
        } else if (EQUAL(returnType, "Q")) { // unsigned long long
            HANDLE_RETURN_TYPE_CAST(unsigned long long, int32_t);
        } else if (EQUAL(returnType, "f")) { // float
            HANDLE_RETURN_TYPE(float);
        } else if (EQUAL(returnType, "d")) { // double
            HANDLE_RETURN_TYPE(double);
        } else if (EQUAL(returnType, "B")) { // bool
            HANDLE_RETURN_TYPE(bool);
            //void* retval;
            //invocation.GetReturnValue(&retval);
            //args.GetReturnValue().Set((bool)retval);
            //return;
        } else if (EQUAL(returnType, "v")) { // void
            args.GetReturnValue().Set(Undefined(isolate));
        } else if (EQUAL(returnType, "*") || EQUAL(returnType, "r*")) { // char*, const char*
            char* retval;
            invocation.GetReturnValue(&retval);
            Local<Value> string = String::NewFromUtf8(isolate, retval);
            args.GetReturnValue().Set(string);
            return;
        } else if (EQUAL(returnType, "#")) { // Class
            // TODO
            args.GetReturnValue().Set(Undefined(isolate));
        } else if (EQUAL(returnType, ":")) { // SEL
            // TODO
            args.GetReturnValue().Set(Undefined(isolate));
        }

        return;
    }

    void Proxy::ReturnTypeOfMethod(const FunctionCallbackInfo<Value> &args) {
        Isolate *isolate = args.GetIsolate();
        HandleScope scope(isolate);

        Proxy *obj = ObjectWrap::Unwrap<Proxy>(args.This());
        SEL sel = resolveSelector(obj->obj_, ValueToChar(isolate, args[0]));

        Method method;

        switch (obj->type_) {
            case Type::klass: method = class_getClassMethod((Class)obj->obj_, sel); break;
            case Type::instance: method = class_getInstanceMethod(object_getClass(obj->obj_), sel); break;
        }

        const char *returnType = method_copyReturnType(method);

        args.GetReturnValue().Set(String::NewFromUtf8(isolate, returnType));
    }
}
<|endoftext|>


<commit_before>#include "Character.h"
#include "OpencraftCore.h"
#include "World.h"

Character::Character( void )
{
	setHeight( 1.9f );
	setMoveSpeed( 2.f );
	setSprintSpeed( 4.f );
	enableSprint( false );
	enableFlying( false );
}

Character::~Character( void )
{

}

void Character::setSkin(std::string name)
{
	Util::log("Setting skin to: " + name);
}

void Character::setHeight( float h )
{
	mHeight = h;
}

void Character::setMoveSpeed( float s )
{
	mMoveSpeed = s;
}

void Character::setSprintSpeed( float s )
{
	mSprintSpeed = s;
}

void Character::enableSprint( bool s )
{
	mSprint = s;
}

void Character::enableFlying( bool f )
{
	mFlying = f;
}

bool Character::isFlying()
{
	return mFlying;
}

Camera* Character::getCamera()
{
	return &mCamera;
}

raycast_r Character::getEyeCast()
{
	raycast_r ray;
	ray.orig = getPosition() + Vector3( 0.f, mHeight * 0.9f, 0.f );
	ray.dir = mCamera.getForward();
	return ray;
}

raycast_r Character::getFeetCast()
{
	raycast_r ray;
	ray.orig = getPosition() + Vector3( 0.f, mHeight, 0.f );
	ray.dir = Vector3( 0.f, -1.f, 0.f );
	return ray;
}

collision_r Character::getCollision()
{
	collision_r col;
	col.min1 = getPosition() + Vector3( -.4f, 0.f, -.4f );
	col.max1 = getPosition() + Vector3( .4f, mHeight, .4f );
	return col;
}

void Character::addMoveDelta(const Vector3 &dp)
{
	mMoveVector += dp;
}

void Character::setPosition(const Vector3 &vec)
{
	mPosition = vec;
}

Vector3 Character::getPosition()
{
	return mPosition;
}

void Character::update(float dt)
{
	Matrix4 yaw = Matrix4::rotateY( -(mCamera.getYaw()*3.141f)/180 );
	Vector3 newDir = yaw * mMoveVector;

	mPosition += ( newDir * ( mSprint ? mSprintSpeed : mMoveSpeed ) * dt);
	if( !mFlying )
	{
		raycast_r feetRay = getFeetCast();
		raycast_r gRay[4];
		// Perform 4 raycasts for edges of player since AABB collision testing doesn't work.
		feetRay.orig += Vector3(0.49f, 0.f, 0.49f);
		gRay[0] = OpencraftCore::Singleton->getWorld()->raycastWorld( feetRay, true );
		feetRay.orig += Vector3(0.f, 0.f, -0.98f);
		gRay[1] = OpencraftCore::Singleton->getWorld()->raycastWorld( feetRay, true );
		feetRay.orig += Vector3(-0.98f, 0.f, 0.f);
		gRay[2] = OpencraftCore::Singleton->getWorld()->raycastWorld( feetRay, true );
		feetRay.orig += Vector3(0.0f, 0.f, 0.98f);
		gRay[3] = OpencraftCore::Singleton->getWorld()->raycastWorld( feetRay, true );

		float i0 = -1;
		for( int i = 0; i < 4; i++ ) {
			if( gRay[i].hit == true ) {
				if( i0 = -1 ) {
					i0 = gRay[i].i0 - mHeight;
				}
				else
				{
					i0 = std::min<float>(i0, gRay[i].i0 - mHeight);
				}
			}
		}
		if( i0 != -1 )
			mPosition.y -= i0;
	}

	// Offset camera by eye height.
	mCamera.setPosition( mPosition + Vector3( 0.f, mHeight * 0.9f, 0.f) );
}<commit_msg>Fixed characters phasing through the world.<commit_after>#include "Character.h"
#include "OpencraftCore.h"
#include "World.h"

Character::Character( void )
{
	setHeight( 1.9f );
	setMoveSpeed( 2.f );
	setSprintSpeed( 4.f );
	enableSprint( false );
	enableFlying( false );
}

Character::~Character( void )
{

}

void Character::setSkin(std::string name)
{
	Util::log("Setting skin to: " + name);
}

void Character::setHeight( float h )
{
	mHeight = h;
}

void Character::setMoveSpeed( float s )
{
	mMoveSpeed = s;
}

void Character::setSprintSpeed( float s )
{
	mSprintSpeed = s;
}

void Character::enableSprint( bool s )
{
	mSprint = s;
}

void Character::enableFlying( bool f )
{
	mFlying = f;
}

bool Character::isFlying()
{
	return mFlying;
}

Camera* Character::getCamera()
{
	return &mCamera;
}

raycast_r Character::getEyeCast()
{
	raycast_r ray;
	ray.orig = getPosition() + Vector3( 0.f, mHeight * 0.9f, 0.f );
	ray.dir = mCamera.getForward();
	return ray;
}

raycast_r Character::getFeetCast()
{
	raycast_r ray;
	ray.orig = getPosition() + Vector3( 0.f, mHeight, 0.f );
	ray.dir = Vector3( 0.f, -1.f, 0.f );
	return ray;
}

collision_r Character::getCollision()
{
	collision_r col;
	col.min1 = getPosition() + Vector3( -.4f, 0.f, -.4f );
	col.max1 = getPosition() + Vector3( .4f, mHeight, .4f );
	return col;
}

void Character::addMoveDelta(const Vector3 &dp)
{
	mMoveVector += dp;
}

void Character::setPosition(const Vector3 &vec)
{
	mPosition = vec;
}

Vector3 Character::getPosition()
{
	return mPosition;
}

void Character::update(float dt)
{
	Matrix4 yaw = Matrix4::rotateY( -(mCamera.getYaw()*3.141f)/180 );
	Vector3 newDir = yaw * mMoveVector;

	mPosition += ( newDir * ( mSprint ? mSprintSpeed : mMoveSpeed ) * dt);
	if( !mFlying )
	{
		raycast_r feetRay = getFeetCast();
		raycast_r gRay[4];
		// Perform 4 raycasts for edges of player since AABB collision testing doesn't work.
		feetRay.orig += Vector3(0.49f, 0.f, 0.49f);
		gRay[0] = OpencraftCore::Singleton->getWorld()->raycastWorld( feetRay, true );
		feetRay.orig += Vector3(0.f, 0.f, -0.98f);
		gRay[1] = OpencraftCore::Singleton->getWorld()->raycastWorld( feetRay, true );
		feetRay.orig += Vector3(-0.98f, 0.f, 0.f);
		gRay[2] = OpencraftCore::Singleton->getWorld()->raycastWorld( feetRay, true );
		feetRay.orig += Vector3(0.0f, 0.f, 0.98f);
		gRay[3] = OpencraftCore::Singleton->getWorld()->raycastWorld( feetRay, true );

		float smallestRay = 10000;
		bool hit = false;
		for( int i = 0; i < 4; i++ ) {
			if( gRay[i].hit == true ) {
				hit = true;
				smallestRay = std::min( smallestRay, gRay[i].i0 );
			}
		}
		if( hit )
			mPosition.y -= smallestRay -= mHeight;
	}

	// Offset camera by eye height.
	mCamera.setPosition( mPosition + Vector3( 0.f, mHeight * 0.9f, 0.f) );
}<|endoftext|>


<commit_before>/*
 * Copyright 2007-2021 CM4all GmbH
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``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
 * FOUNDATION OR CONTRIBUTORS 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.
 */

/*
 * #TranslationCommand::TOKEN_AUTH implementation.
 */

#include "Request.hxx"
#include "Connection.hxx"
#include "Instance.hxx"
#include "puri_escape.hxx"
#include "session/Lease.hxx"
#include "session/Session.hxx"
#include "http/IncomingRequest.hxx"
#include "translation/Handler.hxx"
#include "translation/Service.hxx"
#include "pool/pool.hxx"
#include "uri/Recompose.hxx"
#include "util/IterableSplitString.hxx"

#include <stdexcept>

static const char *
GetTokenAuthRedirectUri(AllocatorPtr alloc,
			const char *scheme, const char *host,
			DissectedUri dissected_uri,
			const TranslateResponse &response) noexcept
{
	/* TODO: deduplicate code from GetBounceUri() */

	if (response.uri != nullptr) {
		dissected_uri.base = response.uri;
		dissected_uri.path_info = nullptr;
	}

	const char *uri_path = RecomposeUri(alloc, dissected_uri);

	return alloc.Concat(scheme, "://", host, uri_path);
}

inline void
Request::OnTokenAuthTranslateResponse(const TranslateResponse &response) noexcept
{
	assert(translate.previous != nullptr);

	if (response.discard_session)
		DiscardSession();

	bool is_authenticated = false;
	{
		auto session = ApplyTranslateSession(response);
		if (session)
			is_authenticated = session->user != nullptr;
	}

	if (CheckHandleRedirectBounceStatus(response))
		return;

	if (!is_authenticated) {
		/* for some reason, the translation server did not send
		   REDIRECT/BOUNCE/STATUS, but we still don't have a user -
		   this should not happen; bail out, don't dare to accept the
		   client */
		DispatchError(HTTP_STATUS_FORBIDDEN, "Forbidden");
		return;
	}

	translate.user_modified = response.user != nullptr;

	/* using the original translation response, because it may
	   have information about the original request */
	const auto &tr = *translate.previous;

	/* don't call OnTranslateResponseAfterAuth() here, instead
	   redirect to the URI with auth_token removed */

	const char *redirect_uri =
		GetTokenAuthRedirectUri(pool,
					GetExternalUriScheme(tr),
					GetExternalUriHost(tr),
					dissected_uri,
					tr);

	DispatchRedirect(HTTP_STATUS_SEE_OTHER, redirect_uri, nullptr);
}

inline void
Request::OnTokenAuthTranslateError(std::exception_ptr ep) noexcept
{
	LogDispatchError(HTTP_STATUS_BAD_GATEWAY,
			 "Configuration server failed", ep, 1);
}

class TokenAuthTranslateHandler final : public TranslateHandler {
	Request &request;

public:
	explicit TokenAuthTranslateHandler(Request &_request) noexcept
		:request(_request) {}

	/* virtual methods from TranslateHandler */
	void OnTranslateResponse(TranslateResponse &response) noexcept override {
		request.OnTokenAuthTranslateResponse(response);
	}

	void OnTranslateError(std::exception_ptr error) noexcept override {
		request.OnTokenAuthTranslateError(std::move(error));
	}
};

static StringView
ConcatQueryStrings(AllocatorPtr alloc, StringView a, StringView b) noexcept
{
	/* strip redundant ampersands */
	if (a.EndsWith('&') && (b.empty() || b.StartsWith('&')))
		a.pop_back();

	if (a.empty() && b.StartsWith('&'))
		b.pop_front();

	/* shortcut: if both are empty, the query string is gone
	   completely */
	if (a.empty() && b.empty())
		return nullptr;

	/* concatenate both parts */
	return alloc.Concat(a, b);
}

static StringView
RemoveFromQueryString(AllocatorPtr alloc, StringView q,
		      StringView name, StringView value) noexcept
{
	StringView a(q.begin(), name.begin());
	StringView b(value.end(), q.end());

	return ConcatQueryStrings(alloc, a, b);
}

static const char *
ExtractAuthToken(AllocatorPtr alloc, DissectedUri &dissected_uri)
{
	char *auth_token = nullptr;

	for (const auto i : IterableSplitString(dissected_uri.query, '&')) {
		const auto [name, escaped_value] = i.Split('=');
		if (!StringView("access_token").Equals(name))
			continue;

		auth_token = uri_unescape_dup(alloc, escaped_value);
		if (auth_token == nullptr)
			throw std::invalid_argument("Malformed auth token");

		/* remove the "access_token" parameter from the query
		   string */
		dissected_uri.query =
			RemoveFromQueryString(alloc, dissected_uri.query,
					      name, escaped_value);

		break;
	}

	return auth_token;
}

void
Request::HandleTokenAuth(const TranslateResponse &response) noexcept
{
	assert(!response.token_auth.IsNull());

	/* we need to validate the session realm early */
	ApplyTranslateRealm(response, nullptr);

	const char *auth_token;

	try {
		auth_token = ExtractAuthToken(pool, dissected_uri);
	} catch (const std::invalid_argument &e) {
		DispatchError(HTTP_STATUS_BAD_REQUEST, e.what());
		return;
	}

	if (auth_token == nullptr) {
		bool is_authenticated = false;
		{
			auto session = GetRealmSession();
			if (session)
				is_authenticated = session->user != nullptr;
		}

		if (is_authenticated) {
			/* already authenticated; we can skip the
			   TOKEN_AUTH request */
			OnTranslateResponseAfterAuth(response);
			return;
		}
	}

	auto t = NewFromPool<TranslateRequest>(pool);
	t->token_auth = response.token_auth;
	t->auth_token = auth_token;
	t->uri = auth_token != nullptr
		? RecomposeUri(pool, dissected_uri)
		: request.uri;
	t->host = translate.request.host;
	t->session = translate.request.session;

	translate.previous = &response;

	auto *http_auth_translate_handler =
		NewFromPool<TokenAuthTranslateHandler>(pool, *this);

	GetTranslationService().SendRequest(pool, *t,
					    stopwatch,
					    *http_auth_translate_handler,
					    cancel_ptr);
}
<commit_msg>bp/TokenAuth: promote the "previous" response to the final response<commit_after>/*
 * Copyright 2007-2021 CM4all GmbH
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``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
 * FOUNDATION OR CONTRIBUTORS 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.
 */

/*
 * #TranslationCommand::TOKEN_AUTH implementation.
 */

#include "Request.hxx"
#include "Connection.hxx"
#include "Instance.hxx"
#include "puri_escape.hxx"
#include "session/Lease.hxx"
#include "session/Session.hxx"
#include "http/IncomingRequest.hxx"
#include "translation/Handler.hxx"
#include "translation/Service.hxx"
#include "pool/pool.hxx"
#include "uri/Recompose.hxx"
#include "util/IterableSplitString.hxx"

#include <stdexcept>

static const char *
GetTokenAuthRedirectUri(AllocatorPtr alloc,
			const char *scheme, const char *host,
			DissectedUri dissected_uri,
			const TranslateResponse &response) noexcept
{
	/* TODO: deduplicate code from GetBounceUri() */

	if (response.uri != nullptr) {
		dissected_uri.base = response.uri;
		dissected_uri.path_info = nullptr;
	}

	const char *uri_path = RecomposeUri(alloc, dissected_uri);

	return alloc.Concat(scheme, "://", host, uri_path);
}

inline void
Request::OnTokenAuthTranslateResponse(const TranslateResponse &response) noexcept
{
	assert(translate.previous != nullptr);

	if (response.discard_session)
		DiscardSession();

	bool is_authenticated = false;
	{
		auto session = ApplyTranslateSession(response);
		if (session)
			is_authenticated = session->user != nullptr;
	}

	if (CheckHandleRedirectBounceStatus(response))
		return;

	if (!is_authenticated) {
		/* for some reason, the translation server did not send
		   REDIRECT/BOUNCE/STATUS, but we still don't have a user -
		   this should not happen; bail out, don't dare to accept the
		   client */
		DispatchError(HTTP_STATUS_FORBIDDEN, "Forbidden");
		return;
	}

	translate.user_modified = response.user != nullptr;

	/* using the original translation response, because it may
	   have information about the original request */
	const auto &tr = *translate.previous;

	/* promote the "previous" response to the final response, so
	   GenerateSetCookie() uses its settings */
	translate.response = &tr;

	/* don't call OnTranslateResponseAfterAuth() here, instead
	   redirect to the URI with auth_token removed */

	const char *redirect_uri =
		GetTokenAuthRedirectUri(pool,
					GetExternalUriScheme(tr),
					GetExternalUriHost(tr),
					dissected_uri,
					tr);

	DispatchRedirect(HTTP_STATUS_SEE_OTHER, redirect_uri, nullptr);
}

inline void
Request::OnTokenAuthTranslateError(std::exception_ptr ep) noexcept
{
	LogDispatchError(HTTP_STATUS_BAD_GATEWAY,
			 "Configuration server failed", ep, 1);
}

class TokenAuthTranslateHandler final : public TranslateHandler {
	Request &request;

public:
	explicit TokenAuthTranslateHandler(Request &_request) noexcept
		:request(_request) {}

	/* virtual methods from TranslateHandler */
	void OnTranslateResponse(TranslateResponse &response) noexcept override {
		request.OnTokenAuthTranslateResponse(response);
	}

	void OnTranslateError(std::exception_ptr error) noexcept override {
		request.OnTokenAuthTranslateError(std::move(error));
	}
};

static StringView
ConcatQueryStrings(AllocatorPtr alloc, StringView a, StringView b) noexcept
{
	/* strip redundant ampersands */
	if (a.EndsWith('&') && (b.empty() || b.StartsWith('&')))
		a.pop_back();

	if (a.empty() && b.StartsWith('&'))
		b.pop_front();

	/* shortcut: if both are empty, the query string is gone
	   completely */
	if (a.empty() && b.empty())
		return nullptr;

	/* concatenate both parts */
	return alloc.Concat(a, b);
}

static StringView
RemoveFromQueryString(AllocatorPtr alloc, StringView q,
		      StringView name, StringView value) noexcept
{
	StringView a(q.begin(), name.begin());
	StringView b(value.end(), q.end());

	return ConcatQueryStrings(alloc, a, b);
}

static const char *
ExtractAuthToken(AllocatorPtr alloc, DissectedUri &dissected_uri)
{
	char *auth_token = nullptr;

	for (const auto i : IterableSplitString(dissected_uri.query, '&')) {
		const auto [name, escaped_value] = i.Split('=');
		if (!StringView("access_token").Equals(name))
			continue;

		auth_token = uri_unescape_dup(alloc, escaped_value);
		if (auth_token == nullptr)
			throw std::invalid_argument("Malformed auth token");

		/* remove the "access_token" parameter from the query
		   string */
		dissected_uri.query =
			RemoveFromQueryString(alloc, dissected_uri.query,
					      name, escaped_value);

		break;
	}

	return auth_token;
}

void
Request::HandleTokenAuth(const TranslateResponse &response) noexcept
{
	assert(!response.token_auth.IsNull());

	/* we need to validate the session realm early */
	ApplyTranslateRealm(response, nullptr);

	const char *auth_token;

	try {
		auth_token = ExtractAuthToken(pool, dissected_uri);
	} catch (const std::invalid_argument &e) {
		DispatchError(HTTP_STATUS_BAD_REQUEST, e.what());
		return;
	}

	if (auth_token == nullptr) {
		bool is_authenticated = false;
		{
			auto session = GetRealmSession();
			if (session)
				is_authenticated = session->user != nullptr;
		}

		if (is_authenticated) {
			/* already authenticated; we can skip the
			   TOKEN_AUTH request */
			OnTranslateResponseAfterAuth(response);
			return;
		}
	}

	auto t = NewFromPool<TranslateRequest>(pool);
	t->token_auth = response.token_auth;
	t->auth_token = auth_token;
	t->uri = auth_token != nullptr
		? RecomposeUri(pool, dissected_uri)
		: request.uri;
	t->host = translate.request.host;
	t->session = translate.request.session;

	translate.previous = &response;

	auto *http_auth_translate_handler =
		NewFromPool<TokenAuthTranslateHandler>(pool, *this);

	GetTranslationService().SendRequest(pool, *t,
					    stopwatch,
					    *http_auth_translate_handler,
					    cancel_ptr);
}
<|endoftext|>


<commit_before>#include <iostream>

#include <Engine.h>
#include <Scene.h>
#include <Mouse.h>

// Used for testing purposes, should be removed before merge.
#include <Components/Alarm.h>
#include <Components/Transform.h>
#include <Components/Mesh.h>

#include <Systems/EnemyBehaviorSystem.h>

#include "Player.h"
#include "Camera.h"
#include "Light.h"
#include "Enemy.h"
#include "Systems/FollowTargetLinearSystem.h"
#include "Systems/PlayerMovementSystem.h"
#include "Systems/PlayerGunSystem.h"
#include "Systems/BulletMovementSystem.h"
#include "Systems/LevelManagerSystem.h"

namespace Spectacle
{
	void CreateTimedBlocks( Gunship::Scene& scene )
	{
		for ( int i = 0; i < 20; ++i )
		{
			auto entity = scene.entities().Create();

			auto& transform =
				scene.componentManager< Gunship::Components::TransformManager >().Assign( entity );
			transform.SetPosition( -10.0f, 10.0f - i, 0.0f );

			scene.componentManager< Gunship::Components::MeshManager >().Assign( entity, "Cube.mesh" );
			scene.componentManager< Gunship::Components::AlarmManager >().Assign(
				entity,
				20.0f - i,
				[]( Gunship::Scene& scene, Gunship::Entity entity )
				{
					scene.componentManager< Gunship::Components::TransformManager >().Destroy( entity );
					scene.componentManager< Gunship::Components::MeshManager >().Destroy( entity );
				} );
		}
	}

	void TimedBlocksReset( Gunship::Scene& scene, Gunship::Entity entity )
	{
		CreateTimedBlocks( scene );
		scene.componentManager< Gunship::Components::AlarmManager >().Assign(
			entity,
			22.0f,
			TimedBlocksReset );
	}

	void InitializeScene( Gunship::Scene& scene )
	{
		scene.AddSystem< Systems::LevelManagerSystem >();

		CreatePlayer( scene );
		CreateCamera( scene );

		TimedBlocksReset( scene, scene.entities().Create() );
	}
}

int main( int argc, char* argv[] )
{
	Gunship::Engine engine;

	// initialize and run the engine
	if ( engine.InitSystems() )
	{
		engine.SetupCurrentScene( Spectacle::InitializeScene );
		engine.Start();
		engine.ShutDown();
	}

	return 0;
}
<commit_msg>Alarm Cancellation Demo - Adds a demonstration of the alarm cancellation functionality.<commit_after>#include <iostream>

#include <Engine.h>
#include <Scene.h>
#include <Mouse.h>

// Used for testing purposes, should be removed before merge.
#include <Components/Alarm.h>
#include <Components/Transform.h>
#include <Components/Mesh.h>
#include <Systems/EnemyBehaviorSystem.h>
#include <Utility/Random.h>

#include "Player.h"
#include "Camera.h"
#include "Light.h"
#include "Enemy.h"
#include "Systems/FollowTargetLinearSystem.h"
#include "Systems/PlayerMovementSystem.h"
#include "Systems/PlayerGunSystem.h"
#include "Systems/BulletMovementSystem.h"
#include "Systems/LevelManagerSystem.h"

namespace Spectacle
{
	using Gunship::Components::AlarmManager;

	AlarmManager::AlarmID CreateBlock( Gunship::Scene& scene, float x, float y, float time )
	{
		auto& alarmManager = scene.componentManager< AlarmManager >();

		auto entity = scene.entities().Create();

		auto& transform =
			scene.componentManager< Gunship::Components::TransformManager >().Assign( entity );
		transform.SetPosition( x, y, 0.0f );

		scene.componentManager< Gunship::Components::MeshManager >().Assign( entity, "Cube.mesh" );
		return alarmManager.Assign(
			entity,
			time,
			[]( Gunship::Scene& scene, Gunship::Entity entity )
			{
					scene.componentManager< Gunship::Components::TransformManager >().Destroy( entity );
					scene.componentManager< Gunship::Components::MeshManager >().Destroy( entity );
			} );
	}

	void CreateTimedBlocks( Gunship::Scene& scene )
	{
		static float xOffset = -15.0f;
		xOffset += 1.0f;

		auto& alarmManager = scene.componentManager< AlarmManager >();

		for ( int i = 0; i < 20; ++i )
		{
			auto alarmID = CreateBlock( scene, xOffset, 10.0f - i, 20.0f - i );

			// Randomly cancel some alarms to see how the manager handles it.
			if ( Random::Probability( 0.5f ) )
			{
				alarmManager.Cancel( alarmID );
			}
		}
	}

	void CreateReferenceBlocks( Gunship::Scene& scene )
	{
		auto& alarmManager = scene.componentManager< AlarmManager >();

		for ( int i = 0; i < 20; ++i )
		{
			CreateBlock( scene, -15.0f, 10.0f - i, 20.0f - i );
		}
	}

	void TimedBlocksReset( Gunship::Scene& scene, Gunship::Entity entity )
	{
		CreateTimedBlocks( scene );
		scene.componentManager< AlarmManager >().Assign(
			entity,
			22.0f,
			TimedBlocksReset );
	}

	void ReferenceBlocksReset( Gunship::Scene& scene, Gunship::Entity entity )
	{
		CreateReferenceBlocks( scene );
		scene.componentManager< AlarmManager >().Assign(
			entity,
			22.0f,
			ReferenceBlocksReset );
	}

	void InitializeScene( Gunship::Scene& scene )
	{
		scene.AddSystem< Systems::LevelManagerSystem >();

		CreatePlayer( scene );
		CreateCamera( scene );

		ReferenceBlocksReset( scene, scene.entities().Create() );
		TimedBlocksReset( scene, scene.entities().Create() );
	}
}

int main( int argc, char* argv[] )
{
	Gunship::Engine engine;

	// initialize and run the engine
	if ( engine.InitSystems() )
	{
		engine.SetupCurrentScene( Spectacle::InitializeScene );
		engine.Start();
		engine.ShutDown();
	}

	return 0;
}
<|endoftext|>


<commit_before>//
//  WallForce.cpp
//  NSolver
//
//  Created by 乔磊 on 15/5/10.
//  Copyright (c) 2015年 乔磊. All rights reserved.
//

#include <NSolver/WallForce.h>

namespace NSFEMSolver
{
  using namespace dealii;

  void WallForce::clear()
  {
    lift = 0.0;
    drag = 0.0;
    for (unsigned int d=0; d<3; ++d)
      {
        force[d] = 0.0;
        moment[d] = 0.0;
      }
  }

  WallForce WallForce::operator+ (WallForce const &op_r)
  {
    WallForce rv;
    rv.lift =this->lift + op_r.lift;
    rv.drag =this->drag + op_r.drag;
    rv.force =this->force + op_r.force;
    rv.moment =this->moment + op_r.moment;
    return (rv);
  }

  void WallForce::mpi_sum (MPI_Comm const &mpi_communicator)
  {
    Utilities::MPI::sum (lift, mpi_communicator);
    Utilities::MPI::sum (drag, mpi_communicator);
    for (unsigned int d=0; d<3; ++d)
      {
        Utilities::MPI::sum (force[d], mpi_communicator);
        Utilities::MPI::sum (moment[d], mpi_communicator);
      }
  }

}
<commit_msg>fix force summation in parallel<commit_after>//
//  WallForce.cpp
//  NSolver
//
//  Created by 乔磊 on 15/5/10.
//  Copyright (c) 2015年 乔磊. All rights reserved.
//

#include <NSolver/WallForce.h>

namespace NSFEMSolver
{
  using namespace dealii;

  void WallForce::clear()
  {
    lift = 0.0;
    drag = 0.0;
    for (unsigned int d=0; d<3; ++d)
      {
        force[d] = 0.0;
        moment[d] = 0.0;
      }
  }

  WallForce WallForce::operator+ (WallForce const &op_r)
  {
    WallForce rv;
    rv.lift =this->lift + op_r.lift;
    rv.drag =this->drag + op_r.drag;
    rv.force =this->force + op_r.force;
    rv.moment =this->moment + op_r.moment;
    return (rv);
  }

  void WallForce::mpi_sum (MPI_Comm const &mpi_communicator)
  {
    double receive_sum;
    receive_sum = Utilities::MPI::sum (lift, mpi_communicator);
    lift = receive_sum;
    receive_sum = Utilities::MPI::sum (drag, mpi_communicator);
    drag = receive_sum;
    for (unsigned int d=0; d<3; ++d)
      {
        receive_sum = Utilities::MPI::sum (force[d], mpi_communicator);
        force[d] = receive_sum;
        receive_sum = Utilities::MPI::sum (moment[d], mpi_communicator);
        moment[d] = receive_sum;
      }
  }

}
<|endoftext|>


<commit_before>//===--- tools/extra/clang-rename/USRLocFinder.cpp - Clang rename tool ----===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// \brief Mehtods for finding all instances of a USR. Our strategy is very
/// simple; we just compare the USR at every relevant AST node with the one
/// provided.
///
//===----------------------------------------------------------------------===//

#include "USRLocFinder.h"
#include "USRFinder.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Index/USRGeneration.h"
#include "clang/Lex/Lexer.h"
#include "llvm/ADT/SmallVector.h"

using namespace llvm;

namespace clang {
namespace rename {

namespace {
// \brief This visitor recursively searches for all instances of a USR in a
// translation unit and stores them for later usage.
class USRLocFindingASTVisitor
    : public clang::RecursiveASTVisitor<USRLocFindingASTVisitor> {
public:
  explicit USRLocFindingASTVisitor(StringRef USR, StringRef PrevName) : USR(USR), PrevName(PrevName) {
  }

  // Declaration visitors:

  bool VisitNamedDecl(const NamedDecl *Decl) {
    if (getUSRForDecl(Decl) == USR) {
      LocationsFound.push_back(Decl->getLocation());
    }
    return true;
  }

  bool VisitVarDecl(clang::VarDecl *Decl) {
    clang::QualType Type = Decl->getType();
    const clang::RecordDecl *RecordDecl = Type->getPointeeCXXRecordDecl();
    if (RecordDecl) {
      if (getUSRForDecl(RecordDecl) == USR) {
        // The declaration refers to a type that is to be renamed.
        LocationsFound.push_back(Decl->getTypeSpecStartLoc());
      }
    }
    return true;
  }

  bool VisitCXXConstructorDecl(clang::CXXConstructorDecl *ConstructorDecl) {
    const ASTContext &Context = ConstructorDecl->getASTContext();
    for (clang::CXXConstructorDecl::init_const_iterator it = ConstructorDecl->init_begin(); it != ConstructorDecl->init_end(); ++it) {
      const clang::CXXCtorInitializer* Initializer = *it;
      if (Initializer->getSourceOrder() == -1) {
        // Ignore implicit initializers.
        continue;
      }

      if (const clang::FieldDecl *FieldDecl = Initializer->getAnyMember()) {
        if (getUSRForDecl(FieldDecl) == USR) {
          // The initializer refers to a field that is to be renamed.
          SourceLocation Location = Initializer->getSourceLocation();
          StringRef TokenName = Lexer::getSourceText(CharSourceRange::getTokenRange(Location), Context.getSourceManager(), Context.getLangOpts());
          if (TokenName == PrevName) {
            // The token of the source location we find actually has the old name.
            LocationsFound.push_back(Initializer->getSourceLocation());
          }
        }
      }
    }
    return true;
  }

  // Expression visitors:

  bool VisitDeclRefExpr(const DeclRefExpr *Expr) {
    const auto *Decl = Expr->getFoundDecl();

    checkNestedNameSpecifierLoc(Expr->getQualifierLoc());
    if (getUSRForDecl(Decl) == USR) {
      LocationsFound.push_back(Expr->getLocation());
    }

    return true;
  }

  bool VisitMemberExpr(const MemberExpr *Expr) {
    const auto *Decl = Expr->getFoundDecl().getDecl();
    if (getUSRForDecl(Decl) == USR) {
      LocationsFound.push_back(Expr->getMemberLoc());
    }
    return true;
  }

  // Non-visitors:

  // \brief Returns a list of unique locations. Duplicate or overlapping
  // locations are erroneous and should be reported!
  const std::vector<clang::SourceLocation> &getLocationsFound() const {
    return LocationsFound;
  }

private:
  // Namespace traversal:
  void checkNestedNameSpecifierLoc(NestedNameSpecifierLoc NameLoc) {
    while (NameLoc) {
      const auto *Decl = NameLoc.getNestedNameSpecifier()->getAsNamespace();
      if (Decl && getUSRForDecl(Decl) == USR)
        LocationsFound.push_back(NameLoc.getLocalBeginLoc());
      NameLoc = NameLoc.getPrefix();
    }
  }

  // All the locations of the USR were found.
  StringRef USR;
  // Old name that is renamed.
  StringRef PrevName;
  std::vector<clang::SourceLocation> LocationsFound;
};
} // namespace

std::vector<SourceLocation> getLocationsOfUSR(StringRef USR,
                                              StringRef PrevName,
                                              Decl *Decl) {
  USRLocFindingASTVisitor visitor(USR, PrevName);

  visitor.TraverseDecl(Decl);
  return visitor.getLocationsFound();
}

} // namespace rename
} // namespace clang
<commit_msg>clang-rename: avoid StringRef members in USRLocFindingASTVisitor<commit_after>//===--- tools/extra/clang-rename/USRLocFinder.cpp - Clang rename tool ----===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// \brief Mehtods for finding all instances of a USR. Our strategy is very
/// simple; we just compare the USR at every relevant AST node with the one
/// provided.
///
//===----------------------------------------------------------------------===//

#include "USRLocFinder.h"
#include "USRFinder.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Index/USRGeneration.h"
#include "clang/Lex/Lexer.h"
#include "llvm/ADT/SmallVector.h"

using namespace llvm;

namespace clang {
namespace rename {

namespace {
// \brief This visitor recursively searches for all instances of a USR in a
// translation unit and stores them for later usage.
class USRLocFindingASTVisitor
    : public clang::RecursiveASTVisitor<USRLocFindingASTVisitor> {
public:
  explicit USRLocFindingASTVisitor(StringRef USR, StringRef PrevName) : USR(USR), PrevName(PrevName) {
  }

  // Declaration visitors:

  bool VisitNamedDecl(const NamedDecl *Decl) {
    if (getUSRForDecl(Decl) == USR) {
      LocationsFound.push_back(Decl->getLocation());
    }
    return true;
  }

  bool VisitVarDecl(clang::VarDecl *Decl) {
    clang::QualType Type = Decl->getType();
    const clang::RecordDecl *RecordDecl = Type->getPointeeCXXRecordDecl();
    if (RecordDecl) {
      if (getUSRForDecl(RecordDecl) == USR) {
        // The declaration refers to a type that is to be renamed.
        LocationsFound.push_back(Decl->getTypeSpecStartLoc());
      }
    }
    return true;
  }

  bool VisitCXXConstructorDecl(clang::CXXConstructorDecl *ConstructorDecl) {
    const ASTContext &Context = ConstructorDecl->getASTContext();
    for (clang::CXXConstructorDecl::init_const_iterator it = ConstructorDecl->init_begin(); it != ConstructorDecl->init_end(); ++it) {
      const clang::CXXCtorInitializer* Initializer = *it;
      if (Initializer->getSourceOrder() == -1) {
        // Ignore implicit initializers.
        continue;
      }

      if (const clang::FieldDecl *FieldDecl = Initializer->getAnyMember()) {
        if (getUSRForDecl(FieldDecl) == USR) {
          // The initializer refers to a field that is to be renamed.
          SourceLocation Location = Initializer->getSourceLocation();
          StringRef TokenName = Lexer::getSourceText(CharSourceRange::getTokenRange(Location), Context.getSourceManager(), Context.getLangOpts());
          if (TokenName == PrevName) {
            // The token of the source location we find actually has the old name.
            LocationsFound.push_back(Initializer->getSourceLocation());
          }
        }
      }
    }
    return true;
  }

  // Expression visitors:

  bool VisitDeclRefExpr(const DeclRefExpr *Expr) {
    const auto *Decl = Expr->getFoundDecl();

    checkNestedNameSpecifierLoc(Expr->getQualifierLoc());
    if (getUSRForDecl(Decl) == USR) {
      LocationsFound.push_back(Expr->getLocation());
    }

    return true;
  }

  bool VisitMemberExpr(const MemberExpr *Expr) {
    const auto *Decl = Expr->getFoundDecl().getDecl();
    if (getUSRForDecl(Decl) == USR) {
      LocationsFound.push_back(Expr->getMemberLoc());
    }
    return true;
  }

  // Non-visitors:

  // \brief Returns a list of unique locations. Duplicate or overlapping
  // locations are erroneous and should be reported!
  const std::vector<clang::SourceLocation> &getLocationsFound() const {
    return LocationsFound;
  }

private:
  // Namespace traversal:
  void checkNestedNameSpecifierLoc(NestedNameSpecifierLoc NameLoc) {
    while (NameLoc) {
      const auto *Decl = NameLoc.getNestedNameSpecifier()->getAsNamespace();
      if (Decl && getUSRForDecl(Decl) == USR)
        LocationsFound.push_back(NameLoc.getLocalBeginLoc());
      NameLoc = NameLoc.getPrefix();
    }
  }

  // All the locations of the USR were found.
  const std::string USR;
  // Old name that is renamed.
  const std::string PrevName;
  std::vector<clang::SourceLocation> LocationsFound;
};
} // namespace

std::vector<SourceLocation> getLocationsOfUSR(StringRef USR,
                                              StringRef PrevName,
                                              Decl *Decl) {
  USRLocFindingASTVisitor visitor(USR, PrevName);

  visitor.TraverseDecl(Decl);
  return visitor.getLocationsFound();
}

} // namespace rename
} // namespace clang
<|endoftext|>


<commit_before>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you 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 <mesos/roles.hpp>

#include <stout/foreach.hpp>
#include <stout/strings.hpp>

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

namespace mesos {
namespace roles {

// TODO(haosdent): Remove this function after we stop supporting `--roles`
// flag in master.
Try<vector<string>> parse(const string& text)
{
  vector<string> roles = strings::tokenize(text, ",");

  Option<Error> error = validate(roles);
  if (error.isSome()) {
    return error.get();
  } else {
    return roles;
  }
}

// TODO(haosdent): Pull this out into `stout` and make it satisfy all
// OS/locale constraints.
// \x09 is horizontal tab (whitespace);
// \x0a is line feed (whitespace);
// \x0b is vertical tab (whitespace);
// \x0c is form feed (whitespace);
// \x0d is carriage return (whitespace);
// \x20 is space (whitespace);
// \x2f is slash ('/');
// \x7f is backspace (del);
static const string INVALID_CHARACTERS = "\x09\x0a\x0b\x0c\x0d\x20\x2f\x7f";

Option<Error> validate(const string& role)
{
  static const string dot = ".";
  static const string dotdot = "..";
  if (role.empty()) {
    return Error("Empty role name is invalid");
  } else if (role == dot) {
    return Error("Role name '.' is invalid");
  } else if (role == dotdot) {
    return Error("Role name '..' is invalid");
  } else if (role[0] == '-') {
    return Error("Role name '" + role + "' is invalid "
                 "because it starts with a dash");
  }

  if (role.find_first_of(INVALID_CHARACTERS) != string::npos) {
    return Error("Role name '" + role + "' is invalid "
                 "because it contains slash, backspace or whitespace");
  }

  return None();
}

Option<Error> validate(const vector<string>& roles)
{
  foreach (const string& role, roles) {
    Option<Error> error = validate(role);
    if (error.isSome()) {
      return error.get();
    }
  }

  return None();
}

} // namespace roles {
} // namespace mesos {
<commit_msg>Changed static pods to pointers in role validation.<commit_after>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you 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 <mesos/roles.hpp>

#include <stout/foreach.hpp>
#include <stout/strings.hpp>

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

namespace mesos {
namespace roles {

// TODO(haosdent): Remove this function after we stop supporting `--roles`
// flag in master.
Try<vector<string>> parse(const string& text)
{
  vector<string> roles = strings::tokenize(text, ",");

  Option<Error> error = validate(roles);
  if (error.isSome()) {
    return error.get();
  } else {
    return roles;
  }
}

// TODO(haosdent): Pull this out into `stout` and make it satisfy all
// OS/locale constraints.
// \x09 is horizontal tab (whitespace);
// \x0a is line feed (whitespace);
// \x0b is vertical tab (whitespace);
// \x0c is form feed (whitespace);
// \x0d is carriage return (whitespace);
// \x20 is space (whitespace);
// \x2f is slash ('/');
// \x7f is backspace (del);
static const string* INVALID_CHARACTERS =
  new string("\x09\x0a\x0b\x0c\x0d\x20\x2f\x7f");

Option<Error> validate(const string& role)
{
  static const string* dot = new string(".");
  static const string* dotdot = new string("..");
  if (role.empty()) {
    return Error("Empty role name is invalid");
  } else if (role == *dot) {
    return Error("Role name '.' is invalid");
  } else if (role == *dotdot) {
    return Error("Role name '..' is invalid");
  } else if (role[0] == '-') {
    return Error("Role name '" + role + "' is invalid "
                 "because it starts with a dash");
  }

  if (role.find_first_of(*INVALID_CHARACTERS) != string::npos) {
    return Error("Role name '" + role + "' is invalid "
                 "because it contains slash, backspace or whitespace");
  }

  return None();
}

Option<Error> validate(const vector<string>& roles)
{
  foreach (const string& role, roles) {
    Option<Error> error = validate(role);
    if (error.isSome()) {
      return error.get();
    }
  }

  return None();
}

} // namespace roles {
} // namespace mesos {
<|endoftext|>