unit tcvarparser; {$mode objfpc}{$H+} interface uses Classes, SysUtils, fpcunit, pastree, pscanner, tcbaseparser, testregistry; Type { TTestVarParser } TTestVarParser = Class(TTestParser) private FHint: string; FVar: TPasVariable; Protected Function ParseVar(ASource : String; Const AHint : String = '') : TPasVariable; virtual; overload; Procedure AssertVariableType(Const ATypeName : String); Procedure AssertVariableType(Const AClass : TClass); Procedure AssertParseVarError(ASource : String); Property TheVar : TPasVariable Read FVar; Property Hint : string Read FHint Write FHint; procedure SetUp; override; Procedure TearDown; override; Published Procedure TestSimpleVar; Procedure TestSimpleVarHelperName; procedure TestSimpleVarHelperType; Procedure TestSimpleVarDeprecated; Procedure TestSimpleVarPlatform; Procedure TestSimpleVarInitialized; procedure TestSimpleVarInitializedDeprecated; procedure TestSimpleVarInitializedPlatform; Procedure TestSimpleVarAbsolute; Procedure TestSimpleVarAbsoluteDot; Procedure TestSimpleVarAbsolute2Dots; Procedure TestVarProcedure; Procedure TestVarFunctionINitialized; Procedure TestVarProcedureDeprecated; Procedure TestVarRecord; Procedure TestVarRecordDeprecated; Procedure TestVarRecordPlatform; Procedure TestVarArray; Procedure TestVarArrayDeprecated; Procedure TestVarDynArray; Procedure TestVarExternal; Procedure TestVarExternalLib; Procedure TestVarExternalLibName; procedure TestVarExternalNoSemiColon; Procedure TestVarCVar; Procedure TestVarCVarExternal; Procedure TestVarPublic; Procedure TestVarPublicName; Procedure TestVarDeprecatedExternalName; Procedure TestVarHintPriorToInit; end; implementation uses typinfo; { TTestVarParser } function TTestVarParser.ParseVar(ASource: String; const AHint: String ): TPasVariable; Var D : String; begin Hint:=AHint; Add('Var'); D:='A : '+ASource; If Hint<>'' then D:=D+' '+Hint; Add(' '+D+';'); // Writeln(source.text); ParseDeclarations; AssertEquals('One variable definition',1,Declarations.Variables.Count); AssertEquals('First declaration is type definition.',TPasVariable,TObject(Declarations.Variables[0]).ClassType); Result:=TPasVariable(Declarations.Variables[0]); AssertEquals('First declaration has correct name.','A',Result.Name); FVar:=Result; Definition:=Result; if (Hint<>'') then CheckHint(TPasMemberHint(Getenumvalue(typeinfo(TPasMemberHint),'h'+Hint))); end; procedure TTestVarParser.AssertVariableType(const ATypeName: String); begin AssertVariableType(TPasUnresolvedTypeRef); AssertEquals('Correct unresolved type name',ATypeName,theVar.VarType.Name); end; procedure TTestVarParser.AssertVariableType(const AClass: TClass); begin AssertNotNull('Have variable type',theVar.VarType); AssertEquals('Correct type class',AClass,theVar.VarType.ClassType); end; procedure TTestVarParser.AssertParseVarError(ASource: String); begin try ParseVar(ASource,''); Fail('Expected parser error'); except // all OK. end; end; procedure TTestVarParser.SetUp; begin inherited SetUp; FHint:=''; FVar:=Nil; end; procedure TTestVarParser.TearDown; begin FVar:=Nil; inherited TearDown; end; procedure TTestVarParser.TestSimpleVar; begin ParseVar('b',''); AssertVariableType('b'); end; procedure TTestVarParser.TestSimpleVarHelperName; Var R : TPasVariable; begin Add('Var'); Add(' Helper : integer;'); // Writeln(source.text); ParseDeclarations; AssertEquals('One variable definition',1,Declarations.Variables.Count); AssertEquals('First declaration is type definition.',TPasVariable,TObject(Declarations.Variables[0]).ClassType); R:=TPasVariable(Declarations.Variables[0]); AssertEquals('First declaration has correct name.','Helper',R.Name); end; procedure TTestVarParser.TestSimpleVarHelperType; begin ParseVar('helper',''); AssertVariableType('helper'); end; procedure TTestVarParser.TestSimpleVarDeprecated; begin ParseVar('b','deprecated'); AssertVariableType('b'); end; procedure TTestVarParser.TestSimpleVarPlatform; begin ParseVar('b','platform'); AssertVariableType('b'); end; procedure TTestVarParser.TestSimpleVarInitialized; begin ParseVar('b = 123',''); AssertVariableType('b'); AssertNotNull(TheVar.expr); AssertExpression('Variable value',TheVar.expr,pekNumber,'123'); end; procedure TTestVarParser.TestSimpleVarInitializedDeprecated; begin ParseVar('b = 123','deprecated'); AssertVariableType('b'); AssertNotNull(TheVar.expr); AssertExpression('Variable value',TheVar.expr,pekNumber,'123'); end; procedure TTestVarParser.TestSimpleVarInitializedPlatform; begin ParseVar('b = 123','platform'); AssertVariableType('b'); AssertNotNull(TheVar.expr); AssertExpression('Variable value',TheVar.expr,pekNumber,'123'); end; procedure TTestVarParser.TestSimpleVarAbsolute; begin ParseVar('q absolute v',''); AssertVariableType('q'); AssertExpression('correct absolute location',TheVar.AbsoluteExpr,pekIdent,'v'); end; procedure TTestVarParser.TestSimpleVarAbsoluteDot; var B: TBinaryExpr; begin ParseVar('q absolute v.w',''); AssertVariableType('q'); B:=AssertExpression('binary',TheVar.AbsoluteExpr,eopSubIdent); AssertExpression('correct absolute expr v',B.left,pekIdent,'v'); AssertExpression('correct absolute expr w',B.right,pekIdent,'w'); end; procedure TTestVarParser.TestSimpleVarAbsolute2Dots; var B: TBinaryExpr; begin ParseVar('q absolute v.w.x',''); AssertVariableType('q'); B:=AssertExpression('binary',TheVar.AbsoluteExpr,eopSubIdent); AssertExpression('correct absolute expr x',B.right,pekIdent,'x'); B:=AssertExpression('binary',B.left,eopSubIdent); AssertExpression('correct absolute expr w',B.right,pekIdent,'w'); AssertExpression('correct absolute expr v',B.left,pekIdent,'v'); end; procedure TTestVarParser.TestVarProcedure; begin ParseVar('procedure',''); AssertVariableType(TPasProcedureType); end; procedure TTestVarParser.TestVarFunctionINitialized; begin ParseVar('function (device: pointer): pointer; cdecl = nil',''); AssertVariableType(TPasFunctionType); end; procedure TTestVarParser.TestVarProcedureDeprecated; begin ParseVar('procedure','deprecated'); AssertVariableType(TPasProcedureType); end; procedure TTestVarParser.TestVarRecord; Var R : TPasRecordtype; begin ParseVar('record x,y : intger; end',''); AssertVariableType(TPasRecordType); R:=TheVar.VarType as TPasRecordType; AssertEquals('Correct number of fields',2,R.Members.Count); end; procedure TTestVarParser.TestVarRecordDeprecated; Var R : TPasRecordtype; begin ParseVar('record x,y : integer; end','deprecated'); AssertVariableType(TPasRecordType); R:=TheVar.VarType as TPasRecordType; AssertEquals('Correct number of fields',2,R.Members.Count); end; procedure TTestVarParser.TestVarRecordPlatform; Var R : TPasRecordtype; begin ParseVar('record x,y : integer; end','platform'); AssertVariableType(TPasRecordType); R:=TheVar.VarType as TPasRecordType; AssertEquals('Correct number of fields',2,R.Members.Count); end; procedure TTestVarParser.TestVarArray; Var R : TPasArrayType; begin ParseVar('Array[1..20] of integer',''); AssertVariableType(TPasArrayType); R:=TheVar.VarType as TPasArrayType; AssertNotNull('Correct array type name',R.ElType); AssertEquals('Correct array type name',TPasunresolvedTypeRef,R.ElType.ClassType); end; procedure TTestVarParser.TestVarArrayDeprecated; Var R : TPasArrayType; begin ParseVar('Array[1..20] of integer','Deprecated'); AssertVariableType(TPasArrayType); R:=TheVar.VarType as TPasArrayType; AssertNotNull('Correct array type name',R.ElType); AssertEquals('Correct array type name',TPasunresolvedTypeRef,R.ElType.ClassType); end; procedure TTestVarParser.TestVarDynArray; Var R : TPasArrayType; begin ParseVar('Array of integer',''); AssertVariableType(TPasArrayType); R:=TheVar.VarType as TPasArrayType; AssertEquals('No index','',R.IndexRange); AssertNotNull('Correct array type name',R.ElType); AssertEquals('Correct array type name',TPasunresolvedTypeRef,R.ElType.ClassType); end; procedure TTestVarParser.TestVarExternal; begin ParseVar('integer; external',''); AssertEquals('Variable modifiers',[vmexternal],TheVar.VarModifiers); end; procedure TTestVarParser.TestVarExternalNoSemiColon; begin ParseVar('integer external',''); AssertEquals('Variable modifiers',[vmexternal],TheVar.VarModifiers); end; procedure TTestVarParser.TestVarExternalLib; begin ParseVar('integer; external name ''mylib''',''); AssertEquals('Variable modifiers',[vmexternal],TheVar.VarModifiers); AssertNull('Library name',TheVar.LibraryName); AssertNotNull('Library symbol',TheVar.ExportName); end; procedure TTestVarParser.TestVarExternalLibName; begin ParseVar('integer; external ''mylib'' name ''de''',''); AssertEquals('Variable modifiers',[vmexternal],TheVar.VarModifiers); AssertNotNull('Library name',TheVar.LibraryName); AssertNotNull('Library symbol',TheVar.ExportName); end; procedure TTestVarParser.TestVarCVar; begin ParseVar('integer; cvar',''); AssertEquals('Variable modifiers',[vmcvar],TheVar.VarModifiers); end; procedure TTestVarParser.TestVarCVarExternal; begin ParseVar('integer; cvar;external',''); AssertEquals('Variable modifiers',[vmcvar,vmexternal],TheVar.VarModifiers); end; procedure TTestVarParser.TestVarPublic; begin ParseVar('integer; public',''); AssertEquals('Variable modifiers',[vmpublic],TheVar.VarModifiers); end; procedure TTestVarParser.TestVarPublicName; begin ParseVar('integer; public name ''ce''',''); AssertEquals('Variable modifiers',[vmpublic],TheVar.VarModifiers); AssertNotNull('Public export name',TheVar.ExportName); end; procedure TTestVarParser.TestVarDeprecatedExternalName; begin ParseVar('integer deprecated; external name ''me''',''); CheckHint(TPasMemberHint(Getenumvalue(typeinfo(TPasMemberHint),'hdeprecated'))); AssertEquals('Variable modifiers',[vmexternal],TheVar.VarModifiers); AssertNull('Library name',TheVar.LibraryName); AssertNotNull('Library symbol',TheVar.ExportName); end; procedure TTestVarParser.TestVarHintPriorToInit; Var E : TBoolConstExpr; begin ParseVar('boolean platform = false',''); CheckHint(TPasMemberHint(Getenumvalue(typeinfo(TPasMemberHint),'hplatform'))); AssertNotNull('Correctly initialized',Thevar.Expr); AssertEquals('Correctly initialized',TBoolConstExpr,Thevar.Expr.ClassType); E:=Thevar.Expr as TBoolConstExpr; AssertEquals('Correct initialization value',False, E.Value); end; initialization RegisterTests([TTestVarParser]); end.