/*
Dense Script v0.1
Author: Konstantin Stupnik (konstantin.stupnik@gmail.com)
This is more of a joke than serious scripting language.

*/
#include <stdio.h>
#include <stdlib.h>
#include <memory>
#include <ctype.h>
#include <memory.h>
#ifndef _WIN32
#include <strings.h>
#endif
#include <string>
#include <vector>
#include <map>
#include <algorithm>
#include <stdexcept>
#include <stdarg.h>
#include <time.h>
#include <assert.h>

#ifdef DEBUG_MEMORY
#include "DebugMemory.h"
#endif

#define PDC_STATIC_BUILD
#ifdef __SUNPRO_CC
//on solaris default curses is way too old
#include <ncurses/curses.h>
#else
#include <curses.h>
#endif
#ifdef clear
#undef clear
#endif
#ifdef erase
#undef erase
#endif

#ifdef _WIN32
#pragma comment(lib,"pdcurses.lib")
#pragma comment(lib,"user32.lib")
#pragma warning(disable:4100)
#pragma warning(disable:4239)
#endif

typedef unsigned char uchar;

struct Pos{
  Pos():line(0),col(0){}
  size_t line;
  size_t col;
};

struct Char:Pos{
  Char():c(0){}
  uchar c;
};

class BaseException:public std::exception{
public:
  ~BaseException()throw()
  {
  }
  const char* what()const throw()
  {
    return message.c_str();
  }
  void appendPos(Pos pos)
  {
    char buf[64];
    sprintf(buf," at line %lu column %lu.",pos.line,pos.col);
    message+=buf;
  }
protected:
  std::string message;
};

class ParsingException:public BaseException{
public:
  ParsingException(Pos pos,const char* msg,...)
  {
    char buf[1024];
    va_list va;
    va_start(va,msg);
    vsprintf(buf,msg,va);
    va_end(va);
    message=buf;
    appendPos(pos);
  }
  ~ParsingException()throw()
  {
  }
};

class RuntimeError:public BaseException{
public:
  RuntimeError(const char* argMessage)
  {
    message=argMessage;
  }
};

class RuntimeException:public BaseException{
public:
  RuntimeException(Pos pos,const char* msg,...)
  {
    char buf[1024];
    va_list va;
    va_start(va,msg);
    vsprintf(buf,msg,va);
    va_end(va);
    message=buf;
    appendPos(pos);
  }
  ~RuntimeException()throw()
  {
  }
};

void error(const char* msg,...)
{
  char buf[1024];
  va_list va;
  va_start(va,msg);
  vsprintf(buf,msg,va);
  va_end(va);
  throw RuntimeError(buf);
}

std::string itos(size_t val)
{
  char buf[32];
  sprintf(buf,"%lu",val);
  return buf;
}

int getrand(int mx)
{
#if RAND_MAX>0x7fff
  long long v=rand();
  v*=mx;
  v/=RAND_MAX;
#else
  long long v=rand();
  v<<=15;
  v|=rand();
  v*=mx;
  v/=(RAND_MAX|(RAND_MAX<<15));
#endif
  return (int)v;
}

enum VarType{
  vtInt,
  vtString,
  vtArray,
  vtStruct,
  vtArraySegment,
  vtArraySlice,
  vtStringSegment,
  vtStringSlice,
  vtStructSlice,
  vtRefVar,
  vtFuncRef,
  vtMethodRef,
  vtAlias,

  vtCount
};

struct VarRef;
typedef std::vector<VarRef> VarVector;
typedef std::vector<size_t> SizeVector;
//class VarVector;

struct ArrSegment;
struct ArrSlice;
struct StrSegment;
struct StrSlice;
struct StructSlice;
struct FuncRefVar;
struct MethodRefVar;
struct AliasVar;

struct VarPool;

struct VarBase{
  VarBase(VarType argVt):vt(argVt){}
  virtual ~VarBase(){}
  VarBase* next;
  VarPool* memPool;
  VarType vt;
  virtual void clean(){}
};

struct VarPool{
  VarPool();
  virtual ~VarPool();
  template <class T>
  T* allocVar()
  {
    return (T*)alloc(T::getType());
  }

  void dispose(VarBase* var)
  {
    pools[var->vt]->dispose(var);
  }

  VarBase* alloc(VarType vt)
  {
    VarBase* rv=pools[vt]->alloc();
    rv->memPool=this;
    return rv;
  }

  struct IAlloc{
    virtual ~IAlloc(){}
    virtual VarBase* alloc()=0;
    virtual void dispose(VarBase*)=0;
  };

  template <class T,size_t pageSize=256>
  struct TypePool:IAlloc{
    TypePool():lastPage(&firstPage),freeList(0){}
    ~TypePool()
    {
      TypePoolPage* ptr=firstPage.nextPage;
      while(ptr)
      {
        TypePoolPage* tmp=ptr->nextPage;
        delete ptr;
        ptr=tmp;
      }
    }
    struct TypePoolPage{
      TypePoolPage():count(0),nextPage(0){}
      T vars[pageSize];
      size_t count;
      TypePoolPage* nextPage;
    };
    TypePoolPage firstPage;
    TypePoolPage* lastPage;

    VarBase* freeList;

    VarBase* alloc()
    {
      if(freeList)
      {
        VarBase* rv=freeList;
        freeList=freeList->next;
        return rv;
      }
      if(lastPage->count==pageSize)
      {
        lastPage->nextPage=new TypePoolPage;
        lastPage=lastPage->nextPage;
      }
      return &lastPage->vars[lastPage->count++];
    }
    void dispose(VarBase* var)
    {
      var->next=freeList;
      freeList=var;
      var->clean();
    }
  };

  IAlloc* pools[vtCount];

};

struct Namespace;

struct Var:VarBase{
  Var(VarType argVt):VarBase(argVt),isTemp(false),refCount(0){}
  bool isTemp;
  size_t refCount;

  virtual void clean(){}

  int& asInt();
  std::string& asString();
  VarVector& asArray();
  Namespace& asStruct();
  FuncRefVar* asFuncRef();
  MethodRefVar* asMethodRef();
  Var** asRefVar();
  ArrSegment* asArrSegment();
  ArrSlice* asArrSlice();
  StrSegment* asStrSegment();
  StrSlice* asStrSlice();
  StructSlice* asStructSlice();
  AliasVar* asAlias();

  VarRef Clone(bool makeTemp=true);
  bool canAssign(VarRef rhs);
  void Assign(VarRef rhs);

  std::string toString();
  int toInt();
  VarVector toArray();

  void Add(VarRef rhs);
  void Sub(VarRef rhs);
  void Mul(VarRef rhs);
  void Div(VarRef rhs);
  void Mod(VarRef rhs);

  bool isEqual(VarRef rhs);
  bool isLessThan(VarRef rhs);
  bool isLessEq(VarRef rhs);

  const char* getTypeName()const
  {
    switch(vt)
    {
      case vtInt:return "int";
      case vtString:return "string";
      case vtArray:return "array";
      case vtStruct:return "struct";
      case vtArraySegment:return "array segment";
      case vtStringSegment:return "string segment";
      case vtStringSlice:return "string slice";
      case vtArraySlice:return "array slice";
      case vtStructSlice:return "struct slice";
      case vtFuncRef:return "func ref";
      case vtMethodRef:return "method ref";
      case vtRefVar:return "var ref";
      case vtAlias:return "alias";
      default:return "unknown";
    }
  }
};

struct VarRef{
  Var* var;
  VarRef(Var* argVar=0):var(argVar)
  {
    if(var)
    {
      var->refCount++;
    }
  }
  VarRef(const VarRef& argRef):var(argRef.var)
  {
    if(var)
    {
      var->refCount++;
    }
  }
  ~VarRef()
  {
    if(var && !--var->refCount)
    {
      var->memPool->dispose(var);
    }
  }
  VarRef& operator=(const VarRef& rhs)
  {
    if(this==&rhs || var==rhs.var)return *this;
    Var* old=var;
    var=rhs.var;
    if(var)var->refCount++;
    if(old)
    {
      if(!--old->refCount)
      {
        old->memPool->dispose(old);
      }
    }
    return *this;
  }

  VarRef& Dealias();

  Var* operator->()
  {
    assert(var!=0);
    return var;
  }
  Var* operator->()const
  {
    return var;
  }
};


struct Namespace{
  typedef std::map<uchar,VarRef> VarMap;
  VarMap entries;
  bool exists(uchar name)
  {
    return entries.find(name)!=entries.end();
  }
  VarRef& operator[](uchar name)
  {
    return entries[name];
  }
  void add(uchar name,VarRef var)
  {
    entries.insert(std::make_pair(name,var));
  }
};


struct IntVar:Var{
  IntVar():Var(vtInt),val(0){}
  IntVar(int argVal):Var(vtInt),val(argVal){}
  static VarType getType(){return vtInt;}
  void clean()
  {
    val=0;
  }
  int val;
};

struct StrVar:Var{
  StrVar():Var(vtString){}
  StrVar(const std::string& argVal):Var(vtString),val(argVal){}
  static VarType getType(){return vtString;}
  void clean()
  {
    val.clear();
  }
  std::string val;
};


struct ArrVar:Var{
  ArrVar():Var(vtArray){}
  ArrVar(VarVector& argVal):Var(vtArray)
  {
    for(VarVector::const_iterator it=argVal.begin(),end=argVal.end();it!=end;it++)
    {
      val.push_back((*it)->Clone(false));
    }
  }
  static VarType getType(){return vtArray;}
  void clean()
  {
    val.clear();
  }
  VarVector val;
};

struct StructVar:Var{
  StructVar():Var(vtStruct)
  {
  }
  ~StructVar()
  {
  }
  static VarType getType(){return vtStruct;}
  void clean()
  {
    vars.entries.clear();
  }
  Namespace vars;
};

struct ArrSegment:Var{
  ArrSegment():Var(vtArraySegment),var(0),from(0),to(0)
  {
  }
  ArrSegment(VarRef argVar,size_t argFrom,size_t argTo):Var(vtArraySegment),var(argVar),from(argFrom),to(argTo)
  {
  }
  static VarType getType(){return vtArraySegment;}
  void clean()
  {
    var=VarRef();
  }
  VarRef var;
  size_t from,to;
};

struct StrSegment:Var{
  StrSegment():Var(vtStringSegment),var(0),from(0),to(0){}
  StrSegment(VarRef argVar,size_t argFrom,size_t argTo):Var(vtStringSegment),var(argVar),from(argFrom),to(argTo){}
  static VarType getType(){return vtStringSegment;}
  void clean()
  {
    var=VarRef();
  }
  VarRef var;
  size_t from,to;
  std::string getString()
  {
    std::string& val=var->asString();
    if(from>val.length())
    {
      return "";
    }
    size_t len=to-from;
    if(from+len>val.length())
    {
      len=val.length()-from;
    }
    return val.substr(from,len);
  }
};


struct ArrSlice:Var{
  ArrSlice():Var(vtArraySlice),var(0){}
  ArrSlice(VarRef argVar):Var(vtArraySlice),var(argVar){}
  ArrSlice(VarRef argVar,const SizeVector& argIndecies):Var(vtArraySlice),var(argVar),indecies(argIndecies){}
  static VarType getType(){return vtArraySlice;}
  void clean()
  {
    var=VarRef();
    indecies.clear();
  }
  VarRef var;
  SizeVector indecies;
};

struct StrSlice:Var{
  StrSlice():Var(vtStringSlice),var(0){}
  StrSlice(VarRef argVar):Var(vtStringSlice),var(argVar){}
  StrSlice(VarRef argVar,const SizeVector& argIndecies):Var(vtStringSlice),var(argVar),indecies(argIndecies){}
  static VarType getType(){return vtStringSlice;}
  void clean()
  {
    var=VarRef();
    indecies.clear();
  }
  VarRef var;
  SizeVector indecies;

  std::string getString()
  {
    std::string rv;
    std::string& val=var->asString();
    for(SizeVector::const_iterator it=indecies.begin(),end=indecies.end();it!=end;it++)
    {
      if(*it<val.length())
      {
        rv+=val[*it];
      }
    }
    return rv;
  }
};

struct StructSlice:Var{
  StructSlice():Var(vtStructSlice),var(0){}
  StructSlice(VarRef argVar):Var(vtStructSlice),var(argVar){}
  StructSlice(VarRef argVar,const std::vector<uchar>& argFields):Var(vtStructSlice),var(argVar),fields(argFields){}
  static VarType getType(){return vtStructSlice;}
  void clean()
  {
    var=VarRef();
    fields.clear();
  }
  VarRef var;
  std::vector<uchar> fields;
};

struct FuncRefVar:Var{
  FuncRefVar():Var(vtFuncRef){}
  static VarType getType(){return vtFuncRef;}
  size_t funcCp;
  std::vector<uchar> args;
  std::vector<bool> isRef;
};

struct MethodRefVar:Var{
  MethodRefVar():Var(vtMethodRef){}
  static VarType getType(){return vtMethodRef;}
  size_t funcCp;
  std::vector<uchar> args;
  std::vector<bool> isRef;
};

struct RefVar:Var{
  Var** varPtr;
  RefVar(Var** argVarPtr=0):Var(vtRefVar),varPtr(argVarPtr){}
  static VarType getType(){return vtRefVar;}
  void clean()
  {
    varPtr=0;
  }
};

struct VM;
struct Expression{
  Expression(VM* argVM):vm(argVM){}
  virtual ~Expression(){}
  virtual VarRef Evaluate(bool writeMode=false)=0;
  virtual void dump(std::string&)=0;
  VM* vm;
};


struct AliasVar:Var{
  AliasVar():Var(vtAlias),ex(0),dealiasing(false){}
  static VarType getType(){return vtAlias;}
  void clean()
  {
    ex=0;
  }
  Expression* ex;
  bool dealiasing;
};

VarRef& VarRef::Dealias()
{
  if(var->vt==vtAlias)
  {
    VarRef alVar=var;
    AliasVar* al=alVar->asAlias();
    if(al->dealiasing)
    {
      error("recursive alias detected");
    }
    al->dealiasing=true;
    *this=var->asAlias()->ex->Evaluate();
    al->dealiasing=false;
  }
  return *this;
}


VarPool::VarPool()
{
  pools[vtInt]=new TypePool<IntVar,1024>();
  pools[vtString]=new TypePool<StrVar,1024>();
  pools[vtArray]=new TypePool<ArrVar>();
  pools[vtStruct]=new TypePool<StructVar>();
  pools[vtArraySegment]=new TypePool<ArrSegment>();
  pools[vtArraySlice]=new TypePool<ArrSlice>();
  pools[vtStringSegment]=new TypePool<StrSegment>();
  pools[vtStringSlice]=new TypePool<StrSlice>();
  pools[vtStructSlice]=new TypePool<StructSlice>();
  pools[vtRefVar]=new TypePool<RefVar>();
  pools[vtFuncRef]=new TypePool<FuncRefVar>();
  pools[vtMethodRef]=new TypePool<MethodRefVar>();
  pools[vtAlias]=new TypePool<AliasVar>();
}

VarPool::~VarPool()
{
  delete pools[vtInt];
  delete pools[vtString];
  delete pools[vtArray];
  delete pools[vtStruct];
  delete pools[vtArraySegment];
  delete pools[vtArraySlice];
  delete pools[vtStringSegment];
  delete pools[vtStringSlice];
  delete pools[vtStructSlice];
  delete pools[vtRefVar];
  delete pools[vtFuncRef];
  delete pools[vtMethodRef];
  delete pools[vtAlias];
}

Var** Var::asRefVar()
{
  assert(vt==vtRefVar);
  return ((RefVar*)this)->varPtr;
}

int& Var::asInt()
{
  assert(vt==vtInt);
  return ((IntVar*)this)->val;
}

std::string& Var::asString()
{
  assert(vt==vtString);
  return ((StrVar*)this)->val;
}

VarVector& Var::asArray()
{
  assert(vt==vtArray);
  return ((ArrVar*)this)->val;
}

Namespace& Var::asStruct()
{
  assert(vt==vtStruct);
  return ((StructVar*)this)->vars;
}

FuncRefVar* Var::asFuncRef()
{
  assert(vt==vtFuncRef);
  return (FuncRefVar*)this;
}

MethodRefVar* Var::asMethodRef()
{
  assert(vt==vtMethodRef);
  return (MethodRefVar*)this;
}

ArrSegment* Var::asArrSegment()
{
  assert(vt==vtArraySegment);
  return (ArrSegment*)this;
}

ArrSlice* Var::asArrSlice()
{
  assert(vt==vtArraySlice);
  return (ArrSlice*)this;
}

StrSegment* Var::asStrSegment()
{
  assert(vt==vtStringSegment);
  return (StrSegment*)this;
}

StrSlice* Var::asStrSlice()
{
  assert(vt==vtStringSlice);
  return (StrSlice*)this;
}

StructSlice* Var::asStructSlice()
{
  assert(vt==vtStructSlice);
  return (StructSlice*)this;
}

AliasVar* Var::asAlias()
{
  assert(vt==vtAlias);
  return (AliasVar*)this;
}


bool Var::isEqual(VarRef rhs)
{
  rhs.Dealias();
  if(!(vt==rhs->vt || vt==vtRefVar || rhs->vt==vtRefVar))return false;
  if(rhs->vt==vtRefVar)
  {
    if(!rhs->asRefVar())
    {
      error("null variable access");
    }
    return isEqual(*rhs->asRefVar());
  }
  switch(vt)
  {
    case vtInt:return asInt()==rhs->asInt();
    case vtString:return asString()==rhs->asString();
    case vtArray:
    {
      VarVector& lv=asArray();
      VarVector& rv=rhs->asArray();
      if(lv.size()!=rv.size())return false;
      for(size_t i=0;i<lv.size();i++)
      {
        if(!lv[i]->isEqual(rv[i]))
        {
          return false;
        }
      }
      return true;
    }break;
    case vtStruct:
    {
      Namespace& lv=asStruct();
      Namespace& rv=rhs->asStruct();
      if(lv.entries.size()!=rv.entries.size())
      {
        return false;
      }
      for(Namespace::VarMap::iterator it1=lv.entries.begin(),it2=rv.entries.begin(),end=lv.entries.end();it1!=end;it1++,it2++)
      {
        if(it1->first!=it1->first || !it1->second->isEqual(it2->second))
        {
          return false;
        }
      }
      return true;
    }break;
    case vtArraySegment:
    {
      ArrSegment* lv=this->asArrSegment();
      ArrSegment* rv=rhs->asArrSegment();
      size_t d=lv->to-lv->from;
      if(d!=rv->to-rv->from)
      {
        return false;
      }
      VarVector& lvv=lv->var->asArray();
      VarVector& rvv=rv->var->asArray();
      for(size_t i=0;i<d;i++)
      {
        if(!lvv[lv->from+i]->isEqual(rvv[rv->from+i]))
        {
          return false;
        }
      }
      return true;
    }break;
    case vtArraySlice:
    {
      ArrSlice* lv=this->asArrSlice();
      ArrSlice* rv=rhs->asArrSlice();
      if(lv->indecies.size()!=rv->indecies.size())
      {
        return false;
      }
      VarVector& lvv=lv->var->asArray();
      VarVector& rvv=rv->var->asArray();
      for(size_t i=0;i<lv->indecies.size();i++)
      {
        if(!lvv[lv->indecies[i]]->isEqual(rvv[rv->indecies[i]]))
        {
          return false;
        }
      }
      return true;
    }break;
    case vtStringSegment:
    {
      StrSegment* lv=this->asStrSegment();
      StrSegment* rv=rhs->asStrSegment();
      size_t d=lv->to-lv->from;
      if(d!=rv->to-rv->from)
      {
        return false;
      }
      std::string& lvv=lv->var->asString();
      std::string& rvv=rv->var->asString();
      for(size_t i=0;i<d;i++)
      {
        if(lvv[lv->from+i]!=rvv[rv->from+i])
        {
          return false;
        }
      }
      return true;
    }break;
    case vtStringSlice:
    {
      StrSlice* lv=this->asStrSlice();
      StrSlice* rv=rhs->asStrSlice();
      if(lv->indecies.size()!=rv->indecies.size())
      {
        return false;
      }
      std::string& lvv=lv->var->asString();
      std::string& rvv=rv->var->asString();
      for(size_t i=0;i<lv->indecies.size();i++)
      {
        if(lvv[lv->indecies[i]]!=rvv[rv->indecies[i]])
        {
          return false;
        }
      }
      return true;
    }break;
    case vtStructSlice:
    {
      StructSlice* lv=this->asStructSlice();
      StructSlice* rv=rhs->asStructSlice();
      if(lv->fields.size()!=rv->fields.size())
      {
        return false;
      }
      Namespace& lvv=lv->var->asStruct();
      Namespace& rvv=rv->var->asStruct();
      for(size_t i=0;i<lv->fields.size();i++)
      {
        if(!lvv[lv->fields[i]]->isEqual(rvv[rv->fields[i]]))
        {
          return false;
        }
      }
      return true;
    }break;
    case vtRefVar:
    {
      if(*asRefVar())
      {
        return (*asRefVar())->isEqual(rhs);
      }else
      {
        error("null variable access");
      }
    }
    default:return false;
  }
  //return false;
}

