2005/5/9

     
 

ExecutionStack.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.
//

#include "Script.h"
#include "ScriptException.h"
#include "ChDir.h"
#include "ScriptEval.h"
#include "ScriptObject.h"
#include "ScriptDebug.h"

#include <acdk/io/StreamTokenizer.h>
#include <acdk/io/FileReader.h>
#include <acdk/io/StringReader.h>
#include <acdk/io/ByteToCharReader.h>
#include <acdk/locale/Encoding.h>
#include <acdk/lang/System.h>
#include <acdk/lang/dmi/AcdkStdWeakTypeDmiClient.h>
#include <acdk/lang/sys/core_vector.h>
#include <acdk/lang/dmi/DmiObject.h>
#include <acdk/lang/reflect/Enumeration.h>

namespace acdk {
namespace cfgscript {

USING_CLASS(::acdk::io::, StreamTokenizer);
using acdk::lang::dmi::ScriptVar;
using acdk::lang::dmi::ScriptVarArray;

//ThreadLocal Script::_currentStack;
OUT(RThreadLocal)
getStackThreadLocal()
{
  static RThreadLocal _stack = new ThreadLocal();
  System::registerStaticReference(_stack);
  return _stack;
}

RExecutionStack 
ExecutionStack::get()
{
  OUT(RThreadLocal) _stack = getStackThreadLocal();
  if (_stack->get() == Nil)
  {
    _stack->set(new ExecutionStack());
  }
  return (RExecutionStack)_stack->get();
}

ExecutionStackFrame::ExecutionStackFrame(IN(RScript) script, int tokenIndex, const acdk::lang::dmi::ClazzMethodInfo* method, int executionFlags)
: _script(script)
, _currentClazzMethodInfo(method)
, _currentClazzInfo(0)
, _executionFlags(executionFlags)
, _curTokenIndex(tokenIndex)
{
  if (_currentClazzMethodInfo != 0)
  {
    _currentClazzInfo = (const acdk::lang::dmi::ClazzInfo*)_currentClazzMethodInfo->_scopeParent;
  }
}

ExecutionStackFrame::ExecutionStackFrame(IN(RScript) script, int tokenIndex, const acdk::lang::dmi::ClazzInfo* clazzInfo, int executionFlags)
: _script(script)
, _currentClazzMethodInfo(0)
, _currentClazzInfo(clazzInfo)
, _executionFlags(executionFlags)
, _curTokenIndex(tokenIndex)
{
}

ExecutionStackFrame::ExecutionStackFrame(IN(RScript) script, int tokenIndex, int executionFlags)
: _script(script)
, _currentClazzMethodInfo(0)
, _currentClazzInfo(0)
, _executionFlags(executionFlags)
, _curTokenIndex(tokenIndex)
{
}

RString 
ExecutionStackFrame::getScriptBackTrace(bool withSourcePos, bool withLocals)
{
  // ### TODO implement withLocals
  RTokenizedSource tsource = _script->getTokenized();
  StringBuffer sb;
  SourceToken& stk = tsource->getSourceToken(_curTokenIndex);

  sb << _script->getFileName()
#if defined(ACDK_OS_WIN32)
     << "(" 
#else
/FONT>
     << ":"
#endif
/FONT>
     << stk.sourcePos.linePos + 1 
#if defined(ACDK_OS_WIN32)
     << ")" 
#endif
/FONT>
     <<  ": " << tsource->getCodeOfLine(stk.sourcePos.linePos) << "\n";
   if (_currentClazzMethodInfo != 0)
  {
    _currentClazzMethodInfo->toTypeString(sb, (const acdk::lang::dmi::ClazzInfo*)_currentClazzMethodInfo->_scopeParent, acdk::lang::dmi::TpFtJavaType);
    sb << "\n";
  }
  return sb.toString();
}

int 
ExecutionStackFrame::getSourceLine()
{
  SourceToken& stk = _script->getTokenized()->getSourceToken(_curTokenIndex);
  return stk.sourcePos.linePos;
}

RString 
ExecutionStackFrame::getSourceFile()
{
  return _script->getFileName();
}

int 
ExecutionStackFrame::getFileLineNo()
{
  // ### todo wrong should be FileLineNo of beginning of method
  return getSourceLine();
}

RString 
ExecutionStackFrame::getFileName()
{
  return getSourceFile();
}

RString 
ExecutionStackFrame::getFunctionSignature()
{
  if (_currentClazzMethodInfo == 0)
    return "<unknown>";

  StringBuffer sb;
  _currentClazzMethodInfo->toTypeString(sb, (const acdk::lang::dmi::ClazzInfo*)_currentClazzMethodInfo->_scopeParent, acdk::lang::dmi::TpFtJavaType);
  return sb.toString();
}

RString 
ExecutionStackFrame::getCurrentSourceLine()
{
  RTokenizedSource tsource = _script->getTokenized();
  StringBuffer sb;
  SourceToken& stk = tsource->getSourceToken(_curTokenIndex);
  //sb << _script->getFileName() << "(" << stk.sourcePos.linePos + 1 << "): " << tsource->getCodeOfLine(stk.sourcePos.linePos) << "\n";
  return tsource->getCodeOfLine(stk.sourcePos.linePos);
}

RString 
ExecutionStackFrame::getLibraryName()
{
  return getSourceFile();
}

acdk::lang::reflect::RMethod 
ExecutionStackFrame::getMethod()
{
  if (_currentClazzMethodInfo == 0)
    return Nil;
  return new acdk::lang::reflect::Method((const acdk::lang::dmi::ClazzInfo*)_currentClazzMethodInfo->_scopeParent, _currentClazzMethodInfo);
}

RStackFrameLocalArray 
ExecutionStackFrame::getLocals()
{
  // ### TODO implement me
  return new StackFrameLocalArray(0);
}


ExecutionStack::~ExecutionStack() 
{ 
  for (int i = _executeStack->length() - 1; _executeStack->length() > 0; --i)
  {
    RExecutionStackFrame fr =  _executeStack[i];
    _executeStack->remove(i);

  }
  // if this done by automatic ~ExecutionStack, _throwObjectInsane happen in props hold by frame
  _executeStack = Nil;
  
}

RString
ExecutionStack::getScriptBackTrace(bool withSourcePos, bool withLocals)
{
  StringBuffer sb;
  for (int i = _executeStack->length() - 1; i >= 0; --i)
    sb << _executeStack[i]->getScriptBackTrace(withSourcePos, withLocals);
  return sb.toString();
}

void 
ExecutionStack::startTransMetaInfo(int flags)
{
  if ((flags & DbgScriptRunIsolated) == 0)
    return;

  _debugFlags |= DbgScriptRunIsolated;
  _registeredMetaInfo = new  acdk::lang::dmi::MetaObjectArray(0);
  acdk::lang::dmi::MetaObject::registerListener(this);
  
}

void deregisterMetaObject(IN(acdk::lang::dmi::RMetaObject) mo)
  {
    if (instanceof(mo, Class) == true)
    {
      RClass cls = (RClass)mo;
      const acdk::lang::dmi::ClazzInfo* ci = cls->objectClazzInfo();
      if (ScriptObject::_isScriptInterface(ci) == false)
        return;
      const_cast<acdk::lang::dmi::ClazzInfo*>(ci)->dispose();
    }
    else if (instanceof(mo, acdk::lang::reflect::Enumeration) == true)
    {
      acdk::lang::reflect::REnumeration ei = (acdk::lang::reflect::REnumeration)mo;
      if (ei->hasMetaAttribute("_cfgscript_script") == true)
      {
        const_cast<acdk::lang::dmi::ClazzEnumInfo*>(ei->getClazzEnumInfo())->dispose();
      }
    }
  }


void
ExecutionStack::rollbackMetaInfo()
{
  if ((_debugFlags & DbgScriptRunIsolated) == 0)
    return;
  acdk::lang::dmi::MetaObject::unRegisterListener(this);
  if (_registeredMetaInfo == Nil)
    return;
  for (int i = 0; i < _registeredMetaInfo->length(); ++i)
    deregisterMetaObject(_registeredMetaInfo[i]);
}
void 
Script::clearStack()
{
  getStackThreadLocal()->set(Nil);
}

void 
ExecutionStack::onRegister(IN(acdk::lang::dmi::RMetaObject) metaObject)
{
  if (_registeredMetaInfo == Nil)
    return;
  _registeredMetaInfo->append(metaObject);
}

void 
ExecutionStack::onUnregister(IN(acdk::lang::dmi::RMetaObject) metaObject)
{
}


} // namespace cfgscript
} // namespace acdk