{
  Examples:
    ./testpassrc --suite=TTestStatementParser.TestCallQualified2
}
unit tcstatements;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, fpcunit, pastree, pscanner, pparser,
  tcbaseparser, testregistry;

Type
  { TTestStatementParser }

  TTestStatementParser = Class(TTestParser)
  private
    FStatement: TPasImplBlock;
    FVariables : TStrings;
    procedure DoTestCallOtherFormat;
    procedure TestCallFormat(FN: String; AddPrecision: Boolean; AddSecondParam: boolean = false);
  Protected
    Procedure SetUp; override;
    Procedure TearDown; override;
    procedure AddStatements(ASource : Array of string);
    Procedure DeclareVar(Const AVarType : String; Const AVarName : String = 'A');
    function TestStatement(ASource : string) : TPasImplElement;
    function TestStatement(ASource : Array of string) : TPasImplElement;
    Procedure ExpectParserError(Const Msg : string);
    Procedure ExpectParserError(Const Msg : string; ASource : Array of string);
    Function AssertStatement(Msg : String; AClass : TClass;AIndex : Integer = 0) : TPasImplBlock;
    Property Statement: TPasImplBlock Read FStatement;
  Published
    Procedure TestEmpty;
    Procedure TestEmptyStatement;
    Procedure TestEmptyStatements;
    Procedure TestBlock;
    Procedure TestBlockComment;
    Procedure TestBlock2Comments;
    Procedure TestAssignment;
    Procedure TestAssignmentAdd;
    Procedure TestAssignmentMinus;
    Procedure TestAssignmentMul;
    Procedure TestAssignmentDivision;
    Procedure TestAssignmentMissingSemicolonError;
    Procedure TestCall;
    Procedure TestCallComment;
    Procedure TestCallQualified;
    Procedure TestCallQualified2;
    Procedure TestCallNoArgs;
    Procedure TestCallOneArg;
    procedure TestCallWriteFormat1;
    procedure TestCallWriteFormat2;
    procedure TestCallWriteFormat3;
    procedure TestCallWriteFormat4;
    procedure TestCallWritelnFormat1;
    procedure TestCallWritelnFormat2;
    procedure TestCallStrFormat1;
    procedure TestCallStrFormat2;
    procedure TestCallOtherFormat;
    Procedure TestIf;
    Procedure TestIfBlock;
    Procedure TestIfAssignment;
    Procedure TestIfElse;
    Procedure TestIfElseBlock;
    Procedure TestIfSemiColonElseError;
    procedure TestIfforElseBlock;
    procedure TestIfRaiseElseBlock;
    procedure TestIfWithBlock;
    Procedure TestNestedIf;
    Procedure TestNestedIfElse;
    Procedure TestWhile;
    Procedure TestWhileBlock;
    Procedure TestWhileNested;
    Procedure TestRepeat;
    Procedure TestRepeatBlock;
    procedure TestRepeatBlockNosemicolon;
    Procedure TestRepeatNested;
    Procedure TestFor;
    Procedure TestForIn;
    Procedure TestForExpr;
    Procedure TestForBlock;
    procedure TestDowntoBlock;
    Procedure TestForNested;
    Procedure TestWith;
    Procedure TestWithMultiple;
    Procedure TestCaseEmpty;
    Procedure TestCaseOneInteger;
    Procedure TestCaseTwoIntegers;
    Procedure TestCaseRange;
    Procedure TestCaseRangeSeparate;
    Procedure TestCase2Cases;
    Procedure TestCaseBlock;
    Procedure TestCaseElseBlockEmpty;
    procedure TestCaseOtherwiseBlockEmpty;
    Procedure TestCaseElseBlockAssignment;
    Procedure TestCaseElseBlock2Assignments;
    Procedure TestCaseIfCaseElse;
    Procedure TestCaseIfElse;
    Procedure TestCaseElseNoSemicolon;
    Procedure TestCaseIfElseNoSemicolon;
    procedure TestCaseIfOtherwiseNoSemicolon;
    Procedure TestRaise;
    Procedure TestRaiseEmpty;
    Procedure TestRaiseAt;
    Procedure TestTryFinally;
    Procedure TestTryFinallyEmpty;
    Procedure TestTryFinallyNested;
    procedure TestTryExcept;
    procedure TestTryExceptNested;
    procedure TestTryExceptEmpty;
    Procedure TestTryExceptOn;
    Procedure TestTryExceptOn2;
    Procedure TestTryExceptOnElse;
    Procedure TestTryExceptOnIfElse;
    Procedure TestTryExceptOnElseNoSemicolo;
    procedure TestTryExceptRaise;
    Procedure TestAsm;
    Procedure TestAsmBlock;
    Procedure TestAsmBlockWithEndLabel;
    Procedure TestAsmBlockInIfThen;
    Procedure TestGotoInIfThen;
    procedure TestAssignToAddress;
    procedure TestFinalizationNoSemicolon;
    procedure TestMacroComment;
    Procedure TestPlatformIdentifier;
    Procedure TestPlatformIdentifier2;
    Procedure TestArgumentNameOn;
  end;


implementation

{ TTestStatementParser }

procedure TTestStatementParser.SetUp;
begin
  inherited SetUp;
  FVariables:=TStringList.Create;
end;

procedure TTestStatementParser.TearDown;
begin
  FreeAndNil(FVariables);
  inherited TearDown;
end;

procedure TTestStatementParser.AddStatements(ASource: array of string);

Var
  I :Integer;
begin
  StartProgram(ExtractFileUnitName(MainFilename));
  if FVariables.Count>0 then
    begin
    Add('Var');
    For I:=0 to FVariables.Count-1 do
      Add('  '+Fvariables[I]);
    end;
  Add('begin');
  For I:=Low(ASource) to High(ASource) do
    Add('  '+ASource[i]);
end;

procedure TTestStatementParser.DeclareVar(const AVarType: String;
  const AVarName: String);
begin
  FVariables.Add(AVarName+' : '+AVarType+';');
end;

function TTestStatementParser.TestStatement(ASource: string): TPasImplElement;
begin
  Result:=TestStatement([ASource]);
end;

function TTestStatementParser.TestStatement(ASource: array of string
  ): TPasImplElement;


begin
  Result:=Nil;
  FStatement:=Nil;
  AddStatements(ASource);
  ParseModule;
  AssertEquals('Have program',TPasProgram,Module.ClassType);
  AssertNotNull('Have program section',PasProgram.ProgramSection);
  AssertNotNull('Have initialization section',PasProgram.InitializationSection);
  if (PasProgram.InitializationSection.Elements.Count>0) then
    if TObject(PasProgram.InitializationSection.Elements[0]) is TPasImplBlock then
      FStatement:=TPasImplBlock(PasProgram.InitializationSection.Elements[0]);
  Result:=FStatement;
end;

procedure TTestStatementParser.ExpectParserError(const Msg: string);
begin
  AssertException(Msg,EParserError,@ParseModule);
end;

procedure TTestStatementParser.ExpectParserError(const Msg: string;
  ASource: array of string);
begin
  AddStatements(ASource);
  ExpectParserError(Msg);
end;

function TTestStatementParser.AssertStatement(Msg: String; AClass: TClass;
  AIndex: Integer): TPasImplBlock;
begin
  if not (AIndex<PasProgram.InitializationSection.Elements.Count) then
    Fail(Msg+': No such statement : '+intTostr(AIndex));
  AssertNotNull(Msg+' Have statement',PasProgram.InitializationSection.Elements[AIndex]);
  AssertEquals(Msg+' statement class',AClass,TObject(PasProgram.InitializationSection.Elements[AIndex]).ClassType);
  Result:=TObject(PasProgram.InitializationSection.Elements[AIndex]) as TPasImplBlock;
end;

procedure TTestStatementParser.TestEmpty;
begin
  //TestStatement(';');
  TestStatement('');
  AssertEquals('No statements',0,PasProgram.InitializationSection.Elements.Count);
end;

procedure TTestStatementParser.TestEmptyStatement;
begin
  TestStatement(';');
  AssertEquals('0 statement',0,PasProgram.InitializationSection.Elements.Count);
end;

procedure TTestStatementParser.TestEmptyStatements;
begin
  TestStatement(';;');
  AssertEquals('0 statement',0,PasProgram.InitializationSection.Elements.Count);
end;

procedure TTestStatementParser.TestBlock;

Var
  B : TPasImplBeginBlock;

begin
  TestStatement(['begin','end']);
  AssertEquals('1 statement',1,PasProgram.InitializationSection.Elements.Count);
  AssertNotNull('Statement assigned',PasProgram.InitializationSection.Elements[0]);
  AssertEquals('Block statement',TPasImplBeginBlock,Statement.ClassType);
  B:= Statement as TPasImplBeginBlock;
  AssertEquals('Empty block',0,B.Elements.Count);
end;

procedure TTestStatementParser.TestBlockComment;
Var
  B : TPasImplBeginBlock;

begin
  Engine.NeedComments:=True;
  TestStatement(['{ This is a comment }','begin','end']);
  AssertEquals('1 statement',1,PasProgram.InitializationSection.Elements.Count);
  AssertNotNull('Statement assigned',PasProgram.InitializationSection.Elements[0]);
  AssertEquals('Block statement',TPasImplBeginBlock,Statement.ClassType);
  B:= Statement as TPasImplBeginBlock;
  AssertEquals('Empty block',0,B.Elements.Count);
  AssertEquals('No DocComment','',B.DocComment);
end;

procedure TTestStatementParser.TestBlock2Comments;
Var
  B : TPasImplBeginBlock;

begin
  Engine.NeedComments:=True;
  TestStatement(['{ This is a comment }','// Another comment','begin','end']);
  AssertEquals('1 statement',1,PasProgram.InitializationSection.Elements.Count);
  AssertNotNull('Statement assigned',PasProgram.InitializationSection.Elements[0]);
  AssertEquals('Block statement',TPasImplBeginBlock,Statement.ClassType);
  B:= Statement as TPasImplBeginBlock;
  AssertEquals('Empty block',0,B.Elements.Count);
  AssertEquals('No DocComment','',B.DocComment);
end;

procedure TTestStatementParser.TestAssignment;

Var
  A : TPasImplAssign;

begin
  DeclareVar('integer');
  TestStatement(['a:=1;']);
  AssertEquals('1 statement',1,PasProgram.InitializationSection.Elements.Count);
  AssertEquals('Assignment statement',TPasImplAssign,Statement.ClassType);
  A:=Statement as TPasImplAssign;
  AssertEquals('Normal assignment',akDefault,A.Kind);
  AssertExpression('Right side is constant',A.Right,pekNumber,'1');
  AssertExpression('Left side is variable',A.Left,pekIdent,'a');
end;

procedure TTestStatementParser.TestAssignmentAdd;

Var
  A : TPasImplAssign;