bool Var::isLessThan(VarRef rhs)
{
  if(!(vt==rhs->vt || vt==vtRefVar || rhs->vt==vtRefVar))return false;
  if(rhs->vt==vtRefVar)
  {
    if(!rhs->asRefVar())
    {
      error("null variable access");
    }
    return isLessThan(*rhs->asRefVar());
  }
  switch(vt)
  {
    case vtInt:return asInt()<rhs->asInt();
    case vtString:return asString()<rhs->asString();
    case vtArray:
    {
      VarVector& lv=asArray();
      VarVector& rv=rhs->asArray();
      if(lv.size()!=rv.size())return false;
      for(size_t i=0;i<lv.size();i++)
      {
        if(!lv[i]->isLessThan(rv[i]))
        {
          return false;
        }
      }
      return true;
    }break;
    case vtStruct:
    {
      Namespace& lv=asStruct();
      Namespace& rv=rhs->asStruct();
      if(lv.entries.size()!=rv.entries.size())
      {
        return false;
      }
      for(Namespace::VarMap::iterator it1=lv.entries.begin(),it2=rv.entries.begin(),end=lv.entries.end();it1!=end;it1++,it2++)
      {
        if(it1->first!=it1->first || !it1->second->isLessThan(it2->second))
        {
          return false;
        }
      }
      return true;
    }break;
    case vtArraySegment:
    {
      ArrSegment* lv=this->asArrSegment();
      ArrSegment* rv=rhs->asArrSegment();
      size_t d=lv->to-lv->from;
      if(d!=rv->to-rv->from)
      {
        return false;
      }
      VarVector& lvv=lv->var->asArray();
      VarVector& rvv=rv->var->asArray();
      for(size_t i=0;i<d;i++)
      {
        if(!lvv[lv->from+i]->isLessThan(rvv[rv->from+i]))
        {
          return false;
        }
      }
      return true;
    }break;
    case vtArraySlice:
    {
      ArrSlice* lv=this->asArrSlice();
      ArrSlice* rv=rhs->asArrSlice();
      if(lv->indecies.size()!=rv->indecies.size())
      {
        return false;
      }
      VarVector& lvv=lv->var->asArray();
      VarVector& rvv=rv->var->asArray();
      for(size_t i=0;i<lv->indecies.size();i++)
      {
        if(!lvv[lv->indecies[i]]->isLessThan(rvv[rv->indecies[i]]))
        {
          return false;
        }
      }
      return true;
    }break;
    case vtStringSegment:
    {
      StrSegment* lv=this->asStrSegment();
      StrSegment* rv=rhs->asStrSegment();
      size_t d=lv->to-lv->from;
      if(d!=rv->to-rv->from)
      {
        return false;
      }
      std::string& lvv=lv->var->asString();
      std::string& rvv=rv->var->asString();
      for(size_t i=0;i<d;i++)
      {
        if(lvv[lv->from+i]>=rvv[rv->from+i])
        {
          return false;
        }
      }
      return true;
    }break;
    case vtStringSlice:
    {
      StrSlice* lv=this->asStrSlice();
      StrSlice* rv=rhs->asStrSlice();
      if(lv->indecies.size()!=rv->indecies.size())
      {
        return false;
      }
      std::string& lvv=lv->var->asString();
      std::string& rvv=rv->var->asString();
      for(size_t i=0;i<lv->indecies.size();i++)
      {
        if(lvv[lv->indecies[i]]>=rvv[rv->indecies[i]])
        {
          return false;
        }
      }
      return true;
    }break;
    case vtStructSlice:
    {
      StructSlice* lv=this->asStructSlice();
      StructSlice* rv=rhs->asStructSlice();
      if(lv->fields.size()!=rv->fields.size())
      {
        return false;
      }
      Namespace& lvv=lv->var->asStruct();
      Namespace& rvv=lv->var->asStruct();
      for(size_t i=0;i<lv->fields.size();i++)
      {
        if(!lvv[lv->fields[i]]->isLessThan(rvv[rv->fields[i]]))
        {
          return false;
        }
      }
    }break;
    case vtRefVar:
    {
      if(*asRefVar())
      {
        return (*asRefVar())->isLessThan(rhs);
      }else
      {
        error("null variable access");
      }
    }
    default:return false;
  }
  return false;
}

bool Var::isLessEq(VarRef rhs)
{
  if(!(vt==rhs->vt || vt==vtRefVar || rhs->vt==vtRefVar))return false;
  if(rhs->vt==vtRefVar)
  {
    if(!rhs->asRefVar())
    {
      error("null variable access");
    }
    return isLessEq(*rhs->asRefVar());
  }
  switch(vt)
  {
    case vtInt:return asInt()<=rhs->asInt();
    case vtString:return asString()<=rhs->asString();
    case vtArray:
    {
      VarVector& lv=asArray();
      VarVector& rv=rhs->asArray();
      if(lv.size()!=rv.size())return false;
      for(size_t i=0;i<lv.size();i++)
      {
        if(!lv[i]->isLessEq(rv[i]))
        {
          return false;
        }
      }
      return true;
    }break;
    case vtStruct:
    {
      Namespace& lv=asStruct();
      Namespace& rv=rhs->asStruct();
      for(Namespace::VarMap::iterator it1=lv.entries.begin(),it2=rv.entries.begin(),end=lv.entries.end();it1!=end;it1++,it2++)
      {
        if(it1->first!=it1->first || !it1->second->isLessEq(it2->second))
        {
          return false;
        }
      }
      return true;
    }break;
    case vtArraySegment:
    {
      ArrSegment* lv=this->asArrSegment();
      ArrSegment* rv=rhs->asArrSegment();
      size_t d=lv->to-lv->from;
      if(d!=rv->to-rv->from)
      {
        return false;
      }
      VarVector& lvv=lv->var->asArray();
      VarVector& rvv=rv->var->asArray();
      for(size_t i=0;i<d;i++)
      {
        if(!lvv[lv->from+i]->isLessEq(rvv[rv->from+i]))
        {
          return false;
        }
      }
      return true;
    }break;
    case vtArraySlice:
    {
      ArrSlice* lv=this->asArrSlice();
      ArrSlice* rv=rhs->asArrSlice();
      if(lv->indecies.size()!=rv->indecies.size())
      {
        return false;
      }
      VarVector& lvv=lv->var->asArray();
      VarVector& rvv=rv->var->asArray();
      for(size_t i=0;i<lv->indecies.size();i++)
      {
        if(!lvv[lv->indecies[i]]->isLessEq(rvv[rv->indecies[i]]))
        {
          return false;
        }
      }
      return true;
    }break;
    case vtStringSegment:
    {
      StrSegment* lv=this->asStrSegment();
      StrSegment* rv=rhs->asStrSegment();
      size_t d=lv->to-lv->from;
      if(d!=rv->to-rv->from)
      {
        return false;
      }
      std::string& lvv=lv->var->asString();
      std::string& rvv=rv->var->asString();
      for(size_t i=0;i<d;i++)
      {
        if(lvv[lv->from+i]>rvv[rv->from+i])
        {
          return false;
        }
      }
      return true;
    }break;
    case vtStringSlice:
    {
      StrSlice* lv=this->asStrSlice();
      StrSlice* rv=rhs->asStrSlice();
      if(lv->indecies.size()!=rv->indecies.size())
      {
        return false;
      }
      std::string& lvv=lv->var->asString();
      std::string& rvv=rv->var->asString();
      for(size_t i=0;i<lv->indecies.size();i++)
      {
        if(lvv[lv->indecies[i]]>rvv[rv->indecies[i]])
        {
          return false;
        }
      }
      return true;
    }break;
    case vtStructSlice:
    {
      StructSlice* lv=this->asStructSlice();
      StructSlice* rv=rhs->asStructSlice();
      if(lv->fields.size()!=rv->fields.size())
      {
        return false;
      }
      Namespace& lvv=lv->var->asStruct();
      Namespace& rvv=lv->var->asStruct();
      for(size_t i=0;i<lv->fields.size();i++)
      {
        if(!lvv[lv->fields[i]]->isLessEq(rvv[rv->fields[i]]))
        {
          return false;
        }
      }
    }break;
    case vtRefVar:
    {
      if(*asRefVar())
      {
        return (*asRefVar())->isLessEq(rhs);
      }else
      {
        error("null variable access");
      }
    }
    default:return false;
  }
  return false;
}

VarRef Var::Clone(bool makeTemp)
{
  if(this==0)
  {
    error("attempt to clone null variable");
  }
  Var* rv=0;
  switch(vt)
  {
    case vtInt:
    {
      rv=memPool->allocVar<IntVar>();
    }break;
    case vtString:
    {
      rv=memPool->allocVar<StrVar>();
    }break;
    case vtArray:
    {
      rv=memPool->allocVar<ArrVar>();
    }break;
    case vtStruct:
    {
      rv=memPool->allocVar<StructVar>();
    }break;
    case vtArraySegment:
    {
      ArrSegment* as=memPool->allocVar<ArrSegment>();
      as->var=asArrSegment()->var;
      as->from=asArrSegment()->from;
      as->to=asArrSegment()->to;
      return as;

    }break;
    case vtArraySlice:
    {
      ArrSlice* as=memPool->allocVar<ArrSlice>();
      as->var=asArrSlice()->var;
      as->indecies=asArrSlice()->indecies;
      return as;
    }break;
    case vtStringSegment:
    {
      StrSegment* ss=memPool->allocVar<StrSegment>();
      ss->var=asStrSegment()->var;
      ss->from=asStrSegment()->from;
      ss->to=asStrSegment()->to;
      return ss;
    }break;
    case vtStringSlice:
    {
      StrSlice* ss=memPool->allocVar<StrSlice>();
      ss->var=asStrSlice()->var;
      ss->indecies=asStrSlice()->indecies;
      return ss;
    }break;
    case vtStructSlice:
    {
      StructSlice* ss=memPool->allocVar<StructSlice>();
      ss->var=asStructSlice()->var;
      ss->fields=asStructSlice()->fields;
      return ss;
    }break;
    case vtFuncRef:
    {
      FuncRefVar* frv=memPool->allocVar<FuncRefVar>();
      *frv=*asFuncRef();
      return frv;
    }break;
    case vtMethodRef:
    {
      MethodRefVar* mrv=memPool->allocVar<MethodRefVar>();
      *mrv=*asMethodRef();
      return mrv;
    }break;
    case vtRefVar:
    {
      RefVar* v=memPool->allocVar<RefVar>();
      v->varPtr=asRefVar();
      return v;
    }break;
    case vtAlias:
    {
      AliasVar* v=memPool->allocVar<AliasVar>();
      v->ex=asAlias()->ex;
      return v;
    }break;
    default:error("broken variable (%d)",vt);
  }
  rv->Assign(this);
  rv->isTemp=makeTemp;
  return rv;
}

void Var::Add(VarRef rhs)
{
  rhs.Dealias();
  switch(vt)
  {
    case vtInt:
    {
      asInt()+=rhs->toInt();
      return;
    }break;
    case vtString:
    {
      asString()+=rhs->toString();
      return;
    }break;
    case vtArray:
    {
      if(rhs->vt==vtInt)
      {
        VarVector& lv=asArray();
        lv.push_back(rhs->Clone(false));
        return;
      }else if(rhs->vt==vtString)
      {
        VarVector& lv=asArray();
        lv.push_back(rhs->Clone(false));
        return;
      }else
      if (rhs->vt==vtStringSlice)
      {
        StrSlice * ss=rhs->asStrSlice();
        VarVector& lv=asArray();
        StrVar* sv=memPool->allocVar<StrVar>();
        sv->val=ss->getString();
        lv.push_back(sv);
        return;
      }else
      if(rhs->vt==vtStringSegment)
      {
        StrSegment* ss=rhs->asStrSegment();
        VarVector& lv=asArray();
        StrVar* sv=memPool->allocVar<StrVar>();
        sv->val=ss->getString();
        lv.push_back(sv);
        return;
      }else
      if(rhs->vt==vtArray)
      {
        VarVector& lv=asArray();
        VarVector& rv=rhs->asArray();
        for(VarVector::iterator it=rv.begin(),end=rv.end();it!=end;it++)
        {
          lv.push_back((*it)->Clone(false));
        }
        return;
      }else if(rhs->vt==vtArraySegment)
      {
        VarVector& lv=asArray();
        ArrSegment* as=rhs->asArrSegment();
        for(size_t i=as->from;i<as->to;i++)
        {
          lv.push_back(as->var->asArray()[i]->Clone(false));
        }
        return;
      }else if(rhs->vt==vtArraySlice)
      {
        VarVector& lv=asArray();
        ArrSlice* as=rhs->asArrSlice();
        for(size_t i=0;i<as->indecies.size();i++)
        {
          lv.push_back(as->var->asArray()[as->indecies[i]]->Clone(false));
        }
        return;
      }else
      {
        VarVector& lv=asArray();
        if(rhs->isTemp)
        {
          lv.push_back(rhs);
        }else
        {
          lv.push_back(rhs->Clone());
        }
        return;
      }
    }break;
    case vtStruct:
    {
      if(rhs->vt==vtStruct)
      {
        Namespace& lns=asStruct();
        Namespace& rns=rhs->asStruct();
        for(Namespace::VarMap::iterator it=lns.entries.begin(),end=lns.entries.end();it!=end;it++)
        {
          if(rns.exists(it->first))
          {
            it->second->Add(rns[it->first]);
          }
        }
        return;
      }else if(rhs->vt==vtStructSlice)
      {
        Namespace& lns=asStruct();
        StructSlice* ss=rhs->asStructSlice();
        Namespace& rns=ss->var->asStruct();
        for(size_t i=0;i<ss->fields.size();i++)
        {
          if(lns.exists(ss->fields[i]))
          {
            lns[ss->fields[i]]->Add(rns[ss->fields[i]]);
          }
        }
        return;
      }
    }break;
    case vtStructSlice:
    {
      if(rhs->vt==vtStruct)
      {
        StructSlice* ss=asStructSlice();
        Namespace& lns=ss->var->asStruct();
        Namespace& rns=rhs->asStruct();
        for(size_t i=0;i<ss->fields.size();i++)
        {
          if(rns.exists(ss->fields[i]))
          {
            lns[ss->fields[i]]->Add(rns[ss->fields[i]]);
          }
        }
        return;
      }else if(rhs->vt==vtStructSlice)
      {
        StructSlice* lss=asStructSlice();
        Namespace& lns=lss->var->asStruct();
        StructSlice* rss=rhs->asStructSlice();
        Namespace& rns=rss->var->asStruct();
        for(size_t i=0;i<lss->fields.size();i++)
        {
          if(std::find(rss->fields.begin(),rss->fields.end(),lss->fields[i])!=rss->fields.end())
          {
            lns[lss->fields[i]]->Add(rns[lss->fields[i]]);
          }
        }
        return;
      }
    }break;
    case vtArraySegment:
    {
    }break;
    case vtArraySlice:
    {
    }break;
    case vtStringSegment:
    {
    }break;
    case vtStringSlice:
    {
    }break;
    case vtFuncRef:break;
    case vtMethodRef:break;
    case vtRefVar:break;
    case vtAlias:break;
    case vtCount:break;
  }
  error("operation + can't be applied to types %s and %s",getTypeName(),rhs->getTypeName());
}

void Var::Sub(VarRef rhs)
{
  rhs.Dealias();
  switch(vt)
  {
    case vtInt:
    {
      asInt()-=rhs->toInt();
      return;
    }break;
    case vtStringSegment:
    {
      StrSegment* ss=asStrSegment();
      int val=rhs->toInt();
      if(val>(int)ss->from)
      {
        ss->from=0;
      }else
      {
        ss->from-=val;
      }
      return;
    }break;
    case vtStringSlice:
    {
      StrSlice* ss=asStrSlice();
      int cnt=rhs->toInt();
      if(cnt>0)
      {
        if(cnt>(int)ss->indecies.size())
        {
          cnt=ss->indecies.size();
        }
        ss->indecies.erase(ss->indecies.begin()+ss->indecies.size()-cnt,ss->indecies.end());
      }
      return;
    }break;
    case vtArraySegment:
    {
      ArrSegment* as=asArrSegment();
      int val=rhs->toInt();
      if(val>(int)as->from)
      {
        as->from=0;
      }else
      {
        as->from-=val;
        if(as->from>as->to)
        {
          as->from=as->to;
        }
      }
      return;
    }break;
    case vtArraySlice:
    {
      ArrSlice* as=asArrSlice();
      int cnt=rhs->toInt();
      if(cnt>0)
      {
        if(cnt>(int)as->indecies.size())
        {
          cnt=as->indecies.size();
        }
        as->indecies.erase(as->indecies.begin()+as->indecies.size()-cnt,as->indecies.end());
      }
    }break;
    case vtStruct:
    {
      if(rhs->vt==vtStruct)
      {
        Namespace& lns=asStruct();
        Namespace& rns=rhs->asStruct();
        for(Namespace::VarMap::iterator it=lns.entries.begin(),end=lns.entries.end();it!=end;it++)
        {
          if(rns.exists(it->first))
          {
            it->second->Sub(rns[it->first]);
          }
        }
        return;
      }else if(rhs->vt==vtStructSlice)
      {
        Namespace& lns=asStruct();
        StructSlice* ss=rhs->asStructSlice();
        Namespace& rns=ss->var->asStruct();
        for(size_t i=0;i<ss->fields.size();i++)
        {
          if(lns.exists(ss->fields[i]))
          {
            lns[ss->fields[i]]->Sub(rns[ss->fields[i]]);
          }
        }
        return;
      }
    }break;
    case vtStructSlice:
    {
      if(rhs->vt==vtStruct)
      {
        StructSlice* ss=asStructSlice();
        Namespace& lns=ss->var->asStruct();
        Namespace& rns=rhs->asStruct();
        for(size_t i=0;i<ss->fields.size();i++)
        {
          if(rns.exists(ss->fields[i]))
          {
            lns[ss->fields[i]]->Sub(rns[ss->fields[i]]);
          }
        }
        return;
      }else if(rhs->vt==vtStructSlice)
      {
        StructSlice* lss=asStructSlice();
        Namespace& lns=lss->var->asStruct();
        StructSlice* rss=rhs->asStructSlice();
        Namespace& rns=rss->var->asStruct();
        for(size_t i=0;i<lss->fields.size();i++)
        {
          if(std::find(rss->fields.begin(),rss->fields.end(),lss->fields[i])!=rss->fields.end())
          {
            lns[lss->fields[i]]->Sub(rns[lss->fields[i]]);
          }
        }
        return;
      }
    }break;
    default:break;
  }
  error("operation - can't be applied to types %s and %s",getTypeName(),rhs->getTypeName());
}

void Var::Mul(VarRef rhs)
{
  rhs.Dealias();
  switch(vt)
  {
    case vtInt:
    {
      asInt()*=rhs->toInt();
      return;
    }break;
    case vtString:
    {
      if(!isTemp)
      {
        error("attempt to apply * to non-temp string");
      }
      std::string val=asString();
      int count=rhs->toInt();
      for(int i=0;i<count-1;i++)
      {
        asString()+=val;
      }
      return;
    }
    case vtArray:
    {
      if(!isTemp)
      {
        error("attempt to apply * to non-temp array");
      }
      VarVector val=asArray();
      int count=rhs->toInt();
      for(int i=0;i<count-1;i++)
      {
        asArray().insert(asArray().end(),val.begin(),val.end());
      }
      return;
    }break;
    case vtStruct:
    {
      if(rhs->vt==vtStruct)
      {
        Namespace& lns=asStruct();
        Namespace& rns=rhs->asStruct();
        for(Namespace::VarMap::iterator it=lns.entries.begin(),end=lns.entries.end();it!=end;it++)
        {
          if(rns.exists(it->first))
          {
            it->second->Mul(rns[it->first]);
          }
        }
        return;
      }else if(rhs->vt==vtStructSlice)
      {
        Namespace& lns=asStruct();
        StructSlice* ss=rhs->asStructSlice();
        Namespace& rns=ss->var->asStruct();
        for(size_t i=0;i<ss->fields.size();i++)
        {
          if(lns.exists(ss->fields[i]))
          {
            lns[ss->fields[i]]->Mul(rns[ss->fields[i]]);
          }
        }
        return;
      }
    }break;
    case vtStructSlice:
    {
      if(rhs->vt==vtStruct)
      {
        StructSlice* ss=asStructSlice();
        Namespace& lns=ss->var->asStruct();
        Namespace& rns=rhs->asStruct();
        for(size_t i=0;i<ss->fields.size();i++)
        {
          if(rns.exists(ss->fields[i]))
          {
            lns[ss->fields[i]]->Mul(rns[ss->fields[i]]);
          }
        }
        return;
      }else if(rhs->vt==vtStructSlice)
      {
        StructSlice* lss=asStructSlice();
        Namespace& lns=lss->var->asStruct();
        StructSlice* rss=rhs->asStructSlice();
        Namespace& rns=rss->var->asStruct();
        for(size_t i=0;i<lss->fields.size();i++)
        {
          if(std::find(rss->fields.begin(),rss->fields.end(),lss->fields[i])!=rss->fields.end())
          {
            lns[lss->fields[i]]->Mul(rns[lss->fields[i]]);
          }
        }
        return;
      }
    }break;
    default:break;
  }
  error("operation * can't be applied to types %s and %s",getTypeName(),rhs->getTypeName());
}

