2005/5/9

     
 

Script2.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.
//
#if !defined(DOXYGENONLY)



#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/sys/core_value_scope.h>

#include <acdk/lang/dmi/DmiObject.h>
#include <acdk/lang/dmi/DmiDelegate.h>
#include <acdk/lang/dmi/MetaInfoChildsArray.h>
#include <acdk/lang/reflect/Method.h>
#include <acdk/lang/reflect/Enumeration.h>
#include <acdk/lang/dmi/DmiNamedArg.h>

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


namespace acdk {
namespace cfgscript {



USING_CLASS(::acdk::io::, StreamTokenizer);
using namespace acdk::lang::reflect;
using namespace acdk::lang::dmi;


acdk::lang::Object getObjectWrapper(PEStack& stack, const acdk::lang::dmi::ScriptVar& sv)
{
  if (sv.isObjectType())
    return sv.getObjectVar();
  return new DmiObject(sv);
}


// helper functions
namespace {


using namespace acdk::lang::dmi;



void getArgs(PEStack& stack, ScriptVarArray& args, OUT(RStringArray) na)
{
  int paramsnum = stack.pop().val.getIntVar();
  int pnum = 0;
  int nnum = 0;
  int i;
  int j = 0;
  for (i = paramsnum - 1; i >= 0; --i, ++j)
  {
    PEVal v = stack.peek(j);
    if (v.tk == TT_ARGLABEL)
      ++nnum;
    else
      ++pnum;
  }
  args.resize(pnum);
  if (nnum != 0)
    na = new StringArray(nnum);
  //pnum = 0;
  //nnum = 0;
  for (i = paramsnum - 1; i >= 0; --i)
  {
    stack.resolveVarOnTop(ResolveToRef);
    PEVal v = stack.pop();
    if (v.tk == TT_ARGLABEL)
      na[--nnum] = v.val.getStringVar();
    else
      args[--pnum] = v.val;

  }
}



const ScriptVar& unwrapObject(const ScriptVar& sv)
{
  if (sv.isObjectType() && instanceof(sv.getObjectVar(), DmiObject) == true)
    return *RDmiObject(sv.getObjectVar());
  return sv;
}

RString ScriptVarArray_toString(ScriptVarArray& args)
{
  StringBuffer sb;
  sb.append("[");
  for (int i = 0; i < args.size(); ++i)
  {
    sb.append(args[i].getClazzInfo()->name);
    sb.append("=");
    sb.append(args[i].toCode());
    sb.append(" | ");
  }
  sb.append("]");
  return sb.toString();
}

} // anon namespace

void setScriptCastFlag(PEStack& stack, short flag, bool onOf)
{
  if (onOf == true)
  {
    stack.script->setCastFlags(stack.script->getCastFlags() | flag);
    stack.props->setCastFlags(stack.props->getCastFlags() | flag);
  }
  else
  {
    stack.script->setCastFlags(stack.script->getCastFlags() & ~flag);
    stack.props->setCastFlags(stack.props->getCastFlags() & ~flag);
  }

}

bool
PragmaParseNode::parseExecute(PEStack& stack)
{
  int tk = stack.nextToken();
  RString s = stack.curTokenAsString();
  if (s->equals("strict") == true)
  {
    stack.script->useStrict(true);
    return true;
  }
  if (s->equals("weak") == true)
  {
    stack.script->useStrict(false);
    return true;
  }
  if (s->equals("cast") == true)
  {

  /*
    #pragma cast c2i2c false
    #pragma cast f2i2f true
    #pragma cast b2n false
    #pragma cast n2b true
    #pragma cast o2b true
    #pragma cast autobox true
    #pragma cast checkoverflow false
    #pragma cast a2s false
    #pragma cast s2n false
  */
    tk = stack.nextToken();
    s = stack.curTokenAsString();
    tk = stack.nextToken();
    RString trueFalse = stack.curTokenAsString();
    bool on = false;
    if (trueFalse->equalsIgnoreCase("true") == true)
      on = true;
    else if (trueFalse->equalsIgnoreCase("false") == true)
      on = false;
    else
      ELOG("expect 'true' or 'false' after pragma cast <casttype>");

    if (s->equals("c2i2c") == true)
      setScriptCastFlag(stack, SVCastSVCastChar2Int, on);
    else if (s->equals("f2i2f") == true)
      setScriptCastFlag(stack, SVCastInt2Float, on);
    else if (s->equals("n2b") == true)
      setScriptCastFlag(stack, SVCastNum2Bool, on);
    else if (s->equals("b2n") == true)
      setScriptCastFlag(stack, SVCastBool2Number, on);
    else if (s->equals("o2b") == true)
      setScriptCastFlag(stack, SVCastObject2Bool, on);
    else if (s->equals("autobox") == true)
      setScriptCastFlag(stack, SVCastAutobox, on);
    else if (s->equals("checkoverflow") == true)
      setScriptCastFlag(stack, SVCastCheckOvervflow, on);
    else if (s->equals("a2s") == true)
      setScriptCastFlag(stack, SVCastEncodeString, on);
    else if (s->equals("s2n") == true)
      setScriptCastFlag(stack, SVCastDecodeString, on);
    else
      ELOG("unknown #pragma cast option: " + s);
  }
  else
    ELOG("Unknown pragma directive: " + stack.curTokenAsString());
  return true;
}

bool
PreProcParseNode::parseExecute(PEStack& stack)
{
  int tk = stack.nextToken();
  if (tk == StreamTokenizer::TT_OPERATOR)
  {
     RString cts = stack.curTokenAsString();
     if (cts->equals("!") == true || cts->equals("!/") == true)
     {
       tk = stack.nextToken();
       if (tk == StreamTokenizer::TT_WORD && stack.curTokenAsString()->equals("ignorenextline") == true)
       {
         stack.skipLine();
         stack.skipLine();
       }
       //else
       stack.pushBack();
       return stack.skipLine();
     }
  }
  if (tk != StreamTokenizer::TT_WORD)
    ELOG("expect identifier after '#'");
  if (stack.curTokenAsString()->equals("include") == true)
  {
    tk = stack.nextToken();
    if (tk != StreamTokenizer::TT_STRING)
      ELOG("expect string after '#include'");
    RString incl = stack.curTokenValue().getStringVar();
    if (stack.script->currentProps == Nil)
      stack.script->currentProps = stack.props;
    if (stack.script->include(incl, true) == false)
      ELOG("Including file failed: " + incl);
  }
  else if (stack.curTokenAsString()->equals("pragma") == true)
  {
   PARSEEXECUTE(PragmaParseNode().);
  }
  else
  {
    ELOG("Unknown preprocessor token: " + stack.curTokenAsString());
  }
  return true;
}



/*
  Stack enter
  -

  stack leave
  0 value parameter count
  1 - n parameter values
*/
bool
ParametersParseNode::parseExecute(PEStack& stack)
{
  int tk = stack.nextToken();

  if (tk != '(')
    ELOG("Expect '('");
  acdk::lang::sys::core_value_scope<RString> _stackOp(stack.leftOp, Nil);
  int topidx = stack.vs.size();
  while ((tk = stack.nextToken()) != ')')
  {
    RString paramname;
    if (tk == ':')
    {
      tk = stack.nextToken();
      paramname = stack.curTokenAsString();
      tk = stack.nextToken();
      if (stack.curTokenAsString()->equals("="))
        tk = stack.nextToken();
      stack.pushBack();
    }
    else
    {
      RString label = stack.curTokenAsString();
      tk = stack.nextToken();
      if (tk == ':')
      {
        paramname = label;
      }
      else
      {
        stack.pushBack();
        stack.pushBack();
      }
    }
    {
      acdk::lang::sys::core_value_scope<bool> evalOnStack(stack.evalAsRef, true);
      PARSEEXECUTE(ExpressionParseNode().);
    }
    if (paramname != Nil)
      stack.push(TT_ARGLABEL, inOf(paramname));
    stack.makeTopInOf();
    tk = stack.nextToken();
    if (tk == ')')
      break;
    if (tk != ',')
    {
      ELOG("Expect ',' for next Parameter");
    }
  }
  int newtop = stack.vs.size();
  stack.push(TT_VALUE, newtop - topidx);
  return true;
}



bool
NewExprParseNode::parseExecute(PEStack& stack)
{
  RString constructor = stack.parseIdentifier("");
  PARSEEXECUTE(ParametersParseNode().);
  ScriptVarArray args;
  RStringArray namedargs;
  getArgs(stack, args, namedargs);
  ASCLITERAL(atom);
  ASCLITERAL(Atom);
  if (constructor->equals(lit_atom) || constructor->equals(lit_Atom))
    constructor = "acdk.lang.dmi.DmiObject";
  RString classname = constructor->replace('.', '/');
  RString funcname = constructor;
  if (funcname->indexOf('/') != -1)
    funcname = funcname->substr(funcname->indexOf('/') + 1);
  ::acdk::lang::dmi::AcdkStdWeakTypeDmiClient dmiclient(stack.props->getCastFlags());
  DOUT("New: " << classname << "()");
  //classname = stack.getAliasOrUsingType(classname, false);
  ScriptVar erg = Object::New(stack.getAliasOrUsingTypeName(classname), args, namedargs, dmiclient);
  acdk::lang::Object tobj = erg.getObjectVar();
  stack.push(TT_VALUE, erg);
  return true;
}


bool
FuncOrMemberParseNode::parseExecute(PEStack& stack)
{
  int tk = stack.nextToken();
  RString m = stack.curTokenAsString();
  tk = stack.nextToken();
  if (tk == '(')
  {
    stack.pushBack();
    PEVal v = stack.pop();
    PARSEEXECUTE(ParametersParseNode().);
    ScriptVarArray args;
    RStringArray namedargs;
    getArgs(stack, args, namedargs);

    acdk::lang::Object o = getObjectWrapper(stack, v.val);
    DOUT("invoke: " << o->getClass()->getName() << "." << m << "()");
    ScriptVar erg;
      CFGSCRIPT_WRAPP_EXT_INVOKE(
        erg = unwrapObject(o->invokeMethod(m, args, namedargs));
      )
    stack.push(TT_VALUE, erg);
    return true;
  }
  else if (tk == StreamTokenizer::TT_OPERATOR && stack.curTokenAsString()->equals("=") == true)
  {

    //stack.pushBack();
    PEVal v = stack.pop();
    ScriptVar sv = v.val;
    if (v.tk == TT_IDENT)
      sv = inOf(stack.props->get(sv.getStringVar()));
    acdk::lang::Object o = getObjectWrapper(stack, sv);
    PARSEEXECUTE(ExpressionParseNode().);
    DOUT("Poke: " << o->getClass()->getName() << "." <<  m << " = " << stack.top().val.toCode());
    o->poke(m, stack.top().val);

  }
  else
  {
    stack.pushBack();
    PEVal v = stack.pop();
    ScriptVar sv = v.val;
    if (v.tk == TT_IDENT)
      sv = inOf(stack.props->get(sv.getStringVar()));
    acdk::lang::Object o = getObjectWrapper(stack, sv);
    DOUT("Peek: " << o->getClass()->getName() << "." <<  m);
    stack.push(TT_VALUE, unwrapObject(o->peek(m, MiAiIn)));

    return true;
  }
  return true;
}


bool
OperatorCall::parseExecute(PEStack& stack)
{
  RString op = stack.pop().val.getStringVar();
  op = acdk::lang::reflect::Method::encodeOperatorToFuncName(op);
  PEVal objv = stack.pop();
  PARSEEXECUTE(ExpressionParseNode().);
  ScriptVarArray args(1);
  stack.resolveVarOnTop();
  args[0] = stack.pop().val;
  acdk::lang::Object o = getObjectWrapper(stack, objv.val);
  DOUT("invoke op: " << o->getClass()->getName() << "." << op << "()");
  ScriptVar erg;
  CFGSCRIPT_WRAPP_EXT_INVOKE(
  erg = unwrapObject(o->invokeMethod(op, args));
  )
  stack.push(TT_VALUE, erg);
  return true;
}



bool
StaticFuncOrMemberParseNode::parseExecute(PEStack& stack)
{
  RString s = stack.pop().val.getStringVar();
  s = stack.getAliasOrUsingTypeName(s); // ### todo seach internal for MetaInfo here and a few lines later to
  const ClazzInfo* ci = 0;
  int tk;
  do {
    const MetaInfo* mi = MetaInfo::findMetaInfo(s);
    if (mi != 0)
    {
      if (mi->isEnumValInfo() == true)
      {
        const ClazzEnumValueInfo* evi = reinterpret_cast<const ClazzEnumValueInfo*>(mi);
        stack.push(TT_VALUE, inOf(evi->value));
        return true;
      }
      else if (mi->isClazzInfo() == true)
      {
        ci = reinterpret_cast<const ClazzInfo*>(mi);
        break;
      }
      else if (mi->isUnitInfo() == true)
      {
        ; //nothing
      }
      else {
        ;
      }
    }
    tk = stack.nextToken();
    if (tk == StreamTokenizer::TT_OPERATOR)
    {
      if (stack.curTokenAsString()->equals(".") == true)
      {
        tk = stack.nextToken();
        if (tk != StreamTokenizer::TT_WORD)
          ELOG("Expect identifier after " + s + ".");
        s = s + "/" + stack.curTokenAsString();
        continue;
      }
      else
      {
        ELOG("Unknown type: " + s);
      }
    }
    else
    {
      ELOG("Unknown type: " + s);
    }
  } while (tk != StreamTokenizer::TT_EOF);
  if (ci != 0)
  {
    int tk = stack.nextToken();
    if (stack.curTokenAsString()->equals(".") != true)
      ELOG("Expect '.' after class name " + s + ".");
    tk = stack.nextToken();
    if (tk != StreamTokenizer::TT_WORD)
      ELOG("Expect identifier after " + s + ".");
    RString m = stack.curTokenAsString();
    tk = stack.nextToken();
    if (tk == '(')
    {
      stack.pushBack();
      PARSEEXECUTE(ParametersParseNode().);
      ScriptVarArray args;
      RStringArray namedargs;
      getArgs(stack, args, namedargs);
      ::acdk::lang::dmi::AcdkStdWeakTypeDmiClient dmiclient(stack.props->getCastFlags());
      DOUT("invoke_static: " << s << "." <<  m << "()");
      CFGSCRIPT_WRAPP_EXT_INVOKE(
      stack.push(TT_VALUE, unwrapObject(StdDispatch::invokeStaticMethod(s, m, args, dmiclient, namedargs)));
      )
      return true;
    }

    else if (tk == StreamTokenizer::TT_OPERATOR && stack.curTokenAsString()->equals("=") == true)
    {
      PARSEEXECUTE(ExpressionParseNode().);
      stack.resolveVarOnTop();
      DOUT("Poke_static: " << s << "." <<  m << " = " << stack.top().val.toCode());
      StdDispatch::poke_static(s, m, stack.top().val);

      return true;
    }
    else //if (tk == StreamTokenizer::TT_OPERATOR && stack.curTokenAsString()->equals(".") == true)
    {
      stack.pushBack();
      DOUT("Peek_static: " << s << "." <<  m);
      ScriptVar erg = StdDispatch::peek_static(s, m);
      stack.push(TT_VALUE, unwrapObject(erg));
      return true;
    }
  }
  return false;
}


bool
pushCurToken(PEStack& stack)
{
  int tk = stack.curToken();
  if (tk == StreamTokenizer::TT_NUMBER || tk == StreamTokenizer::TT_STRING || tk == StreamTokenizer::TT_QCHAR)
    stack.push(TT_VALUE, stack.curTokenValue());
  else if (tk == StreamTokenizer::TT_WORD)
    stack.push(TT_IDENT, stack.curTokenValue());
  else if (tk == StreamTokenizer::TT_OPERATOR)
    stack.push(TT_OPERATOR, stack.curTokenValue());
  else
  {
    ELOG("unknown token type to push");
  }
  return true;
}

bool
tryResolveImportedMethods(PEStack& stack)
{
  RString methodName = stack.pop().val.getStringVar();
  const MetaInfo* mi = 0;
  RUsingEntry ue = stack.findUsingChild(methodName, MiMethodInfo, &mi);
  if (ue != Nil)
  {
    if (ue->isVar == true)
    {
      stack.push(TT_IDENT, inOf(ue->usingName));
      stack.resolveVarOnTop();
      acdk::lang::Object obj = getObjectWrapper(stack, stack.pop().val);
      PEVal dotop(TT_DOTOP, PEVal(TT_VALUE, inOf(obj)), PEVal(TT_IDENT, inOf(methodName)));
      stack.push(dotop);
      PARSEEXECUTE(ExecuteMethodParseNode().);
      return true;
    }
    else
    {
      
      PEVal dotop(TT_DOTOP, PEVal(TT_IDENT, inOf(ue->usingName)), PEVal(TT_IDENT, inOf(methodName)));
      stack.push(dotop);
      PARSEEXECUTE(ExecuteMethodParseNode().);
      return true;
    }
  }
  ELOG("Cannot find object or class for method name: " + methodName);
  return false;
}


/**
  Stack enter:
  0 Method Name
  1 Argnum
  2 - n args
  n + 1 identifier | value

  or
  0 ns.class.method
  1 Argnum
  2 - n args

  stack leave
  0 method return value
*/

bool
ExecuteMethodParseNode::parseExecute(PEStack& stack)
{
  PEVal op = stack.pop();
  if (op.tk != TT_DOTOP)
  {
    RString methodName = op.toCode();
    if (methodName->equals("synchronize") == true)
    {
      ScriptVarArray args;
      RStringArray namedargs;
      getArgs(stack, args, namedargs);
      acdk::lang::Object obj = args[0].getObjectVar();
      SYNCOBJECT(obj);
      PARSEEXECUTE(StatementParseNode().);
      return true;
    }

    stack.push(TT_IDENT, inOf(methodName));
    tryResolveImportedMethods(stack);
    return true;

  }
  RString methodName = op.args->right.val.getStringVar();

  ScriptVarArray args;
  RStringArray namedargs;
  getArgs(stack, args, namedargs);


  acdk::lang::Object object;
  RString className;
  stack.push(op.args->left);
  //className = stack.top().val.getStringVar();
  bool viaObject = false;
  bool superCall = false;
  acdk::lang::Object superObj;
  const acdk::lang::dmi::ClazzInfo* ci = 0;
  ScriptVar orgObjectVar;
  if (stack.resolveVarOnTop(ResolveNothing) == true)
  {
    orgObjectVar = stack.pop().val;
    object = orgObjectVar.getObjectVar(stack.props->getCastFlags());
    viaObject = true;
    if (stack.props->hasValue(lit_this) == true)
    {
      RScriptObject thisO = (RScriptObject)stack.props->getObjectVal(lit_this);
      if (thisO->getSuperObject() == object && thisO != object)
      {
        superObj = thisO->getSuperObject();
        superCall = true;
        ci = superObj->clazzInfo();
      }
    }
  }
  else
  {
    className = stack.pop().val.getStringVar();
    if (stack.props->hasValue(lit_this) == true)
    {
      RScriptObject thisO = (RScriptObject)stack.props->getObjectVal(lit_this);
      if (className->equals(lit_super) == true)
      {
        superObj = thisO->getSuperObject();
        superCall = true;
      }
      else
      {
        ci = Class::forName(className)->objectClazzInfo();
        if (ci->assignableFrom(thisO->getClazzInfo()) == true)
        {
          superCall = true;
          superObj = &thisO;//->getSuperObject();
          if (ci != thisO->getClazzInfo())
            superObj = thisO->getSuperObject();
        }
      }
    }
  }

  ScriptVar erg;
  int callflags = MiPublic;
  if (viaObject == true || superCall == true)
  {

    if (viaObject == false)
    {
      object = superObj;
      if (className->equals(lit_super) == true)
        ci = superObj->getClazzInfo();
      else
        ci = Class::forName(className)->objectClazzInfo();
    }
    else
      ci = object->getClazzInfo();
    if (superCall == true)
    {
      callflags &= ~MiPublic;
      callflags = MiIvTransientCall;
      if (RString(ci->name)->endsWith("_DmiProxy") == true)
      {
        ci = ci->interfaces[0]->type;
        //callflags |= MiIvNoWeakBind;
      }
      //else if ((ci->flags & MiCiWeakBind) == false)
      callflags |= MiIvNoWeakBind;
    }
    const ClazzInfo* orgCi = orgObjectVar.getClazzInfo();
    ASCLITERAL(GetClass); ASCLITERAL(getClass);

    if (orgCi != 0 && orgCi->isBasicClazz() == true && (methodName->equals(lit_GetClass) == true || methodName->equals(lit_getClass) == true))
    {
      // ### todo this if branch is only handled here. but there are much more invokeMethod calls in this source
      erg = inOf(Class::getSingeltonClass(orgCi));
    }
    else
    {
      DOUT("invoke : " << object->getClass()->getName() << "." << methodName << "(...)");
      ScriptVar ret;
      CFGSCRIPT_WRAPP_EXT_INVOKE(
        object->standardDispatch(methodName, ret, args, getDmiClient(), namedargs, callflags, ci, 0);
      )
      erg = unwrapObject(ret);
    }
  }
  else
  {
    //const ClazzInfo* ci = ClazzInfo::findClazzInfo(className);
    const ClazzInfo* ci = stack.findType(className, false);
    if (ci == 0)
    {
      RString tstr = className;
      int idx = 0;
      while (idx != -1)
      {
        idx = tstr->lastIndexOf('.');
        if (idx != -1)
        {
          RString rs = tstr->substr(idx + 1);
          tstr = tstr->substr(0, idx);
          //ci = ClazzInfo::findClazzInfo(tstr);
          ci = stack.findType(tstr);
          RString rp = className->substr(tstr->length() + 1);
          stack.push(TT_IDENT, inOf(rp));
          stack.push(TT_IDENT, inOf(tstr));
          PARSEEXECUTE(ExecStaticPeek().);
          stack.push(TT_IDENT, inOf(methodName));
          PARSEEXECUTE(ExecuteMethodParseNode().);
          return true;
        }
      }
      ELOG("Cannot resolve classname or variable: " + className);
    }

    DOUT("invoke_static : " << className << "." << methodName << "(...)");
    ::acdk::lang::dmi::AcdkStdWeakTypeDmiClient dmiclient(stack.props->getCastFlags());
    className = stack.getAliasOrUsingTypeName(className);
    ASCLITERAL(GetClass);
    if (methodName->equals(lit_GetClass) == true)
    {
      if (ci == ClazzInfo::getCharClazz() || 
          ci == ClazzInfo::getUcCharClazz() ||
          ci == ClazzInfo::getBoolClazz() ||
          ci == ClazzInfo::getByteClazz() ||
          ci == ClazzInfo::getShortClazz() ||
          ci == ClazzInfo::getIntClazz() ||
          ci == ClazzInfo::getLongClazz() ||
          ci == ClazzInfo::getFloatClazz() ||
          ci == ClazzInfo::getDoubleClazz()
          )
      {
        stack.push(TT_VALUE, inOf(Class::getSingeltonClass(ci)));
        return true;
      }
      
    }
    CFGSCRIPT_WRAPP_EXT_INVOKE(
    erg = unwrapObject(invokeStaticMethod(className, methodName, args, dmiclient, namedargs));
    )
  }
  stack.push(TT_VALUE, erg);
  return true;

}

/**
  stack before
  0 left val or identifier
  1 member name
*/

bool
ExecPeek::parseExecute(PEStack& stack)
{
  if (stack.resolveVarOnTop(ResolveNothing | ResolveNoCompIdent | ResolveNotInUsings) == true)
  {
    PEVal objval = stack.pop();
    if (stack.top().tk == TT_DOTOP)
      stack.resolveVarOnTop(ResolveNothing);
    PEVal member = stack.pop();
    if (member.tk == TT_DOTOP)
    {
      ELOG("Unimplemented dotop in peek");
    }
    RString memberName = member.val.getStringVar();
    int midx = memberName->indexOf('.');
    if (midx != -1)
    {
      RString lm = memberName->substr(0, midx);
      RString rm = memberName->substr(midx + 1);
      stack.push(TT_IDENT, inOf(lm));
      stack.push(objval);
      PARSEEXECUTE(ExecPeek().);
      objval = stack.pop();
      stack.push(TT_IDENT, inOf(rm));
      stack.push(objval);
      PARSEEXECUTE(ExecPeek().);
      return true;
    }
    acdk::lang::Object obj = getObjectWrapper(stack, objval.val);
    // ### todo try ...
    DOUT("Peek: " << obj->getClass()->getName() << "." <<  memberName );
    stack.push(TT_VALUE, unwrapObject(obj->peek(memberName)));
    return true;
  }
  PARSEEXECUTE(ExecStaticPeek().);
  return true;
}

/**
  stack before
  0 classname
  1 membername
*/
bool
ExecStaticPeek::parseExecute(PEStack& stack)
{
  RString className = stack.pop().val.getStringVar();
  className = stack.getAliasOrUsingTypeName(className);

  RString memberName = stack.pop().val.getStringVar();
  DOUT("Peek_static: " << className << "." <<  memberName);
  // ### @todo try
  stack.push(TT_VALUE, unwrapObject(StdDispatch::peek_static(className, memberName)));
  return true;
}

/**
  0 right value
  1 member name
  2 left identifier or value
*/
bool
ExecPoke::parseExecute(PEStack& stack)
{
  PEVal val = stack.pop();
  RString memberName = stack.pop().val.getStringVar();
  PEVal objOrClassVal = stack.pop();
  int lps = -1;
  RString objOrClass;
  if (objOrClassVal.tk == TT_IDENT)
  {
    objOrClass = objOrClassVal.val.getStringVar();
    lps = objOrClass->indexOf('.');
  }
  if (lps == -1)
  {
    stack.push(objOrClassVal);
    acdk::lang::Object obj;
    if (stack.resolveVarOnTop(ResolveNothing) == true)
    {
      obj = getObjectWrapper(stack, stack.pop().val);
    }
    if (obj != Nil)
    {
      // ### todo try ...
      DOUT("Poke: " << obj->getClass()->getName() << "." <<  memberName << " = " << val.toCode());
      obj->poke(memberName, val.val);
      stack.push(val);
      return true;
    }
    RString className = stack.pop().val.getStringVar();
    className = stack.getAliasOrUsingTypeName(className);
    StdDispatch::poke_static(className, memberName, val.val);
    stack.push(val);
    return true;
  }
  RString lp = objOrClass->substr(0, lps);
  RString rst = objOrClass->substr(lps + 1);
  stack.push(TT_IDENT, inOf(lp));
  if (stack.resolveVarOnTop(ResolveNothing) == true)
  {
    PEVal tval = stack.pop();
    stack.push(TT_IDENT, inOf(rst));
    stack.push(tval);
    PARSEEXECUTE(ExecPeek().);
    PEVal nval = stack.pop();
    stack.push(nval);
    stack.push(TT_IDENT, inOf(memberName));
    stack.push(val);
    PARSEEXECUTE(ExecPoke().);
    return true;
  }
  else
  {
    stack.pop();
    RString className = objOrClass;
    className = stack.getAliasOrUsingTypeName(className);
    StdDispatch::poke_static(className, memberName, val.val);
    return true;
  }
  return false;
}

/*


  i = i.var + j.var * k.var;
  = .
    -> right
    . +
    -> left
    + .
      -> right
    . *
      -> left
    * .
      -> right

  i = i - j * k | 3
  = -
    -> right
    - *
      -> right
      * |
      -> left
    - |
      left

 */

RString seekNextOperator(PEStack& stack)
{
  int ctokenIdx = stack.getCurTokenIndex();
  int tk;
  while ((tk = stack.nextToken()) != StreamTokenizer::TT_EOF)
  {
    if (isEndExpr(stack.curSourceToken()) == true)
    {
      stack.setCurTokenIndex(ctokenIdx);
      return Nil;
    }
    if (isOperator(stack.curSourceToken()) == true)
    {
      RString ret = stack.curTokenAsString();
      stack.setCurTokenIndex(ctokenIdx);
      return ret;
    }
  }
  stack.setCurTokenIndex(ctokenIdx);
  return Nil;
}

const OpDescription& getOperatorDesc(INP(RString) op);

bool
shallExecuteRight(IN(RString) left, IN(RString) right)
{
  OpDescription opd1 = getOperatorDesc(left);
  OpDescription opd2 = getOperatorDesc(right);
  DOUT("Compare Ops: " << opd1 << " <=> " << opd2);
  if ((opd1.prio - opd2.prio) > 0)
    return true;
  return false;
}


bool
shallExecuteRight(IN(RString) op1, PEStack& stack)
{
  RString op2 = seekNextOperator(stack);
  if (op2 == Nil)
    return false;
  return shallExecuteRight(op1, op2);
  /*
  OpDescription opd1 = getOperatorDesc(op1);
  OpDescription opd2 = getOperatorDesc(op2);
  DOUT("Compare Ops: " << opd1 << " <=> " << opd2);
  if ((opd1.prio - opd2.prio) > 0)
    return true;
  return false;
  */
}

bool handleBuildUnaryOp(PEStack& stack, IN(RString) op, ScriptVar& sv1, OUT(bool) berg)
{
  if (sv1.isObjectType() == true)
    return false;
  berg = true;
  int cf = stack.props->getCastFlags();
  
  if (op->length() == 1)
  {
    switch(op->charAt(0))
    {
    case '!':
      stack.push(TT_VALUE, sv1.logical_not(cf));
      return true;
    case '~':
      stack.push(TT_VALUE, sv1.binary_not(cf));
      return true;
    }
  }
  else if (op->length() == 2)
  {
    int hash = op->hashCode();
    switch(hash)
    {
    case StringHash<'+','+'>::hash:
      sv1 = sv1.addition(1, cf);
      stack.push(TT_VALUE, sv1);
      return true;
    case StringHash<'-','-'>::hash:
      sv1 = sv1.subtraction(1, cf);
      stack.push(TT_VALUE, sv1);
      return true;
    }
  }
  return false;
}

bool handleBuildBinaryOp(PEStack& stack, IN(RString) op, ScriptVar& sv1, const ScriptVar& sv2, bool& ret)
{
  if (sv1.isObjectType() == true)
    return false;
  int cf = stack.props->getCastFlags();
  ret = true;
  if (op->length() == 1)
  {
    switch(op->charAt(0))
    {
    case '+':
      stack.push(TT_VALUE, sv1.addition(sv2, cf));
      return true;
    case '-':
      stack.push(TT_VALUE, sv1.subtraction(sv2, cf));
      return true;
    case '*':
      stack.push(TT_VALUE, sv1.multiply(sv2, cf));
      return true;
    case '/':
      stack.push(TT_VALUE, sv1.divide(sv2, cf));
      return true;
    case '%':
      stack.push(TT_VALUE, sv1.modulo(sv2, cf));
      return true;
    case '<':
      stack.push(TT_VALUE, sv1.less_than(sv2, cf));
      return true;
    case '>':
      stack.push(TT_VALUE, sv1.greater_than(sv2, cf));
      return true;
     case '&':
      stack.push(TT_VALUE, sv1.binary_and(sv2, cf));
      return true;
    case '|':
      stack.push(TT_VALUE, sv1.binary_or(sv2, cf));
      return true;
    case '^':
      stack.push(TT_VALUE, sv1.binary_xor(sv2, cf));
      return true;
     
    }
  }
  else if (op->length() == 2)
  {
    int hash = op->hashCode();
    switch(hash)
    {
    case StringHash<'>','='>::hash:
      stack.push(TT_VALUE, sv1.greater_or_equal(sv2, cf));
      return true;
    case StringHash<'<','='>::hash:
      stack.push(TT_VALUE, sv1.less_or_equal(sv2, cf));
      return true;
    case StringHash<'=','='>::hash:
      stack.push(TT_VALUE, sv1.equal(sv2, cf));
      return true;
    case StringHash<'!','='>::hash:
      stack.push(TT_VALUE, sv1.not_equal(sv2, cf));
      return true;
    case StringHash<'&','&'>::hash:
      stack.push(TT_VALUE, sv1.logical_and(sv2, cf));
      return true;
    case StringHash<'|','|'>::hash:
      stack.push(TT_VALUE, sv1.logical_or(sv2, cf));
      return true;
    case StringHash<'<','<'>::hash:
      stack.push(TT_VALUE, sv1.binary_leftshift(sv2, cf));
      return true;
    case StringHash<'>','>'>::hash:
      stack.push(TT_VALUE, sv1.binary_rightshift(sv2, cf));
      return true;
    case StringHash<'+','+'>::hash:
    {
      ScriptVar sv = sv1;
      sv1 = sv1.addition(1, cf);
      stack.push(TT_VALUE, sv);
      return true;
    }
    case StringHash<'-','-'>::hash:
    {
      ScriptVar sv = sv1;
      sv1 = sv1.subtraction(1, cf);
      stack.push(TT_VALUE, sv);
      return true;
    }
    }
  }
  return false;
}


/**
  Stack on enter
  0 = op
  1 = right arg
  2 = left arg
  stack on leave
  0 = value
*/
bool
ExecBinaryOp::parseExecute(PEStack& stack)
{
  PEVal op = stack.pop();

  RString opstr = op.val.getStringVar();



  // assignment
  if (opstr->equals("=") == true)
  {
    stack.resolveVarOnTop();
    PEVal val = stack.pop();
    PEVal name = stack.pop();
    if (name.tk == TT_IDENT)
    {
      RString n = name.val.getStringVar();
      int nidx = n->lastIndexOf('.');
      if (nidx != -1)
      {
        RString ls = n->substr(0, nidx);
        RString rs = n->substr(nidx + 1);
        stack.push(TT_IDENT, inOf(ls));
        stack.push(TT_IDENT, inOf(rs));
        stack.push(val);
        PARSEEXECUTE(ExecPoke().);
        return true;
      }
      DOUT("Assign " << n << "=" << val.val.toCode());
      if (stack.script->useStrict() == true)
        stack.props->assign(n, new DmiObject(val.val.inOf()));
      else
      {
        if (stack.props->hasValue(n) == true)
          stack.props->assign(n, new DmiObject(val.val.inOf()));
        else
          stack.props->set(n, new DmiObject(val.val.inOf()));
      }

    }
    else if (name.tk == TT_REFVALUE)
    {
      name.val = val.val;
    }
    else if (name.tk == TT_DOTOP)
    {
      PEVal rval = name.args->left;
      PEVal namev = name.args->right;
      RString name = namev.val.getStringVar();
      stack.push(rval);
      if (stack.resolveVarOnTop(ResolveNothing) == false)
      {
        // static
        PEVal rval = stack.pop();
        stack.push(rval);
        stack.push(TT_IDENT, inOf(name));
        stack.push(val);
        PARSEEXECUTE(ExecPoke().);

      }
      else
      {
        // 0 right value
        // 1 member name
        // 2 left identifier or value
        PEVal rval = stack.pop();
        stack.push(rval);
        stack.push(TT_IDENT, inOf(name));
        stack.push(val);
        PARSEEXECUTE(ExecPoke().);
        return true;
      }
    }
    else
    {
      ELOG("Cannot assign");
    }
    stack.push(val);
    return true;
  }
  else if (opstr->equals(".") == true)
  {
    RString nameOrMethod = stack.pop().val.getStringVar();
    if (stack.top().tk == TT_IDENT)
    {
      stack.resolveVarOnTop(ResolveNothing);
    }
    stack.push(PEVal(TT_DOTOP, stack.pop(), PEVal(TT_IDENT, inOf(nameOrMethod))));
    return true;

  }
  else if (opstr->equals("instanceof") == true)
  {
    PEVal cl =  stack.pop();
    RString clsname = cl.toCode();
    clsname = stack.parseIdentifier(clsname);
    stack.resolveVarOnTop();
    ScriptVar sv = stack.pop().val;
    const ClazzInfo* to = stack.findType(clsname);
    if (sv.isObjectType() == true)
    {
      if (sv.getObjectVar(stack.props->getCastFlags())->_cast(to) != 0)
        stack.push(TT_VALUE, inOf(true));
      else
        stack.push(TT_VALUE, inOf(false));
      return true;
    }
    stack.push(TT_VALUE, inOf(to->assignableFrom(sv.getClazzInfo())));
    return true;
  }
  stack.resolveVarOnTop();
  PEVal arg = stack.pop();
  stack.resolveVarOnTop();
  PEVal objv = stack.pop();

  if (opstr->equals("==") == true || opstr->equals("!=") == true ||
      opstr->equals("operator_eq_eq") == true || opstr->equals("operator_nt_eq") == true)
  {
    if (objv.val.isObjectType() == true && arg.val.isObjectType())
    {
      acdk::lang::Object first = objv.val.getObjectVar();
      acdk::lang::Object sec = arg.val.getObjectVar();
      if (opstr->equals("==") == true)
        stack.push(TT_VALUE, inOf(bool(first == sec)));
      else
        stack.push(TT_VALUE, inOf(bool(first != sec)));
      return true;
    }
  }
  bool berg = true;
  if (handleBuildBinaryOp(stack, opstr, objv.val, arg.val, berg) == true)
    return berg;

  opstr = acdk::lang::reflect::Method::encodeOperatorToFuncName(opstr);

  ScriptVarArray args(1);
  args[0] = arg.val;
  acdk::lang::Object o = getObjectWrapper(stack, objv.val);
  DOUT("invoke op: " << o->getClass()->getName() << "." << opstr << "(" << arg.val.toCode() << ")");
  ScriptVar erg;
  CFGSCRIPT_WRAPP_EXT_INVOKE(
  erg = unwrapObject(o->invokeMethod(opstr, args));
  )
  stack.push(TT_VALUE, erg);
  return true;

}

/*
  +a
  (a + 1)
  stack enter
  0 op

  stack leave
  value
*/
bool
ExecUnaryPrefixOp::parseExecute(PEStack& stack)
{
  // handle . as .with statement
  PEVal op = stack.pop();
  RString opstr = op.toCode();
  ASCLITERAL(new);
  if (opstr->equals(lit_new) == true)
  {
    PARSEEXECUTE(NewExprParseNode().);
    return true;
  }
  else if (opstr->equals(".") == true)
  {
    stack.pop();
    ScriptVar sv = *stack.props->get(".with");
    stack.push(TT_VALUE, sv);
    stack.pushBack(); // member
    stack.pushBack(); // .
    //PARSEEXECUTE(ExpressionParseNode2().);
    return true;
  }

  //PEVal valOrId = stack.pop();
  stack.resolveVarOnTop(ResolveToRef);
  PEVal objval = stack.pop();

  bool berg = true;
  if (handleBuildUnaryOp(stack, opstr, objval.val, berg) == true)
    return berg;

  opstr = acdk::lang::reflect::Method::encodeOperatorToFuncName(opstr);
  
  acdk::lang::Object o = getObjectWrapper(stack, objval.val);
  ScriptVar erg;
  ScriptVarArray args;
  CFGSCRIPT_WRAPP_EXT_INVOKE(
    erg = unwrapObject(o->invokeMethod(opstr, args));
  )

  stack.push(TT_VALUE, erg);

  return true;
}

/*
  a--
  a(x)
  Stack enter:
  0 op
  1 left token
  Stack leave
  0 value
*/
bool
ExecUnarySuffixOp::parseExecute(PEStack& stack)
{
  RString op = stack.pop().toCode();
  PEVal lefttk = stack.pop();
  ScriptVar opArg;
  if (op->equals("(") == true)
  {


    stack.pushBack();
    PARSEEXECUTE(ParametersParseNode().);
    RString s;
    int idx = 0;
    if (lefttk.tk == TT_IDENT && (s = lefttk.val.getStringVar()) != Nil && (idx = s->lastIndexOf('.')) != -1)
    {
      RString lp = s->substr(0, idx);
      RString rp = s->substr(idx + 1);
      stack.push(TT_IDENT, inOf(lp));
      stack.push(TT_IDENT, inOf(rp));
    }
    else
      stack.push(lefttk);
    PARSEEXECUTE(ExecuteMethodParseNode().);
    return true;
    // arguments
  }
  else if (op->equals("[") == true)
  {
    //stack.pushBack();
    PARSEEXECUTE(ExpressionParseNode().);
    int tk = stack.nextToken();
    if (tk != ']')
      ELOG("Except ']'");
    stack.resolveVarOnTop();
    opArg = stack.pop().val;
    op = op + "]";
  }
  RString opstr = acdk::lang::reflect::Method::encodeOperatorToFuncName(op);
  stack.push(lefttk);
  stack.resolveVarOnTop(ResolveToRef);
  PEVal objval = stack.pop();
  acdk::lang::Object o = getObjectWrapper(stack, objval.val);
  ScriptVar erg;
  ScriptVarArray args;
  if (op->equals("[]") == true)
    args.push_back(opArg);
  else
    args.push_back(inOf(int(1)));
  CFGSCRIPT_WRAPP_EXT_INVOKE(
  erg = unwrapObject(o->invokeMethod(opstr, args));
  )
  stack.push(TT_VALUE, erg);
  return true;
}


/**
  stack before:
  0 Value;
*/
bool
OptionalSuffixOp::parseExecute(PEStack& stack)
{
  int tokenIndex = stack.getCurTokenIndex();
  int otk = stack.nextToken();
  if (isOperator(stack.curSourceToken()) == true)
  {
    if (otk == '(')
    {
      // noting Calling
      //DOUT("Calling");
    }
    else if (otk == '[')
    {
      // nothing
    }
    else
    {
      RString op1 = stack.curTokenAsString();
      int opflags = getOperatorFlags(op1);
      if ((opflags & OpSuffix) == OpSuffix)
      {
        stack.push(TT_OPERATOR, inOf(op1));
        PARSEEXECUTE(ExecUnarySuffixOp().);
        PARSEEXECUTE(OptionalSuffixOp().);
        return true;
      }
    }
    stack.setCurTokenIndex(tokenIndex);
  }
  else
  {
    stack.setCurTokenIndex(tokenIndex);
  }
  return true;
}

bool
ArrayLiteralParseNode::parseExecute(PEStack& stack)
{
  RDmiObjectArray oa;
  acdk::lang::Object dmiOa;
  if (stack.curLeftDeclType == 0)
    oa = new DmiObjectArray(0);
  else
  {
    RClass cls = Class::getSingeltonClass(stack.curLeftDeclType);
    dmiOa = (acdk::lang::Object)Object::New(cls->getName(), inOf(0));
  }
  stack.curLeftDeclType = 0; // to enable type safe nested arrays
  int tk = 0;
  tk = stack.nextToken();
  if (tk == ']')
  {
  	ScriptVar sv = oa != Nil ? inOf(oa) : inOf(dmiOa);
    stack.push(TT_VALUE, sv);
    return true;
  }
  stack.pushBack();
  do {
    PARSEEXECUTE(ExpressionParseNode().);
    if (oa != Nil)
      oa->append(new DmiObject(stack.pop().val.inOf()));
    else
      dmiOa->invoke("append", stack.pop().val.inOf());
    tk = stack.nextToken();

    if (tk == ',')
      continue;
    if (tk == ']')
    {
    	ScriptVar sv = oa != Nil ? inOf(oa) : inOf(dmiOa);
      stack.push(TT_VALUE, sv);
      return true;
    }
    ELOG("In ArrayLiteral: Expecting ',' or ']'");
  } while (true);
  return false;
}

bool
BacktickParseNode::parseExecute(PEStack& stack)
{
  int otk = stack.nextToken();
  if (otk != StreamTokenizer::TT_STRING)
    ELOG("expect string literal after operator `");

  RString evalstr = stack.curTokenValue().getStringVar();
  RString evaluated = stack.props->eval(evalstr);
  otk = stack.nextToken();
  if (otk != '`')
    ELOG("expect ` after `<stringliteral>");
    //return new ScriptExpr(OpVarOrIdent, 
  stack.push(TT_VALUE, inOf(evaluated));
  return true;
}

bool
DictLiteralParseNode::parseExecute(PEStack& stack)
{
  RProps props = new Props();
  props->setCastFlags(stack.script->getCastFlags());
  int tk = 0;
  tk = stack.nextToken();
  if (tk == '}')
  {
    stack.push(TT_VALUE, inOf(props));
    return true;
  }
  stack.pushBack();
  stack.curLeftDeclType = 0;
  do {
    tk = stack.nextToken();
    if (tk != StreamTokenizer::TT_WORD)
      ELOG("Props litaral: expect key identifier");

    RString ident = stack.curTokenAsString();
    tk = stack.nextToken();
    if (tk != ':')
      ELOG("Props litaral: expect ':' after key identifier");

    PARSEEXECUTE(ExpressionParseNode().);
    props->set(ident, new DmiObject(stack.pop().val.inOf()));
    tk = stack.nextToken();
    RString op1 = stack.curTokenAsString();
    if (tk == ',')
      continue;
    if (tk == '}')
    {
      stack.push(TT_VALUE, inOf(props));
      return true;
    }
    ELOG("In Props: Expecting ',' or '}'");
  } while (true);
  return false;
}




/**
  tokenizer before suffix op
  stack before:
  0 left alue


  stack after
  0 value
*/
bool
SuffixOp::parseExecute(PEStack& stack)
{
  int otk = stack.nextToken();
  if (isOperator(stack.curSourceToken()) == false)
    ELOG("Expect suffix operator");
  RString op1 = stack.curTokenAsString();
  int opflags = getOperatorFlags(op1);
  if ((opflags & OpSuffix) != OpSuffix)
    ELOG("Expect suffix operator");
  stack.push(TT_OPERATOR, inOf(op1));
  PARSEEXECUTE(ExecUnarySuffixOp().);
  PARSEEXECUTE(OptionalSuffixOp().);
  return true;
}

/**
  reads atom with pre and/or postfixes
  Scanner will be before next op/variable
  stack before:
  -
  stack after
  0 Variable
*/
bool
AtomPreOrSuffixOp::parseExecute(PEStack& stack)
{
  int otk = stack.nextToken();
  if (otk == -1)
    ELOG("Unexpected EOF");
  RString op1 = stack.curTokenAsString();
  ASCLITERAL(delegate);
  ASCLITERAL(lambda);
  
  if (op1->equals(lit_delegate) == true)
  {
    PARSEEXECUTE(DelegateParseNode().);
    return true;
  }
  if (op1->equals(lit_lambda) == true)
  {
    PARSEEXECUTE(LambdaParseNode().);
    return true;
  }
  if (isOperator(stack.curSourceToken()) == true)
  {
    int opflags = getOperatorFlags(op1);
    if ((opflags & OpOutfix) == OpOutfix)
    {
      if (otk == '(')
      {
        acdk::lang::sys::core_value_scope<RString> _stackOp(stack.leftOp, Nil);
        PARSEEXECUTE(ExpressionParseNode().);
        otk = stack.nextToken();
        if (otk != ')')
          ELOG("Expect ')'");
        PARSEEXECUTE(ExpressionParseNode2().);
        return true;
      }
      else if (otk == '`')
      {
        PARSEEXECUTE(BacktickParseNode().);
        return true;
      }
      else if (op1->equals("[") == true)
      {
        PARSEEXECUTE(ArrayLiteralParseNode().);
        return true;
      }
      else if (op1->equals("{") == true)
      {
        PARSEEXECUTE(DictLiteralParseNode().);
        return true;
      }
      
    }
    if ((opflags & OpPrefix) != OpPrefix)
      ELOG("Unexpected Operator (no prefix or outfix operator)");
    ASCLITERAL(new);
    if (op1->equals(lit_new) == false)
    {
      PARSEEXECUTE(AtomPreOrSuffixOp().); // ### @todo only parse additionally optional Prefixes
    }
    stack.push(TT_OPERATOR, inOf(op1));
    PARSEEXECUTE(ExecUnaryPrefixOp().);
    return true;
  }
  else if (valOrIdent(stack.curSourceToken()) == true)
  {
    stack.pushValOrIdent(stack.curSourceToken()); // #### @todo will not removed from stack
    //stack.resolveVarOnTop(ResolveNothing | ResolveToRef);
    PARSEEXECUTE(OptionalSuffixOp().);
    return true;
  }
  else
    ELOG("Unexpected token at start of expression");
}

/*
  (1 + 2).toString();
*/
bool parseExpression(PEStack& stack, OUTP(RScriptExpr) expr);

/*
  stack before
  0 label or value

  stack after
  0 value
*/
bool
ExpressionParseNode2::parseExecute(PEStack& stack)
{
restartExpr2:
  //stack.resolveVarOnTop(ResolveNothing);
  PEVal leftexpr = stack.pop();
  int otk = stack.nextToken();

  if (isEndExpr(stack.curSourceToken()) == true)
  {
    stack.pushBack();
    stack.push(leftexpr);
    stack.resolveVarOnTop();
    return true;
  }
  RString op1 = stack.curTokenAsString();

  if (isOperator(stack.curSourceToken()) == false)
    ELOG("Expected Operator");
  bool execRight = shallExecuteRight(op1, stack);

  int opflags = getOperatorFlags(op1);

  if (opflags & OpSuffix)
  {
    stack.pushBack();
    stack.push(leftexpr);
    PARSEEXECUTE(SuffixOp().);
    //goto restartExpr2;
    return true;
  }
  else if (opflags & OpInfix)
  {
    if (op1->equals("||") == true || op1->equals("&&") == true)
    {
      stack.push(leftexpr);
      stack.resolveVarOnTop();
      stack.pushBack();
      return true;
    }
    if (opflags & OpRightAssoc || execRight == true)
    {
      acdk::lang::sys::core_value_scope<RString> _stackOp(stack.leftOp, op1);
      PARSEEXECUTE(ExpressionParseNode().);
      //PARSEEXECUTE(ExpressionParseNodeOne().);
      // ### @todo check if empty
      PEVal rightExpr = stack.pop();
      bool execRight = shallExecuteRight(op1, stack);
      if (execRight == true)
      {
        while (execRight == true)
        {
          stack.push(rightExpr);
          PARSEEXECUTE(ExpressionParseNode2().);
          rightExpr = stack.pop();
          execRight = shallExecuteRight(op1, stack);
          if (execRight == true)
            continue;
          stack.push(leftexpr);
          stack.push(rightExpr);
          stack.push(TT_OPERATOR, inOf(op1));
          PARSEEXECUTE(ExecBinaryOp().);
          return true;
        }
      }
      else
      {
        stack.push(leftexpr);
        stack.push(rightExpr);
        stack.push(TT_OPERATOR, inOf(op1));
        PARSEEXECUTE(ExecBinaryOp().);
        PARSEEXECUTE(ExpressionParseNode2().);
      }
      return true;
    }
    else // left assoc
    {
      //int otk = stack.nextToken();
      PARSEEXECUTE(AtomPreOrSuffixOp().);
      PEVal rightExpr = stack.pop();
      stack.push(leftexpr);
      stack.push(rightExpr);
      stack.push(TT_OPERATOR, inOf(op1));
      PARSEEXECUTE(ExecBinaryOp().);
      /*
      bool execRight = shallExecuteRight(op1, stack);
      PARSEEXECUTE(ExpressionParseNode2().);
      */
      //goto restartExpr2;
      return true;
    }
  }
  else if (getOperatorFlags(op1) & OpOutfix)
  {
    stack.pushBack();
    stack.push(leftexpr);
    stack.push(TT_OPERATOR, inOf(op1));
    PARSEEXECUTE(ExecUnarySuffixOp().);
    int rtk = stack.nextToken();
    if (isEndExpr(stack.curSourceToken()) == true)
    {
      stack.pushBack();
      return true;
    }
    stack.pushBack();
    PARSEEXECUTE(ExpressionParseNode2().);
    //goto restartExpr2;
    return true;
  }
  return true;
}

bool
ExpressionParseNode::parseExecute(PEStack& stack)
{
  int tk = stack.nextToken();
  if (isEndExpr(stack.curSourceToken()) == true)
  {
    stack.push(TT_VALUE, inOf(Nil));
    return true;
  }
  stack.pushBack();
  PARSEEXECUTE(AtomPreOrSuffixOp().);

  // from here to ExpressionParseNode1
  PARSEEXECUTE(ExpressionParseNode1().);
  //dont' do that, because some expression doesn't have evaluatable expr: stack.resolveVarOnTop();
  return true;
  /*
nextRightExpr:
  PARSEEXECUTE(ExpressionParseNode2().);
  tk = stack.nextToken();
  if (isOperator(stack.curSourceToken()) == true)
  {
    //stack.resolveVarOnTop(ResolveNothing);
    stack.pushBack();
    goto nextRightExpr;
  }
  stack.pushBack();
  return true;
  */
}
/* dead
bool
ExpressionParseNodeOne::parseExecute(PEStack& stack)
{
  int tk = stack.nextToken();
  if (isEndExpr(stack.curSourceToken()) == true)
  {
    stack.push(TT_VALUE, inOf(Nil));
    return true;
  }
  stack.pushBack();
  PARSEEXECUTE(AtomPreOrSuffixOp().);
  PARSEEXECUTE(ExpressionParseNode2().);
  PEVal val = stack.top();
  if (val.tk != TT_DOTOP)
    return true;
  tk = stack.nextToken();
  while (tk == '(')
  {
    if (tk == '(')
    {
      stack.push(TT_OPERATOR, inOf(new String("(")));
      PARSEEXECUTE(ExecUnarySuffixOp().);
      val = stack.top();
      tk = stack.nextToken();
    }
    else
    {
      stack.pushBack();
      return true;
    }
  }
  stack.pushBack();
  return true;
}
*/
bool
ExpressionParseNode1::parseExecute(PEStack& stack)
{

nextRightExpr:
  PARSEEXECUTE(ExpressionParseNode2().);
  int tk = stack.nextToken();
  if (isOperator(stack.curSourceToken()) == true)
  {
    RString rop = stack.curTokenAsCode();
    if (rop->equals("||") == true || rop->equals("&&") == true)
    {
      PEVal& val = stack.top();
      if ((val.val.isTrue(stack.props->getCastFlags()) == true && rop->equals("||") == true) ||
          val.val.isTrue(stack.props->getCastFlags()) == false && rop->equals("&&") == true)
      {
        stack.skipExpressionUntilOpLowerOrEqual(getOperatorPredence(rop));
        goto nextRightExpr;
      }
      else
      {
        stack.pop();
        PARSEEXECUTE(ExpressionParseNode().);
        return true;
      }
    }
    if (stack.leftOp == Nil || shallExecuteRight(stack.leftOp, rop) == true)
    {
      //stack.resolveVarOnTop(ResolveNothing);
      stack.pushBack();
      goto nextRightExpr;
    }
  }
  
  if (stack.top().tk == TT_DOTOP) // for (int i in a.b)
    stack.resolveVarOnTop(ResolveNothing); // may be also a typename
  stack.pushBack();
  return true;
}



bool
StatementParseNode::parseExecute(PEStack& stack)
{
  DebugBreakPoints::doBreak(DRANextStatement, stack);
  int debugFlags = ExecutionStack::getDebugFlags();
  if (debugFlags & DbgExitAll)
  {
    stack.executionFlags |= EFActiveReturn;
    return true;
  }

  if (debugFlags & DbgStepOverNextStmt)
  {
     Script:ExecutionStack::setDebugFlags(debugFlags & ~DbgStepOverNextStmt);
     debugFlags &= ~DbgBreakStatements;
     ScopedDbgFlags scopeDbg(debugFlags);
     return StatementParseNode2().parseExecute(stack);
  }
  return StatementParseNode2().parseExecute(stack);
}

bool
ReturnParseNode::parseExecute(PEStack& stack)
{
  int tk = stack.nextToken();
    if (tk == ';')
    {
      stack.executionFlags |= EFActiveReturn;
      stack.push(TT_VALUE, ScriptVar());
      return true;
    }
    stack.pushBack();

    PARSEEXECUTE(ExpressionParseNode().);
    tk = stack.nextToken();
    if (tk != ';')
      ELOG("Expecting ';'");
    stack.resolveVarOnTop();
    stack.executionFlags |= EFActiveReturn;
    return true;
}



bool
StatementParseNode2::parseExecute(PEStack& stack)
{
  int ctokenIdx = stack.getCurTokenIndex();
  
  //stack.script->onBreak(stack);
  int tk = stack.nextToken();
  if (tk == -1)
    return false;
  RString cts = stack.curTokenAsString();
  int ctsHc = cts->hashCode();

  ASCLITERAL(if);
  ASCLITERAL(with);
  ASCLITERAL(while);
  ASCLITERAL(for);
  ASCLITERAL(foreach);
  ASCLITERAL(do);
  ASCLITERAL(using);
  ASCLITERAL(class);
  static StaticAsciiLiteral lit_interface("interface");
  ASCLITERAL(enum);
  ASCLITERAL(ACDK_LOG);
  ASCLITERAL(ACDK_NLOG);
  ASCLITERAL(return);
  ASCLITERAL(break);
  ASCLITERAL(continue);
  ASCLITERAL(try);
  ASCLITERAL(throw);
  ASCLITERAL(catch);
  ASCLITERAL(switch);
  static StaticAsciiLiteral lit_synchronized("synchronized");
  ASCLITERAL(typealias);

  switch (ctsHc)
  {
  case StringHash<'i','f'>::hash:
    if (cts->equals(lit_if) == false)
      break;
    PARSEEXECUTE(IfStatementParseNode().);
    return true;
  case StringHash<'w','i','t','h'>::hash:
    if (cts->equals(lit_with) == false)
      break;
    PARSEEXECUTE(WithParseNode().);
    return true;
  case StringHash<'w','h', 'i','l','e'>::hash:
    if (cts->equals(lit_while) == false)
      break;
    PARSEEXECUTE(WhileParseNode().);
    return true;
  case StringHash<'f','o', 'r'>::hash:
    if (cts->equals(lit_for) == false)
      break;
    PARSEEXECUTE(ForParseNode().);
    return true;
  case StringHash<'f','o', 'r','e', 'a', 'c', 'h'>::hash:
    if (cts->equals(lit_foreach) == false)
      break;
    PARSEEXECUTE(ForEachParseNode().);
    return true;
  case StringHash<'d','o'>::hash:
    if (cts->equals(lit_do) == false)
      break;
    PARSEEXECUTE(DoParseNode().);
    return true;
  case StringHash<'u','s', 'i','n', 'g'>::hash:
    if (cts->equals(lit_using) == false)
      break;
    PARSEEXECUTE(UsingParseNode().);
    return true;
  case StringHash<'c','l', 'a','s', 's'>::hash:
    if (cts->equals(lit_class) == false)
      break;
    PARSEEXECUTE(ClassParseNode().);
    return true;
  case StringHash<'i','n', 't','e', 'r', 'f', 'a', 'c', 'e'>::hash:
    if (cts->equals(lit_interface) == false)
      break;
    PARSEEXECUTE(InterfaceParseNode().);
    return true;
  case StringHash<'e','n', 'u','m'>::hash:
    if (cts->equals(lit_enum) == false)
      break;
    PARSEEXECUTE(EnumParseNode().);
    return true;
   case StringHash<'A','C', 'D','K', '_', 'L', 'O', 'G'>::hash:
   case StringHash<'A','C', 'D','K', '_', 'N', 'L', 'O', 'G'>::hash:
     if (cts->equals(lit_ACDK_LOG) == false && cts->equals(lit_ACDK_NLOG) == false)
      break;
    stack.pushBack();
    PARSEEXECUTE(LogParseNode().);
    return true;
  case StringHash<'r','e', 't','u', 'r', 'n'>::hash:
    if (cts->equals(lit_return) == false)
      break;
    PARSEEXECUTE(ReturnParseNode().);
    return true;
  case StringHash<'b','r', 'e','a', 'k'>::hash:
    if (cts->equals(lit_break) == false)
      break;
    PARSEEXECUTE(BreakParseNode().);
    return true;
  case StringHash<'c','o', 'n','t', 'i', 'n', 'u', 'e'>::hash:
    if (cts->equals(lit_continue) == false)
      break;
    PARSEEXECUTE(ContinueParseNode().);
    return true;
  case StringHash<'t','r', 'y'>::hash:
    if (cts->equals(lit_try) == false)
      break;
    PARSEEXECUTE(TryCatchParseNode().);
    return true;
  case StringHash<'t','h', 'r','o', 'w'>::hash:
    if (cts->equals(lit_throw) == false)
      break;
    PARSEEXECUTE(ThrowParseNode().);
    return true;
  case StringHash<'s','w', 'i','t', 'c', 'h'>::hash:
    if (cts->equals(lit_switch) == false)
      break;
    PARSEEXECUTE(SwitchParseNode().);
    return true;
  case StringHash<'s','y', 'n','c', 'h', 'r', 'o', 'n', 'i', 'z', 'e', 'd'>::hash:
    if (cts->equals(lit_synchronized) == false)
      break;
    PARSEEXECUTE(SynchronizeParseNode().);
    return true;
  case StringHash<'t','y', 'p','e', 'a', 'l', 'i', 'a', 's'>::hash:
    if (cts->equals(lit_typealias) == false)
      break;
    PARSEEXECUTE(TypeAliasParseNode().);
    return true;
  default: 
    break;
  }
  if (tk == '{')
  {
    tk = stack.nextToken();
    if (tk == '}')
      return true;
    
    stack.pushBack();
    //  create new scope
    PropsScope propsscope(stack.props);
    while (tk != -1)
    {
      PARSEEXECUTE(StatementParseNode().);

      if ((stack.executionFlags & EFActiveContinue) || stack.executionFlags & EFActiveBreak)
        return true;
      tk = stack.nextToken();
      if (tk == '}')
        return true;
      stack.pushBack();
    }
    ELOG("Missing closing '}'");
  }
  else if (tk == ';') // empty statement
  {
    return true;
  }
  else if (tk == StreamTokenizer::TT_WORD)
  {
    RString type  = stack.curTokenAsString();
    ASCLITERAL(new);
    if (type->equals(lit_new) == true)
    {
      PARSEEXECUTE(NewExprParseNode().);
      acdk::lang::Object obj = stack.pop().val.getObjectVar();
      return true;
    }
    type = stack.parseIdentifier(type);

    tk = stack.nextToken();
    /*
      int var;
      acdk.lang.String var = 0;
      acdk.lang.String.toString("asdf");
    */
    if (tk == StreamTokenizer::TT_WORD)  // typedeclaration int i
    {
      RString varname = stack.curTokenAsString();
      const ClazzInfo* ci = stack.findType(type);
      stack.props->create(varname, ci);
      acdk::lang::sys::core_value_scope<const ClazzInfo*> leftType(stack.curLeftDeclType, ci);
      tk = stack.nextToken();
      if (tk == ';')
        return true;
      if (tk == StreamTokenizer::TT_OPERATOR && stack.curTokenAsString()->equals("=") == true)
      {
        PARSEEXECUTE(ExpressionParseNode().);
        stack.resolveVarOnTop();
         PEVal var = stack.pop();
        stack.props->assign(varname,  new DmiObject(var.val));
        tk = stack.nextToken();
        if (tk == ';')
          return true;
        ELOG("Expecting ';'");
      }
      else if (tk == '(')
      {
        ELOG("free function definitions not implemented yet");
      }
      ELOG("Expecting ';'");
    }
    else
    {
      stack.setCurTokenIndex(ctokenIdx);
      PARSEEXECUTE(ExpressionParseNode().);
      tk = stack.nextToken();
      if (tk != ';')
        ELOG("Expecting ';'");
    }
    stack.pop();
  }
  else if (tk == STkTemplateComment)
  {
    // simply do nothing
  }
  else if (tk == STkTemplateText)
  {
    acdk::io::RCharWriter cout = (acdk::io::RCharWriter)stack.props->getObjectVal("out");
    acdk::io::RWriter out = cout->getWriter();
    RbyteArray bytes = (RbyteArray)stack.curSourceToken().value.getObjectVar();
    out->write(bytes);
  }
  else if (tk == STkTemplateExpression)
  {
    PARSEEXECUTE(ExpressionParseNode().);
    acdk::io::RPrintWriter cout = (acdk::io::RPrintWriter)stack.props->getObjectVal("out");
    cout->print(stack.pop().val.toString());
  }
  else if (tk == '#')
  {
    PARSEEXECUTE(PreProcParseNode().);
  }
  else
  {
    stack.setCurTokenIndex(ctokenIdx);
    PARSEEXECUTE(ExpressionParseNode().);
    tk = stack.nextToken();
    if (tk != ';')
      ELOG("Expecting ';'");
    stack.pop();
  }
  return true;
}


bool
StatementOrPreProc::parseExecute(PEStack& stack)
{
  int tk;
  while ((tk = stack.nextToken()) != -1)
  {

    if (tk == '#')
    {
      PARSEEXECUTE(PreProcParseNode().);
    }
    else
    {
      stack.pushBack();
      PARSEEXECUTE(StatementParseNode().);
    }
    if (stack.curToken() == -1)
      return true;
  }
  return true;
}


bool
IfStatementParseNode::parseExecute(PEStack& stack)
{
  int tk = stack.nextToken();
  if (tk != '(')
    ELOG("Expecting '(' after 'if' ");
  PARSEEXECUTE(ExpressionParseNode().);

  stack.resolveVarOnTop();
  ScriptVar sv = stack.pop().val;
  tk = stack.nextToken();
  if (tk != ')')
    ELOG("Expecting ')' after 'if (expr'");
  if (sv.isTrue(stack.props->getCastFlags()) == true)
  {
    PARSEEXECUTE(StatementParseNode().);
  }
  else
  {
    tk = stack.skipStatement();
  }
  if (stack.curToken() == -1)
    return true;
  tk = stack.nextToken();
  RString ctstr = stack.curTokenAsString();
  ASCLITERAL(else);
  if (tk == StreamTokenizer::TT_WORD && ctstr->equals(lit_else) == true)
  {
    if (sv.isTrue(stack.props->getCastFlags()) == true)
      tk = stack.skipStatement();
    else
    {
      PARSEEXECUTE(StatementParseNode().);
    }
  }
  else
    stack.pushBack();
  return true;
}

void createStaticMember(const ClazzInfo* ci, ClazzFieldInfo* fi, PEStack& stack);
bool parseArgumentDecl(PEStack& stack, acdk::lang::dmi::ClazzInfo* ci, acdk::lang::dmi::ClazzMethodInfo* mi, IN(acdk::lang::dmi::RDmiNamedArgArray) defaultArgValues);

bool
ClassMemberOrFieldParseNode::parseExecute(PEStack& stack)
{
  ClazzInfo* ci = const_cast<ClazzInfo*>(RClass(stack.top().val.getObjectVar())->objectClazzInfo());
  int tk;
  int nextmemberflags = 0;
  while (true)
  {
    tk = stack.nextToken();
    if (tk == StreamTokenizer::TT_EOF)
      ELOG("Unexpected EOF while parsing class definition");
    RString stk = stack.curTokenAsString();
    if (stk->equals("public") == true)
      nextmemberflags |= MiPublic;
    else if (stk->equals("private") == true)
      nextmemberflags |= MiPrivate;
    else if (stk->equals("protected") == true)
      nextmemberflags |= MiProtected;
    else if (stk->equals("static") == true)
      nextmemberflags |= MiStatic;
    else
      break;
  }
  RString first = stack.curTokenAsString();
  first = stack.parseIdentifier(first);
  tk = stack.nextToken();
  RString second;
  if (tk == StreamTokenizer::TT_WORD)
  {
    second = stack.curTokenAsString();
    tk = stack.nextToken();
  }
  else if (tk == '(') // constructor
  {
    if (first->equals(ci->name) == false)
      ELOG("missing return type or wrong constructor name");
    nextmemberflags |= MiMethodInfo | MiMiConstructor;
    second = first;
    first = Nil;
  } else
    tk = stack.nextToken();
  if (second->equals("operator") == true)
  {
    RString op = stack.curTokenAsString();
    second = acdk::lang::reflect::Method::encodeOperatorToFuncName(op);
    tk = stack.nextToken();
  }
  if (tk == ';' || (tk == StreamTokenizer::TT_OPERATOR && stack.curTokenAsString()->equals("=") == true))
  {
    nextmemberflags |= MiFieldInfo;
    ClazzFieldInfo* fi = createMetaInfo<ClazzFieldInfo>();
    fi->flags = nextmemberflags | MiDelete;
    fi->name = MetaInfo::strdup(second->c_str());
    fi->nameHashCode = -1;
    fi->type = stack.findType(first);
    fi->_scopeParent = (const NamedScopedMetaInfo*)ci;
    ci->addField(fi);
    if (tk == ';')
      return true;

    int codebegin = stack.getCurTokenIndex();
    tk = stack.skipExpression();
    tk = stack.nextToken();
    if (tk != ';')
      ELOG("Expect ';' after <[attributes]> <[type]> <membername> = <expression>");

    int codeend = stack.getCurTokenIndex();
    RScriptMethodInfo methodsource = new ScriptMethodInfo(stack.script, codebegin, codeend);
    Field(ci, fi).setMetaAttribute("_cfgscript_source", (acdk::lang::Object)methodsource);
    if (fi->flags & MiStatic)
    {
      createStaticMember(ci, fi, stack);
    }
    return true;
  }
  else if (tk != '(')
    ELOG("expecting ';' or '(' for class field or member");

  ClazzMethodInfo* mi = createMetaInfo<ClazzMethodInfo>();
  mi->flags = nextmemberflags | MiDelete | MiMethodInfo | MiMiDmiImpl;
  mi->name = MetaInfo::strdup(second->c_str());
  mi->nameHashCode = -1;
  if (nextmemberflags & MiMiConstructor)
    mi->returnType = ci;
  else if (nextmemberflags & MiMiDestructor)
    mi->returnType = ClazzInfo::getVoidClazz();
  else
  {
    mi->returnType = stack.findType(first);
  }
  RDmiNamedArgArray defaultArgValues = new DmiNamedArgArray(0);
  if (parseArgumentDecl(stack, ci, mi, defaultArgValues) == false)
    return false;
  /*
  while ((tk = stack.nextToken()) != StreamTokenizer::TT_EOF)
  {
    if (tk == ')')
    {
      break;
    }
    if (tk == ',')
      continue;

    // ### TODO if (stack.curTokenAsString()->equals("in") out
    RString t = stack.curTokenAsString();

    t = stack.parseIdentifier(t);
    int argumentFlags = 0;
    if (t->equals("in") == true || t->equals("inout") == true || t->equals("out") == true)
    {
      if (t->equals("in") == true) argumentFlags |= MiAiIn;
      if (t->equals("out") == true) argumentFlags |= MiAiOut;
      if (t->equals("inout") == true) argumentFlags |= MiAiInOut;
      t = stack.parseIdentifier("");
    }
    tk = stack.nextToken();
    if (tk != StreamTokenizer::TT_WORD)
      ELOG("expecting word for argument identifier");
    RString n = stack.curTokenAsString();
    ClazzMethodArgInfo* ma = createMetaInfo<ClazzMethodArgInfo>();
    ma->flags = argumentFlags | MiDelete | MiMethodArgInfo;
    ma->name = MetaInfo::strdup(stack.curTokenAsString()->c_str());
    ma->type = stack.findType(t);
    mi->addArgument(ma);
    tk = stack.nextToken();
    if (tk == StreamTokenizer::TT_OPERATOR && stack.curTokenAsString()->equals("=") == true)
    {
      PARSEEXECUTE(ExpressionParseNode().);
      defaultArgValues->append(new DmiNamedArg(ma->name, new DmiObject(stack.pop().val.inOf())));
      // initializer
      tk = stack.nextToken();
    }
    if (tk == ')')
      break;
    if (tk == ',')
      continue;
    ELOG("expect ',' or ')' in parameter declaration");
  }

  // parse parameter
  mi->_scopeParent = (const NamedScopedMetaInfo*)ci;
  ci->addMethod(mi);

  int codebegin = stack.getCurTokenIndex();
  tk = stack.skipStatement();
  int codeend = stack.getCurTokenIndex();
  RScriptMethodInfo methodsource = new ScriptMethodInfo(stack.script, codebegin, codeend);
  Method(ci, mi).setMetaAttribute("_cfgscript_source", (acdk::lang::Object)methodsource);
  mi->dispatch = ScriptObject::dispatch;
  ClazzMethodInfo* defMi = mi;

  int defaultArgsLength = defaultArgValues->length();
  int argsLength = mi->getArgumentCount();
  int reqArgLength  = argsLength - defaultArgsLength;
  int k = 1;
  for (int i = argsLength - 1; i >= reqArgLength; --i, ++k)
  {
    // (int a, int b = 0, int c = 0) => 2

    defMi = defMi->clone();
    defMi->attributeRes = 0;
    Method(ci, defMi).setMetaAttribute("_cfgscript_source", (acdk::lang::Object)methodsource);
    defMi->dispatch = mi->dispatch;
    defMi->_scopeParent = mi->_scopeParent;

    MetaInfoChildsArray<ClazzMethodArgInfo>(defMi->methodArgs).pop_back();
    //RDmiNamedArgArray defArgs = new DmiNamedArgArray(defaultArgsLength - i);
    RDmiNamedArgArray defArgs = new DmiNamedArgArray(k);
    int tdefargslength = defArgs->length();
    for (int j = tdefargslength - 1; j >= 0; --j)
    {
      //int davidx = defaultArgsLength - i + j;
      int davidx = defaultArgsLength - j - 1;
      defArgs[j] = defaultArgValues[davidx];
    }
    Method(ci, defMi).setMetaAttribute("_cfgscript_defaultArgs", (acdk::lang::Object)defArgs);

    ci->addMethod(defMi);
  }

  if (Method(ci, mi).hasMetaAttribute("_cfgscript_defaultArgs") == true)
  {
    RDmiNamedArgArray defaultArgs = (RDmiNamedArgArray)Method(ci, mi).getMetaAttribute("_cfgscript_defaultArgs")->value;
  }
  */
  return true;
}

bool
ClassBodyParseNode::parseExecute(PEStack& stack)
{
  int nextmemberflags = 0;
  int tk;
  RStringArray fields = new StringArray(0);

  while ((tk = stack.nextToken()) != StreamTokenizer::TT_EOF)
  {
    if (tk == '}')
      return true;
    else
    {
      stack.pushBack();
      PARSEEXECUTE(ClassMemberOrFieldParseNode().);
    }
  }
  ELOG("Unexpected EOF while parsing class definition");
  return false;
}

ClazzInfo* ClazzInfo_create(IN(RString) name, const UnitInfo* parent = 0)
{
  int idx = name->lastIndexOf('.');
  RString unit = "";
  RString classname = name;
  UnitInfo* ui = 0;
  if (idx != -1)
  {
    unit = name->substr(0, idx);
    classname = name->substr(idx + 1);
    ui = UnitInfo::findCreateUnit(unit->replace('.', '/')->replace("::", "/")->c_str());
  }
  ClazzInfo* ev = createMetaInfo<ClazzInfo>();
  ev->flags = MiClazzInfo | MiPublic | MiDelete | MiCiWeakBind | MiResolved;
  ev->name = MetaInfo::strdup(classname->c_str());
  ev->nameHashCode = -1;
  ev->ns = MetaInfo::strdup(unit->replace('.', '/')->c_str());
  ev->_scopeParent = ui->getMetaInfo();
  ev->static_dispatch = ScriptObject::static_dispatch;
  return ev;
}

struct RegisterTempClass
{
  ClazzInfo* _ci;
  RegisterTempClass(ClazzInfo* ci)
    : _ci(ci)
  {
    _ci->registerClazzInfo();
  }
  ~RegisterTempClass()
  {
    if (_ci == 0)
      return;
    ClazzInfo::unregisterClazzInfo(_ci);
    _ci->dispose();
  }
  void commit() { _ci = 0; }
};

bool
ClassParseNode_parseExecute(PEStack& stack, bool isInterface)
{
  RString classname = stack.parseIdentifier("");
  //int tk = stack.nextToken();
  //RString classname = stack.curTokenAsString();
  ClazzInfo* ci = ClazzInfo_create(classname);
  if (isInterface == true)
    ci->flags |= MiCiInterface;
  // have to register because in class definition may used the class
  RegisterTempClass _rtc(ci);
  RClass thisclass = Class::getSingeltonClass(ci);
  thisclass->setMetaAttribute("_cfgscript_script", (acdk::lang::Object)&stack.script);
  thisclass->setMetaAttribute("_cfgscript_module_props", (acdk::lang::Object)&stack.props);
  // ### @todo stack controlled unregister
  int tk = 0;
  acdk::lang::sys::core_vector<ClazzSuperInfo*> _supers;
  while ((tk = stack.nextToken()) != StreamTokenizer::TT_EOF)
  {
    if (tk == StreamTokenizer::TT_WORD || tk == ',')
    {
      RString deriveType = stack.curTokenAsString();
      if (deriveType->equals("implements") == true ||
          deriveType->equals("extends") == true ||
          tk == ',')
      {
        if (tk == ',')
          deriveType = "implements";

        RString super = stack.parseIdentifier("")->replace('.', '/');
        if (ClazzInfo::findClazzInfo(super + "_DmiProxy") != 0)
          super = super + "_DmiProxy";
        const ClazzInfo* sci = stack.findType(super);
        ClazzSuperInfo* ev = createMetaInfo<ClazzSuperInfo>();
        ev->flags = MiPublic | MiDelete | MiSuperInfo;
        ev->type = sci;
        _supers.push_back(ev);
        //ci->addSuper(ev);
      }
    }
    else if (tk == '{')
    {
      bool hasSuper = false;
      int i;
      for (i = 0; i < _supers.size(); ++i)
      {
        if (_supers[i] != 0 && ScriptObject::_isDmiProxyInterface(_supers[i]->type) == false)
        {
          hasSuper = true;
          break;
        }
      }
      if (hasSuper == false && isInterface == false)
      {
        ClazzSuperInfo* ev = createMetaInfo<ClazzSuperInfo>();
        ev->flags = MiPublic | MiDelete | MiSuperInfo;

        if (ClazzInfo::findClazzInfo(RString("acdk/lang/Object_DmiProxy")) != 0)
          ev->type = stack.findType("acdk/lang/Object_DmiProxy");
        else
          ev->type = Object::clazzInfo();
        ci->addSuper(ev);
      }
      for (i = 0; i < _supers.size(); ++i)
      {
        ci->addSuper(_supers[i]);
      }
      stack.push(TT_VALUE, inOf(thisclass));
      PARSEEXECUTE(ClassBodyParseNode().);
      stack.pop();
      _rtc.commit();
      // ### @todo register in Script and deregister in ~Script
      return true;
    }
    else
      ELOG("Unknown token in parsing class declaration");
  }
  return true;
}

bool
ClassParseNode::parseExecute(PEStack& stack)
{
  return ClassParseNode_parseExecute(stack, false);
/*
  RString classname = stack.parseIdentifier("");
  //int tk = stack.nextToken();
  //RString classname = stack.curTokenAsString();
  ClazzInfo* ci = ClazzInfo_create(classname);

  // have to register because in class definition may used the class
  RegisterTempClass _rtc(ci);
  RClass thisclass = Class::getSingeltonClass(ci);
  thisclass->setMetaAttribute("_cfgscript_script", (acdk::lang::Object)&stack.script);
  thisclass->setMetaAttribute("_cfgscript_module_props", (acdk::lang::Object)&stack.props);
  // ### @todo stack controlled unregister
  int tk = 0;
  acdk::lang::sys::core_vector<ClazzSuperInfo*> _supers;
  while ((tk = stack.nextToken()) != StreamTokenizer::TT_EOF)
  {
    if (tk == StreamTokenizer::TT_WORD || tk == ',')
    {
      RString deriveType = stack.curTokenAsString();
      if (deriveType->equals("implements") == true ||
          deriveType->equals("extends") == true ||
          tk == ',')
      {
        if (tk == ',')
          deriveType = "implements";

        RString super = stack.parseIdentifier("")->replace('.', '/');
        if (ClazzInfo::findClazzInfo(super + "_DmiProxy") != 0)
          super = super + "_DmiProxy";
        const ClazzInfo* sci = stack.findType(super);
        ClazzSuperInfo* ev = createMetaInfo<ClazzSuperInfo>();
        ev->flags = MiPublic | MiDelete | MiSuperInfo;
        ev->type = sci;
        _supers.push_back(ev);
        //ci->addSuper(ev);
      }
    }
    else if (tk == '{')
    {
      bool hasSuper = false;
      int i;
      for (i = 0; i < _supers.size(); ++i)
      {
        if (ScriptObject::_isDmiProxyInterface(_supers[i]->type) == false)
        {
          hasSuper = true;
          break;
        }
      }
      if (hasSuper == false)
      {
        ClazzSuperInfo* ev = createMetaInfo<ClazzSuperInfo>();
        ev->flags = MiPublic | MiDelete | MiSuperInfo;

        if (ClazzInfo::findClazzInfo(RString("acdk/lang/Object_DmiProxy")) != 0)
          ev->type = stack.findType("acdk/lang/Object_DmiProxy");
        else
          ev->type = Object::clazzInfo();
        ci->addSuper(ev);
      }
      for (i = 0; i < _supers.size(); ++i)
      {
        ci->addSuper(_supers[i]);
      }
      stack.push(TT_VALUE, inOf(thisclass));
      PARSEEXECUTE(ClassBodyParseNode().);
      stack.pop();
      _rtc.commit();
      // ### @todo register in Script and deregister in ~Script
      return true;
    }
    else
      ELOG("Unknown token in parsing class declaration");
  }
  return true;
  */
}

bool
InterfaceParseNode::parseExecute(PEStack& stack)
{
  return ClassParseNode_parseExecute(stack, true);
}

void 
createSuper(PEStack& stack, const ClazzSuperInfo* si, ScriptVarArray& args, IN(RStringArray) namedargs)
{
  RString classname = si->type->toTypeString(TpFtLoadableClass);
  RString funcname = si->type->name;

  ::acdk::lang::dmi::AcdkStdWeakTypeDmiClient dmiclient(stack.props->getCastFlags());

  DOUT("New Super: " << classname << "()");
  if (ClazzInfo::findClazzInfo(classname + "_DmiProxy") != 0)
    classname = classname + "_DmiProxy";
  ScriptVar superobj = Object::New(classname, args, namedargs, dmiclient);
  RScriptObject so = (RScriptObject)stack.props->getObjectVal(lit_this);
  acdk::lang::Object superObj = superobj.getObjectVar();
  so->setSuperObject(superObj);
  stack.props->setObjectVal(lit_super, superObj, PropsNoParentWrite);
  stack.addUsingVar(lit_super, superObj);
}

bool
ConstructorMethodParseNode::parseExecute(PEStack& stack)
{
  int sp = stack.getCurTokenIndex();

  int tk = stack.nextToken(); // consume '{'
  if (tk != '{')
    ELOG("Expect '{' after method header");
  tk = stack.nextToken();
  if (stack.curTokenAsString()->equals(lit_super) == true)
  {
    // ### TODO does't work when static!
    const ClazzSuperInfo* si = ExecutionStack::getTop()->_currentClazzInfo->getSuper();
    if (si == 0)
      ELOG("Class has no super classes to initialize");
    PARSEEXECUTE(ParametersParseNode().);
    ScriptVarArray args;
    RStringArray namedargs;
    getArgs(stack, args, namedargs);
    createSuper(stack, si, args, namedargs);

    while (tk != -1)
    {
      tk = stack.nextToken();
      if (tk == StreamTokenizer::TT_EOF)
        ELOG("Unexpected EOF");
      if (tk == '}')
        break;
      stack.pushBack();
      PARSEEXECUTE(StatementParseNode().);
    }
    return true;
  }
  else
  {
    const ClazzSuperInfo* si = ExecutionStack::getTop()->_currentClazzInfo->getSuper();
    if (si != 0)
    {
      ScriptVarArray args;
      RStringArray namedargs;
      createSuper(stack, si, args, namedargs);
    }
    stack.setCurTokenIndex(sp);
    PARSEEXECUTE(StatementOrPreProc().);
    return true;
  }
}

ClazzEnumInfo* EnumInfo_create(IN(RString) name, const UnitInfo* parent = 0)
{
  int idx = name->lastIndexOf('.');
  RString unit = "";
  RString classname = name;
  const UnitInfo* ui = 0;
  if (idx != -1)
  {
    unit = name->substr(0, idx);
    classname = name->substr(idx + 1);
    ui = UnitInfo::findCreateUnit(unit->c_str());
  }
  ClazzEnumInfo* ev = createMetaInfo<ClazzEnumInfo>();
  ev->flags = MiEnumInfo | MiPublic | MiDelete | MiResolved;
  ev->name = MetaInfo::strdup(classname->c_str());
  ev->nameHashCode = -1;
  ev->ns = MetaInfo::strdup(unit->replace('.', '/')->c_str());
  ev->_scopeParent = ui->getMetaInfo();
  return ev;
}


bool
EnumParseNode::parseExecute(PEStack& stack)
{
  int tk = stack.nextToken();
  RString enumName = stack.curTokenAsString();
  tk = stack.nextToken();
  if (tk != '{')
    ELOG("Excpet '{' after enum <identifier>");

  ClazzEnumInfo* ev = EnumInfo_create(enumName);
  acdk::lang::reflect::Enumeration(ev).setMetaAttribute("_cfgscript_script", (acdk::lang::Object)&stack.script);
  ClazzEnumInfo::registerEnumInfo(ev);
  int lastValue = -1;
  while (true)
  {
    tk = stack.nextToken();
    if (tk != StreamTokenizer::TT_WORD)
      ELOG("Expecting identifier as enum value identifier");
    RString name = stack.curTokenAsString();
    tk = stack.nextToken();
    if (tk == StreamTokenizer::TT_OPERATOR && stack.curTokenAsString()->equals("=") == true)
    {
      PARSEEXECUTE(ExpressionParseNode().);
      int value = stack.pop().val.getIntVar();
      lastValue = value;
      ClazzEnumValueInfo* evi = ClazzEnumValueInfo::create(ev, name, value);
      tk = stack.nextToken();
    }
    else
    {
      ClazzEnumValueInfo* evi = ClazzEnumValueInfo::create(ev, name, ++lastValue);
    }

    if (tk == '}')
      break;
    else if (tk == ',')
      continue;
    else
      ELOG("Unknown Token while parsing enum definition");
  }

  return true;
}


int
Script::_readEval2(IN(RProps) props, bool inplace)
{
  //ScriptSource ss("unknown", in);
  //StreamTokenizer tin(&ss);
  RProps module =  props;
  if (inplace == false)
  {
    module = new Props("module", PropsParentWrite | PropsParentRead, props);
    module->setCastFlags(getCastFlags());
  }
  PEStack stack(this, module);
  ExecutionStack::getTop()->setScopeProps(module);
  ExecutionStack::getTop()->setFrameProps(module);
  
  bool asExpr = props->hasValue("__evalScriptAsExpr");
  if (asExpr == false)
    return StatementOrPreProc().parseExecute(stack) == true ? 0 : 1;
  
  bool erg = ExpressionParseNode().parseExecute(stack);
  if (erg == true)
  {
    RDmiObject erg = new DmiObject(stack.pop().val.inOf());
    props->set("__evalScriptResult", erg);
    return 0;
  }
  return -1;
}


} // namespace cfgscript
} // namespace acdk

#endif //!defined(DOXYGENONLY)