begin
  Parser.Scanner.Options:=[po_cassignments];
  DeclareVar('integer');
  TestStatement(['a+=1;']);
  AssertEquals('1 statement',1,PasProgram.InitializationSection.Elements.Count);
  AssertEquals('Assignment statement',TPasImplAssign,Statement.ClassType);
  A:=Statement as TPasImplAssign;
  AssertEquals('Add assignment',akAdd,A.Kind);
  AssertExpression('Right side is constant',A.Right,pekNumber,'1');
  AssertExpression('Left side is variable',A.Left,pekIdent,'a');
end;

procedure TTestStatementParser.TestAssignmentMinus;
Var
  A : TPasImplAssign;

begin
  Parser.Scanner.Options:=[po_cassignments];
  DeclareVar('integer');
  TestStatement(['a-=1;']);
  AssertEquals('1 statement',1,PasProgram.InitializationSection.Elements.Count);
  AssertEquals('Assignment statement',TPasImplAssign,Statement.ClassType);
  A:=Statement as TPasImplAssign;
  AssertEquals('Minus assignment',akMinus,A.Kind);
  AssertExpression('Right side is constant',A.Right,pekNumber,'1');
  AssertExpression('Left side is variable',A.Left,pekIdent,'a');
end;

procedure TTestStatementParser.TestAssignmentMul;
Var
  A : TPasImplAssign;

begin
  Parser.Scanner.Options:=[po_cassignments];
  DeclareVar('integer');
  TestStatement(['a*=1;']);
  AssertEquals('1 statement',1,PasProgram.InitializationSection.Elements.Count);
  AssertEquals('Assignment statement',TPasImplAssign,Statement.ClassType);
  A:=Statement as TPasImplAssign;
  AssertEquals('Mul assignment',akMul,A.Kind);
  AssertExpression('Right side is constant',A.Right,pekNumber,'1');
  AssertExpression('Left side is variable',A.Left,pekIdent,'a');
end;

procedure TTestStatementParser.TestAssignmentDivision;
Var
  A : TPasImplAssign;

begin
  Parser.Scanner.Options:=[po_cassignments];
  DeclareVar('integer');
  TestStatement(['a/=1;']);
  AssertEquals('1 statement',1,PasProgram.InitializationSection.Elements.Count);
  AssertEquals('Assignment statement',TPasImplAssign,Statement.ClassType);
  A:=Statement as TPasImplAssign;
  AssertEquals('Division assignment',akDivision,A.Kind);
  AssertExpression('Right side is constant',A.Right,pekNumber,'1');
  AssertExpression('Left side is variable',A.Left,pekIdent,'a');
end;

procedure TTestStatementParser.TestAssignmentMissingSemicolonError;
begin
  DeclareVar('integer');
  ExpectParserError('Semicolon expected, but "a" found',['a:=1','a:=2']);
end;

procedure TTestStatementParser.TestCall;

Var
  S : TPasImplSimple;

begin
  TestStatement('Doit;');
  AssertEquals('1 statement',1,PasProgram.InitializationSection.Elements.Count);
  AssertEquals('Simple statement',TPasImplSimple,Statement.ClassType);
  S:=Statement as TPasImplSimple;
  AssertExpression('Doit call',S.Expr,pekIdent,'Doit');
end;

procedure TTestStatementParser.TestCallComment;

Var
  S : TPasImplSimple;
begin
  Engine.NeedComments:=True;
  TestStatement(['//comment line','Doit;']);
  AssertEquals('1 statement',1,PasProgram.InitializationSection.Elements.Count);
  AssertEquals('Simple statement',TPasImplSimple,Statement.ClassType);
  AssertEquals('1 statement',1,PasProgram.InitializationSection.Elements.Count);
  S:=Statement as TPasImplSimple;
  AssertExpression('Doit call',S.Expr,pekIdent,'Doit');
  AssertEquals('No DocComment','',S.DocComment);
end;

procedure TTestStatementParser.TestCallQualified;

Var
  S : TPasImplSimple;
  B : TBinaryExpr;

begin
  TestStatement('Unita.Doit;');
  AssertEquals('1 statement',1,PasProgram.InitializationSection.Elements.Count);
  AssertEquals('Simple statement',TPasImplSimple,Statement.ClassType);
  S:=Statement as TPasImplSimple;
  AssertExpression('Doit call',S.Expr,pekBinary,TBinaryExpr);
  B:=S.Expr as TBinaryExpr;
  TAssert.AssertSame('B.left.Parent=B',B,B.left.Parent);
  TAssert.AssertSame('B.right.Parent=B',B,B.right.Parent);
  AssertExpression('Unit name',B.Left,pekIdent,'Unita');
  AssertExpression('Doit call',B.Right,pekIdent,'Doit');
end;

procedure TTestStatementParser.TestCallQualified2;
Var
  S : TPasImplSimple;
  B : TBinaryExpr;

begin
  TestStatement('Unita.ClassB.Doit;');
  AssertEquals('1 statement',1,PasProgram.InitializationSection.Elements.Count);
  AssertEquals('Simple statement',TPasImplSimple,Statement.ClassType);
  S:=Statement as TPasImplSimple;
  AssertExpression('Doit call',S.Expr,pekBinary,TBinaryExpr);
  B:=S.Expr as TBinaryExpr;
  AssertExpression('Doit call',B.Right,pekIdent,'Doit');
  AssertExpression('First two parts of unit name',B.left,pekBinary,TBinaryExpr);
  B:=B.left as TBinaryExpr;
  AssertExpression('Unit name part 1',B.Left,pekIdent,'Unita');
  AssertExpression('Unit name part 2',B.right,pekIdent,'ClassB');
end;

procedure TTestStatementParser.TestCallNoArgs;

Var
  S : TPasImplSimple;
  P : TParamsExpr;

begin
  TestStatement('Doit();');
  AssertEquals('1 statement',1,PasProgram.InitializationSection.Elements.Count);
  AssertEquals('Simple statement',TPasImplSimple,Statement.ClassType);
  S:=Statement as TPasImplSimple;
  AssertExpression('Doit call',S.Expr,pekFuncParams,TParamsExpr);
  P:=S.Expr as TParamsExpr;
  AssertExpression('Correct function call name',P.Value,pekIdent,'Doit');
  AssertEquals('No params',0,Length(P.Params));
end;

procedure TTestStatementParser.TestCallOneArg;

Var
  S : TPasImplSimple;
  P : TParamsExpr;

begin
  TestStatement('Doit(1);');
  AssertEquals('1 statement',1,PasProgram.InitializationSection.Elements.Count);
  AssertEquals('Simple statement',TPasImplSimple,Statement.ClassType);
  S:=Statement as TPasImplSimple;
  AssertExpression('Doit call',S.Expr,pekFuncParams,TParamsExpr);
  P:=S.Expr as TParamsExpr;
  AssertExpression('Correct function call name',P.Value,pekIdent,'Doit');
  AssertEquals('One param',1,Length(P.Params));
  AssertExpression('Parameter is constant',P.Params[0],pekNumber,'1');
end;

procedure TTestStatementParser.TestCallFormat(FN: String;
  AddPrecision: Boolean; AddSecondParam: boolean);
var
  P : TParamsExpr;

  procedure CheckParam(Index: integer; const aParamName: string);
  begin
    AssertExpression('Parameter['+IntToStr(Index)+'] is identifier',P.Params[Index],pekIdent,aParamName);
    AssertExpression('Parameter['+IntToStr(Index)+'] has formatting constant 1' ,P.Params[Index].format1,pekNumber,'3');
    if AddPrecision then
      AssertExpression('Parameter['+IntToStr(Index)+'] has formatting constant 2',P.Params[Index].format2,pekNumber,'2');
  end;

Var
  S : TPasImplSimple;
  N : String;
  ArgCnt: Integer;
begin
  N:=fn+'(a:3';
  if AddPrecision then
    N:=N+':2';
  ArgCnt:=1;
  if AddSecondParam then
    begin
    ArgCnt:=2;
    N:=N+',b:3';
    if AddPrecision then
      N:=N+':2';
    end;
  N:=N+');';
  TestStatement(N);
  AssertEquals('1 statement',1,PasProgram.InitializationSection.Elements.Count);
  AssertEquals('Simple statement',TPasImplSimple,Statement.ClassType);
  S:=Statement as TPasImplSimple;
  AssertExpression('Doit call',S.Expr,pekFuncParams,TParamsExpr);
  P:=S.Expr as TParamsExpr;
  AssertExpression('Correct function call name',P.Value,pekIdent,FN);
  AssertEquals(IntToStr(ArgCnt)+' param',ArgCnt,Length(P.Params));
  CheckParam(0,'a');
  if AddSecondParam then
    CheckParam(1,'b');
end;

procedure TTestStatementParser.TestCallWriteFormat1;

begin
  TestCallFormat('write',False);
end;

procedure TTestStatementParser.TestCallWriteFormat2;

begin
  TestCallFormat('write',True);
end;

procedure TTestStatementParser.TestCallWriteFormat3;
begin
  TestCallFormat('write',false,true);
end;

procedure TTestStatementParser.TestCallWriteFormat4;
begin
  TestCallFormat('write',true,true);
end;

procedure TTestStatementParser.TestCallWritelnFormat1;
begin
  TestCallFormat('writeln',False);
end;

procedure TTestStatementParser.TestCallWritelnFormat2;
begin
  TestCallFormat('writeln',True);
end;

procedure TTestStatementParser.TestCallStrFormat1;
begin
  TestCallFormat('str',False);
end;

procedure TTestStatementParser.TestCallStrFormat2;
begin
  TestCallFormat('str',True);
end;

procedure TTestStatementParser.DoTestCallOtherFormat;

begin
  TestCallFormat('nono',False);
end;

procedure TTestStatementParser.TestCallOtherFormat;

begin
  AssertException('Only Write(ln) and str allow format',EParserError,@DoTestCallOtherFormat);
end;

procedure TTestStatementParser.TestIf;

Var
  I : TPasImplIfElse;

begin
  DeclareVar('boolean');
  TestStatement(['if a then',';']);
  I:=AssertStatement('If statement',TPasImplIfElse) as TPasImplIfElse;
  AssertExpression('IF condition',I.ConditionExpr,pekIdent,'a');
  AssertNull('No else',i.ElseBranch);
  AssertNull('No if branch',I.IfBranch);
end;

procedure TTestStatementParser.TestIfBlock;

Var
  I : TPasImplIfElse;

begin
  DeclareVar('boolean');
  TestStatement(['if a then','  begin','  end']);
  I:=AssertStatement('If statement',TPasImplIfElse) as TPasImplIfElse;
  AssertExpression('IF condition',I.ConditionExpr,pekIdent,'a');
  AssertNull('No else',i.ElseBranch);
  AssertNotNull('if branch',I.IfBranch);
  AssertEquals('begin end block',TPasImplBeginBlock,I.ifBranch.ClassType);