void Var::Div(VarRef rhs)
{
  rhs.Dealias();
  switch(vt)
  {
    case vtInt:
    {
      int rv=rhs->toInt();
      if(rv==0)
      {
        error("division by zero");
      }
      asInt()/=rv;
      return;
    }break;
    case vtStringSegment:
    {
      StrSegment* ss=asStrSegment();
      int val=rhs->toInt();
      size_t l=ss->var->asString().length();
      if(ss->to+val>l)
      {
        ss->to=l;
      }else
      {
        if(val<0 && -val>(int)ss->to-(int)ss->from)
        {
          ss->to=ss->from;
        }else
        {
          ss->to+=val;
        }
      }
      return;
    }break;
    case vtArraySegment:
    {
      ArrSegment* as=asArrSegment();
      int val=rhs->toInt();
      size_t l=as->var->asArray().size();
      if(as->to+val>l)
      {
        as->to=l;
      }else
      {
        if(val<0 && -val>(int)as->to-(int)as->from)
        {
          as->to=as->from;
        }else
        {
          as->to+=val;
        }
      }
      return;
    }break;
    case vtStruct:
    {
      if(rhs->vt==vtStruct)
      {
        Namespace& lns=asStruct();
        Namespace& rns=rhs->asStruct();
        for(Namespace::VarMap::iterator it=lns.entries.begin(),end=lns.entries.end();it!=end;it++)
        {
          if(rns.exists(it->first))
          {
            it->second->Div(rns[it->first]);
          }
        }
        return;
      }else if(rhs->vt==vtStructSlice)
      {
        Namespace& lns=asStruct();
        StructSlice* ss=rhs->asStructSlice();
        Namespace& rns=ss->var->asStruct();
        for(size_t i=0;i<ss->fields.size();i++)
        {
          if(lns.exists(ss->fields[i]))
          {
            lns[ss->fields[i]]->Div(rns[ss->fields[i]]);
          }
        }
        return;
      }
    }break;
    case vtStructSlice:
    {
      if(rhs->vt==vtStruct)
      {
        StructSlice* ss=asStructSlice();
        Namespace& lns=ss->var->asStruct();
        Namespace& rns=rhs->asStruct();
        for(size_t i=0;i<ss->fields.size();i++)
        {
          if(rns.exists(ss->fields[i]))
          {
            lns[ss->fields[i]]->Div(rns[ss->fields[i]]);
          }
        }
        return;
      }else if(rhs->vt==vtStructSlice)
      {
        StructSlice* lss=asStructSlice();
        Namespace& lns=lss->var->asStruct();
        StructSlice* rss=rhs->asStructSlice();
        Namespace& rns=rss->var->asStruct();
        for(size_t i=0;i<lss->fields.size();i++)
        {
          if(std::find(rss->fields.begin(),rss->fields.end(),lss->fields[i])!=rss->fields.end())
          {
            lns[lss->fields[i]]->Div(rns[lss->fields[i]]);
          }
        }
        return;
      }
    }break;
    default:break;
  }
  error("operation / can't be applied to types %s and %s",getTypeName(),rhs->getTypeName());
}

void Var::Mod(VarRef rhs)
{
  rhs.Dealias();
  switch(vt)
  {
    case vtInt:
    {
      int rv=rhs->toInt();
      if(rv==0)
      {
        error("division by zero");
      }
      asInt()%=rv;
      return;
    }break;
    case vtStruct:
    {
      if(rhs->vt==vtStruct)
      {
        Namespace& lns=asStruct();
        Namespace& rns=rhs->asStruct();
        for(Namespace::VarMap::iterator it=lns.entries.begin(),end=lns.entries.end();it!=end;it++)
        {
          if(rns.exists(it->first))
          {
            it->second->Mod(rns[it->first]);
          }
        }
        return;
      }else if(rhs->vt==vtStructSlice)
      {
        Namespace& lns=asStruct();
        StructSlice* ss=rhs->asStructSlice();
        Namespace& rns=ss->var->asStruct();
        for(size_t i=0;i<ss->fields.size();i++)
        {
          if(lns.exists(ss->fields[i]))
          {
            lns[ss->fields[i]]->Mod(rns[ss->fields[i]]);
          }
        }
        return;
      }
    }break;
    case vtStructSlice:
    {
      if(rhs->vt==vtStruct)
      {
        StructSlice* ss=asStructSlice();
        Namespace& lns=ss->var->asStruct();
        Namespace& rns=rhs->asStruct();
        for(size_t i=0;i<ss->fields.size();i++)
        {
          if(rns.exists(ss->fields[i]))
          {
            lns[ss->fields[i]]->Mod(rns[ss->fields[i]]);
          }
        }
        return;
      }else if(rhs->vt==vtStructSlice)
      {
        StructSlice* lss=asStructSlice();
        Namespace& lns=lss->var->asStruct();
        StructSlice* rss=rhs->asStructSlice();
        Namespace& rns=rss->var->asStruct();
        for(size_t i=0;i<lss->fields.size();i++)
        {
          if(std::find(rss->fields.begin(),rss->fields.end(),lss->fields[i])!=rss->fields.end())
          {
            lns[lss->fields[i]]->Mod(rns[lss->fields[i]]);
          }
        }
        return;
      }
    }break;
    default:break;
  }
  error("operation % can't be applied to types %s and %s",getTypeName(),rhs->getTypeName());
}

bool Var::canAssign(VarRef rhs)
{
  if(vt!=vtRefVar)
  {
    rhs.Dealias();
  }
  switch(vt)
  {
    case vtInt:
    case vtString:
    case vtStringSegment:
    case vtStringSlice:
    {
      switch(rhs->vt)
      {
        case vtInt:
        case vtString:
        case vtStringSegment:
        case vtStringSlice:
          return true;
        default:break;
      }
      return false;
    }break;
    case vtArray:
    {
      switch(rhs->vt)
      {
        case vtArray:
        case vtArraySlice:
        case vtArraySegment:
          return true;
        default:break;
      }
      return false;
    }break;
    case vtStructSlice:
    {
      switch(rhs->vt)
      {
        case vtInt:
        case vtString:
        case vtStringSlice:
        case vtStringSegment:
        case vtStruct:
        case vtArray:
        case vtArraySlice:
        case vtArraySegment:
        case vtStructSlice:
          return true;
        default:break;
      }
      return false;
    }break;
    case vtStruct:
    {
      switch(rhs->vt)
      {
        case vtStruct:
        case vtArray:
        case vtArraySlice:
        case vtArraySegment:
        case vtStructSlice:
          return true;
        default:break;
      }
      return false;
    }break;
    case vtArraySlice:
    case vtArraySegment:
    {
      switch(rhs->vt)
      {
        case vtArray:
        case vtArraySegment:
        case vtArraySlice:
          return true;
        default:break;
      }
      return false;
    }break;
    case vtRefVar:
      return true;
    case vtFuncRef:
    {
      return rhs->vt==vtFuncRef;
    }break;
    case vtMethodRef:
    {
      return rhs->vt==vtMethodRef;
    }break;
    default:return false;
  }
}


void Var::Assign(VarRef rhs)
{
  if(vt!=vtRefVar)
  {
    rhs.Dealias();
  }
  switch(vt)
  {
    case vtInt:
      asInt()=rhs->toInt();
      break;
    case vtString:
      asString()=rhs->toString();
      break;
    case vtArray:
    {
      VarVector& v=asArray();
      v.clear();
      VarVector::iterator it,end;
      VarVector tmp;
      if(rhs->vt==vtArray)
      {
        it=rhs->asArray().begin();
        end=rhs->asArray().end();
      }else
      {
        tmp=toArray();
        it=tmp.begin();
        end=tmp.end();
      }
      for(;it!=end;it++)
      {
        v.push_back((*it)->Clone(false));
      }
    }break;
    case vtStruct:
    {
      if(rhs->vt==vtStruct)
      {
        //asStruct().entries=rhs->asStruct().entries;
        Namespace& lns=asStruct();
        Namespace& rns=rhs->asStruct();
        lns.entries.clear();
        for(Namespace::VarMap::iterator it=rns.entries.begin(),end=rns.entries.end();it!=end;it++)
        {
          lns.add(it->first,it->second->Clone(false));
        }

      }else if(rhs->vt==vtStructSlice)
      {
        Namespace& ns=asStruct();
        StructSlice* ss=rhs->asStructSlice();
        Namespace& rns=ss->var->asStruct();
        for(size_t i=0;i<ss->fields.size();i++)
        {
          ns[ss->fields[i]]=rns[ss->fields[i]]->Clone(false);
        }
      }else
      {
        VarVector v=rhs->toArray();
        Namespace& ns=asStruct();
        Namespace::VarMap::iterator it=ns.entries.begin();
        size_t mn=ns.entries.size()<v.size()?ns.entries.size():v.size();
        for(size_t i=0;i<mn;i++)
        {
          it->second=v[i]->Clone(false);
          it++;
        }
      }
    }break;
    case vtRefVar:
    {
      Var** varPtr=asRefVar();
      VarRef old(*varPtr);
      VarRef rv=rhs->Clone(false);
      *varPtr=rv.var;
      if(old.var)old.var->refCount--;
      (*varPtr)->refCount++;
    }break;
    case vtArraySegment:
    {
      ArrSegment* as=asArrSegment();
      VarVector& lv=as->var->asArray();
      VarVector::iterator from=lv.begin()+as->from;
      VarVector::iterator to=lv.begin()+as->to;
      lv.erase(from,to);
      if(rhs->vt==vtArray)
      {
        VarVector& rv=rhs->asArray();
        for(VarVector::reverse_iterator it=rv.rbegin(),end=rv.rend();it!=end;it++)
        {
          lv.insert(from,(*it)->Clone(false));
        }
      }else
      {
        VarVector rv=rhs->toArray();
        for(VarVector::reverse_iterator it=rv.rbegin(),end=rv.rend();it!=end;it++)
        {
          lv.insert(from,(*it)->Clone(false));
        }
      }
    }break;
    case vtArraySlice:
    {
      ArrSlice* as=asArrSlice();
      VarVector& lv=as->var->asArray();
      if(rhs->vt==vtArray)
      {
        VarVector& rv=rhs->asArray();
        size_t mn=as->indecies.size()<rv.size()?as->indecies.size():rv.size();
        for(size_t i=0;i<mn;i++)
        {
          size_t idx=as->indecies[i];
          if(idx>=0 && idx<lv.size())
          {
            if(lv[idx]->canAssign(rv[i]))
            {
              lv[idx]->Assign(rv[i]);
            }else
            {
              lv[idx]=rv[i]->Clone(false);
            }
          }
        }
      }else
      {
        VarVector rv=rhs->toArray();
        size_t mn=as->indecies.size()<rv.size()?as->indecies.size():rv.size();
        for(size_t i=0;i<mn;i++)
        {
          size_t idx=as->indecies[i];
          if(idx>=0 && idx<lv.size())
          {
            if(lv[idx]->canAssign(rv[i]))
            {
              lv[idx]->Assign(rv[i]);
            }else
            {
              lv[idx]=rv[i]->Clone(false);
            }
          }
        }
      }
    }break;
    case vtStringSegment:
    {
      StrSegment* ss=asStrSegment();
      std::string& str=ss->var->asString();
      const std::string& rv=rhs->vt==vtString?rhs->asString():rhs->toString();
      size_t from=ss->from;
      size_t len=ss->to-ss->from;
      str.erase(from,len);
      str.insert(from,rv);
    }break;
    case vtStringSlice:
    {
      StrSlice* ss=asStrSlice();
      std::string& str=ss->var->asString();
      const std::string& rv=rhs->vt==vtString?rhs->asString():rhs->toString();
      size_t mn=rv.length()<ss->indecies.size()?rv.length():ss->indecies.size();
      for(size_t i=0;i<mn;i++)
      {
        size_t idx=ss->indecies[i];
        if(idx>=0 && idx<str.length())
        {
          str[idx]=rv[i];
        }
      }
    }break;
    case vtStructSlice:
    {
      StructSlice* ss=asStructSlice();
      Namespace& ns=ss->var->asStruct();
      if(rhs->vt==vtInt || rhs->vt==vtString)
      {
        for(size_t i=0;i<ss->fields.size();i++)
        {
          ns[ss->fields[i]]=rhs->Clone(false);
        }
      }else if(rhs->vt==vtStringSlice || rhs->vt==vtStringSegment)
      {
        for(size_t i=0;i<ss->fields.size();i++)
        {
          StrVar* sv=memPool->allocVar<StrVar>();
          sv->val=rhs->toString();
          ns[ss->fields[0]]=sv;
        }
      }
      else if(rhs->vt==vtStruct)
      {
        Namespace& rns=rhs->asStruct();
        for(size_t i=0;i<ss->fields.size();i++)
        {
          uchar f=ss->fields[i];
          if(rns.exists(f))
          {
            if(ns.exists(f))
            {
              if(ns[f]->canAssign(rns[f]))
              {
                ns[f]->Assign(rns[f]);
              }else
              {
                ns[f]=rns[f]->Clone(false);
              }
            }else
            {
              ns.add(f,rns[f]->Clone(false));
            }
          }
        }
      }else if(rhs->vt==vtStructSlice)
      {
        StructSlice* rss=rhs->asStructSlice();
        Namespace& rns=rss->var->asStruct();
        for(size_t i=0;i<ss->fields.size();i++)
        {
          uchar f=ss->fields[i];

          if(std::find(rss->fields.begin(),rss->fields.end(),f)!=rss->fields.end() && rns.exists(f))
          {
            if(ns.exists(f))
            {
              VarRef& r=ns[f];
              if(r->canAssign(rns[f]))
              {
                r->Assign(rns[f]);
              }else
              {
                r=rns[f]->Clone(false);
              }
            }else
            {
              ns.add(f,rns[f]->Clone(false));
            }
          }
        }
      }else if(rhs->vt==vtArray)
      {
        VarVector& v=rhs->asArray();
        size_t mn=v.size()<ss->fields.size()?v.size():ss->fields.size();
        for(size_t i=0;i<mn;i++)
        {
          uchar f=ss->fields[i];
          if(ns.exists(f))
          {
            VarRef& r=ns[f];
            if(r->canAssign(v[i]))
            {
              r->Assign(v[i]);
            }else
            {
              r=v[i]->Clone(false);
            }
          }else
          {
            ns.add(f,v[i]->Clone(false));
          }
        }
      }else
      {
        VarVector v=rhs->toArray();
        size_t mn=v.size()<ss->fields.size()?v.size():ss->fields.size();
        for(size_t i=0;i<mn;i++)
        {
          uchar f=ss->fields[i];
          if(ns.exists(f))
          {
            VarRef& r=ns[f];
            if(r->canAssign(v[i]))
            {
              r->Assign(v[i]);
            }else
            {
              r=v[i]->Clone(false);
            }
          }else
          {
            ns.add(f,v[i]->Clone(false));
          }
        }
      }
    }break;
    case vtFuncRef:
      *asFuncRef()=*rhs->asFuncRef();
      break;
    case vtMethodRef:
      *asMethodRef()=*rhs->asMethodRef();
      break;
    case vtAlias:
    {
      asAlias()->ex=rhs->asAlias()->ex;
    }break;
    case vtCount:error("assignment failed");break;
  }
}


std::string Var::toString()
{
  switch(vt)
  {
    case vtInt:
    {
      char buf[32];
      sprintf(buf,"%d",asInt());
      return buf;
    }break;
    case vtString:
    {
      return asString();
    }break;
    case vtArray:
    {
      std::string rv;
      VarVector& v=asArray();
      bool first=true;
      for(VarVector::iterator it=v.begin(),end=v.end();it!=end;it++)
      {
        if(first)
        {
          first=false;
        }else
        {
          rv+=' ';
        }
        rv+=(*it)->toString();
      }
      return rv;
    }break;
    case vtStruct:
    {
      std::string rv;
      Namespace& v=asStruct();
      bool first=true;
      for(Namespace::VarMap::iterator it=v.entries.begin(),end=v.entries.end();it!=end;it++)
      {
        if(first)
        {
          first=false;
        }else
        {
          rv+=' ';
        }
        rv+=(char)it->first;
        rv+=':';
        rv+=it->second->toString();
      }
      return rv;
    }break;
    case vtArraySegment:
    {
      std::string rv;
      ArrSegment* as=asArrSegment();
      VarVector& v=as->var->asArray();
      bool first=true;
      for(size_t i=as->from;i<as->to;i++)
      {
        if(first)
        {
          first=false;
        }else
        {
          rv+=' ';
        }
        rv+=v[i]->toString();
      }
      return rv;
    }break;
    case vtArraySlice:
    {
      std::string rv;
      ArrSlice* as=asArrSlice();
      VarVector& v=as->var->asArray();
      bool first=true;
      for(size_t i=0;i<as->indecies.size();i++)
      {
        if(first)
        {
          first=false;
        }else
        {
          rv+=' ';
        }
        rv+=v[as->indecies[i]]->toString();
      }
      return rv;
    }break;
    case vtStringSegment:
    {
      StrSegment* ss=asStrSegment();
      std::string& s=ss->var->asString();
      return s.substr(ss->from,ss->to-ss->from);
    }break;
    case vtStringSlice:
    {
      std::string rv;
      StrSlice* ss=asStrSlice();
      std::string& s=ss->var->asString();
      for(size_t i=0;i<ss->indecies.size();i++)
      {
        rv+=s[ss->indecies[i]];
      }
      return rv;
    }break;
    case vtStructSlice:
    {
      std::string rv;
      StructSlice* ss=asStructSlice();
      Namespace& v=ss->var->asStruct();
      bool first=true;
      for(size_t i=0;i<ss->fields.size();i++)
      {
        if(first)
        {
          first=false;
        }else
        {
          rv+=' ';
        }
        rv+=(char)ss->fields[i];
        rv+=':';
        rv+=v[ss->fields[i]]->toString();
      }
      return rv;
    }break;
    case vtRefVar:
    {
      if(*asRefVar())
      {
        return (*asRefVar())->toString();
      }else
      {
        error("null variable access");
        return "";
      }
    }break;
    case vtAlias:
    {
      return asAlias()->ex->Evaluate()->toString();
    }break;
    case vtFuncRef:
      return "";
    case vtMethodRef:
      return "";
    default:
      return "";
  }
}

int Var::toInt()
{
  switch(vt)
  {
    case vtInt:
      return asInt();
    case vtString:
      return atoi(asString().c_str());
    case vtStringSegment:
      return atoi(asStrSegment()->getString().c_str());
    case vtStringSlice:
      return atoi(asStrSlice()->getString().c_str());
    case vtAlias:
      return asAlias()->ex->Evaluate()->toInt();
    case vtRefVar:
      if(*asRefVar())
      {
        return (*asRefVar())->toInt();
      }else
      {
        error("null variable access");
      }
    default:break;
  }
  error("%s cannot be cast to int",getTypeName());
  return 0;
}

VarVector Var::toArray()
{
  switch(vt)
  {
    case vtArray:return asArray();
    case vtArraySegment:
    {
      ArrSegment* as=asArrSegment();
      VarVector& arr=as->var->asArray();
      VarVector::iterator fromIt=arr.begin()+as->from;
      VarVector::iterator toIt=arr.begin()+as->to;
      VarVector rv;
      for(;fromIt!=toIt;fromIt++)
      {
        rv.push_back((*fromIt)->Clone());
      }
      return rv;
    }break;
    case vtArraySlice:
    {
      ArrSlice* as=asArrSlice();
      VarVector& arr=as->var->asArray();
      VarVector rv;
      for(SizeVector::iterator it=as->indecies.begin(),end=as->indecies.end();it!=end;it++)
      {
        if(*it>0 && *it<arr.size())
        {
          rv.push_back(arr[*it]->Clone());
        }
      }
      return rv;
    }break;
    case vtStruct:
    {
      Namespace& ns=asStruct();
      VarVector rv;
      for(Namespace::VarMap::iterator it=ns.entries.begin(),end=ns.entries.end();it!=end;it++)
      {
        rv.push_back(it->second->Clone());
      }
      return rv;
    }break;
    case vtStructSlice:
    {
      StructSlice* ss=asStructSlice();
      VarVector rv;
      Namespace& ns=ss->var->asStruct();
      for(size_t i=0;i>ss->fields.size();i++)
      {
        if(ns.exists(ss->fields[i]))
        {
          rv.push_back(ns[ss->fields[i]]->Clone());
        }
      }
      return rv;
    }break;
    case vtRefVar:
    {
      if(asRefVar())
      {
        return (*asRefVar())->toArray();
      }else
      {
        error("null variable access");
      }
    }
    case vtAlias:
    {
      return asAlias()->ex->Evaluate()->toArray();
    }
    default:break;
  }
  error("Type %s cannot be cast to array",getTypeName());
  return VarVector();
}


struct SourceReader{

  SourceReader(const std::string& argFileName,const std::string& argSource):fileName(argFileName),source(argSource)
  {
    pos=0;
    line=1;
    col=1;
  }

  Char getNext()
  {
    Char rv;
    rv.line=line;
    rv.col=col;
    rv.c=0;
    if(pos>=source.length())
    {
      throw ParsingException(rv,"Unexpected end of file");
    }
    rv.c=source[pos++];
    col++;
    if(rv.c==0x0d || rv.c==0x0a)
    {
      if(rv.c==0x0d && pos<source.length())
      {
        rv.c=source[pos++];
        if(rv.c!=0x0a)
        {
          pos--;
        }
      }
      rv.c=' ';
      line++;
      col=1;
    }
    return rv;
  }

  void skipLine()
  {
    while(pos<source.length() && source[pos]!=0x0d && source[pos]!=0x0a)
    {
      pos++;
    }
    if(pos<source.length()-1 && source[pos]==0x0d && source[pos+1]==0x0a)
    {
      pos++;
    }
    if(pos<source.length() && source[pos]==0x0a)
    {
      pos++;
      line++;
      col=1;
    }
  }

