2005/5/9

     
 

Method.cpp

artefaktur
// -*- mode:C++; tab-width:2; c-basic-offset:2; indent-tabs-mode:nil -*- 
//
// Copyright (C) 2000-2005 by Roger Rene Kommer / artefaktur, Kassel, Germany.
// 
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public License (LGPL).
// 
// 
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the 
// License ACDK-FreeLicense document enclosed in the distribution
// for more for more details.
// This file is part of the Artefaktur Component Development Kit:
//                         ACDK
// 
// Please refer to
// - http://www.acdk.de
// - http://www.artefaktur.com
// - http://acdk.sourceforge.net
// for more information.
// 
// $Header: /cvsroot/acdk/acdk/acdk_core/src/acdk/lang/reflect/Method.cpp,v 1.32 2005/02/05 10:44:59 kommer Exp $

#include <acdk.h>
#include "Method.h"
#include <acdk/lang/Character.h>
//#include <acdk/lang/System.h>
#include "../ObjectArrayImpl.h"
#include "../dmi/AcdkStdWeakTypeDmiClient.h"

namespace acdk {
namespace lang {
namespace reflect {

using namespace acdk::lang;
using namespace acdk::lang::dmi;


//virtual
RClass
Method::getDeclaringClass() 
{ 
  return Class::getSingeltonClass(_theClazz); 
}
//virtual 
int
Method::getModifiers() 
{ 
  return _methodInfo->flags;
}

//virtual 
RString 
Method::getName() 
{ 
  return _methodInfo->name; 
}

RString 
Method::getAlternativeName()
{
  if (_methodInfo->altlabel != 0)
    return _methodInfo->altlabel;
  return _methodInfo->name;
}

//virtual 
RClass 
Method::getReturnType()
{
  return Class::getSingeltonClass(_methodInfo->returnType);
}

//virtual 
RClassArray 
Method::getParameterTypes()
{
  int count = _methodInfo->getArgumentCount();
  RClassArray paramsclasses = new ClassArray(count);
  for (int i = 0; i < count; i++) 
  {
    paramsclasses[i] = Class::getSingeltonClass(_methodInfo->methodArgs[i]->type);
  }
  return paramsclasses;
}

int 
Method::getParameterCount()
{
  return _methodInfo->getArgumentCount();
}

RParameterArray 
Method::getParameters()
{
  int count = _methodInfo->getArgumentCount();
  RParameterArray pa = new ParameterArray(count);
  for (int i = 0; i < count; i++) 
  {
    pa[i] = new Parameter(_theClazz, _methodInfo, _methodInfo->methodArgs[i]); 
  }
  return pa;
}
  
RParameter 
Method::getParameter(int idx)
{
  if (idx >= getParameterCount())
    THROW1(IndexOutOfBoundsException, "Method::getParameter");
  return new Parameter(_theClazz, _methodInfo, _methodInfo->methodArgs[idx]);
}
  
RParameter 
Method::getParameter(IN(RString) paramname)
{
  int i;
  int count = _methodInfo->getArgumentCount();
  
  for (i = 0; i < count; i++) 
  {
    if (paramname->equals(_methodInfo->methodArgs[i]->name) == true)
      return new Parameter(_theClazz, _methodInfo, _methodInfo->methodArgs[i]); 
  }
  return Nil;
}

//virtual 
RClassArray 
Method::getExceptionTypes()
{
  int count = _methodInfo->getExceptionsCount();
  RClassArray exs = new ClassArray(count);
  for (int i = 0; i < count; ++i)
  {
    exs[i] = Class::getSingeltonClass(_methodInfo->exceptions[i]);
  }
  return exs;
}

//virtual 
bool 
Method::equals(IN(acdk::lang::Object) obj)
{
  if (instanceof(obj, Method) == false)
    return false;
  RMethod other = (RMethod)obj;
  if (getName()->equals(other->getName()) == false)
    return false;
  RClassArray p = getParameterTypes();
  RClassArray op  = other->getParameterTypes();
  if (p->length() != op->length())
    return false;
  for (int i = 0; i < p->length(); i++) {
    if (p[i]->getName()->equals(op[i]->getName()) == false)
      return false;
  }
  return true;
}

//virtual 
int 
Method::hashCode()
{
  int result = 0;
  result = 31 * result + getDeclaringClass()->hashCode();
  result = 31 * result + getName()->hashCode();
  result = 31 * result + getParameterTypes()->hashCode();
  return result;
}

//virtual 
RString 
Method::toString()
{
  StringBuffer sb(100);
  MetaInfo::flagsToTypeDecl(sb, getModifiers(), TpFtAcdkType);
  sb.append(" ");
  sb.append(getReturnType()->toString());
  sb.append(" ");
  RClass cls = Class::getSingeltonClass(_theClazz);
  sb.append(cls->toString());
  sb.append(".");
  sb.append(getName());
  sb.append("(");
  RClassArray ca = Method::getParameterTypes();
  for (int i = 0; i < ca->length(); i++) {
    if (i > 0)
      sb.append(", ");
    sb.append(ca[i]->toString());
  }
  sb.append(")");
  return sb.toString();
}

//virtual 
RString 
Method::toIndentifier()
{
  StringBuffer sb(100);
  RClass cls = Class::getSingeltonClass(_theClazz);
  sb.append(cls->getName()->replace('/', '_'));
  sb.append("__");
  sb.append(getName()->replace('/', '_'));
  sb.append("__");
  RClassArray ca = Method::getParameterTypes();
  for (int i = 0; i < ca->length(); i++) {
    if (i > 0)
      sb.append("__");
    sb.append(ca[i]->getName()->replace('/', '_'));
  }
  return sb.toString();
}

//virtual 
acdk::lang::Object 
Method::invoke(IN(acdk::lang::Object) obj, IN(RObjectArray) args) THROWS3(::acdk::lang::RIllegalAccessException, 
							                                                 ::acdk::lang::RIllegalArgumentException,
							                                                 ::acdk::lang::reflect::RInvocationTargetException)
{
  dmi::ScriptVarArray sargs(args != Nil ? args->length() : 0);
  for (int i = 0; i < sargs.size(); i++) 
    sargs[i] = args[i];
  if (getModifiers() & dmi::MiStatic) {
    dmi::ScriptVar ret;
    RClass cls = getDeclaringClass();
    if (cls->objectClazzInfo()->static_dispatch == 0)
      THROW0(InvocationTargetException);
    acdk::lang::dmi::AcdkStdWeakTypeDmiClient dmiclient;
    const acdk::lang::dmi::ClazzInfo* ci = cls->objectClazzInfo();
    if (ci->static_dispatch(getName(), ret, sargs, 
                                                dmiclient, Nil, 
                                                MiPublic | MiStatic, 
                                                ci, 0) == 0)
      THROW0(InvocationTargetException);
    return ret.getObjectVar();
  } else {
    dmi::ScriptVar ret;
    acdk::lang::dmi::AcdkStdWeakTypeDmiClient dmiclient;
    if (obj->standardDispatch(getName(), ret, sargs, 
                              dmiclient, Nil, 
                              MiPublic, obj->getClazzInfo(), 0) == 0)
      THROW0(InvocationTargetException);
    return ret.getObjectVar();
  }
  return Nil;  
}


//static 
char* 
Method::encodeOperatorChar(char op)
{
  switch(op)
  {
  case '*': return "as";
  case '@': return "at";
  case '\\': return "bs";
  case '{': return "co";
  case '}': return "cc";
  case ',': return "cm";
  case '.': return "dt";
  case '=': return "eq";
  case '>': return "gt";
  case '#': return "hs";
  case '<': return "lt";
  case '!': return "nt";
  case '+': return "pl";
  case '%': return "ps";
  case '-': return "mi";
  case '/': return "sl";
  case '[': return "bo";
  case ']': return "bc";
  case ':': return "dp";
  case '|': return "vb";
  case '^': return "rf";
  case '?': return "qs";
  case '&': return "la";
  case '(': return "po";
  case ')': return "pc";
  case '~': return "tl";
  case '': return "pg";
  case '$': return "dl";
  
  default:
    if (Character::isJavaIdentifierPart(op) == true)
    {
      static char retchar[2];
      retchar[0] = op;
      retchar[1] = 0;
      return retchar; // not thread safe
    }
    THROW1(IllegalArgumentException, RString("Unknown operator char:") + op);
  }
  return 0;
}

//static 
RString 
Method::encodeOperatorToFuncName(IN(RString) opchars)
{
  StringBuffer sb("operator");
  String::iterator it = opchars->begin();
  String::iterator end = opchars->end();
  for (; it < end; ++it)
  {
    sb.append("_");
    sb.append(encodeOperatorChar(*it));
  }
  //System::out->println("Operator to func: " + opchars + " = " + sb.toString());
  return sb.toString();
}

/*
RString 
Method::decodeFuncNameToOperator(String::iterator begin, String::iterator end)
{
  //### FIXME
  return Nil;
}
//static 
char 
Method::decodeFuncNameToOpChar(String::iterator& it, String::iterator end)
{
  if (it + 2 >= end || *it != '_')
    THROW1(IllegalArgumentException, RString("Invalid operator encoding:"));
  ++it;
  short v = *(short*)it;
  
  if (v == *(short*)"as")
    return '*';
  else if (v == *(short*)"at")
    return '@';
  else if (v == *(short*)"bs")
    return '\\';
  else if (v == *(short*)"co")
    return '{';
  else if (v == *(short*)"cc")
    return '}';
  else if (v == *(short*)"cm")
    return ',';
  else if (v == *(short*)"dt")
    return '.';
  else if (v == *(short*)"eq")
    return '=';
  else if (v == *(short*)"gt")
    return '>';
  else if (v == *(short*)"hs")
    return '#';
  else if (v == *(short*)"lt")
    return '<';
  else if (v == *(short*)"nt")
    return '!';
  else if (v == *(short*)"pl")
    return '+';
  else if (v == *(short*)"ps")
    return '%';
  else if (v == *(short*)"mi")
    return '-';
  else if (v == *(short*)"sl")
    return '/';
  else if (v == *(short*)"bo")
    return '[';
  else if (v == *(short*)"bc")
    return ']';
  else if (v == *(short*)"dp")
    return ':';
  else if (v == *(short*)"vb")
    return '|';
  else if (v == *(short*)"rf")
    return '^';
  else if (v == *(short*)"qs")
    return '?';
  else if (v == *(short*)"la")
    return '&';
  else if (v == *(short*)"po")
    return '(';
  else if (v == *(short*)"pc")
    return ')';
  else if (v == *(short*)"tl")
    return '~';
  else if (v == *(short*)"pg")
    return '';
  else if (v == *(short*)"dl")
    return '$';
  THROW1(IllegalArgumentException, RString("Invalid operator encoding:"));
  return 0;
}




//static 
RString 
Method::decodeFuncNameToOperator(String::iterator begin, String::iterator end)
{
  StringBuffer sb;
  String::iterator it = begin;
  if (strstr(it, "operator_") == 0)
    it += strlen("operator_");
  while (it < end)
  {
    sb.append(decodeFuncNameToOpChar(it, end));
  }
  return sb.toString();
}
*/
#if defined(__BORLANDC__) //### ACDK_NEED_TEMPLATE_INSTANTIATION

static void __instantiateMissingTemplates()
{
  RInvocationTargetException ex;
  ex = new InvocationTargetException();

}

#endif 


} // reflect
} // lang
} // acdk