end;

procedure TTestStatementParser.TestIfAssignment;

Var
  I : TPasImplIfElse;

begin
  DeclareVar('boolean');
  TestStatement(['if a then','  a:=False;']);
  I:=AssertStatement('If statement',TPasImplIfElse) as TPasImplIfElse;
  AssertExpression('IF condition',I.ConditionExpr,pekIdent,'a');
  AssertNull('No else',i.ElseBranch);
  AssertNotNull('if branch',I.IfBranch);
  AssertEquals('assignment statement',TPasImplAssign,I.ifBranch.ClassType);
end;

procedure TTestStatementParser.TestIfElse;

Var
  I : TPasImplIfElse;

begin
  DeclareVar('boolean');
  TestStatement(['if a then','  begin','  end','else',';']);
  I:=AssertStatement('If statement',TPasImplIfElse) as TPasImplIfElse;
  AssertExpression('IF condition',I.ConditionExpr,pekIdent,'a');
  AssertNull('No else',i.ElseBranch);
  AssertNotNull('if branch',I.IfBranch);
  AssertEquals('begin end block',TPasImplBeginBlock,I.ifBranch.ClassType);
end;

procedure TTestStatementParser.TestIfElseBlock;
Var
  I : TPasImplIfElse;

begin
  DeclareVar('boolean');
  TestStatement(['if a then','  begin','  end','else','  begin','  end']);
  I:=AssertStatement('If statement',TPasImplIfElse) as TPasImplIfElse;
  AssertExpression('IF condition',I.ConditionExpr,pekIdent,'a');
  AssertNotNull('if branch',I.IfBranch);
  AssertEquals('begin end block',TPasImplBeginBlock,I.ifBranch.ClassType);
  AssertNotNull('Else branch',i.ElseBranch);
  AssertEquals('begin end block',TPasImplBeginBlock,I.ElseBranch.ClassType);
end;

procedure TTestStatementParser.TestIfforElseBlock;

Var
  I : TPasImplIfElse;

begin
  TestStatement(['if a then','for X := 1 downto 0 do Writeln(X)','else', 'for X := 0 to 1 do Writeln(X)']);
  I:=AssertStatement('If statement',TPasImplIfElse) as TPasImplIfElse;
  AssertExpression('IF condition',I.ConditionExpr,pekIdent,'a');
  AssertEquals('For statement',TPasImplForLoop,I.ifBranch.ClassType);
  AssertEquals('For statement',TPasImplForLoop,I.ElseBranch.ClassType);
end;

procedure TTestStatementParser.TestIfRaiseElseBlock;
Var
  I : TPasImplIfElse;
begin
  TestStatement(['if a then','raise','else', 'for X := 0 to 1 do Writeln(X)']);
  I:=AssertStatement('If statement',TPasImplIfElse) as TPasImplIfElse;
  AssertExpression('IF condition',I.ConditionExpr,pekIdent,'a');
  AssertEquals('For statement',TPasImplRaise,I.ifBranch.ClassType);
  AssertEquals('For statement',TPasImplForLoop,I.ElseBranch.ClassType);
end;

procedure TTestStatementParser.TestIfWithBlock;
Var
  I : TPasImplIfElse;
begin
  TestStatement(['if a then','with b do something','else', 'for X := 0 to 1 do Writeln(X)']);
  I:=AssertStatement('If statement',TPasImplIfElse) as TPasImplIfElse;
  AssertExpression('IF condition',I.ConditionExpr,pekIdent,'a');
  AssertEquals('For statement',TPasImplWithDo,I.ifBranch.ClassType);
  AssertEquals('For statement',TPasImplForLoop,I.ElseBranch.ClassType);
end;

procedure TTestStatementParser.TestIfSemiColonElseError;

begin
  DeclareVar('boolean');
  ExpectParserError('No semicolon before else',['if a then','  begin','  end;','else','  begin','  end']);
end;

procedure TTestStatementParser.TestNestedIf;
Var
  I : TPasImplIfElse;
begin
  DeclareVar('boolean');
  DeclareVar('boolean','b');
  TestStatement(['if a then','  if b then','    begin','    end','else','  begin','  end']);
  I:=AssertStatement('If statement',TPasImplIfElse) as TPasImplIfElse;
  AssertExpression('IF condition',I.ConditionExpr,pekIdent,'a');
  AssertNotNull('if branch',I.IfBranch);
  AssertNull('Else branch',i.ElseBranch);
  AssertEquals('if in if branch',TPasImplIfElse,I.ifBranch.ClassType);
  I:=I.Ifbranch as TPasImplIfElse;
  AssertEquals('begin end block',TPasImplBeginBlock,I.ElseBranch.ClassType);

end;

procedure TTestStatementParser.TestNestedIfElse;

Var
  I : TPasImplIfElse;

begin
  DeclareVar('boolean');
  TestStatement(['if a then','  if b then','    begin','    end','  else','    begin','    end','else','  begin','end']);
  I:=AssertStatement('If statement',TPasImplIfElse) as TPasImplIfElse;
  AssertExpression('IF condition',I.ConditionExpr,pekIdent,'a');
  AssertNotNull('if branch',I.IfBranch);
  AssertNotNull('Else branch',i.ElseBranch);
  AssertEquals('begin end block',TPasImplBeginBlock,I.ElseBranch.ClassType);
  AssertEquals('if in if branch',TPasImplIfElse,I.ifBranch.ClassType);
  I:=I.Ifbranch as TPasImplIfElse;
  AssertEquals('begin end block',TPasImplBeginBlock,I.ElseBranch.ClassType);
end;

procedure TTestStatementParser.TestWhile;

Var
  W : TPasImplWhileDo;

begin
  DeclareVar('boolean');
  TestStatement(['While a do ;']);
  W:=AssertStatement('While statement',TPasImplWhileDo) as TPasImplWhileDo;
  AssertExpression('While condition',W.ConditionExpr,pekIdent,'a');
  AssertNull('Empty body',W.Body);
end;

procedure TTestStatementParser.TestWhileBlock;
Var
  W : TPasImplWhileDo;

begin
  DeclareVar('boolean');
  TestStatement(['While a do','  begin','  end']);
  W:=AssertStatement('While statement',TPasImplWhileDo) as TPasImplWhileDo;
  AssertExpression('While condition',W.ConditionExpr,pekIdent,'a');
  AssertNotNull('Have while body',W.Body);
  AssertEquals('begin end block',TPasImplBeginBlock,W.Body.ClassType);
  AssertEquals('Empty block',0,TPasImplBeginBlock(W.Body).ELements.Count);
end;

procedure TTestStatementParser.TestWhileNested;

Var
  W : TPasImplWhileDo;

begin
  DeclareVar('boolean');
  DeclareVar('boolean','b');
  TestStatement(['While a do','  while b do','    begin','    end']);
  W:=AssertStatement('While statement',TPasImplWhileDo) as TPasImplWhileDo;
  AssertExpression('While condition',W.ConditionExpr,pekIdent,'a');
  AssertNotNull('Have while body',W.Body);
  AssertEquals('Nested while',TPasImplWhileDo,W.Body.ClassType);
  W:=W.Body as TPasImplWhileDo;
  AssertExpression('While condition',W.ConditionExpr,pekIdent,'b');
  AssertNotNull('Have nested while body',W.Body);
  AssertEquals('Nested begin end block',TPasImplBeginBlock,W.Body.ClassType);
  AssertEquals('Empty nested block',0,TPasImplBeginBlock(W.Body).ELements.Count);
end;

procedure TTestStatementParser.TestRepeat;

Var
  R : TPasImplRepeatUntil;

begin
  DeclareVar('boolean');
  TestStatement(['Repeat','Until a;']);
  R:=AssertStatement('Repeat statement',TPasImplRepeatUntil) as TPasImplRepeatUntil;
  AssertExpression('repeat condition',R.ConditionExpr,pekIdent,'a');
  AssertEquals('Empty body',0,R.Elements.Count);
end;

procedure TTestStatementParser.TestRepeatBlock;

Var
  R : TPasImplRepeatUntil;

begin
  DeclareVar('boolean');
  TestStatement(['Repeat','begin','end;','Until a;']);
  R:=AssertStatement('repeat statement',TPasImplRepeatUntil) as TPasImplRepeatUntil;
  AssertExpression('repeat condition',R.ConditionExpr,pekIdent,'a');
  AssertEquals('Have statement',1,R.Elements.Count);
  AssertEquals('begin end block',TPasImplBeginBlock,TObject(R.Elements[0]).ClassType);
  AssertEquals('Empty block',0,TPasImplBeginBlock(R.Elements[0]).ELements.Count);
end;

procedure TTestStatementParser.TestRepeatBlockNosemicolon;

Var
  R : TPasImplRepeatUntil;

begin
  DeclareVar('boolean');
  TestStatement(['Repeat','begin','end','Until a;']);
  R:=AssertStatement('repeat statement',TPasImplRepeatUntil) as TPasImplRepeatUntil;
  AssertExpression('repeat condition',R.ConditionExpr,pekIdent,'a');
  AssertEquals('Have statement',1,R.Elements.Count);
  AssertEquals('begin end block',TPasImplBeginBlock,TObject(R.Elements[0]).ClassType);
  AssertEquals('Empty block',0,TPasImplBeginBlock(R.Elements[0]).ELements.Count);
end;

procedure TTestStatementParser.TestRepeatNested;

Var
  R : TPasImplRepeatUntil;

begin
  DeclareVar('boolean');
  DeclareVar('boolean','b');
  TestStatement(['Repeat','repeat','begin','end','until b','Until a;']);
  R:=AssertStatement('repeat statement',TPasImplRepeatUntil) as TPasImplRepeatUntil;
  AssertExpression('repeat condition',R.ConditionExpr,pekIdent,'a');
  AssertEquals('Have statement',1,R.Elements.Count);
  AssertEquals('Nested repeat',TPasImplRepeatUntil,TObject(R.Elements[0]).ClassType);
  R:=TPasImplRepeatUntil(R.Elements[0]);
  AssertExpression('repeat condition',R.ConditionExpr,pekIdent,'b');
  AssertEquals('Have statement',1,R.Elements.Count);
  AssertEquals('begin end block',TPasImplBeginBlock,TObject(R.Elements[0]).ClassType);
  AssertEquals('Empty block',0,TPasImplBeginBlock(R.Elements[0]).ELements.Count);
end;

procedure TTestStatementParser.TestFor;

Var
  F : TPasImplForLoop;

begin
  DeclareVar('integer');
  TestStatement(['For a:=1 to 10 do',';']);
  F:=AssertStatement('For statement',TPasImplForLoop) as TPasImplForLoop;
  AssertExpression('Loop variable name',F.VariableName,pekIdent,'a');
  AssertEquals('Loop type',ltNormal,F.Looptype);
  AssertEquals('Up loop',False,F.Down);
  AssertExpression('Start value',F.StartExpr,pekNumber,'1');
  AssertExpression('End value',F.EndExpr,pekNumber,'10');
  AssertNull('Empty body',F.Body);