  uchar peekNext()
  {
    if(pos>=source.length())
    {
      return 0;
    }
    char rv=source[pos];
    if(rv==0x0d || rv==0x0a)
    {
      rv=' ';
    }
    return rv;
  }

  void unget()
  {
    pos--;col--;
    if(col==0)
    {
      line--;
    }
  }

  bool isEof()const
  {
    return pos==source.length();
  }

  const std::string& fileName;
  const std::string& source;
  size_t pos;
  size_t line,col;
protected:
  void operator=(const SourceReader& rhs);
};


struct VM;

struct OpCodeBase;
typedef std::vector<OpCodeBase*> CodeVector;


struct OpCodeBase{
  OpCodeBase(VM* argVM):vm(argVM){}
  virtual ~OpCodeBase(){};
  virtual size_t Execute()=0;
  virtual void dump(std::string& s)=0;

  void dumpIdx(std::string& s)
  {
    char buf[32];
    sprintf(buf,"%lu:",idx);
    s+=buf;
  }

  VM* vm;
  size_t idx;
  Pos pos;
};


struct Func{
  Func():method(false)
  {
  }
  VarRef localVars;
  VarRef result;
  VarRef self;
  size_t retPoint;
  uchar name;
  bool method;
};

static const size_t INVALID_CP_VALUE=(size_t)-1;

struct VM:VarPool{
  VM()
  {
    memset(funcs,0,sizeof(funcs));
    memset(methods,0,sizeof(methods));

    lastColor=7;

    callStack.reserve(32);
  }

  ~VM()
  {
    for(CodeVector::iterator it=code.begin(),end=code.end();it!=end;it++)
    {
      delete *it;
    }
    for(size_t i=0;i<256;i++)vars[i]=VarRef();
    lastExpr=VarRef();
  }

  void Run()
  {
    cp=entryPoint;
    RunLoop();
  }

  void RunLoop()
  {
    try{
      while((cp=code[cp]->Execute())!=INVALID_CP_VALUE);
      /*
      size_t oldCp=cp;
      while(cp!=INVALID_CP_VALUE)
      {
        oldCp=cp;
        cp=code[cp]->Execute();
      }
      if(callStack.empty())
      {
        //printf("oldcp=%lu\n",oldCp);
      }*/
    }catch(RuntimeError& e)
    {
      throw RuntimeException(code[cp]->pos,"%s",e.what());
    }
  }

  void setVar(uchar name,VarRef var)
  {
    if(!callStack.empty() && callStack.back()->localVars->asStruct().exists(name))
    {
      callStack.back()->localVars->asStruct()[name]=var;
    }else
    {
      vars[name]=var;
    }
  }

  VarRef getVar(uchar name,bool writeMode=false)
  {
    if(!callStack.empty() && callStack.back()->localVars->asStruct().exists(name))
    {
      if(writeMode)
      {
        VarRef& var=callStack.back()->localVars->asStruct()[name];
        RefVar* rv=allocVar<RefVar>();
        rv->varPtr=&var.var;
        return rv;
      }
      return callStack.back()->localVars->asStruct()[name];
    }

    if(!vars[name].var || writeMode)
    {
      RefVar* rv=allocVar<RefVar>();
      rv->varPtr=&vars[name].var;
      return rv;
    }
    return vars[name];
  }

  std::vector<Func*> callStack;

  //std::vector<Var*> temporals;

  CodeVector code;
  VarRef vars[256];
  size_t funcs[256];
  size_t methods[256];
  size_t entryPoint;
  size_t cp;

  VarRef lastExpr;

  std::vector<int> storedColors;
  int lastColor;
  void setColor(int color)
  {
    color=color&0x0f;
    int bg=(lastColor&0xf0)>4;
    lastColor=(lastColor&0xf0)|color;
    int att=0;
    if(color>7)
    {
      att=A_BOLD;
      color=color&7;
    }
    bg=bg&7;
    int v=COLOR_PAIR(1+(color|(bg*8)));
    attrset(v|att);
  }
  void setBg(int bg)
  {
    int color=lastColor&0x0f;
    lastColor=(bg<<4)|color;
    int att=0;
    if(color>7)
    {
      att=A_BOLD;
      color=color&7;
    }
    bg=bg&7;
    int v=COLOR_PAIR(1+(color|(bg*8)));
    attrset(v|att);
  }
  void storeColor()
  {
    storedColors.push_back(lastColor);
  }
  void restoreColor()
  {
    if(!storedColors.empty())
    {
      int clr=storedColors.back();
      storedColors.pop_back();
      setColor(clr);
      setBg(clr>>4);
    }
  }

  void outLine(const std::string& line,bool nl)
  {
    bool colorOps=false;
    for(size_t i=0;i<line.length();i++)
    {
      if(line[i]==1 || line[i]==2 || line[i]==3)
      {
        colorOps=true;
        break;
      }
    }
    int storeColorCnt=0;
    if(useCurses)
    {
      if(colorOps)
      {
        std::string tmp;
        size_t lastPos=0;
        for(size_t i=0;i<line.size();i++)
        {
          if(line[i]<=3)
          {
            if(lastPos!=i)
            {
              printw("%s",line.substr(lastPos,i-lastPos).c_str());
            }
            int op=line[i];
            int clr=0;
            if(op==1 || op==2)
            {
              i++;
              clr=line[i];
            }
            if(op==1)
            {
              storeColor();
              setColor(clr);
              storeColorCnt++;
            }else if(op==2)
            {
              storeColor();
              setBg(clr);
              storeColorCnt++;
            }else
            {
              if(storeColorCnt>0)
              {
                restoreColor();
                storeColorCnt--;
              }
            }
            lastPos=i+1;
          }
        }
        printw("%s",line.c_str()+lastPos);
      }else
      {
        printw("%s",line.c_str());
      }
    }else
    {
      if(colorOps)
      {
        std::string tmp;
        for(size_t i=0;i<line.size();i++)
        {
          if(line[i]<=3)
          {
            i++;
          }else
          {
            tmp+=line[i];
          }
        }
        printf("%s",tmp.c_str());
      }else
      {
        printf("%s",line.c_str());
      }
    }

    if(nl)
    {
      if(useCurses)
      {
        printw("\n");
        refresh();
        doupdate();
      }else
      {
        printf("\n");
      }
    }
  }

  /*struct LoopData{
    size_t loopStart;
    size_t loopEnd;
  };

  std::vector<LoopData> loops;*/

  bool useCurses;
};


struct AddOpExpr:Expression{
  AddOpExpr(VM* argVM):Expression(argVM){}
  VarRef Evaluate(bool writeMode=false)
  {
    VarRef lv=left->Evaluate().Dealias();
    VarRef rv=right->Evaluate();
    if(!lv->isTemp)
    {
      VarRef tmp=lv->Clone();
      tmp->Add(rv);
      return tmp;
    }
    lv->Add(rv);
    return lv;
  }

  void dump(std::string& s)
  {
    s+="(";
    left->dump(s);
    s+="+";
    right->dump(s);
    s+=")";
  }


  std::auto_ptr<Expression> left;
  std::auto_ptr<Expression> right;
};

struct SubOpExpr:Expression{
  SubOpExpr(VM* argVM):Expression(argVM){}
  VarRef Evaluate(bool writeMode=false)
  {
    VarRef lv=left->Evaluate().Dealias();
    VarRef rv=right->Evaluate();

    if(lv->vt==vtString)
    {
      StrSegment *ss=vm->allocVar<StrSegment>();
      VarRef ret=ss;
      ss->var=lv;
      size_t l=lv->asString().length();
      if(l>0)
      {
        int val=rv->toInt();
        if(val>0)
        {
          ss->from=(int)l>val?l-val:0;
          ss->to=l;
        }else
        {
          val=-val;
          ss->from=val>(int)l?l:val;
          ss->to=l;
        }
      }else
      {
        ss->from=0;
        ss->to=0;
      }
      return ret;
    }else if(lv->vt==vtArray)
    {
      ArrSegment *as=vm->allocVar<ArrSegment>();
      VarRef ret=as;
      as->var=lv;
      size_t l=lv->asArray().size();
      if(l>0)
      {
        int val=rv->toInt();
        if(val>0)
        {
          as->from=(int)l>val?l-val:0;
          as->to=l;
        }else
        {
          val=-val;
          as->from=val>(int)l?l:val;
          as->to=l;
        }
      }else
      {
        as->from=0;
        as->to=0;
      }
      return ret;
    }

    if(!lv->isTemp)
    {
      VarRef tmp=lv->Clone();
      tmp->Sub(rv);
      return tmp;
    }
    lv->Sub(rv);
    return lv;
  }
  void dump(std::string& s)
  {
    s+="(";
    left->dump(s);
    s+="-";
    right->dump(s);
    s+=")";
  }
  std::auto_ptr<Expression> left;
  std::auto_ptr<Expression> right;
};


struct MulOpExpr:Expression{
  MulOpExpr(VM* argVM):Expression(argVM){}
  VarRef Evaluate(bool writeMode=false)
  {
    VarRef lv=left->Evaluate().Dealias();
    VarRef rv=right->Evaluate();
    if(!lv->isTemp)
    {
      VarRef tmp=lv->Clone();
      tmp->Mul(rv);
      return tmp;
    }
    lv->Mul(rv);
    return lv;
  }
  void dump(std::string& s)
  {
    s+="(";
    left->dump(s);
    s+="*";
    right->dump(s);
    s+=")";
  }
  std::auto_ptr<Expression> left;
  std::auto_ptr<Expression> right;
};

struct DivOpExpr:Expression{
  DivOpExpr(VM* argVM):Expression(argVM){}
  VarRef Evaluate(bool writeMode=false)
  {
    VarRef lv=left->Evaluate().Dealias();
    VarRef rv=right->Evaluate();
    if(lv->vt==vtString)
    {
      StrSegment *ss=vm->allocVar<StrSegment>();
      VarRef ret=ss;
      ss->var=lv;
      size_t l=ss->var->asString().length();
      if(l>0)
      {
        int val=rv->toInt();
        if(val>0)
        {
          ss->from=0;
          ss->to=val>(int)l?l:val;
        }else
        {
          val=-val;
          ss->from=val>(int)l?0:l-val;
          ss->to=l;
        }
      }else
      {
        ss->from=0;
        ss->to=0;
      }
      return ret;
    }else if(lv->vt==vtArray)
    {
      ArrSegment *as=vm->allocVar<ArrSegment>();
      VarRef ret=as;
      as->var=lv;
      size_t l=lv->asArray().size();
      if(l>0)
      {
        int val=rv->toInt();
        if(val>0)
        {
          as->from=0;
          as->to=val>(int)l?l:val;
        }else
        {
          val=-val;
          as->from=val>(int)l?0:l-val;
          as->to=l;
        }
      }else
      {
        as->from=0;
        as->to=0;
      }
      return ret;
    }
    if(!lv->isTemp)
    {
      VarRef tmp=lv->Clone();
      tmp->Div(rv);
      return tmp;
    }
    lv->Div(rv);
    return lv;
  }
  void dump(std::string& s)
  {
    s+="(";
    left->dump(s);
    s+="/";
    right->dump(s);
    s+=")";
  }
  std::auto_ptr<Expression> left;
  std::auto_ptr<Expression> right;
};


struct ModOpExpr:Expression{
  ModOpExpr(VM* argVM):Expression(argVM){}
  VarRef Evaluate(bool writeMode=false)
  {
    VarRef lv=left->Evaluate().Dealias();
    VarRef rv=right->Evaluate();
    if((lv->vt==vtString || lv->vt==vtArray) && rv->vt==vtArray)
    {
      if(lv->vt==vtString)
      {
        StrSlice* ss=vm->allocVar<StrSlice>();
        VarRef ret=ss;
        ss->var=lv;
        VarVector& v=rv->asArray();
        for(VarVector::iterator it=v.begin(),end=v.end();it!=end;it++)
        {
          ss->indecies.push_back((*it)->toInt());
        }
        return ret;
      }else
      {
        ArrSlice* as=vm->allocVar<ArrSlice>();
        VarRef ret=as;
        as->var=lv;
        VarVector& v=rv->asArray();
        for(VarVector::iterator it=v.begin(),end=v.end();it!=end;it++)
        {
          as->indecies.push_back((*it)->toInt());
        }
        return ret;
      }
    }
    if(!lv->isTemp)
    {
      VarRef tmp=lv->Clone();
      tmp->Mod(rv);
      return tmp;
    }
    lv->Mod(rv);
    return lv;
  }
  void dump(std::string& s)
  {
    s+="(";
    left->dump(s);
    s+="%";
    right->dump(s);
    s+=")";
  }
  std::auto_ptr<Expression> left;
  std::auto_ptr<Expression> right;
};

struct PostIncExpr:Expression{
  PostIncExpr(VM* argVM):Expression(argVM){}
  VarRef Evaluate(bool writeMode=false)
  {
    VarRef val=expr->Evaluate().Dealias();
    if(val->vt!=vtInt && val->vt!=vtString)
    {
      error("Operation ++ is only allowed for int and string variables");
    }
    if(val->isTemp)
    {
      error("Operation ++ is not allowed for temporal values");
    }
    VarRef rv=val->Clone();
    if(val->vt==vtInt)
    {
      val->asInt()++;
    }else if(val->vt==vtString)
    {
      if(val->asString().length()>0)
      {
        val->asString()[val->asString().length()-1]++;
      }
    }
    return rv;
  }
  void dump(std::string& s)
  {
    s+="(";
    expr->dump(s);
    s+="++";
    s+=")";
  }
  std::auto_ptr<Expression> expr;
};

struct PreIncExpr:Expression{
  PreIncExpr(VM* argVM):Expression(argVM){}
  VarRef Evaluate(bool writeMode=false)
  {
    VarRef val=expr->Evaluate().Dealias();
    if(val->vt!=vtInt && val->vt!=vtString)
    {
      error("Operation ++ is only allowed for int and string variables");
    }
    if(val->isTemp)
    {
      error("Operation ++ is not allowed for temporal values");
    }
    if(val->vt==vtInt)
    {
      val->asInt()++;
    }else if(val->vt==vtString)
    {
      if(val->asString().length()>0)
      {
        val->asString()[val->asString().length()-1]++;
      }
    }
    return val->Clone();
  }
  void dump(std::string& s)
  {
    s+="(";
    s+="++";
    expr->dump(s);
    s+=")";
  }
  std::auto_ptr<Expression> expr;
};

struct PostDecExpr:Expression{
  PostDecExpr(VM* argVM):Expression(argVM){}
  VarRef Evaluate(bool writeMode=false)
  {
    VarRef val=expr->Evaluate().Dealias();
    if(val->vt!=vtInt && val->vt!=vtString)
    {
      error("Operation -- is only allowed for int and string variables");
    }
    if(val->isTemp)
    {
      error("Operation - is not allowed for temporal values");
    }
    VarRef rv=val->Clone();
    if(val->vt==vtInt)
    {
      val->asInt()--;
    }else if(val->vt==vtString)
    {
      if(val->asString().length()>0)
      {
        val->asString()[val->asString().length()-1]--;
      }
    }
    return rv;
  }
  void dump(std::string& s)
  {
    s+="(";
    expr->dump(s);
    s+="--";
    s+=")";
  }
  std::auto_ptr<Expression> expr;
};

struct PreDecExpr:Expression{
  PreDecExpr(VM* argVM):Expression(argVM){}
  VarRef Evaluate(bool writeMode=false)
  {
    VarRef val=expr->Evaluate().Dealias();
    if(val->vt!=vtInt && val->vt!=vtString)
    {
      error("Operation -- is only allowed for int and string variables");
    }
    if(val->isTemp)
    {
      error("Operation -- is not allowed for temporal values");
    }
    if(val->vt==vtInt)
    {
      val->asInt()--;
    }else if(val->vt==vtString)
    {
      if(val->asString().length()>0)
      {
        val->asString()[val->asString().length()-1]--;
      }
    }
    return val->Clone();
  }
  void dump(std::string& s)
  {
    s+="(";
    s+="--";
    expr->dump(s);
    s+=")";
  }
  std::auto_ptr<Expression> expr;
};


struct NegateExpr:Expression{
  NegateExpr(VM* argVM):Expression(argVM){}
  VarRef Evaluate(bool writeMode=false)
  {
    VarRef rv=expr->Evaluate().Dealias();
    rv=rv->Clone();
    if(rv->vt==vtInt)
    {
      rv->asInt()=-rv->asInt();
    }else if(rv->vt==vtString)
    {
      std::string val=rv->asString();
      std::string tmp;
      for(size_t i=0;i<val.length();i++)
      {
        tmp+=val[val.length()-i-1];
      }
      rv->asString()=tmp;
    }else if(rv->vt==vtArray)
    {
      VarVector& v=rv->asArray();
      size_t sz=v.size();
      size_t l=sz/2;
      for(size_t i=0;i<l;i++)
      {
        size_t j=sz-1-i;
        if(i!=j)
        {
          VarRef tmp=v[i];
          v[i]=v[j];
          v[j]=tmp;
        }
      }
    }else
    {
      error("only int, string or array can be negated");
    }
    return rv;
  }
  void dump(std::string& s)
  {
    s+="(";
    s+="-";
    expr->dump(s);
    s+=")";
  }
  std::auto_ptr<Expression> expr;
};


struct VarAccessExpr:Expression{
  VarAccessExpr(VM* argVM):Expression(argVM){}
  VarRef Evaluate(bool writeMode=false)
  {
    return vm->getVar(var,writeMode);
  }
  void dump(std::string& s)
  {
    s+=var;
  }
  uchar var;
};

struct FieldAccessExpr:Expression{
  FieldAccessExpr(VM* argVM):Expression(argVM){}
  VarRef Evaluate(bool writeMode=false)
  {
    VarRef var=base->Evaluate().Dealias();
    if(var->vt==vtRefVar)
    {
      VarRef str=vm->allocVar<StructVar>();
      var->Assign(str);
      var=*var->asRefVar();
    }else if(var->vt==vtStructSlice)
    {
      StructSlice* ss=var->asStructSlice();
      for(size_t i=0;i<ss->fields.size();i++)
      {
        if(ss->fields[i]==field)
        {
          VarRef& rv=ss->var->asStruct()[field];
          if(!rv.var || writeMode)
          {
            RefVar* r=vm->allocVar<RefVar>();
            r->varPtr=&rv.var;
            return r;
          }
          return rv;
        }
      }
      error("field %c not found in structure slice",field);
    }else if(var->vt!=vtStruct)
    {
      error("attempt to access field %c of non-structure(%s)",field,var->getTypeName());
    }
    VarRef& rv=var->asStruct()[field];
    if(!rv.var || writeMode)
    {
      RefVar* r=vm->allocVar<RefVar>();
      r->varPtr=&rv.var;
      return r;
    }
    return rv;
  }
  void dump(std::string& s)
  {
    base->dump(s);
    s+=field;
  }
  std::auto_ptr<Expression> base;
  uchar field;
};

struct ArrayAccessExpr:Expression{
  ArrayAccessExpr(VM* argVM):Expression(argVM){}
  VarRef Evaluate(bool writeMode=false)
  {
    VarRef arr=base->Evaluate(writeMode).Dealias();
    VarRef idx=index->Evaluate();
    if(arr->vt==vtStructSlice)
    {
      StructSlice* ss=arr->asStructSlice();
      size_t idxVal=idx->toInt();
      if(idxVal>=ss->fields.size())
      {
        error("structure slice index is out of bounds(%lu/%lu)",idxVal,ss->fields.size());
      }
      if(writeMode)
      {
        RefVar* rv=vm->allocVar<RefVar>();
        rv->varPtr=&ss->var->asStruct()[ss->fields[idxVal]].var;
        return rv;
      }else
      {
        return ss->var->asStruct()[ss->fields[idxVal]];
      }
    }else if(arr->vt==vtRefVar)
    {
      VarRef v=vm->allocVar<ArrVar>();
      arr->Assign(v);
      arr=*arr->asRefVar();
    }else if(arr->vt!=vtArray)
    {
      error("attempt to access index of non-array");
    }
    VarVector& arrVal=arr->asArray();
    int intVal=idx->toInt();
    if(intVal<0)
    {
      intVal+=arrVal.size();
    }
    size_t idxVal=intVal;
    if(idxVal>arrVal.size())
    {
      //arrVal.resize(idxVal+1,0);
      error("array index is out of bounds(%lu/%lu)",idxVal,arrVal.size());
    }else if(idxVal==arrVal.size())
    {
      /*if(!writeMode)
      {
        error("array index is out of bounds(%lu/%lu)",idxVal,arrVal.size());
      }*/
      arrVal.push_back(VarRef());
    }
    if(writeMode || !arrVal[idxVal].var)
    {
      RefVar* rv=vm->allocVar<RefVar>();
      rv->varPtr=&arr->asArray()[idxVal].var;
      return rv;
    }else
    {
      return arrVal[idxVal];
    }
  }
  void dump(std::string& s)
  {
    base->dump(s);
    s+="[";
    index->dump(s);
    s+="]";
  }
  std::auto_ptr<Expression> base;
  std::auto_ptr<Expression> index;
};

