//==============================================================================
//  This is where parser is used, yay.
//==============================================================================
unit Structs02;

//==============================================================================
//  INTERFACE
//==============================================================================
interface

procedure Step02(var globalsblock:string; var execblock:string; var firstblock:string; var secondblock:string);


//==============================================================================
//  IMPLEMENTATION
//==============================================================================
implementation
uses StructVariables, StringHash, JHInput, TextOnly, TextCommon, SysUtils,
    JASSerException, JStruct, Translate, Constants, Member, Jasslib, Prototypes,
    Classes, Token, Symbol, PseudoRandom, JType, JassHelperConfigFile,
    JassHelperSymbols, GoldParser, ImportPaths, JHInterface, JHParams,
    Windows, StructsSLK;

var
       whitespace : string;  // current line indentation string
    StructStrings: array of string;
    StructStringN:integer;
    Parser:TGoldParser=nil;

  


//==============================================================================
//  Returns textual representation of terminal token.
//  It is recursive so it works even for nested token terminals.
//  Returns '' for empty nonterminals
//  Returns '?' for non-empty nonterminals
//==============================================================================
function structs_evaluate_terminal(tok:TToken):string;
begin
    if(tok.Kind<>SymbolTypeNonterminal) then begin
        result:=tok.DataVar;
    end else if(tok.Reduction.TokenCount=0) then begin
        result:='';                                                 
    end else if(tok.Reduction.TokenCount>1) then begin
        result:='?';
    end else begin
        result:=structs_evaluate_terminal(tok.Reduction.tokens[0]);
    end;
end;

//==============================================================================
function structs_evaluatecode({const} s:string; var res:string;   fromstruct:integer; const pos:integer; const insetstatement:boolean=false):boolean; forward;
//if it is a correct global declaration, returns true and reevaluated version is in res.
//otherwise, returns false and error is in res.
function structs_evaluateglobal(const s:string; var res:string; const fromstruct:integer=-1):boolean;
var
   constant,isarray:boolean;
   word,name,assign, typename:string;
   x,h:integer;
begin
    // [constant] <type (possibly struct type)> [array] name [= assign]
       // constant structs simply don't have any sense.
       // struct types must be replaced with integer
       // and identifiertypes should make it point to the struct type id.
       // if we evaluated assign, it would later add issues cause it is impossible to declare functions before globals in war3map.j
       // so global declarations can't use . syntax.

   GetLineWord(s,word,x);
   constant:=(word='constant');
   if constant then begin
       GetLineWord(s,word,x,x);
   end;
   typename := word;

   //now word holds a possibly struct type.
   h:= StructHash.ValueOf(typename);
   if (h<>-1) and constant then begin
       res:='constant structs are not supported';result:=false;exit;
   end;
   GetLineToken(s,name,x,x);
   isarray:=(name='array');
   if isarray then begin
       GetLineToken(s,name,x,x);
   end;
   if (name='') then begin
       res:='Expected a name';result:=false;exit;
   end;
   if (not ValidIdentifierName(name)) then begin
       res:='Invalid identifier name: '+name;result:=false;exit;
   end;
   if (h<>-1) then begin
       VerifyRedeclarationRaise(RecCurrentLine,name);
       if(isarray) then IdentifierTypes.Add(name,h+ARRAYEDTYPE)
       else IdentifierTypes.Add(name,h);
   end;

   if GetAssigment(s,assign,x) then begin
       if(assign='') then begin
           res:='Missing expression'+name;result:=false;exit;
       end;
   end else assign:='';
   if(assign<>'') then begin
        if not structs_evaluatecode(assign, res, fromstruct, 1) then begin
            Result := false;
            exit;
        end;
        assign := res;

   end;

   if( word = 'key') then begin
       res:='';
       if(assign<>'') then res:='Unable to assign keys.'
       else if(isarray) then res:='key arrays are not allowed.';

       if(res<>'') then begin
          result:=false;
          exit;
       end;
       Concatenate4(res,'constant integer ',name,'=',GetHashtableKey());
       result:=true;
       exit;
   end;

   if ((assign<>'') and isarray) then begin
      res:='Cannot initialize arrays';result:=false;exit;
   end;
   if( h<>-1) then begin
        typename := 'integer';
   end;
   if (isarray) then
       res:=typename+' array '+name
   else if ( constant) then
       Concatenate4(res,'constant '+typename+' ',name,'=',assign)
   else if(assign='') then
       res:=typename+' '+name
   else
       Concatenate4(res,typename+' ',name,'=',assign);
   Result:=true;
end;


//==============================================================================
//if it is a correct function declaration, returns true and reevaluated version is in res.
//otherwise, returns false and error is in res.
function structs_evaluatefunction(const s:string; var res:string):boolean;
var
    x,L,k,h,indent:integer;
    word,name,argname,argtype:string;