end;

procedure TTestStatementParser.TestForIn;

Var
  F : TPasImplForLoop;

begin
  DeclareVar('integer');
  TestStatement(['For a in SomeSet Do',';']);
  F:=AssertStatement('For statement',TPasImplForLoop) as TPasImplForLoop;
  AssertExpression('Loop variable name',F.VariableName,pekIdent,'a');
  AssertEquals('Loop type',ltIn,F.Looptype);
  AssertEquals('In loop',False,F.Down);
  AssertExpression('Start value',F.StartExpr,pekIdent,'SomeSet');
  AssertNull('Loop type',F.EndExpr);
  AssertNull('Empty body',F.Body);
end;

procedure TTestStatementParser.TestForExpr;
Var
  F : TPasImplForLoop;
  B : TBinaryExpr;

begin
  DeclareVar('integer');
  TestStatement(['For a:=1+1 to 5+5 do',';']);
  F:=AssertStatement('For statement',TPasImplForLoop) as TPasImplForLoop;
  AssertExpression('Loop variable name',F.VariableName,pekIdent,'a');
  AssertEquals('Up loop',False,F.Down);
  AssertExpression('Start expression',F.StartExpr,pekBinary,TBinaryExpr);
  B:=F.StartExpr as TBinaryExpr;
  AssertExpression('Start value left',B.left,pekNumber,'1');
  AssertExpression('Start value right',B.right,pekNumber,'1');
  AssertExpression('Start expression',F.StartExpr,pekBinary,TBinaryExpr);
  B:=F.EndExpr as TBinaryExpr;
  AssertExpression('End value left',B.left,pekNumber,'5');
  AssertExpression('End value right',B.right,pekNumber,'5');
  AssertNull('Empty body',F.Body);
end;

procedure TTestStatementParser.TestForBlock;

Var
  F : TPasImplForLoop;

begin
  DeclareVar('integer');
  TestStatement(['For a:=1 to 10 do','begin','end']);
  F:=AssertStatement('For statement',TPasImplForLoop) as TPasImplForLoop;
  AssertExpression('Loop variable name',F.VariableName,pekIdent,'a');
  AssertEquals('Up loop',False,F.Down);
  AssertExpression('Start value',F.StartExpr,pekNumber,'1');
  AssertExpression('End value',F.EndExpr,pekNumber,'10');
  AssertNotNull('Have for body',F.Body);
  AssertEquals('begin end block',TPasImplBeginBlock,F.Body.ClassType);
  AssertEquals('Empty block',0,TPasImplBeginBlock(F.Body).ELements.Count);
end;

procedure TTestStatementParser.TestDowntoBlock;

Var
  F : TPasImplForLoop;

begin
  DeclareVar('integer');
  TestStatement(['For a:=10 downto 1 do','begin','end']);
  F:=AssertStatement('For statement',TPasImplForLoop) as TPasImplForLoop;
  AssertExpression('Loop variable name',F.VariableName,pekIdent,'a');
  AssertEquals('Down loop',True,F.Down);
  AssertExpression('Start value',F.StartExpr,pekNumber,'10');
  AssertExpression('End value',F.EndExpr,pekNumber,'1');
  AssertNotNull('Have for body',F.Body);
  AssertEquals('begin end block',TPasImplBeginBlock,F.Body.ClassType);
  AssertEquals('Empty block',0,TPasImplBeginBlock(F.Body).ELements.Count);
end;

procedure TTestStatementParser.TestForNested;
Var
  F : TPasImplForLoop;

begin
  DeclareVar('integer');
  DeclareVar('integer','b');
  TestStatement(['For a:=1 to 10 do','For b:=11 to 20 do','begin','end']);
  F:=AssertStatement('For statement',TPasImplForLoop) as TPasImplForLoop;
  AssertExpression('Loop variable name',F.VariableName,pekIdent,'a');
  AssertEquals('Up loop',False,F.Down);
  AssertExpression('Start value',F.StartExpr,pekNumber,'1');
  AssertExpression('End value',F.EndExpr,pekNumber,'10');
  AssertNotNull('Have while body',F.Body);
  AssertEquals('begin end block',TPasImplForLoop,F.Body.ClassType);
  F:=F.Body as TPasImplForLoop;
  AssertExpression('Loop variable name',F.VariableName,pekIdent,'b');
  AssertEquals('Up loop',False,F.Down);
  AssertExpression('Start value',F.StartExpr,pekNumber,'11');
  AssertExpression('End value',F.EndExpr,pekNumber,'20');
  AssertNotNull('Have for body',F.Body);
  AssertEquals('begin end block',TPasImplBeginBlock,F.Body.ClassType);
  AssertEquals('Empty block',0,TPasImplBeginBlock(F.Body).ELements.Count);
end;

procedure TTestStatementParser.TestWith;

Var
  W : TpasImplWithDo;

begin
  DeclareVar('record X,Y : Integer; end');
  TestStatement(['With a do','begin','end']);
  W:=AssertStatement('For statement',TpasImplWithDo) as TpasImplWithDo;
  AssertEquals('1 expression',1,W.Expressions.Count);
  AssertExpression('With identifier',TPasExpr(W.Expressions[0]),pekIdent,'a');
  AssertNotNull('Have with body',W.Body);
  AssertEquals('begin end block',TPasImplBeginBlock,W.Body.ClassType);
  AssertEquals('Empty block',0,TPasImplBeginBlock(W.Body).ELements.Count);
end;

procedure TTestStatementParser.TestWithMultiple;
Var
  W : TpasImplWithDo;

begin
  DeclareVar('record X,Y : Integer; end');
  DeclareVar('record W,Z : Integer; end','b');
  TestStatement(['With a,b do','begin','end']);
  W:=AssertStatement('For statement',TpasImplWithDo) as TpasImplWithDo;
  AssertEquals('2 expressions',2,W.Expressions.Count);
  AssertExpression('With identifier 1',TPasExpr(W.Expressions[0]),pekIdent,'a');
  AssertExpression('With identifier 2',TPasExpr(W.Expressions[1]),pekIdent,'b');
  AssertNotNull('Have with body',W.Body);
  AssertEquals('begin end block',TPasImplBeginBlock,W.Body.ClassType);
  AssertEquals('Empty block',0,TPasImplBeginBlock(W.Body).ELements.Count);
end;

procedure TTestStatementParser.TestCaseEmpty;
begin
  DeclareVar('integer');
  AddStatements(['case a of','end;']);
  ExpectParserError('Empty case not allowed');
end;

procedure TTestStatementParser.TestCaseOneInteger;

Var
  C : TPasImplCaseOf;
  S : TPasImplCaseStatement;

begin
  DeclareVar('integer');
  TestStatement(['case a of','1 : ;','end;']);
  C:=AssertStatement('Case statement',TpasImplCaseOf) as TpasImplCaseOf;
  AssertNotNull('Have case expression',C.CaseExpr);
  AssertExpression('Case expression',C.CaseExpr,pekIdent,'a');
  AssertNull('No else branch',C.ElseBranch);
  AssertEquals('One case label',1,C.Elements.Count);
  AssertEquals('Correct case for case label',TPasImplCaseStatement,TPasElement(C.Elements[0]).ClassType);
  S:=TPasImplCaseStatement(C.Elements[0]);
  AssertEquals('1 expression for case',1,S.Expressions.Count);
  AssertExpression('With identifier 1',TPasExpr(S.Expressions[0]),pekNumber,'1');
  AssertEquals('Empty case label statement',0,S.Elements.Count);
  AssertNull('Empty case label statement',S.Body);
end;

procedure TTestStatementParser.TestCaseTwoIntegers;

Var
  C : TPasImplCaseOf;
  S : TPasImplCaseStatement;

begin
  DeclareVar('integer');
  TestStatement(['case a of','1,2 : ;','end;']);
  C:=AssertStatement('Case statement',TpasImplCaseOf) as TpasImplCaseOf;
  AssertNotNull('Have case expression',C.CaseExpr);
  AssertExpression('Case expression',C.CaseExpr,pekIdent,'a');
  AssertNull('No else branch',C.ElseBranch);
  AssertEquals('One case label',1,C.Elements.Count);
  AssertEquals('Correct case for case label',TPasImplCaseStatement,TPasElement(C.Elements[0]).ClassType);
  S:=TPasImplCaseStatement(C.Elements[0]);
  AssertEquals('2 expressions for case',2,S.Expressions.Count);
  AssertExpression('With identifier 1',TPasExpr(S.Expressions[0]),pekNumber,'1');
  AssertExpression('With identifier 2',TPasExpr(S.Expressions[1]),pekNumber,'2');
  AssertEquals('Empty case label statement',0,S.Elements.Count);
  AssertNull('Empty case label statement',S.Body);
end;

procedure TTestStatementParser.TestCaseRange;
Var
  C : TPasImplCaseOf;
  S : TPasImplCaseStatement;

begin
  DeclareVar('integer');
  TestStatement(['case a of','1..3 : ;','end;']);
  C:=AssertStatement('Case statement',TpasImplCaseOf) as TpasImplCaseOf;
  AssertNotNull('Have case expression',C.CaseExpr);
  AssertExpression('Case expression',C.CaseExpr,pekIdent,'a');
  AssertNull('No else branch',C.ElseBranch);
  AssertEquals('One case label',1,C.Elements.Count);
  AssertEquals('Correct case for case label',TPasImplCaseStatement,TPasElement(C.Elements[0]).ClassType);
  S:=TPasImplCaseStatement(C.Elements[0]);
  AssertEquals('1 expression for case',1,S.Expressions.Count);
  AssertExpression('With identifier 1',TPasExpr(S.Expressions[0]),pekRange,TBinaryExpr);
  AssertEquals('Empty case label statement',0,S.Elements.Count);
  AssertNull('Empty case label statement',S.Body);
end;

procedure TTestStatementParser.TestCaseRangeSeparate;
Var
  C : TPasImplCaseOf;
  S : TPasImplCaseStatement;

begin
  DeclareVar('integer');
  TestStatement(['case a of','1..3,5 : ;','end;']);
  C:=AssertStatement('Case statement',TpasImplCaseOf) as TpasImplCaseOf;
  AssertNotNull('Have case expression',C.CaseExpr);
  AssertExpression('Case expression',C.CaseExpr,pekIdent,'a');
  AssertNull('No else branch',C.ElseBranch);
  AssertEquals('One case label',1,C.Elements.Count);
  AssertEquals('Correct case for case label',TPasImplCaseStatement,TPasElement(C.Elements[0]).ClassType);
  S:=TPasImplCaseStatement(C.Elements[0]);
  AssertEquals('2 expressions for case',2,S.Expressions.Count);
  AssertExpression('With identifier 1',TPasExpr(S.Expressions[0]),pekRange,TBinaryExpr);
  AssertExpression('With identifier 2',TPasExpr(S.Expressions[1]),pekNumber,'5');
  AssertEquals('Empty case label statement',0,S.Elements.Count);
  AssertNull('Empty case label statement',S.Body);