struct ArrayAccessConstExpr:Expression{
  ArrayAccessConstExpr(VM* argVM):Expression(argVM){}
  VarRef Evaluate(bool writeMode=false)
  {
    VarRef arr=base->Evaluate().Dealias();
    if(arr->vt==vtStructSlice)
    {
      StructSlice* ss=arr->asStructSlice();
      if(index>=ss->fields.size())
      {
        error("structure slice index is out of bounds(%lu/%lu)",index,ss->fields.size());
      }
      if(writeMode)
      {
        RefVar* rv=vm->allocVar<RefVar>();
        rv->varPtr=&ss->var->asStruct()[ss->fields[index]].var;
        return rv;
      }else
      {
        return ss->var->asStruct()[ss->fields[index]];
      }
    }else if(arr->vt==vtRefVar)
    {
      VarRef v=vm->allocVar<ArrVar>();
      arr->Assign(v);
      arr=*arr->asRefVar();
    }else if(arr->vt!=vtArray)
    {
      error("attempt to access index of non-array");
    }
    VarVector& arrVal=arr->asArray();
    if(index>arrVal.size())
    {
      //arrVal.resize(idxVal+1,0);
      error("array index is out of bounds(%lu/%lu)",index,arrVal.size());
    }else if(index==arrVal.size())
    {
      /*if(!writeMode)
      {
        error("array index is out of bounds(%lu/%lu)",idxVal,arrVal.size());
      }*/
      arrVal.push_back(VarRef());
    }
    if(writeMode || !arrVal[index].var)
    {
      RefVar* rv=vm->allocVar<RefVar>();
      rv->varPtr=&arr->asArray()[index].var;
      return rv;
    }else
    {
      return arrVal[index];
    }
  }
  void dump(std::string& s)
  {
    base->dump(s);
    s+="[";
    char buf[32];
    sprintf(buf,"%lu",index);
    s+=buf;
    s+="]";
  }
  std::auto_ptr<Expression> base;
  size_t index;
};

struct BaseCallExpr:Expression{
  BaseCallExpr(VM* argVM):Expression(argVM){}
  ~BaseCallExpr()
  {
    for(std::vector<FuncArg>::iterator it=args.begin(),end=args.end();it!=end;it++)
    {
      delete it->expr;
    }
  }
  void prepareArgs(Func& f)
  {
    for(std::vector<FuncArg>::iterator it=args.begin(),end=args.end();it!=end;it++)
    {
      VarRef v=it->expr->Evaluate();
      if(v->isTemp || it->isRef)
      {
        f.localVars->asStruct().add(it->varName,v);
      }else
      {
        f.localVars->asStruct().add(it->varName,v->Clone());
      }
      f.localVars->asStruct()[it->varName]->isTemp=false;
    }
  }
  void dumpArgs(std::string& s)
  {
    bool first=true;
    for(size_t i=0;i<args.size();i++)
    {
      if(first)
      {
        first=false;
      }else
      {
        s+=",";
      }
      args[i].expr->dump(s);
    }
  }
  struct FuncArg{
    Expression* expr;
    uchar varName;
    bool isRef;
  };
  std::vector<FuncArg> args;
};

struct FuncCallExpr:BaseCallExpr{
  FuncCallExpr(VM* argVM):BaseCallExpr(argVM){}
  VarRef Evaluate(bool writeMode=false)
  {
    Func f;
    f.localVars=vm->allocVar<StructVar>();
    prepareArgs(f);
    vm->callStack.push_back(&f);
    f.retPoint=vm->cp;
    vm->cp=funcCp;
    vm->RunLoop();
    vm->cp=f.retPoint+1;
    //vm->temporals.push_back(f.result->Clone());
    //f.result=0;
    vm->callStack.pop_back();
    return f.result.var?f.result:vm->lastExpr;//vm->temporals.back();
  }
  void dump(std::string& s)
  {
    s+=fname;
    s+="(";
    dumpArgs(s);
    s+=")";
  }
  uchar fname;
  size_t funcCp;

};

struct MethodCallExpr:BaseCallExpr{
  MethodCallExpr(VM* argVM):BaseCallExpr(argVM){}

  VarRef Evaluate(bool writeMode=false)
  {
    VarRef self=base->Evaluate().Dealias();
    /*if(self->vt!=vtStruct)
    {
      error("Can't call method on non-struct");
    }*/
    Func f;
    f.localVars=vm->allocVar<StructVar>();
    f.method=true;
    f.self=self;
    prepareArgs(f);
    vm->callStack.push_back(&f);
    f.retPoint=vm->cp;
    vm->cp=methodCp;
    vm->RunLoop();
    vm->cp=f.retPoint+1;
    vm->callStack.pop_back();
    return f.result.var?f.result:vm->lastExpr;
  }
  void dump(std::string& s)
  {
    base->dump(s);
    s+=fname;
    s+="(";
    dumpArgs(s);
    s+=")";
  }
  uchar fname;
  size_t methodCp;
  std::auto_ptr<Expression> base;
};

struct RefCallBaseExpr:Expression{
  RefCallBaseExpr(VM* argVM):Expression(argVM){}
  ~RefCallBaseExpr()
  {
    for(size_t i=0;i<argVals.size();i++)
    {
      delete argVals[i];
    }
  }
  void prepareArgs(Func& f,std::vector<uchar>& args,std::vector<bool>& isRef)
  {
    for(size_t i=0;i<argVals.size();i++)
    {
      VarRef v=argVals[i]->Evaluate();
      if(v->isTemp || isRef[i])
      {
        f.localVars->asStruct().add(args[i],v);
      }else
      {
        f.localVars->asStruct().add(args[i],v->Clone());
      }
      f.localVars->asStruct()[args[i]]->isTemp=false;
    }
  }
  void dumpArgs(std::string& s)
  {
    for(size_t i=0;i<argVals.size();i++)
    {
      if(i!=0)
      {
        s+=',';
      }
      argVals[i]->dump(s);
    }
  }
  std::vector<Expression*> argVals;
  std::auto_ptr<Expression> base;
};

struct FuncRefDerefExpr:RefCallBaseExpr{
  FuncRefDerefExpr(VM* argVM):RefCallBaseExpr(argVM){}
  VarRef Evaluate(bool writeMode=false)
  {
    VarRef ref=base->Evaluate();
    if(ref->vt!=vtFuncRef)
    {
      error("Attempt to dereference non-funcref type %s",ref->getTypeName());
    }
    FuncRefVar* fr=ref->asFuncRef();
    if(fr->args.size()!=argVals.size())
    {
      error("Arguments count mismatch for func ref call(expected %lu, found %lu)",fr->args.size(),argVals.size());
    }
    Func f;
    f.localVars=vm->allocVar<StructVar>();
    prepareArgs(f,fr->args,fr->isRef);
    vm->callStack.push_back(&f);
    f.retPoint=vm->cp;
    vm->cp=fr->funcCp;
    vm->RunLoop();
    vm->cp=f.retPoint+1;
    vm->callStack.pop_back();
    return f.result.var?f.result:vm->lastExpr;
  }
  void dump(std::string& s)
  {
    s+='*';
    base->dump(s);
    s+='(';
    dumpArgs(s);
    s+=')';
  }
};

struct MethodRefDerefExpr:RefCallBaseExpr{
  MethodRefDerefExpr(VM* argVM):RefCallBaseExpr(argVM){}
  VarRef Evaluate(bool writeMode=false)
  {
    VarRef ref=base->Evaluate();
    if(ref->vt!=vtMethodRef)
    {
      error("Attempt to dereference non-funcref type %s",ref->getTypeName());
    }
    MethodRefVar* mr=ref->asMethodRef();
    if(mr->args.size()!=argVals.size())
    {
      error("Arguments count mismatch for func ref call(expected %lu, found %lu)",mr->args.size(),argVals.size());
    }
    VarRef selfVal=self->Evaluate().Dealias();
    Func f;
    f.localVars=vm->allocVar<StructVar>();
    f.method=true;
    f.self=selfVal;
    prepareArgs(f,mr->args,mr->isRef);
    vm->callStack.push_back(&f);
    f.retPoint=vm->cp;
    vm->cp=mr->funcCp;
    vm->RunLoop();
    vm->cp=f.retPoint+1;
    vm->callStack.pop_back();
    return f.result.var?f.result:vm->lastExpr;
  }
  void dump(std::string& s)
  {
    s+='*';
    base->dump(s);
    s+='(';
    dumpArgs(s);
    s+=')';
  }
  std::auto_ptr<Expression> self;
};


struct SelfAccessExpr:Expression{
  SelfAccessExpr(VM* argVM):Expression(argVM){}
  VarRef Evaluate(bool writeMode=false)
  {
    return vm->callStack.back()->self;
  }
  void dump(std::string& s)
  {
    s+=".";
  }
};


struct IntConstExpr:Expression{
  IntConstExpr(VM* argVM,int argVal):Expression(argVM),val(argVal){}
  VarRef Evaluate(bool writeMode=false)
  {
    IntVar* rv=vm->allocVar<IntVar>();
    rv->val=val;
    return rv;
  }
  void dump(std::string& s)
  {
    char buf[32];
    sprintf(buf,"%d",val);
    s+=buf;
  }
  int val;
};

struct StrConstExpr:Expression{
  StrConstExpr(VM* argVM,const std::string& argVal):Expression(argVM),val(argVal){}
  VarRef Evaluate(bool writeMode=false)
  {
    StrVar* rv=vm->allocVar<StrVar>();
    rv->val=val;
    return rv;
  }
  void dump(std::string& s)
  {
    s+='"'+val+'"';
  }
  std::string val;
};

struct InterStrExpr:Expression{
  InterStrExpr(VM* argVM):Expression(argVM){}
  ~InterStrExpr()
  {
    for(std::vector<Item*>::iterator it=items.begin(),end=items.end();it!=end;it++)
    {
      delete *it;
    }
  }
  VarRef Evaluate(bool writeMode=false)
  {
    StrVar* rv=vm->allocVar<StrVar>();
    VarRef ret=rv;
    //size_t colorsCnt=0;
    for(std::vector<Item*>::iterator it=items.begin(),end=items.end();it!=end;it++)
    {
      Item& i=**it;
      if(i.it==itString)
      {
        rv->val+=i.str;
      }else if(i.it==itVariable)
      {
        rv->val+=vm->getVar(i.var)->toString();
      }else if(i.it==itExpression)
      {
        rv->val+=i.expr->Evaluate()->toString();
      }else if(i.it==itSetColor)
      {
        rv->val+=1;
        rv->val+=(char)i.val;
        /*colorsCnt++;
        vm->storeColor();
        vm->setColor(i.val);*/
      }else if(i.it==itSetBg)
      {
        /*colorsCnt++;
        vm->storeColor();
        vm->setBg(i.val);*/
        rv->val+=2;
        rv->val+=(char)i.val;
      }else if(i.it==itRestoreColor)
      {
        /*if(colorsCnt)
        {
          vm->restoreColor();
        }*/
        rv->val+=3;
      }
    }
    /*
    while(colorsCnt--)
    {
      vm->restoreColor();
    }*/
    return ret;
  }
  void dump(std::string& s)
  {
    s+='(';
    for(std::vector<Item*>::iterator it=items.begin(),end=items.end();it!=end;it++)
    {
      if(it!=items.begin())
      {
        s+='+';
      }
      Item& i=**it;
      if(i.it==itString)
      {
        s+='"';
        s+=i.str;
        s+='"';
      }else if(i.it==itVariable)
      {
        s+=i.var;
      }else if(i.it==itExpression)
      {
        i.expr->dump(s);
      }else if(i.it==itSetColor)
      {
        s+="setColor(";
        s+=itos(i.val);
        s+=")";
      }else if(i.it==itSetBg)
      {
        s+="setBg(";
        s+=itos(i.val);
        s+=")";
      }else if(i.it==itRestoreColor)
      {
        s+="restoreColor";
      }
    }
    s+=')';
  }

  enum ItemType{itString,itVariable,itExpression,itSetColor,itSetBg,itRestoreColor};
  struct Item{
    Item(const std::string& argStr):it(itString),str(argStr),expr(0){}
    Item(uchar argVar):it(itVariable),var(argVar),expr(0){}
    Item(Expression* argExpr):it(itExpression),expr(argExpr){}
    Item(ItemType argIt,int argVal):it(argIt),expr(0),val(argVal){}
    Item():it(itRestoreColor),expr(0){}
    ~Item()
    {
      if(expr)
      {
        delete expr;
      }
    }
    ItemType it;
    std::string str;
    uchar var;
    Expression* expr;
    int val;
  };

  std::vector<Item*> items;
};

struct ArrayConstructorExpr:Expression{
  ArrayConstructorExpr(VM* argVM):Expression(argVM){}
  ~ArrayConstructorExpr()
  {
    for(std::vector<Expression*>::iterator it=elements.begin(),end=elements.end();it!=end;it++)
    {
      delete *it;
    }
  }

  VarRef Evaluate(bool writeMode=false)
  {
    ArrVar* arr=vm->allocVar<ArrVar>();
    VarRef rv=arr;
    for(std::vector<Expression*>::iterator it=elements.begin(),end=elements.end();it!=end;it++)
    {
      arr->val.push_back((*it)->Evaluate());
    }
    rv->isTemp=true;
    return rv;
  }

  void dump(std::string& s)
  {
    s+="{";
    bool first=true;
    for(std::vector<Expression*>::iterator it=elements.begin(),end=elements.end();it!=end;it++)
    {
      if(first)
      {
        first=false;
      }else
      {
        s+=",";
      }
      (*it)->dump(s);
    }
    s+="}";
  }
  std::vector<Expression*> elements;
};

struct StructConstructorExpr:Expression{
  StructConstructorExpr(VM* argVM):Expression(argVM){}
  ~StructConstructorExpr()
  {
    for(std::vector<Expression*>::iterator it=elements.begin(),end=elements.end();it!=end;it++)
    {
      delete *it;
    }
  }
  VarRef Evaluate(bool writeMode=false)
  {
    StructVar* str=vm->allocVar<StructVar>();
    VarRef rv=str;
    size_t i=0;
    for(std::vector<Expression*>::iterator it=elements.begin(),end=elements.end();it!=end;it++,i++)
    {
      str->vars.add(fields[i],(*it)->Evaluate());
    }
    return rv;
  }
  void dump(std::string& s)
  {
    s+="{";
    bool first=true;
    size_t i=0;
    for(std::vector<Expression*>::iterator it=elements.begin(),end=elements.end();it!=end;it++,i++)
    {
      if(first)
      {
        first=false;
      }else
      {
        s+=",";
      }
      s+=fields[i];
      s+=':';
      (*it)->dump(s);
    }
    s+="}";
  }
  std::vector<uchar> fields;
  std::vector<Expression*> elements;
};

struct StructSliceConstructorExpr:Expression{
  StructSliceConstructorExpr(VM* argVM):Expression(argVM){}
  VarRef Evaluate(bool writeMode=false)
  {
    StructSlice* ss=vm->allocVar<StructSlice>();
    VarRef rv=ss;
    if(base.get())
    {
      ss->var=base->Evaluate().Dealias();
    }else
    {
      ss->var=vm->callStack.back()->localVars;
    }
    if(ss->var->vt==vtRefVar)
    {
      VarRef s=vm->allocVar<StructVar>();
      ss->var->Assign(s);
      ss->var=*ss->var->asRefVar();
    }else if(ss->var->vt==vtStructSlice)
    {
      ss->var=ss->var->asStructSlice()->var;
    }else if(ss->var->vt!=vtStruct)
    {
      error("Can't create struct slice from non-struct type %s",ss->var->getTypeName());
    }
    ss->fields=fields;
    return rv;
  }
  void dump(std::string& s)
  {
    s+='(';
    if(base.get())
    {
      base->dump(s);
    }
    s+='\'';
    for(size_t i=0;i<fields.size();i++)s+=fields[i];
    s+=')';
  }
  std::vector<uchar> fields;
  std::auto_ptr<Expression> base;
};

struct FuncRefConstructorExpr:Expression{
  FuncRefConstructorExpr(VM* argVM):Expression(argVM){}
  VarRef Evaluate(bool writeMode=false)
  {
    FuncRefVar* rv=vm->allocVar<FuncRefVar>();
    rv->funcCp=funcCp;
    rv->args=args;
    rv->isRef=isRef;
    return rv;
  }
  void dump(std::string& s)
  {
    s+="&(";
    s+=itos(funcCp);
    s+=':';
    for(size_t i=0;i<args.size();i++)
    {
      if(i!=0)
      {
        s+=',';
      }
      if(isRef[i])
      {
        s+='&';
      }
      s+=args[i];
    }
    s+=')';
  }
  size_t funcCp;
  std::vector<uchar> args;
  std::vector<bool> isRef;
};

struct MethodRefConstructorExpr:Expression{
  MethodRefConstructorExpr(VM* argVM):Expression(argVM){}
  VarRef Evaluate(bool writeMode=false)
  {
    MethodRefVar* rv=vm->allocVar<MethodRefVar>();
    rv->funcCp=funcCp;
    rv->args=args;
    rv->isRef=isRef;
    return rv;
  }
  void dump(std::string& s)
  {
    s+="&?(";
    s+=itos(funcCp);
    s+=':';
    for(size_t i=0;i<args.size();i++)
    {
      if(i!=0)
      {
        s+=',';
      }
      if(isRef[i])
      {
        s+='&';
      }
      s+=args[i];
    }
    s+=')';
  }
  size_t funcCp;
  std::vector<uchar> args;
  std::vector<bool> isRef;
};


struct AliasConstructorExpr:Expression{
  AliasConstructorExpr(VM* argVM):Expression(argVM){}
  VarRef Evaluate(bool writeMode=false)
  {
    VarRef rv=vm->allocVar<AliasVar>();
    rv->asAlias()->ex=expr.get();
    return rv;
  }
  void dump(std::string& s)
  {
    s+="^(";
    expr->dump(s);
    s+=")";
  }
  std::auto_ptr<Expression> expr;
};

struct RandomExpr:Expression{
  RandomExpr(VM* argVM):Expression(argVM){}
  VarRef Evaluate(bool writeMode=false)
  {
    int minVal=0;
    if(minEx.get())
    {
      minVal=minEx->Evaluate()->toInt();
    }
    int maxVal=maxEx->Evaluate()->toInt();

    IntVar* iv=vm->allocVar<IntVar>();
    iv->val=minVal+getrand(maxVal-minVal);
    return iv;
  }
  void dump(std::string& s)
  {
    s+="random(";
    if(minEx.get())
    {
      minEx->dump(s);
      s+=',';
    }
    maxEx->dump(s);
    s+=')';
  }
  std::auto_ptr<Expression> minEx;
  std::auto_ptr<Expression> maxEx;
};

struct LengthExpr:Expression{
  LengthExpr(VM* argVM):Expression(argVM){}
  VarRef Evaluate(bool writeMode=false)
  {
    VarRef val=base->Evaluate().Dealias();
    int rv=0;
    switch(val->vt)
    {
      case vtArray:rv=val->asArray().size();break;
      case vtString:rv=val->asString().length();break;
      case vtArraySegment:rv=val->asArrSegment()->to-val->asArrSegment()->from;break;
      case vtArraySlice:rv=val->asArrSlice()->indecies.size();break;
      case vtStruct:rv=val->asStruct().entries.size();break;
      case vtStringSegment:rv=val->asStrSegment()->to-val->asStrSegment()->from;break;
      case vtStringSlice:rv=val->asStrSlice()->indecies.size();break;
      case vtStructSlice:rv=val->asStructSlice()->fields.size();break;
      default:
        error("length operator cannot by applied to type %s",val->getTypeName());
    }
    IntVar* iv=vm->allocVar<IntVar>();
    iv->val=rv;
    return iv;
  }
  void dump(std::string& s)
  {
    s+="length(";
    base->dump(s);
    s+=')';
  }
  std::auto_ptr<Expression> base;
};

struct BoolExpression{
  virtual ~BoolExpression(){}
  virtual bool Evaluate()=0;
  virtual void dump(std::string&)=0;
};

struct BoolSimpleExpr:BoolExpression{
  bool Evaluate()
  {
    VarRef var=expr->Evaluate();
    if(var.var)
    {
      if(var->vt==vtInt)
      {
        return var->asInt()!=0;
      }else if(var->vt==vtString)
      {
        return !var->asString().empty();
      }else if(var->vt==vtArray)
      {
        return !var->asArray().empty();
      }else
      {
        error("Invalid expression of type %s in condition",var->getTypeName());
      }
    }
    return false;
  }
  void dump(std::string& s)
  {
    expr->dump(s);
  }
  std::auto_ptr<Expression> expr;
};

struct BoolNot:BoolExpression{
  bool Evaluate()
  {
    return !base->Evaluate();
  }
  void dump(std::string& s)
  {
    s+="!(";
    base->dump(s);
    s+=")";
  }
  std::auto_ptr<BoolExpression> base;
};

struct BoolAnd:BoolExpression{
  bool Evaluate()
  {
    return left->Evaluate() && right->Evaluate();
  }
  void dump(std::string& s)
  {
    s+="(";
    left->dump(s);
    s+=" && ";
    right->dump(s);
    s+=")";
  }
  std::auto_ptr<BoolExpression> left;
  std::auto_ptr<BoolExpression> right;
};

struct BoolOr:BoolExpression{
  bool Evaluate()
  {
    return left->Evaluate() || right->Evaluate();
  }
  void dump(std::string& s)
  {
    s+="(";
    left->dump(s);
    s+=" || ";
    right->dump(s);
    s+=")";
  }
  std::auto_ptr<BoolExpression> left;
  std::auto_ptr<BoolExpression> right;
};