begin


    GetLineWord(s,word,x);
    indent:=x-Length(word)-1;

    res:='';
    while(indent>0) do begin
        SWrite(res,' ');
        indent:=indent-1;
    end;
    if(word='constant') then begin
        SWrite(res,'constant ');
        GetLineWord(s,word,x,x);
    end;
    if(word<>'function') then begin
        res:='';Result:=false;Exit;
    end;
    SWrite(res,'function ');
    GetLineWord(s,name,x,x);
    if( not(validIdentifierName(name))) then begin
        res:='Not a valid function name: '+name;Result:=false;Exit;
    end;
    SWrite(res,name);
    if(not comparelineword('takes',s,x,x)) then begin
        res:='Expected "takes"';Result:=false;Exit;
    end;
    SWrite(res,' takes ');
    GetLineWord(s,word,x,x);
    if(word='nothing') then begin
        SWrite(res,'nothing');
        //no arguments

    end else begin
        L:=Length(s);
        x:=x-Length(word);
      while(true) do begin
        GetLineWord(s,argtype,x,x);
        if(argtype='') then begin
            res:='Expected an argument type';result:=false;exit;
        end;
        while(x<=L) and ((s[x]=' ') or (s[x]=#9)) do begin
            x:=x+1;
        end;
        if(x>L) then begin
            res:='Expected an argument name';result:=false;exit;
        end;
        k:=x;
        while(x<=L) and (s[x]<>' ') and (s[x]<>#9) and (s[x]<>',') do begin
            x:=x+1;
        end;
        argname:=Copy(s,k,x-k);
        while(x<=L) and ((s[x]=#9) or (s[x]=' ')) do begin
            x:=x+1;
        end;
        if(x>L) then begin
            res:='Expected , or returns';result:=false;exit;
        end;

        h:=StructHash.ValueOf(argtype);
        if(h<>-1) then begin
            SWrite(res,'integer ');

            VerifyRedeclarationRaise(RecCurrentLine,argname,true);
            LocalIdentifierTypes.Add(argname,h);

        end else begin
            VerifyRedeclarationRaise(RecCurrentLine,argname,true);
            LocalIdentifierTypes.Add(argname,-2);
            SWrite(res,argtype);
            SWrite(res,' ');
        end;
        SWrite(res,argname);
        if (x<=L) and (s[x]=',') then begin
            x:=x+1; //continue
            SWrite(res,',');
        end else break;


      end;
    end;
    if(not CompareLineWord('returns',s,x,x)) then begin
        res:='Expected returns';result:=false;exit;
    end;
    Swrite(res,' returns ');
    GetLineWord(s,word,x,x);
    h:=StructHash.ValueOf(word);
    if(h<>-1) then begin
        Swrite(res,'integer');
        // we already verified redeclaration before, no need for this: 
        //VerifyRedeclarationRaise(RecCurrentLine,name);
        IdentifierTypes.Add(name,h);

    end else begin
        Swrite(res,word);
    end;
    Result:=true;



end;


//==============================================================================
//  Recursively gets text of whole parser rule.
//  (tokes have tree structure)
//==============================================================================
function GetTokenText(tok: TToken):string;
var i, subtokens: integer;
begin
    if(tok.Kind = SymbolTypeNonterminal) then begin
        subtokens := tok.Reduction.TokenCount;
        result := '';
        for i := 0 to subtokens-1 do begin
            result := result + GetTokenText(tok.Reduction.tokens[i]);
        end;
    end else begin
        result:=tok.DataVar + ' ';
    end;
end;

//==============================================================================
function evaluate_value_type( const wanted:Tvtype;  var s:string; var typ:Tvtype):boolean;
begin
    if (wanted.name ='_unknown') or (typ.name='_unknown') then begin
        result:=true;
        exit;
    end;
    if(wanted.name ='boolexpr') and (typ.name='code') then begin
        s:='Condition('+s+')';
        typ:=wanted;
        result:=true;
        exit;
    end;
    result:=true;
end;

//==============================================================================
function structs_evaluate_rec(tok: TToken; var res:string; var typ:Tvtype; fromstruct:integer; const pos:integer):boolean;overload; forward;
function structs_evaluate_JassLibArguments( const funname: string; tok:TToken; var res:string; var typ:Tvtype; fromstruct:integer; pos:integer):boolean;
 var
    ctok:TToken;
    red:Treduction;
    func:TJassFunc;
    i:integer;
    typ1: Tvtype;
    res1: string;
    argtok: Array of TToken;
    an : integer;
begin


   result:=false;
   func := GetJassFuncDefinition(funname);
   if (func = nil) then begin
       res:='[internal error] Expected a function?';
       exit;
   end;
   res:='';
   SetLength(argtok,func.arguments.Count);
   an:=0;
   ctok:=nil;
   while(tok<>nil) do begin
       red:=tok.Reduction;

       case RuleConstants(Red.ParentRule.TableIndex) of
          RULE_ARGUMENTS: (* <Arguments> ::= <Expression> *)
          begin
              tok := nil;
              ctok:=red.Tokens[0];
          end;
          RULE_ARGUMENTS_COMMA: (* <Arguments> ::= <Expression> , <Arguments> *)
          begin
              ctok:=red.Tokens[0];
              tok:=red.Tokens[2];
          end;
          else begin
              // ctok:=nil;
              break;
          end;
       end;
       if(an = func.arguments.Count) then begin
           res:='Too many arguments given to function : '+funname;
           exit;
       end;
       argtok[ an ] :=ctok;
       an:=an+1;

   end;
   if (an < func.arguments.Count) then begin
       res:='Not enough arguments given to function : '+funname;
       exit;
   end;

   for i := 0 to func.arguments.Count-1 do begin
       ctok:=argtok[i];
       if( not structs_evaluate_rec(ctok, res1, typ1, fromstruct, pos) ) then begin
           res:=res1;
           exit;
       end;

       if not evaluate_value_type( MakeType(-1,func.arguments[i] ) , res1, typ1) then begin
           res:=res1;
           exit;
       end;
       if(res='') then res:=res1
       else res:=res+', '+res1;


   end;
   result:=true;


end;

//==============================================================================
function structStringGet(const  s:string):string;
begin
  if(s='""') then result:=s
  else result:=StructStrings[byte(s[2])-byte('A')];

end;


//==============================================================================
//  Recursive vJass line evaluation function
//  if it is a correct vJass line, returns true,
//    reevaluated version is in res, type is in typ.
//  otherwise, returns false and error is in res.
//==============================================================================
function structs_evaluate_rec(tok: TToken; var res:string; var typ:Tvtype; fromstruct:integer; const pos:integer):boolean;overload;
var red:Treduction;
var s1,s2,s3,s4:string;
    i1,i2,i3,i4:Tvtype;
    i:integer;
    tmfunc:TJassFunc;
var
   stevrecd: Tdynamicstringarray;
   unused,tocall:boolean;


   procedure handleArraySet(arrtok: TToken;indtok: TToken;valtok: TToken; var result:boolean);
   begin
       result:=true;
             if not structs_evaluate_rec(arrtok,s1,i1,fromstruct,pos)
             then begin res:=s1; result:=false; exit; end;

             if not structs_evaluate_rec(indtok,s2,i2,fromstruct,pos)
             then begin res:=s2; result:=false; exit; end;

             if not structs_evaluate_rec(valtok,s3,i3,fromstruct,pos)
             then begin res:=s3; result:=false; exit; end;


             if ( ((i1.id<>-1) or (StructHash.ValueOf(s1)<>-1) or (BigArrayHash.ValueOf(s1)<>-1) ) and translateIndexSet(s1,i1.id,s2,s3, res,typ,fromstruct,pos )) then begin
                 result:=true;
                 exit;
             end;

             if (not translateArray(s1,s2,i1.id,s4,i4,fromstruct,pos,true)) then
             begin
                 res:=s4;
                 result:=false; exit;
             end;

             Concatenate4(res,'set ',s4,'=',s3);
   end;

   procedure handleArrayGet(arrtok: TToken;indtok: TToken;var result:boolean);
   begin
        result:=true;
             if not structs_evaluate_rec(arrtok,s1,i1,fromstruct,pos)
             then begin res:=s1; result:=false; exit; end;

             if not structs_evaluate_rec(indtok,s2,i2,fromstruct,pos)
             then begin res:=s2; result:=false; exit; end;

             if (not translateArray(s1,s2,i1.id,res,typ,fromstruct,pos,false,true)) then
             begin
                 result:=false; exit;
             end;
    end;



begin

    if(tok.Kind<>SymbolTypeNonterminal) then begin
        //IT is just a terminal
        if (LocalIDentifierTypes.ValueOf(tok.DataVar)=-1) and  TranslateFunctionName(tok.DataVar,res,typ)  then begin
           result:=true;
           exit;
        end;
        result:=true;
        typ:=TryGetTypeOf(tok.DataVar);
        res:=tok.DataVar;
        exit;
    end;

    red:=tok.Reduction;

    case RuleConstants(Red.ParentRule.TableIndex) of
       // for i = low to high
       RULE_FORTO_FOR_EQ_TO:
       begin
           // evaluate iterator
           if(not structs_evaluate_rec(red.Tokens[1], s1, i1, fromstruct,pos) ) then
           begin;
               res:=s1;
               result:=false;
               exit;
           end;
           // evaluate lower bound
           if(not structs_evaluate_rec(red.Tokens[3], s2, i2, fromstruct,pos) ) then
           begin;
               res:=s2;
               result:=false;
               exit;
           end;
           // evaluate upper bound
           if(not structs_evaluate_rec(red.Tokens[5], s3, i3, fromstruct,pos) ) then
           begin;
               res:=s3;
               result:=false;
               exit;
           end;

           res := '//====== '+GetTokenText(tok) + ' ======//';

           // set i = (low) - 1
           // loop
           //     set i = i + 1
           //     exitwhen i > (high)

           res := res+CRLF+whitespace + 'set ' + s1 + ' = (' + s2 + ') - 1';
           res := res+CRLF+whitespace + 'loop';
           res := res+CRLF+whitespace + '    set ' + s1 + ' = ' + s1 + ' + 1';
           res := res+CRLF+whitespace + '    exitwhen ' + s1 + ' > (' + s3 + ')';

           result := true;
           exit;
       end;

       // for i = high downto low
       RULE_FORDOWNTO_FOR_EQ_DOWNTO:
       begin
           // evaluate iterator
           if(not structs_evaluate_rec(red.Tokens[1], s1, i1, fromstruct,pos) ) then
           begin;
               res:=s1;
               result:=false;
               exit;
           end;
           // evaluate lower bound
           if(not structs_evaluate_rec(red.Tokens[5], s2, i2, fromstruct,pos) ) then
           begin;
               res:=s2;
               result:=false;
               exit;
           end;
           // evaluate upper bound
           if(not structs_evaluate_rec(red.Tokens[3], s3, i3, fromstruct,pos) ) then
           begin;
               res:=s3;
               result:=false;
               exit;
           end;

           res := '//====== '+GetTokenText(tok) + ' ======//';

           // set i = (high) + 1
           // loop
           //     set i = i - 1
           //     exitwhen i < (low)
           
           res := res+CRLF+whitespace + 'set ' + s1 + ' = (' + s3 + ') + 1';
           res := res+CRLF+whitespace + 'loop';
           res := res+CRLF+whitespace + '    set ' + s1 + ' = ' + s1 + ' - 1';
           res := res+CRLF+whitespace + '    exitwhen ' + s1 + ' < (' + s2 + ')';

           result := true;
           exit;
       end;

       // for unit in group
       RULE_FORGROUP_FOR_IN:
       begin
           // evaluate unit
           if(not structs_evaluate_rec(red.Tokens[1], s1, i1, fromstruct,pos) ) then
           begin;
               res:=s1;
               result:=false;
               exit;
           end;
           // evaluate group
           if(not structs_evaluate_rec(red.Tokens[3], s2, i2, fromstruct,pos) ) then
           begin;
               res:=s2;
               result:=false;
               exit;
           end;

           res := '//====== '+GetTokenText(tok) + ' ======//';
           // loop
           //     set unit = FirstOfGroup(group)
           //     exitwhen unit == null
           //     call GroupRemoveUnit(group, unit)
           res := res+CRLF+whitespace + 'loop';
           res := res+CRLF+whitespace + '    set ' + s1 + ' = FirstOfGroup(' + s2 + ')';
           res := res+CRLF+whitespace + '    exitwhen ' + s1 + ' == null';
           res := res+CRLF+whitespace + '    call GroupRemoveUnit(' + s2 + ', ' + s1 + ')';

           result := true;
           exit;
       end;

       // while (condition)
       RULE_WHILELOOP_WHILE:
       begin
           // evaluate condition
           if(not structs_evaluate_rec(red.Tokens[1], s1, i1, fromstruct,pos) ) then
           begin;
               res:=s1;
               result:=false;
               exit;
           end;

           res := '//====== '+GetTokenText(tok) + ' ======//';

           // loop
           //     exitwhen not(condition)
           res := res+CRLF+whitespace + 'loop';
           res := res+CRLF+whitespace + '    exitwhen not(' + s1 + ')';

           result := true;
           exit;
       end;

       RULE_BREAK_BREAK:
       begin
           res := 'exitwhen true // break' ;
           result := true;
           exit;
       end;

       RULE_ENDFOR_ENDFOR:
       begin
           res := 'endloop // endfor' ;
           result := true;
           exit;
       end;

       RULE_ENDWHILE_ENDWHILE:
       begin
           res := 'endloop // endwhile' ;
           result := true;
           exit;
       end;

       RULE_EXPRESSION8_STRINGLITERAL:
       begin
            res:=red.Tokens[0].datavar;
            if(res[1]<>'''') then
                res:=structStringGet(res);
            typ:=MakeType(-1);
            result:=true;
       end;
       RULE_EXPRESSION8_IDENTIFIER:
       begin
           (* <Expression8> ::= Identifier *)
           if(fromstruct<>-1)
             and ( not(jasshelperconfigfile.DISABLE_IMPLICIT_THIS) or StructList[fromstruct].zincstruct )
             and (LocalIDentifierTypes.ValueOf(red.Tokens[0].datavar)=-1)
             and TranslateDotVar('this', red.Tokens[0].DataVar, fromstruct, res,typ,fromstruct,pos,false,'',MakeType(-1),tocall)
           then begin
               result:=true;
               exit;
           end else begin
               result:=structs_evaluate_rec(red.Tokens[0],res,typ,fromstruct,pos);
               exit;
           end;
       end;
       RULE_ASSIGNVAR_SET_IDENTIFIER_EQ:
       begin

           (* <AssignVar> ::= set Identifier = <Expression> *)
           s1 := red.Tokens[1].DataVar;
           if(not structs_evaluate_rec(red.Tokens[3], s2, i2, fromstruct,pos) ) then
           begin;
               res:=s2;
               result:=false;
               exit;
           end;

           if(fromstruct<>-1)
             and ( not(jasshelperconfigfile.DISABLE_IMPLICIT_THIS) or StructList[fromstruct].zincstruct )
             and (LocalIDentifierTypes.ValueOf(s1)=-1)
             and TranslateDotVar('this', s1, fromstruct, res,typ,fromstruct,pos,true,s2,i2,tocall)
           then begin
               if(tocall) then begin
                   res:='call '+res;
               end else begin
                   s3:=res;
                   Concatenate4(res,'set ',s3,'=',s2);
               end;
               typ:=MakeType(-1);
               result:=true;
               exit;
           end else begin
               Concatenate4(res,'set ',s1,'=',s2);
               typ:=MakeType(-1);
               result:=true;
               exit;
           end;


       end;
       RULE_EXPRESSION8_NUMBERLITERAL:
          begin
              s1:=red.Tokens[0].datavar;
              if( (Length(s1)>10) and (s1[1]='0') and (s1[2]='x') ) then begin
                   res:='Hexadecimal literal too big';
                   result:=false;
                   exit;
              end;
              typ:=MakeType(-1);
              res:=s1;
              result:=true;
              exit;
          end;

       RULE_GETMEMBER_DOT_IDENTIFIER:
          begin
             if not structs_evaluate_rec(red.Tokens[0],s1,i1,fromstruct,pos)
             then begin res:=s1; result:=false; exit; end;

             //if not structs_evaluate_rec(red.Tokens[2],s2,i2,fromstruct,pos)
             //then begin res:=s2; result:=false; exit; end;
            s2:=structs_evaluate_terminal(red.Tokens[2]); //Reduction.tokens[0].datavar  ;
             //MessageBox(0,pchar(s2),pchar(s2),0);
             result:=false;
             try
                 if ( translateDotVar(structs_evaluate_terminal(red.Tokens[0]),s2,-1,res,typ,fromstruct,pos,false,'',MakeType(0),unused)) then
                 begin
                      result:=true; exit;
                 end;
             finally
             end;

             if (not translateDotVar(s1,s2,i1.id,i1,res,typ,fromstruct,pos,false,'',MakeType(0),unused)) then
             begin
                  result:=false; exit;
             end;
          end;

       RULE_ASSIGNMEMBER_SET_DOT_IDENTIFIER_EQ:
       //set somethind.var = something
       begin

             if not structs_evaluate_rec(red.Tokens[1],s1,i1,fromstruct,pos)
             then begin res:=s1; result:=false; exit; end;

             //if not structs_evaluate_rec(red.Tokens[3],s2,i2,fromstruct,pos)
             //then begin res:=s2; result:=false; exit; end;
             s2:=structs_evaluate_terminal(red.Tokens[3])  ;

             if not structs_evaluate_rec(red.Tokens[5],s4,i4,fromstruct,pos)
             then begin res:=s4; result:=false; exit; end;

             tocall:=false;
             if (not translateDotVar(s1,s2,i1.id,s3,typ,fromstruct,pos,true,s4,i4,tocall)) then
             begin
                 res:=s3;
                 result:=false; exit;
             end;

             if(typ.id=METHODTYPE) then begin
                 res:='Hmnn, you are not supposed to assign values to methods...';
                 result:=false;
                 exit;
             end;

             if( typ.id >= ARRAYEDTYPE ) then begin
                  res:='You cannot directly assign a static array member...';
                  result:=false; exit;
             end;

             if ((typ.id<>-1) and StructList[typ.id].forInternalUse) then begin
                 res:='Cannot assign to : '+StructList[typ.id].name;
                 result:=false; exit;
             end;


             if(tocall) then begin
                 res:='call '+s3;
             end else if CompareSubString(s3,1,4,'set ') then begin
                 res:=s3;
             end else begin
                 Concatenate4(res,'set ',s3,'=',s4);
             end;



       end;

       RULE_NOTHINGMETHOD_DOT_IDENTIFIER_LPARAN_RPARAN:
       // something.method()
       begin
             if not structs_evaluate_rec(red.Tokens[0],s1,i1,fromstruct,pos)
             then begin res:=s1; result:=false; exit; end;

             s2:=red.Tokens[2].DataVar;


             if {(red.TokenCount>1) or} (not translateDotMethod(structs_evaluate_terminal(red.Tokens[0]),s2,'',MakeType(-1),res,typ,fromstruct,pos)) then
             begin
                  if (not translateDotMethod(s1,s2,'',i1,res,typ,fromstruct,pos)) then
                  begin
                      result:=false; exit;
                  end;
             end;

       end;
       RULE_ARGMETHOD_DOT_IDENTIFIER_LPARAN_RPARAN:
       begin
       //something.method(args)
             if not structs_evaluate_rec(red.Tokens[0],s1,i1,fromstruct,pos)
             then begin res:=s1; result:=false; exit; end;

             s2:=red.Tokens[2].DataVar;

             if not structs_evaluate_rec(red.Tokens[4],s3,i3,fromstruct,pos)
             then begin res:=s3; result:=false; exit; end;

             if {(red.TokenCount>1) or} (not translateDotMethod(structs_evaluate_terminal(red.Tokens[0]) ,s2,s3,MakeType(-1),res,typ,fromstruct,pos)) then
             begin
             //res:='{'+res+'}'+red.Tokens[0].DataVar;
              //             exit;
                 if (not translateDotMethod(s1,s2,s3,i1,res,typ,fromstruct,pos)) then
                 begin
                      result:=false; exit;
                 end;

             end;

       end;


       RULE_NOTHINGFUNCTION_IDENTIFIER_LPARAN_RPARAN: (* <NothingFunction> ::= Identifier ( ) *)
       // functionname ( )
       begin
           s1:=red.Tokens[0].DataVar;
           typ:=MakeType(StructHash.valueOf(s1));
           if(typ.id<>-1) then //typecast attempt, but gave no arguments...
           begin res:='Expected argument for typecast operator'; result:=false; exit; end;


           typ:=MakeType( HookedNativeHash.ValueOf(s1) );
           if(typ.id<>-1) then begin
              //doubtful a native returns a struct type...
              typ:=MakeType(-1);
              res:='h__'+s1+'()';
              result:=true;
              exit;
           end;


           if  (fromstruct<>-1)
             and ( not(jasshelperconfigfile.DISABLE_IMPLICIT_THIS) or StructList[fromstruct].zincstruct )
             and TranslateDotMethod('this',s1,'',MakeType(fromstruct),res,typ,fromstruct,pos)
           then begin
               result:=true;
               exit;
           end;


           typ:=TryGetTypeOf(red.Tokens[0].datavar);
           res:=red.Tokens[0].datavar+'()';




       end;

       RULE_ARGFUNCTION_IDENTIFIER_LPARAN_RPARAN:
       // functionname ( args )
       begin
           if not structs_evaluate_rec(red.Tokens[2],s1,i1,fromstruct,pos)
               then begin res:=s1; result:=false; exit; end;

           if(red.Tokens[0].DataVar='integer') then //to integer typecast operator
           begin
               if (i1.id=-1) then  begin res:='Invalid typecast'; result:=false; exit; end;
               typ:=MakeType(-1);
               Concatenate3(res,'(',s1,')'); Result:=true; exit;
           end;

           typ:=MakeType( StructHash.valueOf(red.Tokens[0].DataVar) );
           if(typ.id<>-1) then //typecast operator!
           begin
               Concatenate3(res,'(',s1,')');
           end else begin
               typ:=MakeType(HookedNativeHash.ValueOf(red.Tokens[0].DataVar) );
               if(typ.id<>-1) then begin
                   if not structs_evaluate_JassLibArguments( THookedNative(HookedNatives[typ.id]).nativename    , red.Tokens[2],s1,i1,fromstruct,pos)
                       then begin res:=s1; result:=false; exit; end;


                   Concatenate4(res,'h__'+red.Tokens[0].datavar,'(',s1,')');
                   //doubtful a native returns a struct type...
                   typ.id:=-1;
               end else begin
                   s3 := red.Tokens[0].DataVar;
                   if  (fromstruct<>-1)
                     and TranslateDotMethod('this',s3,s1,MakeType(fromstruct),res,typ,fromstruct,pos)
                     and ( not(jasshelperconfigfile.DISABLE_IMPLICIT_THIS) or StructList[fromstruct].zincstruct )
                   then begin
                      result:=true;
                   end else begin
                       tmfunc := GetJassFuncDefinition(s3);
                       if(tmfunc<>nil) then begin
                           if not structs_evaluate_JassLibArguments( s3, red.Tokens[2],s1,i1,fromstruct,pos)
                              then begin res:=s1; result:=false; exit; end;
                       end;
                       Concatenate4(res,red.Tokens[0].datavar,'(',s1,')');
                       typ:=TryGetTypeOf(red.Tokens[0].datavar);
                   end;
               end;
           end;

       end;

       RULE_EQUALTO_EQEQ:
       (* <EqualTo> ::= <Expression3> == <Expression3> *)
       begin
             if not structs_evaluate_rec(red.Tokens[0],s1,i1,fromstruct,pos)
             then begin res:=s1; result:=false; exit; end;

             if not structs_evaluate_rec(red.Tokens[2],s2,i2,fromstruct,pos)
             then begin res:=s2; result:=false; exit; end;


             if (  ((i1.id<>-1) and (i2.id<>-1)) and (  s1<>'0') and (  s2<>'0') ) then begin
                 Result:=TranslateEqualTo(s1,i1.id,s2,i2.id, res,fromstruct,pos , false);
             end else begin
                 Result:=true;
                 res:= s1+' == '+s2;
             end;
             typ:=MakeType(-1); //type is boolean...
             exit;

       end;
       RULE_NOTEQUALTO_EXCLAMEQ:
       (* <NotEqualTo> ::= <Expression3> != <Expression3> *)
       begin
             if not structs_evaluate_rec(red.Tokens[0],s1,i1,fromstruct,pos)
             then begin res:=s1; result:=false; exit; end;

             if not structs_evaluate_rec(red.Tokens[2],s2,i2,fromstruct,pos)
             then begin res:=s2; result:=false; exit; end;

             if (  ((i1.id<>-1) and (i2.id<>-1)) and (  s1<>'0') and (  s2<>'0') ) then begin
                 Result:=TranslateEqualTo(s1,i1.id,s2,i2.id, res,fromstruct,pos , true);
             end else begin
                 Result:=true;
                 res:= s1+' != '+s2;
             end;
             typ:=MakeType(-1); //type is boolean...
             exit;

       end;

       RULE_LESSTHAN_LT:
       (* <LessThan> ::= <Expression4> < <Expression4> *)
       begin
             if not structs_evaluate_rec(red.Tokens[0],s1,i1,fromstruct,pos)
             then begin res:=s1; result:=false; exit; end;

             if not structs_evaluate_rec(red.Tokens[2],s2,i2,fromstruct,pos)
             then begin res:=s2; result:=false; exit; end;


             if (  ((i1.id<>-1) or (i2.id<>-1)) and (  s1<>'0') and (  s2<>'0') ) then begin
                 Result:=TranslateLessThan(s1,i1.id,s2,i2.id, res,fromstruct,pos );
             end else begin
                 Result:=true;
                 res:= s1+' < '+s2;
             end;
             typ:=MakeType(-1); //type is boolean...
             exit;

       end;

       RULE_GREATERTHAN_GT:
       (* <GreaterThan> ::= <Expression4> > <Expression4> *)

       begin
             if not structs_evaluate_rec(red.Tokens[0],s1,i1,fromstruct,pos)
             then begin res:=s1; result:=false; exit; end;

             if not structs_evaluate_rec(red.Tokens[2],s2,i2,fromstruct,pos)
             then begin res:=s2; result:=false; exit; end;


             if (  ((i1.id<>-1) or (i2.id<>-1)) and (  s1<>'0') and (  s2<>'0') ) then begin
                 Result:=TranslateLessThan(s2,i2.id,s1,i1.id, res,fromstruct,pos );
             end else begin
                 Result:=true;
                 res:= s1+' > '+s2;
             end;
             typ:=MakeType(-1); //type is boolean...
             exit;
       end;


       RULE_ASSIGNARRAY_SET_LBRACKET_RBRACKET_EQ:
       //set something[something]=something
       begin
           HandleArraySet(red.Tokens[1],red.Tokens[3],red.Tokens[6], result);
           exit;
       end;

       RULE_GETARRAY_LBRACKET_RBRACKET:
       //something[something]
       begin
            HandleArrayGet(red.Tokens[0], red.Tokens[2], result);
            exit;
       end;

       RULE_ASSIGNARRAYSUF_SET_COLON_IDENTIFIER_EQ:
       // set something:something =something
       begin
           HandleArraySet(red.Tokens[3],red.Tokens[1],red.Tokens[5], result);
           exit;
       end;

       RULE_GETARRAYSUF_COLON_IDENTIFIER:
       // something:something
       begin
            HandleArrayGet(red.Tokens[2], red.Tokens[0], result);
            exit;
       end;

       RULE_CODEVALUE_FUNCTION_IDENTIFIER :
       // function functionname
       begin
           Result:=true;
           res:='function '+red.Tokens[1].DataVar;
           typ:=MakeType(-1,'code');
       end;

       RULE_MEMBERCODEVALUE_FUNCTION_IDENTIFIER_DOT_IDENTIFIER:
       // function class.method
       begin
           Result:= translateMethodCode( red.Tokens[1].datavar, red.Tokens[3].datavar, res,fromstruct,pos);
           typ:=MakeType(-1,'code');
           Exit;
       end;

       RULE_ADDITION_PLUS:
       (* <Addition> ::= <Expression5> + <Expression4> *)
       begin
             if not structs_evaluate_rec(red.Tokens[0],s1,i1,fromstruct,pos)
             then begin res:=s1; result:=false; exit; end;

             if not structs_evaluate_rec(red.Tokens[2],s2,i2,fromstruct,pos)
             then begin res:=s2; result:=false; exit; end;


             if ( (Length(s1)>=2) and (Length(s2)>=2) and (s1[1]='"')and (s2[1]='"')
              and (s1[Length(s1)]='"')and (s2[Length(s2)]='"') ) then begin
                 Result:=true;
                 res:=Copy(s1,1,Length(s1)-1)+Copy(s2,2,Length(s2)-1);
             end else begin
                 Result:=true;
                 res:= s1+' + '+s2;
             end;
             typ:=MakeType(-1); //type is a native one...
             Exit;

       end;

       RULE_CALL_CALL: //call function([args])
       begin
            red:=red.Tokens[1].Reduction;
            if (RuleConstants(red.ParentRule.TableIndex)=RULE_FUNCTION) then begin
{                //weee ( )
                if not structs_evaluate_rec(red.Tokens[0],s1,i1,fromstruct,pos)
                then begin res:=s1; result:=false; exit; end;
}
                s1:=red.Tokens[0].Reduction.Tokens[0].DataVar;


                if CompareSubString(s1,1,9,'InitTrig_') then begin
                    if(FunctionHash.ValueOf(s1)=-1) then begin
                        Concatenate3(res,'//Function not found: call ',s1,'()');
                        Result:=true;
                        exit;
                    end;
                end;


            end;
            red:=tok.Reduction;
            if not structs_evaluate_rec(red.Tokens[1],s1,i1,fromstruct,pos)
            then begin res:=s1; result:=false; exit; end;
            Result:=true;
            res:='call '+s1;
            exit;

       end;
       else //rules that just stay the way they are,
       begin
           res:='';
           if(Length(stevrecd)<red.TokenCount) then SetLength(stevrecd,red.TokenCount+2);
           for i := 0 to red.TokenCount - 1 do begin
               if(i=0) then begin
                   if(not structs_evaluate_rec(red.Tokens[i],res,typ,fromstruct,pos)) then begin
                       result:=false; exit;
                   end;
               end else begin
                   if(not structs_evaluate_rec(red.Tokens[i],res,i2,fromstruct,pos)) then begin
                       result:=false; exit;
                   end;
               end;
               //MessageBox(0,pchar(res),'!',0);
               stevrecd[i]:=res
           end;
           {stevrecd[0]:='a';
           stevrecd[1]:='b';
           stevrecd[2]:='c';}

           ConcatenateManySep(res,stevrecd, red.TokenCount,' ');
           if(red.TokenCount=0) then
               typ:=MakeType(-1);
//           res:='abc';
       end;
    end;

 Result:=true;
end;

//==============================================================================
procedure addStructString(const  s:string);
begin
   if(Length(StructStrings)<=StructStringN) then begin
       SetLength(StructStrings,StructStringN+3+(StructStringN div 3) );
   end;
   StructStrings[StructStringN]:=s;
   StructStringN:=StructStringN+1;
end;

//==============================================================================
function preprocessStructStrings(var s:string):boolean;
var i,k,L:integer;

begin
    StructStringN:=0;
    L:=Length(s);
    i:=1;
    while(i<=L) do begin
        if(s[i]='"') then begin
            k:=i;
            i:=i+1;
            while(i<=L) do begin
                if(s[i]='"') then break
                else if(s[i]='\') then i:=i+1;

                i:=i+1;

            end;
            if(i>L) then break;

            if(StructStringN=STRUCT_STRING_LIMIT) then begin
                result:=false;
                exit;
            end;
            if((k+1)<>i) then begin
                addStructString(Copy(s,k,i-k+1));
                //prevent having one of these with the escape char...
                if Char(Byte('A')+StructStringN-1) = '\' then
                    addStructString(Copy(s,k,i-k+1));
                s[k+1]:=Char(Byte('A')+StructStringN-1);
                k:=k+2;
                while(k<i) do begin
                    s[k]:=' ';
                    k:=k+1;
                end;

            end;

            i:=i+1;
        end else if(s[i]='/') and (i<L) and (s[i+1]='/') then break
        else i:=i+1;
    end;
 result:=true;
end;




//==============================================================================
// if it is a correct code chunk, returns true and reevaluated version is in res.
// otherwise, returns false and error is in res.
// This is the place where gold parser is called.
// This is entry point for recursive function structs_evaluate_rec
//==============================================================================
function structs_evaluatecode({const} s:string; var res:string;   fromstruct:integer; const pos:integer; const insetstatement:boolean=false):boolean;
 var done:boolean;
     Response:Integer;
     tmres:string;
     //tm:integer;
     i,L:integer;
     tmt:Tvtype;
begin
    RecCurrentLine:=pos;
    //done:=false;
    {i:=1;}L:=Length(s);
    {while( (not done) and (i<=L)) do begin
        done:= done or (s[i]='.') or (s[i]='[') or (s[i]='(') ;
        i:=i+1;
    end;
    if(not done) then begin res:=s; result:=true; exit; end;}



    i:=1;
    while (i<=L) and ((s[i]=' ') or (s[i]=#9)) do i:=i+1;
    whitespace:=Copy(s,1,i-1);

    if not preprocessStructStrings(s) then begin
       raise  JasserLineException(pos,'[Internal error] please have less than '+IntToStR(STRUCT_STRING_LIMIT+1)+' string literals in a line.');
    end;

    if (not Parser.OpenTextString(s)) then raise JasserLineException(pos,'Unknown internal error 1');

    Done := False;
    while not Done do
    begin
            Response := Parser.Parse;
            case Response of
                gpMsgLexicalError:
                begin
                     res:='Unexpected : '+Parser.CurrentToken.DataVar;result:=false;exit;
                end;
                gpMsgSyntaxError: begin
                    if(Parser.CurrentToken.Datavar = '') then
                        res:='Syntax Error, unexpected: end of line?'
                    else
                        res:='Syntax Error, unexpected: "'+Parser.CurrentToken.Datavar+'"?';
                    result:=false;
                    exit;
                end;

                gpMsgAccept:
                    Done := True;
                gpMsgInternalError:  begin res:='Internal Parser Error';result:=false;exit; end;

                gpMsgNotLoadedError: begin res:='Parser Not Loaded Error';result:=false;exit; end;
                gpMsgCommentError: begin res:='Syntax Error, unexpected end of line';result:=false;exit; end;
            end;
    end;


    //Hehem parsed correctly!!! Now we *just* have to translate the reductions
    Result:=structs_evaluate_rec(parser.CurrentReduction.Tokens[0],tmres,tmt,   fromstruct,pos);
    res:=tmres;
    if(not Result) then
        exit;
    if (parser.CurrentReduction.TokenCount>1) then begin
       ConcateNate4(res,whitespace,tmres,' ',parser.CurrentReduction.Tokens[1].DataVar); //comment
    end else begin
       res:=whitespace+tmres;
    end;

end;


//==============================================================================
//if it is a correct local declaration, returns true and reevaluated version is in res.
//otherwise, returns false and error is in res.
function structs_evaluatelocal(const s:string; var res:string;  fromstruct:integer; const pos:integer):boolean;
var
   x,h,i:integer;
   typen,name,assign,tem,indent:string;
   arr:boolean;
begin

    if(not CompareLineWord('local',s,x)) then begin
        res:='Not a local syntax?';Result:=false;Exit;
    end;
    i:=x-6;
    SetLength(indent,i);
    while(i>0) do begin
         indent[i]:=' ';
         i:=i-1;
    end;

    GetLineWord(s,typen,x,x);
    if (typen='') then begin
        res:='Expected a type';Result:=false;Exit;
    end;
    h:=StructHash.ValueOf(typen);
    GetLineToken(s,name,x,x);

    arr:=(name='array');
    if(arr) then begin
        GetLineToken(s,name,x,x);
    end;
    if (name='') then begin
        res:='Expected a name';Result:=false;Exit;
    end;
    if ( not ValidIdentifierName(name)) then begin
        res:='Invalid name: "'+name+'"';Result:=false;Exit;
    end;

    if(GetAssigment(s,tem,x) and (tem='')) then begin
         res:='Expected an expression.';Result:=false;Exit;
    end;
    if(arr and (tem<>'')) then begin
        res:='Cannot initialize an array';Result:=false;Exit;
    end;

    if(tem<>'') then begin
      if(structs_evaluatecode(tem,assign,fromstruct,pos)) then begin

      end else begin
         res:=assign; result:=false;Exit;
      end;
    end;
    if(tem='') and (not IsWhitespace(s,x)) then begin
         res:='Unexpected: '+Copy(s,x,Length(s)-x+1);
         result:=false;
         exit;
    end;

    VerifyRedeclarationRaise(RecCurrentLine,name);
    if(h<>-1) then begin
        if(arr) then
            LocalIDentifierTypes.Add(name,h+ARRAYEDTYPE)
        else
            LocalIDentifierTypes.Add(name,h);
        if(arr) then
            res :='local integer array '+name
        else if (assign<>'') then
            Concatenate4(res,'local integer ',name,'=',assign)
        else
            res:='local integer '+name;
    end else begin

        LocalIdentifierTypes.Add(name,-2);
        if(arr) then
            Concatenate4(res,'local ',typen,' array ',name)
        else if (assign<>'') then
            Concatenate6(res,'local ',typen,' ',name,'=',assign)
        else
            Concatenate4(res,'local ',typen,' ',name);
    end;
    res:=indent+res;


    Result:=true;



end;


 

//==============================================================================
procedure initParser;
var
  lMemStream : TMemoryStream;
  lResource : Pointer;
  lHandle   : Cardinal;

begin
   if (Parser=nil) then
   begin

         lHandle := FindResource(0, 'VJASSLINEGRAMMAR', RT_RCDATA);
         lResource := LockResource(LoadResource(0, lHandle));
         if lResource = nil then begin

             if (fileexists(GRAMMARPATH)) then begin
                 parser:=TGoldParser.Create;
                 if not Parser.LoadCompiledGrammar(GRAMMARPATH) then raise Exception.Create('Load grammar error');
                 exit;

             end else if (fileExists('jasshelper.cgt')) then begin
                 parser:=TGoldParser.Create;
                 if not Parser.LoadCompiledGrammar('jasshelper.cgt') then raise Exception.Create('Load grammar error');
                 exit;
             end else begin
                 raise Exception.Create('nil Resource and unable to find external cgt file.');;
             end;
         end;
         lMemStream := TMemoryStream.Create;
         try
            lMemStream.WriteBuffer(lResource^, SizeofResource(0, lHandle));
            lMemStream.Position := 0;
            Parser:=TGoldParser.Create;
            if not Parser.LoadCompiledGrammar(lMemStream) then begin
                raise Exception.Create('Load grammar error');
            end;
         finally
            lMemStream.Free;
         end; // try .. finally
   end
   else
       Parser.Reset;

end;

//==============================================================================
//  Replace structs with normal jass
//==============================================================================
procedure Step02(var globalsblock:string; var execblock:string; var firstblock:string; var secondblock:string);
var
    i,j,k,h,wordend:integer;
    currentstruct:integer;
    glob,fun,loc:boolean;
    memb:Tmember;
    tmstruct:TStruct;
    tem:string;
    word:string;

    newglob:string;
    gl,fs:integer;
begin
    // GOLD parser, one line parsing only.

    initParser;

    // SLK stuff
    datafunctions_Init;    

    //this is the most scarry process, involves writing the output
    secondblock:='';
    firstblock:='';
    execblock:='';
    globalsblock:='';


    //Parse members inits:
    for i := 1 to StructN do begin
        tmstruct:=StructList[i];
        k:=0;
        while(k<tmstruct.membern) do begin
            memb:=tmstruct.members[k];
            if (memb.oninit_value<>'') and  (structs_evaluatecode(memb.oninit_value,tem,i,memb.decl)) then begin
                memb.oninit_value:=tem;
            end
            else if (memb.oninit_value<>'') then begin
                raise JasserLineException(memb.decl,tem);
            end;

            k:=k+1;
        end;

    end;

    // * parse and replace struct types in variable and function declarations.
    //     (also consider the globals we added (newglobals[] )
    // * remove struct declarations and leave methods.
    // *

    i:=0;
    glob:=false;
    loc:=false;
    fun:=false;



    //h:=-1;
    currentstruct:=-1;
    while(i<inputN) do begin
        //ProPosition(i/inputN);
        RecCurrentLine:=i;

        //WriteLn(DEBUGFILE,JHInput.Get(i));
        GetLineWord(JHInput.Get(i),word,wordend);

         if (glob) then begin

             if (word='') or (CompareSubString(word,1,2,'//')) then begin
                 SWriteLn(globalsblock,JHInput.Get(i));
             end else if(word='endglobals') then begin
                 SWriteLn(globalsblock, #13#10'//JASSHelper struct globals:');

                 for j := 0 to newglobalsn-1 do begin
                    getnewglobal(j, newglob, gl, fs);
                    if (structs_evaluateglobal(newglob,tem, fs)) then
                        SWriteLn(globalsblock,tem)
                    else
                        raise JASSerLineDoubleException(gl,tem,gl,'(At generated code): '+newglob);
                 end;
                 
                 glob:=false;
                 // SWriteLn(firstblock,JHInput.Get(i));
             end else if (structs_evaluateglobal(JHInput.Get(i),tem)) then
                     SWriteLn(globalsblock,tem)
                 else
                     raise JASSerLineException(i,tem);

         end else if(word='//!') then begin

             if(JHInput.Get(i)='//! initstructs') then begin
                     SWriteLn(secondblock,'    call ExecuteFunc("jasshelper__init'+structmagic_time+'")');

             end else if(JHInput.Get(i)='//! initdatastructs') then begin
                 if(StructN>0) and (datafunctions_N>0) then begin
                     for j := 0 to datafunctions_N-1 do begin
                         SWriteLn(secondblock,'call ExecuteFunc("jasshelper__'+IntToStr(j)+'initdatastructs'+structmagic_time+'")');
                     end;
                 end;


             end else if (JHInput.Get(i)='//! ignore') then begin
                 //nothing
             end else begin
                 if compareLineWord('loaddata',JHInput.Get(i),wordend,wordend) then begin
                     loadStructs(JHInput.Get(i),wordend,i);
                     JHInput.Prepend('//processed command: ', i);

                 end;
             end;


         end else if (word='') or (CompareSubString(word,1,2,'//')) then begin

             //comment/empty line, just add.

             SWriteLn(secondblock,JHInput.Get(i));

         end else if(word='globals') then begin
             if (fun) then raise JASSerLineException(i,'Unexpected globals inside of function');
             if (glob) then raise JASSerLineException(i,'Nested globals');
             glob:=true;
             SWriteLn(globalsblock,JHInput.Get(i));
         end else if (word='endglobals') then begin
             raise JASSerLineException(i,'Unexpected endglobals');

         end else if (fun) then begin


             if(word='struct') then raise JASSErLineException(i,'Found struct inside function');
             if(word='local') then begin
                 RecCurrentLine:=i;
                 if (structs_evaluatelocal(JHInput.Get(i),tem,currentstruct,i)) then begin
                     JHInput.Rewrite(i, tem);
                     SWriteLn(secondblock,tem)
                 end else
                     raise JASSerLineException(i,tem);

                 if(not loc) then raise JASSerLineException(i,'locals are only supported at the top of the function');
             end else begin
                 if(loc) then loc:=false;
                 if(word='endfunction') then begin
                     LocalIdentifierTypes.Clear;
                     fun:=false;
                     SWriteLn(secondblock,JHInput.Get(i));

                     if(currentstruct<>-1) then begin
                        tmstruct:=StructList[currentstruct];

                         if (tmstruct.parent=-1) and not(tmstruct.gotstructchildren) and (tmstruct.parentstruct=-1) and (tmstruct.ondestroy<>nil) and(not tmstruct.ondestroydone)
                             and (tmstruct.FunctionInterfacePrototype=-1)
                             and (tmstruct.ondestroy.decl<=i)
                             and (not tmstruct.isarraystruct)
                               then begin
                              //write 'normal' destructor       // TODO: make this a function
                              swrite(secondblock,#13#10'//Generated destructor of ');
                              SWriteLn(secondblock,tmstruct.name);
                              Concatenate3(tem,'function s__',tmstruct.name,'_deallocate takes integer this returns nothing');
                              SWriteLn(secondblock,tem);
                              SWriteLn(secondblock,'    if this==null then');
                              if (DEBUG_MODE()) then begin
                                  SWriteLn(secondblock,'        call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,1000.,"Attempt to destroy a null struct of type: '+tmstruct.name+'")');
                              end;
                              SWriteLn(secondblock,'        return');

                              //tmstruct2:=nil;
                              Concatenate3(tem,'    elseif (si__',tmstruct.name,'_V[this]!=-1) then');
                              SWriteLn(secondblock,tem);
                              if(DEBUG_MODE()) then begin
                                  SWriteLn(secondblock,'        call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,1000.,"Double free of type: '+tmstruct.name+'")');
                              end;
                              SWriteLn(secondblock,'        return');
                              SWriteLn(secondblock,'    endif');

                              Concatenate3(tem,'    call s__',tmstruct.name,'_onDestroy(this)');
                              SWriteLn(secondblock,tem);
                              Concatenate5(tem,'    set si__',tmstruct.name,'_V[this]=si__',tmstruct.name,'_F');
                              SWriteLn(secondblock,tem);
                              Concatenate3(tem,'    set si__',tmstruct.name,'_F=this');
                              SWriteLn(secondblock,tem);
                              SWriteLn(secondblock,'endfunction');
                              tmstruct.ondestroydone:=true;
                         end;
                     end;

                 end else if (structs_evaluatecode(JHInput.Get(i),tem,currentstruct,i)) then begin
                     JHInput.Rewrite(i, tem);
                     SWriteLn(secondblock,tem)
                 end else
                     raise JASSerLineException(i,tem);


             end;



         end else if (word='constant') or (word='function') then begin
             if (structs_evaluatefunction(JHInput.Get(i),tem)) then begin
                 fun:=true;
                 loc:=true;
                 SWriteLn(secondblock,tem)
             end else if(tem<>'') then begin
                 raise JASSerLineException(i,tem);
             end else raise JASSerLineException(i,'Syntax error in function declaration.');

         end else if (word='struct') then begin
             GetLineToken(JHInput.Get(i),word,wordend,wordend);
             h:=StructHash.ValueOf(word);
             if(h=-1) then begin
                 raise JASSerLineException(i,'Internal Error - unrecognized struct (step 2)');
             end;
             currentstruct:=h;

         end else if(word='endstruct') then begin

             currentstruct:=-1;
             //h:=-1;

         end else begin
             //unrecognized, add just in case. could be a preprocessor that is used later
             SWriteLn(secondblock,JHInput.Get(i))
         end;

         i:=i+1;
    end;
end;




end.