end;

procedure TTestStatementParser.TestCase2Cases;
Var
  C : TPasImplCaseOf;
  S : TPasImplCaseStatement;

begin
  DeclareVar('integer');
  TestStatement(['case a of','1 : ;','2 : ;','end;']);
  C:=AssertStatement('Case statement',TpasImplCaseOf) as TpasImplCaseOf;
  AssertNotNull('Have case expression',C.CaseExpr);
  AssertExpression('Case expression',C.CaseExpr,pekIdent,'a');
  AssertNull('No else branch',C.ElseBranch);
  AssertEquals('Two case labels',2,C.Elements.Count);
  AssertEquals('Correct case for case label 1',TPasImplCaseStatement,TPasElement(C.Elements[0]).ClassType);
  S:=TPasImplCaseStatement(C.Elements[0]);
  AssertEquals('2 expressions for case 1',1,S.Expressions.Count);
  AssertExpression('Case 1 With identifier 1',TPasExpr(S.Expressions[0]),pekNumber,'1');
  AssertEquals('Empty case label statement 1',0,S.Elements.Count);
  AssertNull('Empty case label statement 1',S.Body);
  // Two
  AssertEquals('Correct case for case label 2',TPasImplCaseStatement,TPasElement(C.Elements[1]).ClassType);
  S:=TPasImplCaseStatement(C.Elements[1]);
  AssertEquals('2 expressions for case 2',1,S.Expressions.Count);
  AssertExpression('Case 2 With identifier 1',TPasExpr(S.Expressions[0]),pekNumber,'2');
  AssertEquals('Empty case label statement 2',0,S.Elements.Count);
  AssertNull('Empty case label statement 2',S.Body);
end;

procedure TTestStatementParser.TestCaseBlock;

Var
  C : TPasImplCaseOf;
  S : TPasImplCaseStatement;
  B : TPasImplbeginBlock;

begin
  DeclareVar('integer');
  TestStatement(['case a of','1 : begin end;','end;']);
  C:=AssertStatement('Case statement',TpasImplCaseOf) as TpasImplCaseOf;
  AssertNotNull('Have case expression',C.CaseExpr);
  AssertExpression('Case expression',C.CaseExpr,pekIdent,'a');
  AssertNull('No else branch',C.ElseBranch);
  AssertEquals('Two case labels',1,C.Elements.Count);
  AssertEquals('Correct case for case label 1',TPasImplCaseStatement,TPasElement(C.Elements[0]).ClassType);
  S:=TPasImplCaseStatement(C.Elements[0]);
  AssertEquals('2 expressions for case 1',1,S.Expressions.Count);
  AssertExpression('Case With identifier 1',TPasExpr(S.Expressions[0]),pekNumber,'1');
  AssertEquals('1 case label statement',1,S.Elements.Count);
  AssertEquals('Correct case for case label 1',TPasImplbeginBlock,TPasElement(S.Elements[0]).ClassType);
  B:=TPasImplbeginBlock(S.Elements[0]);
  AssertEquals('0 statements in block',0,B.Elements.Count);

end;

procedure TTestStatementParser.TestCaseElseBlockEmpty;

Var
  C : TPasImplCaseOf;
  S : TPasImplCaseStatement;
  B : TPasImplbeginBlock;

begin
  DeclareVar('integer');
  TestStatement(['case a of','1 : begin end;','else',' end;']);
  C:=AssertStatement('Case statement',TpasImplCaseOf) as TpasImplCaseOf;
  AssertNotNull('Have case expression',C.CaseExpr);
  AssertExpression('Case expression',C.CaseExpr,pekIdent,'a');
  AssertEquals('Two case labels',2,C.Elements.Count);
  AssertEquals('Correct case for case label 1',TPasImplCaseStatement,TPasElement(C.Elements[0]).ClassType);
  S:=TPasImplCaseStatement(C.Elements[0]);
  AssertEquals('2 expressions for case 1',1,S.Expressions.Count);
  AssertExpression('Case With identifier 1',TPasExpr(S.Expressions[0]),pekNumber,'1');
  AssertEquals('1 case label statement',1,S.Elements.Count);
  AssertEquals('Correct case for case label 1',TPasImplbeginBlock,TPasElement(S.Elements[0]).ClassType);
  B:=TPasImplbeginBlock(S.Elements[0]);
  AssertEquals('0 statements in block',0,B.Elements.Count);
  AssertNotNull('Have else branch',C.ElseBranch);
  AssertEquals('Correct else branch class',TPasImplCaseElse,C.ElseBranch.ClassType);
  AssertEquals('Zero statements ',0,TPasImplCaseElse(C.ElseBranch).Elements.Count);
end;

procedure TTestStatementParser.TestCaseOtherwiseBlockEmpty;

Var
  C : TPasImplCaseOf;
begin
  DeclareVar('integer');
  TestStatement(['case a of','1 : begin end;','otherwise',' end;']);
  C:=AssertStatement('Case statement',TpasImplCaseOf) as TpasImplCaseOf;
  AssertNotNull('Have case expression',C.CaseExpr);
  AssertNotNull('Have else branch',C.ElseBranch);
  AssertEquals('Correct else branch class',TPasImplCaseElse,C.ElseBranch.ClassType);
  AssertEquals('Zero statements ',0,TPasImplCaseElse(C.ElseBranch).Elements.Count);
end;

procedure TTestStatementParser.TestCaseElseBlockAssignment;
Var
  C : TPasImplCaseOf;
  S : TPasImplCaseStatement;
  B : TPasImplbeginBlock;

begin
  DeclareVar('integer');
  TestStatement(['case a of','1 : begin end;','else','a:=1',' end;']);
  C:=AssertStatement('Case statement',TpasImplCaseOf) as TpasImplCaseOf;
  AssertNotNull('Have case expression',C.CaseExpr);
  AssertExpression('Case expression',C.CaseExpr,pekIdent,'a');
  AssertEquals('Two case labels',2,C.Elements.Count);
  AssertEquals('Correct case for case label 1',TPasImplCaseStatement,TPasElement(C.Elements[0]).ClassType);
  S:=TPasImplCaseStatement(C.Elements[0]);
  AssertEquals('2 expressions for case 1',1,S.Expressions.Count);
  AssertExpression('Case With identifier 1',TPasExpr(S.Expressions[0]),pekNumber,'1');
  AssertEquals('1 case label statement',1,S.Elements.Count);
  AssertEquals('Correct case for case label 1',TPasImplbeginBlock,TPasElement(S.Elements[0]).ClassType);
  B:=TPasImplbeginBlock(S.Elements[0]);
  AssertEquals('0 statements in block',0,B.Elements.Count);
  AssertNotNull('Have else branch',C.ElseBranch);
  AssertEquals('Correct else branch class',TPasImplCaseElse,C.ElseBranch.ClassType);
  AssertEquals('1 statement in else branch ',1,TPasImplCaseElse(C.ElseBranch).Elements.Count);
end;

procedure TTestStatementParser.TestCaseElseBlock2Assignments;

Var
  C : TPasImplCaseOf;
  S : TPasImplCaseStatement;
  B : TPasImplbeginBlock;

begin
  DeclareVar('integer');
  TestStatement(['case a of','1 : begin end;','else','a:=1;','a:=32;',' end;']);
  C:=AssertStatement('Case statement',TpasImplCaseOf) as TpasImplCaseOf;
  AssertNotNull('Have case expression',C.CaseExpr);
  AssertExpression('Case expression',C.CaseExpr,pekIdent,'a');
  AssertEquals('Two case labels',2,C.Elements.Count);
  AssertEquals('Correct case for case label 1',TPasImplCaseStatement,TPasElement(C.Elements[0]).ClassType);
  S:=TPasImplCaseStatement(C.Elements[0]);
  AssertEquals('2 expressions for case 1',1,S.Expressions.Count);
  AssertExpression('Case With identifier 1',TPasExpr(S.Expressions[0]),pekNumber,'1');
  AssertEquals('1 case label statement',1,S.Elements.Count);
  AssertEquals('Correct case for case label 1',TPasImplbeginBlock,TPasElement(S.Elements[0]).ClassType);
  B:=TPasImplbeginBlock(S.Elements[0]);
  AssertEquals('0 statements in block',0,B.Elements.Count);
  AssertNotNull('Have else branch',C.ElseBranch);
  AssertEquals('Correct else branch class',TPasImplCaseElse,C.ElseBranch.ClassType);
  AssertEquals('2 statements in else branch ',2,TPasImplCaseElse(C.ElseBranch).Elements.Count);
end;

procedure TTestStatementParser.TestCaseIfCaseElse;

Var
  C : TPasImplCaseOf;

begin
  DeclareVar('integer');
  DeclareVar('boolean','b');
  TestStatement(['case a of','1 : if b then',' begin end;','else',' end;']);
  C:=AssertStatement('Case statement',TpasImplCaseOf) as TpasImplCaseOf;
  AssertNotNull('Have case expression',C.CaseExpr);
  AssertExpression('Case expression',C.CaseExpr,pekIdent,'a');
  AssertEquals('Two case labels',2,C.Elements.Count);
  AssertNotNull('Have else branch',C.ElseBranch);
  AssertEquals('Correct else branch class',TPasImplCaseElse,C.ElseBranch.ClassType);
  AssertEquals('0 statement in else branch ',0,TPasImplCaseElse(C.ElseBranch).Elements.Count);
end;

procedure TTestStatementParser.TestCaseIfElse;
Var
  C : TPasImplCaseOf;
  S : TPasImplCaseStatement;

begin
  DeclareVar('integer');
  DeclareVar('boolean','b');
  TestStatement(['case a of','1 : if b then',' begin end','else','begin','end',' end;']);
  C:=AssertStatement('Case statement',TpasImplCaseOf) as TpasImplCaseOf;
  AssertNotNull('Have case expression',C.CaseExpr);
  AssertExpression('Case expression',C.CaseExpr,pekIdent,'a');
  AssertEquals('Two case labels',1,C.Elements.Count);
  AssertNull('Have no else branch',C.ElseBranch);
  S:=TPasImplCaseStatement(C.Elements[0]);
  AssertEquals('2 expressions for case 1',1,S.Expressions.Count);
  AssertExpression('Case With identifier 1',TPasExpr(S.Expressions[0]),pekNumber,'1');
  AssertEquals('1 case label statement',1,S.Elements.Count);
  AssertEquals('If statement in case label 1',TPasImplIfElse,TPasElement(S.Elements[0]).ClassType);
  AssertNotNull('If statement has else block',TPasImplIfElse(S.Elements[0]).ElseBranch);
