summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormarco <marco@3ad0048d-3df7-0310-abae-a5850022a9f2>2017-04-27 20:59:57 +0000
committermarco <marco@3ad0048d-3df7-0310-abae-a5850022a9f2>2017-04-27 20:59:57 +0000
commit87f9b1c605f844e48d17c09fc9757cb569de3c70 (patch)
treea5afa0156ae948faace4ae68cebc422aa0cdaedb
parent2b2ff872745dd40adc046e428e1887f40584a13d (diff)
downloadfpc-87f9b1c605f844e48d17c09fc9757cb569de3c70.tar.gz
merged revs: 35782,35790,35791,35793,35794,35795,35798,35799,35800,35801,35802,35803,35804,35805,35806,35808,35809,35810,35811
git-svn-id: http://svn.freepascal.org/svn/fpc/branches/fixes_3_0@35987 3ad0048d-3df7-0310-abae-a5850022a9f2
-rw-r--r--packages/fcl-passrc/src/pasresolver.pp605
-rw-r--r--packages/fcl-passrc/src/pastree.pp49
-rw-r--r--packages/fcl-passrc/src/pasuseanalyzer.pas145
-rw-r--r--packages/fcl-passrc/src/pparser.pp120
-rw-r--r--packages/fcl-passrc/tests/tcbaseparser.pas22
-rw-r--r--packages/fcl-passrc/tests/tcprocfunc.pas241
-rw-r--r--packages/fcl-passrc/tests/tcresolver.pas529
-rw-r--r--packages/fcl-passrc/tests/tcuseanalyzer.pas304
-rw-r--r--packages/pastojs/fpmake.pp2
-rw-r--r--packages/pastojs/src/fppas2js.pp2702
-rw-r--r--packages/pastojs/tests/tcmodules.pas2130
-rw-r--r--packages/pastojs/tests/tcoptimizations.pas104
-rw-r--r--utils/fpdoc/dw_xml.pp2
13 files changed, 5661 insertions, 1294 deletions
diff --git a/packages/fcl-passrc/src/pasresolver.pp b/packages/fcl-passrc/src/pasresolver.pp
index f9c24ca0cd..47b810f0fa 100644
--- a/packages/fcl-passrc/src/pasresolver.pp
+++ b/packages/fcl-passrc/src/pasresolver.pp
@@ -131,6 +131,8 @@ Works:
- built-in functions pred, succ for range type and enums
- untyped parameters
- built-in procedure str(const boolean|integer|enumvalue|classinstance,var s: string)
+- pointer TPasPointerType
+ - nil, assigned(), typecast, class, classref, dynarray, procvar
ToDo:
- fix slow lookup declaration proc in PParser
@@ -141,7 +143,6 @@ ToDo:
- nested types
- check if constant is longint or int64
- for..in..do
-- pointer TPasPointerType
- records - TPasRecordType,
- const TRecordValues
- function default(record type): record
@@ -229,7 +230,7 @@ const
nTypesAreNotRelated = 3029;
nAbstractMethodsCannotBeCalledDirectly = 3030;
nMissingParameterX = 3031;
- nCannotAccessThisMemberFromAClassReference = 3032;
+ nCannotAccessThisMemberFromAX = 3032;
nInOperatorExpectsSetElementButGot = 3033;
nWrongNumberOfParametersForTypeCast = 3034;
nIllegalTypeConversionTo = 3035;
@@ -252,6 +253,8 @@ const
nXModifierMismatchY = 3052;
nSymbolCannotBePublished = 3053;
nCannotTypecastAType = 3054;
+ nTypeIdentifierExpected = 3055;
+ nCannotNestAnonymousX = 3056;
// resourcestring patterns of messages
resourcestring
@@ -286,7 +289,7 @@ resourcestring
sTypesAreNotRelated = 'Types are not related';
sAbstractMethodsCannotBeCalledDirectly = 'Abstract methods cannot be called directly';
sMissingParameterX = 'Missing parameter %s';
- sCannotAccessThisMemberFromAClassReference = 'Cannot access this member from a class reference';
+ sCannotAccessThisMemberFromAX = 'Cannot access this member from a %s';
sInOperatorExpectsSetElementButGot = 'the in-operator expects a set element, but got %s';
sWrongNumberOfParametersForTypeCast = 'wrong number of parameters for type cast to %s';
sIllegalTypeConversionTo = 'Illegal type conversion: "%s" to "%s"';
@@ -307,8 +310,10 @@ resourcestring
sVirtualMethodXHasLowerVisibility = 'Virtual method "%s" has a lower visibility (%s) than parent class %s (%s)';
sExternalClassInstanceCannotAccessStaticX = 'External class instance cannot access static %s';
sXModifierMismatchY = '%s modifier "%s" mismatch';
- sSymbolCannotBePublished = 'Symbol cannot be published. Only methods and properties.';
+ sSymbolCannotBePublished = 'Symbol cannot be published';
sCannotTypecastAType = 'Cannot type cast a type';
+ sTypeIdentifierExpected = 'Type identifier expected';
+ sCannotNestAnonymousX = 'Cannot nest anonymous %s';
type
TResolverBaseType = (
@@ -443,7 +448,7 @@ const
'Nil',
'Procedure/Function',
'BuiltInProc',
- 'set literal',
+ 'set',
'range..',
'array literal'
);
@@ -472,7 +477,8 @@ type
bfConcatArray,
bfCopyArray,
bfInsertArray,
- bfDeleteArray
+ bfDeleteArray,
+ bfTypeInfo
);
TResolverBuiltInProcs = set of TResolverBuiltInProc;
const
@@ -499,7 +505,8 @@ const
'Concat',
'Copy',
'Insert',
- 'Delete'
+ 'Delete',
+ 'TypeInfo'
);
bfAllStandardProcs = [Succ(bfCustom)..high(TResolverBuiltInProc)];
@@ -960,7 +967,8 @@ type
proClassOfIs, // class-of supports is and as operator
proExtClassInstanceNoTypeMembers, // class members of external class cannot be accessed by instance
proOpenAsDynArrays, // open arrays work like dynamic arrays
- proProcTypeWithoutIsNested // proc types can use nested procs without 'is nested'
+ proProcTypeWithoutIsNested, // proc types can use nested procs without 'is nested'
+ proMethodAddrAsPointer // can assign @method to a pointer
);
TPasResolverOptions = set of TPasResolverOption;
@@ -972,6 +980,7 @@ type
TResolveDataListKind = (lkBuiltIn,lkModule);
procedure ClearResolveDataList(Kind: TResolveDataListKind);
private
+ FAnonymousElTypePostfix: String;
FBaseTypes: array[TResolverBaseType] of TPasUnresolvedSymbolRef;
FBaseTypeStringIndex: TResolverBaseType;
FDefaultScope: TPasDefaultScope;
@@ -1085,6 +1094,7 @@ type
procedure FinishTypeDef(El: TPasType); virtual;
procedure FinishEnumType(El: TPasEnumType); virtual;
procedure FinishSetType(El: TPasSetType); virtual;
+ procedure FinishSubElementType(Parent, El: TPasElement); virtual;
procedure FinishRangeType(El: TPasRangeType); virtual;
procedure FinishRecordType(El: TPasRecordType); virtual;
procedure FinishClassType(El: TPasClassType); virtual;
@@ -1218,6 +1228,10 @@ type
Expr: TPasExpr; RaiseOnError: boolean): integer; virtual;
procedure BI_DeleteArray_OnFinishParamsExpr(Proc: TResElDataBuiltInProc;
Params: TParamsExpr); virtual;
+ function BI_TypeInfo_OnGetCallCompatibility(Proc: TResElDataBuiltInProc;
+ Expr: TPasExpr; RaiseOnError: boolean): integer; virtual;
+ procedure BI_TypeInfo_OnGetCallResult({%H-}Proc: TResElDataBuiltInProc;
+ {%H-}Params: TParamsExpr; out ResolvedEl: TPasResolverResult); virtual;
public
constructor Create;
destructor Destroy; override;
@@ -1359,10 +1373,12 @@ type
function GetPasPropertyAncestor(El: TPasProperty): TPasProperty;
function GetPasPropertyGetter(El: TPasProperty): TPasElement;
function GetPasPropertySetter(El: TPasProperty): TPasElement;
+ function GetPasPropertyStored(El: TPasProperty): TPasElement;
function GetPasClassAncestor(ClassEl: TPasClassType; SkipAlias: boolean): TPasType;
function GetLoop(El: TPasElement): TPasImplElement;
function ResolveAliasType(aType: TPasType): TPasType;
function ExprIsAddrTarget(El: TPasExpr): boolean;
+ function IsNameExpr(El: TPasExpr): boolean; inline; // TSelfExpr or TPrimitiveExpr with Kind=pekIdent
function GetLastExprIdentifier(El: TPasExpr): TPasExpr;
function ParentNeedsExprResult(El: TPasExpr): boolean;
function GetReference_NewInstanceClass(Ref: TResolvedReference): TPasClassType;
@@ -1376,6 +1392,7 @@ type
function IsTypeCast(Params: TParamsExpr): boolean;
function ProcNeedsParams(El: TPasProcedureType): boolean;
function GetRangeLength(RangeResolved: TPasResolverResult): integer;
+ function HasTypeInfo(El: TPasType): boolean; virtual;
public
property BaseTypes[bt: TResolverBaseType]: TPasUnresolvedSymbolRef read GetBaseTypes;
property BaseTypeStringIndex: TResolverBaseType read FBaseTypeStringIndex write FBaseTypeStringIndex;
@@ -1399,6 +1416,8 @@ type
property Options: TPasResolverOptions read FOptions write FOptions;
property ScopeClass_Class: TPasClassScopeClass read FScopeClass_Class write FScopeClass_Class;
property ScopeClass_WithExpr: TPasWithExprScopeClass read FScopeClass_WithExpr write FScopeClass_WithExpr;
+ property AnonymousElTypePostfix: String read FAnonymousElTypePostfix
+ write FAnonymousElTypePostfix; // default empty, if set, anonymous element types are named ArrayName+Postfix and added to declarations
end;
function GetObjName(o: TObject): string;
@@ -1407,6 +1426,7 @@ function GetTypeDesc(aType: TPasType; AddPath: boolean = false): string;
function GetTreeDesc(El: TPasElement; Indent: integer = 0): string;
function GetResolverResultDesc(const T: TPasResolverResult): string;
function GetResolverResultDescription(const T: TPasResolverResult; OnlyType: boolean = false): string;
+function GetResolverResultDbg(const T: TPasResolverResult): string;
function ResolverResultFlagsToStr(const Flags: TPasResolverResultFlags): string;
procedure SetResolverIdentifier(out ResolvedType: TPasResolverResult;
BaseType: TResolverBaseType; IdentEl: TPasElement;
@@ -1468,9 +1488,9 @@ begin
Result:=Result+')';
end;
if ProcType.IsOfObject then
- Result:=Result+' of object';
+ Result:=Result+' '+ProcTypeModifiers[ptmOfObject];
if ProcType.IsNested then
- Result:=Result+' is nested';
+ Result:=Result+' '+ProcTypeModifiers[ptmIsNested];
if cCallingConventions[ProcType.CallingConvention]<>'' then
Result:=Result+';'+cCallingConventions[ProcType.CallingConvention];
end;
@@ -1624,9 +1644,9 @@ begin
if El is TPasFunction then
Result:=Result+':'+GetTreeDesc(TPasFunctionType(TPasFunction(El).ProcType).ResultEl,Indent);
if TPasProcedureType(El).IsOfObject then
- Result:=Result+' of object';
+ Result:=Result+' '+ProcTypeModifiers[ptmOfObject];
if TPasProcedureType(El).IsNested then
- Result:=Result+' is nested';
+ Result:=Result+' '+ProcTypeModifiers[ptmIsNested];
if cCallingConventions[TPasProcedureType(El).CallingConvention]<>'' then
Result:=Result+'; '+cCallingConventions[TPasProcedureType(El).CallingConvention];
end
@@ -1742,6 +1762,18 @@ begin
Result:=T.IdentEl.Name+':'+Result;
end;
+function GetResolverResultDbg(const T: TPasResolverResult): string;
+begin
+ Result:='bt='+BaseTypeNames[T.BaseType];
+ if T.SubType<>btNone then
+ Result:=Result+' Sub='+BaseTypeNames[T.SubType];
+ Result:=Result
+ +' Ident='+GetObjName(T.IdentEl)
+ +' Type='+GetObjName(T.TypeEl)
+ +' Expr='+GetObjName(T.ExprEl)
+ +' Flags='+ResolverResultFlagsToStr(T.Flags);
+end;
+
function ResolverResultFlagsToStr(const Flags: TPasResolverResultFlags): string;
var
f: TPasResolverResultFlag;
@@ -2551,6 +2583,13 @@ begin
Result:=FScopes[Index];
end;
+// inline
+function TPasResolver.IsNameExpr(El: TPasExpr): boolean;
+begin
+ if El.ClassType=TSelfExpr then exit(true);
+ Result:=(El.ClassType=TPrimitiveExpr) and (TPrimitiveExpr(El).Kind=pekIdent);
+end;
+
procedure TPasResolver.ClearResolveDataList(Kind: TResolveDataListKind);
var
El: TPasElement;
@@ -2696,9 +2735,11 @@ begin
else if (C=TPasClassType)
or (C=TPasClassOfType)
or (C=TPasEnumType)
+ or (C=TPasProcedureType)
+ or (C=TPasFunctionType)
or (C=TPasArrayType) then
begin
- // type cast to a class, class-of, enum, or array
+ // type cast to user type
Abort:=true; // can't be overloaded
if Data^.Found<>nil then exit;
Distance:=CheckTypeCast(TPasType(El),Data^.Params,false);
@@ -2864,14 +2905,16 @@ var
ClassScope: TPasClassScope;
OlderEl: TPasElement;
IsClassScope: Boolean;
+ C: TClass;
begin
IsClassScope:=(Scope is TPasClassScope);
if (El.Visibility=visPublished) then
begin
- if El.ClassType=TPasProperty then
+ C:=El.ClassType;
+ if (C=TPasProperty) or (C=TPasVariable) then
// Note: VarModifiers are not yet set
- else if (El.ClassType=TPasProcedure) or (El.ClassType=TPasFunction) then
+ else if (C=TPasProcedure) or (C=TPasFunction) then
// ok
else
RaiseMsg(20170403223024,nSymbolCannotBePublished,sSymbolCannotBePublished,[],El);
@@ -3130,12 +3173,16 @@ begin
EnumType:=El.EnumType;
C:=EnumType.ClassType;
if C=TPasEnumType then
- exit
+ begin
+ FinishSubElementType(El,EnumType);
+ exit;
+ end
else if C=TPasRangeType then
begin
RangeExpr:=TPasRangeType(EnumType).RangeExpr;
if RangeExpr.Parent=El then
CheckRangeExpr(RangeExpr.left,RangeExpr.right,StartResolved,EndResolved);
+ FinishSubElementType(El,EnumType);
exit;
end
else if C=TPasUnresolvedSymbolRef then
@@ -3151,6 +3198,37 @@ begin
RaiseXExpectedButYFound(20170216151557,'enum type',EnumType.ElementTypeName,EnumType);
end;
+procedure TPasResolver.FinishSubElementType(Parent, El: TPasElement);
+var
+ Decl: TPasDeclarations;
+ EnumScope: TPasEnumTypeScope;
+begin
+ if (El.Name<>'') or (AnonymousElTypePostfix='') then exit;
+ if Parent.Name='' then
+ RaiseMsg(20170415165455,nCannotNestAnonymousX,sCannotNestAnonymousX,[El.ElementTypeName],El);
+ if not (Parent.Parent is TPasDeclarations) then
+ RaiseMsg(20170416094735,nCannotNestAnonymousX,sCannotNestAnonymousX,[El.ElementTypeName],El);
+ // give anonymous sub type a name
+ El.Name:=Parent.Name+AnonymousElTypePostfix;
+ {$IFDEF VerbosePasResolver}
+ writeln('TPasResolver.FinishSubElementType parent="',GetObjName(Parent),'" named anonymous type "',GetObjName(El),'"');
+ {$ENDIF}
+ Decl:=TPasDeclarations(Parent.Parent);
+ Decl.Declarations.Add(El);
+ El.AddRef;
+ El.Parent:=Decl;
+ Decl.Types.Add(El);
+ if (El.ClassType=TPasEnumType) and (Parent.ClassType=TPasSetType) then
+ begin
+ EnumScope:=TPasEnumTypeScope(El.CustomData);
+ if EnumScope.CanonicalSet<>Parent then
+ begin
+ ReleaseAndNil(TPasElement(EnumScope.CanonicalSet));
+ EnumScope.CanonicalSet:=TPasSetType(Parent);
+ end;
+ end;
+end;
+
procedure TPasResolver.FinishRangeType(El: TPasRangeType);
var
StartResolved, EndResolved: TPasResolverResult;
@@ -3202,6 +3280,7 @@ begin
else
RaiseXExpectedButYFound(20170216151609,'range',RangeResolved.IdentEl.ElementTypeName,Expr);
end;
+ FinishSubElementType(El,El.ElType);
end;
procedure TPasResolver.FinishConstDef(El: TPasConst);
@@ -3254,6 +3333,7 @@ var
DeclProcScope, ProcScope: TPasProcedureScope;
ParentScope: TPasScope;
pm: TProcedureModifier;
+ ptm: TProcTypeModifier;
begin
if (El.Parent is TPasProcedure) and (TPasProcedure(El.Parent).ProcType=El) then
begin
@@ -3281,15 +3361,21 @@ begin
end;
if Proc.IsExternal then
+ begin
for pm in TProcedureModifier do
if (pm in Proc.Modifiers)
and not (pm in [pmVirtual, pmDynamic, pmOverride,
pmOverload, pmMessage, pmReintroduce,
- pmStatic, pmVarargs,
pmExternal, pmDispId,
pmfar]) then
RaiseMsg(20170216151616,nInvalidXModifierY,
sInvalidXModifierY,[Proc.ElementTypeName,'external, '+ModifierNames[pm]],Proc);
+ for ptm in TProcTypeModifier do
+ if (ptm in Proc.ProcType.Modifiers)
+ and not (ptm in [ptmOfObject,ptmIsNested,ptmStatic,ptmVarargs]) then
+ RaiseMsg(20170411171224,nInvalidXModifierY,
+ sInvalidXModifierY,[Proc.ElementTypeName,'external, '+ProcTypeModifiers[ptm]],Proc);
+ end;
if Proc.Parent is TPasClassType then
begin
@@ -3597,19 +3683,25 @@ begin
end;
procedure TPasResolver.FinishDeclaration(El: TPasElement);
+var
+ C: TClass;
begin
- if El.ClassType=TPasVariable then
+ C:=El.ClassType;
+ if C=TPasVariable then
FinishVariable(TPasVariable(El))
- else if El.ClassType=TPasProperty then
+ else if C=TPasProperty then
FinishPropertyOfClass(TPasProperty(El))
- else if El.ClassType=TPasArgument then
+ else if C=TPasArgument then
FinishArgument(TPasArgument(El));
end;
procedure TPasResolver.FinishVariable(El: TPasVariable);
begin
if (El.Visibility=visPublished) then
- RaiseMsg(20170403223837,nSymbolCannotBePublished,sSymbolCannotBePublished,[],El);
+ begin
+ if [vmClass,vmStatic,vmCVar]*El.VarModifiers<>[] then
+ RaiseMsg(20170403223837,nSymbolCannotBePublished,sSymbolCannotBePublished,[],El);
+ end;
if El.Expr<>nil then
begin
ResolveExpr(El.Expr,rraRead);
@@ -3757,7 +3849,7 @@ var
end;
var
- ResultType: TPasType;
+ ResultType, TypeEl: TPasType;
CurClassType: TPasClassType;
AccEl: TPasElement;
Proc: TPasProcedure;
@@ -3788,7 +3880,7 @@ begin
begin
// check compatibility
AccEl:=GetAccessor(PropEl.ReadAccessor);
- if AccEl is TPasVariable then
+ if (AccEl.ClassType=TPasVariable) or (AccEl.ClassType=TPasConst) then
begin
if PropEl.Args.Count>0 then
RaiseXExpectedButYFound(20170216151823,'function',AccEl.ElementTypeName,PropEl.ReadAccessor);
@@ -3838,7 +3930,7 @@ begin
begin
// check compatibility
AccEl:=GetAccessor(PropEl.WriteAccessor);
- if AccEl is TPasVariable then
+ if AccEl.ClassType=TPasVariable then
begin
if PropEl.Args.Count>0 then
RaiseXExpectedButYFound(20170216151852,'procedure',AccEl.ElementTypeName,PropEl.WriteAccessor);
@@ -3892,13 +3984,27 @@ begin
begin
ResolveExpr(PropEl.ImplementsFunc,rraRead);
// ToDo: check compatibility
-
+ RaiseNotYetImplemented(20170409213850,PropEl.ImplementsFunc);
end;
if PropEl.StoredAccessor<>nil then
begin
// check compatibility
AccEl:=GetAccessor(PropEl.StoredAccessor);
- if AccEl is TPasProcedure then
+ if (AccEl.ClassType=TPasVariable) or (AccEl.ClassType=TPasConst) then
+ begin
+ if PropEl.IndexExpr<>nil then
+ RaiseNotYetImplemented(20170409214006,PropEl.StoredAccessor,'stored with index');
+ TypeEl:=ResolveAliasType(TPasVariable(AccEl).VarType);
+ if not IsBaseType(TypeEl,btBoolean) then
+ RaiseIncompatibleType(20170409214300,nIncompatibleTypesGotExpected,
+ [],TypeEl,BaseTypes[btBoolean],PropEl.StoredAccessor);
+ if (vmClass in PropEl.VarModifiers)<>(vmClass in TPasVariable(AccEl).VarModifiers) then
+ if vmClass in PropEl.VarModifiers then
+ RaiseXExpectedButYFound(20170409214351,'class var','var',PropEl.StoredAccessor)
+ else
+ RaiseXExpectedButYFound(20170409214359,'var','class var',PropEl.StoredAccessor);
+ end
+ else if AccEl is TPasProcedure then
begin
// check function
Proc:=TPasProcedure(AccEl);
@@ -4913,9 +5019,7 @@ var
C: TClass;
begin
Value:=Params.Value;
- if (Value.ClassType=TSelfExpr)
- or ((Value.ClassType=TPrimitiveExpr)
- and (TPrimitiveExpr(Value).Kind=pekIdent)) then
+ if IsNameExpr(Value) then
begin
// e.g. Name() -> find compatible
if Value.ClassType=TPrimitiveExpr then
@@ -4932,12 +5036,12 @@ begin
begin
// FoundEl one element, but it was incompatible => raise error
{$IFDEF VerbosePasResolver}
- writeln('TPasResolver.ResolveParamsExpr found one element, but it was incompatible => check again to raise error');
+ writeln('TPasResolver.ResolveFuncParamsExpr found one element, but it was incompatible => check again to raise error. Found=',GetObjName(FindCallData.Found));
{$ENDIF}
if FindCallData.Found is TPasProcedure then
CheckCallProcCompatibility(TPasProcedure(FindCallData.Found).ProcType,Params,true)
else if FindCallData.Found is TPasProcedureType then
- CheckCallProcCompatibility(TPasProcedureType(FindCallData.Found),Params,true)
+ CheckTypeCast(TPasProcedureType(FindCallData.Found),Params,true)
else if FindCallData.Found.ClassType=TPasUnresolvedSymbolRef then
begin
if FindCallData.Found.CustomData is TResElDataBuiltInProc then
@@ -4978,7 +5082,7 @@ begin
// ToDo: create a hint for each candidate
El:=TPasElement(FindCallData.List[i]);
{$IFDEF VerbosePasResolver}
- writeln('TPasResolver.ResolveParamsExpr Overload Candidate: ',GetElementSourcePosStr(El),' ',GetTreeDesc(El));
+ writeln('TPasResolver.ResolveFuncParamsExpr Overload Candidate: ',GetElementSourcePosStr(El),' ',GetTreeDesc(El));
{$ENDIF}
Msg:=Msg+', ';
Msg:=Msg+GetElementSourcePosStr(El);
@@ -5013,6 +5117,10 @@ begin
if (C=TPasClassType)
or (C=TPasClassOfType)
or (C=TPasEnumType)
+ or (C=TPasSetType)
+ or (C=TPasPointerType)
+ or (C=TPasProcedureType)
+ or (C=TPasFunctionType)
or (C=TPasArrayType) then
begin
// type cast
@@ -5050,11 +5158,12 @@ begin
{$IFDEF VerbosePasResolver}
writeln('TPasResolver.ResolveFuncParamsExpr FoundEl=',GetObjName(FoundEl),' CustomData=',GetObjName(FoundEl.CustomData));
{$ENDIF}
- RaiseNotYetImplemented(20170306121908,Params);
+ RaiseMsg(20170306121908,nIllegalExpression,sIllegalExpression,[],Params);
end;
end
else
begin
+ // FoundEl is not a type, maybe a var
ComputeElement(FoundEl,ResolvedEl,[rcNoImplicitProc]);
if ResolvedEl.TypeEl is TPasProcedureType then
begin
@@ -5064,7 +5173,7 @@ begin
{$IFDEF VerbosePasResolver}
writeln('TPasResolver.ResolveFuncParamsExpr FoundEl=',GetObjName(FoundEl),' CustomData=',GetObjName(FoundEl.CustomData),' Resolvedel=',GetResolverResultDesc(ResolvedEl));
{$ENDIF}
- RaiseNotYetImplemented(20170306104301,Params);
+ RaiseMsg(20170306104301,nIllegalExpression,sIllegalExpression,[],Params);
end;
end
else if Value.ClassType=TParamsExpr then
@@ -5078,7 +5187,7 @@ begin
if IsProcedureType(ResolvedEl,true) then
begin
CheckCallProcCompatibility(TPasProcedureType(ResolvedEl.TypeEl),Params,true);
- CreateReference(ResolvedEl.TypeEl,Value,Access);
+ CreateReference(TPasProcedureType(ResolvedEl.TypeEl),Value,Access);
exit;
end
end;
@@ -5273,7 +5382,7 @@ end;
procedure TPasResolver.AccessExpr(Expr: TPasExpr;
Access: TResolvedRefAccess);
-// called after a call overload was found for each element
+// called after a call target was found, called for each element
// to set the rraParamToUnknownProc to Access
var
Ref: TResolvedReference;
@@ -6336,16 +6445,39 @@ begin
end
else if ResolvedEl.TypeEl is TPasProcedureType then
begin
- if rcConstant in Flags then
- RaiseConstantExprExp(20170216152639,Params);
- if ResolvedEl.TypeEl is TPasFunctionType then
- // function call => return result
- ComputeElement(TPasFunctionType(ResolvedEl.TypeEl).ResultEl,
- ResolvedEl,Flags+[rcNoImplicitProc],StartEl)
+ if Params.Value is TParamsExpr then
+ begin
+ // e.g. Name()() or Name[]()
+ Include(ResolvedEl.Flags,rrfReadable);
+ end;
+ if rrfReadable in ResolvedEl.Flags then
+ begin
+ // call procvar
+ if rcConstant in Flags then
+ RaiseConstantExprExp(20170216152639,Params);
+ if ResolvedEl.TypeEl is TPasFunctionType then
+ // function call => return result
+ ComputeElement(TPasFunctionType(ResolvedEl.TypeEl).ResultEl,
+ ResolvedEl,Flags+[rcNoImplicitProc],StartEl)
+ else
+ // procedure call, result is neither readable nor writable
+ SetResolverTypeExpr(ResolvedEl,btProc,TPasProcedureType(ResolvedEl.TypeEl),[]);
+ Include(ResolvedEl.Flags,rrfCanBeStatement);
+ end
else
- // procedure call, result is neither readable nor writable
- SetResolverTypeExpr(ResolvedEl,btProc,TPasProcedureType(ResolvedEl.TypeEl),[]);
- Include(ResolvedEl.Flags,rrfCanBeStatement);
+ begin
+ // typecast proctype
+ if length(Params.Params)<>1 then
+ begin
+ {$IFDEF VerbosePasResolver}
+ writeln('TPasResolver.ComputeFuncParams DeclEl=',GetObjName(DeclEl),' ',GetResolverResultDbg(ResolvedEl));
+ {$ENDIF}
+ RaiseMsg(20170416185211,nWrongNumberOfParametersForTypeCast,
+ sWrongNumberOfParametersForTypeCast,[ResolvedEl.TypeEl.Name],Params);
+ end;
+ SetResolverValueExpr(ResolvedEl,btContext,TPasProcedureType(ResolvedEl.TypeEl),
+ Params.Params[0],[rrfReadable]);
+ end;
end
else if (DeclEl is TPasType) then
begin
@@ -7494,6 +7626,51 @@ begin
AccessExpr(P[2],rraRead);
end;
+function TPasResolver.BI_TypeInfo_OnGetCallCompatibility(
+ Proc: TResElDataBuiltInProc; Expr: TPasExpr; RaiseOnError: boolean): integer;
+var
+ Params: TParamsExpr;
+ Param: TPasExpr;
+ Decl: TPasElement;
+ ParamResolved: TPasResolverResult;
+ aType: TPasType;
+begin
+ Result:=cIncompatible;
+ if not CheckBuiltInMinParamCount(Proc,Expr,1,RaiseOnError) then
+ exit;
+ Params:=TParamsExpr(Expr);
+
+ // check type or var
+ Param:=Params.Params[0];
+ ComputeElement(Param,ParamResolved,[rcNoImplicitProc]);
+ Decl:=ParamResolved.IdentEl;
+ aType:=nil;
+ if (Decl<>nil) then
+ begin
+ if Decl is TPasType then
+ aType:=TPasType(Decl)
+ else if Decl is TPasVariable then
+ aType:=TPasVariable(Decl).VarType
+ else if Decl is TPasArgument then
+ aType:=TPasArgument(Decl).ArgType;
+ end;
+ if aType=nil then
+ RaiseMsg(20170411100259,nTypeIdentifierExpected,sTypeIdentifierExpected,[],Param);
+ aType:=ResolveAliasType(aType);
+ if not HasTypeInfo(aType) then
+ RaiseMsg(20170413200118,nSymbolCannotBePublished,sSymbolCannotBePublished,[],Param);
+
+ Result:=CheckBuiltInMaxParamCount(Proc,Params,1,RaiseOnError);
+end;
+
+procedure TPasResolver.BI_TypeInfo_OnGetCallResult(Proc: TResElDataBuiltInProc;
+ Params: TParamsExpr; out ResolvedEl: TPasResolverResult);
+begin
+ if Proc=nil then;
+ if Params=nil then ;
+ SetResolverTypeExpr(ResolvedEl,btPointer,FBaseTypes[btPointer],[rrfReadable]);
+end;
+
constructor TPasResolver.Create;
begin
inherited Create;
@@ -7807,8 +7984,10 @@ begin
and (vmClass in TPasVariable(FindData.Found).VarModifiers) then
// class var/const/property: ok
else
- RaiseMsg(20170216152348,nCannotAccessThisMemberFromAClassReference,
- sCannotAccessThisMemberFromAClassReference,[],FindData.ErrorPosEl);
+ begin
+ RaiseMsg(20170216152348,nCannotAccessThisMemberFromAX,
+ sCannotAccessThisMemberFromAX,[FindData.Found.Parent.ElementTypeName],FindData.ErrorPosEl);
+ end;
end
else if (proExtClassInstanceNoTypeMembers in Options)
and (StartScope.ClassType=TPasDotClassScope)
@@ -8126,6 +8305,10 @@ begin
AddBuiltInProc('Delete','procedure Delete(var Array; Start, Count: integer)',
@BI_DeleteArray_OnGetCallCompatibility,nil,
@BI_DeleteArray_OnFinishParamsExpr,bfDeleteArray,[bipfCanBeStatement]);
+ if bfTypeInfo in TheBaseProcs then
+ AddBuiltInProc('TypeInfo','function TypeInfo(type or var identifier): Pointer',
+ @BI_TypeInfo_OnGetCallCompatibility,@BI_TypeInfo_OnGetCallResult,
+ nil,bfTypeInfo);
end;
function TPasResolver.AddBaseType(const aName: string; Typ: TResolverBaseType
@@ -8613,7 +8796,10 @@ begin
if GotType.BaseType<>ExpType.BaseType then
begin
GotDesc:=GetBaseDecs(GotType);
- ExpDesc:=GetBaseDecs(ExpType);
+ if ExpType.BaseType=btNil then
+ ExpDesc:=BaseTypeNames[btPointer]
+ else
+ ExpDesc:=GetBaseDecs(ExpType);
if GotDesc=ExpDesc then
begin
GotDesc:=GetBaseDecs(GotType,true);
@@ -8683,8 +8869,7 @@ begin
end
else
begin
- IsVarArgs:=IsVarArgs or ((ProcType.Parent is TPasProcedure)
- and (pmVarargs in TPasProcedure(ProcType.Parent).Modifiers));
+ IsVarArgs:=IsVarArgs or (ptmVarargs in ProcType.Modifiers);
if IsVarArgs then
begin
ComputeElement(Param,ParamResolved,[],Param);
@@ -8884,15 +9069,15 @@ begin
exit;
end;
if Proc1.IsNested<>Proc2.IsNested then
- exit(ModifierError('is nested'));
+ exit(ModifierError(ProcTypeModifiers[ptmIsNested]));
if Proc1.IsOfObject<>Proc2.IsOfObject then
begin
if (proProcTypeWithoutIsNested in Options) then
- exit(ModifierError('of object'))
+ exit(ModifierError(ProcTypeModifiers[ptmOfObject]))
else if Proc1.IsNested then
// "is nested" can handle both, proc and method.
else
- exit(ModifierError('of object'))
+ exit(ModifierError(ProcTypeModifiers[ptmOfObject]))
end;
if Proc1.CallingConvention<>Proc2.CallingConvention then
begin
@@ -9049,6 +9234,7 @@ function TPasResolver.CheckAssignResCompatibility(const LHS,
var
TypeEl: TPasType;
Handled: Boolean;
+ C: TClass;
begin
// check if the RHS can be converted to LHS
{$IFDEF VerbosePasResolver}
@@ -9099,7 +9285,7 @@ begin
[],ErrorEl);
exit(cIncompatible);
end
- else if LHS.BaseType in [btRange,btSet,btModule,btArray] then
+ else if LHS.BaseType in [btRange,btSet,btModule,btArray,btProc] then
begin
if RaiseOnIncompatible then
RaiseMsg(20170216152432,nIllegalExpression,sIllegalExpression,[],ErrorEl);
@@ -9118,10 +9304,11 @@ begin
else if LHS.BaseType=btContext then
begin
TypeEl:=LHS.TypeEl;
- if (TypeEl.ClassType=TPasClassType)
- or (TypeEl.ClassType=TPasClassOfType)
- or (TypeEl.ClassType=TPasPointerType)
- or (TypeEl is TPasProcedureType)
+ C:=TypeEl.ClassType;
+ if (C=TPasClassType)
+ or (C=TPasClassOfType)
+ or (C=TPasPointerType)
+ or C.InheritsFrom(TPasProcedureType)
or IsDynArray(TypeEl) then
Result:=cExact;
end;
@@ -9154,6 +9341,40 @@ begin
Result:=cExact;
end;
end
+ else if LHS.BaseType=btPointer then
+ begin
+ if RHS.BaseType=btPointer then
+ begin
+ if IsBaseType(LHS.TypeEl,btPointer) then
+ Result:=cExact // btPointer can take any pointer
+ else if IsBaseType(RHS.TypeEl,btPointer) then
+ Result:=cExact+1 // any pointer can take a btPointer
+ else if IsSameType(LHS.TypeEl,RHS.TypeEl) then
+ Result:=cExact // pointer of same type
+ else if (LHS.TypeEl.ClassType=TPasPointerType)
+ and (RHS.TypeEl.ClassType=TPasPointerType) then
+ Result:=CheckAssignCompatibility(TPasPointerType(LHS.TypeEl).DestType,
+ TPasPointerType(RHS.TypeEl).DestType,RaiseOnIncompatible);
+ end
+ else if IsBaseType(LHS.TypeEl,btPointer) then
+ begin
+ if RHS.BaseType=btContext then
+ begin
+ C:=RHS.TypeEl.ClassType;
+ if C=TPasClassType then
+ exit(cExact) // class type or class instance
+ else if C=TPasClassOfType then
+ Result:=cExact
+ else if C=TPasArrayType then
+ begin
+ if IsDynArray(RHS.TypeEl) then
+ Result:=cExact;
+ end
+ else if (C=TPasProcedureType) or (C=TPasFunctionType) then
+ Result:=cExact+1;
+ end;
+ end;
+ end
else if (LHS.BaseType=btContext) and (LHS.TypeEl is TPasArrayType) then
Result:=CheckAssignCompatibilityArrayType(LHS,RHS,ErrorEl,RaiseOnIncompatible);
end;
@@ -9309,10 +9530,10 @@ begin
or (TypeEl is TPasProcedureType)
or IsDynArray(TypeEl) then
exit(cExact);
- end
- else if RaiseOnIncompatible then
- RaiseMsg(20170216152442,nIncompatibleTypesGotExpected,sIncompatibleTypesGotExpected,
- [BaseTypeNames[RHS.BaseType],BaseTypeNames[LHS.BaseType]],LErrorEl)
+ end;
+ if RaiseOnIncompatible then
+ RaiseIncompatibleTypeRes(20170216152442,nIncompatibleTypesGotExpected,
+ [],RHS,LHS,RErrorEl)
else
exit(cIncompatible);
end
@@ -9329,10 +9550,10 @@ begin
or (TypeEl is TPasProcedureType)
or IsDynArray(TypeEl) then
exit(cExact);
- end
- else if RaiseOnIncompatible then
- RaiseMsg(20170216152444,nIncompatibleTypesGotExpected,sIncompatibleTypesGotExpected,
- [BaseTypeNames[LHS.BaseType],BaseTypeNames[RHS.BaseType]],LErrorEl)
+ end;
+ if RaiseOnIncompatible then
+ RaiseIncompatibleTypeRes(20170216152444,nIncompatibleTypesGotExpected,
+ [],LHS,RHS,LErrorEl)
else
exit(cIncompatible);
end
@@ -9475,6 +9696,24 @@ begin
end;
end;
+function TPasResolver.GetPasPropertyStored(El: TPasProperty): TPasElement;
+// search the member variable or setter procedure of a property
+var
+ DeclEl: TPasElement;
+begin
+ Result:=nil;
+ while El<>nil do
+ begin
+ if El.StoredAccessor<>nil then
+ begin
+ DeclEl:=(El.StoredAccessor.CustomData as TResolvedReference).Declaration;
+ Result:=DeclEl;
+ exit;
+ end;
+ El:=GetPasPropertyAncestor(El);
+ end;
+end;
+
function TPasResolver.CheckParamCompatibility(Expr: TPasExpr;
Param: TPasArgument; ParamNo: integer; RaiseOnError: boolean): integer;
var
@@ -9529,7 +9768,7 @@ begin
if not ResolvedElCanBeVarParam(ExprResolved) then
begin
{$IFDEF VerbosePasResolver}
- writeln('TPasResolver.CheckParamCompatibility NeedWritable: Identifier=',GetObjName(ExprResolved.IdentEl),' Type=',GetObjName(ExprResolved.TypeEl),' Expr=',GetObjName(ExprResolved.ExprEl),' Flags=',ResolverResultFlagsToStr(ExprResolved.Flags));
+ writeln('TPasResolver.CheckParamCompatibility NeedWritable: ',GetResolverResultDbg(ExprResolved));
{$ENDIF}
if RaiseOnError then
RaiseMsg(20170216152450,nVariableIdentifierExpected,sVariableIdentifierExpected,[],Expr);
@@ -9968,8 +10207,8 @@ begin
exit(cIncompatible);
end;
Param:=Params.Params[0];
- ComputeElement(Param,ParamResolved,[]);
- ComputeElement(El,ResolvedEl,[]);
+ ComputeElement(Param,ParamResolved,[rcNoImplicitProcType]);
+ ComputeElement(El,ResolvedEl,[rcType]);
Result:=CheckTypeCastRes(ParamResolved,ResolvedEl,Param,RaiseOnError);
end;
@@ -9980,9 +10219,10 @@ var
ToTypeEl, ToClassType, FromClassType: TPasType;
ToTypeBaseType: TResolverBaseType;
C: TClass;
+ ToProcType, FromProcType: TPasProcedureType;
begin
Result:=cIncompatible;
- ToTypeEl:=ToResolved.TypeEl;
+ ToTypeEl:=ResolveAliasType(ToResolved.TypeEl);
if (ToTypeEl<>nil)
and (rrfReadable in FromResolved.Flags) then
begin
@@ -10021,33 +10261,75 @@ begin
begin
if FromResolved.BaseType in btAllStringAndChars then
Result:=cExact+1;
+ end
+ else if ToTypeBaseType=btPointer then
+ begin
+ if FromResolved.BaseType=btPointer then
+ Result:=cExact
+ else if FromResolved.BaseType=btContext then
+ begin
+ C:=FromResolved.TypeEl.ClassType;
+ if (C=TPasClassType)
+ or (C=TPasClassOfType)
+ or (C=TPasPointerType)
+ or ((C=TPasArrayType) and IsDynArray(FromResolved.TypeEl)) then
+ Result:=cExact
+ else if (C=TPasProcedureType) or (C=TPasFunctionType) then
+ begin
+ // from procvar to pointer
+ FromProcType:=TPasProcedureType(FromResolved.TypeEl);
+ if FromProcType.IsOfObject then
+ begin
+ if proMethodAddrAsPointer in Options then
+ Result:=cExact+1
+ else if RaiseOnError then
+ RaiseMsg(20170416183615,nIllegalTypeConversionTo,sIllegalTypeConversionTo,
+ [FromProcType.ElementTypeName+' '+ProcTypeModifiers[ptmOfObject],
+ BaseTypeNames[btPointer]],ErrorEl);
+ end
+ else if FromProcType.IsNested then
+ begin
+ if RaiseOnError then
+ RaiseMsg(20170416183800,nIllegalTypeConversionTo,sIllegalTypeConversionTo,
+ [FromProcType.ElementTypeName+' '+ProcTypeModifiers[ptmIsNested],
+ BaseTypeNames[btPointer]],ErrorEl);
+ end
+ else
+ Result:=cExact+1;
+ end;
+ end;
end;
end;
end
else if C=TPasClassType then
begin
// to class
- if FromResolved.BaseType=btNil then
- Result:=cExact
- else if (FromResolved.BaseType=btContext)
- and (FromResolved.TypeEl.ClassType=TPasClassType) then
+ if FromResolved.BaseType=btContext then
begin
- if (FromResolved.IdentEl is TPasType) then
- RaiseMsg(20170404162606,nCannotTypecastAType,sCannotTypecastAType,[],ErrorEl);
- // type cast upwards or downwards
- Result:=CheckSrcIsADstType(FromResolved,ToResolved,ErrorEl);
- if Result=cIncompatible then
- Result:=CheckSrcIsADstType(ToResolved,FromResolved,ErrorEl);
- if Result=cIncompatible then
- Result:=CheckTypeCastClassInstanceToClass(FromResolved,ToResolved,ErrorEl);
+ if FromResolved.TypeEl.ClassType=TPasClassType then
+ begin
+ if FromResolved.IdentEl is TPasType then
+ RaiseMsg(20170404162606,nCannotTypecastAType,sCannotTypecastAType,[],ErrorEl);
+ // type cast upwards or downwards
+ Result:=CheckSrcIsADstType(FromResolved,ToResolved,ErrorEl);
+ if Result=cIncompatible then
+ Result:=CheckSrcIsADstType(ToResolved,FromResolved,ErrorEl);
+ if Result=cIncompatible then
+ Result:=CheckTypeCastClassInstanceToClass(FromResolved,ToResolved,ErrorEl);
+ end
+ end
+ else if FromResolved.BaseType=btPointer then
+ begin
+ if IsBaseType(FromResolved.TypeEl,btPointer) then
+ Result:=cExact; // untyped pointer to class instance
end;
end
else if C=TPasClassOfType then
begin
//writeln('TPasResolver.CheckTypeCast class-of FromRes.TypeEl=',GetObjName(FromResolved.TypeEl),' FromRes.IdentEl=',GetObjName(FromResolved.IdentEl));
- if (FromResolved.BaseType=btContext) then
+ if FromResolved.BaseType=btContext then
begin
- if (FromResolved.TypeEl.ClassType=TPasClassOfType) then
+ if FromResolved.TypeEl.ClassType=TPasClassOfType then
begin
if (FromResolved.IdentEl is TPasType) then
RaiseMsg(20170404162604,nCannotTypecastAType,sCannotTypecastAType,[],ErrorEl);
@@ -10056,6 +10338,11 @@ begin
FromClassType:=TPasClassOfType(FromResolved.TypeEl).DestType;
Result:=CheckClassesAreRelated(ToClassType,FromClassType,ErrorEl);
end;
+ end
+ else if FromResolved.BaseType=btPointer then
+ begin
+ if IsBaseType(FromResolved.TypeEl,btPointer) then
+ Result:=cExact; // untyped pointer to class-of
end;
end
else if C=TPasEnumType then
@@ -10065,29 +10352,89 @@ begin
end
else if C=TPasArrayType then
begin
- if (FromResolved.BaseType=btContext)
- and (FromResolved.TypeEl.ClassType=TPasArrayType) then
- Result:=CheckTypeCastArray(TPasArrayType(FromResolved.TypeEl),
- TPasArrayType(ToTypeEl),ErrorEl,RaiseOnError);
+ if FromResolved.BaseType=btContext then
+ begin
+ if FromResolved.TypeEl.ClassType=TPasArrayType then
+ Result:=CheckTypeCastArray(TPasArrayType(FromResolved.TypeEl),
+ TPasArrayType(ToTypeEl),ErrorEl,RaiseOnError);
+ end
+ else if FromResolved.BaseType=btPointer then
+ begin
+ if IsDynArray(ToResolved.TypeEl)
+ and IsBaseType(FromResolved.TypeEl,btPointer) then
+ Result:=cExact; // untyped pointer to dynnamic array
+ end;
+ end
+ else if (C=TPasProcedureType) or (C=TPasFunctionType) then
+ begin
+ ToProcType:=TPasProcedureType(ToTypeEl);
+ if IsBaseType(FromResolved.TypeEl,btPointer) then
+ begin
+ // type cast untyped pointer value to proctype
+ if ToProcType.IsOfObject then
+ begin
+ if proMethodAddrAsPointer in Options then
+ Result:=cExact+1
+ else if RaiseOnError then
+ RaiseMsg(20170416183940,nIllegalTypeConversionTo,sIllegalTypeConversionTo,
+ [BaseTypeNames[btPointer],
+ ToProcType.ElementTypeName+' '+ProcTypeModifiers[ptmOfObject]],ErrorEl);
+ end
+ else if ToProcType.IsNested then
+ begin
+ if RaiseOnError then
+ RaiseMsg(20170416184149,nIllegalTypeConversionTo,sIllegalTypeConversionTo,
+ [BaseTypeNames[btPointer],
+ ToProcType.ElementTypeName+' '+ProcTypeModifiers[ptmIsNested]],ErrorEl);
+ end
+ else
+ Result:=cExact+1;
+ end
+ else if FromResolved.BaseType=btContext then
+ begin
+ if FromResolved.TypeEl is TPasProcedureType then
+ begin
+ // type cast procvar to proctype
+ FromProcType:=TPasProcedureType(FromResolved.TypeEl);
+ if (FromProcType.IsOfObject<>ToProcType.IsOfObject)
+ and not (proMethodAddrAsPointer in Options) then
+ begin
+ if RaiseOnError then
+ RaiseMsg(20170416183109,nIllegalTypeConversionTo,sIllegalTypeConversionTo,
+ [FromProcType.ElementTypeName+BoolToStr(FromProcType.IsOfObject,' '+ProcTypeModifiers[ptmOfObject],''),
+ ToProcType.ElementTypeName+BoolToStr(ToProcType.IsOfObject,' '+ProcTypeModifiers[ptmOfObject],'')],ErrorEl);
+ end
+ else if FromProcType.IsNested<>ToProcType.IsNested then
+ begin
+ if RaiseOnError then
+ RaiseMsg(20170416183305,nIllegalTypeConversionTo,sIllegalTypeConversionTo,
+ [FromProcType.ElementTypeName+BoolToStr(FromProcType.IsNested,' '+ProcTypeModifiers[ptmIsNested],''),
+ ToProcType.ElementTypeName+BoolToStr(ToProcType.IsNested,' '+ProcTypeModifiers[ptmIsNested],'')],ErrorEl);
+ end
+ else
+ Result:=cExact+1;
+ end;
+ end;
end;
end
else if ToTypeEl<>nil then
begin
// FromResolved is not readable
- if (FromResolved.BaseType=btContext)
- and (FromResolved.TypeEl.ClassType=TPasClassType)
- and (FromResolved.TypeEl=FromResolved.IdentEl)
- and (ToResolved.BaseType=btContext)
- and (ToResolved.TypeEl.ClassType=TPasClassOfType)
- and (ToResolved.TypeEl=ToResolved.IdentEl) then
- begin
- // for example class-of(Self) in a class function
- ToClassType:=TPasClassOfType(ToTypeEl).DestType;
- FromClassType:=TPasClassType(FromResolved.TypeEl);
- Result:=CheckClassesAreRelated(ToClassType,FromClassType,ErrorEl);
- if Result<cIncompatible then exit;
+ if FromResolved.BaseType=btContext then
+ begin
+ if (FromResolved.TypeEl.ClassType=TPasClassType)
+ and (FromResolved.TypeEl=FromResolved.IdentEl)
+ and (ToResolved.BaseType=btContext)
+ and (ToResolved.TypeEl.ClassType=TPasClassOfType)
+ and (ToResolved.TypeEl=ToResolved.IdentEl) then
+ begin
+ // for example class-of(Self) in a class function
+ ToClassType:=TPasClassOfType(ToTypeEl).DestType;
+ FromClassType:=TPasClassType(FromResolved.TypeEl);
+ Result:=CheckClassesAreRelated(ToClassType,FromClassType,ErrorEl);
+ end;
end;
- if RaiseOnError then
+ if (Result=cIncompatible) and RaiseOnError then
begin
if FromResolved.IdentEl is TPasType then
RaiseMsg(20170404162610,nCannotTypecastAType,sCannotTypecastAType,[],ErrorEl);
@@ -10097,7 +10444,7 @@ begin
if Result=cIncompatible then
begin
{$IFDEF VerbosePasResolver}
- writeln('TPasResolver.CheckTypeCastRes From=',GetResolverResultDesc(FromResolved),' To=',GetResolverResultDesc(ToResolved));
+ writeln('TPasResolver.CheckTypeCastRes From={',GetResolverResultDbg(FromResolved),'} To={',GetResolverResultDbg(ToResolved),'}');
{$ENDIF}
if RaiseOnError then
RaiseIncompatibleTypeRes(20170216152528,nIllegalTypeConversionTo,
@@ -10595,11 +10942,21 @@ begin
end;
function TPasResolver.ResolveAliasType(aType: TPasType): TPasType;
+var
+ C: TClass;
begin
Result:=aType;
- while (Result<>nil)
- and ((Result.ClassType=TPasAliasType) or (Result.ClassType=TPasTypeAliasType)) do
- Result:=TPasAliasType(Result).DestType;
+ while Result<>nil do
+ begin
+ C:=Result.ClassType;
+ if (C=TPasAliasType) or (C=TPasTypeAliasType) then
+ Result:=TPasAliasType(Result).DestType
+ else if (C=TPasClassType) and TPasClassType(Result).IsForward
+ and (Result.CustomData is TResolvedReference) then
+ Result:=TResolvedReference(Result.CustomData).Declaration as TPasType
+ else
+ exit;
+ end;
end;
function TPasResolver.ExprIsAddrTarget(El: TPasExpr): boolean;
@@ -10615,8 +10972,7 @@ var
begin
Result:=false;
if El=nil then exit;
- if not ((El.ClassType=TParamsExpr) or (El.ClassType=TPrimitiveExpr)
- or (El.ClassType=TSelfExpr)) then
+ if not IsNameExpr(El) then
exit;
repeat
Parent:=El.Parent;
@@ -10789,23 +11145,30 @@ var
Value: TPasExpr;
Ref: TResolvedReference;
Decl: TPasElement;
+ C: TClass;
begin
Result:=false;
if (Params=nil) or (Params.Kind<>pekFuncParams) then exit;
Value:=Params.Value;
- if (Value.ClassType<>TSelfExpr)
- and ((Value.ClassType<>TPrimitiveExpr) or (TPrimitiveExpr(Value).Kind<>pekIdent)) then
+ if not IsNameExpr(Value) then
exit;
if not (Value.CustomData is TResolvedReference) then exit;
Ref:=TResolvedReference(Value.CustomData);
Decl:=Ref.Declaration;
- if (Decl.ClassType=TPasAliasType) or (Decl.ClassType=TPasTypeAliasType) then
+ C:=Decl.ClassType;
+ if (C=TPasAliasType) or (C=TPasTypeAliasType) then
+ begin
Decl:=ResolveAliasType(TPasAliasType(Decl));
- if (Decl.ClassType=TPasClassType)
- or (Decl.ClassType=TPasClassOfType)
- or (Decl.ClassType=TPasEnumType) then
- exit(true);
- if (Decl.ClassType=TPasUnresolvedSymbolRef)
+ C:=Decl.ClassType;
+ end;
+ if (C=TPasProcedureType)
+ or (C=TPasFunctionType) then
+ exit(true)
+ else if (C=TPasClassType)
+ or (C=TPasClassOfType)
+ or (C=TPasEnumType) then
+ exit(true)
+ else if (C=TPasUnresolvedSymbolRef)
and (Decl.CustomData is TResElDataBaseType) then
exit(true);
end;
@@ -10828,6 +11191,18 @@ begin
Result:=2;
end;
+function TPasResolver.HasTypeInfo(El: TPasType): boolean;
+begin
+ Result:=false;
+ if El=nil then exit;
+ if El.CustomData is TResElDataBaseType then
+ exit(true); // base type
+ if El.Parent=nil then exit;
+ if (El.Parent is TPasType) and not HasTypeInfo(TPasType(El.Parent)) then
+ exit;
+ Result:=true;
+end;
+
function TPasResolver.CheckSrcIsADstType(const ResolvedSrcType,
ResolvedDestType: TPasResolverResult; ErrorEl: TPasElement): integer;
// finds distance between classes SrcType and DestType
diff --git a/packages/fcl-passrc/src/pastree.pp b/packages/fcl-passrc/src/pastree.pp
index 82c701ff24..a6746e497f 100644
--- a/packages/fcl-passrc/src/pastree.pp
+++ b/packages/fcl-passrc/src/pastree.pp
@@ -101,7 +101,10 @@ type
visPublished, visAutomated,
visStrictPrivate, visStrictProtected);
- TCallingConvention = (ccDefault,ccRegister,ccPascal,ccCDecl,ccStdCall,ccOldFPCCall,ccSafeCall,ccSysCall);
+ TCallingConvention = (ccDefault,ccRegister,ccPascal,ccCDecl,ccStdCall,
+ ccOldFPCCall,ccSafeCall,ccSysCall);
+ TProcTypeModifier = (ptmOfObject,ptmIsNested,ptmStatic,ptmVarargs);
+ TProcTypeModifiers = set of TProcTypeModifier;
TPackMode = (pmNone,pmPacked,pmBitPacked);
TPasMemberVisibilities = set of TPasMemberVisibility;
@@ -648,6 +651,11 @@ type
{ TPasProcedureType }
TPasProcedureType = class(TPasType)
+ private
+ function GetIsNested: Boolean;
+ function GetIsOfObject: Boolean;
+ procedure SetIsNested(const AValue: Boolean);
+ procedure SetIsOfObject(const AValue: Boolean);
public
constructor Create(const AName: string; AParent: TPasElement); override;
destructor Destroy; override;
@@ -659,10 +667,11 @@ type
procedure ForEachCall(const aMethodCall: TOnForEachPasElement;
const Arg: Pointer); override;
public
- IsOfObject: Boolean;
- IsNested : Boolean;
Args: TFPList; // List of TPasArgument objects
CallingConvention: TCallingConvention;
+ Modifiers: TProcTypeModifiers;
+ property IsOfObject: Boolean read GetIsOfObject write SetIsOfObject;
+ property IsNested : Boolean read GetIsNested write SetIsNested;
end;
{ TPasResultElement }
@@ -828,7 +837,7 @@ type
TProcedureModifier = (pmVirtual, pmDynamic, pmAbstract, pmOverride,
pmExport, pmOverload, pmMessage, pmReintroduce,
- pmStatic,pmInline,pmAssembler,pmVarargs, pmPublic,
+ pmInline,pmAssembler, pmPublic,
pmCompilerProc,pmExternal,pmForward, pmDispId,
pmNoReturn, pmfar);
TProcedureModifiers = Set of TProcedureModifier;
@@ -1410,11 +1419,13 @@ const
( 'deprecated', 'library', 'platform', 'experimental', 'unimplemented' );
cCallingConventions : Array[TCallingConvention] of string =
( '', 'Register','Pascal','CDecl','StdCall','OldFPCCall','SafeCall','SysCall');
+ ProcTypeModifiers : Array[TProcTypeModifier] of string =
+ ('of Object', 'is nested','static','varargs');
ModifierNames : Array[TProcedureModifier] of string
= ('virtual', 'dynamic','abstract', 'override',
'export', 'overload', 'message', 'reintroduce',
- 'static','inline','assembler','varargs', 'public',
+ 'inline','assembler','public',
'compilerproc','external','forward','dispid',
'noreturn','far');
@@ -2447,6 +2458,32 @@ end;
{ TPasProcedureType }
+function TPasProcedureType.GetIsNested: Boolean;
+begin
+ Result:=ptmIsNested in Modifiers;
+end;
+
+function TPasProcedureType.GetIsOfObject: Boolean;
+begin
+ Result:=ptmOfObject in Modifiers;
+end;
+
+procedure TPasProcedureType.SetIsNested(const AValue: Boolean);
+begin
+ if AValue then
+ Include(Modifiers,ptmIsNested)
+ else
+ Exclude(Modifiers,ptmIsNested);
+end;
+
+procedure TPasProcedureType.SetIsOfObject(const AValue: Boolean);
+begin
+ if AValue then
+ Include(Modifiers,ptmOfObject)
+ else
+ Exclude(Modifiers,ptmOfObject);
+end;
+
constructor TPasProcedureType.Create(const AName: string; AParent: TPasElement);
begin
inherited Create(AName, AParent);
@@ -3690,7 +3727,7 @@ end;
function TPasProcedure.IsStatic: Boolean;
begin
- Result:=pmStatic in FModifiers;
+ Result:=ptmStatic in ProcType.Modifiers;
end;
function TPasProcedure.IsForward: Boolean;
diff --git a/packages/fcl-passrc/src/pasuseanalyzer.pas b/packages/fcl-passrc/src/pasuseanalyzer.pas
index 9cebe564fc..b7fe8cd305 100644
--- a/packages/fcl-passrc/src/pasuseanalyzer.pas
+++ b/packages/fcl-passrc/src/pasuseanalyzer.pas
@@ -147,15 +147,15 @@ type
end;
TPasAnalyzerOption = (
- paoKeepPublished, // when a class is used, all its published members are used as well
paoOnlyExports // default: use all class members accessible from outside (protected, but not private)
);
TPasAnalyzerOptions = set of TPasAnalyzerOption;
TPAUseMode = (
- paumElement, // mark element
- paumAllPublic, // mark element and descend into children and mark public identifiers
- paumAllExports // do not mark element and descend into children and mark exports
+ paumElement, // Mark element. Do not descend into children.
+ paumAllPublic, // Mark element and descend into children and mark public identifiers
+ paumAllExports, // Do not mark element. Descend into children and mark exports.
+ paumPublished // Mark element and its type and descend into children and mark published identifiers
);
TPAUseModes = set of TPAUseMode;
@@ -188,6 +188,7 @@ type
function ElementVisited(El: TPasElement; Mode: TPAUseMode): boolean;
procedure UseElement(El: TPasElement; Access: TResolvedRefAccess;
UseFull: boolean); virtual;
+ procedure UsePublished(El: TPasElement); virtual;
procedure UseModule(aModule: TPasModule; Mode: TPAUseMode); virtual;
procedure UseSection(Section: TPasSection; Mode: TPAUseMode); virtual;
procedure UseImplBlock(Block: TPasImplBlock; Mark: boolean); virtual;
@@ -221,6 +222,7 @@ type
function FindElement(El: TPasElement): TPAElement;
// utility
function IsUsed(El: TPasElement): boolean; // valid after calling Analyze*
+ function IsTypeInfoUsed(El: TPasElement): boolean; // valid after calling Analyze*
function IsModuleInternal(El: TPasElement): boolean;
function IsExport(El: TPasElement): boolean;
function IsIdentifier(El: TPasElement): boolean;
@@ -615,6 +617,82 @@ begin
RaiseNotSupported(20170307090947,El);
end;
+procedure TPasAnalyzer.UsePublished(El: TPasElement);
+// mark typeinfo, do not
+var
+ C: TClass;
+ Members: TFPList;
+ i: Integer;
+ Member: TPasElement;
+ MemberResolved: TPasResolverResult;
+ Prop: TPasProperty;
+ ProcType: TPasProcedureType;
+begin
+ {$IFDEF VerbosePasAnalyzer}
+ writeln('TPasAnalyzer.UsePublished START ',GetObjName(El));
+ {$ENDIF}
+ if ElementVisited(El,paumPublished) then exit;
+ C:=El.ClassType;
+ if C=TPasUnresolvedSymbolRef then
+ else if (C=TPasVariable) or (C=TPasConst) then
+ UsePublished(TPasVariable(El).VarType)
+ else if C=TPasProperty then
+ begin
+ // published property
+ Prop:=TPasProperty(El);
+ for i:=0 to Prop.Args.Count-1 do
+ UsePublished(TPasArgument(Prop.Args[i]).ArgType);
+ UsePublished(Prop.VarType);
+ // Note: read, write and index don't need extra typeinfo
+
+ // stored and defaultvalue are only used when published -> mark as used
+ UseElement(Prop.StoredAccessor,rraRead,false);
+ UseElement(Prop.DefaultExpr,rraRead,false);
+ end
+ else if (C=TPasAliasType) or (C=TPasTypeAliasType) then
+ UsePublished(TPasAliasType(El).DestType)
+ else if C=TPasEnumType then
+ else if C=TPasSetType then
+ UsePublished(TPasSetType(El).EnumType)
+ else if C=TPasArrayType then
+ begin
+ UsePublished(TPasArrayType(El).ElType);
+ for i:=0 to length(TPasArrayType(El).Ranges)-1 do
+ begin
+ Member:=TPasArrayType(El).Ranges[i];
+ Resolver.ComputeElement(Member,MemberResolved,[rcConstant]);
+ UsePublished(MemberResolved.TypeEl);
+ end;
+ end
+ else if C=TPasPointerType then
+ UsePublished(TPasPointerType(El).DestType)
+ else if C=TPasClassType then
+ else if C=TPasClassOfType then
+ else if C=TPasRecordType then
+ begin
+ // published record: use all members
+ Members:=TPasRecordType(El).Members;
+ for i:=0 to Members.Count-1 do
+ begin
+ Member:=TPasElement(Members[i]);
+ UsePublished(Member);
+ UseElement(Member,rraNone,true);
+ end;
+ end
+ else if C.InheritsFrom(TPasProcedure) then
+ UsePublished(TPasProcedure(El).ProcType)
+ else if C.InheritsFrom(TPasProcedureType) then
+ begin
+ ProcType:=TPasProcedureType(El);
+ for i:=0 to ProcType.Args.Count-1 do
+ UsePublished(TPasArgument(ProcType.Args[i]).ArgType);
+ if El is TPasFunctionType then
+ UsePublished(TPasFunctionType(El).ResultEl.ResultType);
+ end
+ else
+ RaiseNotSupported(20170414153904,El);
+end;
+
procedure TPasAnalyzer.UseModule(aModule: TPasModule; Mode: TPAUseMode);
procedure UseInitFinal(aSection: TPasImplBlock);
@@ -877,18 +955,22 @@ var
C: TClass;
Params: TPasExprArray;
i: Integer;
+ BuiltInProc: TResElDataBuiltInProc;
+ ParamResolved: TPasResolverResult;
+ Decl: TPasElement;
begin
if El=nil then exit;
// expressions are not marked
+ Ref:=nil;
if El.CustomData is TResolvedReference then
begin
// this is a reference -> mark target
Ref:=TResolvedReference(El.CustomData);
- UseElement(Ref.Declaration,Ref.Access,false);
+ Decl:=Ref.Declaration;
+ UseElement(Decl,Ref.Access,false);
- if (El.ClassType=TSelfExpr)
- or ((El.ClassType=TPrimitiveExpr) and (TPrimitiveExpr(El).Kind=pekIdent)) then
+ if Resolver.IsNameExpr(El) then
begin
if Ref.WithExprScope<>nil then
begin
@@ -899,12 +981,12 @@ begin
exit;
end;
end;
- if (Ref.Declaration is TPasVariable)
+ if (Decl is TPasVariable)
and (El.Parent is TBinaryExpr)
and (TBinaryExpr(El.Parent).right=El) then
begin
- if ((Ref.Declaration.Parent is TPasRecordType)
- or (Ref.Declaration.Parent is TPasVariant)) then
+ if ((Decl.Parent is TPasRecordType)
+ or (Decl.Parent is TPasVariant)) then
begin
// a record member was accessed -> access the record too
UseExprRef(TBinaryExpr(El.Parent).left,Ref.Access,false);
@@ -912,6 +994,20 @@ begin
end;
end;
+ if Decl is TPasUnresolvedSymbolRef then
+ begin
+ if Decl.CustomData is TResElDataBuiltInProc then
+ begin
+ BuiltInProc:=TResElDataBuiltInProc(Decl.CustomData);
+ if BuiltInProc.BuiltIn=bfTypeInfo then
+ begin
+ Params:=(El.Parent as TParamsExpr).Params;
+ Resolver.ComputeElement(Params[0],ParamResolved,[]);
+ UsePublished(ParamResolved.IdentEl);
+ end;
+ end;
+ end;
+
end;
UseExpr(El.format1);
UseExpr(El.format2);
@@ -1039,7 +1135,7 @@ begin
if ImplProc.Body<>nil then
UseImplBlock(ImplProc.Body.Body,false);
- if ProcScope.OverriddenProc<>nil then
+ if Proc.IsOverride and (ProcScope.OverriddenProc<>nil) then
AddOverride(ProcScope.OverriddenProc,Proc);
// mark overrides
@@ -1158,7 +1254,7 @@ procedure TPasAnalyzer.UseClassType(El: TPasClassType; Mode: TPAUseMode);
var
i: Integer;
Member: TPasElement;
- UsePublished, FirstTime: Boolean;
+ AllPublished, FirstTime: Boolean;
ProcScope: TPasProcedureScope;
ClassScope: TPasClassScope;
Ref: TResolvedReference;
@@ -1178,6 +1274,8 @@ begin
end;
paumElement:
if not MarkElementAsUsed(El) then exit;
+ else
+ RaiseInconsistency(20170414152143,IntToStr(ord(Mode)));
end;
{$IFDEF VerbosePasAnalyzer}
writeln('TPasAnalyzer.UseClassType ',GetElModName(El),' ',Mode,' First=',FirstTime);
@@ -1199,20 +1297,30 @@ begin
UseType(TPasType(El.Interfaces[i]),paumElement);
end;
// members
- UsePublished:=(Mode<>paumAllExports) and (paoKeepPublished in Options);
+ AllPublished:=(Mode<>paumAllExports);
for i:=0 to El.Members.Count-1 do
begin
Member:=TPasElement(El.Members[i]);
if FirstTime and (Member is TPasProcedure) then
begin
ProcScope:=Member.CustomData as TPasProcedureScope;
- if ProcScope.OverriddenProc<>nil then
+ if TPasProcedure(Member).IsOverride and (ProcScope.OverriddenProc<>nil) then
+ begin
+ // this is an override
AddOverride(ProcScope.OverriddenProc,Member);
+ if ScopeModule<>nil then
+ begin
+ // when analyzingf a single module, all overrides are assumed to be called
+ UseElement(Member,rraNone,true);
+ continue;
+ end;
+ end;
end;
- if UsePublished and (Member.Visibility=visPublished) then
+ if AllPublished and (Member.Visibility=visPublished) then
begin
// include published
if not FirstTime then continue;
+ UsePublished(Member);
end
else if Mode=paumElement then
continue
@@ -1763,6 +1871,11 @@ begin
Result:=FindElement(El)<>nil;
end;
+function TPasAnalyzer.IsTypeInfoUsed(El: TPasElement): boolean;
+begin
+ Result:=FChecked[paumPublished].Find(El)<>nil;
+end;
+
function TPasAnalyzer.IsModuleInternal(El: TPasElement): boolean;
begin
if El=nil then
@@ -1772,7 +1885,7 @@ begin
if IsExport(El) then exit(false);
case El.Visibility of
visPrivate,visStrictPrivate: exit(true);
- visPublished: if paoKeepPublished in Options then exit(false);
+ visPublished: exit(false);
end;
Result:=IsModuleInternal(El.Parent);
end;
diff --git a/packages/fcl-passrc/src/pparser.pp b/packages/fcl-passrc/src/pparser.pp
index 170575011d..a8aa7e113c 100644
--- a/packages/fcl-passrc/src/pparser.pp
+++ b/packages/fcl-passrc/src/pparser.pp
@@ -245,6 +245,7 @@ type
function GetVariableModifiers(Parent: TPasElement; Out VarMods: TVariableModifiers; Out LibName, ExportName: TPasExpr; ExternalClass : Boolean): string;
function GetVariableValueAndLocation(Parent : TPasElement; Out Value : TPasExpr; Out Location: String): Boolean;
procedure HandleProcedureModifier(Parent: TPasElement; pm : TProcedureModifier);
+ procedure HandleProcedureTypeModifier(ProcType: TPasProcedureType; ptm : TProcTypeModifier);
procedure ParseClassLocalConsts(AType: TPasClassType; AVisibility: TPasMemberVisibility);
procedure ParseClassLocalTypes(AType: TPasClassType; AVisibility: TPasMemberVisibility);
procedure ParseVarList(Parent: TPasElement; VarList: TFPList; AVisibility: TPasMemberVisibility; Full: Boolean);
@@ -299,8 +300,9 @@ type
function CreateRecordValues(AParent : TPasElement): TRecordValues;
Function IsCurTokenHint(out AHint : TPasMemberHint) : Boolean; overload;
Function IsCurTokenHint: Boolean; overload;
- Function TokenIsCallingConvention(S : String; out CC : TCallingConvention) : Boolean; virtual;
- Function TokenIsProcedureModifier(Parent : TPasElement; S : String; Out Pm : TProcedureModifier) : Boolean; virtual;
+ Function TokenIsCallingConvention(const S : String; out CC : TCallingConvention) : Boolean; virtual;
+ Function TokenIsProcedureModifier(Parent : TPasElement; const S : String; Out PM : TProcedureModifier) : Boolean; virtual;
+ Function TokenIsProcedureTypeModifier(Parent : TPasElement; const S : String; Out PTM : TProcTypeModifier) : Boolean; virtual;
Function CheckHint(Element : TPasElement; ExpectSemiColon : Boolean) : TPasMemberHints;
function ParseParams(AParent : TPasElement;paramskind: TPasExprKind; AllowFormatting : Boolean = False): TParamsExpr;
function ParseExpIdent(AParent : TPasElement): TPasExpr;
@@ -401,7 +403,7 @@ function ParseSource(AEngine: TPasTreeContainer;
const FPCCommandLine, OSTarget, CPUTarget: String;
UseStreams : Boolean = False): TPasModule;
Function IsHintToken(T : String; Out AHint : TPasMemberHint) : boolean;
-Function IsModifier(S : String; Out Pm : TProcedureModifier) : Boolean;
+Function IsProcModifier(S : String; Out PM : TProcedureModifier) : Boolean;
Function IsCallingConvention(S : String; out CC : TCallingConvention) : Boolean;
Function TokenToAssignKind( tk : TToken) : TAssignKind;
@@ -459,9 +461,7 @@ begin
end;
end;
-
-Function IsModifier(S : String; Out Pm : TProcedureModifier) : Boolean;
-
+Function IsProcModifier(S : String; Out PM : TProcedureModifier) : Boolean;
Var
P : TProcedureModifier;
@@ -924,17 +924,17 @@ begin
Result:=IsCurTokenHint(dummy);
end;
-function TPasParser.TokenIsCallingConvention(S: String; out
+function TPasParser.TokenIsCallingConvention(const S: String; out
CC: TCallingConvention): Boolean;
begin
Result:=IsCallingConvention(S,CC);
end;
-function TPasParser.TokenIsProcedureModifier(Parent: TPasElement; S: String;
- out Pm: TProcedureModifier): Boolean;
+function TPasParser.TokenIsProcedureModifier(Parent: TPasElement;
+ const S: String; out PM: TProcedureModifier): Boolean;
begin
- Result:=IsModifier(S,PM);
- if result and (pm in [pmPublic,pmForward]) then
+ Result:=IsProcModifier(S,PM);
+ if Result and (PM in [pmPublic,pmForward]) then
begin
While (Parent<>Nil) and Not ((Parent is TPasClassType) or (Parent is TPasRecordType)) do
Parent:=Parent.Parent;
@@ -942,6 +942,23 @@ begin
end;
end;
+function TPasParser.TokenIsProcedureTypeModifier(Parent: TPasElement;
+ const S: String; out PTM: TProcTypeModifier): Boolean;
+begin
+ if CompareText(S,ProcTypeModifiers[ptmVarargs])=0 then
+ begin
+ Result:=true;
+ PTM:=ptmVarargs;
+ end
+ else if CompareText(S,ProcTypeModifiers[ptmStatic])=0 then
+ begin
+ Result:=true;
+ PTM:=ptmStatic;
+ end
+ else
+ Result:=false;
+ if Parent=nil then;
+end;
function TPasParser.CheckHint(Element: TPasElement; ExpectSemiColon: Boolean
): TPasMemberHints;
@@ -2601,6 +2618,7 @@ begin
for i := 0 to List.Count - 1 do
begin
VarEl := TPasVariable(List[i]);
+ Engine.FinishScope(stDeclaration,VarEl);
Declarations.Declarations.Add(VarEl);
Declarations.Variables.Add(VarEl);
end;
@@ -3083,7 +3101,8 @@ end;
// Full means that a full variable declaration is being parsed.
-procedure TPasParser.ParseVarList(Parent: TPasElement; VarList: TFPList; AVisibility: TPasMemberVisibility; Full : Boolean);
+procedure TPasParser.ParseVarList(Parent: TPasElement; VarList: TFPList;
+ AVisibility: TPasMemberVisibility; Full : Boolean);
// on Exception the VarList is restored, no need to Release the new elements
var
@@ -3186,8 +3205,6 @@ begin
aExpName.AddRef;
end;
end;
- for i := OldListCount to VarList.Count - 1 do
- Engine.FinishScope(stDeclaration,TPasVariable(VarList[i]));
ok:=true;
finally
if aLibName<>nil then aLibName.Release;
@@ -3441,8 +3458,6 @@ Var
end;
begin
- if not (Parent is TPasProcedure) then
- exit;
P:=TPasProcedure(Parent);
if pm<>pmPublic then
AddModifier;
@@ -3541,6 +3556,14 @@ begin
end; // Case
end;
+procedure TPasParser.HandleProcedureTypeModifier(ProcType: TPasProcedureType;
+ ptm: TProcTypeModifier);
+begin
+ if ptm in ProcType.Modifiers then
+ ParseExcSyntaxError;
+ Include(ProcType.Modifiers,ptm);
+end;
+
// Next token is expected to be a "(", ";" or for a function ":". The caller
// will get the token after the final ";" as next token.
procedure TPasParser.ParseProcedureOrFunctionHeader(Parent: TPasElement;
@@ -3608,12 +3631,16 @@ Var
PM : TProcedureModifier;
Done: Boolean;
ResultEl: TPasResultElement;
- OK : Boolean;
+ OK,IsProc : Boolean;
+ PTM: TProcTypeModifier;
+ ModCount: Integer;
+ LastToken: TToken;
begin
// Element must be non-nil. Removed all checks for not-nil.
// If it is nil, the following fails anyway.
CheckProcedureArgs(Element,Element.Args,ProcType in [ptOperator,ptClassOperator]);
+ IsProc:=Parent is TPasProcedure;
case ProcType of
ptFunction,ptClassFunction:
begin
@@ -3667,12 +3694,12 @@ begin
if OfObjectPossible then
begin
NextToken;
- if (curToken =tkOf) then
+ if (CurToken = tkOf) then
begin
ExpectToken(tkObject);
Element.IsOfObject := True;
end
- else if (curToken = tkIs) then
+ else if (CurToken = tkIs) then
begin
expectToken(tkIdentifier);
if (lowerCase(CurTokenString)<>'nested') then
@@ -3682,18 +3709,23 @@ begin
else
UnGetToken;
end;
- NextToken;
- if CurToken = tkEqual then
- begin
- // for example: const p: procedure = nil;
- UngetToken;
- exit;
- end
- else
- UngetToken;
+ ModCount:=0;
Repeat
+ inc(ModCount);
+ LastToken:=CurToken;
NextToken;
- If TokenIsCallingConvention(CurTokenString,cc) then
+ if (ModCount=1) and (CurToken = tkEqual) then
+ begin
+ // for example: const p: procedure = nil;
+ UngetToken;
+ exit;
+ end;
+ If CurToken=tkSemicolon then
+ begin
+ if LastToken=tkSemicolon then
+ ParseExcSyntaxError;
+ end
+ else if TokenIsCallingConvention(CurTokenString,cc) then
begin
Element.CallingConvention:=Cc;
if cc = ccSysCall then
@@ -3712,8 +3744,10 @@ begin
end;
ExpectToken(tkSemicolon);
end
- else if TokenIsProcedureModifier(Parent,CurTokenString,pm) then
- HandleProcedureModifier(Parent,Pm)
+ else if IsProc and TokenIsProcedureModifier(Parent,CurTokenString,PM) then
+ HandleProcedureModifier(Parent,PM)
+ else if TokenIsProcedureTypeModifier(Parent,CurTokenString,PTM) then
+ HandleProcedureTypeModifier(Element,PTM)
else if (CurToken=tklibrary) then // library is a token and a directive.
begin
Tok:=UpperCase(CurTokenString);
@@ -3743,16 +3777,17 @@ begin
until CurToken = tkSquaredBraceClose;
ExpectToken(tkSemicolon);
end
- else if CurToken<>tkSemicolon then
+ else
CheckToken(tkSemicolon);
Done:=(CurToken=tkSemiColon);
if Done then
begin
NextToken;
Done:=Not ((Curtoken=tkSquaredBraceOpen) or
- TokenIsProcedureModifier(Parent,CurtokenString,Pm) or
- IscurtokenHint() or
- TokenisCallingConvention(CurTokenString,cc) or
+ TokenIsProcedureModifier(Parent,CurtokenString,PM) or
+ TokenIsProcedureTypeModifier(Parent,CurtokenString,PTM) or
+ IsCurTokenHint() or
+ TokenIsCallingConvention(CurTokenString,cc) or
(CurToken=tkIdentifier) and (CompareText(CurTokenText,'alias')=0));
// DumpCurToken('Done '+IntToStr(Ord(Done)));
UngetToken;
@@ -3852,7 +3887,7 @@ var
begin
Result:=TPasProperty(CreateElement(TPasProperty,AName,Parent,AVisibility));
if IsClassField then
- Result.VarModifiers:=Result.VarModifiers+[vmClass];
+ Include(Result.VarModifiers,vmClass);
ok:=false;
try
NextToken;
@@ -4103,7 +4138,7 @@ begin
while True do
begin
NextToken;
- WriteLn({$IFDEF VerbosePasParser}i,{$ENDIF}' Token=',CurTokenText);
+ // WriteLn({$IFDEF VerbosePasParser}i,{$ENDIF}' Token=',CurTokenText);
case CurToken of
tkasm:
begin
@@ -4760,6 +4795,7 @@ Var
Cons : TPasConst;
isClass : Boolean;
NamePos: TPasSourcePos;
+ OldCount, i: Integer;
begin
v:=visDefault;
isClass:=False;
@@ -4818,7 +4854,10 @@ begin
NextToken;
Continue;
end;
+ OldCount:=ARec.Members.Count;
ParseInlineVarDecl(ARec, ARec.Members, v, AEndToken=tkBraceClose);
+ for i:=OldCount to ARec.Members.Count-1 do
+ Engine.FinishScope(stDeclaration,TPasVariable(ARec.Members[i]));
end;
tkCase :
begin
@@ -4946,6 +4985,7 @@ Var
Element: TPasElement;
I : Integer;
isStatic : Boolean;
+ VarEl: TPasVariable;
begin
VarList := TFPList.Create;
@@ -4966,10 +5006,12 @@ begin
Element.Visibility := AVisibility;
if (Element is TPasVariable) then
begin
+ VarEl:=TPasVariable(Element);
if IsClassField then
- TPasVariable(Element).VarModifiers:=TPasVariable(Element).VarModifiers+[vmClass];
+ Include(VarEl.VarModifiers,vmClass);
if isStatic then
- TPasVariable(Element).VarModifiers:=TPasVariable(Element).VarModifiers+[vmStatic];
+ Include(VarEl.VarModifiers,vmStatic);
+ Engine.FinishScope(stDeclaration,VarEl);
end;
AType.Members.Add(Element);
end;
diff --git a/packages/fcl-passrc/tests/tcbaseparser.pas b/packages/fcl-passrc/tests/tcbaseparser.pas
index e3e0569b93..733173f6f8 100644
--- a/packages/fcl-passrc/tests/tcbaseparser.pas
+++ b/packages/fcl-passrc/tests/tcbaseparser.pas
@@ -79,6 +79,7 @@ Type
Procedure AssertEquals(Const Msg : String; AExpected, AActual: TPasMemberVisibility); overload;
Procedure AssertEquals(Const Msg : String; AExpected, AActual: TProcedureModifier); overload;
Procedure AssertEquals(Const Msg : String; AExpected, AActual: TProcedureModifiers); overload;
+ Procedure AssertEquals(Const Msg : String; AExpected, AActual: TProcTypeModifiers); overload;
Procedure AssertEquals(Const Msg : String; AExpected, AActual: TAssignKind); overload;
Procedure AssertEquals(Const Msg : String; AExpected, AActual: TProcedureMessageType); overload;
Procedure AssertEquals(Const Msg : String; AExpected, AActual: TOperatorType); overload;
@@ -850,6 +851,27 @@ begin
end;
procedure TTestParser.AssertEquals(const Msg: String; AExpected,
+ AActual: TProcTypeModifiers);
+
+ Function Sn (S : TProcTypeModifiers) : String;
+
+ Var
+ m : TProcTypeModifier;
+ begin
+ Result:='';
+ For M:=Low(TProcTypeModifier) to High(TProcTypeModifier) do
+ If (m in S) then
+ begin
+ If (Result<>'') then
+ Result:=Result+',';
+ Result:=Result+GetEnumName(TypeInfo(TProcTypeModifier),Ord(m))
+ end;
+ end;
+begin
+ AssertEquals(Msg,Sn(AExpected),SN(AActual));
+end;
+
+procedure TTestParser.AssertEquals(const Msg: String; AExpected,
AActual: TAssignKind);
begin
AssertEquals(Msg,GetEnumName(TypeInfo(TAssignKind),Ord(AExpected)),
diff --git a/packages/fcl-passrc/tests/tcprocfunc.pas b/packages/fcl-passrc/tests/tcprocfunc.pas
index db37a12ce4..1fb053c159 100644
--- a/packages/fcl-passrc/tests/tcprocfunc.pas
+++ b/packages/fcl-passrc/tests/tcprocfunc.pas
@@ -24,8 +24,8 @@ type
AValue: String='');
procedure AssertArrayArg(ProcType: TPasProcedureType; AIndex: Integer;
AName: String; AAccess: TArgumentAccess; const ElementTypeName: String);
- procedure AssertFunc(Mods: TProcedureModifiers; CC: TCallingConvention; ArgCount: Integer; P: TPasFunction=nil);
- procedure AssertProc(Mods: TProcedureModifiers; CC: TCallingConvention; ArgCount: Integer; P: TPasProcedure=nil);
+ procedure AssertFunc(const Mods: TProcedureModifiers; const TypeMods: TProcTypeModifiers; CC: TCallingConvention; ArgCount: Integer; P: TPasFunction=nil);
+ procedure AssertProc(const Mods: TProcedureModifiers; const TypeMods: TProcTypeModifiers; CC: TCallingConvention; ArgCount: Integer; P: TPasProcedure=nil);
function BaseAssertArg(ProcType: TPasProcedureType; AIndex: Integer;
AName: String; AAccess: TArgumentAccess; AValue: String=''): TPasArgument;
procedure CreateForwardTest;
@@ -269,13 +269,16 @@ begin
CheckHint(TPasMemberHint(Getenumvalue(typeinfo(TPasMemberHint),'h'+Hint)));
end;
-procedure TTestProcedureFunction.AssertProc(Mods : TProcedureModifiers; CC : TCallingConvention; ArgCount : Integer; P : TPasProcedure = Nil);
+procedure TTestProcedureFunction.AssertProc(const Mods: TProcedureModifiers;
+ const TypeMods: TProcTypeModifiers; CC: TCallingConvention; ArgCount: Integer;
+ P: TPasProcedure);
begin
If P=Nil then
P:=Proc;
AssertNotNull('No proc to assert',P);
AssertEquals('Procedure modifiers',Mods,P.Modifiers);
+ AssertEquals('Procedure type modifiers',TypeMods,P.ProcType.Modifiers);
AssertEquals('Procedue calling convention',CC,P.CallingConvention);
AssertEquals('No message name','',p.MessageName);
AssertEquals('No message type',pmtNone,P.MessageType);
@@ -285,13 +288,16 @@ begin
AssertEquals('Not is nested',False,P.ProcType.IsNested);
end;
-procedure TTestProcedureFunction.AssertFunc(Mods : TProcedureModifiers; CC : TCallingConvention; ArgCount : Integer; P : TPasFunction = Nil);
+procedure TTestProcedureFunction.AssertFunc(const Mods: TProcedureModifiers;
+ const TypeMods: TProcTypeModifiers; CC: TCallingConvention; ArgCount: Integer;
+ P: TPasFunction);
begin
If P=Nil then
P:=Func;
AssertNotNull('No func to assert',P);
AssertEquals('Procedure modifiers',Mods,P.Modifiers);
+ AssertEquals('Procedure type modifiers',TypeMods,P.ProcType.Modifiers);
AssertEquals('Procedue calling convention',CC,P.CallingConvention);
AssertEquals('No message name','',p.MessageName);
AssertEquals('No message type',pmtNone,P.MessageType);
@@ -384,7 +390,7 @@ end;
procedure TTestProcedureFunction.TestEmptyProcedure;
begin
ParseProcedure('');
- AssertProc([],ccDefault,0);
+ AssertProc([],[],ccDefault,0);
end;
procedure TTestProcedureFunction.TestEmptyProcedureComment;
@@ -396,7 +402,7 @@ end;
procedure TTestProcedureFunction.TestEmptyFunction;
begin
ParseFunction('');
- AssertFunc([],ccDefault,0);
+ AssertFunc([],[],ccDefault,0);
end;
procedure TTestProcedureFunction.TestEmptyFunctionComment;
@@ -408,50 +414,49 @@ end;
procedure TTestProcedureFunction.TestEmptyProcedureDeprecated;
begin
ParseProcedure('','deprecated');
- AssertProc([],ccDefault,0);
+ AssertProc([],[],ccDefault,0);
end;
procedure TTestProcedureFunction.TestEmptyFunctionDeprecated;
begin
ParseFunction('','deprecated');
- AssertFunc([],ccDefault,0);
+ AssertFunc([],[],ccDefault,0);
end;
procedure TTestProcedureFunction.TestEmptyProcedurePlatform;
begin
ParseProcedure('','platform');
- AssertProc([],ccDefault,0);
+ AssertProc([],[],ccDefault,0);
end;
procedure TTestProcedureFunction.TestEmptyFunctionPlatform;
begin
ParseFunction('','platform');
- AssertFunc([],ccDefault,0);
+ AssertFunc([],[],ccDefault,0);
end;
procedure TTestProcedureFunction.TestEmptyProcedureExperimental;
begin
ParseProcedure('','experimental');
- AssertProc([],ccDefault,0);
+ AssertProc([],[],ccDefault,0);
end;
procedure TTestProcedureFunction.TestEmptyFunctionExperimental;
begin
ParseFunction('','experimental');
- AssertFunc([],ccDefault,0);
+ AssertFunc([],[],ccDefault,0);
end;
procedure TTestProcedureFunction.TestEmptyProcedureUnimplemented;
begin
ParseProcedure('','unimplemented');
- AssertProc([],ccDefault,0);
+ AssertProc([],[],ccDefault,0);
end;
procedure TTestProcedureFunction.TestEmptyFunctionUnimplemented;
begin
ParseFunction('','unimplemented');
- AssertFunc([],ccDefault,0);
-
+ AssertFunc([],[],ccDefault,0);
end;
@@ -459,77 +464,77 @@ end;
procedure TTestProcedureFunction.TestProcedureOneArg;
begin
ParseProcedure('(B : Integer)');
- AssertProc([],ccDefault,1);
+ AssertProc([],[],ccDefault,1);
AssertArg(ProcType,0,'B',argDefault,'Integer','');
end;
procedure TTestProcedureFunction.TestFunctionOneArg;
begin
ParseFunction('(B : Integer)');
- AssertFunc([],ccDefault,1);
+ AssertFunc([],[],ccDefault,1);
AssertArg(FuncType,0,'B',argDefault,'Integer','');
end;
procedure TTestProcedureFunction.TestProcedureOneVarArg;
begin
ParseProcedure('(Var B : Integer)');
- AssertProc([],ccDefault,1);
+ AssertProc([],[],ccDefault,1);
AssertArg(ProcType,0,'B',argVar,'Integer','');
end;
procedure TTestProcedureFunction.TestFunctionOneVarArg;
begin
ParseFunction('(Var B : Integer)');
- AssertFunc([],ccDefault,1);
+ AssertFunc([],[],ccDefault,1);
AssertArg(FuncType,0,'B',argVar,'Integer','');
end;
procedure TTestProcedureFunction.TestProcedureOneConstArg;
begin
ParseProcedure('(Const B : Integer)');
- AssertProc([],ccDefault,1);
+ AssertProc([],[],ccDefault,1);
AssertArg(ProcType,0,'B',argConst,'Integer','');
end;
procedure TTestProcedureFunction.TestFunctionOneConstArg;
begin
ParseFunction('(Const B : Integer)');
- AssertFunc([],ccDefault,1);
+ AssertFunc([],[],ccDefault,1);
AssertArg(FuncType,0,'B',argConst,'Integer','');
end;
procedure TTestProcedureFunction.TestProcedureOneOutArg;
begin
ParseProcedure('(Out B : Integer)');
- AssertProc([],ccDefault,1);
+ AssertProc([],[],ccDefault,1);
AssertArg(ProcType,0,'B',argOut,'Integer','');
end;
procedure TTestProcedureFunction.TestFunctionOneOutArg;
begin
ParseFunction('(Out B : Integer)');
- AssertFunc([],ccDefault,1);
+ AssertFunc([],[],ccDefault,1);
AssertArg(FuncType,0,'B',argOut,'Integer','');
end;
procedure TTestProcedureFunction.TestProcedureOneConstRefArg;
begin
ParseProcedure('(Constref B : Integer)');
- AssertProc([],ccDefault,1);
+ AssertProc([],[],ccDefault,1);
AssertArg(ProcType,0,'B',argConstRef,'Integer','');
end;
procedure TTestProcedureFunction.TestFunctionOneConstRefArg;
begin
ParseFunction('(ConstRef B : Integer)');
- AssertFunc([],ccDefault,1);
+ AssertFunc([],[],ccDefault,1);
AssertArg(FuncType,0,'B',argConstref,'Integer','');
end;
procedure TTestProcedureFunction.TestProcedureTwoArgs;
begin
ParseProcedure('(B,C : Integer)');
- AssertProc([],ccDefault,2);
+ AssertProc([],[],ccDefault,2);
AssertArg(ProcType,0,'B',argDefault,'Integer','');
AssertArg(ProcType,1,'C',argDefault,'Integer','');
end;
@@ -537,7 +542,7 @@ end;
procedure TTestProcedureFunction.TestFunctionTwoArgs;
begin
ParseFunction('(B,C : Integer)');
- AssertFunc([],ccDefault,2);
+ AssertFunc([],[],ccDefault,2);
AssertArg(FuncType,0,'B',argDefault,'Integer','');
AssertArg(FuncType,1,'C',argDefault,'Integer','');
end;
@@ -545,7 +550,7 @@ end;
procedure TTestProcedureFunction.TestProcedureTwoArgsSeparate;
begin
ParseProcedure('(B : Integer; C : Integer)');
- AssertProc([],ccDefault,2);
+ AssertProc([],[],ccDefault,2);
AssertArg(ProcType,0,'B',argDefault,'Integer','');
AssertArg(ProcType,1,'C',argDefault,'Integer','');
end;
@@ -553,7 +558,7 @@ end;
procedure TTestProcedureFunction.TestFunctionTwoArgsSeparate;
begin
ParseFunction('(B : Integer;C : Integer)');
- AssertFunc([],ccDefault,2);
+ AssertFunc([],[],ccDefault,2);
AssertArg(FuncType,0,'B',argDefault,'Integer','');
AssertArg(FuncType,1,'C',argDefault,'Integer','');
end;
@@ -561,56 +566,56 @@ end;
procedure TTestProcedureFunction.TestProcedureOneArgDefault;
begin
ParseProcedure('(B : Integer = 1)');
- AssertProc([],ccDefault,1);
+ AssertProc([],[],ccDefault,1);
AssertArg(ProcType,0,'B',argDefault,'Integer','1');
end;
procedure TTestProcedureFunction.TestFunctionOneArgDefault;
begin
ParseFunction('(B : Integer = 1)');
- AssertFunc([],ccDefault,1);
+ AssertFunc([],[],ccDefault,1);
AssertArg(FuncType,0,'B',argDefault,'Integer','1');
end;
procedure TTestProcedureFunction.TestFunctionOneArgEnumeratedExplicit;
begin
ParseFunction('(B : TSomeEnum = TSomeEnum.False)');
- AssertFunc([],ccDefault,1);
+ AssertFunc([],[],ccDefault,1);
AssertArg(FuncType,0,'B',argDefault,'TSomeEnum','TSomeEnum.False');
end;
procedure TTestProcedureFunction.TestProcedureOneArgDefaultSet;
begin
ParseProcedure('(B : MySet = [1,2])');
- AssertProc([],ccDefault,1);
+ AssertProc([],[],ccDefault,1);
AssertArg(ProcType,0,'B',argDefault,'MySet','[1, 2]');
end;
procedure TTestProcedureFunction.TestFunctionOneArgDefaultSet;
begin
ParseFunction('(B : MySet = [1,2])');
- AssertFunc([],ccDefault,1);
+ AssertFunc([],[],ccDefault,1);
AssertArg(FuncType,0,'B',argDefault,'MySet','[1, 2]');
end;
procedure TTestProcedureFunction.TestProcedureOneArgDefaultExpr;
begin
ParseProcedure('(B : Integer = 1 + 2)');
- AssertProc([],ccDefault,1);
+ AssertProc([],[],ccDefault,1);
AssertArg(ProcType,0,'B',argDefault,'Integer','1 + 2');
end;
procedure TTestProcedureFunction.TestFunctionOneArgDefaultExpr;
begin
ParseFunction('(B : Integer = 1 + 2)');
- AssertFunc([],ccDefault,1);
+ AssertFunc([],[],ccDefault,1);
AssertArg(FuncType,0,'B',argDefault,'Integer','1 + 2');
end;
procedure TTestProcedureFunction.TestProcedureTwoArgsDefault;
begin
ParseProcedure('(B : Integer = 1; C : Integer = 2)');
- AssertProc([],ccDefault,2);
+ AssertProc([],[],ccDefault,2);
AssertArg(ProcType,0,'B',argDefault,'Integer','1');
AssertArg(ProcType,1,'C',argDefault,'Integer','2');
end;
@@ -618,7 +623,7 @@ end;
procedure TTestProcedureFunction.TestFunctionTwoArgsDefault;
begin
ParseFunction('(B : Integer = 1; C : Integer = 2)');
- AssertFunc([],ccDefault,2);
+ AssertFunc([],[],ccDefault,2);
AssertArg(FuncType,0,'B',argDefault,'Integer','1');
AssertArg(FuncType,1,'C',argDefault,'Integer','2');
end;
@@ -626,21 +631,21 @@ end;
procedure TTestProcedureFunction.TestProcedureOneUntypedVarArg;
begin
ParseProcedure('(Var B)');
- AssertProc([],ccDefault,1);
+ AssertProc([],[],ccDefault,1);
AssertArg(ProcType,0,'B',argVar,'','');
end;
procedure TTestProcedureFunction.TestFunctionOneUntypedVarArg;
begin
ParseFunction('(Var B)');
- AssertFunc([],ccDefault,1);
+ AssertFunc([],[],ccDefault,1);
AssertArg(FuncType,0,'B',argVar,'','');
end;
procedure TTestProcedureFunction.TestProcedureTwoUntypedVarArgs;
begin
ParseProcedure('(Var B; Var C)');
- AssertProc([],ccDefault,2);
+ AssertProc([],[],ccDefault,2);
AssertArg(ProcType,0,'B',argVar,'','');
AssertArg(ProcType,1,'C',argVar,'','');
end;
@@ -648,7 +653,7 @@ end;
procedure TTestProcedureFunction.TestFunctionTwoUntypedVarArgs;
begin
ParseFunction('(Var B; Var C)');
- AssertFunc([],ccDefault,2);
+ AssertFunc([],[],ccDefault,2);
AssertArg(FuncType,0,'B',argVar,'','');
AssertArg(FuncType,1,'C',argVar,'','');
end;
@@ -656,21 +661,21 @@ end;
procedure TTestProcedureFunction.TestProcedureOneUntypedConstArg;
begin
ParseProcedure('(Const B)');
- AssertProc([],ccDefault,1);
+ AssertProc([],[],ccDefault,1);
AssertArg(ProcType,0,'B',argConst,'','');
end;
procedure TTestProcedureFunction.TestFunctionOneUntypedConstArg;
begin
ParseFunction('(Const B)');
- AssertFunc([],ccDefault,1);
+ AssertFunc([],[],ccDefault,1);
AssertArg(FuncType,0,'B',argConst,'','');
end;
procedure TTestProcedureFunction.TestProcedureTwoUntypedConstArgs;
begin
ParseProcedure('(Const B; Const C)');
- AssertProc([],ccDefault,2);
+ AssertProc([],[],ccDefault,2);
AssertArg(ProcType,0,'B',argConst,'','');
AssertArg(ProcType,1,'C',argConst,'','');
end;
@@ -678,7 +683,7 @@ end;
procedure TTestProcedureFunction.TestFunctionTwoUntypedConstArgs;
begin
ParseFunction('(Const B; Const C)');
- AssertFunc([],ccDefault,2);
+ AssertFunc([],[],ccDefault,2);
AssertArg(FuncType,0,'B',argConst,'','');
AssertArg(FuncType,1,'C',argConst,'','');
end;
@@ -686,21 +691,21 @@ end;
procedure TTestProcedureFunction.TestProcedureOpenArrayArg;
begin
ParseProcedure('(B : Array of Integer)');
- AssertProc([],ccDefault,1);
+ AssertProc([],[],ccDefault,1);
AssertArrayArg(ProcType,0,'B',argDefault,'Integer');
end;
procedure TTestProcedureFunction.TestFunctionOpenArrayArg;
begin
ParseFunction('(B : Array of Integer)');
- AssertFunc([],ccDefault,1);
+ AssertFunc([],[],ccDefault,1);
AssertArrayArg(FuncType,0,'B',argDefault,'Integer');
end;
procedure TTestProcedureFunction.TestProcedureTwoOpenArrayArgs;
begin
ParseProcedure('(B : Array of Integer;C : Array of Integer)');
- AssertProc([],ccDefault,2);
+ AssertProc([],[],ccDefault,2);
AssertArrayArg(ProcType,0,'B',argDefault,'Integer');
AssertArrayArg(ProcType,1,'C',argDefault,'Integer');
end;
@@ -708,7 +713,7 @@ end;
procedure TTestProcedureFunction.TestFunctionTwoOpenArrayArgs;
begin
ParseFunction('(B : Array of Integer;C : Array of Integer)');
- AssertFunc([],ccDefault,2);
+ AssertFunc([],[],ccDefault,2);
AssertArrayArg(FuncType,0,'B',argDefault,'Integer');
AssertArrayArg(FuncType,1,'C',argDefault,'Integer');
end;
@@ -716,142 +721,142 @@ end;
procedure TTestProcedureFunction.TestProcedureConstOpenArrayArg;
begin
ParseProcedure('(Const B : Array of Integer)');
- AssertProc([],ccDefault,1);
+ AssertProc([],[],ccDefault,1);
AssertArrayArg(ProcType,0,'B',argConst,'Integer');
end;
procedure TTestProcedureFunction.TestFunctionConstOpenArrayArg;
begin
ParseFunction('(Const B : Array of Integer)');
- AssertFunc([],ccDefault,1);
+ AssertFunc([],[],ccDefault,1);
AssertArrayArg(FuncType,0,'B',argConst,'Integer');
end;
procedure TTestProcedureFunction.TestProcedureVarOpenArrayArg;
begin
ParseProcedure('(Var B : Array of Integer)');
- AssertProc([],ccDefault,1);
+ AssertProc([],[],ccDefault,1);
AssertArrayArg(ProcType,0,'B',argVar,'Integer');
end;
procedure TTestProcedureFunction.TestFunctionVarOpenArrayArg;
begin
ParseFunction('(Var B : Array of Integer)');
- AssertFunc([],ccDefault,1);
+ AssertFunc([],[],ccDefault,1);
AssertArrayArg(FuncType,0,'B',argVar,'Integer');
end;
procedure TTestProcedureFunction.TestProcedureArrayOfConstArg;
begin
ParseProcedure('(B : Array of Const)');
- AssertProc([],ccDefault,1);
+ AssertProc([],[],ccDefault,1);
AssertArrayArg(ProcType,0,'B',argDefault,'');
end;
procedure TTestProcedureFunction.TestFunctionArrayOfConstArg;
begin
ParseFunction('(B : Array of Const)');
- AssertFunc([],ccDefault,1);
+ AssertFunc([],[],ccDefault,1);
AssertArrayArg(FuncType,0,'B',argDefault,'');
end;
procedure TTestProcedureFunction.TestProcedureConstArrayOfConstArg;
begin
ParseProcedure('(Const B : Array of Const)');
- AssertProc([],ccDefault,1);
+ AssertProc([],[],ccDefault,1);
AssertArrayArg(ProcType,0,'B',argConst,'');
end;
procedure TTestProcedureFunction.TestFunctionConstArrayOfConstArg;
begin
ParseFunction('(Const B : Array of Const)');
- AssertFunc([],ccDefault,1);
+ AssertFunc([],[],ccDefault,1);
AssertArrayArg(FuncType,0,'B',argConst,'');
end;
procedure TTestProcedureFunction.TestProcedureCdecl;
begin
ParseProcedure('; cdecl');
- AssertProc([],ccCdecl,0);
+ AssertProc([],[],ccCdecl,0);
end;
procedure TTestProcedureFunction.TestFunctionCdecl;
begin
ParseFunction('','','',ccCdecl);
- AssertFunc([],ccCdecl,0);
+ AssertFunc([],[],ccCdecl,0);
end;
procedure TTestProcedureFunction.TestProcedureCdeclDeprecated;
begin
ParseProcedure('; cdecl;','deprecated');
- AssertProc([],ccCdecl,0);
+ AssertProc([],[],ccCdecl,0);
end;
procedure TTestProcedureFunction.TestFunctionCdeclDeprecated;
begin
ParseFunction('','','deprecated',ccCdecl);
- AssertFunc([],ccCdecl,0);
+ AssertFunc([],[],ccCdecl,0);
end;
procedure TTestProcedureFunction.TestProcedureSafeCall;
begin
ParseProcedure('; safecall;','');
- AssertProc([],ccSafeCall,0);
+ AssertProc([],[],ccSafeCall,0);
end;
procedure TTestProcedureFunction.TestFunctionSafeCall;
begin
ParseFunction('','','',ccSafecall);
- AssertFunc([],ccSafecall,0);
+ AssertFunc([],[],ccSafecall,0);
end;
procedure TTestProcedureFunction.TestProcedurePascal;
begin
ParseProcedure('; pascal;','');
- AssertProc([],ccPascal,0);
+ AssertProc([],[],ccPascal,0);
end;
procedure TTestProcedureFunction.TestFunctionPascal;
begin
ParseFunction('','','',ccPascal);
- AssertFunc([],ccPascal,0);
+ AssertFunc([],[],ccPascal,0);
end;
procedure TTestProcedureFunction.TestProcedureStdCall;
begin
ParseProcedure('; stdcall;','');
- AssertProc([],ccstdcall,0);
+ AssertProc([],[],ccstdcall,0);
end;
procedure TTestProcedureFunction.TestFunctionStdCall;
begin
ParseFunction('','','',ccStdCall);
- AssertFunc([],ccStdCall,0);
+ AssertFunc([],[],ccStdCall,0);
end;
procedure TTestProcedureFunction.TestProcedureOldFPCCall;
begin
ParseProcedure('; oldfpccall;','');
- AssertProc([],ccoldfpccall,0);
+ AssertProc([],[],ccoldfpccall,0);
end;
procedure TTestProcedureFunction.TestFunctionOldFPCCall;
begin
ParseFunction('','','',ccOldFPCCall);
- AssertFunc([],ccOldFPCCall,0);
+ AssertFunc([],[],ccOldFPCCall,0);
end;
procedure TTestProcedureFunction.TestProcedurePublic;
begin
ParseProcedure('; public name ''myfunc'';','');
- AssertProc([pmPublic],ccDefault,0);
+ AssertProc([pmPublic],[],ccDefault,0);
AssertExpression('Public name',Proc.PublicName,pekString,'''myfunc''');
end;
procedure TTestProcedureFunction.TestProcedurePublicIdent;
begin
ParseProcedure('; public name exportname;','');
- AssertProc([pmPublic],ccDefault,0);
+ AssertProc([pmPublic],[],ccDefault,0);
AssertExpression('Public name',Proc.PublicName,pekIdent,'exportname');
end;
@@ -859,14 +864,14 @@ procedure TTestProcedureFunction.TestFunctionPublic;
begin
AddDeclaration('function A : Integer; public name exportname');
ParseFunction;
- AssertFunc([pmPublic],ccDefault,0);
+ AssertFunc([pmPublic],[],ccDefault,0);
AssertExpression('Public name',Func.PublicName,pekIdent,'exportname');
end;
procedure TTestProcedureFunction.TestProcedureCdeclPublic;
begin
ParseProcedure('; cdecl; public name exportname;','');
- AssertProc([pmPublic],ccCDecl,0);
+ AssertProc([pmPublic],[],ccCDecl,0);
AssertExpression('Public name',Proc.PublicName,pekIdent,'exportname');
end;
@@ -874,47 +879,47 @@ procedure TTestProcedureFunction.TestFunctionCdeclPublic;
begin
AddDeclaration('function A : Integer; cdecl; public name exportname');
ParseFunction;
- AssertFunc([pmPublic],ccCDecl,0);
+ AssertFunc([pmPublic],[],ccCDecl,0);
AssertExpression('Public name',Func.PublicName,pekIdent,'exportname');
end;
procedure TTestProcedureFunction.TestProcedureOverload;
begin
ParseProcedure('; overload;','');
- AssertProc([pmOverload],ccDefault,0);
+ AssertProc([pmOverload],[],ccDefault,0);
end;
procedure TTestProcedureFunction.TestFunctionOverload;
begin
AddDeclaration('function A : Integer; overload');
ParseFunction;
- AssertFunc([pmOverload],ccDefault,0);
+ AssertFunc([pmOverload],[],ccDefault,0);
end;
procedure TTestProcedureFunction.TestProcedureVarargs;
begin
ParseProcedure('; varargs;','');
- AssertProc([pmVarArgs],ccDefault,0);
+ AssertProc([],[ptmVarArgs],ccDefault,0);
end;
procedure TTestProcedureFunction.TestFunctionVarArgs;
begin
AddDeclaration('function A : Integer; varargs');
ParseFunction;
- AssertFunc([pmVarArgs],ccDefault,0);
+ AssertFunc([],[ptmVarArgs],ccDefault,0);
end;
procedure TTestProcedureFunction.TestProcedureCDeclVarargs;
begin
ParseProcedure(';cdecl; varargs;','');
- AssertProc([pmVarArgs],ccCDecl,0);
+ AssertProc([],[ptmVarArgs],ccCDecl,0);
end;
procedure TTestProcedureFunction.TestFunctionCDeclVarArgs;
begin
AddDeclaration('function A : Integer; cdecl; varargs');
ParseFunction;
- AssertFunc([pmVarArgs],ccCdecl,0);
+ AssertFunc([],[ptmVarArgs],ccCdecl,0);
end;
procedure TTestProcedureFunction.TestProcedureForwardInterface;
@@ -934,7 +939,7 @@ begin
UseImplementation:=True;
AddDeclaration('procedure A; forward;');
ParseProcedure;
- AssertProc([pmforward],ccDefault,0);
+ AssertProc([pmforward],[],ccDefault,0);
end;
procedure TTestProcedureFunction.TestFunctionForward;
@@ -942,21 +947,21 @@ begin
UseImplementation:=True;
AddDeclaration('function A : integer; forward;');
ParseFunction;
- AssertFunc([pmforward],ccDefault,0);
+ AssertFunc([pmforward],[],ccDefault,0);
end;
procedure TTestProcedureFunction.TestProcedureFar;
begin
AddDeclaration('procedure A; far;');
ParseProcedure;
- AssertProc([pmfar],ccDefault,0);
+ AssertProc([pmfar],[],ccDefault,0);
end;
procedure TTestProcedureFunction.TestFunctionFar;
begin
AddDeclaration('function A : integer; far;');
ParseFunction;
- AssertFunc([pmfar],ccDefault,0);
+ AssertFunc([pmfar],[],ccDefault,0);
end;
procedure TTestProcedureFunction.TestProcedureCdeclForward;
@@ -964,7 +969,7 @@ begin
UseImplementation:=True;
AddDeclaration('procedure A; cdecl; forward;');
ParseProcedure;
- AssertProc([pmforward],ccCDecl,0);
+ AssertProc([pmforward],[],ccCDecl,0);
end;
procedure TTestProcedureFunction.TestFunctionCDeclForward;
@@ -972,97 +977,97 @@ begin
UseImplementation:=True;
AddDeclaration('function A : integer; cdecl; forward;');
ParseFunction;
- AssertFunc([pmforward],ccCDecl,0);
+ AssertFunc([pmforward],[],ccCDecl,0);
end;
procedure TTestProcedureFunction.TestProcedureCompilerProc;
begin
ParseProcedure(';compilerproc;','');
- AssertProc([pmCompilerProc],ccDefault,0);
+ AssertProc([pmCompilerProc],[],ccDefault,0);
end;
procedure TTestProcedureFunction.TestProcedureNoReturn;
begin
ParseProcedure(';noreturn;','');
- AssertProc([pmnoreturn],ccDefault,0);
+ AssertProc([pmnoreturn],[],ccDefault,0);
end;
procedure TTestProcedureFunction.TestFunctionCompilerProc;
begin
AddDeclaration('function A : Integer; compilerproc');
ParseFunction;
- AssertFunc([pmCompilerProc],ccDefault,0);
+ AssertFunc([pmCompilerProc],[],ccDefault,0);
end;
procedure TTestProcedureFunction.TestProcedureCDeclCompilerProc;
begin
ParseProcedure(';cdecl;compilerproc;','');
- AssertProc([pmCompilerProc],ccCDecl,0);
+ AssertProc([pmCompilerProc],[],ccCDecl,0);
end;
procedure TTestProcedureFunction.TestFunctionCDeclCompilerProc;
begin
AddDeclaration('function A : Integer; cdecl; compilerproc');
ParseFunction;
- AssertFunc([pmCompilerProc],ccCDecl,0);
+ AssertFunc([pmCompilerProc],[],ccCDecl,0);
end;
procedure TTestProcedureFunction.TestProcedureAssembler;
begin
ParseProcedure(';assembler;','');
- AssertProc([pmAssembler],ccDefault,0);
+ AssertProc([pmAssembler],[],ccDefault,0);
end;
procedure TTestProcedureFunction.TestFunctionAssembler;
begin
AddDeclaration('function A : Integer; assembler');
ParseFunction;
- AssertFunc([pmAssembler],ccDefault,0);
+ AssertFunc([pmAssembler],[],ccDefault,0);
end;
procedure TTestProcedureFunction.TestProcedureCDeclAssembler;
begin
ParseProcedure(';cdecl;assembler;','');
- AssertProc([pmAssembler],ccCDecl,0);
+ AssertProc([pmAssembler],[],ccCDecl,0);
end;
procedure TTestProcedureFunction.TestFunctionCDeclAssembler;
begin
AddDeclaration('function A : Integer; cdecl; assembler');
ParseFunction;
- AssertFunc([pmAssembler],ccCDecl,0);
+ AssertFunc([pmAssembler],[],ccCDecl,0);
end;
procedure TTestProcedureFunction.TestProcedureExport;
begin
ParseProcedure(';export;','');
- AssertProc([pmExport],ccDefault,0);
+ AssertProc([pmExport],[],ccDefault,0);
end;
procedure TTestProcedureFunction.TestFunctionExport;
begin
AddDeclaration('function A : Integer; export');
ParseFunction;
- AssertFunc([pmExport],ccDefault,0);
+ AssertFunc([pmExport],[],ccDefault,0);
end;
procedure TTestProcedureFunction.TestProcedureCDeclExport;
begin
ParseProcedure('cdecl;export;','');
- AssertProc([pmExport],ccCDecl,0);
+ AssertProc([pmExport],[],ccCDecl,0);
end;
procedure TTestProcedureFunction.TestFunctionCDeclExport;
begin
AddDeclaration('function A : Integer; cdecl; export');
ParseFunction;
- AssertFunc([pmExport],ccCDecl,0);
+ AssertFunc([pmExport],[],ccCDecl,0);
end;
procedure TTestProcedureFunction.TestProcedureExternal;
begin
ParseProcedure(';external','');
- AssertProc([pmExternal],ccDefault,0);
+ AssertProc([pmExternal],[],ccDefault,0);
AssertNull('No Library name expression',Proc.LibraryExpr);
end;
@@ -1070,7 +1075,7 @@ procedure TTestProcedureFunction.TestFunctionExternal;
begin
AddDeclaration('function A : Integer; external');
ParseFunction;
- AssertFunc([pmExternal],ccDefault,0);
+ AssertFunc([pmExternal],[],ccDefault,0);
AssertNull('No Library name expression',Func.LibraryExpr);
end;
@@ -1110,7 +1115,7 @@ end;
procedure TTestProcedureFunction.TestProcedureExternalLibName;
begin
ParseProcedure(';external ''libname''','');
- AssertProc([pmExternal],ccDefault,0);
+ AssertProc([pmExternal],[],ccDefault,0);
AssertExpression('Library name expression',Proc.LibraryExpr,pekString,'''libname''');
end;
@@ -1118,14 +1123,14 @@ procedure TTestProcedureFunction.TestFunctionExternalLibName;
begin
AddDeclaration('function A : Integer; external ''libname''');
ParseFunction;
- AssertFunc([pmExternal],ccDefault,0);
+ AssertFunc([pmExternal],[],ccDefault,0);
AssertExpression('Library name expression',Func.LibraryExpr,pekString,'''libname''');
end;
procedure TTestProcedureFunction.TestProcedureExternalLibNameName;
begin
ParseProcedure(';external ''libname'' name ''symbolname''','');
- AssertProc([pmExternal],ccDefault,0);
+ AssertProc([pmExternal],[],ccDefault,0);
AssertExpression('Library name expression',Proc.LibraryExpr,pekString,'''libname''');
AssertExpression('Library symbol expression',Proc.LibrarySymbolName,pekString,'''symbolname''');
end;
@@ -1134,7 +1139,7 @@ procedure TTestProcedureFunction.TestFunctionExternalLibNameName;
begin
AddDeclaration('function A : Integer; external ''libname'' name ''symbolname''');
ParseFunction;
- AssertFunc([pmExternal],ccDefault,0);
+ AssertFunc([pmExternal],[],ccDefault,0);
AssertExpression('Library name expression',Func.LibraryExpr,pekString,'''libname''');
AssertExpression('Library symbol expression',Func.LibrarySymbolName,pekString,'''symbolname''');
end;
@@ -1142,7 +1147,7 @@ end;
procedure TTestProcedureFunction.TestProcedureExternalName;
begin
ParseProcedure(';external name ''symbolname''','');
- AssertProc([pmExternal],ccDefault,0);
+ AssertProc([pmExternal],[],ccDefault,0);
AssertNull('No Library name expression',Proc.LibraryExpr);
AssertExpression('Library symbol expression',Proc.LibrarySymbolName,pekString,'''symbolname''');
end;
@@ -1151,7 +1156,7 @@ procedure TTestProcedureFunction.TestFunctionExternalName;
begin
AddDeclaration('function A : Integer; external name ''symbolname''');
ParseFunction;
- AssertFunc([pmExternal],ccDefault,0);
+ AssertFunc([pmExternal],[],ccDefault,0);
AssertNull('No Library name expression',Func.LibraryExpr);
AssertExpression('Library symbol expression',Func.LibrarySymbolName,pekString,'''symbolname''');
end;
@@ -1159,7 +1164,7 @@ end;
procedure TTestProcedureFunction.TestProcedureCdeclExternal;
begin
ParseProcedure('; cdecl; external','');
- AssertProc([pmExternal],ccCdecl,0);
+ AssertProc([pmExternal],[],ccCdecl,0);
AssertNull('No Library name expression',Proc.LibraryExpr);
end;
@@ -1167,14 +1172,14 @@ procedure TTestProcedureFunction.TestFunctionCdeclExternal;
begin
AddDeclaration('function A : Integer; cdecl; external');
ParseFunction;
- AssertFunc([pmExternal],ccCdecl,0);
+ AssertFunc([pmExternal],[],ccCdecl,0);
AssertNull('No Library name expression',Func.LibraryExpr);
end;
procedure TTestProcedureFunction.TestProcedureCdeclExternalLibName;
begin
ParseProcedure('; cdecl; external ''libname''','');
- AssertProc([pmExternal],ccCdecl,0);
+ AssertProc([pmExternal],[],ccCdecl,0);
AssertExpression('Library name expression',Proc.LibraryExpr,pekString,'''libname''');
end;
@@ -1182,14 +1187,14 @@ procedure TTestProcedureFunction.TestFunctionCdeclExternalLibName;
begin
AddDeclaration('function A : Integer; cdecl; external ''libname''');
ParseFunction;
- AssertFunc([pmExternal],ccCdecl,0);
+ AssertFunc([pmExternal],[],ccCdecl,0);
AssertExpression('Library name expression',Func.LibraryExpr,pekString,'''libname''');
end;
procedure TTestProcedureFunction.TestProcedureCdeclExternalLibNameName;
begin
ParseProcedure('; cdecl; external ''libname'' name ''symbolname''','');
- AssertProc([pmExternal],ccCdecl,0);
+ AssertProc([pmExternal],[],ccCdecl,0);
AssertExpression('Library name expression',Proc.LibraryExpr,pekString,'''libname''');
AssertExpression('Library symbol expression',Proc.LibrarySymbolName,pekString,'''symbolname''');
end;
@@ -1198,7 +1203,7 @@ procedure TTestProcedureFunction.TestFunctionCdeclExternalLibNameName;
begin
AddDeclaration('function A : Integer; cdecl; external ''libname'' name ''symbolname''');
ParseFunction;
- AssertFunc([pmExternal],ccCdecl,0);
+ AssertFunc([pmExternal],[],ccCdecl,0);
AssertExpression('Library name expression',Func.LibraryExpr,pekString,'''libname''');
AssertExpression('Library symbol expression',Func.LibrarySymbolName,pekString,'''symbolname''');
end;
@@ -1206,7 +1211,7 @@ end;
procedure TTestProcedureFunction.TestProcedureCdeclExternalName;
begin
ParseProcedure('; cdecl; external name ''symbolname''','');
- AssertProc([pmExternal],ccCdecl,0);
+ AssertProc([pmExternal],[],ccCdecl,0);
AssertNull('No Library name expression',Proc.LibraryExpr);
AssertExpression('Library symbol expression',Proc.LibrarySymbolName,pekString,'''symbolname''');
end;
@@ -1215,7 +1220,7 @@ procedure TTestProcedureFunction.TestFunctionCdeclExternalName;
begin
AddDeclaration('function A : Integer; cdecl; external name ''symbolname''');
ParseFunction;
- AssertFunc([pmExternal],ccCdecl,0);
+ AssertFunc([pmExternal],[],ccCdecl,0);
AssertNull('No Library name expression',Func.LibraryExpr);
AssertExpression('Library symbol expression',Func.LibrarySymbolName,pekString,'''symbolname''');
end;
@@ -1224,7 +1229,7 @@ procedure TTestProcedureFunction.TestFunctionAlias;
begin
AddDeclaration('function A : Integer; alias: ''myalias''');
ParseFunction;
- AssertFunc([],ccDefault,0);
+ AssertFunc([],[],ccDefault,0);
AssertEquals('Alias name','''myalias''',Func.AliasName);
end;
@@ -1232,7 +1237,7 @@ procedure TTestProcedureFunction.TestProcedureAlias;
begin
AddDeclaration('Procedure A; Alias : ''myalias''');
ParseProcedure;
- AssertProc([],ccDefault,0);
+ AssertProc([],[],ccDefault,0);
AssertEquals('Alias name','''myalias''',Proc.AliasName);
end;
diff --git a/packages/fcl-passrc/tests/tcresolver.pas b/packages/fcl-passrc/tests/tcresolver.pas
index a68b8605ce..9e591e1a57 100644
--- a/packages/fcl-passrc/tests/tcresolver.pas
+++ b/packages/fcl-passrc/tests/tcresolver.pas
@@ -179,12 +179,7 @@ type
Procedure TestTypedConstWrongExprFail;
Procedure TestVarWrongExprFail;
Procedure TestArgWrongExprFail;
- Procedure TestIncDec;
- Procedure TestIncStringFail;
Procedure TestVarExternal;
- Procedure TestStr_BaseTypes;
- Procedure TestStr_StringFail;
- Procedure TestStr_CharFail;
Procedure TestVarNoSemicolonBeginFail;
// strings
@@ -208,8 +203,11 @@ type
Procedure TestEnumHighLow;
Procedure TestEnumOrd;
Procedure TestEnumPredSucc;
+ Procedure TestEnum_EqualNilFail;
Procedure TestEnum_CastIntegerToEnum;
Procedure TestEnum_Str;
+ Procedure TestSet_AnonymousEnumtype;
+ Procedure TestSet_AnonymousEnumtypeName;
// operators
Procedure TestPrgAssignment;
@@ -233,10 +231,18 @@ type
Procedure TestTypeCastDoubleToIntFail;
Procedure TestTypeCastDoubleToBoolFail;
Procedure TestTypeCastBooleanToDoubleFail;
- Procedure TestHighLow;
Procedure TestAssign_Access;
Procedure TestAssignedIntFail;
+ // misc built-in functions
+ Procedure TestHighLow;
+ Procedure TestStr_BaseTypes;
+ Procedure TestStr_StringFail;
+ Procedure TestStr_CharFail;
+ Procedure TestIncDec;
+ Procedure TestIncStringFail;
+ Procedure TestTypeInfo;
+
// statements
Procedure TestForLoop;
Procedure TestStatements;
@@ -305,6 +311,7 @@ type
Procedure TestProc_Varargs;
Procedure TestProc_ParameterExprAccess;
Procedure TestProc_FunctionResult_DeclProc;
+ Procedure TestProc_TypeCastFunctionResult;
// ToDo: fail builtin functions in constant with non const param
// record
@@ -391,7 +398,7 @@ type
// Todo: Fail to use class.method in constant or type, e.g. const p = @o.doit;
// published
- Procedure TestClass_PublishedVarFail;
+ Procedure TestClass_PublishedClassVarFail;
Procedure TestClass_PublishedClassPropertyFail;
Procedure TestClass_PublishedClassFunctionFail;
Procedure TestClass_PublishedOverloadFail;
@@ -439,6 +446,8 @@ type
Procedure TestPropertyWriteAccessorProc;
Procedure TestPropertyTypeless;
Procedure TestPropertyTypelessNoAncestorFail;
+ Procedure TestPropertyStoredAccessor;
+ Procedure TestPropertyStoredAccessorVarWrongType;
Procedure TestPropertyStoredAccessorProcNotFunc;
Procedure TestPropertyStoredAccessorFuncWrongResult;
Procedure TestPropertyStoredAccessorFuncWrongArgCount;
@@ -465,6 +474,7 @@ type
Procedure TestDynArrayOfLongint;
Procedure TestStaticArray;
Procedure TestArrayOfArray;
+ Procedure TestArrayOfArray_NameAnonymous;
Procedure TestFunctionReturningArray;
Procedure TestArray_LowHigh;
Procedure TestArray_AssignSameSignatureFail;
@@ -520,6 +530,14 @@ type
Procedure TestProcType_AsArgOtherUnit;
Procedure TestProcType_Property;
Procedure TestProcType_PropertyCallWrongArgFail;
+ Procedure TestProcType_Typecast;
+
+ // pointer
+ Procedure TestPointer;
+ Procedure TestPointer_AssignPointerToClassFail;
+ Procedure TestPointer_TypecastToMethodTypeFail;
+ Procedure TestPointer_TypecastFromMethodTypeFail;
+ Procedure TestPointer_TypecastMethod_proMethodAddrAsPointer;
end;
function LinesToStr(Args: array of const): string;
@@ -2002,30 +2020,6 @@ begin
PasResolver.nIncompatibleTypesGotExpected);
end;
-procedure TTestResolver.TestIncDec;
-begin
- StartProgram(false);
- Add('var');
- Add(' i: longint;');
- Add('begin');
- Add(' inc({#a_var}i);');
- Add(' inc({#b_var}i,2);');
- Add(' dec({#c_var}i);');
- Add(' dec({#d_var}i,3);');
- ParseProgram;
- CheckAccessMarkers;
-end;
-
-procedure TTestResolver.TestIncStringFail;
-begin
- StartProgram(false);
- Add('var');
- Add(' i: string;');
- Add('begin');
- Add(' inc(i);');
- CheckResolverException('Incompatible type arg no. 1: Got "String", expected "integer"',PasResolver.nIncompatibleTypeArgNo);
-end;
-
procedure TTestResolver.TestVarExternal;
begin
StartProgram(false);
@@ -2035,74 +2029,6 @@ begin
ParseProgram;
end;
-procedure TTestResolver.TestStr_BaseTypes;
-begin
- StartProgram(false);
- Add('var');
- Add(' b: boolean;');
- Add(' i: longint;');
- Add(' i64: int64;');
- Add(' s: single;');
- Add(' d: double;');
- Add(' aString: string;');
- Add(' r: record end;');
- Add('begin');
- Add(' Str(b,{#a_var}aString);');
- Add(' Str(b:1,aString);');
- Add(' Str(b:i,aString);');
- Add(' Str(i,aString);');
- Add(' Str(i:2,aString);');
- Add(' Str(i:i64,aString);');
- Add(' Str(i64,aString);');
- Add(' Str(i64:3,aString);');
- Add(' Str(i64:i,aString);');
- Add(' Str(s,aString);');
- Add(' Str(d,aString);');
- Add(' Str(d:4,aString);');
- Add(' Str(d:4:5,aString);');
- Add(' Str(d:4:i,aString);');
- Add(' aString:=Str(b);');
- Add(' aString:=Str(i:3);');
- Add(' aString:=Str(d:3:4);');
- Add(' aString:=Str(b,i,d);');
- Add(' aString:=Str(s,''foo'');');
- Add(' aString:=Str(i,{#assign_read}aString);');
- Add(' while true do Str(i,{#whiledo_var}aString);');
- Add(' repeat Str(i,{#repeat_var}aString); until true;');
- Add(' if true then Str(i,{#ifthen_var}aString) else Str(i,{#ifelse_var}aString);');
- Add(' for i:=0 to 0 do Str(i,{#fordo_var}aString);');
- Add(' with r do Str(i,{#withdo_var}aString);');
- Add(' case Str(s,''caseexpr'') of');
- Add(' ''bar'': Str(i,{#casest_var}aString);');
- Add(' else Str(i,{#caseelse_var}aString);');
- Add(' end;');
- ParseProgram;
- CheckAccessMarkers;
-end;
-
-procedure TTestResolver.TestStr_StringFail;
-begin
- StartProgram(false);
- Add('var');
- Add(' aString: string;');
- Add('begin');
- Add(' Str(aString,aString);');
- CheckResolverException('Incompatible type arg no. 1: Got "String", expected "boolean, integer, enum value"',
- nIncompatibleTypeArgNo);
-end;
-
-procedure TTestResolver.TestStr_CharFail;
-begin
- StartProgram(false);
- Add('var');
- Add(' c: char;');
- Add(' aString: string;');
- Add('begin');
- Add(' Str(c,aString);');
- CheckResolverException('Incompatible type arg no. 1: Got "Char", expected "boolean, integer, enum value"',
- nIncompatibleTypeArgNo);
-end;
-
procedure TTestResolver.TestVarNoSemicolonBeginFail;
begin
StartProgram(false);
@@ -2447,6 +2373,19 @@ begin
ParseProgram;
end;
+procedure TTestResolver.TestEnum_EqualNilFail;
+begin
+ StartProgram(false);
+ Add('type');
+ Add(' TFlag = (red, green);');
+ Add('var');
+ Add(' f: TFlag;');
+ Add('begin');
+ Add(' if f=nil then ;');
+ CheckResolverException('Incompatible types: got "TFlag" expected "Pointer"',
+ nIncompatibleTypesGotExpected);
+end;
+
procedure TTestResolver.TestEnum_CastIntegerToEnum;
begin
StartProgram(false);
@@ -2479,6 +2418,57 @@ begin
ParseProgram;
end;
+procedure TTestResolver.TestSet_AnonymousEnumtype;
+begin
+ StartProgram(false);
+ Add('type');
+ Add(' TFlags = set of (red, green);');
+ Add('const');
+ Add(' favorite = red;');
+ Add('var');
+ Add(' f: TFlags;');
+ Add(' i: longint;');
+ Add('begin');
+ Add(' Include(f,red);');
+ Add(' Include(f,favorite);');
+ Add(' i:=ord(red);');
+ Add(' i:=ord(favorite);');
+ Add(' i:=ord(low(TFlags));');
+ Add(' i:=ord(low(f));');
+ Add(' i:=ord(low(favorite));');
+ Add(' i:=ord(high(TFlags));');
+ Add(' i:=ord(high(f));');
+ Add(' i:=ord(high(favorite));');
+ Add(' f:=[green,favorite];');
+ ParseProgram;
+end;
+
+procedure TTestResolver.TestSet_AnonymousEnumtypeName;
+begin
+ ResolverEngine.AnonymousElTypePostfix:='$enum';
+ StartProgram(false);
+ Add('type');
+ Add(' TFlags = set of (red, green);');
+ Add('const');
+ Add(' favorite = red;');
+ Add('var');
+ Add(' f: TFlags;');
+ Add(' i: longint;');
+ Add('begin');
+ Add(' Include(f,red);');
+ Add(' Include(f,favorite);');
+ Add(' i:=ord(red);');
+ Add(' i:=ord(favorite);');
+ Add(' i:=ord(low(TFlags));');
+ Add(' i:=ord(low(f));');
+ Add(' i:=ord(low(favorite));');
+ Add(' i:=ord(high(TFlags));');
+ Add(' i:=ord(high(f));');
+ Add(' i:=ord(high(favorite));');
+ Add(' f:=[green,favorite];');
+ ParseProgram;
+end;
+
procedure TTestResolver.TestPrgAssignment;
var
El: TPasElement;
@@ -2947,6 +2937,31 @@ begin
CheckResolverException(sIllegalTypeConversionTo,PasResolver.nIllegalTypeConversionTo);
end;
+procedure TTestResolver.TestAssign_Access;
+begin
+ StartProgram(false);
+ Parser.Options:=Parser.Options+[po_cassignments];
+ Scanner.Options:=Scanner.Options+[po_cassignments];
+ Add('var i: longint;');
+ Add('begin');
+ Add(' {#a1_assign}i:={#a2_read}i;');
+ Add(' {#b1_readandassign}i+={#b2_read}i;');
+ Add(' {#c1_readandassign}i-={#c2_read}i;');
+ Add(' {#d1_readandassign}i*={#d2_read}i;');
+ ParseProgram;
+ CheckAccessMarkers;
+end;
+
+procedure TTestResolver.TestAssignedIntFail;
+begin
+ StartProgram(false);
+ Add('var i: longint;');
+ Add('begin');
+ Add(' if Assigned(i) then ;');
+ CheckResolverException('Incompatible type arg no. 1: Got "Longint", expected "class or array"',
+ nIncompatibleTypeArgNo);
+end;
+
procedure TTestResolver.TestHighLow;
begin
StartProgram(false);
@@ -2961,31 +2976,121 @@ begin
ParseProgram;
end;
-procedure TTestResolver.TestAssign_Access;
+procedure TTestResolver.TestStr_BaseTypes;
begin
StartProgram(false);
- Parser.Options:=Parser.Options+[po_cassignments];
- Scanner.Options:=Scanner.Options+[po_cassignments];
- Add('var i: longint;');
+ Add('var');
+ Add(' b: boolean;');
+ Add(' i: longint;');
+ Add(' i64: int64;');
+ Add(' s: single;');
+ Add(' d: double;');
+ Add(' aString: string;');
+ Add(' r: record end;');
Add('begin');
- Add(' {#a1_assign}i:={#a2_read}i;');
- Add(' {#b1_readandassign}i+={#b2_read}i;');
- Add(' {#c1_readandassign}i-={#c2_read}i;');
- Add(' {#d1_readandassign}i*={#d2_read}i;');
+ Add(' Str(b,{#a_var}aString);');
+ Add(' Str(b:1,aString);');
+ Add(' Str(b:i,aString);');
+ Add(' Str(i,aString);');
+ Add(' Str(i:2,aString);');
+ Add(' Str(i:i64,aString);');
+ Add(' Str(i64,aString);');
+ Add(' Str(i64:3,aString);');
+ Add(' Str(i64:i,aString);');
+ Add(' Str(s,aString);');
+ Add(' Str(d,aString);');
+ Add(' Str(d:4,aString);');
+ Add(' Str(d:4:5,aString);');
+ Add(' Str(d:4:i,aString);');
+ Add(' aString:=Str(b);');
+ Add(' aString:=Str(i:3);');
+ Add(' aString:=Str(d:3:4);');
+ Add(' aString:=Str(b,i,d);');
+ Add(' aString:=Str(s,''foo'');');
+ Add(' aString:=Str(i,{#assign_read}aString);');
+ Add(' while true do Str(i,{#whiledo_var}aString);');
+ Add(' repeat Str(i,{#repeat_var}aString); until true;');
+ Add(' if true then Str(i,{#ifthen_var}aString) else Str(i,{#ifelse_var}aString);');
+ Add(' for i:=0 to 0 do Str(i,{#fordo_var}aString);');
+ Add(' with r do Str(i,{#withdo_var}aString);');
+ Add(' case Str(s,''caseexpr'') of');
+ Add(' ''bar'': Str(i,{#casest_var}aString);');
+ Add(' else Str(i,{#caseelse_var}aString);');
+ Add(' end;');
ParseProgram;
CheckAccessMarkers;
end;
-procedure TTestResolver.TestAssignedIntFail;
+procedure TTestResolver.TestStr_StringFail;
begin
StartProgram(false);
- Add('var i: longint;');
+ Add('var');
+ Add(' aString: string;');
Add('begin');
- Add(' if Assigned(i) then ;');
- CheckResolverException('Incompatible type arg no. 1: Got "Longint", expected "class or array"',
+ Add(' Str(aString,aString);');
+ CheckResolverException('Incompatible type arg no. 1: Got "String", expected "boolean, integer, enum value"',
+ nIncompatibleTypeArgNo);
+end;
+
+procedure TTestResolver.TestStr_CharFail;
+begin
+ StartProgram(false);
+ Add('var');
+ Add(' c: char;');
+ Add(' aString: string;');
+ Add('begin');
+ Add(' Str(c,aString);');
+ CheckResolverException('Incompatible type arg no. 1: Got "Char", expected "boolean, integer, enum value"',
nIncompatibleTypeArgNo);
end;
+procedure TTestResolver.TestIncDec;
+begin
+ StartProgram(false);
+ Add('var');
+ Add(' i: longint;');
+ Add('begin');
+ Add(' inc({#a_var}i);');
+ Add(' inc({#b_var}i,2);');
+ Add(' dec({#c_var}i);');
+ Add(' dec({#d_var}i,3);');
+ ParseProgram;
+ CheckAccessMarkers;
+end;
+
+procedure TTestResolver.TestIncStringFail;
+begin
+ StartProgram(false);
+ Add('var');
+ Add(' i: string;');
+ Add('begin');
+ Add(' inc(i);');
+ CheckResolverException('Incompatible type arg no. 1: Got "String", expected "integer"',PasResolver.nIncompatibleTypeArgNo);
+end;
+
+procedure TTestResolver.TestTypeInfo;
+begin
+ StartProgram(false);
+ Add('type');
+ Add(' integer = longint;');
+ Add(' TRec = record');
+ Add(' v: integer;');
+ Add(' end;');
+ Add('var');
+ Add(' i: integer;');
+ Add(' s: string;');
+ Add(' p: pointer;');
+ Add(' r: TRec;');
+ Add('begin');
+ Add(' p:=typeinfo(integer);');
+ Add(' p:=typeinfo(longint);');
+ Add(' p:=typeinfo(i);');
+ Add(' p:=typeinfo(s);');
+ Add(' p:=typeinfo(p);');
+ Add(' p:=typeinfo(r.v);');
+ ParseProgram;
+end;
+
procedure TTestResolver.TestForLoop;
begin
StartProgram(false);
@@ -4162,6 +4267,16 @@ begin
end;
end;
+procedure TTestResolver.TestProc_TypeCastFunctionResult;
+begin
+ StartProgram(false);
+ Add('function GetIt: longint; begin end;');
+ Add('var s: smallint;');
+ Add('begin');
+ Add(' s:=smallint(GetIt);');
+ ParseProgram;
+end;
+
procedure TTestResolver.TestRecord;
begin
StartProgram(false);
@@ -5211,8 +5326,8 @@ begin
Add(' end;');
Add('begin');
Add(' if TObject.i=7 then ;');
- CheckResolverException(sCannotAccessThisMemberFromAClassReference,
- PasResolver.nCannotAccessThisMemberFromAClassReference);
+ CheckResolverException(sCannotAccessThisMemberFromAX,
+ PasResolver.nCannotAccessThisMemberFromAX);
end;
procedure TTestResolver.TestClass_FuncReturningObjectMember;
@@ -5958,13 +6073,13 @@ begin
ParseProgram;
end;
-procedure TTestResolver.TestClass_PublishedVarFail;
+procedure TTestResolver.TestClass_PublishedClassVarFail;
begin
StartProgram(false);
Add('type');
Add(' TObject = class');
Add(' published');
- Add(' Id: longint;');
+ Add(' class var Id: longint;');
Add(' end;');
Add('begin');
CheckResolverException(sSymbolCannotBePublished,nSymbolCannotBePublished);
@@ -6204,8 +6319,8 @@ begin
Add(' oc: TObjectClass;');
Add('begin');
Add(' oc.Id:=3;');
- CheckResolverException(sCannotAccessThisMemberFromAClassReference,
- PasResolver.nCannotAccessThisMemberFromAClassReference);
+ CheckResolverException(sCannotAccessThisMemberFromAX,
+ PasResolver.nCannotAccessThisMemberFromAX);
end;
procedure TTestResolver.TestClassOfDotClassProc;
@@ -6264,8 +6379,8 @@ begin
Add(' oc: TObjectClass;');
Add('begin');
Add(' oc.ProcA;');
- CheckResolverException(sCannotAccessThisMemberFromAClassReference,
- PasResolver.nCannotAccessThisMemberFromAClassReference);
+ CheckResolverException(sCannotAccessThisMemberFromAX,
+ PasResolver.nCannotAccessThisMemberFromAX);
end;
procedure TTestResolver.TestClassOfDotClassProperty;
@@ -6311,8 +6426,8 @@ begin
Add(' oc: TObjectClass;');
Add('begin');
Add(' if oc.A=3 then ;');
- CheckResolverException(sCannotAccessThisMemberFromAClassReference,
- PasResolver.nCannotAccessThisMemberFromAClassReference);
+ CheckResolverException(sCannotAccessThisMemberFromAX,
+ PasResolver.nCannotAccessThisMemberFromAX);
end;
procedure TTestResolver.TestClass_ClassProcSelf;
@@ -6775,6 +6890,35 @@ begin
PasResolver.nNoPropertyFoundToOverride);
end;
+procedure TTestResolver.TestPropertyStoredAccessor;
+begin
+ StartProgram(false);
+ Add('type');
+ Add(' TObject = class');
+ Add(' FBird: longint;');
+ Add(' VStored: boolean;');
+ Add(' function IsBirdStored: boolean; virtual; abstract;');
+ Add(' property Bird: longint read FBird stored VStored;');
+ Add(' property B: longint read FBird stored IsBirdStored;');
+ Add(' end;');
+ Add('begin');
+ ParseProgram;
+end;
+
+procedure TTestResolver.TestPropertyStoredAccessorVarWrongType;
+begin
+ StartProgram(false);
+ Add('type');
+ Add(' TObject = class');
+ Add(' FB: longint;');
+ Add(' BStored: longint;');
+ Add(' property B: longint read FB stored BStored;');
+ Add(' end;');
+ Add('begin');
+ CheckResolverException('Incompatible types: got "Longint" expected "Boolean"',
+ PasResolver.nIncompatibleTypesGotExpected);
+end;
+
procedure TTestResolver.TestPropertyStoredAccessorProcNotFunc;
begin
StartProgram(false);
@@ -7218,12 +7362,31 @@ begin
Add('type');
Add(' TArrA = array[byte] of longint;');
Add(' TArrB = array[smallint] of TArrA;');
+ Add(' TArrC = array of array of longint;');
Add('var');
Add(' b: TArrB;');
+ Add(' c: TArrC;');
Add('begin');
Add(' b[1][2]:=5;');
Add(' b[1,2]:=5;');
Add(' if b[2,1]=b[0,1] then ;');
+ Add(' c[3][4]:=c[5,6];');
+ ParseProgram;
+end;
+
+procedure TTestResolver.TestArrayOfArray_NameAnonymous;
+begin
+ ResolverEngine.AnonymousElTypePostfix:='$array';
+ StartProgram(false);
+ Add('type');
+ Add(' TArrA = array of array of longint;');
+ Add('var');
+ Add(' a: TArrA;');
+ Add('begin');
+ Add(' a[1][2]:=5;');
+ Add(' a[1,2]:=5;');
+ Add(' if a[2,1]=a[0,1] then ;');
+ Add(' a[3][4]:=a[5,6];');
ParseProgram;
end;
@@ -7979,7 +8142,7 @@ begin
Add('var n: TNotifyEvent;');
Add('begin');
Add(' n:=@ProcA;');
- CheckResolverException('procedure type modifier "of object" mismatch',
+ CheckResolverException('procedure type modifier "of Object" mismatch',
PasResolver.nXModifierMismatchY);
end;
@@ -7998,7 +8161,7 @@ begin
Add(' o: TObject;');
Add('begin');
Add(' n:=@o.ProcA;');
- CheckResolverException('procedure type modifier "of object" mismatch',
+ CheckResolverException('procedure type modifier "of Object" mismatch',
PasResolver.nXModifierMismatchY);
end;
@@ -8173,7 +8336,7 @@ begin
Add('begin');
Add(' Button1.OnClick := App.BtnClickHandler();');
CheckResolverException(
- 'Wrong number of parameters specified for call to "procedure BtnClickHandler(TObject) of object"',
+ 'Wrong number of parameters specified for call to "procedure BtnClickHandler(TObject) of Object"',
nWrongNumberOfParametersForCallTo);
end;
@@ -8197,7 +8360,7 @@ begin
Add('begin');
Add(' Button1.OnClick := @App.BtnClickHandler();');
CheckResolverException(
- 'Wrong number of parameters specified for call to "procedure BtnClickHandler(TObject) of object"',
+ 'Wrong number of parameters specified for call to "procedure BtnClickHandler(TObject) of Object"',
nWrongNumberOfParametersForCallTo);
end;
@@ -8407,6 +8570,122 @@ begin
nIncompatibleTypeArgNo);
end;
+procedure TTestResolver.TestProcType_Typecast;
+begin
+ StartProgram(false);
+ Add('type');
+ Add(' TNotifyEvent = procedure(Sender: Pointer) of object;');
+ Add(' TEvent = procedure of object;');
+ Add(' TProcA = procedure(i: longint);');
+ Add(' TFuncB = function(i, j: longint): longint;');
+ Add('var');
+ Add(' Notify: TNotifyEvent;');
+ Add(' Event: TEvent;');
+ Add(' ProcA: TProcA;');
+ Add(' FuncB: TFuncB;');
+ Add(' p: pointer;');
+ Add('begin');
+ Add(' Notify:=TNotifyEvent(Event);');
+ Add(' Event:=TEvent(Event);');
+ Add(' Event:=TEvent(Notify);');
+ Add(' ProcA:=TProcA(FuncB);');
+ Add(' FuncB:=TFuncB(FuncB);');
+ Add(' FuncB:=TFuncB(ProcA);');
+ Add(' ProcA:=TProcA(p);');
+ Add(' FuncB:=TFuncB(p);');
+ ParseProgram;
+end;
+
+procedure TTestResolver.TestPointer;
+begin
+ StartProgram(false);
+ Add('type');
+ Add(' TObject = class end;');
+ Add(' TClass = class of TObject;');
+ Add(' TMyPtr = pointer;');
+ Add(' TArrInt = array of longint;');
+ Add(' TFunc = function: longint;');
+ Add('procedure DoIt; begin end;');
+ Add('var');
+ Add(' p: TMyPtr;');
+ Add(' Obj: TObject;');
+ Add(' Cl: TClass;');
+ Add(' a: tarrint;');
+ Add(' f: TFunc;');
+ Add('begin');
+ Add(' p:=nil;');
+ Add(' if p=nil then;');
+ Add(' if nil=p then;');
+ Add(' if Assigned(p) then;');
+ Add(' p:=obj;');
+ Add(' p:=cl;');
+ Add(' p:=a;');
+ Add(' p:=Pointer(f);');
+ Add(' p:=@DoIt;');
+ Add(' p:=Pointer(@DoIt)');
+ Add(' obj:=TObject(p);');
+ Add(' cl:=TClass(p);');
+ Add(' a:=TArrInt(p);');
+ ParseProgram;
+end;
+
+procedure TTestResolver.TestPointer_AssignPointerToClassFail;
+begin
+ StartProgram(false);
+ Add('type');
+ Add(' TObject = class end;');
+ Add('var');
+ Add(' Obj: TObject;');
+ Add(' p: pointer;');
+ Add('begin');
+ Add(' obj:=p;');
+ CheckResolverException('Incompatible types: got "Pointer" expected "TObject"',
+ nIncompatibleTypesGotExpected);
+end;
+
+procedure TTestResolver.TestPointer_TypecastToMethodTypeFail;
+begin
+ StartProgram(false);
+ Add('type');
+ Add(' TEvent = procedure of object;');
+ Add('var');
+ Add(' p: pointer;');
+ Add(' e: TEvent;');
+ Add('begin');
+ Add(' e:=TEvent(p);');
+ CheckResolverException('Illegal type conversion: "Pointer" to "procedure type of Object"',
+ nIllegalTypeConversionTo);
+end;
+
+procedure TTestResolver.TestPointer_TypecastFromMethodTypeFail;
+begin
+ StartProgram(false);
+ Add('type');
+ Add(' TEvent = procedure of object;');
+ Add('var');
+ Add(' p: pointer;');
+ Add(' e: TEvent;');
+ Add('begin');
+ Add(' p:=Pointer(e);');
+ CheckResolverException('Illegal type conversion: "procedure type of Object" to "Pointer"',
+ nIllegalTypeConversionTo);
+end;
+
+procedure TTestResolver.TestPointer_TypecastMethod_proMethodAddrAsPointer;
+begin
+ ResolverEngine.Options:=ResolverEngine.Options+[proMethodAddrAsPointer];
+ StartProgram(false);
+ Add('type');
+ Add(' TEvent = procedure of object;');
+ Add('var');
+ Add(' p: pointer;');
+ Add(' e: TEvent;');
+ Add('begin');
+ Add(' e:=TEvent(p);');
+ Add(' p:=Pointer(e);');
+ ParseProgram;
+end;
+
initialization
RegisterTests([TTestResolver]);
diff --git a/packages/fcl-passrc/tests/tcuseanalyzer.pas b/packages/fcl-passrc/tests/tcuseanalyzer.pas
index 7919996660..3c4cad5249 100644
--- a/packages/fcl-passrc/tests/tcuseanalyzer.pas
+++ b/packages/fcl-passrc/tests/tcuseanalyzer.pas
@@ -21,6 +21,7 @@ type
private
FAnalyzer: TPasAnalyzer;
FPAMessages: TFPList; // list of TPAMessage
+ FPAGoodMessages: TFPList;
function GetPAMessages(Index: integer): TPAMessage;
procedure OnAnalyzerMessage(Sender: TObject; Msg: TPAMessage);
protected
@@ -32,8 +33,9 @@ type
procedure AnalyzeWholeProgram; virtual;
procedure CheckUsedMarkers; virtual;
procedure CheckHasHint(MsgType: TMessageType; MsgNumber: integer;
- const MsgText: string; Has: boolean = true); virtual;
- procedure CheckUnitUsed(const aFilename: string; Used: boolean);
+ const MsgText: string); virtual;
+ procedure CheckUnexpectedMessages; virtual;
+ procedure CheckUnitUsed(const aFilename: string; Used: boolean); virtual;
public
property Analyzer: TPasAnalyzer read FAnalyzer;
function PAMessageCount: integer;
@@ -77,6 +79,7 @@ type
procedure TestM_Hint_UnitNotUsed_No_OnlyExternal;
procedure TestM_Hint_ParameterNotUsed;
procedure TestM_Hint_ParameterNotUsed_Abstract;
+ procedure TestM_Hint_ParameterNotUsedTypecast;
procedure TestM_Hint_LocalVariableNotUsed;
procedure TestM_Hint_InterfaceUnitVariableUsed;
procedure TestM_Hint_ValueParameterIsAssignedButNeverUsed;
@@ -85,6 +88,7 @@ type
procedure TestM_Hint_PrivateFieldIsNeverUsed;
procedure TestM_Hint_PrivateFieldIsAssignedButNeverUsed;
procedure TestM_Hint_PrivateMethodIsNeverUsed;
+ procedure TestM_Hint_LocalDestructor_No_IsNeverUsed;
procedure TestM_Hint_PrivateTypeNeverUsed;
procedure TestM_Hint_PrivateConstNeverUsed;
procedure TestM_Hint_PrivatePropertyNeverUsed;
@@ -106,6 +110,13 @@ type
procedure TestWP_CallInherited;
procedure TestWP_ProgramPublicDeclarations;
procedure TestWP_ClassDefaultProperty;
+ procedure TestWP_Published;
+ procedure TestWP_PublishedSetType;
+ procedure TestWP_PublishedArrayType;
+ procedure TestWP_PublishedClassOfType;
+ procedure TestWP_PublishedRecordType;
+ procedure TestWP_PublishedProcType;
+ procedure TestWP_PublishedProperty;
end;
implementation
@@ -128,6 +139,7 @@ procedure TCustomTestUseAnalyzer.SetUp;
begin
inherited SetUp;
FPAMessages:=TFPList.Create;
+ FPAGoodMessages:=TFPList.Create;
FAnalyzer:=TPasAnalyzer.Create;
FAnalyzer.Resolver:=ResolverEngine;
Analyzer.OnMessage:=@OnAnalyzerMessage;
@@ -137,6 +149,7 @@ procedure TCustomTestUseAnalyzer.TearDown;
var
i: Integer;
begin
+ FreeAndNil(FPAGoodMessages);
for i:=0 to FPAMessages.Count-1 do
TPAMessage(FPAMessages[i]).Release;
FreeAndNil(FPAMessages);
@@ -227,7 +240,7 @@ begin
end;
procedure TCustomTestUseAnalyzer.CheckHasHint(MsgType: TMessageType;
- MsgNumber: integer; const MsgText: string; Has: boolean);
+ MsgNumber: integer; const MsgText: string);
var
i: Integer;
Msg: TPAMessage;
@@ -239,22 +252,14 @@ begin
Msg:=PAMessages[i];
if (Msg.MsgNumber=MsgNumber) then
begin
- if Has then
+ if (Msg.MsgType=MsgType) and (Msg.MsgText=MsgText) then
begin
- // must have -> message type and text must match exactly
- if (Msg.MsgType=MsgType) and (Msg.MsgText=MsgText) then
- exit;
- end
- else
- begin
- // must not have -> matching number is enough
- break;
+ FPAGoodMessages.Add(Msg);
+ exit;
end;
end;
dec(i);
end;
- if (not Has) and (i<0) then exit;
-
// mismatch
writeln('TCustomTestUseAnalyzer.CheckHasHint: ');
for i:=0 to PAMessageCount-1 do
@@ -264,7 +269,23 @@ begin
end;
s:='';
str(MsgType,s);
- Fail('Analyzer Message '+BoolToStr(Has,'not ','')+'found: '+s+': ('+IntToStr(MsgNumber)+') {'+MsgText+'}');
+ Fail('Analyzer Message not found: '+s+': ('+IntToStr(MsgNumber)+') {'+MsgText+'}');
+end;
+
+procedure TCustomTestUseAnalyzer.CheckUnexpectedMessages;
+var
+ i: Integer;
+ Msg: TPAMessage;
+ s: String;
+begin
+ for i:=0 to PAMessageCount-1 do
+ begin
+ Msg:=PAMessages[i];
+ if FPAGoodMessages.IndexOf(Msg)>=0 then continue;
+ s:='';
+ str(Msg.MsgType,s);
+ Fail('Analyzer Message found ['+IntToStr(Msg.Id)+'] '+s+': ('+IntToStr(Msg.MsgNumber)+') {'+Msg.MsgText+'}');
+ end;
end;
procedure TCustomTestUseAnalyzer.CheckUnitUsed(const aFilename: string;
@@ -749,7 +770,7 @@ begin
Add(' {tmobile_used}TMobile = class(TObject)');
Add(' constructor {#mob_create_used}Create;');
Add(' procedure {#mob_doa_used}DoA; override;');
- Add(' procedure {#mob_dob_notused}DoB; override;');
+ Add(' procedure {#mob_dob_used}DoB; override;');
Add(' end;');
Add('constructor TMobile.Create; begin end;');
Add('procedure TMobile.DoA; begin end;');
@@ -831,6 +852,7 @@ begin
Add('begin');
AnalyzeProgram;
CheckHasHint(mtHint,nPAUnitNotUsed,'Unit "unit2" not used in afile');
+ CheckUnexpectedMessages;
end;
procedure TTestUseAnalyzer.TestM_Hint_UnitNotUsed_No_OnlyExternal;
@@ -851,7 +873,7 @@ begin
AnalyzeProgram;
// unit hints: no hint, even though no code is actually used
- CheckHasHint(mtHint,nPAUnitNotUsed,'Unit "unit2" not used in afile',false);
+ CheckUnexpectedMessages;
end;
procedure TTestUseAnalyzer.TestM_Hint_ParameterNotUsed;
@@ -863,6 +885,7 @@ begin
Add(' DoIt(1);');
AnalyzeProgram;
CheckHasHint(mtHint,nPAParameterNotUsed,'Parameter "i" not used');
+ CheckUnexpectedMessages;
end;
procedure TTestUseAnalyzer.TestM_Hint_ParameterNotUsed_Abstract;
@@ -875,8 +898,28 @@ begin
Add('begin');
Add(' TObject.DoIt(3);');
AnalyzeProgram;
- CheckHasHint(mtHint,nPAParameterNotUsed,
- sPAParameterNotUsed,false);
+ CheckUnexpectedMessages;
+end;
+
+procedure TTestUseAnalyzer.TestM_Hint_ParameterNotUsedTypecast;
+begin
+ StartProgram(true);
+ Add('type');
+ Add(' TObject = class end;');
+ Add(' TSortCompare = function(a,b: Pointer): integer;');
+ Add(' TObjCompare = function(a,b: TObject): integer;');
+ Add('procedure Sort(const Compare: TSortCompare);');
+ Add('begin');
+ Add(' Compare(nil,nil);');
+ Add('end;');
+ Add('procedure DoIt(const Compare: TObjCompare);');
+ Add('begin');
+ Add(' Sort(TSortCompare(Compare));');
+ Add('end;');
+ Add('begin');
+ Add(' DoIt(nil);');
+ AnalyzeProgram;
+ CheckUnexpectedMessages;
end;
procedure TTestUseAnalyzer.TestM_Hint_LocalVariableNotUsed;
@@ -897,6 +940,7 @@ begin
CheckHasHint(mtHint,nPALocalXYNotUsed,'Local constant "b" not used');
CheckHasHint(mtHint,nPALocalVariableNotUsed,'Local variable "c" not used');
CheckHasHint(mtHint,nPALocalVariableNotUsed,'Local variable "d" not used');
+ CheckUnexpectedMessages;
end;
procedure TTestUseAnalyzer.TestM_Hint_InterfaceUnitVariableUsed;
@@ -921,8 +965,14 @@ begin
Add(' {#ImpTFlags_notused}ImpTFlags = set of TFlag;');
Add(' {#ImpTArrInt_notused}ImpTArrInt = array of integer;');
AnalyzeUnit;
- CheckHasHint(mtHint,nPALocalVariableIsAssignedButNeverUsed,
- 'Local variable "a" is assigned but never used',false);
+ CheckHasHint(mtHint,nPALocalXYNotUsed,'Local constant "d" not used');
+ CheckHasHint(mtHint,nPALocalXYNotUsed,'Local constant "e" not used');
+ CheckHasHint(mtHint,nPALocalVariableNotUsed,'Local variable "f" not used');
+ CheckHasHint(mtHint,nPALocalXYNotUsed,'Local alias type "ImpTColor" not used');
+ CheckHasHint(mtHint,nPALocalXYNotUsed,'Local enumeration type "ImpTFlag" not used');
+ CheckHasHint(mtHint,nPALocalXYNotUsed,'Local set type "ImpTFlags" not used');
+ CheckHasHint(mtHint,nPALocalXYNotUsed,'Local array type "ImpTArrInt" not used');
+ CheckUnexpectedMessages;
end;
procedure TTestUseAnalyzer.TestM_Hint_ValueParameterIsAssignedButNeverUsed;
@@ -937,6 +987,7 @@ begin
AnalyzeProgram;
CheckHasHint(mtHint,nPAValueParameterIsAssignedButNeverUsed,
'Value parameter "i" is assigned but never used');
+ CheckUnexpectedMessages;
end;
procedure TTestUseAnalyzer.TestM_Hint_LocalVariableIsAssignedButNeverUsed;
@@ -962,6 +1013,7 @@ begin
'Local variable "b" is assigned but never used');
CheckHasHint(mtHint,nPALocalVariableIsAssignedButNeverUsed,
'Local variable "c" is assigned but never used');
+ CheckUnexpectedMessages;
end;
procedure TTestUseAnalyzer.TestM_Hint_LocalXYNotUsed;
@@ -984,6 +1036,7 @@ begin
CheckHasHint(mtHint,nPALocalXYNotUsed,'Local set type "TFlags" not used');
CheckHasHint(mtHint,nPALocalXYNotUsed,'Local array type "TArrInt" not used');
CheckHasHint(mtHint,nPALocalXYNotUsed,'Local procedure "Sub" not used');
+ CheckUnexpectedMessages;
end;
procedure TTestUseAnalyzer.TestM_Hint_PrivateFieldIsNeverUsed;
@@ -998,7 +1051,11 @@ begin
Add('begin');
Add(' m:=nil;');
AnalyzeProgram;
- CheckHasHint(mtHint,nPAPrivateFieldIsNeverUsed,'Private field "TMobile.a" is never used');
+ CheckHasHint(mtHint,nPAPrivateFieldIsNeverUsed,
+ 'Private field "TMobile.a" is never used');
+ CheckHasHint(mtHint,nPALocalVariableIsAssignedButNeverUsed,
+ 'Local variable "m" is assigned but never used');
+ CheckUnexpectedMessages;
end;
procedure TTestUseAnalyzer.TestM_Hint_PrivateFieldIsAssignedButNeverUsed;
@@ -1020,6 +1077,7 @@ begin
AnalyzeProgram;
CheckHasHint(mtHint,nPAPrivateFieldIsAssignedButNeverUsed,
'Private field "TMobile.a" is assigned but never used');
+ CheckUnexpectedMessages;
end;
procedure TTestUseAnalyzer.TestM_Hint_PrivateMethodIsNeverUsed;
@@ -1040,6 +1098,34 @@ begin
AnalyzeProgram;
CheckHasHint(mtHint,nPAPrivateMethodIsNeverUsed,
'Private method "TMobile.DoSome" is never used');
+ CheckUnexpectedMessages;
+end;
+
+procedure TTestUseAnalyzer.TestM_Hint_LocalDestructor_No_IsNeverUsed;
+begin
+ StartProgram(true,[supTObject]);
+ Add('type');
+ Add(' TMobile = class');
+ Add(' private');
+ Add(' public');
+ Add(' constructor Create;');
+ Add(' destructor Destroy; override;');
+ Add(' end;');
+ Add('var DestroyCount: longint = 0;');
+ Add('constructor TMobile.Create;');
+ Add('begin');
+ Add('end;');
+ Add('destructor TMobile.Destroy;');
+ Add('begin');
+ Add(' inc(DestroyCount);');
+ Add(' inherited;');
+ Add('end;');
+ Add('var o: TObject;');
+ Add('begin');
+ Add(' o:=TMobile.Create;');
+ Add(' o.Destroy;');
+ AnalyzeProgram;
+ CheckUnexpectedMessages;
end;
procedure TTestUseAnalyzer.TestM_Hint_PrivateTypeNeverUsed;
@@ -1060,6 +1146,7 @@ begin
AnalyzeProgram;
CheckHasHint(mtHint,nPAPrivateTypeXNeverUsed,
'Private type "TMobile.t" never used');
+ CheckUnexpectedMessages;
end;
procedure TTestUseAnalyzer.TestM_Hint_PrivateConstNeverUsed;
@@ -1080,6 +1167,7 @@ begin
AnalyzeProgram;
CheckHasHint(mtHint,nPAPrivateConstXNeverUsed,
'Private const "TMobile.c" never used');
+ CheckUnexpectedMessages;
end;
procedure TTestUseAnalyzer.TestM_Hint_PrivatePropertyNeverUsed;
@@ -1101,6 +1189,9 @@ begin
AnalyzeProgram;
CheckHasHint(mtHint,nPAPrivatePropertyXNeverUsed,
'Private property "TMobile.A" never used');
+ CheckHasHint(mtHint,nPAPrivateFieldIsNeverUsed,
+ 'Private field "TMobile.FA" is never used');
+ CheckUnexpectedMessages;
end;
procedure TTestUseAnalyzer.TestM_Hint_LocalClassInProgramNotUsed;
@@ -1120,6 +1211,7 @@ begin
AnalyzeProgram;
CheckHasHint(mtHint,nPALocalXYNotUsed,'Local class "TMobile" not used');
CheckHasHint(mtHint,nPALocalVariableNotUsed,'Local variable "m" not used');
+ CheckUnexpectedMessages;
end;
procedure TTestUseAnalyzer.TestM_Hint_LocalMethodInProgramNotUsed;
@@ -1139,6 +1231,7 @@ begin
Add(' if m=nil then ;');
AnalyzeProgram;
CheckHasHint(mtHint,nPALocalXYNotUsed,'Local constructor "Create" not used');
+ CheckUnexpectedMessages;
end;
procedure TTestUseAnalyzer.TestM_Hint_AssemblerParameterIgnored;
@@ -1161,8 +1254,7 @@ begin
Add('begin');
Add(' DoIt(1);');
AnalyzeProgram;
- CheckHasHint(mtHint,nPAParameterNotUsed,'Parameter "i" not used',false);
- AssertEquals('no hints for assembler proc',0,PAMessageCount);
+ CheckUnexpectedMessages;
end;
procedure TTestUseAnalyzer.TestM_Hint_FunctionResultDoesNotSeemToBeSet;
@@ -1175,6 +1267,7 @@ begin
AnalyzeProgram;
CheckHasHint(mtHint,nPAFunctionResultDoesNotSeemToBeSet,
sPAFunctionResultDoesNotSeemToBeSet);
+ CheckUnexpectedMessages;
end;
procedure TTestUseAnalyzer.TestM_Hint_FunctionResultDoesNotSeemToBeSet_Abstract;
@@ -1187,8 +1280,7 @@ begin
Add('begin');
Add(' TObject.DoIt;');
AnalyzeProgram;
- CheckHasHint(mtHint,nPAFunctionResultDoesNotSeemToBeSet,
- sPAFunctionResultDoesNotSeemToBeSet,false);
+ CheckUnexpectedMessages;
end;
procedure TTestUseAnalyzer.TestM_Hint_FunctionResultRecord;
@@ -1196,15 +1288,17 @@ begin
StartProgram(true);
Add('type');
Add(' TPoint = record X,Y:longint; end;');
- Add('function Point(Left,Top: longint): TPoint;');
+ Add('function Point(Left: longint): TPoint;');
Add('begin');
Add(' Result.X:=Left;');
Add('end;');
Add('begin');
- Add(' Point(1,2);');
+ Add(' Point(1);');
AnalyzeProgram;
- CheckHasHint(mtHint,nPAFunctionResultDoesNotSeemToBeSet,
- sPAFunctionResultDoesNotSeemToBeSet,false);
+ CheckHasHint(mtHint,nPALocalVariableIsAssignedButNeverUsed,
+ 'Local variable "X" is assigned but never used');
+ CheckHasHint(mtHint,nPALocalVariableNotUsed,'Local variable "Y" not used');
+ CheckUnexpectedMessages;
end;
procedure TTestUseAnalyzer.TestM_Hint_FunctionResultPassRecordElement;
@@ -1216,15 +1310,15 @@ begin
Add('begin');
Add(' x:=3;');
Add('end;');
- Add('function Point(Left,Top: longint): TPoint;');
+ Add('function Point(): TPoint;');
Add('begin');
Add(' Three(Result.X)');
Add('end;');
Add('begin');
- Add(' Point(1,2);');
+ Add(' Point();');
AnalyzeProgram;
- CheckHasHint(mtHint,nPAFunctionResultDoesNotSeemToBeSet,
- sPAFunctionResultDoesNotSeemToBeSet,false);
+ CheckHasHint(mtHint,nPALocalVariableNotUsed,'Local variable "Y" not used');
+ CheckUnexpectedMessages;
end;
procedure TTestUseAnalyzer.TestM_Hint_OutParam_No_AssignedButNeverUsed;
@@ -1238,8 +1332,7 @@ begin
Add('begin');
Add(' DoIt(i);');
AnalyzeProgram;
- CheckHasHint(mtHint,nPAValueParameterIsAssignedButNeverUsed,
- sPAValueParameterIsAssignedButNeverUsed,false);
+ CheckUnexpectedMessages;
end;
procedure TTestUseAnalyzer.TestWP_LocalVar;
@@ -1402,6 +1495,145 @@ begin
AnalyzeWholeProgram;
end;
+procedure TTestUseAnalyzer.TestWP_Published;
+begin
+ StartProgram(false);
+ Add('type');
+ Add(' {#tobject_used}TObject = class');
+ Add(' private');
+ Add(' {#fcol_used}FCol: string;');
+ Add(' {#fbird_notused}FBird: string;');
+ Add(' published');
+ Add(' {#fielda_used}FieldA: longint;');
+ Add(' procedure {#doit_used}ProcA; virtual; abstract;');
+ Add(' property {#col_used}Col: string read FCol;');
+ Add(' end;');
+ Add('var');
+ Add(' {#o_used}o: TObject;');
+ Add('begin');
+ Add(' o:=nil;');
+ AnalyzeWholeProgram;
+end;
+
+procedure TTestUseAnalyzer.TestWP_PublishedSetType;
+begin
+ StartProgram(false);
+ Add('type');
+ Add(' {#tflag_used}TFlag = (red, green);');
+ Add(' {#tflags_used}TFlags = set of TFlag;');
+ Add(' {#tobject_used}TObject = class');
+ Add(' published');
+ Add(' {#fielda_used}FieldA: TFlag;');
+ Add(' {#fieldb_used}FieldB: TFlags;');
+ Add(' end;');
+ Add('var');
+ Add(' {#o_used}o: TObject;');
+ Add('begin');
+ Add(' o:=nil;');
+ AnalyzeWholeProgram;
+end;
+
+procedure TTestUseAnalyzer.TestWP_PublishedArrayType;
+begin
+ StartProgram(false);
+ Add('type');
+ Add(' {#tdynarr_used}TDynArr = array of longint;');
+ Add(' {#tstatarr_used}TStatArr = array[boolean] of longint;');
+ Add(' {#tobject_used}TObject = class');
+ Add(' published');
+ Add(' {#fielda_used}FieldA: TDynArr;');
+ Add(' {#fieldb_used}FieldB: TStatArr;');
+ Add(' end;');
+ Add('var');
+ Add(' {#o_used}o: TObject;');
+ Add('begin');
+ Add(' o:=nil;');
+ AnalyzeWholeProgram;
+end;
+
+procedure TTestUseAnalyzer.TestWP_PublishedClassOfType;
+begin
+ StartProgram(false);
+ Add('type');
+ Add(' {#tobjectclass_used}TObjectClass = class of TObject;');
+ Add(' {#tobject_used}TObject = class');
+ Add(' published');
+ Add(' {#fielda_used}FieldA: TObjectClass;');
+ Add(' end;');
+ Add(' {#tclass_used}TClass = class of TObject;');
+ Add('var');
+ Add(' {#c_used}c: TClass;');
+ Add('begin');
+ Add(' c:=nil;');
+ AnalyzeWholeProgram;
+end;
+
+procedure TTestUseAnalyzer.TestWP_PublishedRecordType;
+begin
+ StartProgram(false);
+ Add('type');
+ Add(' {#trec_used}TRec = record');
+ Add(' {treci_used}i: longint;');
+ Add(' end;');
+ Add(' {#tobject_used}TObject = class');
+ Add(' published');
+ Add(' {#fielda_used}FieldA: TRec;');
+ Add(' end;');
+ Add('var');
+ Add(' {#o_used}o: TObject;');
+ Add('begin');
+ Add(' o:=nil;');
+ AnalyzeWholeProgram;
+end;
+
+procedure TTestUseAnalyzer.TestWP_PublishedProcType;
+begin
+ StartProgram(false);
+ Add('type');
+ Add(' {#ta_used}ta = array of longint;');
+ Add(' {#tb_used}tb = array of longint;');
+ Add(' {#tproca_used}TProcA = procedure;');
+ Add(' {#tfunca_used}TFuncA = function: ta;');
+ Add(' {#tprocb_used}TProcB = procedure(a: tb);');
+ Add(' {#tobject_used}TObject = class');
+ Add(' published');
+ Add(' {#fielda_used}FieldA: TProcA;');
+ Add(' {#fieldb_used}FieldB: TFuncA;');
+ Add(' {#fieldc_used}FieldC: TProcB;');
+ Add(' end;');
+ Add('var');
+ Add(' {#o_used}o: TObject;');
+ Add('begin');
+ Add(' o:=nil;');
+ AnalyzeWholeProgram;
+end;
+
+procedure TTestUseAnalyzer.TestWP_PublishedProperty;
+begin
+ StartProgram(false);
+ Add('const');
+ Add(' {#defcol_used}DefCol = 3;');
+ Add(' {#defsize_notused}DefSize = 43;');
+ Add('type');
+ Add(' {#tobject_used}TObject = class');
+ Add(' private');
+ Add(' {#fcol_used}FCol: longint;');
+ Add(' {#fsize_used}FSize: longint;');
+ Add(' {#fbird_notused}FBird: string;');
+ Add(' {#fcolstored_used}FColStored: boolean;');
+ Add(' {#fsizestored_notused}FSizeStored: boolean;');
+ Add(' public');
+ Add(' property {#size_used}Size: longint read FSize stored FSizeStored default DefSize;');
+ Add(' published');
+ Add(' property {#col_used}Col: longint read FCol stored FColStored default DefCol;');
+ Add(' end;');
+ Add('var');
+ Add(' {#o_used}o: TObject;');
+ Add('begin');
+ Add(' if o.Size=13 then ;');
+ AnalyzeWholeProgram;
+end;
+
initialization
RegisterTests([TTestUseAnalyzer]);
diff --git a/packages/pastojs/fpmake.pp b/packages/pastojs/fpmake.pp
index 935778586a..7400adf5e3 100644
--- a/packages/pastojs/fpmake.pp
+++ b/packages/pastojs/fpmake.pp
@@ -19,7 +19,7 @@ begin
{$endif ALLPACKAGES}
P.Version:='3.0.3';
- P.OSes := AllOses-[embedded,msdos,win16];
+ P.OSes := AllOses-[embedded,msdos];
P.Dependencies.Add('fcl-js');
P.Dependencies.Add('fcl-passrc');
diff --git a/packages/pastojs/src/fppas2js.pp b/packages/pastojs/src/fppas2js.pp
index c9fff09c3b..cc5920c29d 100644
--- a/packages/pastojs/src/fppas2js.pp
+++ b/packages/pastojs/src/fppas2js.pp
@@ -103,6 +103,7 @@ Works:
- reintroduced variables
- external vars and methods
- const
+ - bracket accessor, getter/setter has external name '[]'
- dynamic arrays
- arrays can be null
- init as "arr = []" so typeof works
@@ -133,6 +134,7 @@ Works:
- ord(), low(), high(), pred(), succ()
- type cast alias to enumtype
- type cast number to enumtype
+ - const aliasname = enumvalue
- sets
- set of enum
- include, exclude, clone when referenced
@@ -142,6 +144,7 @@ Works:
- in-operator
- low(), high()
- when passing as argument set state referenced
+ - set of (enum,enum2) - anonymous enumtype
- with-do using local var
- with record do i:=v;
- with classinstance do begin create; i:=v; f(); i:=a[]; end;
@@ -188,7 +191,6 @@ Works:
- Pascal descendant can override newinstance
- any class can be typecasted to any root class
- class instances cannot access external class members (e.g. static class functions)
- - external class bracket accessor, getter/setter has external name '[]'
- external class 'Array' bracket operator [integer] type jsvalue
- external class 'Object' bracket operator [string] type jsvalue
- jsvalue
@@ -210,29 +212,60 @@ Works:
- parameter, result type, assign from/to untyped
- operators equal, not equal
- callback: assign to jsvalue, equal, not equal
+- RTTI
+ - base types
+ - unit $rtti
+ - enum type tkEnumeration
+ - set type tkSet
+ - procedure type tkProcVar, tkMethod
+ - class type tkClass
+ - fields,
+ - methods,
+ - properties no params, no index, no defaultvalue
+ - class forward
+ - class-of type tkClassRef
+ - dyn array type tkDynArray
+ - static array type tkArray
+ - record type tkRecord
+ - no typeinfo for local types
+ - built-in function typeinfo(): Pointer/TTypeInfo/...;
+ - typeinfo(class) -> class.$rtti
+ - WPO skip not used typeinfo
+- pointer
+ - compare with and assign nil
- ECMAScript6:
- use 0b for binary literals
- use 0o for octal literals
ToDos:
-- -Jirtl.js-
+- typecast proctype
+- RTTI
+ - open array param
+ - codetools function typeinfo
+ - jsinteger (pasresolver: btIntDouble)
+ - class property
+ - defaultvalue
+ - type alias type
+ - typinfo.pp functions to get/setprop
+ - documentation
+- warn int64
+- move local types to unit scope
+- local var absolute
- make -Jirtl.js default for -Jc and -Tnodejs, needs #IFDEF in cfg
-- remove 'Object' array workaround
- FuncName:= (instead of Result:=)
-- ord(s[i]) -> s.charCodeAt(i)
- $modeswitch -> define <modeswitch>
- $modeswitch- -> turn off
+- check memleaks
- integer range
- @@ compare method in delphi mode
- make records more lightweight
- dotted unit names, namespaces
-- type alias type
-- RTTI
- enumeration for..in..do
- pointer of record
- nested types in class
- asm: pas() - useful for overloads and protect an identifier from optimization
- source maps
+- ifthen
Not in Version 1.0:
- write, writeln
@@ -243,9 +276,9 @@ Not in Version 1.0:
- array of const
- sets
- set of char, boolean, integer range, char range, enum range
- - set of (enum,enum2) - anonymous enumtype
- call array of proc element without ()
- record const
+- class: property modifier index
- enums with custom values
- library
- option typecast checking
@@ -300,12 +333,15 @@ const
nInvalidFunctionReference = 4011;
nMissingExternalName = 4012;
nVirtualMethodNameMustMatchExternal = 4013;
- nInvalidVariableModifier = 4014;
- nNoArgumentsAllowedForExternalObjectConstructor = 4015;
- nNewInstanceFunctionMustBeVirtual = 4016;
- nNewInstanceFunctionMustHaveTwoParameters = 4017;
- nNewInstanceFunctionMustNotHaveOverloads = 4018;
- nBracketAccessorOfExternalClassMustHaveOneParameter = 4019;
+ nPublishedNameMustMatchExternal = 4014;
+ nInvalidVariableModifier = 4015;
+ nNoArgumentsAllowedForExternalObjectConstructor = 4016;
+ nNewInstanceFunctionMustBeVirtual = 4017;
+ nNewInstanceFunctionMustHaveTwoParameters = 4018;
+ nNewInstanceFunctionMustNotHaveOverloadAtX = 4019;
+ nBracketAccessorOfExternalClassMustHaveOneParameter = 4020;
+ nTypeXCannotBePublished = 4021;
+ nNotSupportedX = 4022;
// resourcestring patterns of messages
resourcestring
sPasElementNotSupported = 'Pascal element not supported: %s';
@@ -322,11 +358,14 @@ resourcestring
sMissingExternalName = 'Missing external name';
sVirtualMethodNameMustMatchExternal = 'Virtual method name must match external';
sInvalidVariableModifier = 'Invalid variable modifier "%s"';
+ sPublishedNameMustMatchExternal = 'Published name must match external';
sNoArgumentsAllowedForExternalObjectConstructor = 'no arguments allowed for external object constructor';
sNewInstanceFunctionMustBeVirtual = 'NewInstance function must be virtual';
sNewInstanceFunctionMustHaveTwoParameters = 'NewInstance function must have two parameters';
- sNewInstanceFunctionMustNotHaveOverloads = 'NewInstance function must not have overloads';
+ sNewInstanceFunctionMustNotHaveOverloadAtX = 'NewInstance function must not have overload at %s';
sBracketAccessorOfExternalClassMustHaveOneParameter = 'Bracket accessor of external class must have one parameter';
+ sTypeXCannotBePublished = 'Type "%s" cannot be published';
+ sNotSupportedX = 'Not supported: %s';
const
ExtClassBracketAccessor = '[]'; // external name '[]' marks the array param getter/setter
@@ -353,6 +392,21 @@ type
pbifnProcType_Equal,
pbifnProgramMain,
pbifnRecordEqual,
+ pbifnRTTIAddField, // typeinfos of tkclass and tkrecord have addField
+ pbifnRTTIAddFields, // typeinfos of tkclass and tkrecord have addFields
+ pbifnRTTIAddMethod,// " "
+ pbifnRTTIAddProperty,// " "
+ pbifnRTTINewClass,// typeinfo creator of tkClass $Class
+ pbifnRTTINewClassRef,// typeinfo of tkClassRef $ClassRef
+ pbifnRTTINewEnum,// typeinfo of tkEnumeration $Enum
+ pbifnRTTINewDynArray,// typeinfo of tkDynArray $DynArray
+ pbifnRTTINewMethodVar,// typeinfo of tkMethod $MethodVar
+ pbifnRTTINewPointer,// typeinfo of tkPointer $Pointer
+ pbifnRTTINewProcSig,// rtl.newTIProcSig
+ pbifnRTTINewProcVar,// typeinfo of tkProcVar $ProcVar
+ pbifnRTTINewRecord,// typeinfo creator of tkRecord $Record
+ pbifnRTTINewSet,// typeinfo of tkSet $Set
+ pbifnRTTINewStaticArray,// typeinfo of tkArray $StaticArray
pbifnSetCharAt,
pbifnSet_Clone,
pbifnSet_Create,
@@ -375,7 +429,35 @@ type
pbivnModules,
pbivnPtrClass,
pbivnRTL,
- pbivnWith
+ pbivnRTTI, // $rtti
+ pbivnRTTIArray_Dims,
+ pbivnRTTIArray_ElType,
+ pbivnRTTIClassRef_InstanceType,
+ pbivnRTTIEnum_EnumType,
+ pbivnRTTIInt_MaxValue,
+ pbivnRTTIInt_MinValue,
+ pbivnRTTILocal, // $r
+ pbivnRTTIMethodKind, // tTypeInfoMethodVar has methodkind
+ pbivnRTTIPointer_RefType,
+ pbivnRTTIProcFlags,
+ pbivnRTTIProcVar_ProcSig,
+ pbivnRTTIPropDefault,
+ pbivnRTTIPropStored,
+ pbivnRTTISet_CompType,
+ pbivnWith,
+ pbitnAnonymousPostfix,
+ pbitnTI,
+ pbitnTIClass,
+ pbitnTIClassRef,
+ pbitnTIDynArray,
+ pbitnTIEnum,
+ pbitnTIInteger,
+ pbitnTIMethodVar,
+ pbitnTIPointer,
+ pbitnTIProcVar,
+ pbitnTIRecord,
+ pbitnTISet,
+ pbitnTIStaticArray
);
const
@@ -400,6 +482,21 @@ const
'eqCallback', // rtl.eqCallback
'$main',
'$equal',
+ 'addField',
+ 'addFields',
+ 'addMethod',
+ 'addProperty',
+ '$Class',
+ '$ClassRef',
+ '$Enum',
+ '$DynArray',
+ '$MethodVar',
+ '$Pointer',
+ 'newTIProcSig',
+ '$ProcVar',
+ '$Record',
+ '$Set',
+ '$StaticArray',
'setCharAt', // rtl.setCharAt
'cloneSet', // rtl.cloneSet
'createSet', // rtl.createSet [...]
@@ -422,10 +519,38 @@ const
'pas',
'$class',
'rtl',
- '$with'
+ '$rtti',
+ 'dims',
+ 'eltype',
+ 'instancetype',
+ 'enumtype',
+ 'maxvalue',
+ 'minvalue',
+ '$r',
+ 'methodkind',
+ 'reftype',
+ 'flags',
+ 'procsig',
+ 'defaultvalue',
+ 'stored',
+ 'comptype',
+ '$with',
+ '$a',
+ 'tTypeInfo',
+ 'tTypeInfoClass',
+ 'tTypeInfoClassRef',
+ 'tTypeInfoDynArray',
+ 'tTypeInfoEnum',
+ 'tTypeInfoInteger',
+ 'tTypeInfoMethodVar',
+ 'tTypeInfoPointer',
+ 'tTypeInfoProcVar',
+ 'tTypeInfoRecord',
+ 'tTypeInfoSet',
+ 'tTypeInfoStaticArray'
);
- JSReservedWords: array[0..106] of string = (
+ JSReservedWords: array[0..108] of string = (
// keep sorted, first uppercase, then lowercase !
'Array',
'ArrayBuffer',
@@ -479,6 +604,8 @@ const
'call',
'case',
'catch',
+ 'charAt',
+ 'charCodeAt',
'class',
'constructor',
'continue',
@@ -542,7 +669,6 @@ const
HighJSInteger = $fffffffffffff;
LowJSBoolean = false;
HighJSBoolean = true;
-
Type
{ EPas2JS }
@@ -570,10 +696,10 @@ const
'None',
'JSValue'
);
- btAllJSValueSrcTypes = [btNil,btUntyped]+btAllInteger
+ btAllJSValueSrcTypes = [btNil,btUntyped,btPointer]+btAllInteger
+btAllStringAndChars+btAllFloats+btAllBooleans;
btAllJSValueTypeCastTo = btAllInteger
- +btAllStringAndChars+btAllFloats+btAllBooleans;
+ +btAllStringAndChars+btAllFloats+btAllBooleans+[btPointer];
//------------------------------------------------------------------------------
// Element CustomData
@@ -625,6 +751,30 @@ type
//------------------------------------------------------------------------------
// TPas2JSResolver
const
+ btAllPas2jsBaseTypes = [
+ btChar,
+ btString,
+ btDouble,
+ btBoolean,
+ //btByteBool,
+ //btWordBool,
+ //btLongBool,
+ //btQWordBool,
+ btByte,
+ btShortInt,
+ btWord,
+ btSmallInt,
+ btLongWord,
+ btCardinal,
+ btLongint,
+ //btQWord,
+ btInt64,
+ btPointer
+ //btFile,
+ //btText,
+ //btVariant
+ ];
+ bfAllPas2jsBaseProcs = bfAllStandardProcs;
DefaultPasResolverOptions = [
proFixCaseOfOverrides,
proClassPropertyNonStatic,
@@ -632,7 +782,8 @@ const
proClassOfIs,
proExtClassInstanceNoTypeMembers,
proOpenAsDynArrays,
- proProcTypeWithoutIsNested
+ proProcTypeWithoutIsNested,
+ proMethodAddrAsPointer
];
type
TPas2JSResolver = class(TPasResolver)
@@ -645,9 +796,12 @@ type
procedure OnClearHashItem(Item, Dummy: pointer);
protected
FOverloadScopes: TFPList; // list of TPasIdentifierScope
+ function HasOverloadIndex(El: TPasElement): boolean; virtual;
function GetOverloadIndex(Identifier: TPasIdentifier;
StopAt: TPasElement): integer;
+ function GetOverloadAt(Identifier: TPasIdentifier; var Index: integer): TPasIdentifier;
function GetOverloadIndex(El: TPasElement): integer;
+ function GetOverloadAt(const aName: String; Index: integer): TPasIdentifier;
function RenameOverload(El: TPasElement): boolean;
procedure RenameOverloadsInSection(aSection: TPasSection);
procedure RenameOverloads(DeclEl: TPasElement; Declarations: TFPList);
@@ -656,6 +810,7 @@ type
procedure PopOverloadScope;
procedure ResolveImplAsm(El: TPasImplAsmStatement); override;
procedure FinishModule(CurModule: TPasModule); override;
+ procedure FinishSetType(El: TPasSetType); override;
procedure FinishClassType(El: TPasClassType); override;
procedure FinishVariable(El: TPasVariable); override;
procedure FinishProcedureType(El: TPasProcedureType); override;
@@ -679,19 +834,15 @@ type
function CheckEqualCompatibilityCustomType(const LHS,
RHS: TPasResolverResult; ErrorEl: TPasElement;
RaiseOnIncompatible: boolean): integer; override;
- function ResolveBracketOperatorClass(Params: TParamsExpr;
- const ResolvedValue: TPasResolverResult; ClassScope: TPasClassScope;
- Access: TResolvedRefAccess): boolean; override;
- procedure ComputeArrayParams_Class(Params: TParamsExpr; var
- ResolvedEl: TPasResolverResult; ClassScope: TPasClassScope;
- Flags: TPasResolverComputeFlags; StartEl: TPasElement); override;
+ procedure BI_TypeInfo_OnGetCallResult(Proc: TResElDataBuiltInProc;
+ Params: TParamsExpr; out ResolvedEl: TPasResolverResult); override;
public
constructor Create;
destructor Destroy; override;
// base types
procedure AddObjFPCBuiltInIdentifiers(
- const TheBaseTypes: TResolveBaseTypes=btAllStandardTypes;
- const TheBaseProcs: TResolverBuiltInProcs=bfAllStandardProcs); override;
+ const TheBaseTypes: TResolveBaseTypes;
+ const TheBaseProcs: TResolverBuiltInProcs); override;
function CheckTypeCastRes(const FromResolved,
ToResolved: TPasResolverResult; ErrorEl: TPasElement;
RaiseOnError: boolean): integer; override;
@@ -707,6 +858,8 @@ type
procedure AddElementData(Data: TPas2JsElementData); virtual;
function CreateElementData(DataClass: TPas2JsElementDataClass;
El: TPasElement): TPas2JsElementData; virtual;
+ // utility
+ function HasTypeInfo(El: TPasType): boolean; override;
end;
//------------------------------------------------------------------------------
@@ -773,9 +926,9 @@ type
constructor Create(PasEl: TPasElement; JSEl: TJSElement; aParent: TConvertContext); override;
end;
- { TInterfaceContext }
+ { TSectionContext - interface/implementation/program/library }
- TInterfaceContext = Class(TFunctionContext)
+ TSectionContext = Class(TFunctionContext)
public
constructor Create(PasEl: TPasElement; JSEl: TJSElement; aParent: TConvertContext); override;
end;
@@ -825,7 +978,8 @@ type
coLowerCase, // lowercase all identifiers, except conflicts with JS reserved words
coSwitchStatement, // convert case-of into switch instead of if-then-else
coEnumNumbers, // use enum numbers instead of names
- coUseStrict // insert 'use strict'
+ coUseStrict, // insert 'use strict'
+ coNoTypeInfo // do not generate RTTI
);
TPasToJsConverterOptions = set of TPasToJsConverterOption;
@@ -891,6 +1045,7 @@ type
private
FBuiltInNames: array[TPas2JSBuiltInName] of string;
FOnIsElementUsed: TPas2JSIsElementUsedEvent;
+ FOnIsTypeInfoUsed: TPas2JSIsElementUsedEvent;
FOptions: TPasToJsConverterOptions;
FPreservedWords: TJSReservedWordList; // sorted with CompareStr
FTargetPlatform: TPasToJsPlatform;
@@ -924,17 +1079,22 @@ type
Function GetPasIdentValueType(AName: String; AContext: TConvertContext): TJSType; virtual;
Function ComputeConstString(Expr: TPasExpr; AContext: TConvertContext; NotEmpty: boolean): String; virtual;
Function IsExternalClassConstructor(El: TPasElement): boolean;
+ Procedure ComputeRange(const RangeResolved: TPasResolverResult;
+ out MinValue, MaxValue: int64; ErrorEl: TPasElement); virtual;
// Name mangling
Function TransformVariableName(El: TPasElement; Const AName: String; AContext : TConvertContext): String; virtual;
Function TransformVariableName(El: TPasElement; AContext : TConvertContext) : String; virtual;
- Function TransformModuleName(El: TPasModule; AContext : TConvertContext) : String; virtual;
+ Function TransformModuleName(El: TPasModule; AddModulesPrefix: boolean; AContext : TConvertContext) : String; virtual;
Function IsPreservedWord(const aName: string): boolean; virtual;
// Never create an element manually, always use the below functions
Function IsElementUsed(El: TPasElement): boolean; virtual;
+ Function HasTypeInfo(El: TPasType; AContext: TConvertContext): boolean; virtual;
+ Function IsClassRTTICreatedBefore(aClass: TPasClassType; Before: TPasElement): boolean;
Function CreateElement(C: TJSElementClass; Src: TPasElement): TJSElement; virtual;
Function CreateFreeOrNewInstanceExpr(Ref: TResolvedReference;
AContext : TConvertContext): TJSCallExpression; virtual;
- Function CreateFunction(El: TPasElement; WithBody: boolean = true): TJSFunctionDeclarationStatement;
+ Function CreateFunction(El: TPasElement; WithBody: boolean = true;
+ WithSrc: boolean = false): TJSFunctionDeclarationStatement;
Procedure CreateProcedureCall(var Call: TJSCallExpression; Args: TParamsExpr;
TargetProc: TPasProcedureType; AContext: TConvertContext); virtual;
Procedure CreateProcedureCallArgs(Elements: TJSArrayLiteralElements;
@@ -949,23 +1109,30 @@ type
Function CreateUsesList(UsesSection: TPasSection; AContext : TConvertContext): TJSArrayLiteral;
Procedure AddToStatementList(var First, Last: TJSStatementList;
Add: TJSElement; Src: TPasElement);
- Function CreateValInit(PasType: TPasType; Expr: TPasElement; El: TPasElement; AContext: TConvertContext): TJSElement; virtual;
+ Function CreateValInit(PasType: TPasType; Expr: TPasElement; El: TPasElement;
+ AContext: TConvertContext): TJSElement; virtual;
Function CreateVarInit(El: TPasVariable; AContext: TConvertContext): TJSElement; virtual;
+ Function CreateVarStatement(const aName: String; Init: TJSElement;
+ El: TPasElement): TJSVariableStatement; virtual;
+ Function CreateVarDecl(const aName: String; Init: TJSElement; El: TPasElement): TJSVarDeclaration; virtual;
Function CreateLiteralNumber(El: TPasElement; const n: TJSNumber): TJSLiteral; virtual;
Function CreateLiteralString(El: TPasElement; const s: string): TJSLiteral; virtual;
Function CreateLiteralJSString(El: TPasElement; const s: TJSString): TJSLiteral; virtual;
Function CreateLiteralBoolean(El: TPasElement; b: boolean): TJSLiteral; virtual;
Function CreateLiteralNull(El: TPasElement): TJSLiteral; virtual;
Function CreateLiteralUndefined(El: TPasElement): TJSLiteral; virtual;
+ Function CreateSetLiteralElement(Expr: TPasExpr; AContext: TConvertContext): TJSElement; virtual;
Function CreateRecordInit(aRecord: TPasRecordType; Expr: TPasElement;
El: TPasElement; AContext: TConvertContext): TJSElement; virtual;
Function CreateArrayInit(ArrayType: TPasArrayType; Expr: TPasElement;
El: TPasElement; AContext: TConvertContext): TJSElement; virtual;
- Function CreateCmpArrayWithNil(El: TPasElement; JSArray: TJSElement; OpCode: TExprOpCode): TJSElement; virtual;
+ Function CreateCmpArrayWithNil(El: TPasElement; JSArray: TJSElement;
+ OpCode: TExprOpCode): TJSElement; virtual;
Function CreateReferencePath(El: TPasElement; AContext : TConvertContext;
Kind: TRefPathKind; Full: boolean = false; Ref: TResolvedReference = nil): string; virtual;
- Function CreateReferencePathExpr(El: TPasElement; AContext : TConvertContext; Full: boolean = false; Ref: TResolvedReference = nil): TJSPrimaryExpressionIdent; virtual;
- Function CreateImplementationSection(El: TPasModule; Src: TJSSourceElements; AContext: TConvertContext): TJSElement;
+ Function CreateReferencePathExpr(El: TPasElement; AContext : TConvertContext;
+ Full: boolean = false; Ref: TResolvedReference = nil): TJSPrimaryExpressionIdent; virtual;
+ Function CreateImplementationSection(El: TPasModule; AContext: TConvertContext): TJSFunctionDeclarationStatement;
Procedure CreateInitSection(El: TPasModule; Src: TJSSourceElements; AContext: TConvertContext);
Function CreateDotExpression(aParent: TPasElement; Left, Right: TJSElement): TJSElement; virtual;
Function CreateReferencedSet(El: TPasElement; SetExpr: TJSElement): TJSElement; virtual;
@@ -974,6 +1141,17 @@ type
Function CreateCallback(El: TPasElement; ResolvedEl: TPasResolverResult;
AContext: TConvertContext): TJSElement; virtual;
Function CreateAssignStatement(LeftEl: TPasElement; AssignContext: TAssignContext): TJSElement; virtual;
+ Function CreateTypeInfoRef(El: TPasType; AContext: TConvertContext;
+ ErrorEl: TPasElement): TJSElement; virtual;
+ Function CreateRTTIArgList(Parent: TPasElement; Args: TFPList;
+ AContext: TConvertContext): TJSElement; virtual;
+ Procedure AddRTTIArgument(Arg: TPasArgument; TargetParams: TJSArrayLiteral;
+ AContext: TConvertContext); virtual;
+ Function CreateRTTINewType(El: TPasType; const CallFuncName: string;
+ IsForward: boolean; AContext: TConvertContext; out ObjLit: TJSObjectLiteral): TJSCallExpression; virtual;
+ Function CreateRTTIClassField(V: TPasVariable; AContext: TConvertContext): TJSElement; virtual;
+ Function CreateRTTIClassMethod(Proc: TPasProcedure; AContext: TConvertContext): TJSElement; virtual;
+ Function CreateRTTIClassProperty(Prop: TPasProperty; AContext: TConvertContext): TJSElement; virtual;
// Statements
Function ConvertImplBlockElements(El: TPasImplBlock; AContext: TConvertContext; NilIfEmpty: boolean): TJSElement; virtual;
Function ConvertBeginEndStatement(El: TPasImplBeginBlock; AContext: TConvertContext; NilIfEmpty: boolean): TJSElement; virtual;
@@ -1002,30 +1180,31 @@ type
Function ConvertExternalConstructor(Left: TPasElement;
Ref: TResolvedReference; ParamsExpr: TParamsExpr;
AContext : TConvertContext): TJSElement; virtual;
- Function ConvertTypeCastToBaseType(El: TParamsExpr; AContext: TConvertContext; BaseTypeData: TResElDataBaseType): TJSElement; virtual;
+ Function ConvertTypeCastToBaseType(El: TParamsExpr; AContext: TConvertContext; ToBaseTypeData: TResElDataBaseType): TJSElement; virtual;
Function ConvertSetLiteral(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
Function ConvertOpenArrayParam(ElType: TPasType; El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
- Function ConvertBuiltInLength(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
- Function ConvertBuiltInSetLength(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
- Function ConvertBuiltInExcludeInclude(El: TParamsExpr; AContext: TConvertContext; IsInclude: boolean): TJSElement; virtual;
+ Function ConvertBuiltIn_Length(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
+ Function ConvertBuiltIn_SetLength(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
+ Function ConvertBuiltIn_ExcludeInclude(El: TParamsExpr; AContext: TConvertContext; IsInclude: boolean): TJSElement; virtual;
Function ConvertBuiltInContinue(El: TPasExpr; AContext: TConvertContext): TJSElement; virtual;
Function ConvertBuiltInBreak(El: TPasExpr; AContext: TConvertContext): TJSElement; virtual;
- Function ConvertBuiltInExit(El: TPasExpr; AContext: TConvertContext): TJSElement; virtual;
- Function ConvertBuiltInIncDec(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
- Function ConvertBuiltInAssigned(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
- Function ConvertBuiltInChr(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
- Function ConvertBuiltInOrd(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
- Function ConvertBuiltInLow(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
- Function ConvertBuiltInHigh(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
- Function ConvertBuiltInPred(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
- Function ConvertBuiltInSucc(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
- Function ConvertBuiltInStrProc(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
- Function ConvertBuiltInStrFunc(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
+ Function ConvertBuiltIn_Exit(El: TPasExpr; AContext: TConvertContext): TJSElement; virtual;
+ Function ConvertBuiltIn_IncDec(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
+ Function ConvertBuiltIn_Assigned(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
+ Function ConvertBuiltIn_Chr(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
+ Function ConvertBuiltIn_Ord(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
+ Function ConvertBuiltIn_Low(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
+ Function ConvertBuiltIn_High(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
+ Function ConvertBuiltIn_Pred(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
+ Function ConvertBuiltIn_Succ(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
+ Function ConvertBuiltIn_StrProc(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
+ Function ConvertBuiltIn_StrFunc(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
Function ConvertBuiltInStrParam(El: TPasExpr; AContext: TConvertContext; IsStrFunc, IsFirst: boolean): TJSElement; virtual;
- Function ConvertBuiltInConcatArray(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
- Function ConvertBuiltInCopyArray(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
- Function ConvertBuiltInInsertArray(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
- Function ConvertBuiltInDeleteArray(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
+ Function ConvertBuiltIn_ConcatArray(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
+ Function ConvertBuiltIn_CopyArray(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
+ Function ConvertBuiltIn_InsertArray(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
+ Function ConvertBuiltIn_DeleteArray(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
+ Function ConvertBuiltIn_TypeInfo(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
Function ConvertRecordValues(El: TRecordValues; AContext: TConvertContext): TJSElement; virtual;
Function ConvertSelfExpression(El: TSelfExpr; AContext: TConvertContext): TJSElement; virtual;
Function ConvertBinaryExpression(El: TBinaryExpr; AContext: TConvertContext): TJSElement; virtual;
@@ -1055,8 +1234,38 @@ type
Function ConvertVariable(El: TPasVariable; AContext: TConvertContext): TJSElement; virtual;
Function ConvertRecordType(El: TPasRecordType; AContext: TConvertContext): TJSElement; virtual;
Function ConvertClassType(El: TPasClassType; AContext: TConvertContext): TJSElement; virtual;
+ Function ConvertClassForwardType(El: TPasClassType; AContext: TConvertContext): TJSElement; virtual;
Function ConvertClassExternalType(El: TPasClassType; AContext: TConvertContext): TJSElement; virtual;
+ Function ConvertClassOfType(El: TPasClassOfType; AContext: TConvertContext): TJSElement; virtual;
Function ConvertEnumType(El: TPasEnumType; AContext: TConvertContext): TJSElement; virtual;
+ Function ConvertSetType(El: TPasSetType; AContext: TConvertContext): TJSElement; virtual;
+ Function ConvertPointerType(El: TPasPointerType; AContext: TConvertContext): TJSElement; virtual;
+ Function ConvertProcedureType(El: TPasProcedureType; AContext: TConvertContext): TJSElement; virtual;
+ Function ConvertArrayType(El: TPasArrayType; AContext: TConvertContext): TJSElement; virtual;
+ Public
+ // RTTI, TypeInfo constants
+ const
+ // TParamFlag
+ pfVar = 1;
+ pfConst = 2;
+ pfOut = 4;
+ // TProcedureFlag
+ pfStatic = 1;
+ pfVarargs = 2;
+ pfExternal = 4;
+ // TPropertyFlag
+ pfGetFunction = 1;
+ pfSetProcedure = 2;
+ pfStoredFunction = 4;
+ type
+ TMethodKind = (
+ mkProcedure, // 0 default
+ mkFunction, // 1
+ mkConstructor, // 2
+ mkDestructor, // 3
+ mkClassProcedure, // 4
+ mkClassFunction // 5
+ );
Public
Constructor Create;
destructor Destroy; override;
@@ -1069,6 +1278,7 @@ type
Property UseSwitchStatement: boolean read GetUseSwitchStatement write SetUseSwitchStatement;// default false, because slower than "if" in many engines
Property UseEnumNumbers: boolean read GetUseEnumNumbers write SetUseEnumNumbers; // default false
Property OnIsElementUsed: TPas2JSIsElementUsedEvent read FOnIsElementUsed write FOnIsElementUsed;
+ Property OnIsTypeInfoUsed: TPas2JSIsElementUsedEvent read FOnIsTypeInfoUsed write FOnIsTypeInfoUsed;
Property PreservedWords: TJSReservedWordList read FPreservedWords write SetPreservedWords;
// names
Property BuildInNames[bin: TPas2JSBuiltInName]: string read GetBuildInNames write SetBuildInNames;
@@ -1170,17 +1380,42 @@ begin
end;
end;
+function TPas2JSResolver.HasOverloadIndex(El: TPasElement): boolean;
+var
+ C: TClass;
+ ProcScope: TPasProcedureScope;
+begin
+ C:=El.ClassType;
+ if C=TPasProperty then
+ exit(false)
+ else if C=TPasClassType then
+ begin
+ if TPasClassType(El).IsForward then
+ exit(false);
+ end
+ else if C.InheritsFrom(TPasProcedure) then
+ begin
+ if TPasProcedure(El).IsOverride then
+ exit(true);
+ // Note: external proc pollutes the name space
+ ProcScope:=TPasProcedureScope(El.CustomData);
+ if ProcScope.DeclarationProc<>nil then
+ // implementation proc -> only count the header -> skip
+ exit(false);
+ end;
+ Result:=true;
+end;
+
function TPas2JSResolver.GetOverloadIndex(Identifier: TPasIdentifier;
StopAt: TPasElement): integer;
// if not found return number of overloads
// if found return index in overloads
var
El: TPasElement;
- ProcScope: TPasProcedureScope;
- C: TClass;
begin
Result:=0;
// iterate from last added to first added
+ // Note: the first added has Index=0
while Identifier<>nil do
begin
El:=Identifier.Element;
@@ -1190,23 +1425,53 @@ begin
Result:=0;
continue;
end;
- C:=El.ClassType;
- if C=TPasClassType then
- begin
- if TPasClassType(El).IsForward then
- continue;
- end
- else if C.InheritsFrom(TPasProcedure) then
+ if HasOverloadIndex(El) then
+ inc(Result);
+ end;
+end;
+
+function TPas2JSResolver.GetOverloadAt(Identifier: TPasIdentifier;
+ var Index: integer): TPasIdentifier;
+// if found Result<>nil and Index=0
+// if not found Result=nil and Index is reduced by number of overloads
+var
+ El: TPasElement;
+ CurIdent: TPasIdentifier;
+ Count: Integer;
+begin
+ if Identifier=nil then exit(nil);
+ // Note: the Identifier chain is from last added to first added
+ // -> get length of chain
+ Count:=0;
+ CurIdent:=Identifier;
+ while CurIdent<>nil do
+ begin
+ El:=CurIdent.Element;
+ CurIdent:=CurIdent.NextSameIdentifier;
+ if HasOverloadIndex(El) then
+ inc(Count);
+ end;
+ if Count<=Index then
+ begin
+ // Index is not in this scope
+ dec(Index);
+ exit(nil);
+ end;
+ // Index is in this scope -> find it
+ CurIdent:=Identifier;
+ while CurIdent<>nil do
+ begin
+ if HasOverloadIndex(CurIdent.Element) then
begin
- if TPasProcedure(El).IsOverride then
- continue;
- // Note: external proc pollute the name space
- ProcScope:=TPasProcedureScope(El.CustomData);
- if ProcScope.DeclarationProc<>nil then
- // implementation proc -> only count the header -> skip
- continue;
+ dec(Count);
+ if (Index=Count) then
+ begin
+ Index:=0;
+ Result:=CurIdent;
+ exit;
+ end;
end;
- inc(Result);
+ CurIdent:=CurIdent.NextSameIdentifier;
end;
end;
@@ -1229,19 +1494,60 @@ begin
inc(Result,GetOverloadIndex(Identifier,El));
end;
+function TPas2JSResolver.GetOverloadAt(const aName: String; Index: integer
+ ): TPasIdentifier;
+var
+ i: Integer;
+begin
+ Result:=nil;
+ for i:=FOverloadScopes.Count-1 downto 0 do
+ begin
+ // find last added
+ Result:=TPasIdentifierScope(FOverloadScopes[i]).FindLocalIdentifier(aName);
+ Result:=GetOverloadAt(Result,Index);
+ if Result<>nil then
+ exit;
+ end;
+ // find in external names
+ Result:=FindExternalName(aName);
+ Result:=GetOverloadAt(Result,Index);
+end;
+
function TPas2JSResolver.RenameOverload(El: TPasElement): boolean;
var
OverloadIndex: Integer;
+
+ function GetDuplicate: TPasElement;
+ var
+ Duplicate: TPasIdentifier;
+ begin
+ Duplicate:=GetOverloadAt(El.Name,0);
+ Result:=Duplicate.Element;
+ end;
+
+var
NewName: String;
+ Duplicate: TPasElement;
begin
// => count overloads in this section
OverloadIndex:=GetOverloadIndex(El);
if OverloadIndex=0 then
exit(false); // there is no overload
+
if (El.ClassType=TPasClassFunction)
and (TPas2JSClassScope(TPasClassType(El.Parent).CustomData).NewInstanceFunction=El) then
- RaiseMsg(20170324234324,nNewInstanceFunctionMustNotHaveOverloads,
- sNewInstanceFunctionMustNotHaveOverloads,[],El);
+ begin
+ Duplicate:=GetDuplicate;
+ RaiseMsg(20170324234324,nNewInstanceFunctionMustNotHaveOverloadAtX,
+ sNewInstanceFunctionMustNotHaveOverloadAtX,[GetElementSourcePosStr(Duplicate)],El);
+ end;
+ if El.Visibility=visPublished then
+ begin
+ Duplicate:=GetDuplicate;
+ RaiseMsg(20170413220924,nDuplicateIdentifier,sDuplicateIdentifier,
+ [Duplicate.Name,GetElementSourcePosStr(Duplicate)],El);
+ end;
+
NewName:=El.Name+'$'+IntToStr(OverloadIndex);
{$IFDEF VerbosePas2JS}
writeln('TPas2JSResolver.RenameOverload "',El.Name,'" has overload. NewName="',NewName,'"');
@@ -1456,6 +1762,18 @@ begin
end;
end;
+procedure TPas2JSResolver.FinishSetType(El: TPasSetType);
+var
+ TypeEl: TPasType;
+begin
+ inherited FinishSetType(El);
+ TypeEl:=ResolveAliasType(El.EnumType);
+ if TypeEl.ClassType=TPasEnumType then
+ // ok
+ else
+ RaiseMsg(20170415182320,nNotSupportedX,sNotSupportedX,['set of '+TypeEl.Name],El);
+end;
+
procedure TPas2JSResolver.FinishClassType(El: TPasClassType);
begin
inherited FinishClassType(El);
@@ -1514,6 +1832,10 @@ begin
end;
Include(El.VarModifiers,vmExternal);
end;
+ if El.Visibility=visPublished then
+ // Note: an external class has no typeinfo
+ RaiseMsg(20170413221516,nSymbolCannotBePublished,sSymbolCannotBePublished,
+ [],El);
end;
end
else if ParentC=TPasRecordType then
@@ -1547,6 +1869,9 @@ begin
if El.ExportName=nil then
RaiseMsg(20170227100750,nMissingExternalName,sMissingExternalName,[],El);
ExtName:=ComputeConstString(El.ExportName,true,true);
+ if (El.Visibility=visPublished) and (ExtName<>El.Name) then
+ RaiseMsg(20170407002940,nPublishedNameMustMatchExternal,
+ sPublishedNameMustMatchExternal,[],El.ExportName);
// add external name to FExternalNames
if (El.Parent is TPasSection)
or ((El.ClassType=TPasConst) and (El.Parent is TPasProcedure)) then
@@ -1562,6 +1887,7 @@ var
C: TClass;
AClass: TPasClassType;
ClassScope: TPas2JSClassScope;
+ ptm: TProcTypeModifier;
begin
inherited FinishProcedureType(El);
if El.Parent is TPasProcedure then
@@ -1577,9 +1903,13 @@ begin
if (pm in Proc.Modifiers)
and (not (pm in [pmVirtual, pmAbstract, pmOverride,
pmOverload, pmReintroduce,
- pmAssembler, pmVarargs, pmPublic,
+ pmAssembler, pmPublic,
pmExternal, pmForward])) then
RaiseNotYetImplemented(20170208142159,El,'modifier '+ModifierNames[pm]);
+ for ptm in TProcTypeModifiers do
+ if (ptm in Proc.ProcType.Modifiers)
+ and (not (ptm in [ptmOfObject,ptmVarargs])) then
+ RaiseNotYetImplemented(20170411171454,El,'modifier '+ProcTypeModifiers[ptm]);
// check pmPublic
if [pmPublic,pmExternal]<=Proc.Modifiers then
@@ -1607,6 +1937,11 @@ begin
Proc.LibrarySymbolName:=TPrimitiveExpr.Create(El,pekString,''''+Proc.Name+'''');
end;
+ if Proc.Visibility=visPublished then
+ // Note: an external class has no typeinfo
+ RaiseMsg(20170413221327,nSymbolCannotBePublished,sSymbolCannotBePublished,
+ [],Proc);
+
C:=Proc.ClassType;
if (C=TPasProcedure) or (C=TPasFunction)
or (C=TPasClassProcedure) or (C=TPasClassFunction) then
@@ -1667,7 +2002,7 @@ begin
if Proc.LibraryExpr<>nil then
RaiseMsg(20170211220712,nPasElementNotSupported,sPasElementNotSupported,
- ['library'],Proc.LibraryExpr);
+ ['external library name'],Proc.LibraryExpr);
if Proc.LibrarySymbolName=nil then
RaiseMsg(20170227095454,nMissingExternalName,sMissingExternalName,
['missing external name'],Proc);
@@ -1685,6 +2020,17 @@ begin
RaiseMsg(20170321090049,nVirtualMethodNameMustMatchExternal,
sVirtualMethodNameMustMatchExternal,[],Proc.LibrarySymbolName);
+ // a published must have the external name, so that streaming works
+ if (Proc.Visibility=visPublished) then
+ begin
+ if (Proc.Name<>ExtName) then
+ RaiseMsg(20170407002940,nPublishedNameMustMatchExternal,
+ sPublishedNameMustMatchExternal,[],Proc.LibrarySymbolName);
+ if ExtName=ExtClassBracketAccessor then
+ RaiseMsg(20170409211805,nSymbolCannotBePublished,
+ sSymbolCannotBePublished,[],Proc.LibrarySymbolName);
+ end;
+
if Proc.Parent is TPasSection then
AddExternalPath(ExtName,Proc.LibrarySymbolName);
@@ -1699,8 +2045,24 @@ var
GetterIsBracketAccessor, SetterIsBracketAccessor: Boolean;
Arg: TPasArgument;
ArgResolved: TPasResolverResult;
+ ParentC: TClass;
begin
inherited FinishPropertyOfClass(PropEl);
+
+ ParentC:=PropEl.Parent.ClassType;
+ if (ParentC=TPasClassType) then
+ begin
+ // class member
+ if TPasClassType(PropEl.Parent).IsExternal then
+ begin
+ // external class
+ if PropEl.Visibility=visPublished then
+ // Note: an external class has no typeinfo
+ RaiseMsg(20170413221703,nSymbolCannotBePublished,sSymbolCannotBePublished,
+ [],PropEl);
+ end;
+ end;
+
Getter:=GetPasPropertyGetter(PropEl);
GetterIsBracketAccessor:=IsExternalBracketAccessor(Getter);
Setter:=GetPasPropertySetter(PropEl);
@@ -1912,7 +2274,7 @@ begin
if RHS.IdentEl<>nil then
begin
if RHS.IdentEl.ClassType=TPasClassType then
- Result:=cExact+1; // RHS is a class
+ Result:=cExact+1; // RHS is a class type
end;
end;
end;
@@ -2008,75 +2370,123 @@ begin
RaiseInternalError(20170330005725);
end;
-function TPas2JSResolver.ResolveBracketOperatorClass(Params: TParamsExpr;
- const ResolvedValue: TPasResolverResult; ClassScope: TPasClassScope;
- Access: TResolvedRefAccess): boolean;
+procedure TPas2JSResolver.BI_TypeInfo_OnGetCallResult(
+ Proc: TResElDataBuiltInProc; Params: TParamsExpr; out
+ ResolvedEl: TPasResolverResult);
+// if an external type with the right name and external name is in scope return
+// that, otherwise btPointer
var
- ParamResolved: TPasResolverResult;
Param: TPasExpr;
- aClass: TPasClassType;
-begin
- if ClassScope.DefaultProperty=nil then
- begin
- aClass:=TPasClassType(ClassScope.Element);
- if IsExternalClassName(aClass,'Array') then
- begin
- if ResolvedValue.IdentEl is TPasType then
- RaiseMsg(20170402194000,nIllegalQualifier,sIllegalQualifier,['['],Params);
- if length(Params.Params)<>1 then
- RaiseMsg(20170402194059,nWrongNumberOfParametersForArray,
- sWrongNumberOfParametersForArray,[],Params);
- // check first param is an integer value
- Param:=Params.Params[0];
- ComputeElement(Param,ParamResolved,[]);
- if (not (rrfReadable in ParamResolved.Flags))
- or not (ParamResolved.BaseType in btAllInteger) then
- CheckRaiseTypeArgNo(20170402194221,1,Param,ParamResolved,'integer',true);
- AccessExpr(Param,rraRead);
- exit(true);
+ ParamResolved: TPasResolverResult;
+ C: TClass;
+ TIName: String;
+ FindData: TPRFindData;
+ Abort: boolean;
+ bt: TResolverBaseType;
+ jbt: TPas2jsBaseType;
+ TypeEl: TPasType;
+ FoundClass: TPasClassType;
+begin
+ Param:=Params.Params[0];
+ ComputeElement(Param,ParamResolved,[rcNoImplicitProc]);
+ if ParamResolved.TypeEl=nil then
+ RaiseInternalError(20170413090726);
+ TypeEl:=ResolveAliasType(ParamResolved.TypeEl);
+ C:=TypeEl.ClassType;
+ TIName:='';
+ //writeln('TPas2JSResolver.BI_TypeInfo_OnGetCallResult TypeEl=',GetObjName(TypeEl));
+ if C=TPasUnresolvedSymbolRef then
+ begin
+ if TypeEl.CustomData is TResElDataPas2JSBaseType then
+ begin
+ jbt:=TResElDataPas2JSBaseType(TypeEl.CustomData).JSBaseType;
+ if jbt=pbtJSValue then
+ TIName:=Pas2JSBuiltInNames[pbitnTI];
end
- else if IsExternalClassName(aClass,'Object') then
- begin
- if ResolvedValue.IdentEl is TPasType then
- RaiseMsg(20170402194453,nIllegalQualifier,sIllegalQualifier,['['],Params);
- if length(Params.Params)<>1 then
- RaiseMsg(20170402194456,nWrongNumberOfParametersForArray,
- sWrongNumberOfParametersForArray,[],Params);
- // check first param is a string value
- Param:=Params.Params[0];
- ComputeElement(Param,ParamResolved,[]);
- if (not (rrfReadable in ParamResolved.Flags))
- or not (ParamResolved.BaseType in btAllStringAndChars) then
- CheckRaiseTypeArgNo(20170402194511,1,Param,ParamResolved,'string',true);
- AccessExpr(Param,rraRead);
- exit(true);
+ else if TypeEl.CustomData is TResElDataBaseType then
+ begin
+ bt:=TResElDataBaseType(TypeEl.CustomData).BaseType;
+ if bt in btAllInteger then
+ TIName:=Pas2JSBuiltInNames[pbitnTIInteger]
+ else if bt in [btString,btChar,btDouble,btBoolean] then
+ TIName:=Pas2JSBuiltInNames[pbitnTI]
+ else if bt=btPointer then
+ TIName:=Pas2JSBuiltInNames[pbitnTIPointer];
end;
+ end
+ else if ParamResolved.BaseType=btContext then
+ begin
+ if C=TPasEnumType then
+ TIName:=Pas2JSBuiltInNames[pbitnTIEnum]
+ else if C=TPasSetType then
+ TIName:=Pas2JSBuiltInNames[pbitnTISet]
+ else if C.InheritsFrom(TPasProcedureType) then
+ begin
+ if TPasProcedureType(TypeEl).IsOfObject then
+ TIName:=Pas2JSBuiltInNames[pbitnTIMethodVar]
+ else
+ TIName:=Pas2JSBuiltInNames[pbitnTIProcVar];
+ end
+ else if C=TPasRecordType then
+ TIName:=Pas2JSBuiltInNames[pbitnTIRecord]
+ else if C=TPasClassType then
+ TIName:=Pas2JSBuiltInNames[pbitnTIClass]
+ else if C=TPasClassOfType then
+ TIName:=Pas2JSBuiltInNames[pbitnTIClassRef]
+ else if C=TPasArrayType then
+ begin
+ if length(TPasArrayType(TypeEl).Ranges)>0 then
+ TIName:=Pas2JSBuiltInNames[pbitnTIStaticArray]
+ else
+ TIName:=Pas2JSBuiltInNames[pbitnTIDynArray];
+ end
+ else if C=TPasPointerType then
+ TIName:=Pas2JSBuiltInNames[pbitnTIPointer]
+ end
+ else if ParamResolved.BaseType=btSet then
+ begin
+ if ParamResolved.IdentEl is TPasSetType then
+ TIName:=Pas2JSBuiltInNames[pbitnTISet];
+ end
+ else if ParamResolved.BaseType=btCustom then
+ begin
+
+ end;
+ if TIName='' then
+ begin
+ {$IFDEF VerbosePas2JS}
+ writeln('TPas2JSResolver.BI_TypeInfo_OnGetCallResult ',GetResolverResultDesc(ParamResolved));
+ {$ENDIF}
+ RaiseMsg(20170413091852,nTypeIdentifierExpected,sTypeIdentifierExpected,[],Param);
end;
- Result:=inherited ResolveBracketOperatorClass(Params, ResolvedValue, ClassScope, Access);
-end;
-procedure TPas2JSResolver.ComputeArrayParams_Class(Params: TParamsExpr;
- var ResolvedEl: TPasResolverResult; ClassScope: TPasClassScope;
- Flags: TPasResolverComputeFlags; StartEl: TPasElement);
-var
- aClass: TPasClassType;
- OrigResolved: TPasResolverResult;
-begin
- aClass:=TPasClassType(ClassScope.Element);
- if IsExternalClassName(aClass,'Array') or IsExternalClassName(aClass,'Object') then
- begin
- if [rcConstant,rcType]*Flags<>[] then
- RaiseConstantExprExp(20170402202137,Params);
- OrigResolved:=ResolvedEl;
- SetResolverTypeExpr(ResolvedEl,btCustom,JSBaseTypes[pbtJSValue],[rrfReadable,rrfWritable]);
- // identifier and value is the array/object itself
- ResolvedEl.IdentEl:=OrigResolved.IdentEl;
- ResolvedEl.ExprEl:=OrigResolved.ExprEl;
- ResolvedEl.Flags:=OrigResolved.Flags+[rrfReadable,rrfWritable];
- exit;
+ // search for TIName
+ FindData:=Default(TPRFindData);
+ FindData.ErrorPosEl:=Params;
+ Abort:=false;
+ IterateElements(TIName,@OnFindFirstElement,@FindData,Abort);
+ {$IFDEF VerbosePas2JS}
+ writeln('TPas2JSResolver.BI_TypeInfo_OnGetCallResult TIName="',TIName,'" FindData.Found="',GetObjName(FindData.Found),'"');
+ {$ENDIF}
+ if (FindData.Found<>nil) and (FindData.Found.ClassType=TPasClassType) then
+ begin
+ FoundClass:=TPasClassType(FindData.Found);
+ if FoundClass.IsExternal
+ and (FoundClass.ExternalName=Pas2JSBuiltInNames[pbivnRTL]+'.'+TIName) then
+ begin
+ // use external class definition
+ {$IFDEF VerbosePas2JS}
+ writeln('TPas2JSResolver.BI_TypeInfo_OnGetCallResult FindData.Found="',FindData.Found.FullName,'"');
+ {$ENDIF}
+ SetResolverTypeExpr(ResolvedEl,btContext,TPasClassType(FindData.Found),[rrfReadable]);
+ exit;
+ end;
end;
- inherited ComputeArrayParams_Class(Params, ResolvedEl, ClassScope, Flags,
- StartEl);
+
+ // default: btPointer
+ SetResolverTypeExpr(ResolvedEl,btPointer,BaseTypes[btPointer],[rrfReadable]);
+
+ if Proc=nil then ;
end;
constructor TPas2JSResolver.Create;
@@ -2091,6 +2501,7 @@ begin
ScopeClass_WithExpr:=TPas2JSWithExprScope;
for bt in [pbtJSValue] do
AddJSBaseType(Pas2jsBaseTypeNames[bt],bt);
+ AnonymousElTypePostfix:=Pas2JSBuiltInNames[pbitnAnonymousPostfix];
end;
destructor TPas2JSResolver.Destroy;
@@ -2103,12 +2514,21 @@ end;
procedure TPas2JSResolver.AddObjFPCBuiltInIdentifiers(
const TheBaseTypes: TResolveBaseTypes;
const TheBaseProcs: TResolverBuiltInProcs);
+var
+ InvalidTypes: TResolveBaseTypes;
+ bt: TResolverBaseType;
+ InvalidProcs: TResolverBuiltInProcs;
+ bf: TResolverBuiltInProc;
begin
- inherited AddObjFPCBuiltInIdentifiers(
- TheBaseTypes
- -btAllStrings+[btString] // allow only String
- -btAllFloats+[btDouble] // allow only Double
- ,TheBaseProcs);
+ InvalidTypes:=TheBaseTypes-btAllPas2jsBaseTypes;
+ if InvalidTypes<>[] then
+ for bt in InvalidTypes do
+ RaiseInternalError(20170409180202,BaseTypeNames[bt]);
+ InvalidProcs:=TheBaseProcs-bfAllPas2jsBaseProcs;
+ if InvalidProcs<>[] then
+ for bf in InvalidProcs do
+ RaiseInternalError(20170409180246,ResolverBuiltInProcNames[bf]);
+ inherited AddObjFPCBuiltInIdentifiers(TheBaseTypes,TheBaseProcs);
end;
function TPas2JSResolver.CheckTypeCastRes(const FromResolved,
@@ -2167,11 +2587,8 @@ begin
Result:=cExact+1 // type cast JSValue to simple base type
else if ToResolved.BaseType=btContext then
begin
- C:=ToResolved.TypeEl.ClassType;
- if (C=TPasClassType)
- or (C=TPasClassOfType)
- or (C=TPasEnumType) then
- Result:=cExact+1;
+ // typecast JSValue to user type
+ Result:=cExact+1;
end;
end;
exit;
@@ -2440,6 +2857,16 @@ begin
AddElementData(Result);
end;
+function TPas2JSResolver.HasTypeInfo(El: TPasType): boolean;
+begin
+ Result:=inherited HasTypeInfo(El);
+ if not Result then exit;
+ if (El.ClassType=TPasClassType) and TPasClassType(El).IsExternal then
+ exit(false);
+ if El.Parent is TProcedureBody then
+ Result:=false;
+end;
+
{ TP2JConstExprData }
destructor TP2JConstExprData.Destroy;
@@ -2533,9 +2960,9 @@ begin
Kind:=cjkDot;
end;
-{ TInterfaceContext }
+{ TSectionContext }
-constructor TInterfaceContext.Create(PasEl: TPasElement; JSEl: TJSElement;
+constructor TSectionContext.Create(PasEl: TPasElement; JSEl: TJSElement;
aParent: TConvertContext);
begin
inherited;
@@ -2742,33 +3169,45 @@ end;
function TPasToJSConverter.ConvertModule(El: TPasModule;
AContext: TConvertContext): TJSElement;
-(* Format:
- rtl.module('<unitname>',
- [<interface uses1>,<uses2>, ...],
- function(){
- <interface>
- <implementation>
- this.$init=function(){
- <initialization>
- };
- },
- [<implementation uses1>,<uses2>, ...]);
+(*
+Program:
+ rtl.module('program',
+ [<uses1>,<uses2>, ...],
+ function(){
+ <programsection>
+ this.$main=function(){
+ <initialization>
+ };
+ });
+
+Unit:
+ rtl.module('<unitname>',
+ [<interface uses1>,<uses2>, ...],
+ function(){
+ var $impl = {};
+ this.$impl = $impl;
+ <interface>
+ this.$init=function(){
+ <initialization>
+ };
+ },
+ [<implementation uses1>,<uses2>, ...],
+ function(){
+ var $impl = this.$impl;
+ <implementation>
+ });
*)
Var
OuterSrc , Src: TJSSourceElements;
RegModuleCall: TJSCallExpression;
ArgArray: TJSArguments;
UsesList: TFPList;
- FunDef: TJSFuncDef;
- FunBody: TJSFunctionBody;
- FunDecl: TJSFunctionDeclarationStatement;
+ FunDecl, ImplFunc: TJSFunctionDeclarationStatement;
UsesSection: TPasSection;
ModuleName: String;
- IntfContext: TInterfaceContext;
+ IntfContext: TSectionContext;
ImplVarSt: TJSVariableStatement;
- VarDecl: TJSVarDeclaration;
- ImplAssignSt: TJSSimpleAssignStatement;
- ImplDecl: TJSElement;
+ HasImplUsesList: Boolean;
begin
Result:=Nil;
OuterSrc:=TJSSourceElements(CreateElement(TJSSourceElements, El));
@@ -2782,7 +3221,7 @@ begin
RegModuleCall.Args:=ArgArray;
// add unitname parameter: unitname
- ModuleName:=TransformModuleName(El,AContext);
+ ModuleName:=TransformModuleName(El,false,AContext);
ArgArray.Elements.AddElement.Expr:=CreateLiteralString(El,ModuleName);
// add interface-uses-section parameter: [<interface uses1>,<uses2>, ...]
@@ -2796,20 +3235,17 @@ begin
ArgArray.Elements.AddElement.Expr:=CreateUsesList(UsesSection,AContext);
// add interface parameter: function(){}
- FunDecl:=TJSFunctionDeclarationStatement.Create(0,0);
+ FunDecl:=CreateFunction(El,true,true);
ArgArray.Elements.AddElement.Expr:=FunDecl;
- FunDef:=TJSFuncDef.Create;
- FunDecl.AFunction:=FunDef;
- FunDef.Name:='';
- FunBody:=TJSFunctionBody.Create(0,0);
- FunDef.Body:=FunBody;
- Src:=TJSSourceElements(CreateElement(TJSSourceElements, El));
- FunBody.A:=Src;
+ Src:=FunDecl.AFunction.Body.A as TJSSourceElements;
if coUseStrict in Options then
AddToSourceElements(Src,CreateLiteralString(El,'use strict'));
- IntfContext:=TInterfaceContext.Create(El,Src,AContext);
+ ImplVarSt:=nil;
+ HasImplUsesList:=false;
+
+ IntfContext:=TSectionContext.Create(El,Src,AContext);
try
IntfContext.This:=El;
if (El is TPasProgram) then
@@ -2827,37 +3263,15 @@ begin
else
begin // unit
// add implementation object at top, so the interface elemwnts can add stuff
- if (FBuiltInNames[pbivnImplementation]<>'') and Assigned(El.ImplementationSection) then
+ if Assigned(El.ImplementationSection) then
begin
- // add 'var $impl = {};'
- ImplVarSt:=TJSVariableStatement(CreateElement(TJSVariableStatement,El));
+ // add var $impl = this.$impl
+ ImplVarSt:=CreateVarStatement(FBuiltInNames[pbivnImplementation],
+ CreateMemberExpression(['this',FBuiltInNames[pbivnImplementation]]),El);
AddToSourceElements(Src,ImplVarSt);
- VarDecl:=TJSVarDeclaration(CreateElement(TJSVarDeclaration,El));
- ImplVarSt.A:=VarDecl;
- VarDecl.Name:=FBuiltInNames[pbivnImplementation];
- VarDecl.Init:=TJSEmptyBlockStatement(CreateElement(TJSEmptyBlockStatement,El.ImplementationSection));
- // add 'this.$impl = $impl;'
- ImplAssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
- AddToSourceElements(Src,ImplAssignSt);
- ImplAssignSt.LHS:=CreateBuiltInIdentifierExpr('this.'+FBuiltInNames[pbivnImplementation]);
- ImplAssignSt.Expr:=CreateBuiltInIdentifierExpr(FBuiltInNames[pbivnImplementation]);
- end
- else
- begin
- ImplVarSt:=nil;
- ImplAssignSt:=nil;
end;
if Assigned(El.InterfaceSection) then
AddToSourceElements(Src,ConvertDeclarations(El.InterfaceSection,IntfContext));
- if ImplVarSt<>nil then
- begin
- ImplDecl:=CreateImplementationSection(El,Src,IntfContext);
- if ImplDecl=nil then
- begin
- RemoveFromSourceElements(Src,ImplVarSt);
- RemoveFromSourceElements(Src,ImplAssignSt);
- end;
- end;
CreateInitSection(El,Src,IntfContext);
// add optional implementation uses list: [<implementation uses1>,<uses2>, ...]
@@ -2865,12 +3279,34 @@ begin
begin
UsesList:=El.ImplementationSection.UsesList;
if (UsesList<>nil) and (UsesList.Count>0) then
+ begin
ArgArray.Elements.AddElement.Expr:=CreateUsesList(El.ImplementationSection,AContext);
+ HasImplUsesList:=true;
+ end;
end;
+
end;
finally
IntfContext.Free;
end;
+
+ // add implementation function
+ if ImplVarSt<>nil then
+ begin
+ ImplFunc:=CreateImplementationSection(El,AContext);
+ if ImplFunc=nil then
+ begin
+ // remove unneeded $impl from interface
+ RemoveFromSourceElements(Src,ImplVarSt);
+ end
+ else
+ begin
+ // add param
+ if not HasImplUsesList then
+ ArgArray.Elements.AddElement.Expr:=CreateLiteralNull(El);
+ ArgArray.Elements.AddElement.Expr:=ImplFunc;
+ end;
+ end;
end;
function TPasToJSConverter.CreateElement(C: TJSElementClass; Src: TPasElement
@@ -2937,18 +3373,26 @@ begin
Result:=C;
end;
-function TPasToJSConverter.CreateFunction(El: TPasElement; WithBody: boolean
- ): TJSFunctionDeclarationStatement;
+function TPasToJSConverter.CreateFunction(El: TPasElement; WithBody: boolean;
+ WithSrc: boolean): TJSFunctionDeclarationStatement;
var
FuncDef: TJSFuncDef;
FuncSt: TJSFunctionDeclarationStatement;
+ Src: TJSSourceElements;
begin
FuncSt:=TJSFunctionDeclarationStatement(CreateElement(TJSFunctionDeclarationStatement,El));
Result:=FuncSt;
FuncDef:=TJSFuncDef.Create;
FuncSt.AFunction:=FuncDef;
if WithBody then
+ begin
FuncDef.Body:=TJSFunctionBody(CreateElement(TJSFunctionBody,El));
+ if WithSrc then
+ begin
+ Src:=TJSSourceElements(CreateElement(TJSSourceElements, El));
+ FuncDef.Body.A:=Src;
+ end;
+ end;
end;
function TPasToJSConverter.ConvertUnaryExpression(El: TUnaryExpr;
@@ -3117,6 +3561,66 @@ begin
Result:=false;
end;
+procedure TPasToJSConverter.ComputeRange(
+ const RangeResolved: TPasResolverResult; out MinValue, MaxValue: int64;
+ ErrorEl: TPasElement);
+var
+ EnumType: TPasEnumType;
+begin
+ if RangeResolved.BaseType in btAllBooleans then
+ begin
+ MinValue:=0;
+ MaxValue:=1;
+ end
+ else if RangeResolved.BaseType=btShortInt then
+ begin
+ MinValue:=-$80;
+ MaxValue:=-$7f;
+ end
+ else if RangeResolved.BaseType=btByte then
+ begin
+ MinValue:=0;
+ MaxValue:=$ff;
+ end
+ else if RangeResolved.BaseType=btSmallInt then
+ begin
+ MinValue:=-$8000;
+ MaxValue:=$7fff;
+ end
+ else if RangeResolved.BaseType=btWord then
+ begin
+ MinValue:=0;
+ MaxValue:=$ffff;
+ end
+ else if RangeResolved.BaseType=btLongint then
+ begin
+ MinValue:=-$80000000;
+ MaxValue:=$7fffffff;
+ end
+ else if RangeResolved.BaseType=btCardinal then
+ begin
+ MinValue:=0;
+ MaxValue:=$ffffffff;
+ end
+ else if RangeResolved.BaseType in [btChar,btWideChar] then
+ begin
+ MinValue:=0;
+ MaxValue:=$ffff;
+ end
+ else if RangeResolved.BaseType=btContext then
+ begin
+ if RangeResolved.TypeEl.ClassType=TPasEnumType then
+ begin
+ EnumType:=TPasEnumType(RangeResolved.TypeEl);
+ MinValue:=0;
+ MaxValue:=EnumType.Values.Count-1;
+ end;
+ end
+ else
+ DoError(20170411224022,nPasElementNotSupported,sPasElementNotSupported,
+ [BaseTypeNames[RangeResolved.BaseType]],ErrorEl);
+end;
+
function TPasToJSConverter.ConvertBinaryExpression(El: TBinaryExpr;
AContext: TConvertContext): TJSElement;
Const
@@ -3229,8 +3733,8 @@ begin
else
// otherwise -> "rtl.as(A,B)"
Call.Expr:=CreateBuiltInIdentifierExpr(FBuiltInNames[pbivnRTL]+'.'+FBuiltInNames[pbifnAs]);
- Call.Args.Elements.AddElement.Expr:=A;
- Call.Args.Elements.AddElement.Expr:=B;
+ Call.AddArg(A);
+ Call.AddArg(B);
Result:=Call;
exit;
end;
@@ -3273,7 +3777,7 @@ begin
begin
// convert "a div b" to "Math.floor(a/b)"
Call:=CreateCallExpression(El);
- Call.Args.Elements.AddElement.Expr:=R;
+ Call.AddArg(R);
Call.Expr:=CreateBuiltInIdentifierExpr('Math.floor');
Result:=Call;
end;
@@ -3299,9 +3803,9 @@ function TPasToJSConverter.ConvertBinaryExpressionRes(El: TBinaryExpr;
// convert "proctypeA = proctypeB" to "rtl.eqCallback(proctypeA,proctypeB)"
Call:=CreateCallExpression(El);
Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnProcType_Equal]]);
- Call.Args.Elements.AddElement.Expr:=A;
+ Call.AddArg(A);
A:=nil;
- Call.Args.Elements.AddElement.Expr:=B;
+ Call.AddArg(B);
B:=nil;
if El.OpCode=eopNotEqual then
begin
@@ -3317,9 +3821,9 @@ function TPasToJSConverter.ConvertBinaryExpressionRes(El: TBinaryExpr;
var
FunName: String;
Call: TJSCallExpression;
- Bracket: TJSBracketMemberExpression;
DotExpr: TJSDotMemberExpression;
NotEl: TJSUnaryNotExpression;
+ InOp: TJSRelationalExpressionIn;
begin
{$IFDEF VerbosePas2JS}
writeln('TPasToJSConverter.ConvertBinaryExpressionRes OpCode="',OpcodeStrings[El.OpCode],'" Left=',GetResolverResultDesc(LeftResolved),' Right=',GetResolverResultDesc(RightResolved));
@@ -3342,22 +3846,27 @@ begin
end;
Call:=CreateCallExpression(El);
Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FunName]);
- Call.Args.Elements.AddElement.Expr:=A;
+ Call.AddArg(A);
A:=nil;
- Call.Args.Elements.AddElement.Expr:=B;
+ Call.AddArg(B);
B:=nil;
Result:=Call;
exit;
end
else if (RightResolved.BaseType=btSet) and (El.OpCode=eopIn) then
begin
- // a in b -> b[a]
- Bracket:=TJSBracketMemberExpression(CreateElement(TJSBracketMemberExpression,El));
- Bracket.MExpr:=B;
- B:=nil;
- Bracket.Name:=A;
+ // a in b -> a in b
+ if not (A is TJSLiteral) or (TJSLiteral(A).Value.ValueType<>jstNumber) then
+ begin
+ FreeAndNil(A);
+ A:=CreateSetLiteralElement(El.left,AContext);
+ end;
+ InOp:=TJSRelationalExpressionIn(CreateElement(TJSRelationalExpressionIn,El));
+ InOp.A:=A;
A:=nil;
- Result:=Bracket;
+ InOp.B:=B;
+ B:=nil;
+ Result:=InOp;
exit;
end
else if (El.OpCode=eopIs) then
@@ -3365,7 +3874,7 @@ begin
// "A is B"
Call:=CreateCallExpression(El);
Result:=Call;
- Call.Args.Elements.AddElement.Expr:=A; A:=nil;
+ Call.AddArg(A); A:=nil;
if RightResolved.IdentEl is TPasClassOfType then
begin
// "A is class-of-type" -> "A is class"
@@ -3376,13 +3885,13 @@ begin
begin
// B is an external class -> "rtl.isExt(A,B)"
Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnIsExt]]);
- Call.Args.Elements.AddElement.Expr:=B; B:=nil;
+ Call.AddArg(B); B:=nil;
end
else if LeftResolved.TypeEl is TPasClassOfType then
begin
// A is a TPasClassOfType -> "rtl.is(A,B)"
Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnIs]]);
- Call.Args.Elements.AddElement.Expr:=B; B:=nil;
+ Call.AddArg(B); B:=nil;
end
else
begin
@@ -3415,7 +3924,7 @@ begin
Call:=CreateCallExpression(El);
Call.Expr:=CreateDotExpression(El,A,CreateBuiltInIdentifierExpr(FBuiltInNames[pbifnRecordEqual]));
A:=nil;
- Call.Args.Elements.AddElement.Expr:=B;
+ Call.AddArg(B);
B:=nil;
if El.OpCode=eopNotEqual then
begin
@@ -3544,7 +4053,7 @@ var
CurName: String;
begin
CurName:=TransformVariableName(El,Name,AContext);
- if (FBuiltInNames[pbivnImplementation]<>'') and (El.Parent.ClassType=TImplementationSection) then
+ if El.Parent.ClassType=TImplementationSection then
CurName:=FBuiltInNames[pbivnImplementation]+'.'+CurName
else
CurName:='this.'+CurName;
@@ -3690,7 +4199,7 @@ begin
Call:=CreateCallExpression(El);
AssignContext.Call:=Call;
Call.Expr:=CreateReferencePathExpr(Decl,AContext,false,Ref);
- Call.Args.Elements.AddElement.Expr:=AssignContext.RightSide;
+ Call.AddArg(AssignContext.RightSide);
AssignContext.RightSide:=nil;
Result:=Call;
exit;
@@ -3734,7 +4243,7 @@ begin
Call.Expr:=CreateDotExpression(El,
CreateIdentifierExpr(Arg.Name,Arg,AContext),
CreateBuiltInIdentifierExpr(TempRefObjSetterName));
- Call.Args.Elements.AddElement.Expr:=AssignContext.RightSide;
+ Call.AddArg(AssignContext.RightSide);
AssignContext.RightSide:=nil;
Result:=Call;
exit;
@@ -3763,7 +4272,7 @@ begin
case BuiltInProc.BuiltIn of
bfBreak: Result:=ConvertBuiltInBreak(El,AContext);
bfContinue: Result:=ConvertBuiltInContinue(El,AContext);
- bfExit: Result:=ConvertBuiltInExit(El,AContext);
+ bfExit: Result:=ConvertBuiltIn_Exit(El,AContext);
else
RaiseNotSupported(El,AContext,20161130164955,'built in proc '+ResolverBuiltInProcNames[BuiltInProc.BuiltIn]);
end;
@@ -3776,7 +4285,7 @@ begin
writeln('TPasToJSConverter.ConvertIdentifierExpr ',GetObjName(El),' Decl=',GetObjName(Decl),' Decl.Parent=',GetObjName(Decl.Parent));
{$ENDIF}
if Decl is TPasModule then
- Name:=FBuiltInNames[pbivnModules]+'.'+TransformModuleName(TPasModule(Decl),AContext)
+ Name:=TransformModuleName(TPasModule(Decl),true,AContext)
else if (Decl is TPasFunctionType) and (CompareText(ResolverResultVar,El.Value)=0) then
Name:=ResolverResultVar
else if Decl.ClassType=TPasEnumValue then
@@ -3891,9 +4400,9 @@ function TPasToJSConverter.ConvertInheritedExpression(El: TInheritedExpr;
try
Call:=CreateCallExpression(ParentEl);
Call.Expr:=CreateBuiltInIdentifierExpr(FunName);
- Call.Args.Elements.AddElement.Expr:=CreateBuiltInIdentifierExpr('this');
+ Call.AddArg(CreateBuiltInIdentifierExpr('this'));
if Apply then
- Call.Args.Elements.AddElement.Expr:=CreateBuiltInIdentifierExpr('arguments')
+ Call.AddArg(CreateBuiltInIdentifierExpr('arguments'))
else
CreateProcedureCall(Call,ParamsExpr,AncestorProc.ProcType,AContext);
Result:=Call;
@@ -4394,7 +4903,7 @@ begin
if AContext.Resolver=nil then
begin
// without Resolver
- if Length(El.Params)<>1 then
+ if Length(El.Params)>1 then
RaiseNotSupported(El,AContext,20170207151325,'Cannot convert 2-dim arrays');
B:=TJSBracketMemberExpression(CreateElement(TJSBracketMemberExpression,El));
try
@@ -4432,12 +4941,9 @@ begin
if TypeEl.ClassType=TPasClassType then
begin
aClass:=TPasClassType(TypeEl);
- ClassScope:=TypeEl.CustomData as TPas2JSClassScope;
+ ClassScope:=aClass.CustomData as TPas2JSClassScope;
if ClassScope.DefaultProperty<>nil then
ConvertDefaultProperty(ResolvedEl,ClassScope.DefaultProperty)
- else if AContext.Resolver.IsExternalClassName(aClass,'Array')
- or AContext.Resolver.IsExternalClassName(aClass,'Object') then
- ConvertJSObject
else
RaiseInconsistency(20170206180448);
end
@@ -4468,7 +4974,7 @@ var
Elements: TJSArrayLiteralElements;
E: TJSArrayLiteral;
OldAccess: TCtxAccess;
- DeclResolved, ParamResolved: TPasResolverResult;
+ DeclResolved, ParamResolved, ValueResolved: TPasResolverResult;
Param: TPasExpr;
JSBaseType: TPas2jsBaseType;
C: TClass;
@@ -4498,26 +5004,27 @@ begin
writeln('TPasToJSConverter.ConvertFuncParams ',Decl.Name,' ',ResolverBuiltInProcNames[BuiltInProc.BuiltIn]);
{$ENDIF}
case BuiltInProc.BuiltIn of
- bfLength: Result:=ConvertBuiltInLength(El,AContext);
- bfSetLength: Result:=ConvertBuiltInSetLength(El,AContext);
- bfInclude: Result:=ConvertBuiltInExcludeInclude(El,AContext,true);
- bfExclude: Result:=ConvertBuiltInExcludeInclude(El,AContext,false);
- bfExit: Result:=ConvertBuiltInExit(El,AContext);
+ bfLength: Result:=ConvertBuiltIn_Length(El,AContext);
+ bfSetLength: Result:=ConvertBuiltIn_SetLength(El,AContext);
+ bfInclude: Result:=ConvertBuiltIn_ExcludeInclude(El,AContext,true);
+ bfExclude: Result:=ConvertBuiltIn_ExcludeInclude(El,AContext,false);
+ bfExit: Result:=ConvertBuiltIn_Exit(El,AContext);
bfInc,
- bfDec: Result:=ConvertBuiltInIncDec(El,AContext);
- bfAssigned: Result:=ConvertBuiltInAssigned(El,AContext);
- bfChr: Result:=ConvertBuiltInChr(El,AContext);
- bfOrd: Result:=ConvertBuiltInOrd(El,AContext);
- bfLow: Result:=ConvertBuiltInLow(El,AContext);
- bfHigh: Result:=ConvertBuiltInHigh(El,AContext);
- bfPred: Result:=ConvertBuiltInPred(El,AContext);
- bfSucc: Result:=ConvertBuiltInSucc(El,AContext);
- bfStrProc: Result:=ConvertBuiltInStrProc(El,AContext);
- bfStrFunc: Result:=ConvertBuiltInStrFunc(El,AContext);
- bfConcatArray: Result:=ConvertBuiltInConcatArray(El,AContext);
- bfCopyArray: Result:=ConvertBuiltInCopyArray(El,AContext);
- bfInsertArray: Result:=ConvertBuiltInInsertArray(El,AContext);
- bfDeleteArray: Result:=ConvertBuiltInDeleteArray(El,AContext);
+ bfDec: Result:=ConvertBuiltIn_IncDec(El,AContext);
+ bfAssigned: Result:=ConvertBuiltIn_Assigned(El,AContext);
+ bfChr: Result:=ConvertBuiltIn_Chr(El,AContext);
+ bfOrd: Result:=ConvertBuiltIn_Ord(El,AContext);
+ bfLow: Result:=ConvertBuiltIn_Low(El,AContext);
+ bfHigh: Result:=ConvertBuiltIn_High(El,AContext);
+ bfPred: Result:=ConvertBuiltIn_Pred(El,AContext);
+ bfSucc: Result:=ConvertBuiltIn_Succ(El,AContext);
+ bfStrProc: Result:=ConvertBuiltIn_StrProc(El,AContext);
+ bfStrFunc: Result:=ConvertBuiltIn_StrFunc(El,AContext);
+ bfConcatArray: Result:=ConvertBuiltIn_ConcatArray(El,AContext);
+ bfCopyArray: Result:=ConvertBuiltIn_CopyArray(El,AContext);
+ bfInsertArray: Result:=ConvertBuiltIn_InsertArray(El,AContext);
+ bfDeleteArray: Result:=ConvertBuiltIn_DeleteArray(El,AContext);
+ bfTypeInfo: Result:=ConvertBuiltIn_TypeInfo(El,AContext);
else
RaiseNotSupported(El,AContext,20161130164955,'built in proc '+ResolverBuiltInProcNames[BuiltInProc.BuiltIn]);
end;
@@ -4572,7 +5079,7 @@ begin
// TObject(jsvalue) -> rtl.getObject(jsvalue)
Call:=CreateCallExpression(El);
Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnGetObject]]);
- Call.Args.Elements.AddElement.Expr:=Result;
+ Call.AddArg(Result);
Result:=Call;
end;
end;
@@ -4598,7 +5105,19 @@ begin
else if (C=TPasProcedureType)
or (C=TPasFunctionType) then
begin
- TargetProcType:=TPasProcedureType(Decl);
+ AContext.Resolver.ComputeElement(El.Value,ValueResolved,[rcNoImplicitProc]);
+ if ValueResolved.IdentEl is TPasProcedureType then
+ begin
+ // type cast to proc type
+ Param:=El.Params[0];
+ Result:=ConvertElement(Param,AContext);
+ exit;
+ end
+ else
+ begin
+ // calling proc var
+ TargetProcType:=TPasProcedureType(Decl);
+ end;
end
else
begin
@@ -4728,9 +5247,9 @@ begin
end;
function TPasToJSConverter.ConvertTypeCastToBaseType(El: TParamsExpr;
- AContext: TConvertContext; BaseTypeData: TResElDataBaseType): TJSElement;
+ AContext: TConvertContext; ToBaseTypeData: TResElDataBaseType): TJSElement;
var
- bt: TResolverBaseType;
+ to_bt: TResolverBaseType;
Param: TPasExpr;
ParamResolved: TPasResolverResult;
NotEqual: TJSEqualityExpressionNE;
@@ -4763,8 +5282,8 @@ begin
JSBaseTypeData:=nil;
JSBaseType:=pbtNone;
- bt:=BaseTypeData.BaseType;
- if bt in btAllInteger then
+ to_bt:=ToBaseTypeData.BaseType;
+ if to_bt in btAllInteger then
begin
if ParamResolved.BaseType in btAllInteger then
begin
@@ -4793,13 +5312,13 @@ begin
// Note: convert value first in case it raises an exception
Call:=CreateCallExpression(El);
Call.Expr:=CreateMemberExpression(['Math','floor']);
- Call.Args.Elements.AddElement.Expr:=Result;
+ Call.AddArg(Result);
Result:=Call;
exit;
end;
end;
end
- else if bt in btAllBooleans then
+ else if to_bt in btAllBooleans then
begin
if ParamResolved.BaseType in btAllBooleans then
begin
@@ -4834,7 +5353,7 @@ begin
end;
end;
end
- else if bt in btAllFloats then
+ else if to_bt in btAllFloats then
begin
if ParamResolved.BaseType in (btAllFloats+btAllInteger) then
begin
@@ -4851,13 +5370,13 @@ begin
// Note: convert value first in case it raises an exception
Call:=CreateCallExpression(El);
Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnGetNumber]]);
- Call.Args.Elements.AddElement.Expr:=Result;
+ Call.AddArg(Result);
Result:=Call;
exit;
end;
end;
end
- else if bt in btAllStrings then
+ else if to_bt in btAllStrings then
begin
if ParamResolved.BaseType in btAllStringAndChars then
begin
@@ -4880,7 +5399,7 @@ begin
end;
end;
end
- else if bt=btChar then
+ else if to_bt=btChar then
begin
if ParamResolved.BaseType=btChar then
begin
@@ -4897,15 +5416,33 @@ begin
// Note: convert value first in case it raises an exception
Call:=CreateCallExpression(El);
Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnGetChar]]);
- Call.Args.Elements.AddElement.Expr:=Result;
+ Call.AddArg(Result);
Result:=Call;
exit;
end;
end;
end
- else if (bt=btCustom) and (BaseTypeData is TResElDataPas2JSBaseType) then
+ else if to_bt=btPointer then
+ begin
+ if IsParamPas2JSBaseType then
+ begin
+ if JSBaseType=pbtJSValue then
+ begin
+ // convert jsvalue to pointer -> pass through
+ Result:=ConvertElement(Param,AContext);
+ exit;
+ end;
+ end
+ else if ParamResolved.BaseType=btContext then
+ begin
+ // convert user type/value to pointer -> pass through
+ Result:=ConvertElement(Param,AContext);
+ exit;
+ end;
+ end
+ else if (to_bt=btCustom) and (ToBaseTypeData is TResElDataPas2JSBaseType) then
begin
- JSBaseType:=TResElDataPas2JSBaseType(BaseTypeData).JSBaseType;
+ JSBaseType:=TResElDataPas2JSBaseType(ToBaseTypeData).JSBaseType;
if JSBaseType=pbtJSValue then
begin
// type cast to jsvalue
@@ -4920,7 +5457,7 @@ begin
// TObject(vsvalue) -> rtl.getObject(vsvalue)
Call:=CreateCallExpression(El);
Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnGetObject]]);
- Call.Args.Elements.AddElement.Expr:=Result;
+ Call.AddArg(Result);
Result:=Call;
end;
end;
@@ -4928,7 +5465,7 @@ begin
end;
end;
{$IFDEF VerbosePas2JS}
- writeln('TPasToJSConverter.ConvertTypeCastToBaseType BaseTypeData=',BaseTypeNames[bt],' ParamResolved=',GetResolverResultDesc(ParamResolved));
+ writeln('TPasToJSConverter.ConvertTypeCastToBaseType BaseTypeData=',BaseTypeNames[to_bt],' ParamResolved=',GetResolverResultDesc(ParamResolved));
{$ENDIF}
RaiseNotSupported(El,AContext,20170325161150);
end;
@@ -4938,8 +5475,15 @@ function TPasToJSConverter.ConvertSetLiteral(El: TParamsExpr;
var
Call: TJSCallExpression;
ArgContext: TConvertContext;
+
+ procedure AddArg(Expr: TPasExpr);
+ begin
+ Result:=CreateSetLiteralElement(Expr,ArgContext);
+ Call.AddArg(Result);
+ end;
+
+var
i: Integer;
- Arg: TJSElement;
ArgEl: TPasExpr;
begin
if El.Kind<>pekSet then
@@ -4966,21 +5510,12 @@ begin
if (ArgEl.ClassType=TBinaryExpr) and (TBinaryExpr(ArgEl).Kind=pekRange) then
begin
// range -> add three parameters: null,left,right
- // ToDo: error if left>right
- // add null
- Call.Args.Elements.AddElement.Expr:=CreateLiteralNull(ArgEl);
- // add left
- Arg:=ConvertElement(TBinaryExpr(ArgEl).left,ArgContext);
- Call.Args.Elements.AddElement.Expr:=Arg;
- // add right
- Arg:=ConvertElement(TBinaryExpr(ArgEl).right,ArgContext);
- Call.Args.Elements.AddElement.Expr:=Arg;
+ Call.AddArg(CreateLiteralNull(ArgEl));
+ AddArg(TBinaryExpr(ArgEl).left);
+ AddArg(TBinaryExpr(ArgEl).right);
end
else
- begin
- Arg:=ConvertElement(ArgEl,ArgContext);
- Call.Args.Elements.AddElement.Expr:=Arg;
- end;
+ AddArg(ArgEl);
end;
Result:=Call;
finally
@@ -5025,14 +5560,15 @@ begin
end;
end;
-function TPasToJSConverter.ConvertBuiltInLength(El: TParamsExpr;
+function TPasToJSConverter.ConvertBuiltIn_Length(El: TParamsExpr;
AContext: TConvertContext): TJSElement;
var
Arg: TJSElement;
- Param: TPasExpr;
+ Param, RangeEl: TPasExpr;
ParamResolved, RangeResolved: TPasResolverResult;
Ranges: TPasExprArray;
Call: TJSCallExpression;
+ aMinValue, aMaxValue: int64;
begin
Result:=nil;
Param:=El.Params[0];
@@ -5047,20 +5583,11 @@ begin
// static array -> number literal
if length(Ranges)>1 then
RaiseNotSupported(El,AContext,20170223131042);
- AContext.Resolver.ComputeElement(Ranges[0],RangeResolved,[rcConstant]);
- if RangeResolved.BaseType=btContext then
- begin
- if RangeResolved.IdentEl is TPasEnumType then
- begin
- Result:=CreateLiteralNumber(El,TPasEnumType(RangeResolved.IdentEl).Values.Count);
- exit;
- end;
- end
- else if RangeResolved.BaseType=btBoolean then
- begin
- Result:=CreateLiteralNumber(El,2);
- exit;
- end;
+ RangeEl:=Ranges[0];
+ AContext.Resolver.ComputeElement(RangeEl,RangeResolved,[rcType]);
+ ComputeRange(RangeResolved,aMinValue,aMaxValue,RangeEl);
+ Result:=CreateLiteralNumber(El,aMaxValue-aMinValue+1);
+ exit;
end
else
begin
@@ -5069,7 +5596,7 @@ begin
// Note: convert param first, it may raise an exception
Call:=CreateCallExpression(El);
Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnArray_Length]]);
- Call.Args.Elements.AddElement.Expr:=Result;
+ Call.AddArg(Result);
Result:=Call;
exit;
end;
@@ -5081,7 +5608,7 @@ begin
Result:=CreateDotExpression(El,Arg,CreateBuiltInIdentifierExpr('length'));
end;
-function TPasToJSConverter.ConvertBuiltInSetLength(El: TParamsExpr;
+function TPasToJSConverter.ConvertBuiltIn_SetLength(El: TParamsExpr;
AContext: TConvertContext): TJSElement;
// convert "SetLength(a,Len)" to "a = rtl.arraySetLength(a,Len)"
var
@@ -5122,16 +5649,16 @@ begin
AssignContext.RightSide:=Call;
Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnArray_SetLength]]);
// 1st param: AnArray
- Call.Args.Elements.AddElement.Expr:=ConvertElement(Param0,AContext);
+ Call.AddArg(ConvertElement(Param0,AContext));
// 2nd param: newlength
- Call.Args.Elements.AddElement.Expr:=ConvertElement(El.Params[1],AContext);
+ Call.AddArg(ConvertElement(El.Params[1],AContext));
// 3rd param: default value
ElType:=AContext.Resolver.ResolveAliasType(ArrayType.ElType);
if ElType.ClassType=TPasRecordType then
ValInit:=CreateReferencePathExpr(ElType,AContext)
else
ValInit:=CreateValInit(ElType,nil,Param0,AContext);
- Call.Args.Elements.AddElement.Expr:=ValInit;
+ Call.AddArg(ValInit);
// create left side: array =
Result:=CreateAssignStatement(Param0,AssignContext);
@@ -5163,7 +5690,7 @@ begin
RaiseNotSupported(El.Value,AContext,20170130141026,'setlength '+GetResolverResultDesc(ResolvedParam0));
end;
-function TPasToJSConverter.ConvertBuiltInExcludeInclude(El: TParamsExpr;
+function TPasToJSConverter.ConvertBuiltIn_ExcludeInclude(El: TParamsExpr;
AContext: TConvertContext; IsInclude: boolean): TJSElement;
// convert "Include(aSet,Enum)" to "aSet=rtl.includeSet(aSet,Enum)"
var
@@ -5187,8 +5714,8 @@ begin
else
FunName:=FBuiltInNames[pbifnSet_Exclude];
Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FunName]);
- Call.Args.Elements.AddElement.Expr:=ConvertElement(Param0,AContext);
- Call.Args.Elements.AddElement.Expr:=ConvertElement(El.Params[1],AContext);
+ Call.AddArg(ConvertElement(Param0,AContext));
+ Call.AddArg(ConvertElement(El.Params[1],AContext));
Result:=CreateAssignStatement(Param0,AssignContext);
finally
@@ -5211,7 +5738,7 @@ begin
Result:=TJSBreakStatement(CreateElement(TJSBreakStatement,El));
end;
-function TPasToJSConverter.ConvertBuiltInExit(El: TPasExpr;
+function TPasToJSConverter.ConvertBuiltIn_Exit(El: TPasExpr;
AContext: TConvertContext): TJSElement;
// convert "exit;" -> in a function: "return result;" in a procedure: "return;"
// convert "exit(param);" -> "return param;"
@@ -5237,7 +5764,7 @@ begin
end;
end;
-function TPasToJSConverter.ConvertBuiltInIncDec(El: TParamsExpr;
+function TPasToJSConverter.ConvertBuiltIn_IncDec(El: TParamsExpr;
AContext: TConvertContext): TJSElement;
// convert inc(a,b) to a+=b
// convert dec(a,b) to a-=b
@@ -5256,7 +5783,7 @@ begin
AssignSt.Expr:=ConvertExpression(El.Params[1],AContext);
end;
-function TPasToJSConverter.ConvertBuiltInAssigned(El: TParamsExpr;
+function TPasToJSConverter.ConvertBuiltIn_Assigned(El: TParamsExpr;
AContext: TConvertContext): TJSElement;
var
NE: TJSEqualityExpressionNE;
@@ -5274,7 +5801,17 @@ begin
{$IFDEF VerbosePas2JS}
writeln('TPasToJSConverter.ConvertBuiltInAssigned ParamResolved=',GetResolverResultDesc(ParamResolved));
{$ENDIF}
- if ParamResolved.BaseType=btContext then
+ if ParamResolved.BaseType=btPointer then
+ begin
+ // convert Assigned(value) -> value!=null
+ Result:=ConvertElement(Param,AContext);
+ // Note: convert Param first, it may raise an exception
+ NE:=TJSEqualityExpressionNE(CreateElement(TJSEqualityExpressionNE,El));
+ NE.A:=Result;
+ NE.B:=CreateLiteralNull(El);
+ Result:=NE;
+ end
+ else if ParamResolved.BaseType=btContext then
begin
C:=ParamResolved.TypeEl.ClassType;
if (C=TPasClassType)
@@ -5297,7 +5834,7 @@ begin
GT:=TJSRelationalExpressionGT(CreateElement(TJSRelationalExpressionGT,El));
Call:=CreateCallExpression(El);
Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnArray_Length]]);
- Call.Args.Elements.AddElement.Expr:=Result;
+ Call.AddArg(Result);
GT.A:=Call;
GT.B:=CreateLiteralNumber(El,0);
Result:=GT;
@@ -5307,7 +5844,7 @@ begin
end;
end;
-function TPasToJSConverter.ConvertBuiltInChr(El: TParamsExpr;
+function TPasToJSConverter.ConvertBuiltIn_Chr(El: TParamsExpr;
AContext: TConvertContext): TJSElement;
var
ParamResolved: TPasResolverResult;
@@ -5326,19 +5863,22 @@ begin
// Note: convert Param first, as it might raise an exception
Call:=CreateCallExpression(El);
Call.Expr:=CreateMemberExpression(['String','fromCharCode']);
- Call.Args.Elements.AddElement.Expr:=Result;
+ Call.AddArg(Result);
Result:=Call;
exit;
end;
DoError(20170325185906,nExpectedXButFoundY,sExpectedXButFoundY,['integer',GetResolverResultDescription(ParamResolved)],Param);
end;
-function TPasToJSConverter.ConvertBuiltInOrd(El: TParamsExpr;
+function TPasToJSConverter.ConvertBuiltIn_Ord(El: TParamsExpr;
AContext: TConvertContext): TJSElement;
var
- ParamResolved: TPasResolverResult;
- Param: TPasExpr;
+ ParamResolved, SubParamResolved: TPasResolverResult;
+ Param, SubParam: TPasExpr;
Call: TJSCallExpression;
+ SubParams: TParamsExpr;
+ SubParamJS: TJSElement;
+ Minus: TJSAdditiveExpressionMinus;
begin
Result:=nil;
if AContext.Resolver=nil then
@@ -5347,6 +5887,38 @@ begin
AContext.Resolver.ComputeElement(Param,ParamResolved,[]);
if ParamResolved.BaseType=btChar then
begin
+ if Param is TParamsExpr then
+ begin
+ SubParams:=TParamsExpr(Param);
+ if SubParams.Kind=pekArrayParams then
+ begin
+ // e.g. ord(something[index])
+ SubParam:=SubParams.Value;
+ AContext.Resolver.ComputeElement(SubParam,SubParamResolved,[]);
+ if SubParamResolved.BaseType in btAllStrings then
+ begin
+ // e.g. ord(aString[index]) -> aString.charCodeAt(index-1)
+ SubParamJS:=ConvertElement(SubParam,AContext);
+ // Note: convert SubParam first, as it might raise an exception
+ Call:=nil;
+ try
+ Call:=CreateCallExpression(El);
+ Call.Expr:=CreateDotExpression(El,SubParamJS,CreateBuiltInIdentifierExpr('charCodeAt'));
+ Minus:=TJSAdditiveExpressionMinus(CreateElement(TJSAdditiveExpressionMinus,Param));
+ Call.AddArg(Minus);
+ if length(SubParams.Params)<>1 then
+ RaiseInconsistency(20170405231706);
+ Minus.A:=ConvertElement(SubParams.Params[0],AContext);
+ Minus.B:=CreateLiteralNumber(Param,1);
+ Result:=Call;
+ finally
+ if Result=nil then
+ Call.Free;
+ end;
+ exit;
+ end;
+ end;
+ end;
// ord(aChar) -> aChar.charCodeAt()
Result:=ConvertElement(Param,AContext);
// Note: convert Param first, as it might raise an exception
@@ -5367,7 +5939,7 @@ begin
DoError(20170210105339,nExpectedXButFoundY,sExpectedXButFoundY,['enum',GetResolverResultDescription(ParamResolved)],Param);
end;
-function TPasToJSConverter.ConvertBuiltInLow(El: TParamsExpr;
+function TPasToJSConverter.ConvertBuiltIn_Low(El: TParamsExpr;
AContext: TConvertContext): TJSElement;
// low(enumtype) -> first enumvalue
// low(set var) -> first enumvalue
@@ -5463,7 +6035,7 @@ begin
DoError(20170210110717,nExpectedXButFoundY,sExpectedXButFoundY,['enum or array',GetResolverResultDescription(ResolvedEl)],Param);
end;
-function TPasToJSConverter.ConvertBuiltInHigh(El: TParamsExpr;
+function TPasToJSConverter.ConvertBuiltIn_High(El: TParamsExpr;
AContext: TConvertContext): TJSElement;
// high(enumtype) -> last enumvalue
// high(set var) -> last enumvalue
@@ -5485,6 +6057,7 @@ var
TypeEl: TPasType;
MinusExpr: TJSAdditiveExpressionMinus;
Call: TJSCallExpression;
+ aMinValue, aMaxValue: int64;
begin
Result:=nil;
if AContext.Resolver=nil then
@@ -5518,7 +6091,7 @@ begin
// Note: convert Param first, it may raise an exception
Call:=CreateCallExpression(El);
Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnArray_Length]]);
- Call.Args.Elements.AddElement.Expr:=Result;
+ Call.AddArg(Result);
MinusExpr:=TJSAdditiveExpressionMinus(CreateElement(TJSAdditiveExpressionMinus,El));
MinusExpr.A:=Call;
MinusExpr.B:=CreateLiteralNumber(El,1);
@@ -5542,6 +6115,12 @@ begin
begin
Result:=CreateLiteralBoolean(Param,HighJSBoolean);
exit;
+ end
+ else if RangeResolved.BaseType in btAllInteger then
+ begin
+ ComputeRange(RangeResolved,aMinValue,aMaxValue,Range);
+ Result:=CreateLiteralNumber(Param,aMaxValue);
+ exit;
end;
end;
RaiseNotSupported(El,AContext,20170222231101);
@@ -5565,7 +6144,7 @@ begin
DoError(20170210114139,nExpectedXButFoundY,sExpectedXButFoundY,['enum or array',GetResolverResultDescription(ResolvedEl)],Param);
end;
-function TPasToJSConverter.ConvertBuiltInPred(El: TParamsExpr;
+function TPasToJSConverter.ConvertBuiltIn_Pred(El: TParamsExpr;
AContext: TConvertContext): TJSElement;
// pred(enumvalue) -> enumvalue-1
var
@@ -5592,7 +6171,7 @@ begin
DoError(20170210120039,nExpectedXButFoundY,sExpectedXButFoundY,['enum',GetResolverResultDescription(ResolvedEl)],Param);
end;
-function TPasToJSConverter.ConvertBuiltInSucc(El: TParamsExpr;
+function TPasToJSConverter.ConvertBuiltIn_Succ(El: TParamsExpr;
AContext: TConvertContext): TJSElement;
// succ(enumvalue) -> enumvalue+1
var
@@ -5619,7 +6198,7 @@ begin
DoError(20170210120626,nExpectedXButFoundY,sExpectedXButFoundY,['enum',GetResolverResultDescription(ResolvedEl)],Param);
end;
-function TPasToJSConverter.ConvertBuiltInStrProc(El: TParamsExpr;
+function TPasToJSConverter.ConvertBuiltIn_StrProc(El: TParamsExpr;
AContext: TConvertContext): TJSElement;
// convert 'str(value,aString)' to 'aString = <string>'
// for the conversion see ConvertBuiltInStrFunc
@@ -5646,7 +6225,7 @@ begin
end;
end;
-function TPasToJSConverter.ConvertBuiltInStrFunc(El: TParamsExpr;
+function TPasToJSConverter.ConvertBuiltIn_StrFunc(El: TParamsExpr;
AContext: TConvertContext): TJSElement;
// convert 'str(boolean)' to '""+boolean'
// convert 'str(integer)' to '""+integer'
@@ -5729,7 +6308,7 @@ begin
NeedStrLit:=false;
Call:=CreateCallExpression(El);
Call.Expr:=CreateDotExpression(El,Add,CreateBuiltInIdentifierExpr('toFixed'));
- Call.Args.Elements.AddElement.Expr:=ConvertElement(El.format2,AContext);
+ Call.AddArg(ConvertElement(El.format2,AContext));
Add:=Call;
Call:=nil;
end;
@@ -5761,9 +6340,9 @@ begin
// create 'rtl.spaceLeft(add,width)'
Call:=CreateCallExpression(El);
Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnSpaceLeft]]);
- Call.Args.Elements.AddElement.Expr:=Add;
+ Call.AddArg(Add);
Add:=nil;
- Call.Args.Elements.AddElement.Expr:=ConvertElement(El.format1,AContext);
+ Call.AddArg(ConvertElement(El.format1,AContext));
Add:=Call;
Call:=nil;
end
@@ -5778,7 +6357,7 @@ begin
end;
end;
-function TPasToJSConverter.ConvertBuiltInConcatArray(El: TParamsExpr;
+function TPasToJSConverter.ConvertBuiltIn_ConcatArray(El: TParamsExpr;
AContext: TConvertContext): TJSElement;
// concat(array1, array2)
var
@@ -5822,22 +6401,21 @@ begin
begin
// record: rtl.arrayConcat(RecordType,array1,array2,...)
Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnArray_Concat]]);
- Call.Args.Elements.AddElement.Expr:=CreateReferencePathExpr(
- ElTypeResolved.TypeEl,AContext);
+ Call.AddArg(CreateReferencePathExpr(ElTypeResolved.TypeEl,AContext));
end;
end
else if ElTypeResolved.BaseType=btSet then
begin
// set: rtl.arrayConcat("refSet",array1,array2,...)
Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnArray_Concat]]);
- Call.Args.Elements.AddElement.Expr:=CreateLiteralString(El,FBuiltInNames[pbifnSet_Reference]);
+ Call.AddArg(CreateLiteralString(El,FBuiltInNames[pbifnSet_Reference]));
end;
if Call.Expr=nil then
// default: array1.concat(array2,...)
Call.Expr:=CreateDotExpression(El,ConvertElement(Param0,AContext),
CreateBuiltInIdentifierExpr('concat'));
for i:=1 to length(El.Params)-1 do
- Call.Args.Elements.AddElement.Expr:=ConvertElement(El.Params[i],AContext);
+ Call.AddArg(ConvertElement(El.Params[i],AContext));
Result:=Call;
finally
if Result=nil then
@@ -5846,7 +6424,7 @@ begin
end;
end;
-function TPasToJSConverter.ConvertBuiltInCopyArray(El: TParamsExpr;
+function TPasToJSConverter.ConvertBuiltIn_CopyArray(El: TParamsExpr;
AContext: TConvertContext): TJSElement;
var
Param: TPasExpr;
@@ -5883,17 +6461,17 @@ begin
// rtl.arrayCopy
Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnArray_Copy]]);
// param: type
- Call.Args.Elements.AddElement.Expr:=TypeParam;
+ Call.AddArg(TypeParam);
// param: src
- Call.Args.Elements.AddElement.Expr:=ConvertElement(Param,AContext);
+ Call.AddArg(ConvertElement(Param,AContext));
// param: start
if length(El.Params)=1 then
- Call.Args.Elements.AddElement.Expr:=CreateLiteralNumber(El,0)
+ Call.AddArg(CreateLiteralNumber(El,0))
else
- Call.Args.Elements.AddElement.Expr:=ConvertElement(El.Params[1],AContext);
+ Call.AddArg(ConvertElement(El.Params[1],AContext));
// param: count
if length(El.Params)>=3 then
- Call.Args.Elements.AddElement.Expr:=ConvertElement(El.Params[2],AContext);
+ Call.AddArg(ConvertElement(El.Params[2],AContext));
Result:=Call;
finally
if Result=nil then
@@ -5904,7 +6482,7 @@ begin
if AContext=nil then;
end;
-function TPasToJSConverter.ConvertBuiltInInsertArray(El: TParamsExpr;
+function TPasToJSConverter.ConvertBuiltIn_InsertArray(El: TParamsExpr;
AContext: TConvertContext): TJSElement;
// procedure insert(item,var array,const position)
// -> array.splice(position,1,item);
@@ -5918,9 +6496,9 @@ begin
Call:=CreateCallExpression(El);
ArrEl:=ConvertElement(El.Params[1],AContext);
Call.Expr:=CreateDotExpression(El,ArrEl,CreateBuiltInIdentifierExpr('splice'));
- Call.Args.Elements.AddElement.Expr:=ConvertElement(El.Params[2],AContext);
- Call.Args.Elements.AddElement.Expr:=CreateLiteralNumber(El,1);
- Call.Args.Elements.AddElement.Expr:=ConvertElement(El.Params[0],AContext);
+ Call.AddArg(ConvertElement(El.Params[2],AContext));
+ Call.AddArg(CreateLiteralNumber(El,1));
+ Call.AddArg(ConvertElement(El.Params[0],AContext));
Result:=Call;
finally
if Result=nil then
@@ -5928,7 +6506,7 @@ begin
end;
end;
-function TPasToJSConverter.ConvertBuiltInDeleteArray(El: TParamsExpr;
+function TPasToJSConverter.ConvertBuiltIn_DeleteArray(El: TParamsExpr;
AContext: TConvertContext): TJSElement;
// proc delete(var array,const start,count)
// -> array.splice(start,count)
@@ -5942,8 +6520,8 @@ begin
Call:=CreateCallExpression(El);
ArrEl:=ConvertElement(El.Params[0],AContext);
Call.Expr:=CreateDotExpression(El,ArrEl,CreateBuiltInIdentifierExpr('splice'));
- Call.Args.Elements.AddElement.Expr:=ConvertElement(El.Params[1],AContext);
- Call.Args.Elements.AddElement.Expr:=ConvertElement(El.Params[2],AContext);
+ Call.AddArg(ConvertElement(El.Params[1],AContext));
+ Call.AddArg(ConvertElement(El.Params[2],AContext));
Result:=Call;
finally
if Result=nil then
@@ -5951,6 +6529,35 @@ begin
end;
end;
+function TPasToJSConverter.ConvertBuiltIn_TypeInfo(El: TParamsExpr;
+ AContext: TConvertContext): TJSElement;
+var
+ ParamResolved: TPasResolverResult;
+ Param: TPasExpr;
+begin
+ Result:=nil;
+ Param:=El.Params[0];
+ AContext.Resolver.ComputeElement(Param,ParamResolved,[rcNoImplicitProc]);
+ if ParamResolved.IdentEl is TPasType then
+ Result:=CreateTypeInfoRef(TPasType(ParamResolved.IdentEl),AContext,Param)
+ else if ParamResolved.TypeEl<>nil then
+ begin
+ if (ParamResolved.TypeEl.ClassType=TPasClassType)
+ and (rrfReadable in ParamResolved.Flags)
+ and ((ParamResolved.IdentEl is TPasVariable)
+ or (ParamResolved.IdentEl.ClassType=TPasArgument)) then
+ begin
+ // typeinfo(classinstance) -> classinstance.$rtti
+ Result:=ConvertElement(Param,AContext);
+ Result:=CreateDotExpression(El,Result,CreateBuiltInIdentifierExpr(FBuiltInNames[pbivnRTTI]));
+ end
+ else
+ Result:=CreateTypeInfoRef(ParamResolved.TypeEl,AContext,Param);
+ end
+ else
+ RaiseNotSupported(El,AContext,20170413001544);
+end;
+
function TPasToJSConverter.ConvertRecordValues(El: TRecordValues;
AContext: TConvertContext): TJSElement;
@@ -6044,34 +6651,22 @@ begin
ElClass:=El.ClassType;
if ElClass=TPasClassType then
Result := ConvertClassType(TPasClassType(El), AContext)
+ else if (ElClass=TPasClassOfType) then
+ Result := ConvertClassOfType(TPasClassOfType(El), AContext)
else if ElClass=TPasRecordType then
Result := ConvertRecordType(TPasRecordType(El), AContext)
else if ElClass=TPasEnumType then
Result := ConvertEnumType(TPasEnumType(El), AContext)
else if (ElClass=TPasSetType) then
- begin
- if TPasSetType(El).IsPacked then
- DoError(20170222231613,nPasElementNotSupported,sPasElementNotSupported,
- ['packed'],El);
- end
- else if (ElClass=TPasAliasType)
- or (ElClass=TPasClassOfType) then
+ Result := ConvertSetType(TPasSetType(El), AContext)
+ else if (ElClass=TPasAliasType) then
+ else if (ElClass=TPasPointerType) then
+ Result:=ConvertPointerType(TPasPointerType(El),AContext)
else if (ElClass=TPasProcedureType)
or (ElClass=TPasFunctionType) then
- begin
- if TPasProcedureType(El).IsNested then
- DoError(20170222231636,nPasElementNotSupported,sPasElementNotSupported,
- ['is nested'],El);
- if TPasProcedureType(El).CallingConvention<>ccDefault then
- DoError(20170222231532,nPasElementNotSupported,sPasElementNotSupported,
- [cCallingConventions[TPasProcedureType(El).CallingConvention]],El);
- end
+ Result:=ConvertProcedureType(TPasProcedureType(El),AContext)
else if (ElClass=TPasArrayType) then
- begin
- if TPasArrayType(El).PackMode<>pmNone then
- DoError(20170222231648,nPasElementNotSupported,sPasElementNotSupported,
- ['packed'],El);
- end
+ Result:=ConvertArrayType(TPasArrayType(El),AContext)
else
begin
{$IFDEF VerbosePas2JS}
@@ -6225,7 +6820,6 @@ Var
Procedure AddFunctionResultInit;
var
VarSt: TJSVariableStatement;
- AssignSt: TJSSimpleAssignStatement;
PasFun: TPasFunction;
FunType: TPasFunctionType;
ResultEl: TPasResultElement;
@@ -6235,13 +6829,9 @@ Var
ResultEl:=FunType.ResultEl;
// add 'var result=initvalue'
- VarSt:=TJSVariableStatement(CreateElement(TJSVariableStatement,El));
+ VarSt:=CreateVarStatement(ResolverResultVar,CreateValInit(ResultEl.ResultType,nil,El,aContext),El);
Add(VarSt);
Result:=SLFirst;
- AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
- VarSt.A:=AssignSt;
- AssignSt.LHS:=CreateBuiltInIdentifierExpr(ResolverResultVar);
- AssignSt.Expr:=CreateValInit(ResultEl.ResultType,nil,El,aContext);
end;
Procedure AddFunctionResultReturn;
@@ -6277,7 +6867,9 @@ begin
For I:=0 to El.Declarations.Count-1 do
begin
P:=TPasElement(El.Declarations[i]);
+ {$IFDEF VerbosePas2JS}
//writeln('TPasToJSConverter.ConvertDeclarations El[',i,']=',GetObjName(P));
+ {$ENDIF}
if not IsElementUsed(P) then continue;
E:=Nil;
@@ -6366,7 +6958,7 @@ var
Call:=CreateCallExpression(El);
AncestorPath:=CreateReferencePath(Ancestor,ClassContext,rpkPathAndName);
Call.Expr:=CreateBuiltInIdentifierExpr(AncestorPath+'.'+MemberFuncName[Kind]+'.call');
- Call.Args.Elements.AddElement.Expr:=CreateBuiltInIdentifierExpr('this');
+ Call.AddArg(CreateBuiltInIdentifierExpr('this'));
AddToSourceElements(Src,Call);
end;
@@ -6458,10 +7050,50 @@ var
end;
end;
+ procedure AddRTTI(Src: TJSSourceElements; FuncContext: TConvertContext);
+ var
+ HasRTTIMembers: Boolean;
+ i: Integer;
+ P: TPasElement;
+ NewEl: TJSElement;
+ VarSt: TJSVariableStatement;
+ begin
+ HasRTTIMembers:=false;
+ For i:=0 to El.Members.Count-1 do
+ begin
+ P:=TPasElement(El.Members[i]);
+ //writeln('TPasToJSConverter.ConvertClassType RTTI El[',i,']=',GetObjName(P));
+ if P.Visibility<>visPublished then continue;
+ if not IsMemberNeeded(P) then continue;
+ NewEl:=nil;
+ if P.ClassType=TPasVariable then
+ NewEl:=CreateRTTIClassField(TPasVariable(P),FuncContext)
+ else if P.InheritsFrom(TPasProcedure) then
+ NewEl:=CreateRTTIClassMethod(TPasProcedure(P),FuncContext)
+ else if P.ClassType=TPasProperty then
+ NewEl:=CreateRTTIClassProperty(TPasProperty(P),FuncContext)
+ else if P.InheritsFrom(TPasType) then
+ continue
+ else
+ DoError(20170409202315,nSymbolCannotBePublished,sSymbolCannotBePublished,[],P);
+ if NewEl=nil then
+ continue; // e.g. abstract or external proc
+ // add RTTI element
+ if not HasRTTIMembers then
+ begin
+ // add "var $r = this.$rtti"
+ VarSt:=CreateVarStatement(FBuiltInNames[pbivnRTTILocal],
+ CreateMemberExpression(['this',FBuiltInNames[pbivnRTTI]]),El);
+ AddToSourceElements(Src,VarSt);
+ HasRTTIMembers:=true;
+ end;
+ AddToSourceElements(Src,NewEl);
+ end;
+ end;
+
var
Call: TJSCallExpression;
FunDecl: TJSFunctionDeclarationStatement;
- FunDef: TJSFuncDef;
Src: TJSSourceElements;
ArgEx: TJSLiteral;
FuncContext: TFunctionContext;
@@ -6475,7 +7107,10 @@ var
begin
Result:=nil;
if El.IsForward then
- exit(nil);
+ begin
+ Result:=ConvertClassForwardType(El,AContext);
+ exit;
+ end;
if El.IsExternal then exit;
@@ -6492,6 +7127,7 @@ begin
Ancestor:=El.AncestorType;
// create call 'rtl.createClass('
+ FuncContext:=nil;
Call:=CreateCallExpression(El);
try
AncestorIsExternal:=(Ancestor is TPasClassType) and TPasClassType(Ancestor).IsExternal;
@@ -6501,11 +7137,11 @@ begin
Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnCreateClass]]);
// add parameter: owner. 'this' for top level class.
- Call.Args.Elements.AddElement.Expr:=CreateBuiltInIdentifierExpr('this');
+ Call.AddArg(CreateBuiltInIdentifierExpr('this'));
// add parameter: string constant '"classname"'
ArgEx := CreateLiteralString(El,TransformVariableName(El,AContext));
- Call.Args.Elements.AddElement.Expr:=ArgEx;
+ Call.AddArg(ArgEx);
// add parameter: ancestor
if Ancestor=nil then
@@ -6514,100 +7150,115 @@ begin
AncestorPath:=TPasClassType(Ancestor).ExternalName
else
AncestorPath:=CreateReferencePath(Ancestor,AContext,rpkPathAndName);
- Call.Args.Elements.AddElement.Expr:=CreateBuiltInIdentifierExpr(AncestorPath);
+ Call.AddArg(CreateBuiltInIdentifierExpr(AncestorPath));
if AncestorIsExternal then
begin
// add the name of the NewInstance function
if Scope.NewInstanceFunction<>nil then
- Call.Args.Elements.AddElement.Expr:=CreateLiteralString(
- Scope.NewInstanceFunction,Scope.NewInstanceFunction.Name)
+ Call.AddArg(CreateLiteralString(
+ Scope.NewInstanceFunction,Scope.NewInstanceFunction.Name))
else
- Call.Args.Elements.AddElement.Expr:=CreateLiteralString(El,'');
+ Call.AddArg(CreateLiteralString(El,''));
end;
// add parameter: class initialize function 'function(){...}'
- FunDecl:=TJSFunctionDeclarationStatement.Create(0,0);
- Call.Args.Elements.AddElement.Expr:=FunDecl;
- FunDef:=TJSFuncDef.Create;
- FunDecl.AFunction:=FunDef;
- FunDef.Name:='';
- FunDef.Body:=TJSFunctionBody.Create(0,0);
- Src:=TJSSourceElements(CreateElement(TJSSourceElements, El));
- FunDef.Body.A:=Src;
+ FunDecl:=CreateFunction(El,true,true);
+ Call.AddArg(FunDecl);
+ Src:=TJSSourceElements(FunDecl.AFunction.Body.A);
// add members
FuncContext:=TFunctionContext.Create(El,Src,AContext);
- try
- FuncContext.IsSingleton:=true;
- FuncContext.This:=El;
- // add class members: types and class vars
- For i:=0 to El.Members.Count-1 do
+ FuncContext.IsSingleton:=true;
+ FuncContext.This:=El;
+ // add class members: types and class vars
+ For i:=0 to El.Members.Count-1 do
+ begin
+ P:=TPasElement(El.Members[i]);
+ //writeln('TPasToJSConverter.ConvertClassType class vars El[',i,']=',GetObjName(P));
+ if not IsMemberNeeded(P) then continue;
+ C:=P.ClassType;
+ NewEl:=nil;
+ if C=TPasVariable then
begin
- P:=TPasElement(El.Members[i]);
- //writeln('TPasToJSConverter.ConvertClassType class El[',i,']=',GetObjName(P));
- if not IsMemberNeeded(P) then continue;
- C:=P.ClassType;
- NewEl:=nil;
- if C=TPasVariable then
- begin
- if ClassVarModifiersType*TPasVariable(P).VarModifiers<>[] then
- begin
- NewEl:=CreateVarDecl(TPasVariable(P),FuncContext); // can be nil
- if NewEl=nil then continue;
- end
- else
- continue;
- end
- else if C=TPasConst then
- NewEl:=ConvertConst(TPasConst(P),aContext)
- else if C=TPasProperty then
+ if ClassVarModifiersType*TPasVariable(P).VarModifiers<>[] then
begin
- NewEl:=ConvertProperty(TPasProperty(P),AContext);
+ NewEl:=CreateVarDecl(TPasVariable(P),FuncContext); // can be nil
if NewEl=nil then continue;
end
- else if C.InheritsFrom(TPasType) then
- NewEl:=CreateTypeDecl(TPasType(P),aContext)
- else if C.InheritsFrom(TPasProcedure) then
- continue
else
- RaiseNotSupported(P,FuncContext,20161221233338);
- if NewEl=nil then
- RaiseNotSupported(P,FuncContext,20170204223922);
- AddToSourceElements(Src,NewEl);
- end;
+ continue;
+ end
+ else if C=TPasConst then
+ NewEl:=ConvertConst(TPasConst(P),aContext)
+ else if C=TPasProperty then
+ begin
+ NewEl:=ConvertProperty(TPasProperty(P),AContext);
+ if NewEl=nil then continue;
+ end
+ else if C.InheritsFrom(TPasType) then
+ NewEl:=CreateTypeDecl(TPasType(P),aContext)
+ else if C.InheritsFrom(TPasProcedure) then
+ continue
+ else
+ RaiseNotSupported(P,FuncContext,20161221233338);
+ if NewEl=nil then
+ RaiseNotSupported(P,FuncContext,20170204223922);
+ AddToSourceElements(Src,NewEl);
+ end;
- // instance initialization function
- AddInstanceMemberFunction(Src,FuncContext,Ancestor,mfInit);
- // instance finalization function
- AddInstanceMemberFunction(Src,FuncContext,Ancestor,mfFinalize);
+ // instance initialization function
+ AddInstanceMemberFunction(Src,FuncContext,Ancestor,mfInit);
+ // instance finalization function
+ AddInstanceMemberFunction(Src,FuncContext,Ancestor,mfFinalize);
- // add methods
- For i:=0 to El.Members.Count-1 do
- begin
- P:=TPasElement(El.Members[i]);
- //writeln('TPasToJSConverter.ConvertClassType class El[',i,']=',GetObjName(P));
- if not IsMemberNeeded(P) then continue;
- if P is TPasProcedure then
- NewEl:=ConvertProcedure(TPasProcedure(P),aContext)
- else
- continue;
- if NewEl=nil then
- continue; // e.g. abstract or external proc
- AddToSourceElements(Src,NewEl);
- end;
+ // add methods
+ For i:=0 to El.Members.Count-1 do
+ begin
+ P:=TPasElement(El.Members[i]);
+ //writeln('TPasToJSConverter.ConvertClassType methods El[',i,']=',GetObjName(P));
+ if not IsMemberNeeded(P) then continue;
+ if P is TPasProcedure then
+ NewEl:=ConvertProcedure(TPasProcedure(P),FuncContext)
+ else
+ continue;
+ if NewEl=nil then
+ continue; // e.g. abstract or external proc
+ AddToSourceElements(Src,NewEl);
+ end;
- finally
- FuncContext.Free;
- end;
+ // add RTTI init function
+ if AContext.Resolver<>nil then
+ AddRTTI(Src,FuncContext);
Result:=Call;
finally
+ FuncContext.Free;
if Result<>Call then
Call.Free;
end;
end;
+function TPasToJSConverter.ConvertClassForwardType(El: TPasClassType;
+ AContext: TConvertContext): TJSElement;
+// module.$rtti.$Class("classname");
+var
+ Ref: TResolvedReference;
+ aClass: TPasClassType;
+ ObjLit: TJSObjectLiteral;
+begin
+ Result:=nil;
+ if (AContext.Resolver=nil) or not (El.CustomData is TResolvedReference) then exit;
+ Ref:=TResolvedReference(El.CustomData);
+ aClass:=Ref.Declaration as TPasClassType;
+ if not HasTypeInfo(aClass,AContext) then exit;
+ if IsClassRTTICreatedBefore(aClass,El) then exit;
+ // module.$rtti.$Class("classname");
+ Result:=CreateRTTINewType(aClass,FBuiltInNames[pbifnRTTINewClass],true,AContext,ObjLit);
+ if ObjLit<>nil then
+ RaiseInconsistency(20170412093427);
+end;
+
function TPasToJSConverter.ConvertClassExternalType(El: TPasClassType;
AContext: TConvertContext): TJSElement;
@@ -6625,7 +7276,6 @@ begin
Result:=nil;
if El.IsForward then exit;
-
// add class members: types and class vars
For i:=0 to El.Members.Count-1 do
begin
@@ -6653,24 +7303,78 @@ begin
end;
end;
+function TPasToJSConverter.ConvertClassOfType(El: TPasClassOfType;
+ AContext: TConvertContext): TJSElement;
+// create
+// module.$rtti.$ClassRef("typename",{
+// instancetype: module.$rtti["classname"])
+// }
+// if class is defined later add a forward define for the class
+var
+ ObjLit: TJSObjectLiteral;
+ Prop: TJSObjectLiteralElement;
+ Call: TJSCallExpression;
+ ok: Boolean;
+ List: TJSStatementList;
+begin
+ Result:=nil;
+ if not HasTypeInfo(El,AContext) then exit;
+
+ ok:=false;
+ Call:=CreateRTTINewType(El,FBuiltInNames[pbifnRTTINewClassRef],false,AContext,ObjLit);
+ Result:=Call;
+ try
+ Prop:=ObjLit.Elements.AddElement;
+ Prop.Name:=TJSString(FBuiltInNames[pbivnRTTIClassRef_InstanceType]);
+ Prop.Expr:=CreateTypeInfoRef(El.DestType,AContext,El);
+
+ if not IsClassRTTICreatedBefore(El.DestType as TPasClassType,El) then
+ begin
+ // class rtti must be forward registered
+ if not (AContext is TFunctionContext) then
+ RaiseNotSupported(El,AContext,20170412102916);
+ // prepend module.$rtti.$Class("classname");
+ Call:=CreateRTTINewType(El.DestType,FBuiltInNames[pbifnRTTINewClass],true,AContext,ObjLit);
+ if ObjLit<>nil then
+ RaiseInconsistency(20170412102654);
+ List:=TJSStatementList(CreateElement(TJSStatementList,El));
+ List.A:=Call;
+ List.B:=Result;
+ Result:=List;
+ end;
+ ok:=true;
+ finally
+ if not ok then
+ FreeAndNil(Result);
+ end;
+end;
+
function TPasToJSConverter.ConvertEnumType(El: TPasEnumType;
AContext: TConvertContext): TJSElement;
// TMyEnum = (red, green)
// convert to
-// this.TMyEnum = {
-// "0":"red",
-// "red":0,
-// "0":"green",
-// "green":0,
-// }
+// this.TMyEnum = {
+// "0":"red",
+// "red":0,
+// "0":"green",
+// "green":0,
+// };
+// module.$rtti.$TIEnum("TMyEnum",{
+// enumtype: this.TMyEnum,
+// minvalue: 0,
+// maxvalue: 1
+// });
var
ObjectContect: TObjectContext;
i: Integer;
EnumValue: TPasEnumValue;
- ParentObj, Obj: TJSObjectLiteral;
- ObjLit: TJSObjectLiteralElement;
+ ParentObj, Obj, TIObj: TJSObjectLiteral;
+ ObjLit, TIProp: TJSObjectLiteralElement;
AssignSt: TJSSimpleAssignStatement;
JSName: TJSString;
+ Call: TJSCallExpression;
+ List: TJSStatementList;
+ ok: Boolean;
begin
Result:=nil;
for i:=0 to El.Values.Count-1 do
@@ -6680,6 +7384,7 @@ begin
RaiseNotSupported(EnumValue.Value,AContext,20170208145221,'enum constant');
end;
+ ok:=false;
ObjectContect:=nil;
try
Obj:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,El));
@@ -6716,8 +7421,254 @@ begin
ObjLit.Expr:=CreateLiteralNumber(El,i);
end;
+ if HasTypeInfo(El,AContext) then
+ begin
+ // create typeinfo
+ if not (AContext is TFunctionContext) then
+ RaiseNotSupported(El,AContext,20170411210045,'typeinfo');
+ // create statement list
+ List:=TJSStatementList(CreateElement(TJSStatementList,El));
+ List.A:=Result;
+ Result:=List;
+ // module.$rtti.$TIEnum("TMyEnum",{...});
+ Call:=CreateRTTINewType(El,FBuiltInNames[pbifnRTTINewEnum],false,AContext,TIObj);
+ List.B:=Call;
+ // add minvalue: number
+ TIProp:=TIObj.Elements.AddElement;
+ TIProp.Name:=TJSString(FBuiltInNames[pbivnRTTIInt_MinValue]);
+ TIProp.Expr:=CreateLiteralNumber(El,0);
+ // add maxvalue: number
+ TIProp:=TIObj.Elements.AddElement;
+ TIProp.Name:=TJSString(FBuiltInNames[pbivnRTTIInt_MaxValue]);
+ TIProp.Expr:=CreateLiteralNumber(El,El.Values.Count-1);
+ // add enumtype: this.TypeName
+ TIProp:=TIObj.Elements.AddElement;
+ TIProp.Name:=TJSString(FBuiltInNames[pbivnRTTIEnum_EnumType]);
+ TIProp.Expr:=CreateDeclNameExpression(El,El.Name,AContext);
+ end;
+
+ ok:=true;
finally
ObjectContect.Free;
+ if not ok then
+ FreeAndNil(Result);
+ end;
+end;
+
+function TPasToJSConverter.ConvertSetType(El: TPasSetType;
+ AContext: TConvertContext): TJSElement;
+// create
+// module.$rtti.$Set("name",{
+// comptype: module.$rtti["enumtype"]
+// })
+var
+ Obj: TJSObjectLiteral;
+ Call: TJSCallExpression;
+ Prop: TJSObjectLiteralElement;
+begin
+ Result:=nil;
+ if El.IsPacked then
+ DoError(20170222231613,nPasElementNotSupported,sPasElementNotSupported,
+ ['packed'],El);
+ if not HasTypeInfo(El,AContext) then exit;
+
+ // module.$rtti.$Set("name",{...})
+ Call:=CreateRTTINewType(El,FBuiltInNames[pbifnRTTINewSet],false,AContext,Obj);
+ try
+ // "comptype: ref"
+ Prop:=Obj.Elements.AddElement;
+ Prop.Name:=TJSString(FBuiltInNames[pbivnRTTISet_CompType]);
+ Prop.Expr:=CreateTypeInfoRef(El.EnumType,AContext,El);
+ Result:=Call;
+ finally
+ if Result=nil then
+ Call.Free;
+ end;
+end;
+
+function TPasToJSConverter.ConvertPointerType(El: TPasPointerType;
+ AContext: TConvertContext): TJSElement;
+// create
+// module.$rtti.$Set("name",{
+// reftype: module.$rtti["reftype"]
+// })
+var
+ Obj: TJSObjectLiteral;
+ Call: TJSCallExpression;
+ Prop: TJSObjectLiteralElement;
+begin
+ Result:=nil;
+ if not HasTypeInfo(El,AContext) then exit;
+
+ // module.$rtti.$Pointer("name",{...})
+ Call:=CreateRTTINewType(El,FBuiltInNames[pbifnRTTINewPointer],false,AContext,Obj);
+ try
+ // "reftype: ref"
+ Prop:=Obj.Elements.AddElement;
+ Prop.Name:=TJSString(FBuiltInNames[pbivnRTTISet_CompType]);
+ Prop.Expr:=CreateTypeInfoRef(El.DestType,AContext,El);
+ Result:=Call;
+ finally
+ if Result=nil then
+ Call.Free;
+ end;
+end;
+
+function TPasToJSConverter.ConvertProcedureType(El: TPasProcedureType;
+ AContext: TConvertContext): TJSElement;
+// create
+// module.$rtti.$ProcVar("name",{
+// procsig: rtl.newTIProcSignature([[arg1name,arg1type,arg1flags],[arg2name...],...],resulttype,flags)
+// })
+// module.$rtti.$MethodVar("name",{
+// procsig: rtl.newTIProcSignature([[arg1name,arg1type,arg1flags],[arg2name...],...],resulttype,flags),
+// methodkind: 1
+// })
+var
+ Call, InnerCall: TJSCallExpression;
+ FunName: String;
+ ResultEl: TPasResultElement;
+ ResultTypeInfo: TJSElement;
+ Flags: Integer;
+ MethodKind: TMethodKind;
+ Obj: TJSObjectLiteral;
+ Prop: TJSObjectLiteralElement;
+begin
+ Result:=nil;
+ if El.IsNested then
+ DoError(20170222231636,nPasElementNotSupported,sPasElementNotSupported,
+ ['is nested'],El);
+ if El.CallingConvention<>ccDefault then
+ DoError(20170222231532,nPasElementNotSupported,sPasElementNotSupported,
+ ['calling convention '+cCallingConventions[El.CallingConvention]],El);
+ if not HasTypeInfo(El,AContext) then exit;
+
+ // module.$rtti.$ProcVar("name",function(){})
+ if El.IsOfObject then
+ FunName:=FBuiltInNames[pbifnRTTINewMethodVar]
+ else
+ FunName:=FBuiltInNames[pbifnRTTINewProcVar];
+ Call:=CreateRTTINewType(El,FunName,false,AContext,Obj);
+ try
+ // add "procsig: rtl.newTIProcSignature()"
+ Prop:=Obj.Elements.AddElement;
+ Prop.Name:=TJSString(FBuiltInNames[pbivnRTTIProcVar_ProcSig]);
+ InnerCall:=CreateCallExpression(El);
+ Prop.Expr:=InnerCall;
+ InnerCall.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnRTTINewProcSig]]);
+ // add array of arguments
+ InnerCall.AddArg(CreateRTTIArgList(El,El.Args,AContext));
+ // add resulttype as typeinfo reference
+ if El is TPasFunctionType then
+ begin
+ ResultEl:=TPasFunctionType(El).ResultEl;
+ ResultTypeInfo:=CreateTypeInfoRef(ResultEl.ResultType,AContext,ResultEl);
+ if ResultTypeInfo<>nil then
+ InnerCall.AddArg(ResultTypeInfo);
+ end;
+ // add param flags
+ Flags:=0;
+ if ptmVarargs in El.Modifiers then
+ inc(Flags,pfVarargs);
+ if Flags>0 then
+ InnerCall.AddArg(CreateLiteralNumber(El,Flags));
+
+ if El.IsOfObject then
+ begin
+ // add "methodkind: number;"
+ Prop:=Obj.Elements.AddElement;
+ Prop.Name:=TJSString(FBuiltInNames[pbivnRTTIMethodKind]);
+ if El.ClassType=TPasProcedureType then
+ MethodKind:=mkProcedure
+ else if El.ClassType=TPasFunctionType then
+ MethodKind:=mkFunction
+ else
+ RaiseNotSupported(El,AContext,20170411180848);
+ Prop.Expr:=CreateLiteralNumber(El,ord(MethodKind));
+ end;
+
+ Result:=Call;
+ finally
+ if Result=nil then
+ Call.Free;
+ end;
+end;
+
+function TPasToJSConverter.ConvertArrayType(El: TPasArrayType;
+ AContext: TConvertContext): TJSElement;
+// Create
+// module.$rtti.$StaticArray("name",{
+// dims: [dimsize1,dimsize2,...],
+// eltype: module.$rtti["ElTypeName"]
+// };
+// module.$rtti.$DynArray("name",{
+// eltype: module.$rtti["ElTypeName"]
+// };
+var
+ CallName: String;
+ Obj: TJSObjectLiteral;
+ Prop: TJSObjectLiteralElement;
+ ArrLit: TJSArrayLiteral;
+ Arr: TPasArrayType;
+ Index: Integer;
+ RangeResolved: TPasResolverResult;
+ ElType: TPasType;
+ RangeEl: TPasExpr;
+ aMinValue, aMaxValue: int64;
+ Call: TJSCallExpression;
+begin
+ Result:=nil;
+ if El.PackMode<>pmNone then
+ DoError(20170222231648,nPasElementNotSupported,sPasElementNotSupported,
+ ['packed'],El);
+ {$IFDEF VerbosePas2JS}
+ writeln('TPasToJSConverter.ConvertArrayType ',GetObjName(El));
+ {$ENDIF}
+ if not HasTypeInfo(El,AContext) then exit;
+
+ // module.$rtti.$DynArray("name",{...})
+ if length(El.Ranges)>0 then
+ CallName:=FBuiltInNames[pbifnRTTINewStaticArray]
+ else
+ CallName:=FBuiltInNames[pbifnRTTINewDynArray];
+ Call:=CreateRTTINewType(El,CallName,false,AContext,Obj);
+ try
+ ElType:=El.ElType;
+ if length(El.Ranges)>0 then
+ begin
+ // dims: [dimsize1,dimsize2,...]
+ Prop:=Obj.Elements.AddElement;
+ Prop.Name:=TJSString(FBuiltInNames[pbivnRTTIArray_Dims]);
+ ArrLit:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,El));
+ Prop.Expr:=ArrLit;
+ Arr:=El;
+ Index:=0;
+ repeat
+ RangeEl:=Arr.Ranges[Index];
+ AContext.Resolver.ComputeElement(RangeEl,RangeResolved,[rcType]);
+ ComputeRange(RangeResolved,aMinValue,aMaxValue,RangeEl);
+ ArrLit.AddElement(CreateLiteralNumber(RangeEl,aMaxValue-aMinValue+1));
+ inc(Index);
+ if Index=length(Arr.Ranges) then
+ begin
+ if ElType.ClassType<>TPasArrayType then
+ break;
+ Arr:=TPasArrayType(ElType);
+ if length(Arr.Ranges)=0 then
+ RaiseNotSupported(Arr,AContext,20170411222315,'static array of anonymous array');
+ ElType:=Arr.ElType;
+ Index:=0;
+ end;
+ until false;
+ end;
+ // eltype: ref
+ Prop:=Obj.Elements.AddElement;
+ Prop.Name:=TJSString(FBuiltInNames[pbivnRTTIArray_ElType]);
+ Prop.Expr:=CreateTypeInfoRef(ElType,AContext,El);
+ Result:=Call;
+ finally
+ if Result=nil then
+ Call.Free;
end;
end;
@@ -7201,18 +8152,44 @@ begin
end;
function TPasToJSConverter.CreateImplementationSection(El: TPasModule;
- Src: TJSSourceElements; AContext: TConvertContext): TJSElement;
+ AContext: TConvertContext
+ ): TJSFunctionDeclarationStatement;
var
- Section: TImplementationSection;
+ Src: TJSSourceElements;
+ ImplContext: TSectionContext;
+ ImplDecl: TJSElement;
+ ImplVarSt: TJSVariableStatement;
+ FunDecl: TJSFunctionDeclarationStatement;
begin
Result:=nil;
- if not Assigned(El.ImplementationSection) then
- exit;
- Section:=El.ImplementationSection;
- // add implementation section
- // merge interface and implementation
- Result:=ConvertDeclarations(Section,AContext);
- AddToSourceElements(Src,Result);
+ // create function(){}
+ FunDecl:=CreateFunction(El,true,true);
+ Src:=TJSSourceElements(FunDecl.AFunction.Body.A);
+
+ // create section context (a function)
+ ImplContext:=TSectionContext.Create(El,Src,AContext);
+ try
+ if coUseStrict in Options then
+ AddToSourceElements(Src,CreateLiteralString(El,'use strict'));
+
+ // add var $impl = this.$impl
+ ImplVarSt:=CreateVarStatement(FBuiltInNames[pbivnImplementation],
+ CreateMemberExpression(['this',FBuiltInNames[pbivnImplementation]]),El);
+ AddToSourceElements(Src,ImplVarSt);
+
+ ImplContext.This:=El;
+ // create implementation declarations
+ ImplDecl:=ConvertDeclarations(El.ImplementationSection,ImplContext);
+ if ImplDecl=nil then
+ exit;
+ // add impl declarations
+ AddToSourceElements(Src,ImplDecl);
+ Result:=FunDecl;
+ finally
+ ImplContext.Free;
+ if Result=nil then
+ FunDecl.Free;
+ end;
end;
procedure TPasToJSConverter.CreateInitSection(El: TPasModule;
@@ -7333,7 +8310,7 @@ var
begin
Call:=CreateCallExpression(El);
Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnSet_Reference]]);
- Call.Args.Elements.AddElement.Expr:=SetExpr;
+ Call.AddArg(SetExpr);
Result:=Call;
end;
@@ -7349,7 +8326,7 @@ begin
NewExpr:=TJSNewMemberExpression(CreateElement(TJSNewMemberExpression,El));
NewExpr.MExpr:=CreateReferencePathExpr(ResolvedEl.TypeEl,AContext);
NewExpr.Args:=TJSArguments(CreateElement(TJSArguments,El));
- NewExpr.Args.Elements.AddElement.Expr:=RecordExpr;
+ NewExpr.AddArg(RecordExpr);
Result:=NewExpr;
end;
@@ -7416,9 +8393,9 @@ begin
{$ENDIF}
DoError(20170215161802,nInvalidFunctionReference,sInvalidFunctionReference,[],El);
end;
- Call.Args.Elements.AddElement.Expr:=Scope;
+ Call.AddArg(Scope);
// add function name as parameter
- Call.Args.Elements.AddElement.Expr:=CreateLiteralString(El,FunName);
+ Call.AddArg(CreateLiteralString(El,FunName));
end
else if Scope.ClassType=TJSPrimaryExpressionIdent then
begin
@@ -7430,18 +8407,18 @@ begin
// chomp dotted identifier -> rtl.createCallback(scope,"FunName")
FunName:=copy(aName,DotPos+1);
Prim.Name:=TJSString(LeftStr(aName,DotPos-1));
- Call.Args.Elements.AddElement.Expr:=Prim;
+ Call.AddArg(Prim);
// add function name as parameter
- Call.Args.Elements.AddElement.Expr:=CreateLiteralString(El,FunName);
+ Call.AddArg(CreateLiteralString(El,FunName));
end
else
begin
// nested proc -> rtl.createCallback(this,FunName)
FunName:=aName;
Prim.Name:='this';
- Call.Args.Elements.AddElement.Expr:=Prim;
+ Call.AddArg(Prim);
// add function as parameter
- Call.Args.Elements.AddElement.Expr:=CreateBuiltInIdentifierExpr(FunName);
+ Call.AddArg(CreateBuiltInIdentifierExpr(FunName));
end;
end
else
@@ -7490,6 +8467,449 @@ begin
end;
end;
+function TPasToJSConverter.CreateTypeInfoRef(El: TPasType;
+ AContext: TConvertContext; ErrorEl: TPasElement): TJSElement;
+var
+ C: TClass;
+ aName, aModName: String;
+ bt: TResolverBaseType;
+ jbt: TPas2jsBaseType;
+ Parent: TPasElement;
+ aModule: TPasModule;
+ Bracket: TJSBracketMemberExpression;
+begin
+ El:=AContext.Resolver.ResolveAliasType(El);
+ if El=nil then
+ RaiseInconsistency(20170409172756);
+ if El=AContext.PasElement then
+ begin
+ // refering itself
+ if El is TPasClassType then
+ begin
+ // use this
+ Result:=CreateBuiltInIdentifierExpr(FBuiltInNames[pbivnRTTILocal]);
+ exit;
+ end
+ else
+ RaiseNotSupported(ErrorEl,AContext,20170409195518,'cannot typeinfo itself');
+ end;
+ if El.Name='' then
+ RaiseNotSupported(El,AContext,20170412125911,'typeinfo of anonymous '+El.ElementTypeName);
+
+ C:=El.ClassType;
+ if C=TPasUnresolvedSymbolRef then
+ begin
+ if El.CustomData is TResElDataBaseType then
+ begin
+ bt:=TResElDataBaseType(El.CustomData).BaseType;
+ case bt of
+ btLongint,btCardinal,btSmallInt,btWord,btShortInt,btByte,
+ btString,btChar,
+ btDouble,
+ btBoolean,
+ btPointer:
+ begin
+ // create rtl.basename
+ Result:=CreateMemberExpression([FBuiltInNames[pbivnRTL],lowercase(BaseTypeNames[bt])]);
+ exit;
+ end;
+ btCustom:
+ if El.CustomData is TResElDataPas2JSBaseType then
+ begin
+ jbt:=TResElDataPas2JSBaseType(El.CustomData).JSBaseType;
+ case jbt of
+ pbtJSValue:
+ begin
+ // create rtl.basename
+ Result:=CreateMemberExpression([FBuiltInNames[pbivnRTL],lowercase(Pas2jsBaseTypeNames[jbt])]);
+ exit;
+ end;
+ else
+ {$IFDEF VerbosePas2JS}
+ writeln('TPasToJSConverter.CreateTypeInfoRef [20170409174539] El=',GetObjName(El),' El.CustomData=',GetObjName(El.CustomData),' jbt=',Pas2jsBaseTypeNames[jbt]);
+ {$ENDIF}
+ end;
+ end
+ else
+ begin
+ {$IFDEF VerbosePas2JS}
+ writeln('TPasToJSConverter.CreateTypeInfoRef [20170409174645] El=',GetObjName(El),' El.CustomData=',GetObjName(El.CustomData),' bt=',BaseTypeNames[bt]);
+ {$ENDIF}
+ end
+ else
+ {$IFDEF VerbosePas2JS}
+ writeln('TPasToJSConverter.CreateTypeInfoRef [20170409173746] El=',GetObjName(El),' El.CustomData=',GetObjName(El.CustomData),' bt=',BaseTypeNames[bt]);
+ {$ENDIF}
+ end;
+ end
+ else
+ begin
+ {$IFDEF VerbosePas2JS}
+ writeln('TPasToJSConverter.CreateTypeInfoRef [20170409173729] El=',GetObjName(El),' El.CustomData=',GetObjName(El.CustomData));
+ {$ENDIF}
+ end;
+ end
+ else if (C=TPasEnumType)
+ or (C=TPasSetType)
+ or (C=TPasClassType)
+ or (C=TPasClassOfType)
+ or (C=TPasArrayType)
+ or (C=TPasProcedureType)
+ or (C=TPasFunctionType)
+ or (C=TPasPointerType)
+ // ToDo or (C=TPasTypeAliasType)
+ or (C=TPasRecordType)
+ // ToDo or (C=TPasRangeType)
+ then
+ begin
+ // user type -> module.$rtti[typename]
+ aName:=TransformVariableName(El,AContext);
+ if aName='' then
+ DoError(20170411230435,nPasElementNotSupported,sPasElementNotSupported,
+ ['typeinfo of anonymous '+El.ElementTypeName+' not supported'],ErrorEl);
+ Parent:=El.Parent;
+ while Parent.ClassType=TPasClassType do
+ begin
+ aName:=TransformVariableName(Parent,AContext)+'.'+aName;
+ Parent:=Parent.Parent;
+ end;
+ if Parent is TPasSection then
+ begin
+ aModule:=Parent.Parent as TPasModule;
+ if AContext.GetThis=aModule then
+ aModName:='this'
+ else
+ aModName:=TransformModuleName(aModule,true,AContext);
+ Bracket:=TJSBracketMemberExpression(CreateElement(TJSBracketMemberExpression,El));
+ Bracket.MExpr:=CreateMemberExpression([aModName,FBuiltInNames[pbivnRTTI]]);
+ Bracket.Name:=CreateLiteralString(El,aName);
+ Result:=Bracket;
+ exit;
+ end;
+ end;
+ aName:=El.Name;
+ if aName='' then aName:=El.ClassName;
+ DoError(20170409173329,nTypeXCannotBePublished,sTypeXCannotBePublished,
+ [aName],ErrorEl);
+end;
+
+function TPasToJSConverter.CreateRTTIArgList(Parent: TPasElement;
+ Args: TFPList; AContext: TConvertContext): TJSElement;
+var
+ Params: TJSArrayLiteral;
+ i: Integer;
+begin
+ Result:=nil;
+ if Args.Count=0 then
+ Result:=CreateLiteralNull(Parent)
+ else
+ begin
+ try
+ Params:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,Parent));
+ for i:=0 to Args.Count-1 do
+ AddRTTIArgument(TPasArgument(Args[i]),Params,AContext);
+ Result:=Params;
+ finally
+ if Result=nil then
+ Params.Free;
+ end;
+ end;
+end;
+
+procedure TPasToJSConverter.AddRTTIArgument(Arg: TPasArgument;
+ TargetParams: TJSArrayLiteral; AContext: TConvertContext);
+var
+ Param: TJSArrayLiteral;
+ ArgName: String;
+ Flags: Integer;
+begin
+ // for each param add "["argname",argtype,flags]" Note: flags only if >0
+ Param:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,Arg));
+ TargetParams.Elements.AddElement.Expr:=Param;
+ // add "argname"
+ ArgName:=TransformVariableName(Arg,Arg.Name,AContext);
+ Param.Elements.AddElement.Expr:=CreateLiteralString(Arg,ArgName);
+ // add "argtype"
+ if Arg.ArgType=nil then
+ // untyped
+ Param.Elements.AddElement.Expr:=CreateLiteralNull(Arg)
+ else
+ Param.Elements.AddElement.Expr:=CreateTypeInfoRef(Arg.ArgType,AContext,Arg);
+ // add flags
+ Flags:=0;
+ case Arg.Access of
+ argDefault: ;
+ argConst: inc(Flags,pfConst);
+ argVar: inc(Flags,pfVar);
+ argOut: inc(Flags,pfOut);
+ else
+ RaiseNotSupported(Arg,AContext,20170409192127,AccessNames[Arg.Access]);
+ end;
+ if Flags>0 then
+ Param.Elements.AddElement.Expr:=CreateLiteralNumber(Arg,Flags);
+end;
+
+function TPasToJSConverter.CreateRTTINewType(El: TPasType;
+ const CallFuncName: string; IsForward: boolean; AContext: TConvertContext;
+ out ObjLit: TJSObjectLiteral): TJSCallExpression;
+// module.$rtti.$TiSomething("name",{})
+var
+ ThisContext: TFunctionContext;
+ RttiPath, TypeName: String;
+ Call: TJSCallExpression;
+begin
+ Result:=nil;
+ ObjLit:=nil;
+ // get module path
+ ThisContext:=AContext.GetThisContext;
+ if ThisContext=nil then
+ RaiseInconsistency(20170411151517);
+ if ThisContext.This is TPasModule then
+ RttiPath:='this'
+ else
+ begin
+ RttiPath:=TransformModuleName(ThisContext.GetRootModule,true,AContext);
+ end;
+ Call:=CreateCallExpression(El);
+ try
+ // module.$rtti.$ProcVar
+ Call.Expr:=CreateMemberExpression([RttiPath,FBuiltInNames[pbivnRTTI],CallFuncName]);
+ // add param "typename"
+ TypeName:=TransformVariableName(El,AContext);
+ Call.AddArg(CreateLiteralString(El,TypeName));
+ if not IsForward then
+ begin
+ // add {}
+ ObjLit:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,El));
+ Call.AddArg(ObjLit);
+ end;
+ Result:=Call;
+ finally
+ if Result=nil then
+ Call.Free;
+ end;
+end;
+
+function TPasToJSConverter.CreateRTTIClassField(V: TPasVariable;
+ AContext: TConvertContext): TJSElement;
+// create $r.addField("varname",typeinfo);
+var
+ Call: TJSCallExpression;
+var
+ JSTypeInfo: TJSElement;
+ aName: String;
+begin
+ Result:=nil;
+ JSTypeInfo:=CreateTypeInfoRef(V.VarType,AContext,V);
+ // Note: create JSTypeInfo first, it may raise an exception
+ Call:=CreateCallExpression(V);
+ // $r.addField
+ Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTTILocal],FBuiltInNames[pbifnRTTIAddField]]);
+ // param "varname"
+ aName:=TransformVariableName(V,AContext);
+ Call.AddArg(CreateLiteralString(V,aName));
+ // param typeinfo
+ Call.AddArg(JSTypeInfo);
+ Result:=Call;
+end;
+
+function TPasToJSConverter.CreateRTTIClassMethod(Proc: TPasProcedure;
+ AContext: TConvertContext): TJSElement;
+// create $r.addMethod("funcname",methodkind,params,resulttype,options)
+var
+ OptionsEl: TJSObjectLiteral;
+ ResultTypeInfo: TJSElement;
+ Call: TJSCallExpression;
+
+ procedure AddOption(const aName: String; JS: TJSElement);
+ var
+ ObjLit: TJSObjectLiteralElement;
+ begin
+ if OptionsEl=nil then
+ begin
+ OptionsEl:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,Proc));
+ if ResultTypeInfo=nil then
+ Call.AddArg(CreateLiteralNull(Proc));
+ Call.AddArg(OptionsEl);
+ end;
+ ObjLit:=OptionsEl.Elements.AddElement;
+ ObjLit.Name:=TJSString(aName);
+ ObjLit.Expr:=JS;
+ end;
+
+var
+ FunName: String;
+ C: TClass;
+ MethodKind, Flags: Integer;
+ ResultEl: TPasResultElement;
+ ProcScope, OverriddenProcScope: TPasProcedureScope;
+ OverriddenClass: TPasClassType;
+begin
+ Result:=nil;
+ if Proc.IsOverride then
+ begin
+ ProcScope:=Proc.CustomData as TPasProcedureScope;
+ if ProcScope.OverriddenProc.Visibility=visPublished then
+ begin
+ // overridden proc is published as well
+ OverriddenProcScope:=ProcScope.OverriddenProc.CustomData as TPasProcedureScope;
+ OverriddenClass:=OverriddenProcScope.ClassScope.Element as TPasClassType;
+ if HasTypeInfo(OverriddenClass,AContext) then
+ exit; // overridden proc was already published in ancestor
+ end;
+ end;
+ OptionsEl:=nil;
+ ResultTypeInfo:=nil;
+ try
+ // $r.addMethod
+ Call:=CreateCallExpression(Proc);
+ Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTTILocal],FBuiltInNames[pbifnRTTIAddMethod]]);
+
+ // param "funname"
+ FunName:=TransformVariableName(Proc,AContext);
+ Call.AddArg(CreateLiteralString(Proc,FunName));
+
+ // param methodkind as number
+ C:=Proc.ClassType;
+ if C=TPasProcedure then
+ MethodKind:=ord(mkProcedure)
+ else if C=TPasFunction then
+ MethodKind:=ord(mkFunction)
+ else if C=TPasConstructor then
+ MethodKind:=ord(mkConstructor)
+ else if C=TPasDestructor then
+ MethodKind:=ord(mkDestructor)
+ else if C=TPasClassProcedure then
+ MethodKind:=ord(mkClassProcedure)
+ else if C=TPasClassFunction then
+ MethodKind:=ord(mkClassFunction)
+ else
+ RaiseNotSupported(Proc,AContext,20170409190242);
+ Call.AddArg(CreateLiteralNumber(Proc,MethodKind));
+
+ // param params as []
+ Call.AddArg(CreateRTTIArgList(Proc,Proc.ProcType.Args,AContext));
+
+ // param resulttype as typeinfo reference
+ if C.InheritsFrom(TPasFunction) then
+ begin
+ ResultEl:=TPasFunction(Proc).FuncType.ResultEl;
+ ResultTypeInfo:=CreateTypeInfoRef(ResultEl.ResultType,AContext,ResultEl);
+ if ResultTypeInfo<>nil then
+ Call.AddArg(ResultTypeInfo);
+ end;
+
+ // param options if needed as {}
+ Flags:=0;
+ if Proc.IsStatic then
+ inc(Flags,pfStatic);
+ if ptmVarargs in Proc.ProcType.Modifiers then
+ inc(Flags,pfVarargs);
+ if Proc.IsExternal then
+ inc(Flags,pfExternal);
+ if Flags>0 then
+ AddOption(FBuiltInNames[pbivnRTTIProcFlags],CreateLiteralNumber(Proc,Flags));
+
+ Result:=Call;
+ finally
+ if Result=nil then
+ Call.Free;
+ end;
+end;
+
+function TPasToJSConverter.CreateRTTIClassProperty(Prop: TPasProperty;
+ AContext: TConvertContext): TJSElement;
+// create $r.addProperty("propname",flags,result,"getter","setter",{options})
+var
+ Call: TJSCallExpression;
+ OptionsEl: TJSObjectLiteral;
+
+ function GetAccessorName(Decl: TPasElement): String;
+ begin
+ Result:=TransformVariableName(Decl,AContext);
+ end;
+
+ procedure AddOption(const aName: String; JS: TJSElement);
+ var
+ ObjLit: TJSObjectLiteralElement;
+ begin
+ if OptionsEl=nil then
+ begin
+ OptionsEl:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,Prop));
+ Call.AddArg(OptionsEl);
+ end;
+ ObjLit:=OptionsEl.Elements.AddElement;
+ ObjLit.Name:=TJSString(aName);
+ ObjLit.Expr:=JS;
+ end;
+
+var
+ PropName: String;
+ Flags: Integer;
+ GetterPas, StoredPas, SetterPas: TPasElement;
+ ResultTypeInfo: TJSElement;
+begin
+ Result:=nil;
+ OptionsEl:=nil;
+ try
+ // $r.addProperty
+ Call:=CreateCallExpression(Prop);
+ Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTTILocal],FBuiltInNames[pbifnRTTIAddProperty]]);
+
+ // param "propname"
+ PropName:=TransformVariableName(Prop,Prop.Name,AContext);
+ Call.AddArg(CreateLiteralString(Prop,PropName));
+
+ // add flags
+ Flags:=0;
+ GetterPas:=AContext.Resolver.GetPasPropertyGetter(Prop);
+ if GetterPas is TPasProcedure then
+ inc(Flags,pfGetFunction);
+ SetterPas:=AContext.Resolver.GetPasPropertySetter(Prop);
+ if SetterPas is TPasProcedure then
+ inc(Flags,pfSetProcedure);
+ StoredPas:=AContext.Resolver.GetPasPropertyStored(Prop);
+ if StoredPas is TPasProcedure then
+ inc(Flags,pfStoredFunction);
+ Call.AddArg(CreateLiteralNumber(Prop,Flags));
+
+ // add resulttype
+ ResultTypeInfo:=CreateTypeInfoRef(Prop.VarType,AContext,Prop);
+ if ResultTypeInfo<>nil then
+ Call.AddArg(ResultTypeInfo)
+ else
+ Call.AddArg(CreateLiteralNull(Prop));
+
+ // add "getter"
+ if GetterPas=nil then
+ Call.AddArg(CreateLiteralString(Prop,''))
+ else
+ Call.AddArg(CreateLiteralString(GetterPas,GetAccessorName(GetterPas)));
+
+ // add "setter"
+ if SetterPas=nil then
+ Call.AddArg(CreateLiteralString(Prop,''))
+ else
+ Call.AddArg(CreateLiteralString(SetterPas,GetAccessorName(SetterPas)));
+
+ // add option "stored"
+ if StoredPas<>nil then
+ AddOption(FBuiltInNames[pbivnRTTIPropStored],
+ CreateLiteralString(StoredPas,GetAccessorName(StoredPas)));
+
+ // add option defaultvalue
+ // ToDo
+
+ // add option Index
+ // ToDo
+
+ Result:=Call;
+ finally
+ if Result=nil then
+ Call.Free;
+ end;
+end;
+
function TPasToJSConverter.ConvertImplBlock(El: TPasImplBlock;
AContext: TConvertContext): TJSElement;
@@ -7579,10 +8999,6 @@ begin
RaiseNotSupported(El.DispIDExpr,AContext,20170215103029,'property dispid expression');
if El.DefaultExpr<>nil then
RaiseNotSupported(El.DefaultExpr,AContext,20170215103129,'property default modifier');
- if El.StoredAccessor<>nil then
- RaiseNotSupported(El.StoredAccessor,AContext,20170215121145,'property stored accessor');
- if El.StoredAccessorName<>'' then
- RaiseNotSupported(El,AContext,20170215121248,'property stored accessor');
// does not need any declaration. Access is redirected to getter/setter.
end;
@@ -7850,7 +9266,6 @@ Var
ForSt : TJSForStatement;
List, ListEnd: TJSStatementList;
SimpleAss : TJSSimpleAssignStatement;
- VarDecl : TJSVarDeclaration;
Incr, Decr : TJSUNaryExpression;
BinExp : TJSBinaryExpression;
VarStat: TJSVariableStatement;
@@ -7916,12 +9331,9 @@ begin
ListEnd:=List;
try
// add "var $loopend=<EndExpr>"
- VarStat:=TJSVariableStatement(CreateElement(TJSVariableStatement,El));
+ VarStat:=CreateVarStatement(CurLoopEndVarName,
+ ConvertElement(El.EndExpr,AContext),El);
List.A:=VarStat;
- VarDecl:=TJSVarDeclaration(CreateElement(TJSVarDeclaration,El));
- VarStat.A:=VarDecl;
- VarDecl.Name:=CurLoopEndVarName;
- VarDecl.Init:=ConvertElement(El.EndExpr,AContext);
// add "for()"
ForSt:=TJSForStatement(CreateElement(TJSForStatement,El));
List.B:=ForSt;
@@ -8007,7 +9419,6 @@ Var
ok: Boolean;
PasExpr: TPasElement;
V: TJSVariableStatement;
- VarDecl: TJSVarDeclaration;
FuncContext: TFunctionContext;
FirstSt, LastSt: TJSStatementList;
WithScope: TPasWithScope;
@@ -8039,11 +9450,7 @@ begin
WithExprScope:=WithScope.ExpressionScopes[i] as TPas2JSWithExprScope;
WithExprScope.WithVarName:=FuncContext.CreateLocalIdentifier(FBuiltInNames[pbivnWith]);
// create local "var $with1 = expr;"
- V:=TJSVariableStatement(CreateElement(TJSVariableStatement,PasExpr));
- VarDecl:=TJSVarDeclaration(CreateElement(TJSVarDeclaration,PasExpr));
- V.A:=VarDecl;
- VarDecl.Name:=WithExprScope.WithVarName;
- VarDecl.Init:=Expr;
+ V:=CreateVarStatement(WithExprScope.WithVarName,Expr,PasExpr);
AddToStatementList(FirstSt,LastSt,V,PasExpr);
end;
if Assigned(El.Body) then
@@ -8098,6 +9505,51 @@ begin
Result:=true;
end;
+function TPasToJSConverter.HasTypeInfo(El: TPasType; AContext: TConvertContext
+ ): boolean;
+begin
+ Result:=false;
+ if coNoTypeInfo in Options then exit;
+ if AContext.Resolver=nil then exit;
+ if not AContext.Resolver.HasTypeInfo(El) then exit;
+ if Assigned(OnIsTypeInfoUsed) and not OnIsTypeInfoUsed(Self,El) then exit;
+ Result:=true;
+end;
+
+function TPasToJSConverter.IsClassRTTICreatedBefore(aClass: TPasClassType;
+ Before: TPasElement): boolean;
+var
+ Decls: TPasDeclarations;
+ i: Integer;
+ Types: TFPList;
+ T: TPasType;
+ C: TClass;
+begin
+ Result:=false;
+ if aClass.Parent=nil then exit;
+ if not aClass.Parent.InheritsFrom(TPasDeclarations) then
+ RaiseInconsistency(20170412101457);
+ Decls:=TPasDeclarations(aClass.Parent);
+ Types:=Decls.Types;
+ for i:=0 to Types.Count-1 do
+ begin
+ T:=TPasType(Types[i]);
+ if T=Before then exit;
+ if T=aClass then exit(true);
+ C:=T.ClassType;
+ if C=TPasClassType then
+ begin
+ if TPasClassType(T).IsForward and (T.CustomData is TResolvedReference)
+ and (TResolvedReference(T.CustomData).Declaration=aClass) then
+ exit(true);
+ end
+ else if C=TPasClassOfType then
+ begin
+ if TPasClassOfType(T).DestType=aClass then exit(true);
+ end;
+ end;
+end;
+
procedure TPasToJSConverter.RaiseInconsistency(Id: int64);
begin
raise Exception.Create('TPasToJSConverter.RaiseInconsistency['+IntToStr(Id)+']: you found a bug');
@@ -8179,7 +9631,7 @@ procedure TPasToJSConverter.AddToStatementList(var First,
var
SL2: TJSStatementList;
begin
- if not Assigned(Add) then exit;
+ if Add=nil then exit;
if Add is TJSStatementList then
begin
// add list
@@ -8246,37 +9698,58 @@ var
Lit: TJSLiteral;
bt: TResolverBaseType;
JSBaseType: TPas2jsBaseType;
+ C: TClass;
begin
T:=PasType;
if AContext.Resolver<>nil then
T:=AContext.Resolver.ResolveAliasType(T);
- if (T is TPasArrayType) then
+ //writeln('START TPasToJSConverter.CreateValInit PasType=',GetObjName(PasType),' El=',GetObjName(El),' T=',GetObjName(T),' Expr=',GetObjName(Expr));
+ if T=nil then
+ begin
+ // untyped var/const
+ if Expr=nil then
+ begin
+ if AContext.Resolver=nil then
+ exit(CreateLiteralUndefined(El));
+ RaiseInconsistency(20170415185745);
+ end;
+ Result:=ConvertElement(Expr,AContext);
+ if Result=nil then
+ begin
+ {$IFDEF VerbosePas2JS}
+ writeln('TPasToJSConverter.CreateValInit PasType=',GetObjName(PasType),' El=',GetObjName(El),' T=',GetObjName(T),' Expr=',GetObjName(Expr));
+ {$ENDIF}
+ RaiseNotSupported(Expr,AContext,20170415185927);
+ end;
+ exit;
+ end;
+
+ C:=T.ClassType;
+ if C=TPasArrayType then
Result:=CreateArrayInit(TPasArrayType(T),Expr,El,AContext)
- else if T is TPasRecordType then
+ else if C=TPasRecordType then
Result:=CreateRecordInit(TPasRecordType(T),Expr,El,AContext)
else if Assigned(Expr) then
Result:=ConvertElement(Expr,AContext)
- else if T is TPasSetType then
+ else if C=TPasSetType then
Result:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,El))
else
begin
// always init with a default value to create a typed variable (faster and more readable)
Lit:=TJSLiteral(CreateElement(TJSLiteral,El));
Result:=Lit;
- if T=nil then
- Lit.Value.IsUndefined:=true
- else if (T.ClassType=TPasPointerType)
- or (T.ClassType=TPasClassType)
- or (T.ClassType=TPasClassOfType)
- or (T.ClassType=TPasProcedureType)
- or (T.ClassType=TPasFunctionType) then
+ if (C=TPasPointerType)
+ or (C=TPasClassType)
+ or (C=TPasClassOfType)
+ or (C=TPasProcedureType)
+ or (C=TPasFunctionType) then
Lit.Value.IsNull:=true
- else if T.ClassType=TPasStringType then
+ else if C=TPasStringType then
Lit.Value.AsString:=''
- else if T.ClassType=TPasEnumType then
+ else if C=TPasEnumType then
Lit.Value.AsNumber:=0
- else if T.ClassType=TPasUnresolvedSymbolRef then
+ else if C=TPasUnresolvedSymbolRef then
begin
if T.CustomData is TResElDataBaseType then
begin
@@ -8305,6 +9778,13 @@ begin
RaiseNotSupported(PasType,AContext,20170208162121);
end;
end
+ else if AContext.Resolver<>nil then
+ begin
+ {$IFDEF VerbosePas2JS}
+ writeln('TPasToJSConverter.CreateValInit PasType=',GetObjName(PasType),' El=',GetObjName(El),' T=',GetObjName(T),' Expr=',GetObjName(Expr));
+ {$ENDIF}
+ RaiseNotSupported(El,AContext,20170415190259);
+ end
else if (CompareText(T.Name,'longint')=0)
or (CompareText(T.Name,'int64')=0)
or (CompareText(T.Name,'real')=0)
@@ -8333,6 +9813,13 @@ begin
RaiseNotSupported(PasType,AContext,20170208161506);
end;
end;
+ if Result=nil then
+ begin
+ {$IFDEF VerbosePas2JS}
+ writeln('TPasToJSConverter.CreateValInit PasType=',GetObjName(PasType),' El=',GetObjName(El),' T=',GetObjName(T),' Expr=',GetObjName(Expr));
+ {$ENDIF}
+ RaiseNotSupported(El,AContext,20170415190103);
+ end;
end;
function TPasToJSConverter.CreateVarInit(El: TPasVariable;
@@ -8341,6 +9828,21 @@ begin
Result:=CreateValInit(El.VarType,El.Expr,El,AContext);
end;
+function TPasToJSConverter.CreateVarStatement(const aName: String;
+ Init: TJSElement; El: TPasElement): TJSVariableStatement;
+begin
+ Result:=TJSVariableStatement(CreateElement(TJSVariableStatement,El));
+ Result.A:=CreateVarDecl(aName,Init,El);
+end;
+
+function TPasToJSConverter.CreateVarDecl(const aName: String; Init: TJSElement;
+ El: TPasElement): TJSVarDeclaration;
+begin
+ Result:=TJSVarDeclaration(CreateElement(TJSVarDeclaration,El));
+ Result.Name:=aName;
+ Result.Init:=Init;
+end;
+
function TPasToJSConverter.CreateLiteralNumber(El: TPasElement;
const n: TJSNumber): TJSLiteral;
begin
@@ -8381,6 +9883,86 @@ begin
Result.Value.IsUndefined:=true;
end;
+function TPasToJSConverter.CreateSetLiteralElement(Expr: TPasExpr;
+ AContext: TConvertContext): TJSElement;
+var
+ LitVal: TJSValue;
+ NewEl: TJSElement;
+ WS: TJSString;
+ ExprResolved: TPasResolverResult;
+ Call: TJSCallExpression;
+ DotExpr: TJSDotMemberExpression;
+begin
+ Result:=ConvertElement(Expr,AContext);
+ if Result=nil then
+ RaiseNotSupported(Expr,AContext,20170415192209);
+ if Result.ClassType=TJSLiteral then
+ begin
+ // argument is a literal -> convert to number
+ LitVal:=TJSLiteral(Result).Value;
+ case LitVal.ValueType of
+ jstBoolean:
+ begin
+ if LitVal.AsBoolean=LowJSBoolean then
+ NewEl:=CreateLiteralNumber(Expr,0)
+ else
+ NewEl:=CreateLiteralNumber(Expr,1);
+ Result.Free;
+ exit(NewEl);
+ end;
+ jstNumber:
+ exit;
+ jstString:
+ begin
+ WS:=LitVal.AsString;
+ Result.Free;
+ if length(WS)<>1 then
+ DoError(20170415193254,nXExpectedButYFound,sXExpectedButYFound,['char','string'],Expr);
+ Result:=CreateLiteralNumber(Expr,ord(WS[1]));
+ exit;
+ end;
+ else
+ RaiseNotSupported(Expr,AContext,20170415205955);
+ end;
+ end
+ else if Result.ClassType=TJSCallExpression then
+ begin
+ Call:=TJSCallExpression(Result);
+ if (Call.Expr is TJSDotMemberExpression) then
+ begin
+ DotExpr:=TJSDotMemberExpression(Call.Expr);
+ if DotExpr.Name='charCodeAt' then
+ exit;
+ if DotExpr.Name='charAt' then
+ begin
+ DotExpr.Name:='charCodeAt';
+ exit;
+ end;
+ end;
+ end;
+
+ if AContext.Resolver<>nil then
+ begin
+ AContext.Resolver.ComputeElement(Expr,ExprResolved,[]);
+ if ExprResolved.BaseType in btAllStringAndChars then
+ begin
+ // aChar -> aChar.charCodeAt()
+ Call:=TJSCallExpression(CreateElement(TJSCallExpression,Expr));
+ Call.Expr:=CreateDotExpression(Expr,Result,CreateBuiltInIdentifierExpr('charCodeAt'));
+ Result:=Call;
+ end
+ else if ExprResolved.BaseType=btContext then
+ begin
+ if ExprResolved.TypeEl.ClassType=TPasEnumType then
+ // ok
+ else
+ RaiseNotSupported(Expr,AContext,20170415191933);
+ end
+ else
+ RaiseNotSupported(Expr,AContext,20170415191822);
+ end;
+end;
+
function TPasToJSConverter.CreateRecordInit(aRecord: TPasRecordType;
Expr: TPasElement; El: TPasElement; AContext: TConvertContext): TJSElement;
// new recordtype()
@@ -8447,7 +10029,7 @@ begin
Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnArray_NewMultiDim]]);
// add parameter [dim1,dim2,...]
DimArray:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,El));
- Call.Args.Elements.AddElement.Expr:=DimArray;
+ Call.AddArg(DimArray);
CurArrayType:=ArrayType;
while true do
begin
@@ -8477,7 +10059,7 @@ begin
// add parameter defaultvalue
DefaultValue:=CreateValInit(ElTypeResolved.TypeEl,nil,El,AContext);
- Call.Args.Elements.AddElement.Expr:=DefaultValue;
+ Call.AddArg(DefaultValue);
Result:=Call;
finally
@@ -8497,7 +10079,7 @@ begin
RaiseInconsistency(20170401184819);
Call:=CreateCallExpression(El);
Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnArray_Length]]);
- Call.Args.Elements.AddElement.Expr:=JSArray;
+ Call.AddArg(JSArray);
if OpCode=eopEqual then
BinExpr:=TJSEqualityExpressionEQ(CreateElement(TJSEqualityExpressionEQ,El))
else
@@ -8640,7 +10222,7 @@ begin
Result:='';
exit;
end
- else if (El is TPasClassType) and TPasClassType(El).IsExternal then
+ else if (El.ClassType=TPasClassType) and TPasClassType(El).IsExternal then
begin
Result:=TPasClassType(El).ExternalName;
exit;
@@ -8658,7 +10240,7 @@ begin
end;
ThisContext:=AContext.GetThisContext;
if ThisContext<>nil then
- This:=ThisContext.GetThis
+ This:=ThisContext.This
else
This:=nil;
ParentEl:=El.Parent;
@@ -8685,8 +10267,7 @@ begin
Prepend(Result,FBuiltInNames[pbivnImplementation])
else
// in other unit -> use pas.unitname.$impl
- Prepend(Result,FBuiltInNames[pbivnModules]
- +'.'+TransformModuleName(FoundModule,AContext)
+ Prepend(Result,TransformModuleName(FoundModule,true,AContext)
+'.'+FBuiltInNames[pbivnImplementation]);
end;
break;
@@ -8697,8 +10278,7 @@ begin
if ParentEl=This then
Prepend(Result,'this')
else
- Prepend(Result,FBuiltInNames[pbivnModules]
- +'.'+TransformModuleName(TPasModule(ParentEl),AContext));
+ Prepend(Result,TransformModuleName(TPasModule(ParentEl),true,AContext));
break;
end
else if (ParentEl.ClassType=TPasClassType)
@@ -9167,8 +10747,6 @@ Var
DotExpr: TJSDotMemberExpression;
Call: TJSCallExpression;
V: TJSVariableStatement;
- VarDecl: TJSVarDeclaration;
-
begin
Result:=nil;
// create "if()"
@@ -9181,7 +10759,7 @@ begin
// create "T.isPrototypeOf(exceptObject)"
Call:=CreateCallExpression(El);
Call.Expr:=DotExpr;
- Call.Args.Elements.AddElement.Expr:=CreateBuiltInIdentifierExpr(FBuiltInNames[pbivnExceptObject]);
+ Call.AddArg(CreateBuiltInIdentifierExpr(FBuiltInNames[pbivnExceptObject]));
IfSt.Cond:=Call;
if El.VarEl<>nil then
@@ -9190,12 +10768,9 @@ begin
ListFirst:=TJSStatementList(CreateElement(TJSStatementList,El.Body));
ListLast:=ListFirst;
IfSt.BTrue:=ListFirst;
- V:=TJSVariableStatement(CreateElement(TJSVariableStatement,El));
+ V:=CreateVarStatement(TransformVariableName(El,El.VariableName,AContext),
+ CreateBuiltInIdentifierExpr(FBuiltInNames[pbivnExceptObject]),El);
ListFirst.A:=V;
- VarDecl:=TJSVarDeclaration(CreateElement(TJSVarDeclaration,El));
- V.A:=VarDecl;
- VarDecl.Name:=TransformVariableName(El,El.VariableName,AContext);
- VarDecl.Init:=CreateBuiltInIdentifierExpr(FBuiltInNames[pbivnExceptObject]);
// add statements
AddToStatementList(ListFirst,ListLast,ConvertElement(El.Body,AContext),El);
end
@@ -9250,7 +10825,6 @@ end;
function TPasToJSConverter.ConvertConst(El: TPasConst; AContext: TConvertContext
): TJSElement;
// Important: returns nil if const was added to higher context
-
Var
AssignSt: TJSSimpleAssignStatement;
Obj: TJSObjectLiteral;
@@ -9535,7 +11109,7 @@ const
Call:=CreateCallExpression(PasVar);
Add_AndExpr_ToReturnSt(RetSt,PasVar,LastAndExpr,Call);
Call.Expr:=CreateMemberExpression(['this',VarName,FBuiltInNames[pbifnRecordEqual]]);
- Call.Args.Elements.AddElement.Expr:=CreateMemberExpression([EqualParamName,VarName]);
+ Call.AddArg(CreateMemberExpression([EqualParamName,VarName]));
end
else if VarType.ClassType=TPasSetType then
begin
@@ -9544,8 +11118,8 @@ const
Call:=CreateCallExpression(PasVar);
Add_AndExpr_ToReturnSt(RetSt,PasVar,LastAndExpr,Call);
Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnSet_Equal]]);
- Call.Args.Elements.AddElement.Expr:=CreateMemberExpression(['this',VarName]);
- Call.Args.Elements.AddElement.Expr:=CreateMemberExpression([EqualParamName,VarName]);
+ Call.AddArg(CreateMemberExpression(['this',VarName]));
+ Call.AddArg(CreateMemberExpression([EqualParamName,VarName]));
end
else if VarType is TPasProcedureType then
begin
@@ -9554,8 +11128,8 @@ const
Call:=CreateCallExpression(PasVar);
Add_AndExpr_ToReturnSt(RetSt,PasVar,LastAndExpr,Call);
Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnProcType_Equal]]);
- Call.Args.Elements.AddElement.Expr:=CreateMemberExpression(['this',VarName]);
- Call.Args.Elements.AddElement.Expr:=CreateMemberExpression([EqualParamName,VarName]);
+ Call.AddArg(CreateMemberExpression(['this',VarName]));
+ Call.AddArg(CreateMemberExpression([EqualParamName,VarName]));
end
else
begin
@@ -9568,33 +11142,53 @@ const
end;
end;
+ procedure AddRTTIFields(Args: TJSArguments);
+ var
+ i: Integer;
+ PasVar: TPasVariable;
+ begin
+ for i:=0 to El.Members.Count-1 do
+ begin
+ PasVar:=TPasVariable(El.Members[i]);
+ if not IsElementUsed(PasVar) then continue;
+ // add quoted "fieldname"
+ Args.AddElement(CreateLiteralString(PasVar,TransformVariableName(PasVar,AContext)));
+ // add typeinfo ref
+ Args.AddElement(CreateTypeInfoRef(PasVar.VarType,AContext,PasVar));
+ end;
+ end;
+
var
AssignSt: TJSSimpleAssignStatement;
FDS: TJSFunctionDeclarationStatement;
FD: TJSFuncDef;
- BodyFirst, BodyLast: TJSStatementList;
+ BodyFirst, BodyLast, List: TJSStatementList;
FuncContext: TFunctionContext;
- Obj: TJSObjectLiteral;
- ObjLit: TJSObjectLiteralElement;
+ ObjLit: TJSObjectLiteral;
+ ObjEl: TJSObjectLiteralElement;
IfSt: TJSIfStatement;
+ Call: TJSCallExpression;
+ ok: Boolean;
begin
Result:=nil;
FuncContext:=nil;
- AssignSt:=nil;
+ ok:=false;
try
FDS:=CreateFunction(El);
if AContext is TObjectContext then
begin
// add 'TypeName: function(){}'
- Obj:=TObjectContext(AContext).JSElement as TJSObjectLiteral;
- ObjLit:=Obj.Elements.AddElement;
- ObjLit.Name:=TJSString(TransformVariableName(El,AContext));
- ObjLit.Expr:=FDS;
+ ObjLit:=TObjectContext(AContext).JSElement as TJSObjectLiteral;
+ Result:=ObjLit;
+ ObjEl:=ObjLit.Elements.AddElement;
+ ObjEl.Name:=TJSString(TransformVariableName(El,AContext));
+ ObjEl.Expr:=FDS;
end
else
begin
// add 'this.TypeName = function(){}'
AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
+ Result:=AssignSt;
AssignSt.LHS:=CreateDeclNameExpression(El,El.Name,AContext);
AssignSt.Expr:=FDS;
end;
@@ -9624,10 +11218,38 @@ begin
AddEqualFunction(BodyFirst,BodyLast,FuncContext);
end;
- Result:=AssignSt;
+
+ if HasTypeInfo(El,AContext) then
+ begin
+ // add $rtti as second statement
+ if not (AContext is TFunctionContext) then
+ RaiseNotSupported(El,AContext,20170412120012);
+
+ List:=TJSStatementList(CreateElement(TJSStatementList,El));
+ List.A:=Result;
+ Result:=List;
+ // module.$rtti.$Record("typename",{});
+ Call:=CreateRTTINewType(El,FBuiltInNames[pbifnRTTINewRecord],false,AContext,ObjLit);
+ List.B:=Call;
+ if ObjLit=nil then
+ RaiseInconsistency(20170412124804);
+ if El.Members.Count>0 then
+ begin
+ // module.$rtti.$Record("typename",{}).addFields(
+ // "fieldname1",type1,"fieldname2",type2,...
+ // );
+ Call:=CreateCallExpression(El);
+ Call.Expr:=CreateDotExpression(El,List.B,
+ CreateBuiltInIdentifierExpr(FBuiltInNames[pbifnRTTIAddFields]));
+ List.B:=Call;
+ AddRTTIFields(Call.Args);
+ end;
+ end;
+ ok:=true;;
finally
FuncContext.Free;
- if Result=nil then AssignSt.Free;
+ if not ok then
+ FreeAndNil(Result);
end;
end;
@@ -9747,12 +11369,14 @@ begin
end;
function TPasToJSConverter.TransformModuleName(El: TPasModule;
- AContext: TConvertContext): String;
+ AddModulesPrefix: boolean; AContext: TConvertContext): String;
begin
if El is TPasProgram then
Result:='program'
else
Result:=TransformVariableName(El,AContext);
+ if AddModulesPrefix then
+ Result:=FBuiltInNames[pbivnModules]+'.'+Result;
end;
function TPasToJSConverter.IsPreservedWord(const aName: string): boolean;
diff --git a/packages/pastojs/tests/tcmodules.pas b/packages/pastojs/tests/tcmodules.pas
index 784dfcb780..7c29627770 100644
--- a/packages/pastojs/tests/tcmodules.pas
+++ b/packages/pastojs/tests/tcmodules.pas
@@ -28,7 +28,9 @@ uses
pastree, PScanner, PasResolver, PParser, jstree, jswriter, jsbase;
const
+ // default parser+scanner options
po_pas2js = [po_asmwhole,po_resolvestandardtypes];
+ co_tcmodules = [coNoTypeInfo];
type
{ TTestPasParser }
@@ -73,7 +75,10 @@ type
FExpectedErrorNumber: integer;
FFilename: string;
FFileResolver: TStreamResolver;
+ FJSImplementationSrc: TJSSourceElements;
+ FJSImplementationUses: TJSArrayLiteral;
FJSInitBody: TJSFunctionBody;
+ FJSImplentationUses: TJSArrayLiteral;
FJSInterfaceUses: TJSArrayLiteral;
FJSModule: TJSSourceElements;
FJSModuleSrc: TJSSourceElements;
@@ -113,7 +118,8 @@ type
Procedure ConvertUnit; virtual;
procedure CheckDottedIdentifier(Msg: string; El: TJSElement; DottedName: string);
function GetDottedIdentifier(El: TJSElement): string;
- procedure CheckSource(Msg,Statements, InitStatements: string); virtual;
+ procedure CheckSource(Msg,Statements: String; InitStatements: string = '';
+ ImplStatements: string = ''); virtual;
procedure CheckDiff(Msg, Expected, Actual: string); virtual;
procedure SetExpectedPasResolverError(Msg: string; MsgNumber: integer);
procedure SetExpectedConverterError(Msg: string; MsgNumber: integer);
@@ -137,9 +143,11 @@ type
property JSModule: TJSSourceElements read FJSModule;
property JSRegModuleCall: TJSCallExpression read FJSRegModuleCall;
property JSModuleCallArgs: TJSArguments read FJSModuleCallArgs;
+ property JSImplementationUses: TJSArrayLiteral read FJSImplementationUses;
property JSInterfaceUses: TJSArrayLiteral read FJSInterfaceUses;
property JSModuleSrc: TJSSourceElements read FJSModuleSrc;
property JSInitBody: TJSFunctionBody read FJSInitBody;
+ property JSImplementationSrc: TJSSourceElements read FJSImplementationSrc;
property ExpectedErrorClass: ExceptClass read FExpectedErrorClass write FExpectedErrorClass;
property ExpectedErrorMsg: string read FExpectedErrorMsg write FExpectedErrorMsg;
property ExpectedErrorNumber: integer read FExpectedErrorNumber write FExpectedErrorNumber;
@@ -215,28 +223,34 @@ type
Procedure TestExit;
Procedure TestBreak;
Procedure TestContinue;
- Procedure TestProcedureExternal;
- Procedure TestProcedureExternalOtherUnit;
- Procedure TestProcedure_Asm;
- Procedure TestProcedureAssembler;
- Procedure TestProcedure_VarParam;
- Procedure TestProcedureOverload;
- Procedure TestProcedureOverloadForward;
- Procedure TestProcedureOverloadUnit;
- Procedure TestProcedureOverloadNested;
+ Procedure TestProc_External;
+ Procedure TestProc_ExternalOtherUnit;
+ Procedure TestProc_Asm;
+ Procedure TestProc_Assembler;
+ Procedure TestProc_VarParam;
+ Procedure TestProc_Overload;
+ Procedure TestProc_OverloadForward;
+ Procedure TestProc_OverloadUnit;
+ Procedure TestProc_OverloadNested;
Procedure TestProc_Varargs;
// enums, sets
- Procedure TestEnumName;
- Procedure TestEnumNumber;
- Procedure TestEnumFunctions;
+ Procedure TestEnum_Name;
+ Procedure TestEnum_Number;
+ Procedure TestEnum_Functions;
+ Procedure TestEnum_AsParams;
Procedure TestSet;
- Procedure TestSetOperators;
- Procedure TestSetFunctions;
+ Procedure TestSet_Operators;
+ Procedure TestSet_Operator_In;
+ Procedure TestSet_Functions;
Procedure TestSet_PassAsArgClone;
- Procedure TestEnum_AsParams;
Procedure TestSet_AsParams;
Procedure TestSet_Property;
+ Procedure TestSet_EnumConst;
+ Procedure TestSet_AnonymousEnumType;
+ Procedure TestSet_CharFail;
+ Procedure TestSet_BooleanFail;
+ Procedure TestSet_ConstChar;
// statements
Procedure TestNestBegin;
@@ -279,8 +293,9 @@ type
Procedure TestArray_InsertDelete;
Procedure TestExternalClass_TypeCastArrayToExternalArray;
Procedure TestExternalClass_TypeCastArrayFromExternalArray;
- // ToDo: const array
+ // ToDo: array const
// ToDo: SetLength(array of static array)
+ // ToDo: SetLength(dim1,dim2)
// record
Procedure TestRecord_Var;
@@ -371,7 +386,6 @@ type
Procedure TestExternalClass_TypeCastToRootClass;
Procedure TestExternalClass_TypeCastStringToExternalString;
Procedure TestExternalClass_CallClassFunctionOfInstanceFail;
- Procedure TestExternalClass_BracketOperatorOld;
Procedure TestExternalClass_BracketAccessor;
Procedure TestExternalClass_BracketAccessor_2ParamsFail;
Procedure TestExternalClass_BracketAccessor_ReadOnly;
@@ -389,6 +403,14 @@ type
Procedure TestProcType_PropertyDelphi;
Procedure TestProcType_WithClassInstDoPropertyFPC;
Procedure TestProcType_Nested;
+ Procedure TestProcType_Typecast;
+
+ // pointer
+ Procedure TestPointer;
+ Procedure TestPointer_Proc;
+ Procedure TestPointer_AssignRecordFail;
+ Procedure TestPointer_AssignStaticArrayFail;
+ Procedure TestPointer_ArrayParamsFail;
// jsvalue
Procedure TestJSValue_AssignToJSValue;
@@ -403,6 +425,38 @@ type
Procedure TestJSValue_FuncResultType;
Procedure TestJSValue_ProcType_Assign;
Procedure TestJSValue_ProcType_Equal;
+
+ // RTTI
+ Procedure TestRTTI_ProcType;
+ Procedure TestRTTI_ProcType_ArgFromOtherUnit;
+ Procedure TestRTTI_EnumAndSetType;
+ Procedure TestRTTI_AnonymousEnumType;
+ Procedure TestRTTI_StaticArray;
+ Procedure TestRTTI_DynArray;
+ Procedure TestRTTI_ArrayNestedAnonymous;
+ // ToDo: Procedure TestRTTI_Pointer;
+ Procedure TestRTTI_PublishedMethodOverloadFail;
+ Procedure TestRTTI_PublishedMethodExternalFail;
+ Procedure TestRTTI_PublishedClassPropertyFail;
+ Procedure TestRTTI_PublishedClassFieldFail;
+ Procedure TestRTTI_PublishedFieldExternalFail;
+ Procedure TestRTTI_Class_Field;
+ Procedure TestRTTI_Class_Method;
+ Procedure TestRTTI_Class_Property;
+ Procedure TestRTTI_Class_PropertyParams;
+ // ToDo: property default value
+ Procedure TestRTTI_OverrideMethod;
+ Procedure TestRTTI_OverloadProperty;
+ // ToDo: array argument
+ Procedure TestRTTI_ClassForward;
+ Procedure TestRTTI_ClassOf;
+ Procedure TestRTTI_Record;
+ Procedure TestRTTI_LocalTypes;
+ Procedure TestRTTI_TypeInfo_BaseTypes;
+ Procedure TestRTTI_TypeInfo_LocalFail;
+ Procedure TestRTTI_TypeInfo_ExtTypeInfoClasses1;
+ Procedure TestRTTI_TypeInfo_ExtTypeInfoClasses2;
+ Procedure TestRTTI_TypeInfo_ExtTypeInfoClasses3;
end;
function LinesToStr(Args: array of const): string;
@@ -573,7 +627,7 @@ begin
Parser.Options:=Parser.Options+po_pas2js;
FModule:=Nil;
FConverter:=TPasToJSConverter.Create;
- FConverter.UseLowerCase:=false;
+ FConverter.Options:=co_tcmodules;
FExpectedErrorClass:=nil;
end;
@@ -584,6 +638,7 @@ begin
FJSModule:=nil;
FJSRegModuleCall:=nil;
FJSModuleCallArgs:=nil;
+ FJSImplentationUses:=nil;
FJSInterfaceUses:=nil;
FJSModuleSrc:=nil;
FJSInitBody:=nil;
@@ -697,7 +752,7 @@ begin
Fail('TTestModuleConverter.AddModule: file "'+aFilename+'" already exists');
Result:=TTestEnginePasResolver.Create;
Result.Filename:=aFilename;
- Result.AddObjFPCBuiltInIdentifiers([btChar,btString,btLongint,btInt64,btBoolean,btDouble]);
+ Result.AddObjFPCBuiltInIdentifiers(btAllPas2jsBaseTypes,bfAllPas2jsBaseProcs);
Result.OnFindUnit:=@OnPasResolverFindUnit;
FModules.Add(Result);
end;
@@ -763,14 +818,61 @@ begin
end;
procedure TCustomTestModule.ConvertModule;
+
+ procedure CheckUsesList(UsesName: String; Arg: TJSArrayLiteralElement;
+ out UsesLit: TJSArrayLiteral);
+ var
+ i: Integer;
+ Item: TJSElement;
+ Lit: TJSLiteral;
+ begin
+ UsesLit:=nil;
+ AssertNotNull(UsesName+' uses section',Arg.Expr);
+ if (Arg.Expr.ClassType=TJSLiteral) and TJSLiteral(Arg.Expr).Value.IsNull then
+ exit; // null is ok
+ AssertEquals(UsesName+' uses section param is array',TJSArrayLiteral,Arg.Expr.ClassType);
+ FJSInterfaceUses:=TJSArrayLiteral(Arg.Expr);
+ for i:=0 to FJSInterfaceUses.Elements.Count-1 do
+ begin
+ Item:=FJSInterfaceUses.Elements.Elements[i].Expr;
+ AssertNotNull(UsesName+' uses section item['+IntToStr(i)+'].Expr',Item);
+ AssertEquals(UsesName+' uses section item['+IntToStr(i)+'] is lit',TJSLiteral,Item.ClassType);
+ Lit:=TJSLiteral(Item);
+ AssertEquals(UsesName+' uses section item['+IntToStr(i)+'] is string lit',
+ ord(jsbase.jstString),ord(Lit.Value.ValueType));
+ end;
+ end;
+
+ procedure CheckFunctionParam(ParamName: string; Arg: TJSArrayLiteralElement;
+ out Src: TJSSourceElements);
+ var
+ FunDecl: TJSFunctionDeclarationStatement;
+ FunDef: TJSFuncDef;
+ FunBody: TJSFunctionBody;
+ begin
+ Src:=nil;
+ AssertNotNull(ParamName,Arg.Expr);
+ AssertEquals(ParamName+' Arg.Expr type',TJSFunctionDeclarationStatement,Arg.Expr.ClassType);
+ FunDecl:=Arg.Expr as TJSFunctionDeclarationStatement;
+ AssertNotNull(ParamName+' FunDecl.AFunction',FunDecl.AFunction);
+ AssertEquals(ParamName+' FunDecl.AFunction type',TJSFuncDef,FunDecl.AFunction.ClassType);
+ FunDef:=FunDecl.AFunction as TJSFuncDef;
+ AssertEquals(ParamName+' name empty','',String(FunDef.Name));
+ AssertNotNull(ParamName+' body',FunDef.Body);
+ AssertEquals(ParamName+' body type',TJSFunctionBody,FunDef.Body.ClassType);
+ FunBody:=FunDef.Body as TJSFunctionBody;
+ AssertNotNull(ParamName+' body.A',FunBody.A);
+ AssertEquals(ParamName+' body.A type',TJSSourceElements,FunBody.A.ClassType);
+ Src:=FunBody.A as TJSSourceElements;
+ end;
+
var
ModuleNameExpr: TJSLiteral;
- FunDecl, InitFunction: TJSFunctionDeclarationStatement;
- FunDef: TJSFuncDef;
+ InitFunction: TJSFunctionDeclarationStatement;
InitAssign: TJSSimpleAssignStatement;
- FunBody: TJSFunctionBody;
InitName: String;
LastNode: TJSElement;
+ Arg: TJSArrayLiteralElement;
begin
if SkipTests then exit;
try
@@ -807,11 +909,13 @@ begin
AssertNotNull('register module rtl.module args',JSRegModuleCall.Args);
AssertEquals('rtl.module args',TJSArguments,JSRegModuleCall.Args.ClassType);
FJSModuleCallArgs:=JSRegModuleCall.Args as TJSArguments;
- AssertEquals('rtl.module args.count',3,JSModuleCallArgs.Elements.Count);
// parameter 'unitname'
- AssertNotNull('module name param',JSModuleCallArgs.Elements.Elements[0].Expr);
- ModuleNameExpr:=JSModuleCallArgs.Elements.Elements[0].Expr as TJSLiteral;
+ if JSModuleCallArgs.Elements.Count<1 then
+ Fail('rtl.module first param unit missing');
+ Arg:=JSModuleCallArgs.Elements.Elements[0];
+ AssertNotNull('module name param',Arg.Expr);
+ ModuleNameExpr:=Arg.Expr as TJSLiteral;
AssertEquals('module name param is string',ord(jstString),ord(ModuleNameExpr.Value.ValueType));
if Module is TPasProgram then
AssertEquals('module name','program',String(ModuleNameExpr.Value.AsString))
@@ -819,22 +923,18 @@ begin
AssertEquals('module name',Module.Name,String(ModuleNameExpr.Value.AsString));
// main uses section
- AssertNotNull('interface uses section',JSModuleCallArgs.Elements.Elements[1].Expr);
- AssertEquals('interface uses section type',TJSArrayLiteral,JSModuleCallArgs.Elements.Elements[1].Expr.ClassType);
- FJSInterfaceUses:=JSModuleCallArgs.Elements.Elements[1].Expr as TJSArrayLiteral;
-
- // function()
- AssertNotNull('module function',JSModuleCallArgs.Elements.Elements[2].Expr);
- AssertEquals('module function type',TJSFunctionDeclarationStatement,JSModuleCallArgs.Elements.Elements[2].Expr.ClassType);
- FunDecl:=JSModuleCallArgs.Elements.Elements[2].Expr as TJSFunctionDeclarationStatement;
- AssertNotNull('module function def',FunDecl.AFunction);
- FunDef:=FunDecl.AFunction as TJSFuncDef;
- AssertEquals('module function name','',String(FunDef.Name));
- AssertNotNull('module function body',FunDef.Body);
- FunBody:=FunDef.Body as TJSFunctionBody;
- FJSModuleSrc:=FunBody.A as TJSSourceElements;
-
- // init this.$main - the last statement
+ if JSModuleCallArgs.Elements.Count<2 then
+ Fail('rtl.module second param main uses missing');
+ Arg:=JSModuleCallArgs.Elements.Elements[1];
+ CheckUsesList('interface',Arg,FJSInterfaceUses);
+
+ // program/library/interface function()
+ if JSModuleCallArgs.Elements.Count<3 then
+ Fail('rtl.module third param intf-function missing');
+ Arg:=JSModuleCallArgs.Elements.Elements[2];
+ CheckFunctionParam('module intf-function',Arg,FJSModuleSrc);
+
+ // search for this.$init or this.$main - the last statement
if Module is TPasProgram then
begin
InitName:='$main';
@@ -858,6 +958,18 @@ begin
CheckDottedIdentifier('init function',InitAssign.LHS,'this.'+InitName);
end;
end;
+
+ // optional: implementation uses section
+ if JSModuleCallArgs.Elements.Count<4 then
+ exit;
+ Arg:=JSModuleCallArgs.Elements.Elements[3];
+ CheckUsesList('implementation',Arg,FJSImplentationUses);
+
+ // optional: implementation function()
+ if JSModuleCallArgs.Elements.Count<5 then
+ exit;
+ Arg:=JSModuleCallArgs.Elements.Elements[4];
+ CheckFunctionParam('module impl-function',Arg,FJSImplementationSrc);
end;
procedure TCustomTestModule.ConvertProgram;
@@ -900,7 +1012,8 @@ begin
AssertEquals('GetDottedIdentifier',TJSPrimaryExpressionIdent,El.ClassType);
end;
-procedure TCustomTestModule.CheckSource(Msg, Statements, InitStatements: string);
+procedure TCustomTestModule.CheckSource(Msg, Statements: String;
+ InitStatements: string; ImplStatements: string);
var
ActualSrc, ExpectedSrc, InitName: String;
begin
@@ -910,13 +1023,26 @@ begin
InitName:='$main'
else
InitName:='$init';
- if (Module is TPasProgram) or (InitStatements<>'') then
+ if (Module is TPasProgram) or (Trim(InitStatements)<>'') then
ExpectedSrc:=ExpectedSrc+LineEnding
+'this.'+InitName+' = function () {'+LineEnding
+InitStatements
+'};'+LineEnding;
//writeln('TTestModule.CheckSource InitStatements="',InitStatements,'"');
CheckDiff(Msg,ExpectedSrc,ActualSrc);
+
+ if (JSImplementationSrc<>nil) then
+ begin
+ ActualSrc:=JSToStr(JSImplementationSrc);
+ ExpectedSrc:='var $impl = this.$impl;'+LineEnding+ImplStatements;
+ end
+ else
+ begin
+ ActualSrc:='';
+ ExpectedSrc:=ImplStatements;
+ end;
+ //writeln('TTestModule.CheckSource InitStatements="',InitStatements,'"');
+ CheckDiff(Msg,ExpectedSrc,ActualSrc);
end;
procedure TCustomTestModule.CheckDiff(Msg, Expected, Actual: string);
@@ -975,7 +1101,7 @@ var
break;
end;
until p^=#0;
- raise Exception.Create('diff found, but lines are the same, internal error');
+ Fail('diff found, but lines are the same, internal error');
end;
var
@@ -1072,7 +1198,7 @@ begin
WriteSources(E.Filename,E.Row,E.Column);
writeln('ERROR: TCustomTestModule.HandleParserError '+E.ClassName+':'+E.Message
+' '+E.Filename+'('+IntToStr(E.Row)+','+IntToStr(E.Column)+')'
- +' Line="'+Scanner.CurLine+'"'
+ +' MainModuleScannerLine="'+Scanner.CurLine+'"'
);
RaiseException(E);
end;
@@ -1105,8 +1231,11 @@ end;
procedure TCustomTestModule.HandleException(E: Exception);
begin
if IsErrorExpected(E) then exit;
- WriteSources('',0,0);
- writeln('ERROR: TCustomTestModule.HandleException '+E.ClassName+':'+E.Message);
+ if not (E is EAssertionFailedError) then
+ begin
+ WriteSources('',0,0);
+ writeln('ERROR: TCustomTestModule.HandleException '+E.ClassName+':'+E.Message);
+ end;
RaiseException(E);
end;
@@ -1141,6 +1270,7 @@ var
Line: string;
aModule: TTestEnginePasResolver;
begin
+ writeln('TCustomTestModule.WriteSources File="',aFilename,'" Row=',aRow,' Col=',aCol);
for i:=0 to ModuleCount-1 do
begin
aModule:=Modules[i];
@@ -1679,16 +1809,17 @@ begin
ConvertUnit;
CheckSource('TestUnitProcVar',
LinesToStr([ // statements
- 'var $impl = {',
- '};',
- 'this.$impl = $impl;',
+ 'var $impl = this.$impl;',
'this.Proc1 = function () {',
' var v1 = 0;',
'};',
- '$impl.v2 = "";'
- ]),
- '' // this.$init
- );
+ '']),
+ // this.$init
+ '',
+ // implementation
+ LinesToStr([
+ '$impl.v2 = "";',
+ '']));
end;
procedure TTestModule.TestImplProc;
@@ -1708,18 +1839,19 @@ begin
ConvertUnit;
CheckSource('TestImplProc',
LinesToStr([ // statements
- 'var $impl = {',
- '};',
- 'this.$impl = $impl;',
+ 'var $impl = this.$impl;',
'this.Proc1 = function () {',
'};',
- '$impl.Proc2 = function () {',
- '};',
'']),
LinesToStr([ // this.$init
'this.Proc1();',
'$impl.Proc2();',
- '']));
+ '']),
+ LinesToStr([ // implementation
+ '$impl.Proc2 = function () {',
+ '};',
+ ''])
+ );
end;
procedure TTestModule.TestFunctionResult;
@@ -2004,7 +2136,7 @@ begin
]));
end;
-procedure TTestModule.TestProcedureExternal;
+procedure TTestModule.TestProc_External;
begin
StartProgram(false);
Add('procedure Foo; external name ''console.log'';');
@@ -2028,7 +2160,7 @@ begin
]));
end;
-procedure TTestModule.TestProcedureExternalOtherUnit;
+procedure TTestModule.TestProc_ExternalOtherUnit;
begin
AddModuleWithIntfImplSrc('unit2.pas',
LinesToStr([
@@ -2068,7 +2200,7 @@ begin
]));
end;
-procedure TTestModule.TestProcedure_Asm;
+procedure TTestModule.TestProc_Asm;
begin
StartProgram(false);
Add('function DoIt: longint;');
@@ -2092,7 +2224,7 @@ begin
]));
end;
-procedure TTestModule.TestProcedureAssembler;
+procedure TTestModule.TestProc_Assembler;
begin
StartProgram(false);
Add('function DoIt: longint; assembler;');
@@ -2112,7 +2244,7 @@ begin
]));
end;
-procedure TTestModule.TestProcedure_VarParam;
+procedure TTestModule.TestProc_VarParam;
begin
StartProgram(false);
Add('type integer = longint;');
@@ -2179,7 +2311,7 @@ begin
]));
end;
-procedure TTestModule.TestProcedureOverload;
+procedure TTestModule.TestProc_Overload;
begin
StartProgram(false);
Add('procedure DoIt(vI: longint); begin end;');
@@ -2206,7 +2338,7 @@ begin
'']));
end;
-procedure TTestModule.TestProcedureOverloadForward;
+procedure TTestModule.TestProc_OverloadForward;
begin
StartProgram(false);
Add('procedure DoIt(vI: longint); forward;');
@@ -2229,7 +2361,7 @@ begin
'']));
end;
-procedure TTestModule.TestProcedureOverloadUnit;
+procedure TTestModule.TestProc_OverloadUnit;
begin
StartUnit(false);
Add('interface');
@@ -2251,30 +2383,30 @@ begin
ConvertUnit;
CheckSource('TestProcedureOverloadUnit',
LinesToStr([ // statements
- 'var $impl = {',
- '};',
- 'this.$impl = $impl;',
+ 'var $impl = this.$impl;',
'this.DoIt = function (vI) {',
'};',
'this.DoIt$1 = function (vI, vJ) {',
'};',
- '$impl.DoIt$3 = function (vI, vJ, vK) {',
- '};',
- '$impl.DoIt$4 = function (vI, vJ, vK, vL) {',
- '};',
- '$impl.DoIt$2 = function (vI, vJ, vK, vL, vM) {',
- '};',
'']),
- LinesToStr([
+ LinesToStr([ // this.$init
'this.DoIt(1);',
'this.DoIt$1(2, 3);',
'$impl.DoIt$3(4,5,6);',
'$impl.DoIt$4(7,8,9,10);',
'$impl.DoIt$2(11,12,13,14,15);',
+ '']),
+ LinesToStr([ // implementation
+ '$impl.DoIt$3 = function (vI, vJ, vK) {',
+ '};',
+ '$impl.DoIt$4 = function (vI, vJ, vK, vL) {',
+ '};',
+ '$impl.DoIt$2 = function (vI, vJ, vK, vL, vM) {',
+ '};',
'']));
end;
-procedure TTestModule.TestProcedureOverloadNested;
+procedure TTestModule.TestProc_OverloadNested;
begin
StartProgram(false);
Add('procedure DoIt(vA: longint); forward;');
@@ -2435,7 +2567,7 @@ begin
'']));
end;
-procedure TTestModule.TestEnumName;
+procedure TTestModule.TestEnum_Name;
begin
StartProgram(false);
Add('type TMyEnum = (Red, Green, Blue);');
@@ -2462,7 +2594,7 @@ begin
]));
end;
-procedure TTestModule.TestEnumNumber;
+procedure TTestModule.TestEnum_Number;
begin
Converter.Options:=Converter.Options+[coEnumNumbers];
StartProgram(false);
@@ -2489,7 +2621,7 @@ begin
]));
end;
-procedure TTestModule.TestEnumFunctions;
+procedure TTestModule.TestEnum_Functions;
begin
StartProgram(false);
Add('type TMyEnum = (Red, Green);');
@@ -2547,6 +2679,79 @@ begin
'']));
end;
+procedure TTestModule.TestEnum_AsParams;
+begin
+ StartProgram(false);
+ Add('type TEnum = (Red,Blue);');
+ Add('procedure DoIt(vG: TEnum; const vH: TEnum; var vI: TEnum);');
+ Add('var vJ: TEnum;');
+ Add('begin');
+ Add(' vg:=vg;');
+ Add(' vj:=vh;');
+ Add(' vi:=vi;');
+ Add(' doit(vg,vg,vg);');
+ Add(' doit(vh,vh,vj);');
+ Add(' doit(vi,vi,vi);');
+ Add(' doit(vj,vj,vj);');
+ Add('end;');
+ Add('var i: TEnum;');
+ Add('begin');
+ Add(' doit(i,i,i);');
+ ConvertProgram;
+ CheckSource('TestEnum_AsParams',
+ LinesToStr([ // statements
+ 'this.TEnum = {',
+ ' "0": "Red",',
+ ' Red: 0,',
+ ' "1": "Blue",',
+ ' Blue: 1',
+ '};',
+ 'this.DoIt = function (vG,vH,vI) {',
+ ' var vJ = 0;',
+ ' vG = vG;',
+ ' vJ = vH;',
+ ' vI.set(vI.get());',
+ ' this.DoIt(vG, vG, {',
+ ' get: function () {',
+ ' return vG;',
+ ' },',
+ ' set: function (v) {',
+ ' vG = v;',
+ ' }',
+ ' });',
+ ' this.DoIt(vH, vH, {',
+ ' get: function () {',
+ ' return vJ;',
+ ' },',
+ ' set: function (v) {',
+ ' vJ = v;',
+ ' }',
+ ' });',
+ ' this.DoIt(vI.get(), vI.get(), vI);',
+ ' this.DoIt(vJ, vJ, {',
+ ' get: function () {',
+ ' return vJ;',
+ ' },',
+ ' set: function (v) {',
+ ' vJ = v;',
+ ' }',
+ ' });',
+ '};',
+ 'this.i = 0;'
+ ]),
+ LinesToStr([
+ 'this.DoIt(this.i,this.i,{',
+ ' p: this,',
+ ' get: function () {',
+ ' return this.p.i;',
+ ' },',
+ ' set: function (v) {',
+ ' this.p.i = v;',
+ ' }',
+ '});'
+ ]));
+end;
+
procedure TTestModule.TestSet;
begin
StartProgram(false);
@@ -2593,7 +2798,7 @@ begin
'']));
end;
-procedure TTestModule.TestSetOperators;
+procedure TTestModule.TestSet_Operators;
begin
StartProgram(false);
Add('type');
@@ -2640,12 +2845,8 @@ begin
Add(' b:=vt>=[red];');
Add(' b:=[red]>=vt;');
Add(' b:=[red]>=[green];');
- Add(' b:=Red in vt;');
- Add(' b:=vc in vt;');
- Add(' b:=Green in [Red..Blue];');
- Add(' b:=vc in [Red..Blue];');
ConvertProgram;
- CheckSource('TestEnumName',
+ CheckSource('TestSet_Operators',
LinesToStr([ // statements
'this.TColor = {',
' "0":"Red",',
@@ -2696,14 +2897,58 @@ begin
'this.B = rtl.geSet(this.vT, rtl.createSet(this.TColor.Red));',
'this.B = rtl.geSet(rtl.createSet(this.TColor.Red), this.vT);',
'this.B = rtl.geSet(rtl.createSet(this.TColor.Red), rtl.createSet(this.TColor.Green));',
- 'this.B = this.vT[this.TColor.Red];',
- 'this.B = this.vT[this.vC];',
- 'this.B = rtl.createSet(null, this.TColor.Red, this.TColor.Blue)[this.TColor.Green];',
- 'this.B = rtl.createSet(null, this.TColor.Red, this.TColor.Blue)[this.vC];',
'']));
end;
-procedure TTestModule.TestSetFunctions;
+procedure TTestModule.TestSet_Operator_In;
+begin
+ StartProgram(false);
+ Add('type');
+ Add(' TColor = (Red, Green, Blue);');
+ Add(' TColors = set of tcolor;');
+ Add('var');
+ Add(' vC: tcolor;');
+ Add(' vT: tcolors;');
+ Add(' B: boolean;');
+ Add('begin');
+ Add(' b:=red in vt;');
+ Add(' b:=vc in vt;');
+ Add(' b:=green in [red..blue];');
+ Add(' b:=vc in [red..blue];');
+ Add(' ');
+ Add(' if red in vt then ;');
+ Add(' while vC in vt do ;');
+ Add(' repeat');
+ Add(' until vC in vt;');
+ ConvertProgram;
+ CheckSource('TestSet_Operator_In',
+ LinesToStr([ // statements
+ 'this.TColor = {',
+ ' "0":"Red",',
+ ' Red:0,',
+ ' "1":"Green",',
+ ' Green:1,',
+ ' "2":"Blue",',
+ ' Blue:2',
+ ' };',
+ 'this.vC = 0;',
+ 'this.vT = {};',
+ 'this.B = false;'
+ ]),
+ LinesToStr([
+ 'this.B = this.TColor.Red in this.vT;',
+ 'this.B = this.vC in this.vT;',
+ 'this.B = this.TColor.Green in rtl.createSet(null, this.TColor.Red, this.TColor.Blue);',
+ 'this.B = this.vC in rtl.createSet(null, this.TColor.Red, this.TColor.Blue);',
+ 'if (this.TColor.Red in this.vT) ;',
+ 'while (this.vC in this.vT) {',
+ '};',
+ 'do {',
+ '} while (!(this.vC in this.vT));',
+ '']));
+end;
+
+procedure TTestModule.TestSet_Functions;
begin
StartProgram(false);
Add('type');
@@ -2771,79 +3016,6 @@ begin
'']));
end;
-procedure TTestModule.TestEnum_AsParams;
-begin
- StartProgram(false);
- Add('type TEnum = (Red,Blue);');
- Add('procedure DoIt(vG: TEnum; const vH: TEnum; var vI: TEnum);');
- Add('var vJ: TEnum;');
- Add('begin');
- Add(' vg:=vg;');
- Add(' vj:=vh;');
- Add(' vi:=vi;');
- Add(' doit(vg,vg,vg);');
- Add(' doit(vh,vh,vj);');
- Add(' doit(vi,vi,vi);');
- Add(' doit(vj,vj,vj);');
- Add('end;');
- Add('var i: TEnum;');
- Add('begin');
- Add(' doit(i,i,i);');
- ConvertProgram;
- CheckSource('TestEnum_AsParams',
- LinesToStr([ // statements
- 'this.TEnum = {',
- ' "0": "Red",',
- ' Red: 0,',
- ' "1": "Blue",',
- ' Blue: 1',
- '};',
- 'this.DoIt = function (vG,vH,vI) {',
- ' var vJ = 0;',
- ' vG = vG;',
- ' vJ = vH;',
- ' vI.set(vI.get());',
- ' this.DoIt(vG, vG, {',
- ' get: function () {',
- ' return vG;',
- ' },',
- ' set: function (v) {',
- ' vG = v;',
- ' }',
- ' });',
- ' this.DoIt(vH, vH, {',
- ' get: function () {',
- ' return vJ;',
- ' },',
- ' set: function (v) {',
- ' vJ = v;',
- ' }',
- ' });',
- ' this.DoIt(vI.get(), vI.get(), vI);',
- ' this.DoIt(vJ, vJ, {',
- ' get: function () {',
- ' return vJ;',
- ' },',
- ' set: function (v) {',
- ' vJ = v;',
- ' }',
- ' });',
- '};',
- 'this.i = 0;'
- ]),
- LinesToStr([
- 'this.DoIt(this.i,this.i,{',
- ' p: this,',
- ' get: function () {',
- ' return this.p.i;',
- ' },',
- ' set: function (v) {',
- ' this.p.i = v;',
- ' }',
- '});'
- ]));
-end;
-
procedure TTestModule.TestSet_AsParams;
begin
StartProgram(false);
@@ -2961,6 +3133,147 @@ begin
'']));
end;
+procedure TTestModule.TestSet_EnumConst;
+begin
+ StartProgram(false);
+ Add('type');
+ Add(' TEnum = (Red,Blue);');
+ Add(' TEnums = set of TEnum;');
+ Add('const');
+ Add(' Orange = red;');
+ Add('var');
+ Add(' Enum: tenum;');
+ Add(' Enums: tenums;');
+ Add('begin');
+ Add(' Include(enums,orange);');
+ Add(' Exclude(enums,orange);');
+ Add(' if orange in enums then;');
+ Add(' if orange in [orange,red] then;');
+ ConvertProgram;
+ CheckSource('TestEnumConst',
+ LinesToStr([ // statements
+ 'this.TEnum = {',
+ ' "0": "Red",',
+ ' Red: 0,',
+ ' "1": "Blue",',
+ ' Blue: 1',
+ '};',
+ 'this.Orange = this.TEnum.Red;',
+ 'this.Enum = 0;',
+ 'this.Enums = {};',
+ '']),
+ LinesToStr([
+ 'this.Enums = rtl.includeSet(this.Enums, this.Orange);',
+ 'this.Enums = rtl.excludeSet(this.Enums, this.Orange);',
+ 'if (this.Orange in this.Enums) ;',
+ 'if (this.Orange in rtl.createSet(this.Orange, this.TEnum.Red)) ;',
+ '']));
+end;
+
+procedure TTestModule.TestSet_AnonymousEnumType;
+begin
+ StartProgram(false);
+ Add('type');
+ Add(' TFlags = set of (red, green);');
+ Add('const');
+ Add(' favorite = red;');
+ Add('var');
+ Add(' f: TFlags;');
+ Add(' i: longint;');
+ Add('begin');
+ Add(' Include(f,red);');
+ Add(' Include(f,favorite);');
+ Add(' i:=ord(red);');
+ Add(' i:=ord(favorite);');
+ Add(' i:=ord(low(TFlags));');
+ Add(' i:=ord(low(f));');
+ Add(' i:=ord(low(favorite));');
+ Add(' i:=ord(high(TFlags));');
+ Add(' i:=ord(high(f));');
+ Add(' i:=ord(high(favorite));');
+ Add(' f:=[green,favorite];');
+ ConvertProgram;
+ CheckSource('TestSet_AnonymousEnumType',
+ LinesToStr([ // statements
+ 'this.TFlags$a = {',
+ ' "0": "red",',
+ ' red: 0,',
+ ' "1": "green",',
+ ' green: 1',
+ '};',
+ 'this.favorite = this.TFlags$a.red;',
+ 'this.f = {};',
+ 'this.i = 0;',
+ '']),
+ LinesToStr([
+ 'this.f = rtl.includeSet(this.f, this.TFlags$a.red);',
+ 'this.f = rtl.includeSet(this.f, this.favorite);',
+ 'this.i = this.TFlags$a.red;',
+ 'this.i = this.favorite;',
+ 'this.i = this.TFlags$a.red;',
+ 'this.i = this.TFlags$a.red;',
+ 'this.i = this.TFlags$a.red;',
+ 'this.i = this.TFlags$a.green;',
+ 'this.i = this.TFlags$a.green;',
+ 'this.i = this.TFlags$a.green;',
+ 'this.f = rtl.createSet(this.TFlags$a.green, this.favorite);',
+ '']));
+end;
+
+procedure TTestModule.TestSet_CharFail;
+begin
+ StartProgram(false);
+ Add('type');
+ Add(' TChars = set of char;');
+ Add('begin');
+ SetExpectedPasResolverError('Not supported: set of Char',nNotSupportedX);
+ ConvertProgram;
+end;
+
+procedure TTestModule.TestSet_BooleanFail;
+begin
+ StartProgram(false);
+ Add('type');
+ Add(' TBools = set of boolean;');
+ Add('begin');
+ SetExpectedPasResolverError('Not supported: set of Boolean',nNotSupportedX);
+ ConvertProgram;
+end;
+
+procedure TTestModule.TestSet_ConstChar;
+begin
+ StartProgram(false);
+ Add('const');
+ Add(' LowChars = [''a''..''z''];');
+ Add(' Chars = LowChars+[''A''..''Z''];');
+ Add('var');
+ Add(' c: char;');
+ Add(' s: string;');
+ Add('begin');
+ Add(' if c in lowchars then ;');
+ Add(' if ''a'' in lowchars then ;');
+ Add(' if s[1] in lowchars then ;');
+ Add(' if c in chars then ;');
+ Add(' if c in [''a''..''z'',''_''] then ;');
+ Add(' if ''b'' in [''a''..''z'',''_''] then ;');
+ ConvertProgram;
+ CheckSource('TestSet_ConstChar',
+ LinesToStr([ // statements
+ 'this.LowChars = rtl.createSet(null, 97, 122);',
+ 'this.Chars = rtl.unionSet(this.LowChars, rtl.createSet(null, 65, 90));',
+ 'this.c = "";',
+ 'this.s = "";',
+ '']),
+ LinesToStr([
+ 'if (this.c.charCodeAt() in this.LowChars) ;',
+ 'if (97 in this.LowChars) ;',
+ 'if (this.s.charCodeAt(1 - 1) in this.LowChars) ;',
+ 'if (this.c.charCodeAt() in this.Chars) ;',
+ 'if (this.c.charCodeAt() in rtl.createSet(null, 97, 122, 95)) ;',
+ 'if (98 in rtl.createSet(null, 97, 122, 95)) ;',
+ '']));
+end;
+
procedure TTestModule.TestNestBegin;
begin
StartProgram(false);
@@ -2990,14 +3303,14 @@ begin
ConvertUnit;
CheckSource('TestUnitImplVars',
LinesToStr([ // statements
- 'var $impl = {',
- '};',
- 'this.$impl = $impl;',
+ 'var $impl = this.$impl;',
+ '']),
+ '', // this.$init
+ LinesToStr([ // implementation
'$impl.V1 = 0;',
'$impl.V2 = 3;',
- '$impl.V3 = "abc";'
- ]),
- '');
+ '$impl.V3 = "abc";',
+ '']) );
end;
procedure TTestModule.TestUnitImplConsts;
@@ -3012,14 +3325,14 @@ begin
ConvertUnit;
CheckSource('TestUnitImplConsts',
LinesToStr([ // statements
- 'var $impl = {',
- '};',
- 'this.$impl = $impl;',
+ 'var $impl = this.$impl;',
+ '']),
+ '', // this.$init
+ LinesToStr([ // implementation
'$impl.v1 = 3;',
'$impl.v2 = 4;',
- '$impl.v3 = "abc";'
- ]),
- '');
+ '$impl.v3 = "abc";',
+ '']) );
end;
procedure TTestModule.TestUnitImplRecord;
@@ -3037,9 +3350,11 @@ begin
ConvertUnit;
CheckSource('TestUnitImplRecord',
LinesToStr([ // statements
- 'var $impl = {',
- '};',
- 'this.$impl = $impl;',
+ 'var $impl = this.$impl;',
+ '']),
+ // this.$init
+ '$impl.aRec.i = 3;',
+ LinesToStr([ // implementation
'$impl.TMyRecord = function (s) {',
' if (s) {',
' this.i = s.i;',
@@ -3050,10 +3365,8 @@ begin
' return this.i == b.i;',
' };',
'};',
- '$impl.aRec = new $impl.TMyRecord();'
- ]),
- '$impl.aRec.i = 3;'
- );
+ '$impl.aRec = new $impl.TMyRecord();',
+ '']) );
end;
procedure TTestModule.TestRenameJSNameConflict;
@@ -3157,20 +3470,20 @@ begin
ConvertUnit;
CheckSource('TestVarExternalOtherUnit',
LinesToStr([
- 'var $impl = {',
- '};',
- 'this.$impl = $impl;',
- '$impl.d = 0.0;',
- '$impl.i = 0;',
+ 'var $impl = this.$impl;',
'']),
- LinesToStr([
+ LinesToStr([ // this.$init
'$impl.d = Global.NaN;',
'$impl.d = Global.NaN;',
'$impl.d = Global.NaN;',
'$impl.i = pas.unit2.iV;',
'$impl.i = pas.unit2.iV;',
'$impl.i = pas.unit2.iV;',
- '']));
+ '']),
+ LinesToStr([ // implementation
+ '$impl.d = 0.0;',
+ '$impl.i = 0;',
+ '']) );
end;
procedure TTestModule.TestCharConst;
@@ -3263,16 +3576,20 @@ begin
Add('var');
Add(' c: char;');
Add(' i: longint;');
+ Add(' s: string;');
Add('begin');
Add(' i:=ord(c);');
+ Add(' i:=ord(s[i]);');
ConvertProgram;
CheckSource('TestChar_Ord',
LinesToStr([
'this.c = "";',
- 'this.i = 0;'
+ 'this.i = 0;',
+ 'this.s = "";'
]),
LinesToStr([
'this.i = this.c.charCodeAt();',
+ 'this.i = this.s.charCodeAt(this.i-1);',
'']));
end;
@@ -3834,19 +4151,19 @@ begin
// ToDo: check use analyzer
CheckSource('TestAsmPas_Impl',
LinesToStr([
- 'var $impl = {',
- '};',
- 'this.$impl = $impl;',
+ 'var $impl = this.$impl;',
'this.cIntf = 1;',
'this.vIntf = 0;',
+ '']),
+ '', // this.$init
+ LinesToStr([ // implementation
'var cLoc = 3;',
'$impl.cImpl = 2;',
'$impl.vImpl = 0;',
'$impl.DoIt = function () {',
' var vLoc = 0;',
'};',
- '']),
- '');
+ '']) );
end;
procedure TTestModule.TestTryFinally;
@@ -7020,9 +7337,7 @@ begin
ConvertUnit;
CheckSource('TestClass_ExternalMethod',
LinesToStr([
- 'var $impl = {',
- '};',
- 'this.$impl = $impl;',
+ 'var $impl = this.$impl;',
'rtl.createClass(this, "TCar", pas.unit2.TObject, function () {',
' this.DoIt = function () {',
' this.$DoIntern();',
@@ -7031,9 +7346,8 @@ begin
' this.$DoIntern2();',
' };',
' });',
- '$impl.Obj = null;',
'']),
- LinesToStr([
+ LinesToStr([ // this.$init
'$impl.Obj.$DoIntern();',
'$impl.Obj.$DoIntern();',
'$impl.Obj.$DoIntern2();',
@@ -7045,7 +7359,10 @@ begin
'$with1.$DoIntern();',
'$with1.$DoIntern2();',
'$with1.$DoIntern2();',
- '']));
+ '']),
+ LinesToStr([ // implementation
+ '$impl.Obj = null;',
+ '']) );
end;
procedure TTestModule.TestClass_ExternalVirtualNameMismatchFail;
@@ -7118,16 +7435,13 @@ begin
ConvertUnit;
CheckSource('TestClass_ExternalVar',
LinesToStr([
- 'var $impl = {',
- '};',
- 'this.$impl = $impl;',
+ 'var $impl = this.$impl;',
'rtl.createClass(this, "TCar", pas.unit2.TObject, function () {',
' this.DoIt = function () {',
' this.$Intern = this.$Intern + 1;',
' this.$Intern2 = this.$Intern2 + 2;',
' };',
' });',
- '$impl.Obj = null;',
'']),
LinesToStr([
'$impl.Obj.$Intern = $impl.Obj.$Intern + 1;',
@@ -7135,6 +7449,9 @@ begin
'var $with1 = $impl.Obj;',
'$with1.$Intern = $with1.$Intern + 1;',
'$with1.$Intern2 = $with1.$Intern2 + 2;',
+ '']),
+ LinesToStr([ // implementation
+ '$impl.Obj = null;',
'']));
end;
@@ -8674,93 +8991,6 @@ begin
ConvertProgram;
end;
-procedure TTestModule.TestExternalClass_BracketOperatorOld;
-begin
- StartProgram(false);
- Add('{$modeswitch externalclass}');
- Add('type');
- Add(' TJSArray = class external name ''Array''');
- Add(' end;');
- Add(' TJSObject = class external name ''Object''');
- Add(' end;');
- Add('procedure DoIt(vI: JSValue; const vJ: jsvalue; var vK: jsvalue; out vL: jsvalue);');
- Add('begin end;');
- Add('var');
- Add(' Obj: tjsobject;');
- Add(' Arr: tjsarray;');
- Add(' s: string;');
- Add(' i: longint;');
- Add(' v: jsvalue;');
- Add('begin');
- Add(' arr[1]:=s;');
- Add(' arr[2]:=i;');
- Add(' arr[3]:=arr[4];');
- Add(' v:=arr[5];');
- Add(' v:=obj[''one''];');
- Add(' obj[''two'']:=i;');
- Add(' obj[''three'']:=v;');
- Add(' doit(arr[6],arr[7],arr[8],arr[9]);');
- Add(' doit(obj[''10''],obj[''11''],obj[''12''],obj[''13'']);');
- ConvertProgram;
- CheckSource('TestExternalClass_BracketOperator',
- LinesToStr([ // statements
- 'this.DoIt = function (vI, vJ, vK, vL) {',
- '};',
- 'this.Obj = null;',
- 'this.Arr = null;',
- 'this.s = "";',
- 'this.i = 0;',
- 'this.v = undefined;',
- '']),
- LinesToStr([ // this.$main
- 'this.Arr[1] = this.s;',
- 'this.Arr[2] = this.i;',
- 'this.Arr[3] = this.Arr[4];',
- 'this.v = this.Arr[5];',
- 'this.v = this.Obj["one"];',
- 'this.Obj["two"] = this.i;',
- 'this.Obj["three"] = this.v;',
- 'this.DoIt(this.Arr[6], this.Arr[7], {',
- ' a: 8,',
- ' p: this.Arr,',
- ' get: function () {',
- ' return this.p[this.a];',
- ' },',
- ' set: function (v) {',
- ' this.p[this.a] = v;',
- ' }',
- '}, {',
- ' a: 9,',
- ' p: this.Arr,',
- ' get: function () {',
- ' return this.p[this.a];',
- ' },',
- ' set: function (v) {',
- ' this.p[this.a] = v;',
- ' }',
- '});',
- ' this.DoIt(this.Obj["10"], this.Obj["11"], {',
- ' a: "12",',
- ' p: this.Obj,',
- ' get: function () {',
- ' return this.p[this.a];',
- ' },',
- ' set: function (v) {',
- ' this.p[this.a] = v;',
- ' }',
- '}, {',
- ' a: "13",',
- ' p: this.Obj,',
- ' get: function () {',
- ' return this.p[this.a];',
- ' },',
- ' set: function (v) {',
- ' this.p[this.a] = v;',
- ' }',
- '});',
- '']));
-end;
-
procedure TTestModule.TestExternalClass_BracketAccessor;
begin
StartProgram(false);
@@ -9798,6 +10028,196 @@ begin
'']));
end;
+procedure TTestModule.TestProcType_Typecast;
+begin
+ StartProgram(false);
+ Add('type');
+ Add(' TNotifyEvent = procedure(Sender: Pointer) of object;');
+ Add(' TEvent = procedure of object;');
+ Add(' TProcA = procedure(i: longint);');
+ Add(' TFuncB = function(i, j: longint): longint;');
+ Add('var');
+ Add(' Notify: TNotifyEvent;');
+ Add(' Event: TEvent;');
+ Add(' ProcA: TProcA;');
+ Add(' FuncB: TFuncB;');
+ Add(' p: pointer;');
+ Add('begin');
+ Add(' Notify:=TNotifyEvent(Event);');
+ Add(' Event:=TEvent(Event);');
+ Add(' Event:=TEvent(Notify);');
+ Add(' ProcA:=TProcA(FuncB);');
+ Add(' FuncB:=TFuncB(FuncB);');
+ Add(' FuncB:=TFuncB(ProcA);');
+ Add(' ProcA:=TProcA(p);');
+ Add(' FuncB:=TFuncB(p);');
+ Add(' p:=Pointer(Notify);');
+ Add(' p:=Notify;');
+ Add(' p:=Pointer(ProcA);');
+ Add(' p:=ProcA;');
+ Add(' p:=Pointer(FuncB);');
+ Add(' p:=FuncB;');
+ ConvertProgram;
+ CheckSource('TestProcType_Typecast',
+ LinesToStr([ // statements
+ 'this.Notify = null;',
+ 'this.Event = null;',
+ 'this.ProcA = null;',
+ 'this.FuncB = null;',
+ 'this.p = null;',
+ '']),
+ LinesToStr([ // this.$main
+ 'this.Notify = this.Event;',
+ 'this.Event = this.Event;',
+ 'this.Event = this.Notify;',
+ 'this.ProcA = this.FuncB;',
+ 'this.FuncB = this.FuncB;',
+ 'this.FuncB = this.ProcA;',
+ 'this.ProcA = this.p;',
+ 'this.FuncB = this.p;',
+ 'this.p = this.Notify;',
+ 'this.p = this.Notify;',
+ 'this.p = this.ProcA;',
+ 'this.p = this.ProcA;',
+ 'this.p = this.FuncB;',
+ 'this.p = this.FuncB;',
+ '']));
+end;
+
+procedure TTestModule.TestPointer;
+begin
+ StartProgram(false);
+ Add('type');
+ Add(' TObject = class end;');
+ Add(' TClass = class of TObject;');
+ Add(' TArrInt = array of longint;');
+ Add('var');
+ Add(' v: jsvalue;');
+ Add(' Obj: tobject;');
+ Add(' C: tclass;');
+ Add(' a: tarrint;');
+ Add(' p: Pointer;');
+ Add('begin');
+ Add(' p:=p;');
+ Add(' p:=nil;');
+ Add(' if p=nil then;');
+ Add(' if nil=p then;');
+ Add(' if Assigned(p) then;');
+ Add(' p:=Pointer(v);');
+ Add(' p:=obj;');
+ Add(' p:=c;');
+ Add(' p:=a;');
+ Add(' p:=tobject;');
+ Add(' obj:=TObject(p);');
+ Add(' c:=TClass(p);');
+ Add(' a:=TArrInt(p);');
+ ConvertProgram;
+ CheckSource('TestPointer',
+ LinesToStr([ // statements
+ 'rtl.createClass(this, "TObject", null, function () {',
+ ' this.$init = function () {',
+ ' };',
+ ' this.$final = function () {',
+ ' };',
+ '});',
+ 'this.v = undefined;',
+ 'this.Obj = null;',
+ 'this.C = null;',
+ 'this.a = [];',
+ 'this.p = null;',
+ '']),
+ LinesToStr([ // this.$main
+ 'this.p = this.p;',
+ 'this.p = null;',
+ 'if (this.p == null) ;',
+ 'if (null == this.p) ;',
+ 'if (this.p != null) ;',
+ 'this.p = this.v;',
+ 'this.p = this.Obj;',
+ 'this.p = this.C;',
+ 'this.p = this.a;',
+ 'this.p = this.TObject;',
+ 'this.Obj = this.p;',
+ 'this.C = this.p;',
+ 'this.a = this.p;',
+ '']));
+end;
+
+procedure TTestModule.TestPointer_Proc;
+begin
+ StartProgram(false);
+ Add('type');
+ Add(' TObject = class');
+ Add(' procedure DoIt; virtual; abstract;');
+ Add(' end;');
+ Add('procedure DoSome; begin end;');
+ Add('var');
+ Add(' o: TObject;');
+ Add(' p: Pointer;');
+ Add('begin');
+ Add(' p:=@DoSome;');
+ Add(' p:=@o.DoIt;');
+ ConvertProgram;
+ CheckSource('TestPointer_Proc',
+ LinesToStr([ // statements
+ 'rtl.createClass(this, "TObject", null, function () {',
+ ' this.$init = function () {',
+ ' };',
+ ' this.$final = function () {',
+ ' };',
+ '});',
+ 'this.DoSome = function () {',
+ '};',
+ 'this.o = null;',
+ 'this.p = null;',
+ '']),
+ LinesToStr([ // this.$main
+ 'this.p = rtl.createCallback(this, "DoSome");',
+ 'this.p = rtl.createCallback(this.o, "DoIt");',
+ '']));
+end;
+
+procedure TTestModule.TestPointer_AssignRecordFail;
+begin
+ StartProgram(false);
+ Add('type');
+ Add(' TRec = record end;');
+ Add('var');
+ Add(' p: Pointer;');
+ Add(' r: TRec;');
+ Add('begin');
+ Add(' p:=r;');
+ SetExpectedPasResolverError('Incompatible types: got "TRec" expected "Pointer"',
+ nIncompatibleTypesGotExpected);
+ ConvertProgram;
+end;
+
+procedure TTestModule.TestPointer_AssignStaticArrayFail;
+begin
+ StartProgram(false);
+ Add('type');
+ Add(' TArr = array[boolean] of longint;');
+ Add('var');
+ Add(' p: Pointer;');
+ Add(' a: TArr;');
+ Add('begin');
+ Add(' p:=a;');
+ SetExpectedPasResolverError('Incompatible types: got "TArr" expected "Pointer"',
+ nIncompatibleTypesGotExpected);
+ ConvertProgram;
+end;
+
+procedure TTestModule.TestPointer_ArrayParamsFail;
+begin
+ StartProgram(false);
+ Add('var');
+ Add(' p: Pointer;');
+ Add('begin');
+ Add(' p:=p[1];');
+ SetExpectedPasResolverError('illegal qualifier "["',nIllegalQualifier);
+ ConvertProgram;
+end;
+
procedure TTestModule.TestJSValue_AssignToJSValue;
begin
StartProgram(false);
@@ -9807,6 +10227,7 @@ begin
Add(' s: string;');
Add(' b: boolean;');
Add(' d: double;');
+ Add(' p: pointer;');
Add('begin');
Add(' v:=v;');
Add(' v:=1;');
@@ -9821,6 +10242,7 @@ begin
Add(' v:=0.1;');
Add(' v:=d;');
Add(' v:=nil;');
+ Add(' v:=p;');
ConvertProgram;
CheckSource('TestJSValue_AssignToJSValue',
LinesToStr([ // statements
@@ -9829,6 +10251,7 @@ begin
'this.s = "";',
'this.b = false;',
'this.d = 0.0;',
+ 'this.p = null;',
'']),
LinesToStr([ // this.$main
'this.v = this.v;',
@@ -9844,6 +10267,7 @@ begin
'this.v = 0.1;',
'this.v = this.d;',
'this.v = null;',
+ 'this.v = this.p;',
'']));
end;
@@ -10490,6 +10914,1120 @@ begin
'']));
end;
+procedure TTestModule.TestRTTI_ProcType;
+begin
+ Converter.Options:=Converter.Options-[coNoTypeInfo];
+ StartProgram(false);
+ Add('type');
+ Add(' TProcA = procedure;');
+ Add(' TMethodB = procedure of object;');
+ Add(' TProcC = procedure; varargs;');
+ Add(' TProcD = procedure(i: longint; const j: string; var c: char; out d: double);');
+ Add(' TProcE = function: longint;');
+ Add(' TProcF = function(const p: TProcA): longint;');
+ Add('var p: pointer;');
+ Add('begin');
+ Add(' p:=typeinfo(tproca);');
+ ConvertProgram;
+ CheckSource('TestRTTI_ProcType',
+ LinesToStr([ // statements
+ 'this.$rtti.$ProcVar("TProcA", {',
+ ' procsig: rtl.newTIProcSig(null)',
+ '});',
+ 'this.$rtti.$MethodVar("TMethodB", {',
+ ' procsig: rtl.newTIProcSig(null),',
+ ' methodkind: 0',
+ '});',
+ 'this.$rtti.$ProcVar("TProcC", {',
+ ' procsig: rtl.newTIProcSig(null, 2)',
+ '});',
+ 'this.$rtti.$ProcVar("TProcD", {',
+ ' procsig: rtl.newTIProcSig([["i", rtl.longint], ["j", rtl.string, 2], ["c", rtl.char, 1], ["d", rtl.double, 4]])',
+ '});',
+ 'this.$rtti.$ProcVar("TProcE", {',
+ ' procsig: rtl.newTIProcSig(null, rtl.longint)',
+ '});',
+ 'this.$rtti.$ProcVar("TProcF", {',
+ ' procsig: rtl.newTIProcSig([["p", this.$rtti["TProcA"], 2]], rtl.longint)',
+ '});',
+ 'this.p = null;',
+ '']),
+ LinesToStr([ // this.$main
+ 'this.p = this.$rtti["TProcA"];',
+ '']));
+end;
+
+procedure TTestModule.TestRTTI_ProcType_ArgFromOtherUnit;
+begin
+ Converter.Options:=Converter.Options-[coNoTypeInfo];
+
+ AddModuleWithIntfImplSrc('unit2.pas',
+ LinesToStr([
+ 'type',
+ ' TObject = class end;'
+ ]),
+ '');
+ StartUnit(true);
+ Add('interface');
+ Add('uses unit2;');
+ Add('type');
+ Add(' TProcA = function(o: tobject): tobject;');
+ Add('implementation');
+ Add('type');
+ Add(' TProcB = function(o: tobject): tobject;');
+ Add('var p: Pointer;');
+ Add('initialization');
+ Add(' p:=typeinfo(tproca);');
+ Add(' p:=typeinfo(tprocb);');
+ ConvertUnit;
+ CheckSource('TestRTTI_ProcType_ArgFromOtherUnit',
+ LinesToStr([ // statements
+ 'var $impl = this.$impl;',
+ 'this.$rtti.$ProcVar("TProcA", {',
+ ' procsig: rtl.newTIProcSig([["o", pas.unit2.$rtti["TObject"]]], pas.unit2.$rtti["TObject"])',
+ '});',
+ '']),
+ LinesToStr([ // this.$init
+ '$impl.p = this.$rtti["TProcA"];',
+ '$impl.p = this.$rtti["TProcB"];',
+ '']),
+ LinesToStr([ // implementation
+ 'this.$rtti.$ProcVar("TProcB", {',
+ ' procsig: rtl.newTIProcSig([["o", pas.unit2.$rtti["TObject"]]], pas.unit2.$rtti["TObject"])',
+ '});',
+ '$impl.p = null;',
+ '']) );
+end;
+
+procedure TTestModule.TestRTTI_EnumAndSetType;
+begin
+ Converter.Options:=Converter.Options-[coNoTypeInfo];
+ StartProgram(false);
+ Add('type');
+ Add(' TFlag = (light,dark);');
+ Add(' TFlags = set of TFlag;');
+ Add(' TProc = function(f: TFlags): TFlag;');
+ Add('var p: pointer;');
+ Add('begin');
+ Add(' p:=typeinfo(tflag);');
+ Add(' p:=typeinfo(tflags);');
+ ConvertProgram;
+ CheckSource('TestRTTI_EnumAndType',
+ LinesToStr([ // statements
+ 'this.TFlag = {',
+ ' "0": "light",',
+ ' light: 0,',
+ ' "1": "dark",',
+ ' dark: 1',
+ '};',
+ 'this.$rtti.$Enum("TFlag", {',
+ ' minvalue: 0,',
+ ' maxvalue: 1,',
+ ' enumtype: this.TFlag',
+ '});',
+ 'this.$rtti.$Set("TFlags", {',
+ ' comptype: this.$rtti["TFlag"]',
+ '});',
+ 'this.$rtti.$ProcVar("TProc", {',
+ ' procsig: rtl.newTIProcSig([["f", this.$rtti["TFlags"]]], this.$rtti["TFlag"])',
+ '});',
+ 'this.p = null;',
+ '']),
+ LinesToStr([ // this.$main
+ 'this.p = this.$rtti["TFlag"];',
+ 'this.p = this.$rtti["TFlags"];',
+ '']));
+end;
+
+procedure TTestModule.TestRTTI_AnonymousEnumType;
+begin
+ Converter.Options:=Converter.Options-[coNoTypeInfo];
+ StartProgram(false);
+ Add('type');
+ Add(' TFlags = set of (red, green);');
+ Add('var');
+ Add(' f: TFlags;');
+ Add('begin');
+ Add(' Include(f,red);');
+ ConvertProgram;
+ CheckSource('TestRTTI_AnonymousEnumType',
+ LinesToStr([ // statements
+ 'this.TFlags$a = {',
+ ' "0": "red",',
+ ' red: 0,',
+ ' "1": "green",',
+ ' green: 1',
+ '};',
+ 'this.$rtti.$Enum("TFlags$a", {',
+ ' minvalue: 0,',
+ ' maxvalue: 1,',
+ ' enumtype: this.TFlags$a',
+ '});',
+ 'this.$rtti.$Set("TFlags", {',
+ ' comptype: this.$rtti["TFlags$a"]',
+ '});',
+ 'this.f = {};',
+ '']),
+ LinesToStr([
+ 'this.f = rtl.includeSet(this.f, this.TFlags$a.red);',
+ '']));
+end;
+
+procedure TTestModule.TestRTTI_StaticArray;
+begin
+ Converter.Options:=Converter.Options-[coNoTypeInfo];
+ StartProgram(false);
+ Add('type');
+ Add(' TFlag = (light,dark);');
+ Add(' TFlagNames = array[TFlag] of string;');
+ Add(' TBoolNames = array[boolean] of string;');
+ Add(' TProc = function(f: TBoolNames): TFlagNames;');
+ Add('var p: pointer;');
+ Add('begin');
+ Add(' p:=typeinfo(TFlagNames);');
+ Add(' p:=typeinfo(TBoolNames);');
+ ConvertProgram;
+ CheckSource('TestRTTI_StaticArray',
+ LinesToStr([ // statements
+ 'this.TFlag = {',
+ ' "0": "light",',
+ ' light: 0,',
+ ' "1": "dark",',
+ ' dark: 1',
+ '};',
+ 'this.$rtti.$Enum("TFlag", {',
+ ' minvalue: 0,',
+ ' maxvalue: 1,',
+ ' enumtype: this.TFlag',
+ '});',
+ 'this.$rtti.$StaticArray("TFlagNames", {',
+ ' dims: [2],',
+ ' eltype: rtl.string',
+ '});',
+ 'this.$rtti.$StaticArray("TBoolNames", {',
+ ' dims: [2],',
+ ' eltype: rtl.string',
+ '});',
+ 'this.$rtti.$ProcVar("TProc", {',
+ ' procsig: rtl.newTIProcSig([["f", this.$rtti["TBoolNames"]]], this.$rtti["TFlagNames"])',
+ '});',
+ 'this.p = null;',
+ '']),
+ LinesToStr([ // this.$main
+ 'this.p = this.$rtti["TFlagNames"];',
+ 'this.p = this.$rtti["TBoolNames"];',
+ '']));
+end;
+
+procedure TTestModule.TestRTTI_DynArray;
+begin
+ Converter.Options:=Converter.Options-[coNoTypeInfo];
+ StartProgram(false);
+ Add('type');
+ Add(' TArrStr = array of string;');
+ Add(' TArr2Dim = array of tarrstr;');
+ Add(' TProc = function(f: TArrStr): TArr2Dim;');
+ Add('var p: pointer;');
+ Add('begin');
+ Add(' p:=typeinfo(tarrstr);');
+ Add(' p:=typeinfo(tarr2dim);');
+ ConvertProgram;
+ CheckSource('TestRTTI_DynArray',
+ LinesToStr([ // statements
+ 'this.$rtti.$DynArray("TArrStr", {',
+ ' eltype: rtl.string',
+ '});',
+ 'this.$rtti.$DynArray("TArr2Dim", {',
+ ' eltype: this.$rtti["TArrStr"]',
+ '});',
+ 'this.$rtti.$ProcVar("TProc", {',
+ ' procsig: rtl.newTIProcSig([["f", this.$rtti["TArrStr"]]], this.$rtti["TArr2Dim"])',
+ '});',
+ 'this.p = null;',
+ '']),
+ LinesToStr([ // this.$main
+ 'this.p = this.$rtti["TArrStr"];',
+ 'this.p = this.$rtti["TArr2Dim"];',
+ '']));
+end;
+
+procedure TTestModule.TestRTTI_ArrayNestedAnonymous;
+begin
+ Converter.Options:=Converter.Options-[coNoTypeInfo];
+ StartProgram(false);
+ Add('type');
+ Add(' TArr = array of array of longint;');
+ Add('var a: TArr;');
+ Add('begin');
+ ConvertProgram;
+ CheckSource('TestRTTI_ArrayNestedAnonymous',
+ LinesToStr([ // statements
+ 'this.$rtti.$DynArray("TArr$a", {',
+ ' eltype: rtl.longint',
+ '});',
+ 'this.$rtti.$DynArray("TArr", {',
+ ' eltype: this.$rtti["TArr$a"]',
+ '});',
+ 'this.a = [];',
+ '']),
+ LinesToStr([ // this.$main
+ ]));
+end;
+
+procedure TTestModule.TestRTTI_PublishedMethodOverloadFail;
+begin
+ Converter.Options:=Converter.Options-[coNoTypeInfo];
+ StartProgram(false);
+ Add('type');
+ Add(' TObject = class');
+ Add(' published');
+ Add(' procedure Proc; virtual; abstract;');
+ Add(' procedure Proc(Sender: tobject); virtual; abstract;');
+ Add(' end;');
+ Add('begin');
+ SetExpectedPasResolverError('Duplicate identifier "Proc" at test1.pp(6,18)',
+ nDuplicateIdentifier);
+ ConvertProgram;
+end;
+
+procedure TTestModule.TestRTTI_PublishedMethodExternalFail;
+begin
+ Converter.Options:=Converter.Options-[coNoTypeInfo];
+ StartProgram(false);
+ Add('type');
+ Add(' TObject = class');
+ Add(' published');
+ Add(' procedure Proc; external name ''foo'';');
+ Add(' end;');
+ Add('begin');
+ SetExpectedPasResolverError(sPublishedNameMustMatchExternal,
+ nPublishedNameMustMatchExternal);
+ ConvertProgram;
+end;
+
+procedure TTestModule.TestRTTI_PublishedClassPropertyFail;
+begin
+ Converter.Options:=Converter.Options-[coNoTypeInfo];
+ StartProgram(false);
+ Add('type');
+ Add(' TObject = class');
+ Add(' class var FA: longint;');
+ Add(' published');
+ Add(' class property A: longint read FA;');
+ Add(' end;');
+ Add('begin');
+ SetExpectedPasResolverError('Invalid published property modifier "class"',
+ nInvalidXModifierY);
+ ConvertProgram;
+end;
+
+procedure TTestModule.TestRTTI_PublishedClassFieldFail;
+begin
+ Converter.Options:=Converter.Options-[coNoTypeInfo];
+ StartProgram(false);
+ Add('type');
+ Add(' TObject = class');
+ Add(' published');
+ Add(' class var FA: longint;');
+ Add(' end;');
+ Add('begin');
+ SetExpectedPasResolverError(sSymbolCannotBePublished,
+ nSymbolCannotBePublished);
+ ConvertProgram;
+end;
+
+procedure TTestModule.TestRTTI_PublishedFieldExternalFail;
+begin
+ Converter.Options:=Converter.Options-[coNoTypeInfo];
+ StartProgram(false);
+ Add('{$modeswitch externalclass}');
+ Add('type');
+ Add(' TObject = class');
+ Add(' published');
+ Add(' V: longint; external name ''foo'';');
+ Add(' end;');
+ Add('begin');
+ SetExpectedPasResolverError(sPublishedNameMustMatchExternal,
+ nPublishedNameMustMatchExternal);
+ ConvertProgram;
+end;
+
+procedure TTestModule.TestRTTI_Class_Field;
+begin
+ Converter.Options:=Converter.Options-[coNoTypeInfo];
+ StartProgram(false);
+ Add('{$modeswitch externalclass}');
+ Add('type');
+ Add(' TObject = class');
+ Add(' private');
+ Add(' FPropA: string;');
+ Add(' published');
+ Add(' VarLI: longint;');
+ Add(' VarC: char;');
+ Add(' VarS: string;');
+ Add(' VarD: double;');
+ Add(' VarB: boolean;');
+ Add(' VarCa: cardinal;');
+ Add(' VarSmI: smallint;');
+ Add(' VarW: word;');
+ Add(' VarShI: shortint;');
+ Add(' VarBy: byte;');
+ Add(' VarExt: longint external name ''VarExt'';');
+ Add(' end;');
+ Add('var p: pointer;');
+ Add(' Obj: tobject;');
+ Add('begin');
+ Add(' p:=typeinfo(tobject);');
+ Add(' p:=typeinfo(p);');
+ Add(' p:=typeinfo(obj);');
+ ConvertProgram;
+ CheckSource('TestRTTI_Class_Field',
+ LinesToStr([ // statements
+ 'rtl.createClass(this, "TObject", null, function () {',
+ ' this.$init = function () {',
+ ' this.FPropA = "";',
+ ' this.VarLI = 0;',
+ ' this.VarC = "";',
+ ' this.VarS = "";',
+ ' this.VarD = 0.0;',
+ ' this.VarB = false;',
+ ' this.VarCa = 0;',
+ ' this.VarSmI = 0;',
+ ' this.VarW = 0;',
+ ' this.VarShI = 0;',
+ ' this.VarBy = 0;',
+ ' };',
+ ' this.$final = function () {',
+ ' };',
+ ' var $r = this.$rtti;',
+ ' $r.addField("VarLI", rtl.longint);',
+ ' $r.addField("VarC", rtl.char);',
+ ' $r.addField("VarS", rtl.string);',
+ ' $r.addField("VarD", rtl.double);',
+ ' $r.addField("VarB", rtl.boolean);',
+ ' $r.addField("VarCa", rtl.cardinal);',
+ ' $r.addField("VarSmI", rtl.smallint);',
+ ' $r.addField("VarW", rtl.word);',
+ ' $r.addField("VarShI", rtl.shortint);',
+ ' $r.addField("VarBy", rtl.byte);',
+ ' $r.addField("VarExt", rtl.longint);',
+ '});',
+ 'this.p = null;',
+ 'this.Obj = null;',
+ '']),
+ LinesToStr([ // this.$main
+ 'this.p = this.$rtti["TObject"];',
+ 'this.p = rtl.pointer;',
+ 'this.p = this.Obj.$rtti;',
+ '']));
+end;
+
+procedure TTestModule.TestRTTI_Class_Method;
+begin
+ Converter.Options:=Converter.Options-[coNoTypeInfo];
+ StartProgram(false);
+ Add('type');
+ Add(' TObject = class');
+ Add(' private');
+ Add(' procedure Internal; external name ''$intern'';');
+ Add(' published');
+ Add(' procedure Click; virtual; abstract;');
+ Add(' procedure Notify(Sender: TObject); virtual; abstract;');
+ Add(' function GetNotify: boolean; external name ''GetNotify'';');
+ Add(' procedure Println(a,b: longint); varargs; virtual; abstract;');
+ Add(' end;');
+ Add('begin');
+ ConvertProgram;
+ CheckSource('TestRTTI_Class_Method',
+ LinesToStr([ // statements
+ 'rtl.createClass(this, "TObject", null, function () {',
+ ' this.$init = function () {',
+ ' };',
+ ' this.$final = function () {',
+ ' };',
+ ' var $r = this.$rtti;',
+ ' $r.addMethod("Click", 0, null);',
+ ' $r.addMethod("Notify", 0, [["Sender", $r]]);',
+ ' $r.addMethod("GetNotify", 1, null, rtl.boolean,{flags: 4});',
+ ' $r.addMethod("Println", 0, [["a", rtl.longint], ["b", rtl.longint]], null, {',
+ ' flags: 2',
+ ' });',
+ '});',
+ '']),
+ LinesToStr([ // this.$main
+ '']));
+end;
+
+procedure TTestModule.TestRTTI_Class_Property;
+begin
+ Converter.Options:=Converter.Options-[coNoTypeInfo];
+ StartProgram(false);
+ Add('{$modeswitch externalclass}');
+ Add('type');
+ Add(' TObject = class');
+ Add(' private');
+ Add(' FColor: longint;');
+ Add(' FColorStored: boolean;');
+ Add(' procedure SetColor(Value: longint); virtual; abstract;');
+ Add(' function GetColor: longint; virtual; abstract;');
+ Add(' function GetColorStored: boolean; virtual; abstract;');
+ Add(' FExtSize: longint external name ''$extSize'';');
+ Add(' FExtSizeStored: boolean external name ''$extSizeStored'';');
+ Add(' procedure SetExtSize(Value: longint); external name ''$setSize'';');
+ Add(' function GetExtSize: longint; external name ''$getSize'';');
+ Add(' function GetExtSizeStored: boolean; external name ''$getExtSizeStored'';');
+ Add(' published');
+ Add(' property ColorA: longint read FColor;');
+ Add(' property ColorB: longint write FColor;');
+ Add(' property ColorC: longint read GetColor write SetColor;');
+ Add(' property ColorD: longint read FColor write FColor stored FColorStored;');
+ Add(' property ExtSizeA: longint read FExtSize write FExtSize;');
+ Add(' property ExtSizeB: longint read GetExtSize write SetExtSize stored FExtSizeStored;');
+ Add(' property ExtSizeC: longint read FExtSize write FExtSize stored GetExtSizeStored;');
+ Add(' end;');
+ Add('begin');
+ ConvertProgram;
+ CheckSource('TestRTTI_Class_Property',
+ LinesToStr([ // statements
+ 'rtl.createClass(this, "TObject", null, function () {',
+ ' this.$init = function () {',
+ ' this.FColor = 0;',
+ ' this.FColorStored = false;',
+ ' };',
+ ' this.$final = function () {',
+ ' };',
+ ' var $r = this.$rtti;',
+ ' $r.addProperty("ColorA", 0, rtl.longint, "FColor", "");',
+ ' $r.addProperty("ColorB", 0, rtl.longint, "", "FColor");',
+ ' $r.addProperty("ColorC", 3, rtl.longint, "GetColor", "SetColor");',
+ ' $r.addProperty("ColorD", 0, rtl.longint, "FColor", "FColor",{',
+ ' stored: "FColorStored"',
+ ' }',
+ ' );',
+ ' $r.addProperty("ExtSizeA", 0, rtl.longint, "$extSize", "$extSize");',
+ ' $r.addProperty("ExtSizeB", 3, rtl.longint, "$getSize", "$setSize",{',
+ ' stored: "$extSizeStored"',
+ ' }',
+ ' );',
+ ' $r.addProperty("ExtSizeC", 4, rtl.longint, "$extSize", "$extSize",{',
+ ' stored: "$getExtSizeStored"',
+ ' }',
+ ' );',
+ '});',
+ '']),
+ LinesToStr([ // this.$main
+ '']));
+end;
+
+procedure TTestModule.TestRTTI_Class_PropertyParams;
+begin
+ Converter.Options:=Converter.Options-[coNoTypeInfo];
+ StartProgram(false);
+ Add('{$modeswitch externalclass}');
+ Add('type');
+ Add(' integer = longint;');
+ Add(' TObject = class');
+ Add(' private');
+ Add(' function GetItems(i: integer): tobject; virtual; abstract;');
+ Add(' procedure SetItems(i: integer; value: tobject); virtual; abstract;');
+ Add(' function GetValues(const i: integer; var b: boolean): char; virtual; abstract;');
+ Add(' procedure SetValues(const i: integer; var b: boolean; value: char); virtual; abstract;');
+ Add(' published');
+ Add(' property Items[Index: integer]: tobject read getitems write setitems;');
+ Add(' property Values[const keya: integer; var keyb: boolean]: char read getvalues write setvalues;');
+ Add(' end;');
+ Add('begin');
+ ConvertProgram;
+ CheckSource('TestRTTI_Class_PropertyParams',
+ LinesToStr([ // statements
+ 'rtl.createClass(this, "TObject", null, function () {',
+ ' this.$init = function () {',
+ ' };',
+ ' this.$final = function () {',
+ ' };',
+ ' var $r = this.$rtti;',
+ ' $r.addProperty("Items", 3, $r, "GetItems", "SetItems");',
+ ' $r.addProperty("Values", 3, rtl.char, "GetValues", "SetValues");',
+ '});',
+ '']),
+ LinesToStr([ // this.$main
+ '']));
+end;
+
+procedure TTestModule.TestRTTI_OverrideMethod;
+begin
+ Converter.Options:=Converter.Options-[coNoTypeInfo];
+ StartProgram(false);
+ Add('type');
+ Add(' TObject = class');
+ Add(' published');
+ Add(' procedure DoIt; virtual; abstract;');
+ Add(' end;');
+ Add(' TSky = class');
+ Add(' published');
+ Add(' procedure DoIt; override;');
+ Add(' end;');
+ Add('procedure TSky.DoIt; begin end;');
+ Add('begin');
+ ConvertProgram;
+ CheckSource('TestRTTI_OverrideMethod',
+ LinesToStr([ // statements
+ 'rtl.createClass(this, "TObject", null, function () {',
+ ' this.$init = function () {',
+ ' };',
+ ' this.$final = function () {',
+ ' };',
+ ' var $r = this.$rtti;',
+ ' $r.addMethod("DoIt", 0, null);',
+ '});',
+ 'rtl.createClass(this, "TSky", this.TObject, function () {',
+ ' this.DoIt = function () {',
+ ' };',
+ '});',
+ '']),
+ LinesToStr([ // this.$main
+ '']));
+end;
+
+procedure TTestModule.TestRTTI_OverloadProperty;
+begin
+ Converter.Options:=Converter.Options-[coNoTypeInfo];
+ StartProgram(false);
+ Add('type');
+ Add(' TObject = class');
+ Add(' protected');
+ Add(' FFlag: longint;');
+ Add(' published');
+ Add(' property Flag: longint read FFlag;');
+ Add(' end;');
+ Add(' TSky = class');
+ Add(' published');
+ Add(' property Flag: longint write FFlag;');
+ Add(' end;');
+ Add('begin');
+ ConvertProgram;
+ CheckSource('TestRTTI_OverrideMethod',
+ LinesToStr([ // statements
+ 'rtl.createClass(this, "TObject", null, function () {',
+ ' this.$init = function () {',
+ ' this.FFlag = 0;',
+ ' };',
+ ' this.$final = function () {',
+ ' };',
+ ' var $r = this.$rtti;',
+ ' $r.addProperty("Flag", 0, rtl.longint, "FFlag", "");',
+ '});',
+ 'rtl.createClass(this, "TSky", this.TObject, function () {',
+ ' var $r = this.$rtti;',
+ ' $r.addProperty("Flag", 0, rtl.longint, "", "FFlag");',
+ '});',
+ '']),
+ LinesToStr([ // this.$main
+ '']));
+end;
+
+procedure TTestModule.TestRTTI_ClassForward;
+begin
+ Converter.Options:=Converter.Options-[coNoTypeInfo];
+ StartProgram(false);
+ Add('type');
+ Add(' TObject = class end;');
+ Add(' tbridge = class;');
+ Add(' TProc = function: tbridge;');
+ Add(' TOger = class');
+ Add(' published');
+ Add(' FBridge: tbridge;');
+ Add(' procedure SetBridge(Value: tbridge); virtual; abstract;');
+ Add(' property Bridge: tbridge read fbridge write setbridge;');
+ Add(' end;');
+ Add(' TBridge = class');
+ Add(' FOger: toger;');
+ Add(' end;');
+ Add('var p: Pointer;');
+ Add(' b: tbridge;');
+ Add('begin');
+ Add(' p:=typeinfo(tbridge);');
+ Add(' p:=typeinfo(b);');
+ ConvertProgram;
+ CheckSource('TestRTTI_ClassForward',
+ LinesToStr([ // statements
+ 'rtl.createClass(this, "TObject", null, function () {',
+ ' this.$init = function () {',
+ ' };',
+ ' this.$final = function () {',
+ ' };',
+ '});',
+ 'this.$rtti.$Class("TBridge");',
+ 'this.$rtti.$ProcVar("TProc", {',
+ ' procsig: rtl.newTIProcSig(null, this.$rtti["TBridge"])',
+ '});',
+ 'rtl.createClass(this, "TOger", this.TObject, function () {',
+ ' this.$init = function () {',
+ ' pas.program.TObject.$init.call(this);',
+ ' this.FBridge = null;',
+ ' };',
+ ' this.$final = function () {',
+ ' this.FBridge = undefined;',
+ ' pas.program.TObject.$final.call(this);',
+ ' };',
+ ' var $r = this.$rtti;',
+ ' $r.addField("FBridge", pas.program.$rtti["TBridge"]);',
+ ' $r.addMethod("SetBridge", 0, [["Value", pas.program.$rtti["TBridge"]]]);',
+ ' $r.addProperty("Bridge", 2, pas.program.$rtti["TBridge"], "FBridge", "SetBridge");',
+ '});',
+ 'rtl.createClass(this, "TBridge", this.TObject, function () {',
+ ' this.$init = function () {',
+ ' pas.program.TObject.$init.call(this);',
+ ' this.FOger = null;',
+ ' };',
+ ' this.$final = function () {',
+ ' this.FOger = undefined;',
+ ' pas.program.TObject.$final.call(this);',
+ ' };',
+ '});',
+ 'this.p = null;',
+ 'this.b = null;',
+ '']),
+ LinesToStr([ // this.$main
+ 'this.p = this.$rtti["TBridge"];',
+ 'this.p = this.b.$rtti;',
+ '']));
+end;
+
+procedure TTestModule.TestRTTI_ClassOf;
+begin
+ Converter.Options:=Converter.Options-[coNoTypeInfo];
+ StartProgram(false);
+ Add('type');
+ Add(' TClass = class of tobject;');
+ Add(' TProcA = function: TClass;');
+ Add(' TObject = class');
+ Add(' published');
+ Add(' C: tclass;');
+ Add(' end;');
+ Add(' tfox = class;');
+ Add(' TBird = class end;');
+ Add(' TBirds = class of tbird;');
+ Add(' TFox = class end;');
+ Add(' TFoxes = class of tfox;');
+ Add(' TCows = class of TCow;');
+ Add(' TCow = class;');
+ Add(' TCow = class end;');
+ Add('begin');
+ ConvertProgram;
+ CheckSource('TestRTTI_ClassOf',
+ LinesToStr([ // statements
+ 'this.$rtti.$Class("TObject");',
+ 'this.$rtti.$ClassRef("TClass", {',
+ ' instancetype: this.$rtti["TObject"]',
+ '});',
+ 'this.$rtti.$ProcVar("TProcA", {',
+ ' procsig: rtl.newTIProcSig(null, this.$rtti["TClass"])',
+ '});',
+ 'rtl.createClass(this, "TObject", null, function () {',
+ ' this.$init = function () {',
+ ' this.C = null;',
+ ' };',
+ ' this.$final = function () {',
+ ' this.C = undefined;',
+ ' };',
+ ' var $r = this.$rtti;',
+ ' $r.addField("C", pas.program.$rtti["TClass"]);',
+ '});',
+ 'this.$rtti.$Class("TFox");',
+ 'rtl.createClass(this, "TBird", this.TObject, function () {',
+ '});',
+ 'this.$rtti.$ClassRef("TBirds", {',
+ ' instancetype: this.$rtti["TBird"]',
+ '});',
+ 'rtl.createClass(this, "TFox", this.TObject, function () {',
+ '});',
+ 'this.$rtti.$ClassRef("TFoxes", {',
+ ' instancetype: this.$rtti["TFox"]',
+ '});',
+ 'this.$rtti.$Class("TCow");',
+ 'this.$rtti.$ClassRef("TCows", {',
+ ' instancetype: this.$rtti["TCow"]',
+ '});',
+ 'rtl.createClass(this, "TCow", this.TObject, function () {',
+ '});',
+ '']),
+ LinesToStr([ // this.$main
+ '']));
+end;
+
+procedure TTestModule.TestRTTI_Record;
+begin
+ Converter.Options:=Converter.Options-[coNoTypeInfo];
+ StartProgram(false);
+ Add('type');
+ Add(' integer = longint;');
+ Add(' TPoint = record');
+ Add(' x,y: integer;');
+ Add(' end;');
+ Add('var p: pointer;');
+ Add(' r: tpoint;');
+ Add('begin');
+ Add(' p:=typeinfo(tpoint);');
+ Add(' p:=typeinfo(r);');
+ Add(' p:=typeinfo(r.x);');
+ ConvertProgram;
+ CheckSource('TestRTTI_Record',
+ LinesToStr([ // statements
+ 'this.TPoint = function (s) {',
+ ' if (s) {',
+ ' this.x = s.x;',
+ ' this.y = s.y;',
+ ' } else {',
+ ' this.x = 0;',
+ ' this.y = 0;',
+ ' };',
+ ' this.$equal = function (b) {',
+ ' return (this.x == b.x) && (this.y == b.y);',
+ ' };',
+ '};',
+ 'this.$rtti.$Record("TPoint", {}).addFields("x", rtl.longint, "y", rtl.longint);',
+ 'this.p = null;',
+ 'this.r = new this.TPoint();',
+ '']),
+ LinesToStr([ // this.$main
+ 'this.p = this.$rtti["TPoint"];',
+ 'this.p = this.$rtti["TPoint"];',
+ 'this.p = rtl.longint;',
+ '']));
+end;
+
+procedure TTestModule.TestRTTI_LocalTypes;
+begin
+ Converter.Options:=Converter.Options-[coNoTypeInfo];
+ StartProgram(false);
+ Add('procedure DoIt;');
+ Add('type');
+ Add(' integer = longint;');
+ Add(' TPoint = record');
+ Add(' x,y: integer;');
+ Add(' end;');
+ Add('begin');
+ Add('end;');
+ Add('begin');
+ ConvertProgram;
+ CheckSource('TestRTTI_LocalTypes',
+ LinesToStr([ // statements
+ 'this.DoIt = function () {',
+ ' this.TPoint = function (s) {',
+ ' if (s) {',
+ ' this.x = s.x;',
+ ' this.y = s.y;',
+ ' } else {',
+ ' this.x = 0;',
+ ' this.y = 0;',
+ ' };',
+ ' this.$equal = function (b) {',
+ ' return (this.x == b.x) && (this.y == b.y);',
+ ' };',
+ ' };',
+ '};',
+ '']),
+ LinesToStr([ // this.$main
+ '']));
+end;
+
+procedure TTestModule.TestRTTI_TypeInfo_BaseTypes;
+begin
+ Converter.Options:=Converter.Options-[coNoTypeInfo];
+ StartProgram(false);
+ Add('type');
+ Add(' TCaption = string;');
+ Add(' TYesNo = boolean;');
+ Add(' TLetter = char;');
+ Add(' TFloat = double;');
+ Add(' TPtr = pointer;');
+ Add(' TShortInt = shortint;');
+ Add(' TByte = byte;');
+ Add(' TSmallInt = smallint;');
+ Add(' TWord = word;');
+ Add(' TInt32 = longint;');
+ Add(' TDWord = cardinal;');
+ Add(' TValue = jsvalue;');
+ Add('var p: TPtr;');
+ Add('begin');
+ Add(' p:=typeinfo(string);');
+ Add(' p:=typeinfo(tcaption);');
+ Add(' p:=typeinfo(boolean);');
+ Add(' p:=typeinfo(tyesno);');
+ Add(' p:=typeinfo(char);');
+ Add(' p:=typeinfo(tletter);');
+ Add(' p:=typeinfo(double);');
+ Add(' p:=typeinfo(tfloat);');
+ Add(' p:=typeinfo(pointer);');
+ Add(' p:=typeinfo(tptr);');
+ Add(' p:=typeinfo(shortint);');
+ Add(' p:=typeinfo(tshortint);');
+ Add(' p:=typeinfo(byte);');
+ Add(' p:=typeinfo(tbyte);');
+ Add(' p:=typeinfo(smallint);');
+ Add(' p:=typeinfo(tsmallint);');
+ Add(' p:=typeinfo(word);');
+ Add(' p:=typeinfo(tword);');
+ Add(' p:=typeinfo(cardinal);');
+ Add(' p:=typeinfo(tdword);');
+ Add(' p:=typeinfo(jsvalue);');
+ Add(' p:=typeinfo(tvalue);');
+ ConvertProgram;
+ CheckSource('TestRTTI_TypeInfo_BaseTypes',
+ LinesToStr([ // statements
+ 'this.p = null;',
+ '']),
+ LinesToStr([ // this.$main
+ 'this.p = rtl.string;',
+ 'this.p = rtl.string;',
+ 'this.p = rtl.boolean;',
+ 'this.p = rtl.boolean;',
+ 'this.p = rtl.char;',
+ 'this.p = rtl.char;',
+ 'this.p = rtl.double;',
+ 'this.p = rtl.double;',
+ 'this.p = rtl.pointer;',
+ 'this.p = rtl.pointer;',
+ 'this.p = rtl.shortint;',
+ 'this.p = rtl.shortint;',
+ 'this.p = rtl.byte;',
+ 'this.p = rtl.byte;',
+ 'this.p = rtl.smallint;',
+ 'this.p = rtl.smallint;',
+ 'this.p = rtl.word;',
+ 'this.p = rtl.word;',
+ 'this.p = rtl.cardinal;',
+ 'this.p = rtl.cardinal;',
+ 'this.p = rtl.jsvalue;',
+ 'this.p = rtl.jsvalue;',
+ '']));
+end;
+
+procedure TTestModule.TestRTTI_TypeInfo_LocalFail;
+begin
+ Converter.Options:=Converter.Options-[coNoTypeInfo];
+ StartProgram(false);
+ Add('procedure DoIt;');
+ Add('type');
+ Add(' integer = longint;');
+ Add(' TPoint = record');
+ Add(' x,y: integer;');
+ Add(' end;');
+ Add('var p: pointer;');
+ Add('begin');
+ Add(' p:=typeinfo(tpoint);');
+ Add('end;');
+ Add('begin');
+ SetExpectedPasResolverError(sSymbolCannotBePublished,nSymbolCannotBePublished);
+ ConvertProgram;
+end;
+
+procedure TTestModule.TestRTTI_TypeInfo_ExtTypeInfoClasses1;
+begin
+ Converter.Options:=Converter.Options-[coNoTypeInfo];
+ StartProgram(false);
+ Add('{$modeswitch externalclass}');
+ Add('type');
+ Add(' TTypeInfo = class external name ''rtl.tTypeInfo'' end;');
+ Add(' TTypeInfoInteger = class external name ''rtl.tTypeInfoInteger''(TTypeInfo) end;');
+ Add(' TFlag = (up,down);');
+ Add(' TTypeInfoEnum = class external name ''rtl.tTypeInfoEnum''(TTypeInfoInteger) end;');
+ Add(' TFlags = set of TFlag;');
+ Add(' TTypeInfoSet = class external name ''rtl.tTypeInfoSet''(TTypeInfo) end;');
+ Add('var');
+ Add(' ti: TTypeInfo;');
+ Add(' tiInt: TTypeInfoInteger;');
+ Add(' tiEnum: TTypeInfoEnum;');
+ Add(' tiSet: TTypeInfoSet;');
+ Add('begin');
+ Add(' ti:=typeinfo(string);');
+ Add(' ti:=typeinfo(boolean);');
+ Add(' ti:=typeinfo(char);');
+ Add(' ti:=typeinfo(double);');
+ Add(' tiInt:=typeinfo(shortint);');
+ Add(' tiInt:=typeinfo(byte);');
+ Add(' tiInt:=typeinfo(smallint);');
+ Add(' tiInt:=typeinfo(word);');
+ Add(' tiInt:=typeinfo(longint);');
+ Add(' tiInt:=typeinfo(cardinal);');
+ Add(' ti:=typeinfo(jsvalue);');
+ Add(' tiEnum:=typeinfo(tflag);');
+ Add(' tiSet:=typeinfo(tflags);');
+ ConvertProgram;
+ CheckSource('TestRTTI_TypeInfo_ExtTypeInfoClasses1',
+ LinesToStr([ // statements
+ 'this.TFlag = {',
+ ' "0": "up",',
+ ' up: 0,',
+ ' "1": "down",',
+ ' down: 1',
+ '};',
+ 'this.$rtti.$Enum("TFlag", {',
+ ' minvalue: 0,',
+ ' maxvalue: 1,',
+ ' enumtype: this.TFlag',
+ '});',
+ 'this.$rtti.$Set("TFlags", {',
+ ' comptype: this.$rtti["TFlag"]',
+ '});',
+ 'this.ti = null;',
+ 'this.tiInt = null;',
+ 'this.tiEnum = null;',
+ 'this.tiSet = null;',
+ '']),
+ LinesToStr([ // this.$main
+ 'this.ti = rtl.string;',
+ 'this.ti = rtl.boolean;',
+ 'this.ti = rtl.char;',
+ 'this.ti = rtl.double;',
+ 'this.tiInt = rtl.shortint;',
+ 'this.tiInt = rtl.byte;',
+ 'this.tiInt = rtl.smallint;',
+ 'this.tiInt = rtl.word;',
+ 'this.tiInt = rtl.longint;',
+ 'this.tiInt = rtl.cardinal;',
+ 'this.ti = rtl.jsvalue;',
+ 'this.tiEnum = this.$rtti["TFlag"];',
+ 'this.tiSet = this.$rtti["TFlags"];',
+ '']));
+end;
+
+procedure TTestModule.TestRTTI_TypeInfo_ExtTypeInfoClasses2;
+begin
+ Converter.Options:=Converter.Options-[coNoTypeInfo];
+ StartProgram(false);
+ Add('{$modeswitch externalclass}');
+ Add('type');
+ Add(' TTypeInfo = class external name ''rtl.tTypeInfo'' end;');
+ Add(' TStaticArr = array[boolean] of string;');
+ Add(' TTypeInfoStaticArray = class external name ''rtl.tTypeInfoStaticArray''(TTypeInfo) end;');
+ Add(' TDynArr = array of string;');
+ Add(' TTypeInfoDynArray = class external name ''rtl.tTypeInfoDynArray''(TTypeInfo) end;');
+ Add(' TProc = procedure;');
+ Add(' TTypeInfoProcVar = class external name ''rtl.tTypeInfoProcVar''(TTypeInfo) end;');
+ Add(' TMethod = procedure of object;');
+ Add(' TTypeInfoMethodVar = class external name ''rtl.tTypeInfoMethodVar''(TTypeInfoProcVar) end;');
+ Add('var');
+ Add(' StaticArray: TStaticArr;');
+ Add(' tiStaticArray: TTypeInfoStaticArray;');
+ Add(' DynArray: TDynArr;');
+ Add(' tiDynArray: TTypeInfoDynArray;');
+ Add(' ProcVar: TProc;');
+ Add(' tiProcVar: TTypeInfoProcVar;');
+ Add(' MethodVar: TMethod;');
+ Add(' tiMethodVar: TTypeInfoMethodVar;');
+ Add('begin');
+ Add(' tiStaticArray:=typeinfo(StaticArray);');
+ Add(' tiStaticArray:=typeinfo(TStaticArr);');
+ Add(' tiDynArray:=typeinfo(DynArray);');
+ Add(' tiDynArray:=typeinfo(TDynArr);');
+ Add(' tiProcVar:=typeinfo(ProcVar);');
+ Add(' tiProcVar:=typeinfo(TProc);');
+ Add(' tiMethodVar:=typeinfo(MethodVar);');
+ Add(' tiMethodVar:=typeinfo(TMethod);');
+ ConvertProgram;
+ CheckSource('TestRTTI_TypeInfo_ExtTypeInfoClasses2',
+ LinesToStr([ // statements
+ ' this.$rtti.$StaticArray("TStaticArr", {',
+ ' dims: [2],',
+ ' eltype: rtl.string',
+ '});',
+ 'this.$rtti.$DynArray("TDynArr", {',
+ ' eltype: rtl.string',
+ '});',
+ 'this.$rtti.$ProcVar("TProc", {',
+ ' procsig: rtl.newTIProcSig(null)',
+ '});',
+ 'this.$rtti.$MethodVar("TMethod", {',
+ ' procsig: rtl.newTIProcSig(null),',
+ ' methodkind: 0',
+ '});',
+ 'this.StaticArray = rtl.arrayNewMultiDim([2], "");',
+ 'this.tiStaticArray = null;',
+ 'this.DynArray = [];',
+ 'this.tiDynArray = null;',
+ 'this.ProcVar = null;',
+ 'this.tiProcVar = null;',
+ 'this.MethodVar = null;',
+ 'this.tiMethodVar = null;',
+ '']),
+ LinesToStr([ // this.$main
+ 'this.tiStaticArray = this.$rtti["TStaticArr"];',
+ 'this.tiStaticArray = this.$rtti["TStaticArr"];',
+ 'this.tiDynArray = this.$rtti["TDynArr"];',
+ 'this.tiDynArray = this.$rtti["TDynArr"];',
+ 'this.tiProcVar = this.$rtti["TProc"];',
+ 'this.tiProcVar = this.$rtti["TProc"];',
+ 'this.tiMethodVar = this.$rtti["TMethod"];',
+ 'this.tiMethodVar = this.$rtti["TMethod"];',
+ '']));
+end;
+
+procedure TTestModule.TestRTTI_TypeInfo_ExtTypeInfoClasses3;
+begin
+ Converter.Options:=Converter.Options-[coNoTypeInfo];
+ StartProgram(false);
+ Add('{$modeswitch externalclass}');
+ Add('type');
+ Add(' TTypeInfo = class external name ''rtl.tTypeInfo'' end;');
+ Add(' TRec = record end;');
+ Add(' TTypeInfoRecord = class external name ''rtl.tTypeInfoRecord''(TTypeInfo) end;');
+ // ToDo: ^PRec
+ Add(' TObject = class end;');
+ Add(' TTypeInfoClass = class external name ''rtl.tTypeInfoClass''(TTypeInfo) end;');
+ Add(' TClass = class of tobject;');
+ Add(' TTypeInfoClassRef = class external name ''rtl.tTypeInfoClassRef''(TTypeInfo) end;');
+ Add(' TTypeInfoPointer = class external name ''rtl.tTypeInfoPointer''(TTypeInfo) end;');
+ Add('var');
+ Add(' Rec: trec;');
+ Add(' tiRecord: ttypeinforecord;');
+ Add(' Obj: tobject;');
+ Add(' tiClass: ttypeinfoclass;');
+ Add(' aClass: tclass;');
+ Add(' tiClassRef: ttypeinfoclassref;');
+ // ToDo: ^PRec
+ Add(' tiPointer: ttypeinfopointer;');
+ Add('begin');
+ Add(' tirecord:=typeinfo(trec);');
+ Add(' tirecord:=typeinfo(trec);');
+ Add(' ticlass:=typeinfo(obj);');
+ Add(' ticlass:=typeinfo(tobject);');
+ Add(' ticlassref:=typeinfo(aclass);');
+ Add(' ticlassref:=typeinfo(tclass);');
+ ConvertProgram;
+ CheckSource('TestRTTI_TypeInfo_ExtTypeInfoClasses3',
+ LinesToStr([ // statements
+ 'this.TRec = function (s) {',
+ '};',
+ 'this.$rtti.$Record("TRec", {});',
+ 'rtl.createClass(this, "TObject", null, function () {',
+ ' this.$init = function () {',
+ ' };',
+ ' this.$final = function () {',
+ ' };',
+ '});',
+ 'this.$rtti.$ClassRef("TClass", {',
+ ' instancetype: this.$rtti["TObject"]',
+ '});',
+ 'this.Rec = new this.TRec();',
+ 'this.tiRecord = null;',
+ 'this.Obj = null;',
+ 'this.tiClass = null;',
+ 'this.aClass = null;',
+ 'this.tiClassRef = null;',
+ 'this.tiPointer = null;',
+ '']),
+ LinesToStr([ // this.$main
+ 'this.tiRecord = this.$rtti["TRec"];',
+ 'this.tiRecord = this.$rtti["TRec"];',
+ 'this.tiClass = this.Obj.$rtti;',
+ 'this.tiClass = this.$rtti["TObject"];',
+ 'this.tiClassRef = this.$rtti["TClass"];',
+ 'this.tiClassRef = this.$rtti["TClass"];',
+ '']));
+end;
+
Initialization
RegisterTests([TTestModule]);
end.
diff --git a/packages/pastojs/tests/tcoptimizations.pas b/packages/pastojs/tests/tcoptimizations.pas
index 0591127b92..73329a2f5f 100644
--- a/packages/pastojs/tests/tcoptimizations.pas
+++ b/packages/pastojs/tests/tcoptimizations.pas
@@ -38,8 +38,8 @@ type
FAnalyzerModule: TPasAnalyzer;
FAnalyzerProgram: TPasAnalyzer;
FWholeProgramOptimization: boolean;
- function OnConverterIsElementUsed(Sender: TObject; El: TPasElement
- ): boolean;
+ function OnConverterIsElementUsed(Sender: TObject; El: TPasElement): boolean;
+ function OnConverterIsTypeInfoUsed(Sender: TObject; El: TPasElement): boolean;
protected
procedure SetUp; override;
procedure TearDown; override;
@@ -78,6 +78,8 @@ type
procedure TestWPO_CallInherited;
procedure TestWPO_UseUnit;
procedure TestWPO_ProgramPublicDeclaration;
+ procedure TestWPO_RTTI_PublishedField;
+ procedure TestWPO_RTTI_TypeInfo;
end;
implementation
@@ -99,6 +101,21 @@ begin
{$ENDIF}
end;
+function TCustomTestOptimizations.OnConverterIsTypeInfoUsed(Sender: TObject;
+ El: TPasElement): boolean;
+var
+ A: TPasAnalyzer;
+begin
+ if WholeProgramOptimization then
+ A:=AnalyzerProgram
+ else
+ A:=AnalyzerModule;
+ Result:=A.IsTypeInfoUsed(El);
+ {$IF defined(VerbosePas2JS) or defined(VerbosePasAnalyzer)}
+ writeln('TCustomTestOptimizations.OnConverterIsTypeInfoUsed El=',GetObjName(El),' WPO=',WholeProgramOptimization,' Result=',Result);
+ {$ENDIF}
+end;
+
procedure TCustomTestOptimizations.SetUp;
begin
inherited SetUp;
@@ -108,6 +125,7 @@ begin
FAnalyzerProgram:=TPasAnalyzer.Create;
FAnalyzerProgram.Resolver:=Engine;
Converter.OnIsElementUsed:=@OnConverterIsElementUsed;
+ Converter.OnIsTypeInfoUsed:=@OnConverterIsTypeInfoUsed;
end;
procedure TCustomTestOptimizations.TearDown;
@@ -756,6 +774,88 @@ begin
CheckDiff('TestWPO_ProgramPublicDeclaration',ExpectedSrc,ActualSrc);
end;
+procedure TTestOptimizations.TestWPO_RTTI_PublishedField;
+var
+ ActualSrc, ExpectedSrc: String;
+begin
+ Converter.Options:=Converter.Options-[coNoTypeInfo];
+ StartProgram(true);
+ Add('type');
+ Add(' TArrA = array of char;');
+ Add(' TArrB = array of string;');
+ Add(' TObject = class');
+ Add(' public');
+ Add(' PublicA: TArrA;');
+ Add(' published');
+ Add(' PublishedB: TArrB;');
+ Add(' end;');
+ Add('var');
+ Add(' C: TObject;');
+ Add('begin');
+ Add(' C.PublicA:=nil;');
+ ConvertProgram;
+ ActualSrc:=JSToStr(JSModule);
+ ExpectedSrc:=LinesToStr([
+ 'rtl.module("program", ["system"], function () {',
+ 'this.$rtti.$DynArray("TArrB", {',
+ ' eltype: rtl.string',
+ '});',
+ ' rtl.createClass(this, "TObject", null, function () {',
+ ' this.$init = function () {',
+ ' this.PublicA = [];',
+ ' this.PublishedB = [];',
+ ' };',
+ ' this.$final = function () {',
+ ' this.PublicA = undefined;',
+ ' this.PublishedB = undefined;',
+ ' };',
+ ' var $r = this.$rtti;',
+ ' $r.addField("PublishedB", pas.program.$rtti["TArrB"]);',
+ ' });',
+ ' this.C = null;',
+ ' this.$main = function () {',
+ ' this.C.PublicA = [];',
+ ' };',
+ '});',
+ '']);
+ CheckDiff('TestWPO_RTTI_PublishedField',ExpectedSrc,ActualSrc);
+end;
+
+procedure TTestOptimizations.TestWPO_RTTI_TypeInfo;
+var
+ ActualSrc, ExpectedSrc: String;
+begin
+ Converter.Options:=Converter.Options-[coNoTypeInfo];
+ StartProgram(true);
+ Add('type');
+ Add(' TArrA = array of char;');
+ Add(' TArrB = array of string;');
+ Add('var');
+ Add(' A: TArrA;');
+ Add(' B: TArrB;');
+ Add(' p: pointer;');
+ Add('begin');
+ Add(' A:=nil;');
+ Add(' p:=typeinfo(B);');
+ ConvertProgram;
+ ActualSrc:=JSToStr(JSModule);
+ ExpectedSrc:=LinesToStr([
+ 'rtl.module("program", ["system"], function () {',
+ 'this.$rtti.$DynArray("TArrB", {',
+ ' eltype: rtl.string',
+ '});',
+ ' this.A = [];',
+ ' this.B = [];',
+ ' this.p = null;',
+ ' this.$main = function () {',
+ ' this.A = [];',
+ ' this.p = this.$rtti["TArrB"];',
+ ' };',
+ '});',
+ '']);
+ CheckDiff('TestWPO_RTTI_TypeInfo',ExpectedSrc,ActualSrc);
+end;
+
Initialization
RegisterTests([TTestOptimizations]);
end.
diff --git a/utils/fpdoc/dw_xml.pp b/utils/fpdoc/dw_xml.pp
index b9e435e834..6925c45ac0 100644
--- a/utils/fpdoc/dw_xml.pp
+++ b/utils/fpdoc/dw_xml.pp
@@ -100,7 +100,7 @@ var
Node['virtual'] := 'true';
if pmAbstract in ADecl.Modifiers then
Node['abstract'] := 'true';
- if pmStatic in ADecl.Modifiers then
+ if assigned(ADecl.ProcType) and (ptmStatic in ADecl.ProcType.Modifiers) then
Node['static'] := 'true';
if pmReintroduce in ADecl.Modifiers then
Node['reintroduce'] := 'true';