struct BoolEq:BoolExpression{
  bool Evaluate()
  {
    VarRef lv(left->Evaluate());
    VarRef rt(right->Evaluate());
    return lv->isEqual(rt.var);
  }
  void dump(std::string& s)
  {
    s+="(";
    left->dump(s);
    s+=" == ";
    right->dump(s);
    s+=")";
  }
  std::auto_ptr<Expression> left;
  std::auto_ptr<Expression> right;
};

struct BoolNEq:BoolExpression{
  bool Evaluate()
  {
    VarRef lv(left->Evaluate());
    VarRef rt(right->Evaluate());
    return !lv->isEqual(rt.var);
  }
  void dump(std::string& s)
  {
    s+="(";
    left->dump(s);
    s+=" != ";
    right->dump(s);
    s+=")";
  }
  std::auto_ptr<Expression> left;
  std::auto_ptr<Expression> right;
};


struct BoolLt:BoolExpression{
  bool Evaluate()
  {
    VarRef lv(left->Evaluate());
    VarRef rt(right->Evaluate());
    return lv->isLessThan(rt.var);
  }
  void dump(std::string& s)
  {
    s+="(";
    left->dump(s);
    s+=" < ";
    right->dump(s);
    s+=")";
  }
  std::auto_ptr<Expression> left;
  std::auto_ptr<Expression> right;
};

struct BoolLtEq:BoolExpression{
  bool Evaluate()
  {
    VarRef lv(left->Evaluate());
    VarRef rt(right->Evaluate());
    return lv->isLessEq(rt.var);
  }
  void dump(std::string& s)
  {
    s+="(";
    left->dump(s);
    s+=" <= ";
    right->dump(s);
    s+=")";
  }
  std::auto_ptr<Expression> left;
  std::auto_ptr<Expression> right;
};

struct BoolGt:BoolExpression{
  bool Evaluate()
  {
    VarRef lv(left->Evaluate());
    VarRef rt(right->Evaluate());
    return !lv->isLessEq(rt.var);
  }
  void dump(std::string& s)
  {
    s+="(";
    left->dump(s);
    s+=" > ";
    right->dump(s);
    s+=")";
  }
  std::auto_ptr<Expression> left;
  std::auto_ptr<Expression> right;
};

struct BoolGtEq:BoolExpression{
  bool Evaluate()
  {
    VarRef lv(left->Evaluate());
    VarRef rt(right->Evaluate());
    return !lv->isLessThan(rt.var);
  }
  void dump(std::string& s)
  {
    s+="(";
    left->dump(s);
    s+=" >= ";
    right->dump(s);
    s+=")";
  }
  std::auto_ptr<Expression> left;
  std::auto_ptr<Expression> right;
};

struct CondExpr:Expression{
  CondExpr(VM* argVM):Expression(argVM){}

  VarRef Evaluate(bool writeMode=false)
  {
    if(cond->Evaluate())
    {
      return trueExpr->Evaluate();
    }else
    {
      return falseExpr->Evaluate();
    }
  }

  void dump(std::string& s)
  {
    s+="(";
    cond->dump(s);
    s+="?";
    trueExpr->dump(s);
    s+=":";
    falseExpr->dump(s);
    s+=")";
  }

  std::auto_ptr<BoolExpression> cond;
  std::auto_ptr<Expression> trueExpr;
  std::auto_ptr<Expression> falseExpr;
};

struct AssignmentOp:OpCodeBase{
  AssignmentOp(VM* argVM):OpCodeBase(argVM){}
  size_t Execute()
  {
    VarRef lv;
    if(left.get())
    {
      lv=left->Evaluate();
    }else
    {
      lv=vm->lastExpr;
      if(lv.var==0)
      {
        error("Null variable left side of assignment");
      }
    }
    VarRef rv=right->Evaluate();
    if(lv->isTemp)
    {
      error("Attempt to assign value to temporal");
    }
    if(lv->canAssign(rv))
    {
      lv->Assign(rv);
    }else
    {
      lv=rv->Clone(false);
    }
    return idx+1;
  }
  void dump(std::string& s)
  {
    dumpIdx(s);
    if(left.get())left->dump(s);
    s+="=";
    right->dump(s);
    s+=";\n";
  }
  std::auto_ptr<Expression> left;
  std::auto_ptr<Expression> right;
};

struct ForceAssignmentOp:OpCodeBase{
  ForceAssignmentOp(VM* argVM):OpCodeBase(argVM){}
  size_t Execute()
  {
    VarRef lv;
    if(left.get())
    {
      lv=left->Evaluate(true);
    }else
    {
      lv=vm->lastExpr;
      if(lv.var==0)
      {
        error("Null variable on left side of rewrite");
      }
    }
    VarRef rv=right->Evaluate();
    if(lv->isTemp)
    {
      error("Attempt rewrite temporal value");
    }
    if(lv->vt==vtStructSlice)
    {
      StructSlice* ss=lv->asStructSlice();
      Namespace& ns=ss->var->asStruct();
      for(size_t i=0;i<ss->fields.size();i++)
      {
         ns.add(ss->fields[i],rv->Clone());
      }
    }else if(lv->canAssign(rv))
    {
      lv->Assign(rv);
    }else
    {
      error("Cannot rewrite %s",lv->getTypeName());
    }
    return idx+1;
  }
  void dump(std::string& s)
  {
    dumpIdx(s);
    if(left.get())left->dump(s);
    s+="==";
    right->dump(s);
    s+=";\n";
  }
  std::auto_ptr<Expression> left;
  std::auto_ptr<Expression> right;
};


struct OpEqOpBase:OpCodeBase{
  OpEqOpBase(VM* argVM):OpCodeBase(argVM)
  {
    opChar='?';
    opMethod=0;
  }
  size_t Execute()
  {
    VarRef lv=left->Evaluate();
    if(lv->isTemp)
    {
      error("Attempt to apply %c= to temporal",opChar);
    }
    (lv.var->*opMethod)(right->Evaluate());
    return idx+1;
  }
  void dump(std::string& s)
  {
    dumpIdx(s);
    if(left.get())left->dump(s);
    s+=opChar;
    s+='=';
    right->dump(s);
    s+=";\n";
  }
  uchar opChar;
  void (Var::*opMethod)(VarRef);
  std::auto_ptr<Expression> left;
  std::auto_ptr<Expression> right;
};

struct AddEqOp:OpEqOpBase{
  AddEqOp(VM* argVM):OpEqOpBase(argVM)
  {
    opChar='+';
    opMethod=&Var::Add;
  }
};

struct SubEqOp:OpEqOpBase{
  SubEqOp(VM* argVM):OpEqOpBase(argVM)
  {
    opChar='-';
    opMethod=&Var::Sub;
  }
};

struct MulEqOp:OpEqOpBase{
  MulEqOp(VM* argVM):OpEqOpBase(argVM)
  {
    opChar='*';
    opMethod=&Var::Mul;
  }
};


struct DivEqOp:OpEqOpBase{
  DivEqOp(VM* argVM):OpEqOpBase(argVM)
  {
    opChar='/';
    opMethod=&Var::Div;
  }
};

struct ModEqOp:OpEqOpBase{
  ModEqOp(VM* argVM):OpEqOpBase(argVM)
  {
    opChar='/';
    opMethod=&Var::Div;
  }
};


struct ExecExprOp:OpCodeBase{
  ExecExprOp(VM* argVM):OpCodeBase(argVM){}
  size_t Execute()
  {
    vm->lastExpr=expr->Evaluate();
    return idx+1;
  }
  void dump(std::string& s)
  {
    dumpIdx(s);
    expr->dump(s);
    s+=";\n";
  }
  std::auto_ptr<Expression> expr;
};


struct FuncRetOp:OpCodeBase{
  FuncRetOp(VM* argVM):OpCodeBase(argVM){}
  size_t Execute()
  {
    if(rv.get())
    {
      VarRef res=rv->Evaluate();
      //printf("ret(%p)=%d\n",res,res->asInt());
      vm->callStack.back()->result=res;
    }
    return INVALID_CP_VALUE;
  }
  void dump(std::string& s)
  {
    dumpIdx(s);
    s+="return";
    if(rv.get())
    {
      s+=" ";
      rv->dump(s);
    }
    s+=";\n";
  }
  std::auto_ptr<Expression> rv;
};

struct OutOp:OpCodeBase{
  OutOp(VM* argVM):OpCodeBase(argVM){}
  size_t Execute()
  {
    VarRef var=expr->Evaluate();
    vm->outLine(var->toString(),false);
    return idx+1;
  }
  void dump(std::string& s)
  {
    dumpIdx(s);
    s+="print ";
    expr->dump(s);
    s+=";\n";
  }
  std::auto_ptr<Expression> expr;
};


struct OutLineOp:OpCodeBase{
  OutLineOp(VM* argVM):OpCodeBase(argVM){}
  size_t Execute()
  {
    VarRef var=expr->Evaluate();
    vm->outLine(var->toString().c_str(),true);
    return idx+1;
  }
  void dump(std::string& s)
  {
    dumpIdx(s);
    s+="print ";
    expr->dump(s);
    s+=";\n";
  }
  std::auto_ptr<Expression> expr;
};

struct OutDebugOp:OpCodeBase{
  OutDebugOp(VM* argVM):OpCodeBase(argVM){}
  size_t Execute()
  {
    VarRef var=expr->Evaluate();
    fprintf(stderr,"L%luC%lu:%s\n",pos.line,pos.col,var->toString().c_str());
    return idx+1;
  }
  void dump(std::string& s)
  {
    dumpIdx(s);
    s+="print ";
    expr->dump(s);
    s+=";\n";
  }
  std::auto_ptr<Expression> expr;
};


struct InCharOp:OpCodeBase{
  InCharOp(VM* argVM):OpCodeBase(argVM){}
  size_t Execute()
  {
    VarRef var=expr->Evaluate();
    if(var->isTemp)
    {
      error("Character can't be read into temporal");
    }
    int code;
    if(vm->useCurses)
    {
      code=getch();
    }else
    {
      code=fgetc(stdin);
    }
    IntVar* iv=vm->allocVar<IntVar>();
    iv->val=code;
    var->Assign(iv);
    return idx+1;
  }
  void dump(std::string& s)
  {
    dumpIdx(s);
    s+="getch ";
    expr->dump(s);
    s+=";\n";
  }
  std::auto_ptr<Expression> expr;
};

struct InLineOp:OpCodeBase{
  InLineOp(VM* argVM):OpCodeBase(argVM){}
  size_t Execute()
  {
    VarRef var=expr->Evaluate();
    if(var->isTemp)
    {
      error("Line can't be read into temporal");
    }
    std::string val;
    if(vm->useCurses)
    {
      char buf[1024];
      echo();
      getnstr(buf,sizeof(buf));
      noecho();
      val=buf;
    }else
    {
      char buf[1024];
      fgets(buf,sizeof(buf),stdin);
      val=buf;
    }
    StrVar* sv=vm->allocVar<StrVar>();
    sv->val=val;
    var->Assign(sv);
    return idx+1;
  }
  void dump(std::string& s)
  {
    dumpIdx(s);
    s+="getline ";
    expr->dump(s);
    s+=";\n";
  }
  std::auto_ptr<Expression> expr;
};

struct SetCurOp:OpCodeBase{
  SetCurOp(VM* argVM):OpCodeBase(argVM){}
  size_t Execute()
  {
    if(!vm->useCurses)
    {
      error("Set cursor position operator is only available in curses mode");
    }
    int x=xexpr->Evaluate()->toInt();
    int y=yexpr->Evaluate()->toInt();
    move(y,x);
    return idx+1;
  }
  void dump(std::string& s)
  {
    dumpIdx(s);
    s+="setCurPos(";
    xexpr->dump(s);
    s+=",";
    yexpr->dump(s);
    s+=");\n";
  }
  std::auto_ptr<Expression> xexpr;
  std::auto_ptr<Expression> yexpr;
};

struct SetColorOp:OpCodeBase{
  SetColorOp(VM* argVM):OpCodeBase(argVM){}
  size_t Execute()
  {
    if(!vm->useCurses)
    {
      error("Set curses position operator is only available in curses mode");
    }
    vm->setColor(cexpr->Evaluate()->toInt());
    if(bexpr.get())
    {
      vm->setBg(bexpr->Evaluate()->toInt());
    }
    return idx+1;
  }
  void dump(std::string& s)
  {
    dumpIdx(s);
  }
  std::auto_ptr<Expression> cexpr;
  std::auto_ptr<Expression> bexpr;
};

struct JumpOp:OpCodeBase{
  JumpOp(VM* argVM):OpCodeBase(argVM){}
  size_t Execute()
  {
    return jumpCp;
  }
  void dump(std::string& s)
  {
    dumpIdx(s);
    char buf[32];
    sprintf(buf,"jump:%lu\n",jumpCp);
    s+=buf;
  }
  size_t jumpCp;
};

struct CondJumpOp:OpCodeBase{
  CondJumpOp(VM* argVM):OpCodeBase(argVM){}
  size_t Execute()
  {
    return !cond->Evaluate()?jumpCpFalse:idx+1;
  }
  void dump(std::string& s)
  {
    dumpIdx(s);
    s+="jump if(";
    cond->dump(s);
    char buf[32];
    sprintf(buf,"):%lu\n",jumpCpFalse);
    s+=buf;
  }
  std::auto_ptr<BoolExpression> cond;
  size_t jumpCpFalse;
};

struct SelectJumpOp:OpCodeBase{
  SelectJumpOp(VM* argVM):OpCodeBase(argVM)
  {
    defaultChoiceCp=INVALID_CP_VALUE;
  }
  ~SelectJumpOp()
  {
    for(std::vector<Choice*>::iterator it=choices.begin(),end=choices.end();it!=end;it++)
    {
      delete *it;
    }
  }
  size_t Execute()
  {
    VarRef val=base->Evaluate();
    VarRef choice;
    for(std::vector<Choice*>::iterator it=choices.begin(),end=choices.end();it!=end;it++)
    {
      choice=(*it)->expr->Evaluate();
      if(val->isEqual(choice))
      {
        return (*it)->jumpCp;
      }
    }
    if(defaultChoiceCp!=INVALID_CP_VALUE)
    {
      return defaultChoiceCp;
    }
    return endCp;
  }

  void dump(std::string& s)
  {
    s+="jump switch(";
    base->dump(s);
    s+="):(";
    for(std::vector<Choice*>::iterator it=choices.begin(),end=choices.end();it!=end;it++)
    {
      if(it!=choices.begin())
      {
        s+=',';
      }
      (*it)->expr->dump(s);
      s+=':';
      s+=itos((*it)->jumpCp);
    }
    if(defaultChoiceCp!=INVALID_CP_VALUE)
    {
      s+="default:";
      s+=itos(defaultChoiceCp);
    }
    s+="):";
    s+=itos(endCp);
  }

  std::auto_ptr<Expression> base;
  struct Choice{
    std::auto_ptr<Expression> expr;
    size_t jumpCp;
  };
  std::vector<Choice*> choices;
  size_t defaultChoiceCp;
  size_t endCp;

};

struct ILoopStepOp:OpCodeBase{
  ILoopStepOp(VM* argVM):OpCodeBase(argVM),isInclusive(true){}
  virtual void Init()=0;
  size_t endOfLoopCp;
  bool isInclusive;
};

struct LoopStepOp:ILoopStepOp{
  LoopStepOp(VM* argVM):ILoopStepOp(argVM){}
  ~LoopStepOp()
  {
    for(size_t i=0;i<initVal.size();i++)
    {
      delete initVal[i];
    }
    for(size_t i=0;i<finVal.size();i++)
    {
      delete finVal[i];
    }
  }
  size_t Execute()
  {
    size_t dim=curVal.size();
    if(dim>0)
    {
      if(first)
      {
        first=false;
        if(isInclusive?curVal[0]>finValCalc[0]:curVal[0]>=finValCalc[0])
        {
          return endOfLoopCp;
        }
      }else
      {
        for(size_t i=0;i<dim;i++)
        {
          curVal[i]++;
          if(isInclusive?curVal[i]>finValCalc[i]:curVal[i]>=finValCalc[i])
          {
            if(i==dim-1)
            {
              return endOfLoopCp;
            }
            curVal[i]=initValCalc[i];
            continue;
          }
          break;
        }
      }
    }
    if(!vars.empty())
    {
      for(size_t i=0;i<dim;i++)
      {
        IntVar* iv=vm->allocVar<IntVar>();
        iv->val=curVal[i];
        vm->getVar(vars[i],true)->Assign(iv);
      }
    }
    return idx+1;
  }
  void Init()
  {
    first=true;
    size_t dim=initVal.size();
    initValCalc.resize(dim);
    curVal.resize(dim);
    finValCalc.resize(dim);
    for(size_t i=0;i<dim;i++)
    {
      curVal[i]=initValCalc[i]=initVal[i]->Evaluate()->toInt();
      finValCalc[i]=finVal[i]->Evaluate()->toInt();
      if(!vars.empty())
      {
        vm->setVar(vars[i],vm->allocVar<IntVar>());
      }
    }
  }
  void dump(std::string& s)
  {
    dumpIdx(s);
    s+="loop(";
    //size_t dim=vars.size();
    for(size_t i=0;i<vars.size();i++)
    {
      if(i!=0)
      {
        s+=',';
      }
      s+=vars[i];
    }
    s+="):(";
    for(size_t i=0;i<initVal.size();i++)
    {
      if(i!=0)
      {
        s+=',';
      }
      initVal[i]->dump(s);
    }
    s+="):(";
    for(size_t i=0;i<finVal.size();i++)
    {
      if(i!=0)
      {
        s+=',';
      }
      finVal[i]->dump(s);
    }
    s+="):";
    s+=itos(endOfLoopCp);
    s+="\n";
  }

  bool first;
  std::vector<uchar> vars;
  std::vector<Expression*> initVal;
  std::vector<Expression*> finVal;
  std::vector<int> initValCalc;
  std::vector<int> curVal;
  std::vector<int> finValCalc;
};

struct ArrayLoopStepOp:ILoopStepOp{
  ArrayLoopStepOp(VM* argVM):ILoopStepOp(argVM){}
  size_t Execute()
  {
    VarVector& arr=arrVal->asArray();
    if(first)
    {
      if(arr.empty())
      {
        return endOfLoopCp;
      }
      first=false;
    }else
    {
      curIdx++;
      if(curIdx>=arr.size())
      {
        return endOfLoopCp;
      }
    }
    vm->setVar(varName,arr[curIdx]);
    return idx+1;
  }

  void Init()
  {
    first=true;
    arrVal=expr->Evaluate();
    if(arrVal->vt!=vtArray)
    {
      ArrVar* arr=vm->allocVar<ArrVar>();
      VarRef var=arr;
      arr->val=arrVal->toArray();
      arrVal=arr;
    }
    curIdx=0;
  }

  void dump(std::string& s)
  {
    dumpIdx(s);
    s+="arrayloop(";
    s+=varName;
    s+="):(";
    expr->dump(s);
    s+="):";
    s+=itos(endOfLoopCp);
    s+="\n";
  }

  bool first;
  uchar varName;
  size_t curIdx;
  VarRef arrVal;
  std::auto_ptr<Expression> expr;
};

struct InfLoopStepOp:ILoopStepOp{
  InfLoopStepOp(VM* argVM):ILoopStepOp(argVM){}
  size_t Execute()
  {
    return idx+1;
  }
  void Init()
  {
  }
  void dump(std::string& s)
  {
    dumpIdx(s);
    s+="loop\n";
  }
};

struct InitLoopOp:OpCodeBase{
  InitLoopOp(VM* argVM):OpCodeBase(argVM){}
  size_t Execute()
  {
    //VM::LoopData ld;
    //ld.loopStart=loopStep->idx;
    //ld.loopEnd=loopStep->endOfLoopCp;
    loopStep->Init();
    return idx+1;
  }
  void dump(std::string& s)
  {
    dumpIdx(s);
    s+="init loop\n";
  }
  ILoopStepOp* loopStep;
};

/*
struct EndOfLoopOp:OpCodeBase{
  EndOfLoopOp(VM* argVM):OpCodeBase(argVM){}
  size_t Execute()
  {
    vm->loops.pop_back();
    return idx+1;
  }
  void dump(std::string& s)
  {
    dumpIdx(s);
    s+="end of loop\n";
  }
};

struct LoopContOp:OpCodeBase{
  LoopContOp(VM* argVM):OpCodeBase(argVM){}
  size_t Execute()
  {
    return vm->loops.back().loopStart;
  }
  void dump(std::string& s)
  {
    dumpIdx(s);
    s+="continue;\n";
  }
};

struct LoopBreakOp:OpCodeBase{
  LoopBreakOp(VM* argVM):OpCodeBase(argVM){}
  size_t Execute()
  {
    return vm->loops.back().loopEnd;
  }
  void dump(std::string& s)
  {
    dumpIdx(s);
    s+="break;\n";
  }
};*/

struct EndOfCodeOp:OpCodeBase{
  EndOfCodeOp(VM* argVM):OpCodeBase(argVM){}
  size_t Execute()
  {
    return INVALID_CP_VALUE;
  }
  void dump(std::string& s)
  {
    dumpIdx(s);
    s+="END\n";
  }
};

enum ParsingState{
  psFunc,psMethod,psLoop,psIf,psSwitch
};

struct ParsingStackItem{
  ParsingState ps;
  Char pos;
  size_t idx;
  int data;
  std::vector<JumpOp*> jumpFixes;
};


struct Parser{
  Parser(VM& argVM):vm(argVM)
  {
  }

  void Parse(const std::string& fileName,const std::string& source)
  {
    SourceReader sr(fileName,source);
    Parse(sr);
  }