end;

procedure TTestStatementParser.TestCaseElseNoSemicolon;
Var
  C : TPasImplCaseOf;
  S : TPasImplCaseStatement;
begin
  DeclareVar('integer');
  TestStatement(['case a of','1 : dosomething;','2 : dosomethingmore','else','a:=1;','end;']);
  C:=AssertStatement('Case statement',TpasImplCaseOf) as TpasImplCaseOf;
  AssertNotNull('Have case expression',C.CaseExpr);
  AssertExpression('Case expression',C.CaseExpr,pekIdent,'a');
  AssertEquals('case label count',3,C.Elements.Count);
  S:=TPasImplCaseStatement(C.Elements[0]);
  AssertEquals('case 1',1,S.Expressions.Count);
  AssertExpression('Case With identifier 1',TPasExpr(S.Expressions[0]),pekNumber,'1');
  S:=TPasImplCaseStatement(C.Elements[1]);
  AssertEquals('case 2',1,S.Expressions.Count);
  AssertExpression('Case With identifier 1',TPasExpr(S.Expressions[0]),pekNumber,'2');
  AssertEquals('third is else',TPasImplCaseElse,TObject(C.Elements[2]).ClassType);
  AssertNotNull('Have else branch',C.ElseBranch);
  AssertEquals('Correct else branch class',TPasImplCaseElse,C.ElseBranch.ClassType);
  AssertEquals('1 statements in else branch ',1,TPasImplCaseElse(C.ElseBranch).Elements.Count);
end;

procedure TTestStatementParser.TestCaseIfElseNoSemicolon;
Var
  C : TPasImplCaseOf;
  S : TPasImplCaseStatement;
begin
  DeclareVar('integer');
  TestStatement(['case a of','1 : dosomething;','2: if b then',' dosomething','else  dosomethingmore','else','a:=1;','end;']);
  C:=AssertStatement('Case statement',TpasImplCaseOf) as TpasImplCaseOf;
  AssertNotNull('Have case expression',C.CaseExpr);
  AssertExpression('Case expression',C.CaseExpr,pekIdent,'a');
  AssertEquals('case label count',3,C.Elements.Count);
  S:=TPasImplCaseStatement(C.Elements[0]);
  AssertEquals('case 1',1,S.Expressions.Count);
  AssertExpression('Case With identifier 1',TPasExpr(S.Expressions[0]),pekNumber,'1');
  S:=TPasImplCaseStatement(C.Elements[1]);
  AssertEquals('case 2',1,S.Expressions.Count);
  AssertExpression('Case With identifier 1',TPasExpr(S.Expressions[0]),pekNumber,'2');
  AssertEquals('third is else',TPasImplCaseElse,TObject(C.Elements[2]).ClassType);
  AssertNotNull('Have else branch',C.ElseBranch);
  AssertEquals('Correct else branch class',TPasImplCaseElse,C.ElseBranch.ClassType);
  AssertEquals('1 statements in else branch ',1,TPasImplCaseElse(C.ElseBranch).Elements.Count);
end;

procedure TTestStatementParser.TestCaseIfOtherwiseNoSemicolon;
Var
  C : TPasImplCaseOf;
  S : TPasImplCaseStatement;
begin
  DeclareVar('integer');
  TestStatement(['case a of','1 : dosomething;','2: if b then',' dosomething','else  dosomethingmore','otherwise','a:=1;','end;']);
  C:=AssertStatement('Case statement',TpasImplCaseOf) as TpasImplCaseOf;
  AssertNotNull('Have case expression',C.CaseExpr);
  AssertExpression('Case expression',C.CaseExpr,pekIdent,'a');
  AssertEquals('case label count',3,C.Elements.Count);
  S:=TPasImplCaseStatement(C.Elements[0]);
  AssertEquals('case 1',1,S.Expressions.Count);
  AssertExpression('Case With identifier 1',TPasExpr(S.Expressions[0]),pekNumber,'1');
  S:=TPasImplCaseStatement(C.Elements[1]);
  AssertEquals('case 2',1,S.Expressions.Count);
  AssertExpression('Case With identifier 1',TPasExpr(S.Expressions[0]),pekNumber,'2');
  AssertEquals('third is else',TPasImplCaseElse,TObject(C.Elements[2]).ClassType);
  AssertNotNull('Have else branch',C.ElseBranch);
  AssertEquals('Correct else branch class',TPasImplCaseElse,C.ElseBranch.ClassType);
  AssertEquals('1 statements in else branch ',1,TPasImplCaseElse(C.ElseBranch).Elements.Count);
end;



procedure TTestStatementParser.TestRaise;

Var
  R : TPasImplRaise;

begin
  DeclareVar('Exception');
  TestStatement('Raise A;');
  R:=AssertStatement('Raise statement',TPasImplRaise) as TPasImplRaise;
  AssertEquals(0,R.Elements.Count);
  AssertNotNull(R.ExceptObject);
  AssertNull(R.ExceptAddr);
  AssertExpression('Expression object',R.ExceptObject,pekIdent,'A');
end;

procedure TTestStatementParser.TestRaiseEmpty;
Var
  R : TPasImplRaise;

begin
  TestStatement('Raise;');
  R:=AssertStatement('Raise statement',TPasImplRaise) as TPasImplRaise;
  AssertEquals(0,R.Elements.Count);
  AssertNull(R.ExceptObject);
  AssertNull(R.ExceptAddr);
end;

procedure TTestStatementParser.TestRaiseAt;

Var
  R : TPasImplRaise;

begin
  DeclareVar('Exception');
  DeclareVar('Pointer','B');
  TestStatement('Raise A at B;');
  R:=AssertStatement('Raise statement',TPasImplRaise) as TPasImplRaise;
  AssertEquals(0,R.Elements.Count);
  AssertNotNull(R.ExceptObject);
  AssertNotNull(R.ExceptAddr);
  AssertExpression('Expression object',R.ExceptAddr,pekIdent,'B');
end;

procedure TTestStatementParser.TestTryFinally;

Var
  T : TPasImplTry;
  S : TPasImplSimple;
  F : TPasImplTryFinally;

begin
  TestStatement(['Try','  DoSomething;','finally','  DoSomethingElse','end']);
  T:=AssertStatement('Try statement',TPasImplTry) as TPasImplTry;
  AssertEquals(1,T.Elements.Count);
  AssertNotNull(T.FinallyExcept);
  AssertNull(T.ElseBranch);
  AssertNotNull(T.Elements[0]);
  AssertEquals('Simple statement',TPasImplSimple,TPasElement(T.Elements[0]).ClassType);
  S:=TPasImplSimple(T.Elements[0]);
  AssertExpression('DoSomething call',S.Expr,pekIdent,'DoSomething');
  AssertEquals('Simple statement',TPasImplSimple,TPasElement(T.Elements[0]).ClassType);
  AssertEquals('Finally statement',TPasImplTryFinally,T.FinallyExcept.ClassType);
  F:=TPasImplTryFinally(T.FinallyExcept);
  AssertEquals(1,F.Elements.Count);
  AssertEquals('Simple statement',TPasImplSimple,TPasElement(F.Elements[0]).ClassType);
  S:=TPasImplSimple(F.Elements[0]);
  AssertExpression('DoSomethingElse call',S.Expr,pekIdent,'DoSomethingElse');
end;

procedure TTestStatementParser.TestTryFinallyEmpty;
Var
  T : TPasImplTry;
  F : TPasImplTryFinally;

begin
  TestStatement(['Try','finally','end;']);
  T:=AssertStatement('Try statement',TPasImplTry) as TPasImplTry;
  AssertEquals(0,T.Elements.Count);
  AssertNotNull(T.FinallyExcept);
  AssertNull(T.ElseBranch);
  AssertEquals('Finally statement',TPasImplTryFinally,T.FinallyExcept.ClassType);
  F:=TPasImplTryFinally(T.FinallyExcept);
  AssertEquals(0,F.Elements.Count);
end;

procedure TTestStatementParser.TestTryFinallyNested;
Var
  T : TPasImplTry;
  S : TPasImplSimple;
  F : TPasImplTryFinally;

begin
  TestStatement(['Try','  DoSomething1;','  Try','    DoSomething2;','  finally','    DoSomethingElse2','  end;','Finally','  DoSomethingElse1','end']);
  T:=AssertStatement('Try statement',TPasImplTry) as TPasImplTry;
  AssertEquals(2,T.Elements.Count);
  AssertNotNull(T.FinallyExcept);
  AssertNull(T.ElseBranch);
  AssertNotNull(T.Elements[0]);
  AssertEquals('Simple statement',TPasImplSimple,TPasElement(T.Elements[0]).ClassType);
  S:=TPasImplSimple(T.Elements[0]);
  AssertExpression('DoSomething call',S.Expr,pekIdent,'DoSomething1');
  AssertEquals('Simple statement',TPasImplSimple,TPasElement(T.Elements[0]).ClassType);
  AssertEquals('Finally statement',TPasImplTryFinally,T.FinallyExcept.ClassType);
  F:=TPasImplTryFinally(T.FinallyExcept);
  AssertEquals(1,F.Elements.Count);
  AssertEquals('Simple statement',TPasImplSimple,TPasElement(F.Elements[0]).ClassType);
  S:=TPasImplSimple(F.Elements[0]);
  AssertExpression('DoSomethingElse call',S.Expr,pekIdent,'DoSomethingElse1');
  // inner statement
  AssertNotNull(T.Elements[1]);
  AssertEquals('Nested try statement',TPasImplTry,TPasElement(T.Elements[1]).ClassType);
  T:=TPasImplTry(T.Elements[1]);
  AssertEquals(1,T.Elements.Count);
  AssertNotNull(T.FinallyExcept);
  AssertNull(T.ElseBranch);
  AssertNotNull(T.Elements[0]);
  AssertEquals('Simple statement',TPasImplSimple,TPasElement(T.Elements[0]).ClassType);
  S:=TPasImplSimple(T.Elements[0]);
  AssertExpression('DoSomething call',S.Expr,pekIdent,'DoSomething2');
  AssertEquals('Simple statement',TPasImplSimple,TPasElement(T.Elements[0]).ClassType);
  AssertEquals('Finally statement',TPasImplTryFinally,T.FinallyExcept.ClassType);
  F:=TPasImplTryFinally(T.FinallyExcept);
  AssertEquals(1,F.Elements.Count);
  AssertEquals('Simple statement',TPasImplSimple,TPasElement(F.Elements[0]).ClassType);
  S:=TPasImplSimple(F.Elements[0]);
  AssertExpression('DoSomethingElse call',S.Expr,pekIdent,'DoSomethingElse2');
end;

procedure TTestStatementParser.TestTryExcept;

Var
  T : TPasImplTry;
  S : TPasImplSimple;
  E : TPasImplTryExcept;