  void Parse(SourceReader& sr)
  {
    Char c;
    std::auto_ptr<Expression> tempExpr;
    while(!sr.isEof())
    {
      c=sr.getNext();
      if(tempExpr.get() && c.c!='=' && !isOp(c.c))
      {
        std::auto_ptr<ExecExprOp> op(new ExecExprOp(&vm));
        op->expr=tempExpr;
        PushOp(op,c);
      }
      switch(c.c)
      {
        case ';':
        case ' ':break;
        case '#':
        {
          if(sr.peekNext()=='!')
          {
            sr.skipLine();
            continue;
          }
          ParsingStackItem psi;
          psi.idx=vm.code.size();
          psi.pos=c;
          psi.ps=psFunc;
          ps.push_back(psi);
          PushOp(new JumpOp(&vm),c);
          ParseFunc(sr,c);
        }break;
        case '\\':
        {
          if(ps.empty())
          {
            throw ParsingException(c,"Unexpected \\");
          }
          if(ps.back().ps==psFunc || ps.back().ps==psMethod)
          {
            PushOp(new FuncRetOp(&vm),c);
            ((JumpOp*)vm.code[ps.back().idx])->jumpCp=vm.code.size();
            ps.pop_back();
          }else if(ps.back().ps==psIf)
          {
            if(ps.back().data==0)
            {
              CondJumpOp* op=(CondJumpOp*)vm.code[ps.back().idx];
              op->jumpCpFalse=vm.code.size();
            }else
            {
              JumpOp* op=(JumpOp*)vm.code[ps.back().idx];
              op->jumpCp=vm.code.size();
            }
            ps.pop_back();
          }else if(ps.back().ps==psLoop)
          {
            ILoopStepOp* st=(ILoopStepOp*)vm.code[ps.back().idx];
            JumpOp* jop=new JumpOp(&vm);
            jop->jumpCp=st->idx;
            PushOp(jop,c);
            st->endOfLoopCp=vm.code.size();

            //EndOfLoopOp* op=new EndOfLoopOp(&vm);
            //PushOp(op,c);
            for(size_t i=0;i<ps.back().jumpFixes.size();i++)
            {
              ps.back().jumpFixes[i]->jumpCp=st->endOfLoopCp;
            }
            ps.pop_back();
          }else if(ps.back().ps==psSwitch)
          {
            SelectJumpOp* op=(SelectJumpOp*)vm.code[ps.back().idx];
            op->endCp=vm.code.size();
            for(size_t i=0;i<ps.back().jumpFixes.size();i++)
            {
              ps.back().jumpFixes[i]->jumpCp=vm.code.size();
            }
            ps.pop_back();
          }
        }break;
        case '!':
        {
          std::auto_ptr<FuncRetOp> op(new FuncRetOp(&vm));
          op->rv=ParseExpr(sr,mmMayBeExpr,c);
          PushOp(op,c);
        }break;
        case '@':
          ParseLoop(sr,c);
          break;
        case '<':
        {
          if(sr.peekNext()=='<')
          {
            sr.getNext();
            std::auto_ptr<OutLineOp> op(new OutLineOp(&vm));
            op->expr=ParseExpr(sr,mmExpr,c);
            PushOp(op,c);
          }else if(sr.peekNext()=='!')
          {
            sr.getNext();
            std::auto_ptr<OutDebugOp> op(new OutDebugOp(&vm));
            op->expr=ParseExpr(sr,mmExpr,c);
            PushOp(op,c);
          }else
          {
            std::auto_ptr<OutOp> op(new OutOp(&vm));
            op->expr=ParseExpr(sr,mmExpr,c);
            PushOp(op,c);
          }
        }break;
        case '>':
        {
          if(sr.peekNext()=='>')
          {
            sr.getNext();
            std::auto_ptr<InLineOp> op(new InLineOp(&vm));
            op->expr=ParseExpr(sr,mmExprMin,c);
            PushOp(op,c);
          }else
          {
            std::auto_ptr<InCharOp> op(new InCharOp(&vm));
            op->expr=ParseExpr(sr,mmExprMin,c);
            PushOp(op,c);
          }
        }break;
        case '^':
        {
          std::auto_ptr<SetCurOp> op(new SetCurOp(&vm));
          op->xexpr=ParseExpr(sr,mmExpr,c);
          c=sr.getNext();
          if(c.c!=',')
          {
            throw ParsingException(c,"Expected ,");
          }
          op->yexpr=ParseExpr(sr,mmExpr,c);
          PushOp(op,c);
        }break;
        case '$':
        {
          std::auto_ptr<SetColorOp> op(new SetColorOp(&vm));
          op->cexpr=ParseExpr(sr,mmExpr,c);
          if(sr.peekNext()==',')
          {
            c=sr.getNext();
            op->bexpr=ParseExpr(sr,mmExpr,c);
          }
          PushOp(op,c);
        }break;
        case '?':
        {
          if(sr.peekNext()=='?')
          {
            sr.getNext();
            ParsingStackItem psi;
            psi.pos=c;
            psi.ps=psSwitch;
            psi.idx=vm.code.size();
            psi.data=0;
            ps.push_back(psi);
            std::auto_ptr<SelectJumpOp> op(new SelectJumpOp(&vm));
            op->base=ParseExpr(sr,mmExpr,c);
            PushOp(op,c);
          }else
          {
            ParsingStackItem psi;
            psi.pos=c;
            std::auto_ptr<CondJumpOp> op(new CondJumpOp(&vm));
            op->cond=ParseCond(sr,c);
            if(sr.peekNext()=='`')
            {
              sr.getNext();
            }
            psi.ps=psIf;
            psi.idx=vm.code.size();
            psi.data=0;
            ps.push_back(psi);
            PushOp(op,c);
          }
        }break;
        case '`':
        {
          if(ps.back().ps!=psSwitch)
          {
            throw ParsingException(c,"Unexpected `");
          }
          JumpOp* jop=new JumpOp(&vm);
          ps.back().jumpFixes.push_back(jop);
          PushOp(jop,c);

          SelectJumpOp* op=(SelectJumpOp*)vm.code[ps.back().idx];
          if(sr.peekNext()!=':')
          {
            std::auto_ptr<SelectJumpOp::Choice> choice(new SelectJumpOp::Choice);
            choice->expr=ParseExpr(sr,mmExpr,c);
            choice->jumpCp=vm.code.size();
            op->choices.push_back(choice.release());
          }else
          {
            if(op->defaultChoiceCp!=INVALID_CP_VALUE)
            {
              throw ParsingException(c,"Duplicate default case in switch started at %lu:%lu",ps.back().pos.line,ps.back().pos.col);
            }
            op->defaultChoiceCp=vm.code.size();
          }
          if(sr.getNext().c!=':')
          {
            throw ParsingException(c,"Expected :");
          }
        }break;
        case '+':
        case '-':
        case '*':
        case '/':
        case '%':
        {
          if(sr.peekNext()!='=')
          {
            sr.unget();
            tempExpr=ParseExpr(sr,mmExpr,c);break;
          }else
          {
            Pos opPos=c;
            uchar opSym=c.c;
            c=sr.getNext();
            if(!tempExpr.get())
            {
              throw ParsingException(c,"Unexpected %c=",opSym);
            }
            std::auto_ptr<Expression> rhs=ParseExpr(sr,mmExpr,c);
            std::auto_ptr<OpEqOpBase> op;
            switch(opSym)
            {
              case '+':op.reset(new AddEqOp(&vm));break;
              case '-':op.reset(new SubEqOp(&vm));break;
              case '*':op.reset(new MulEqOp(&vm));break;
              case '/':op.reset(new DivEqOp(&vm));break;
              case '%':op.reset(new ModEqOp(&vm));break;
            }
            op->left=tempExpr;
            op->right=rhs;
            PushOp(op,opPos);
          }
        }break;
        case ':':
        {
          if(ps.back().ps!=psIf)
          {
            throw ParsingException(c,"Unexpected :");
          }
          CondJumpOp* jop=(CondJumpOp*)vm.code[ps.back().idx];
          JumpOp* op=new JumpOp(&vm);
          ps.back().idx=vm.code.size();
          PushOp(op,c);
          jop->jumpCpFalse=vm.code.size();
          ps.back().data=1;
        }break;
        case '=':
        {
          if(sr.peekNext()=='=')
          {
            sr.getNext();
            std::auto_ptr<ForceAssignmentOp> op(new ForceAssignmentOp(&vm));
            op->left=tempExpr;
            op->right=ParseExpr(sr,mmExpr,c);
            PushOp(op,c);
          }else
          {
            std::auto_ptr<AssignmentOp> op(new AssignmentOp(&vm));
            op->left=tempExpr;
            op->right=ParseExpr(sr,mmExpr,c);
            PushOp(op,c);
          }
        }break;
        default:
        {
          sr.unget();
          tempExpr=ParseExpr(sr,mmExpr,c);break;
        }break;
      }
    }
    if(!ps.empty())
    {
      switch(ps.back().ps)
      {
        case psFunc:throw ParsingException(c,"End of function started at line %lu col %lu not found",ps.back().pos.line,ps.back().pos.col);
        case psMethod:throw ParsingException(c,"End of method started at line %lu col %lu not found",ps.back().pos.line,ps.back().pos.col);
        case psIf:throw ParsingException(c,"End of conditional statement started at line %lu col %lu not found",ps.back().pos.line,ps.back().pos.col);
        case psLoop:throw ParsingException(c,"End of loop started at line %lu col %lu not found",ps.back().pos.line,ps.back().pos.col);
        case psSwitch:throw ParsingException(c,"End of switch started at line %lu col %lu not found",ps.back().pos.line,ps.back().pos.col);
      }
    }
    PushOp(new EndOfCodeOp(&vm),c);
    vm.entryPoint=0;
  }

  template <class T>
  void PushOp(std::auto_ptr<T>& op,Pos pos)
  {
    op->idx=vm.code.size();
    op->pos=pos;
    vm.code.push_back(op.release());
  }
  void PushOp(OpCodeBase* op,Pos pos)
  {
    op->idx=vm.code.size();
    op->pos=pos;
    vm.code.push_back(op);
  }

  void ParseFunc(SourceReader& sr,Char start)
  {
    Char c=sr.getNext();
    if(c.c!='?' && !isValidIdent(c.c))
    {
      throw ParsingException(start,"Invalid function name '%c'",c.c);
    }
    bool method=false;
    if(c.c=='?')
    {
      c=sr.getNext();
      method=true;
      ps.back().ps=psMethod;
      if(!isValidIdent(c.c))
      {
        throw ParsingException(start,"Invalid method name '%c'",c.c);
      }
    }
    ps.back().pos.c=c.c;

    if(method)
    {
      vm.methods[c.c]=vm.code.size();
    }else
    {
      vm.funcs[c.c]=vm.code.size();
    }

    uchar nx=sr.peekNext();
    if(nx=='(')
    {
      sr.getNext();
      FuncInfo& f=method?mi[c.c]:fi[c.c];
      f.exists=true;
      bool needBreak=false;
      while(!sr.isEof() && !needBreak)
      {
        c=sr.getNext();
        if(c.c==')')break;
        if(c.c==',')continue;
        if(c.c==' ')continue;
        if(isValidIdent(c.c))
        {
          f.args.push_back(c.c);
          f.isRef.push_back(false);
        }else if(c.c=='&')
        {
          c=sr.getNext();
          if(!isValidIdent(c.c))
          {
            throw ParsingException(c,"Expected variable name");
          }
          f.args.push_back(c.c);
          f.isRef.push_back(true);
        }
        else
        {
          throw ParsingException(c,"Unexpected %c",c.c);
        }
      }
    }else
    {
      if(method)
      {
        mi[c.c].exists=true;
      }else
      {
        fi[c.c].exists=true;
      }
    }
  }

  void ParseLoop(SourceReader& sr,Char start)
  {
    Char c;
    c=sr.getNext();

    if(c.c=='<' || c.c=='>')
    {
      size_t i=ps.size()-1;
      bool loopFound=false;
      while(i>=0)
      {
        if(ps[i].ps==psLoop)
        {
          loopFound=true;
          break;
        }
        if(ps[i].ps==psFunc || ps[i].ps==psMethod)
        {
          break;
        }
        i--;
      }
      if(!loopFound)
      {
        if(c.c=='<')
        {
          throw ParsingException(start,"Continue outside loop context");
        }else
        {
          throw ParsingException(start,"Break outside loop context");
        }
      }
      ILoopStepOp* st=(ILoopStepOp*)vm.code[ps[i].idx];
      JumpOp* jop=new JumpOp(&vm);
      if(c.c=='<')
      {
        jop->jumpCp=st->idx;
      }else
      {
        ps[i].jumpFixes.push_back(jop);
      }
      PushOp(jop,start);
      return;
    }

    if(c.c==':')
    {
      InitLoopOp* op=new InitLoopOp(&vm);
      PushOp(op,start);
      ILoopStepOp* st=op->loopStep=new InfLoopStepOp(&vm);
      ParsingStackItem psi;
      psi.ps=psLoop;
      psi.idx=vm.code.size();
      psi.pos=start;
      PushOp(st,start);
      ps.push_back(psi);
      return;
    }
    if(c.c=='{')
    {
      InitLoopOp* op=new InitLoopOp(&vm);
      PushOp(op,start);
      ArrayLoopStepOp* st=new ArrayLoopStepOp(&vm);
      op->loopStep=st;
      ParsingStackItem psi;
      psi.ps=psLoop;
      psi.idx=vm.code.size();
      psi.pos=start;
      PushOp(st,start);
      ps.push_back(psi);
      c=sr.getNext();
      if(!isValidIdent(c.c))
      {
        throw ParsingException(c,"Variable name expected");
      }
      st->varName=c.c;
      c=sr.getNext();
      if(c.c!=':')
      {
        throw ParsingException(c,"Expected :");
      }
      st->expr=ParseExpr(sr,mmExpr,c);
      c=sr.getNext();
      if(c.c!='}')
      {
        throw ParsingException(c,"Expected }");
      }
      return;
    }
    bool isAnonymous=false;
    InitLoopOp* op=new InitLoopOp(&vm);
    PushOp(op,start);
    LoopStepOp* st=new LoopStepOp(&vm);
    op->loopStep=st;
    ParsingStackItem psi;
    psi.ps=psLoop;
    psi.idx=vm.code.size();
    psi.pos=start;
    PushOp(st,start);
    ps.push_back(psi);
    if(c.c=='`')
    {
      isAnonymous=true;
    }else
    {
      if(!isValidIdent(c.c))
      {
        throw ParsingException(c,"Expected variable name");
      }
      do{
        st->vars.push_back(c.c);
        c=sr.getNext();
      }while(c.c!='`');
    }
    do{
      st->initVal.push_back(ParseExpr(sr,mmExpr,c).release());
      c=sr.getNext();
      if(c.c!=',' && c.c!=':' && c.c!='<')
      {
        throw ParsingException(c,"Expected ,< or :");
      }
    }while(c.c!=':' && c.c!='<');
    if(!isAnonymous && st->vars.size()!=st->initVal.size())
    {
      throw ParsingException(start,"Number of loops variables and init values do not match");
    }
    st->isInclusive=c.c==':';
    size_t dim=st->initVal.size();
    for(size_t i=0;i<dim;i++)
    {
      st->finVal.push_back(ParseExpr(sr,mmExpr,c).release());
      if(i<dim-1)
      {
        c=sr.getNext();
        if(c.c!=',')
        {
          throw ParsingException(c,"Expected ,");
        }
      }
    }
  }

  enum MatchMode{
    mmMayBeExpr,mmExpr,mmExprMin,mmArgument,mmBracketExpr
  };
  enum Op{
    opNone,opAdd,opSub,opDiv,opMul,opMod,opNegate,opRandom,opLength
  };

  std::auto_ptr<Expression> makeOp(std::auto_ptr<Expression>& left,std::auto_ptr<Expression>& right,Op& op)
  {
    std::auto_ptr<Expression> rv;
    switch(op)
    {
      case opAdd:
      {
        std::auto_ptr<AddOpExpr> ex(new AddOpExpr(&vm));
        ex->left=left;
        ex->right=right;
        rv=ex;
      }break;
      case opSub:
      {
        std::auto_ptr<SubOpExpr> ex(new SubOpExpr(&vm));
        ex->left=left;
        ex->right=right;
        rv=ex;
      }break;
      case opDiv:
      {
        std::auto_ptr<DivOpExpr> ex(new DivOpExpr(&vm));
        ex->left=left;
        ex->right=right;
        rv=ex;
      }break;
      case opMul:
      {
        std::auto_ptr<MulOpExpr> ex(new MulOpExpr(&vm));
        ex->left=left;
        ex->right=right;
        rv=ex;
      }break;
      case opMod:
      {
        std::auto_ptr<ModOpExpr> ex(new ModOpExpr(&vm));
        ex->left=left;
        ex->right=right;
        rv=ex;
      }break;
      case opNegate:
      {
        std::auto_ptr<NegateExpr> ex(new NegateExpr(&vm));
        ex->expr=right;
        rv=ex;
      }break;
      case opRandom:
      {
        std::auto_ptr<RandomExpr> ex(new RandomExpr(&vm));
        ex->minEx=left;
        ex->maxEx=right;
        rv=ex;
      }break;
      case opLength:
      {
        std::auto_ptr<LengthExpr> ex(new LengthExpr(&vm));
        ex->base=right;
        rv=ex;
      }break;
      case opNone:throw ParsingException(Char(),"Fatal parsing error");
    }
    op=opNone;
    return rv;
  }