begin
  TestStatement(['Try','  DoSomething;','except','  DoSomethingElse','end']);
  T:=AssertStatement('Try statement',TPasImplTry) as TPasImplTry;
  AssertEquals(1,T.Elements.Count);
  AssertNotNull(T.FinallyExcept);
  AssertNull(T.ElseBranch);
  AssertNotNull(T.Elements[0]);
  AssertEquals('Simple statement',TPasImplSimple,TPasElement(T.Elements[0]).ClassType);
  S:=TPasImplSimple(T.Elements[0]);
  AssertExpression('DoSomething call',S.Expr,pekIdent,'DoSomething');
  AssertEquals('Simple statement',TPasImplSimple,TPasElement(T.Elements[0]).ClassType);
  AssertEquals('Except statement',TPasImplTryExcept,T.FinallyExcept.ClassType);
  E:=TPasImplTryExcept(T.FinallyExcept);
  AssertEquals(1,E.Elements.Count);
  AssertEquals('Simple statement',TPasImplSimple,TPasElement(E.Elements[0]).ClassType);
  S:=TPasImplSimple(E.Elements[0]);
  AssertExpression('DoSomethingElse call',S.Expr,pekIdent,'DoSomethingElse');
end;

procedure TTestStatementParser.TestTryExceptNested;
Var
  T : TPasImplTry;
  S : TPasImplSimple;
  E : TPasImplTryExcept;

begin
  TestStatement(['Try','  DoSomething1;','  try','    DoSomething2;','  except','    DoSomethingElse2','  end','except','  DoSomethingElse1','end']);
  T:=AssertStatement('Try statement',TPasImplTry) as TPasImplTry;
  AssertEquals(2,T.Elements.Count);
  AssertNotNull(T.FinallyExcept);
  AssertNull(T.ElseBranch);
  AssertNotNull(T.Elements[0]);
  AssertEquals('Simple statement',TPasImplSimple,TPasElement(T.Elements[0]).ClassType);
  S:=TPasImplSimple(T.Elements[0]);
  AssertExpression('DoSomething call',S.Expr,pekIdent,'DoSomething1');
  AssertEquals('Simple statement',TPasImplSimple,TPasElement(T.Elements[0]).ClassType);
  AssertEquals('Except statement',TPasImplTryExcept,T.FinallyExcept.ClassType);
  E:=TPasImplTryExcept(T.FinallyExcept);
  AssertEquals(1,E.Elements.Count);
  AssertEquals('Simple statement',TPasImplSimple,TPasElement(E.Elements[0]).ClassType);
  S:=TPasImplSimple(E.Elements[0]);
  AssertExpression('DoSomethingElse call',S.Expr,pekIdent,'DoSomethingElse1');
  AssertNotNull(T.Elements[1]);
  AssertEquals('Simple statement',TPasImplTry,TPasElement(T.Elements[1]).ClassType);
  T:=TPasImplTry(T.Elements[1]);
  AssertEquals(1,T.Elements.Count);
  AssertNotNull(T.FinallyExcept);
  AssertNull(T.ElseBranch);
  AssertNotNull(T.Elements[0]);
  AssertEquals('Simple statement 2',TPasImplSimple,TPasElement(T.Elements[0]).ClassType);
  S:=TPasImplSimple(T.Elements[0]);
  AssertExpression('DoSomething2 call ',S.Expr,pekIdent,'DoSomething2');
  AssertEquals('Simple statement2',TPasImplSimple,TPasElement(T.Elements[0]).ClassType);
  AssertEquals('Except statement2',TPasImplTryExcept,T.FinallyExcept.ClassType);
  E:=TPasImplTryExcept(T.FinallyExcept);
  AssertEquals(1,E.Elements.Count);
  AssertEquals('Simple statement2',TPasImplSimple,TPasElement(E.Elements[0]).ClassType);
  S:=TPasImplSimple(E.Elements[0]);
  AssertExpression('DoSomethingElse2 call',S.Expr,pekIdent,'DoSomethingElse2');
end;

procedure TTestStatementParser.TestTryExceptEmpty;

Var
  T : TPasImplTry;
  E : TPasImplTryExcept;

begin
  TestStatement(['Try','except','end;']);
  T:=AssertStatement('Try statement',TPasImplTry) as TPasImplTry;
  AssertEquals(0,T.Elements.Count);
  AssertNotNull(T.FinallyExcept);
  AssertNull(T.ElseBranch);
  AssertEquals('Except statement',TPasImplTryExcept,T.FinallyExcept.ClassType);
  E:=TPasImplTryExcept(T.FinallyExcept);
  AssertEquals(0,E.Elements.Count);
end;

procedure TTestStatementParser.TestTryExceptOn;

Var
  T : TPasImplTry;
  S : TPasImplSimple;
  E : TPasImplTryExcept;
  O : TPasImplExceptOn;

begin
  TestStatement(['Try','  DoSomething;','except','On E : Exception do','DoSomethingElse;','end']);
  T:=AssertStatement('Try statement',TPasImplTry) as TPasImplTry;
  AssertEquals(1,T.Elements.Count);
  AssertNotNull(T.FinallyExcept);
  AssertNull(T.ElseBranch);
  AssertNotNull(T.Elements[0]);
  AssertEquals('Simple statement',TPasImplSimple,TPasElement(T.Elements[0]).ClassType);
  S:=TPasImplSimple(T.Elements[0]);
  AssertExpression('DoSomething call',S.Expr,pekIdent,'DoSomething');
  AssertEquals('Simple statement',TPasImplSimple,TPasElement(T.Elements[0]).ClassType);
  AssertEquals('Except statement',TPasImplTryExcept,T.FinallyExcept.ClassType);
  E:=TPasImplTryExcept(T.FinallyExcept);
  AssertEquals(1,E.Elements.Count);
  AssertEquals('Except on handler',TPasImplExceptOn,TPasElement(E.Elements[0]).ClassType);
  O:=TPasImplExceptOn(E.Elements[0]);
  AssertEquals(1,O.Elements.Count);
  AssertEquals('Simple statement',TPasImplSimple,TPasElement(O.Elements[0]).ClassType);
  AssertEquals('Exception Variable name','E',O.VariableName);
  AssertEquals('Exception Type name','Exception',O.TypeName);
  S:=TPasImplSimple(O.Elements[0]);
  AssertExpression('DoSomethingElse call',S.Expr,pekIdent,'DoSomethingElse');
//  AssertEquals('Variable name',

end;

procedure TTestStatementParser.TestTryExceptOn2;

Var
  T : TPasImplTry;
  S : TPasImplSimple;
  E : TPasImplTryExcept;
  O : TPasImplExceptOn;

begin
  TestStatement(['Try','  DoSomething;','except',
                 'On E : Exception do','DoSomethingElse;',
                 'On Y : Exception2 do','DoSomethingElse2;',
                 'end']);
  T:=AssertStatement('Try statement',TPasImplTry) as TPasImplTry;
  AssertEquals(1,T.Elements.Count);
  AssertNotNull(T.FinallyExcept);
  AssertNull(T.ElseBranch);
  AssertNotNull(T.Elements[0]);
  AssertEquals('Simple statement',TPasImplSimple,TPasElement(T.Elements[0]).ClassType);
  S:=TPasImplSimple(T.Elements[0]);
  AssertExpression('DoSomething call',S.Expr,pekIdent,'DoSomething');
  AssertEquals('Simple statement',TPasImplSimple,TPasElement(T.Elements[0]).ClassType);
  AssertEquals('Except statement',TPasImplTryExcept,T.FinallyExcept.ClassType);
  E:=TPasImplTryExcept(T.FinallyExcept);
  AssertEquals(2,E.Elements.Count);
  // Exception handler 1
  AssertEquals('Except on handler',TPasImplExceptOn,TPasElement(E.Elements[0]).ClassType);
  O:=TPasImplExceptOn(E.Elements[0]);
  AssertEquals(1,O.Elements.Count);
  AssertEquals('Simple statement',TPasImplSimple,TPasElement(O.Elements[0]).ClassType);
  AssertEquals('Exception Variable name','E',O.VariableName);
  AssertEquals('Exception Type name','Exception',O.TypeName);
  S:=TPasImplSimple(O.Elements[0]);
  AssertExpression('DoSomethingElse call',S.Expr,pekIdent,'DoSomethingElse');
  // Exception handler 2
  AssertEquals('Except on handler',TPasImplExceptOn,TPasElement(E.Elements[1]).ClassType);
  O:=TPasImplExceptOn(E.Elements[1]);
  AssertEquals(1,O.Elements.Count);
  AssertEquals('Simple statement',TPasImplSimple,TPasElement(O.Elements[0]).ClassType);
  AssertEquals('Exception Variable name','Y',O.VariableName);
  AssertEquals('Exception Type name','Exception2',O.TypeName);
  S:=TPasImplSimple(O.Elements[0]);
  AssertExpression('DoSomethingElse call',S.Expr,pekIdent,'DoSomethingElse2');
end;

procedure TTestStatementParser.TestTryExceptOnElse;
Var
  T : TPasImplTry;
  S : TPasImplSimple;
  E : TPasImplTryExcept;
  O : TPasImplExceptOn;
  EE : TPasImplTryExceptElse;
  I : TPasImplIfElse;

begin
  DeclareVar('Boolean','b');
  // Check that Else belongs to Except, not to IF

  TestStatement(['Try','  DoSomething;','except','On E : Exception do','if b then','DoSomethingElse;','else','DoSomethingMore;','end']);
  T:=AssertStatement('Try statement',TPasImplTry) as TPasImplTry;
  AssertEquals(1,T.Elements.Count);
  AssertNotNull(T.FinallyExcept);
  AssertNotNull(T.ElseBranch);
  AssertNotNull(T.Elements[0]);
  AssertEquals('Simple statement',TPasImplSimple,TPasElement(T.Elements[0]).ClassType);
  S:=TPasImplSimple(T.Elements[0]);
  AssertExpression('DoSomething call',S.Expr,pekIdent,'DoSomething');
  AssertEquals('Simple statement',TPasImplSimple,TPasElement(T.Elements[0]).ClassType);
  AssertEquals('Except statement',TPasImplTryExcept,T.FinallyExcept.ClassType);
  E:=TPasImplTryExcept(T.FinallyExcept);
  AssertEquals(1,E.Elements.Count);
  AssertEquals('Except on handler',TPasImplExceptOn,TPasElement(E.Elements[0]).ClassType);
  O:=TPasImplExceptOn(E.Elements[0]);
  AssertEquals('Exception Variable name','E',O.VariableName);
  AssertEquals('Exception Type name','Exception',O.TypeName);
  AssertEquals(1,O.Elements.Count);
  AssertEquals('Simple statement',TPasImplIfElse,TPasElement(O.Elements[0]).ClassType);
  I:=TPasImplIfElse(O.Elements[0]);
  AssertEquals(1,I.Elements.Count);
  AssertNull('No else barcnh for if',I.ElseBranch);
  AssertEquals('Simple statement',TPasImplSimple,TPasElement(I.Elements[0]).ClassType);
  S:=TPasImplSimple(I.Elements[0]);
  AssertExpression('DoSomethingElse call',S.Expr,pekIdent,'DoSomethingElse');
  AssertEquals('Except Else statement',TPasImplTryExceptElse,T.ElseBranch.ClassType);
  EE:=TPasImplTryExceptElse(T.ElseBranch);
  AssertEquals(1,EE.Elements.Count);
  AssertNotNull(EE.Elements[0]);
  AssertEquals('Simple statement',TPasImplSimple,TPasElement(EE.Elements[0]).ClassType);
  S:=TPasImplSimple(EE.Elements[0]);
  AssertExpression('DoSomething call',S.Expr,pekIdent,'DoSomethingMore');