  std::auto_ptr<Expression> ParseExpr(SourceReader& sr,MatchMode mm,Char start)
  {
    std::auto_ptr<Expression> rv;
    std::auto_ptr<Expression> left;
    Op op=opNone;
    Char c;
    int tmpInt=0;
    std::string tmpStr;
    char nx=0;
    bool derefMode=false;
    if(sr.peekNext()=='&')
    {
      sr.getNext();
      c=sr.getNext();
      if(c.c=='?')
      {
        c=sr.getNext();
        if(!mi[c.c].exists)
        {
          throw ParsingException(c,"Method %c not found",c.c);
        }
        std::auto_ptr<MethodRefConstructorExpr> rc(new MethodRefConstructorExpr(&vm));
        rc->funcCp=vm.methods[c.c];
        rc->args=mi[c.c].args;
        rc->isRef=mi[c.c].isRef;
        rv=rc;
        return rv;
      }else
      {
        if(!fi[c.c].exists)
        {
          throw ParsingException(c,"Function %c not found",c.c);
        }
        std::auto_ptr<FuncRefConstructorExpr> rc(new FuncRefConstructorExpr(&vm));
        rc->funcCp=vm.funcs[c.c];
        rc->args=fi[c.c].args;
        rc->isRef=fi[c.c].isRef;
        rv=rc;
        return rv;
      }
    }
    if(sr.peekNext()=='^')
    {
      sr.getNext();
      std::auto_ptr<AliasConstructorExpr> rc(new AliasConstructorExpr(&vm));
      rc->expr=ParseExpr(sr,mmExpr,c);
      rv=rc;
      return rv;
    }

    while(!sr.isEof())
    {
      if(strchr(" !}])=,:;`^$@<>\\|",nx=sr.peekNext()))
      {
        if(op!=opNone)
        {
          if(!rv.get() && mm!=mmMayBeExpr)
          {
            throw ParsingException(c,"Expected expression");
          }
          rv=makeOp(left,rv,op);
        }
        if(nx==')' && mm==mmBracketExpr)
        {
          sr.getNext();
        }
        break;
      }
      if(rv.get() && (nx=='?' || nx=='#' || nx=='&'))
      {
        if(op==opNone)
        {
          break;
        }
        rv=makeOp(left,rv,op);
        break;
      }
      if(mm==mmExprMin && isOp(nx) && rv.get())
      {
        break;
      }
      c=sr.getNext();
      if(isOp(c.c))
      {
        if(op!=opNone)
        {
          if(!rv.get())
          {
            if(!canBeUnaryOp(c.c))
            {
              throw ParsingException(c,"Expected expression");
            }
          }else
          {
            rv=makeOp(left,rv,op);
          }
        }else
        {
          if(sr.peekNext()=='=')
          {
            sr.unget();
            break;
          }
        }
      }
      switch(c.c)
      {
        case '?':
        {
          std::auto_ptr<CondExpr> ex(new CondExpr(&vm));
          ex->cond=ParseCond(sr,c);
          c=sr.getNext();
          if(c.c!='`')
          {
            throw ParsingException(c,"Expected `");
          }
          ex->trueExpr=ParseExpr(sr,mmExpr,c);
          c=sr.getNext();
          if(c.c!=':')
          {
            throw ParsingException(c,"Expected :");
          }
          ex->falseExpr=ParseExpr(sr,mmExpr,c);
          c=sr.getNext();
          if(c.c!='\\')
          {
            throw ParsingException(c,"Expected \\");
          }
          rv=ex;
        }break;
        case '+':
        {
          if(sr.peekNext()=='+')
          {
            sr.getNext();
            if(rv.get())
            {
              std::auto_ptr<PostIncExpr> ex(new PostIncExpr(&vm));
              ex->expr=rv;
              rv=ex;
            }else
            {
              std::auto_ptr<PreIncExpr> ex(new PreIncExpr(&vm));
              ex->expr=ParseExpr(sr,mmExprMin,c);
              rv=ex;
            }
            break;
          }
          if(!rv.get())
          {
            throw ParsingException(c,"Unexpected +");
          }
          left=rv;
          op=opAdd;
        }break;
        case '-':
        {
          if(sr.peekNext()=='-')
          {
            sr.getNext();
            if(rv.get())
            {
              std::auto_ptr<PostDecExpr> ex(new PostDecExpr(&vm));
              ex->expr=rv;
              rv=ex;
            }else
            {
              std::auto_ptr<PreDecExpr> ex(new PreDecExpr(&vm));
              ex->expr=ParseExpr(sr,mmExprMin,c);
              rv=ex;
            }
            break;
          }
          if(!rv.get())
          {
            /*if(op==opNone)
            {
              op=opNegate;
              break;
            }*/
            std::auto_ptr<NegateExpr> ex(new NegateExpr(&vm));
            ex->expr=ParseExpr(sr,mmExprMin,c);
            rv=ex;
            break;
          }
          left=rv;
          op=opSub;
        }break;
        case '*':
        {
          if(!rv.get())
          {
            derefMode=true;
            break;
          }
          left=rv;
          op=opMul;
        }break;
        case '/':
        {
          if(!rv.get())
          {
            throw ParsingException(c,"Unexpected /");
          }
          left=rv;
          op=opDiv;
        }break;
        case '%':
        {
          if(!rv.get())
          {
            throw ParsingException(c,"Unexpected %");
          }
          left=rv;
          op=opMod;
        }break;
        case '~':
        {
          if(!rv.get())
          {
            std::auto_ptr<RandomExpr> ex(new RandomExpr(&vm));
            ex->maxEx=ParseExpr(sr,mmExprMin,c);
            rv=ex;
            break;
          }
          left=rv;
          op=opRandom;
        }break;
        case '#':
        {
          std::auto_ptr<LengthExpr> ex(new LengthExpr(&vm));
          ex->base=ParseExpr(sr,mmExprMin,c);
          rv=ex;
        }break;
        case '(':
          if(rv.get())
          {
            throw ParsingException(c,"Unexpected (");
          }
          rv=ParseExpr(sr,mmBracketExpr,c);
          break;
        case '"':
        {
          if(rv.get())
          {
            throw ParsingException(c,"Unexpected \"");
          }
          tmpStr="";
          std::vector<InterStrExpr::Item*> is;
          while(!sr.isEof())
          {
            Char c=sr.getNext();
            if(c.c=='"')
            {
              break;
            }
            if(c.c=='\\')
            {
              c=sr.getNext();
              if(c.c=='n')
              {
                tmpStr+="\n";
                continue;
              }else if(c.c=='c' || c.c=='b')
              {
                if(tmpStr.length())
                {
                  is.push_back(new InterStrExpr::Item(tmpStr));
                  tmpStr="";
                }
                if(!isdigit(sr.peekNext()))
                {
                  throw ParsingException(c,"Expected digit");
                }
                int clr=0;
                while(!sr.isEof() && isdigit(sr.peekNext()))
                {
                  clr*=10;
                  clr+=sr.getNext().c-'0';
                }
                is.push_back(new InterStrExpr::Item(c.c=='c'?InterStrExpr::itSetColor:InterStrExpr::itSetBg,clr));
                continue;
              }else if(c.c=='r')
              {
                if(tmpStr.length())
                {
                  is.push_back(new InterStrExpr::Item(tmpStr));
                  tmpStr="";
                }
                is.push_back(new InterStrExpr::Item());
                continue;
              }else if(c.c=='R')
              {
                if(tmpStr.length())
                {
                  is.push_back(new InterStrExpr::Item(tmpStr));
                  tmpStr="";
                }
                is.push_back(new InterStrExpr::Item());
                is.push_back(new InterStrExpr::Item());
                continue;
              }
            }else if(c.c=='$')
            {
              if(tmpStr.length())
              {
                is.push_back(new InterStrExpr::Item(tmpStr));
                tmpStr="";
              }
              if(isValidIdent(sr.peekNext()))
              {
                uchar v=sr.getNext().c;
                if(!isValidIdent(sr.peekNext()) && sr.peekNext()!='(' && sr.peekNext()!='[')
                {
                  is.push_back(new InterStrExpr::Item(v));
                  continue;
                }
                sr.unget();
              }
              if(sr.peekNext()=='(')
              {
                sr.getNext();
                is.push_back(new InterStrExpr::Item(ParseExpr(sr,mmBracketExpr,c).release()));
              }else
              {
                is.push_back(new InterStrExpr::Item(ParseExpr(sr,mmExprMin,c).release()));
              }
              continue;
            }
            tmpStr+=c.c;
          }
          if(is.empty())
          {
            rv.reset(new StrConstExpr(&vm,tmpStr));
          }else
          {
            if(tmpStr.length())
            {
              is.push_back(new InterStrExpr::Item(tmpStr));
            }
            InterStrExpr* ex=new InterStrExpr(&vm);
            ex->items=is;
            rv.reset(ex);
          }
        }break;

        case '{':
        {
          if(rv.get())
          {
            throw ParsingException(c,"Unexpected {");
          }
          if(sr.peekNext()=='}')
          {
            sr.getNext();
            rv.reset(new ArrayConstructorExpr(&vm));
            break;
          }
          if(sr.peekNext()==':')
          {
            sr.getNext();
            if(sr.getNext().c!='}')
            {
              throw ParsingException(c,"Expected }");
            }
            rv.reset(new StructConstructorExpr(&vm));
            break;
          }
          if(isValidIdent(sr.peekNext()))
          {
            Char v=sr.getNext();
            if(sr.peekNext()==':')
            {
              sr.unget();
              std::auto_ptr<StructConstructorExpr> ex(new StructConstructorExpr(&vm));
              for(;;)
              {
                v=sr.getNext();
                if(sr.getNext().c!=':')
                {
                  throw ParsingException(c,"Expected :");
                }
                ex->fields.push_back(v.c);
                ex->elements.push_back(ParseExpr(sr,mmExpr,c).release());
                v=sr.getNext();
                if(v.c==',')
                {
                  continue;
                }else if(v.c=='}')
                {
                  break;
                }else
                {
                  throw ParsingException(v,"Expected , or }");
                }
              }
              rv=ex;
              break;
            }else
            {
              sr.unget();
            }
          }
          std::auto_ptr<ArrayConstructorExpr> ex(new ArrayConstructorExpr(&vm));

          for(;;)
          {
            ex->elements.push_back(ParseExpr(sr,mmExpr,c).release());
            Char n=sr.getNext();
            if(n.c==',')
            {
              continue;
            }else
            if(n.c=='}')
            {
              break;
            }else
            {
              throw ParsingException(n,"Expected , or }");
            }
          }
          rv=ex;
        }break;

        case '[':
        {
          if(!rv.get())
          {
            throw ParsingException(c,"Unexpected [");
          }
          do{
            std::auto_ptr<ArrayAccessExpr> ex(new ArrayAccessExpr(&vm));
            ex->base=rv;
            ex->index=ParseExpr(sr,mmExpr,c);
            rv=ex;
            c=sr.getNext();
          }while(c.c==',');
          if(c.c!=']')
          {
            throw ParsingException(c,"Expected ]");
          }
        }break;

        case '.':
        {
          if(rv.get())
          {
            throw ParsingException(c,"Unexpected .");
          }
          size_t i=ps.size()-1;
          bool foundMethod=false;
          if(!ps.empty())
          {
            while(i>=0)
            {
              if(ps[i].ps==psMethod)
              {
                foundMethod=true;
              }
              if(ps[i].ps==psFunc)
              {
                break;
              }
              i--;
            }
          }
          if(!foundMethod)
          {
            throw ParsingException(c,"Unexpected self . reference in non-method");
          }
          rv.reset(new SelfAccessExpr(&vm));
        }break;

        case '\'':
        {
          if(!rv.get())
          {
            bool haveFunc=false;
            size_t idx=ps.size()-1;
            if(!ps.empty())
            {
              while(idx>=0)
              {
                if(ps[idx].ps==psFunc || ps[idx].ps==psMethod)
                {
                  haveFunc=true;
                  break;
                }
                idx--;
              }
            }
            if(!haveFunc)
            {
              throw ParsingException(c,"Locals are only available in functions and methods");
            }
          }
          std::auto_ptr<StructSliceConstructorExpr> op(new StructSliceConstructorExpr(&vm));
          op->base=rv;
          while(!sr.isEof() && isValidIdent(sr.peekNext()))
          {
            op->fields.push_back(sr.getNext().c);
          }
          rv=op;
        }break;

        default:
        {
          if(isdigit(c.c))
          {
            if(rv.get()/* && op==opNone*/)
            {
              std::auto_ptr<ArrayAccessConstExpr> ex(new ArrayAccessConstExpr(&vm));
              ex->base=rv;
              int idx=c.c-'0';
              while(!sr.isEof() && isdigit(sr.peekNext()))
              {
                idx*=10;
                idx+=sr.peekNext()-'0';
                sr.getNext();
              }
              ex->index=idx;
              rv=ex;
              break;
            }
            tmpInt=c.c-'0';
            while(!sr.isEof() && isdigit(sr.peekNext()))
            {
              tmpInt*=10;
              tmpInt+=sr.peekNext()-'0';
              sr.getNext();
            }
            rv.reset(new IntConstExpr(&vm,tmpInt));
          }else
          if(isValidIdent(c.c))
          {
            if(sr.peekNext()=='(')
            {
              if(!derefMode)
              {
                if(rv.get())
                {
                  if(!mi[c.c].exists)
                  {
                    throw ParsingException(c,"Method %c not declared",c.c);
                  }
                }else
                {
                  if(!fi[c.c].exists)
                  {
                    throw ParsingException(c,"Function %c not declared",c.c);
                  }
                }
              }
              sr.getNext();
              if(derefMode)
              {
                derefMode=false;
                if(rv.get())
                {
                  std::auto_ptr<MethodRefDerefExpr> op(new MethodRefDerefExpr(&vm));
                  std::auto_ptr<VarAccessExpr> va(new VarAccessExpr(&vm));
                  va->var=c.c;
                  op->base=va;
                  op->self=rv;
                  for(;;)
                  {
                    if(sr.peekNext()==')')
                    {
                      sr.getNext();
                      break;
                    }
                    std::auto_ptr<Expression> arg(ParseExpr(sr,mmArgument,c));
                    if(sr.peekNext()==' '||sr.peekNext()==',')
                    {
                      sr.getNext();
                    }
                    op->argVals.push_back(arg.release());
                  }
                  if(sr.peekNext()==')')
                  {
                    sr.getNext();
                  }
                  rv=op;
                }else
                {
                  std::auto_ptr<FuncRefDerefExpr> op(new FuncRefDerefExpr(&vm));
                  std::auto_ptr<VarAccessExpr> va(new VarAccessExpr(&vm));
                  va->var=c.c;
                  op->base=va;
                  for(;;)
                  {
                    if(sr.peekNext()==')')
                    {
                      sr.getNext();
                      break;
                    }
                    std::auto_ptr<Expression> arg(ParseExpr(sr,mmArgument,c));
                    if(sr.peekNext()==' '||sr.peekNext()==',')
                    {
                      sr.getNext();
                    }
                    op->argVals.push_back(arg.release());
                  }
                  if(sr.peekNext()==')')
                  {
                    sr.getNext();
                  }
                  rv=op;
                }
              }else
              {
                if(rv.get())
                {
                  std::auto_ptr<MethodCallExpr> op(new MethodCallExpr(&vm));
                  FuncInfo& f=mi[c.c];
                  op->fname=c.c;
                  op->base=rv;
                  op->methodCp=vm.methods[c.c];
                  for(size_t i=0;i<f.args.size();i++)
                  {
                    MethodCallExpr::FuncArg fa;
                    fa.varName=f.args[i];
                    fa.expr=ParseExpr(sr,mmArgument,c).release();
                    fa.isRef=f.isRef[i];
                    if(sr.peekNext()==' '||sr.peekNext()==',')
                    {
                      sr.getNext();
                    }
                    op->args.push_back(fa);
                  }
                  if(sr.peekNext()==')')
                  {
                    sr.getNext();
                  }
                  rv=op;
                }else
                {
                  std::auto_ptr<FuncCallExpr> op(new FuncCallExpr(&vm));
                  FuncInfo& f=fi[c.c];
                  op->fname=c.c;
                  op->funcCp=vm.funcs[c.c];
                  for(size_t i=0;i<f.args.size();i++)
                  {
                    FuncCallExpr::FuncArg fa;
                    fa.varName=f.args[i];
                    fa.expr=ParseExpr(sr,mmArgument,c).release();
                    fa.isRef=f.isRef[i];
                    if(sr.peekNext()==' '||sr.peekNext()==',')
                    {
                      sr.getNext();
                    }
                    op->args.push_back(fa);
                  }
                  if(sr.peekNext()==')')
                  {
                    sr.getNext();
                  }
                  rv=op;
                }
              }
            }else
            if(rv.get())
            {
              std::auto_ptr<FieldAccessExpr> fa(new FieldAccessExpr(&vm));
              fa->base=rv;
              fa->field=c.c;
              rv=fa;
            }else
            {
              if(isValidIdent(c.c))
              {
                VarAccessExpr* va=new VarAccessExpr(&vm);
                va->var=c.c;
                rv.reset(va);
              }else
              {
                throw ParsingException(c,"Unexpected %c",c.c);
              }
            }
          }else
          {
            throw ParsingException(c,"Unexpected %c",c.c);
          }
        }
      }
    }
    if(op!=opNone)
    {
      if(!rv.get())
      {
        throw ParsingException(c,"Expression expected");
      }
      rv=makeOp(left,rv,op);
    }
    if(!rv.get() && mm!=mmMayBeExpr)
    {
      throw ParsingException(start,"Expression expected");
    }
    return rv;
  }

  std::auto_ptr<BoolExpression> ParseCond(SourceReader& sr,Char start)
  {
    std::auto_ptr<BoolExpression> left;
    if(sr.peekNext()=='(')
    {
      sr.getNext();
      left=ParseCond(sr,start);
      if(sr.peekNext()=='`')
      {
        return left;
      }
    }else if(sr.peekNext()=='!')
    {
      sr.getNext();
      std::auto_ptr<BoolNot> op(new BoolNot);
      op->base=ParseCond(sr,start);
      left=op;
      if(sr.peekNext()=='`')
      {
        return left;
      }
    }
    std::auto_ptr<Expression> expr=ParseExpr(sr,mmExpr,start);
    if(sr.peekNext()=='`')
    {
      std::auto_ptr<BoolSimpleExpr> op(new BoolSimpleExpr());
      op->expr=expr;
      left=op;
      return left;
    }
    while(!sr.isEof())
    {
      if(sr.peekNext()=='`')
      {
        break;
      }
      Char c=sr.getNext();
      if(c.c=='`' || c.c==')')
      {
        if(!left.get())
        {
          throw ParsingException(c,"Empty condition");
        }
        break;
      }
      if((c.c=='|' || c.c=='&') && !left.get() && expr.get())
      {
        std::auto_ptr<BoolSimpleExpr> op(new BoolSimpleExpr());
        op->expr=expr;
        left=op;
      }
      switch(c.c)
      {
        case '|':
        {
          std::auto_ptr<BoolOr> op(new BoolOr);
          op->left=left;
          op->right=ParseCond(sr,c);
          left=op;
        }break;
        case '&':
        {
          std::auto_ptr<BoolAnd> op(new BoolAnd);
          op->left=left;
          op->right=ParseCond(sr,c);
          left=op;
        }break;
        case '=':
        {
          if(!expr.get())
          {
            throw ParsingException(c,"Unexpected =");
          }
          std::auto_ptr<BoolEq> op(new BoolEq);
          op->left=expr;
          op->right=ParseExpr(sr,mmExpr,c);
          left=op;
        }break;
        case '!':
        {
          if(!expr.get())
          {
            throw ParsingException(c,"Unexpected !");
          }
          std::auto_ptr<BoolNEq> op(new BoolNEq);
          op->left=expr;
          op->right=ParseExpr(sr,mmExpr,c);
          left=op;
        }break;
        case '<':
        {
          if(!expr.get())
          {
            throw ParsingException(c,"Unexpected <");
          }
          if(sr.peekNext()=='=')
          {
            sr.getNext();
            std::auto_ptr<BoolLtEq> op(new BoolLtEq);
            op->left=expr;
            op->right=ParseExpr(sr,mmExpr,c);
            left=op;
          }else
          {
            std::auto_ptr<BoolLt> op(new BoolLt);
            op->left=expr;
            op->right=ParseExpr(sr,mmExpr,c);
            left=op;
          }
        }break;
        case '>':
        {
          if(!expr.get())
          {
            throw ParsingException(c,"Unexpected >");
          }
          if(sr.peekNext()=='=')
          {
            sr.getNext();
            std::auto_ptr<BoolGtEq> op(new BoolGtEq);
            op->left=expr;
            op->right=ParseExpr(sr,mmExpr,c);
            left=op;
          }else
          {
            std::auto_ptr<BoolGt> op(new BoolGt);
            op->left=expr;
            op->right=ParseExpr(sr,mmExpr,c);
            left=op;
          }
        }break;
        default:
        {
          throw ParsingException(c,"Unexpected %c",c.c);
        }
      }
    }
    return left;
  }

  bool isOp(uchar c)
  {
    return (c=='+' || c=='-' || c=='*' || c=='/' || c=='%' || c=='~' || c=='#');
  }

  bool canBeUnaryOp(uchar c)
  {
    return c=='-' || c=='~' || c=='#';
  }

  bool isValidIdent(uchar c)
  {
    return (c>='A'&&c<='Z')||(c>='a'&&c<='z')||c=='_';
  }

  struct FuncInfo{
    FuncInfo():exists(false){}
    std::vector<uchar> args;
    std::vector<bool> isRef;
    bool exists;
  };

  FuncInfo fi[256];
  FuncInfo mi[256];

  std::vector<ParsingStackItem> ps;
  VM& vm;
protected:
  void operator=(const Parser& rhs);
};


int main(int argc,char* argv[])
{
  srand(time(0)^0xaaaaaaaaul);
  srand(rand());
  std::string inFile="stdin";
  std::string source;
  FILE *f=stdin;
  int optIdx=1;
  std::string dumpFile;
  bool useCurses=true;
  while(optIdx<argc)
  {
    if(argv[optIdx][0]=='-')
    {
      char opt=argv[optIdx][1];
      if(opt=='d')
      {
        dumpFile=argv[optIdx]+2;
      }else if(opt=='n')
      {
        useCurses=false;
      }else if(opt=='v' || opt=='h' || opt=='?')
      {
        fprintf(stderr,"Dense script v0.1 (c) 2009 Konstantin Stupnik\n");
        if(opt!='v')
        {
          fprintf(stderr,"Usage: ds [-ddumpfile] [-n] [scriptfile]\n");
          fprintf(stderr,"Usage: ds [-ddumpfile] [-n] -e script source text\n");
          fprintf(stderr,"-ddumpfile - dump script pseudocode into file\n");
          fprintf(stderr,"-n - do not use curses\n");
          fprintf(stderr,"-v - print version info\n");
          fprintf(stderr,"-h or -? - print command line help\n");
          return 0;
        }
      }else if(opt=='e')
      {
        inFile="command line";
        while(++optIdx<argc)
        {
          source+=argv[optIdx];
        }
        f=0;
      }
      else if(opt=='r')
      {
        std::string errFile=argv[optIdx]+2;
        freopen(errFile.c_str(),"w",stderr);
      }
      else
      {
        fprintf(stderr,"Unknown option:%s",argv[optIdx]);
        return 1;
      }
    }else
    {
      break;
    }
    optIdx++;
  }
  if(optIdx<argc)
  {
    f=fopen(argv[optIdx],"rt");
    inFile=argv[optIdx];
  }
  if(!f && !source.length())
  {
    fprintf(stderr,"Failed to open file %s for reading.\n",inFile.c_str());
    return 1;
  }
  if(f)
  {
    char buf[1024];
    while(fgets(buf,1024,f))
    {
      source+=buf;
    }
    if(inFile!="stdin")
    {
      fclose(f);
    }
  }
  bool cursesInit=false;
  try{
    VM vm;
    Parser p(vm);
    p.Parse(inFile,source);
    if(dumpFile.length())
    {
      std::string dump;
      for(size_t i=0;i<vm.code.size();i++)
      {
        vm.code[i]->dump(dump);
      }
      FILE* g=fopen(dumpFile.c_str(),"wt");
      fprintf(g,"%s",dump.c_str());
      fclose(g);
    }
    if(useCurses)
    {
      initscr();
      raw();
      start_color();
      noecho();
      for(short c=0;c<8;c++)
      {
        for(short b=0;b<8;b++)
        {
          short cc=c;
          short bb=b;
#ifndef WIN32
          //       0 1 2 3 4 5 6 7
          short o[]={0,4,2,6,1,5,3,7};
          cc=o[cc];
          bb=o[bb];
#endif
          init_pair((short)b*8+c+1,cc,bb);
        }
      }
      cursesInit=true;
    }
    vm.useCurses=useCurses;
    vm.Run();
  }catch(std::exception& e)
  {
    fprintf(stderr,"Exception:%s\n",e.what());
    if(cursesInit)
    {
      endwin();
    }
#ifdef DEBUG_MEMORY
    DumpUnfreed(true);
#endif
    return 1;
  }
  if(cursesInit)
  {
    endwin();
  }
#ifdef DEBUG_MEMORY
  DumpUnfreed(true);
#endif
  return 0;
}