end;

procedure TTestStatementParser.TestTryExceptOnIfElse;
Var
  T : TPasImplTry;
  S : TPasImplSimple;
  E : TPasImplTryExcept;
  O : TPasImplExceptOn;
  EE : TPasImplTryExceptElse;

begin
  TestStatement(['Try','  DoSomething;','except','On E : Exception do','DoSomethingElse;','else','DoSomethingMore;','end']);
  T:=AssertStatement('Try statement',TPasImplTry) as TPasImplTry;
  AssertEquals(1,T.Elements.Count);
  AssertNotNull(T.FinallyExcept);
  AssertNotNull(T.ElseBranch);
  AssertNotNull(T.Elements[0]);
  AssertEquals('Simple statement',TPasImplSimple,TPasElement(T.Elements[0]).ClassType);
  S:=TPasImplSimple(T.Elements[0]);
  AssertExpression('DoSomething call',S.Expr,pekIdent,'DoSomething');
  AssertEquals('Simple statement',TPasImplSimple,TPasElement(T.Elements[0]).ClassType);
  AssertEquals('Except statement',TPasImplTryExcept,T.FinallyExcept.ClassType);
  E:=TPasImplTryExcept(T.FinallyExcept);
  AssertEquals(1,E.Elements.Count);
  AssertEquals('Except on handler',TPasImplExceptOn,TPasElement(E.Elements[0]).ClassType);
  O:=TPasImplExceptOn(E.Elements[0]);
  AssertEquals('Exception Variable name','E',O.VariableName);
  AssertEquals('Exception Type name','Exception',O.TypeName);
  AssertEquals(1,O.Elements.Count);
  AssertEquals('Simple statement',TPasImplSimple,TPasElement(O.Elements[0]).ClassType);
  S:=TPasImplSimple(O.Elements[0]);
  AssertExpression('DoSomethingElse call',S.Expr,pekIdent,'DoSomethingElse');
  AssertEquals('Except Else statement',TPasImplTryExceptElse,T.ElseBranch.ClassType);
  EE:=TPasImplTryExceptElse(T.ElseBranch);
  AssertEquals(1,EE.Elements.Count);
  AssertNotNull(EE.Elements[0]);
  AssertEquals('Simple statement',TPasImplSimple,TPasElement(EE.Elements[0]).ClassType);
  S:=TPasImplSimple(EE.Elements[0]);
  AssertExpression('DoSomething call',S.Expr,pekIdent,'DoSomethingMore');
end;

procedure TTestStatementParser.TestTryExceptOnElseNoSemicolo;
Var
  T : TPasImplTry;
  S : TPasImplSimple;
  E : TPasImplTryExcept;
  O : TPasImplExceptOn;
  EE : TPasImplTryExceptElse;
begin
  TestStatement(['Try','  DoSomething;','except','On E : Exception do','DoSomethingElse','else','DoSomethingMore','end']);
  T:=AssertStatement('Try statement',TPasImplTry) as TPasImplTry;
  AssertEquals(1,T.Elements.Count);
  AssertNotNull(T.FinallyExcept);
  AssertNotNull(T.ElseBranch);
  AssertNotNull(T.Elements[0]);
  AssertEquals('Simple statement',TPasImplSimple,TPasElement(T.Elements[0]).ClassType);
  S:=TPasImplSimple(T.Elements[0]);
  AssertExpression('DoSomething call',S.Expr,pekIdent,'DoSomething');
  AssertEquals('Simple statement',TPasImplSimple,TPasElement(T.Elements[0]).ClassType);
  AssertEquals('Except statement',TPasImplTryExcept,T.FinallyExcept.ClassType);
  E:=TPasImplTryExcept(T.FinallyExcept);
  AssertEquals(1,E.Elements.Count);
  AssertEquals('Except on handler',TPasImplExceptOn,TPasElement(E.Elements[0]).ClassType);
  O:=TPasImplExceptOn(E.Elements[0]);
  AssertEquals('Exception Variable name','E',O.VariableName);
  AssertEquals('Exception Type name','Exception',O.TypeName);
  AssertEquals(1,O.Elements.Count);
  AssertEquals('Simple statement',TPasImplSimple,TPasElement(O.Elements[0]).ClassType);
  S:=TPasImplSimple(O.Elements[0]);
  AssertExpression('DoSomethingElse call',S.Expr,pekIdent,'DoSomethingElse');
  AssertEquals('Except Else statement',TPasImplTryExceptElse,T.ElseBranch.ClassType);
  EE:=TPasImplTryExceptElse(T.ElseBranch);
  AssertEquals(1,EE.Elements.Count);
  AssertNotNull(EE.Elements[0]);
  AssertEquals('Simple statement',TPasImplSimple,TPasElement(EE.Elements[0]).ClassType);
  S:=TPasImplSimple(EE.Elements[0]);
  AssertExpression('DoSomething call',S.Expr,pekIdent,'DoSomethingMore');
end;

procedure TTestStatementParser.TestTryExceptRaise;
Var
  T : TPasImplTry;
  S : TPasImplSimple;
  E : TPasImplTryExcept;

begin
  TestStatement(['Try','  DoSomething;','except','  raise','end']);
  T:=AssertStatement('Try statement',TPasImplTry) as TPasImplTry;
  AssertEquals(1,T.Elements.Count);
  AssertNotNull(T.FinallyExcept);
  AssertNull(T.ElseBranch);
  AssertNotNull(T.Elements[0]);
  AssertEquals('Simple statement',TPasImplSimple,TPasElement(T.Elements[0]).ClassType);
  S:=TPasImplSimple(T.Elements[0]);
  AssertExpression('DoSomething call',S.Expr,pekIdent,'DoSomething');
  AssertEquals('Simple statement',TPasImplSimple,TPasElement(T.Elements[0]).ClassType);
  AssertEquals('Except statement',TPasImplTryExcept,T.FinallyExcept.ClassType);
  E:=TPasImplTryExcept(T.FinallyExcept);
  AssertEquals(1,E.Elements.Count);
  AssertEquals('Raise statement',TPasImplRaise,TPasElement(E.Elements[0]).ClassType);
end;

procedure TTestStatementParser.TestAsm;

Var
  T : TPasImplAsmStatement;

begin
  TestStatement(['asm','  mov eax,1','end;']);
  T:=AssertStatement('Asm statement',TPasImplAsmStatement) as TPasImplAsmStatement;
  AssertEquals('Asm tokens',4,T.Tokens.Count);
  AssertEquals('token 1 ','mov',T.Tokens[0]);
  AssertEquals('token 2 ','eax',T.Tokens[1]);
  AssertEquals('token 3 ',',',T.Tokens[2]);
  AssertEquals('token 4 ','1',T.Tokens[3]);
end;

procedure TTestStatementParser.TestAsmBlock;
begin
  Source.Add('{$MODE DELPHI}');
  Source.Add('function BitsHighest(X: Cardinal): Integer;');
  Source.Add('asm');
  Source.Add('end;');
  Source.Add('begin');
  Source.Add('end.');
  ParseModule;
end;

procedure TTestStatementParser.TestAsmBlockWithEndLabel;
begin
  Source.Add('{$MODE DELPHI}');
  Source.Add('function BitsHighest(X: Cardinal): Integer;');
  Source.Add('asm');
  Source.Add('  MOV ECX, EAX');
  Source.Add('  MOV EAX, -1');
  Source.Add('  BSR EAX, ECX');
  Source.Add('  JNZ @@End');
  Source.Add('  MOV EAX, -1');
  Source.Add('@@End:');
  Source.Add('end;');
  Source.Add('begin');
  Source.Add('end.');
  ParseModule;
end;

procedure TTestStatementParser.TestAsmBlockInIfThen;
begin
  Source.Add('{$MODE DELPHI}');
  Source.Add('function Get8087StatusWord(ClearExceptions: Boolean): Word;');
  Source.Add('  begin');
  Source.Add('    if ClearExceptions then');
  Source.Add('    asm');
  Source.Add('    end');
  Source.Add('    else');
  Source.Add('    asm');
  Source.Add('    end;');
  Source.Add('  end;');
  Source.Add('  begin');
  Source.Add('  end.');
  ParseModule;
end;

procedure TTestStatementParser.TestAssignToAddress;

begin
  AddStatements(['@Proc:=Nil']);
  ParseModule;
end;

procedure TTestStatementParser.TestFinalizationNoSemicolon;
begin
  Source.Add('unit afile;');
  Source.Add('{$mode objfpc}');
  Source.Add('interface');
  Source.Add('implementation');
  Source.Add('initialization');
  Source.Add('  writeln(''qqq'')');
  Source.Add('finalization');
  Source.Add('  write(''rrr'')');
  ParseModule;
end;

procedure TTestStatementParser.TestMacroComment;
begin
  AddStatements(['{$MACRO ON}',
  '{$DEFINE func := //}',
  '  calltest;',
  '  func (''1'',''2'',''3'');',
  'CallTest2;'
  ]);
  ParseModule;
end;

procedure TTestStatementParser.TestPlatformIdentifier;
begin
  AddStatements(['write(platform);']);
  ParseModule;
end;

procedure TTestStatementParser.TestPlatformIdentifier2;
begin
  AddStatements(['write(libs+platform);']);
  ParseModule;
end;

procedure TTestStatementParser.TestArgumentNameOn;
begin
  Source.Add('function TryOn(const on: boolean): boolean;');
  Source.Add('  begin');
  Source.Add('  end;');
  Source.Add('  begin');
  Source.Add('  end.');
  ParseModule;
end;

procedure TTestStatementParser.TestGotoInIfThen;

begin
  AddStatements([
  '{$goto on}',
  'if expr then',
  '  dosomething',
  '   else if expr2 then',
  '    goto try_qword',
  '  else',
  '    dosomething;',
  '  try_qword:',
  '  dosomething;']);
  ParseModule;
end;

initialization
  RegisterTests([TTestStatementParser]);

end.

