pastojs: implemented property with index specifier

git-svn-id: trunk@37383 -
This commit is contained in:
Mattias Gaertner 2017-10-02 12:56:29 +00:00
parent 6148ba8c31
commit e5d4d763b3
2 changed files with 195 additions and 14 deletions

View File

@ -458,6 +458,7 @@ type
pbivnRTTIProcFlags, pbivnRTTIProcFlags,
pbivnRTTIProcVar_ProcSig, pbivnRTTIProcVar_ProcSig,
pbivnRTTIPropDefault, pbivnRTTIPropDefault,
pbivnRTTIPropIndex,
pbivnRTTIPropStored, pbivnRTTIPropStored,
pbivnRTTISet_CompType, pbivnRTTISet_CompType,
pbivnSelf, pbivnSelf,
@ -560,6 +561,7 @@ const
'flags', 'flags',
'procsig', 'procsig',
'Default', 'Default',
'index',
'stored', 'stored',
'comptype', 'comptype',
'Self', 'Self',
@ -1348,6 +1350,8 @@ type
pfStoredFalse = 4; // stored false, never pfStoredFalse = 4; // stored false, never
pfStoredField = 8; // stored field, field name is in Stored pfStoredField = 8; // stored field, field name is in Stored
pfStoredFunction = 12; // stored function, function name is in Stored pfStoredFunction = 12; // stored function, function name is in Stored
pfHasIndex = 16; { if getter is function, append Index as last param
if setter is function, append Index as second last param }
type type
TMethodKind = ( TMethodKind = (
mkProcedure, // 0 default mkProcedure, // 0 default
@ -2242,6 +2246,7 @@ var
Arg: TPasArgument; Arg: TPasArgument;
ArgResolved: TPasResolverResult; ArgResolved: TPasResolverResult;
ParentC: TClass; ParentC: TClass;
IndexExpr: TPasExpr;
begin begin
inherited FinishPropertyOfClass(PropEl); inherited FinishPropertyOfClass(PropEl);
@ -2263,16 +2268,17 @@ begin
GetterIsBracketAccessor:=IsExternalBracketAccessor(Getter); GetterIsBracketAccessor:=IsExternalBracketAccessor(Getter);
Setter:=GetPasPropertySetter(PropEl); Setter:=GetPasPropertySetter(PropEl);
SetterIsBracketAccessor:=IsExternalBracketAccessor(Setter); SetterIsBracketAccessor:=IsExternalBracketAccessor(Setter);
IndexExpr:=GetPasPropertyIndex(PropEl);
if GetterIsBracketAccessor then if GetterIsBracketAccessor then
begin begin
if PropEl.Args.Count<>1 then if (PropEl.Args.Count<>1) or (IndexExpr<>nil) then
RaiseMsg(20170403001743,nBracketAccessorOfExternalClassMustHaveOneParameter, RaiseMsg(20170403001743,nBracketAccessorOfExternalClassMustHaveOneParameter,
sBracketAccessorOfExternalClassMustHaveOneParameter, sBracketAccessorOfExternalClassMustHaveOneParameter,
[],PropEl); [],PropEl);
end; end;
if SetterIsBracketAccessor then if SetterIsBracketAccessor then
begin begin
if PropEl.Args.Count<>1 then if (PropEl.Args.Count<>1) or (IndexExpr<>nil) then
RaiseMsg(20170403001806,nBracketAccessorOfExternalClassMustHaveOneParameter, RaiseMsg(20170403001806,nBracketAccessorOfExternalClassMustHaveOneParameter,
sBracketAccessorOfExternalClassMustHaveOneParameter, sBracketAccessorOfExternalClassMustHaveOneParameter,
[],PropEl); [],PropEl);
@ -4573,6 +4579,7 @@ var
ResolvedEl: TPasResolverResult; ResolvedEl: TPasResolverResult;
ProcType, TargetProcType: TPasProcedureType; ProcType, TargetProcType: TPasProcedureType;
ArrLit: TJSArrayLiteral; ArrLit: TJSArrayLiteral;
IndexExpr: TPasExpr;
begin begin
Result:=nil; Result:=nil;
if not (El.CustomData is TResolvedReference) then if not (El.CustomData is TResolvedReference) then
@ -4644,6 +4651,9 @@ begin
Call:=CreateCallExpression(El); Call:=CreateCallExpression(El);
AssignContext.Call:=Call; AssignContext.Call:=Call;
Call.Expr:=CreateReferencePathExpr(Decl,AContext,false,Ref); Call.Expr:=CreateReferencePathExpr(Decl,AContext,false,Ref);
IndexExpr:=AContext.Resolver.GetPasPropertyIndex(Prop);
if IndexExpr<>nil then
Call.AddArg(ConvertElement(IndexExpr,AContext));
Call.AddArg(AssignContext.RightSide); Call.AddArg(AssignContext.RightSide);
AssignContext.RightSide:=nil; AssignContext.RightSide:=nil;
Result:=Call; Result:=Call;
@ -4653,8 +4663,26 @@ begin
caRead: caRead:
begin begin
Decl:=AContext.Resolver.GetPasPropertyGetter(Prop); Decl:=AContext.Resolver.GetPasPropertyGetter(Prop);
if (Decl is TPasFunction) and (Prop.Args.Count=0) then if Decl is TPasFunction then
ImplicitCall:=true; begin
IndexExpr:=AContext.Resolver.GetPasPropertyIndex(Prop);
if IndexExpr<>nil then
begin
// call function with index specifier
Call:=CreateCallExpression(El);
try
Call.Expr:=CreateReferencePathExpr(Decl,AContext,false,Ref);
Call.AddArg(ConvertElement(IndexExpr,AContext));
Result:=Call;
finally
if Result=nil then
Call.Free;
end;
exit;
end
else if (Prop.Args.Count=0) then
ImplicitCall:=true;
end;
end; end;
else else
RaiseNotSupported(El,AContext,20170213212623); RaiseNotSupported(El,AContext,20170213212623);
@ -5380,6 +5408,7 @@ var
AccessEl: TPasElement; AccessEl: TPasElement;
AssignContext: TAssignContext; AssignContext: TAssignContext;
OldAccess: TCtxAccess; OldAccess: TCtxAccess;
IndexExpr: TPasExpr;
begin begin
Result:=nil; Result:=nil;
AssignContext:=nil; AssignContext:=nil;
@ -5434,6 +5463,10 @@ var
Elements.AddElement.Expr:=Arg; Elements.AddElement.Expr:=Arg;
inc(i); inc(i);
end; end;
// add index specifier
IndexExpr:=AContext.Resolver.GetPasPropertyIndex(Prop);
if IndexExpr<>nil then
Elements.AddElement.Expr:=ConvertElement(IndexExpr,ArgContext);
// finally add as last parameter the value // finally add as last parameter the value
if AssignContext<>nil then if AssignContext<>nil then
begin begin
@ -9834,9 +9867,9 @@ var
GetterPas, SetterPas, DeclEl: TPasElement; GetterPas, SetterPas, DeclEl: TPasElement;
ResultTypeInfo, DefValue: TJSElement; ResultTypeInfo, DefValue: TJSElement;
VarType: TPasType; VarType: TPasType;
StoredExpr: TPasExpr; StoredExpr, IndexExpr: TPasExpr;
StoredResolved, VarTypeResolved: TPasResolverResult; StoredResolved, VarTypeResolved: TPasResolverResult;
StoredValue, PasValue: TResEvalValue; StoredValue, PasValue, IndexValue: TResEvalValue;
begin begin
Result:=nil; Result:=nil;
OptionsEl:=nil; OptionsEl:=nil;
@ -9857,8 +9890,10 @@ begin
SetterPas:=AContext.Resolver.GetPasPropertySetter(Prop); SetterPas:=AContext.Resolver.GetPasPropertySetter(Prop);
if SetterPas is TPasProcedure then if SetterPas is TPasProcedure then
inc(Flags,pfSetProcedure); inc(Flags,pfSetProcedure);
StoredExpr:=AContext.Resolver.GetPasPropertyStoredExpr(Prop); StoredExpr:=AContext.Resolver.GetPasPropertyStoredExpr(Prop);
IndexExpr:=AContext.Resolver.GetPasPropertyIndex(Prop);
if IndexExpr<>nil then
inc(Flags,pfHasIndex);
if StoredExpr<>nil then if StoredExpr<>nil then
begin begin
AContext.Resolver.ComputeElement(StoredExpr,StoredResolved,[rcNoImplicitProc]); AContext.Resolver.ComputeElement(StoredExpr,StoredResolved,[rcNoImplicitProc]);
@ -9869,7 +9904,8 @@ begin
begin begin
if (StoredResolved.BaseType=btBoolean) and (StoredResolved.ExprEl<>nil) then if (StoredResolved.BaseType=btBoolean) and (StoredResolved.ExprEl<>nil) then
begin begin
// try evaluating const boolean // could be a const boolean
// -> try evaluating const boolean
StoredValue:=AContext.Resolver.Eval(StoredExpr,[]); StoredValue:=AContext.Resolver.Eval(StoredExpr,[]);
if StoredValue<>nil then if StoredValue<>nil then
try try
@ -9913,6 +9949,19 @@ begin
else else
Call.AddArg(CreateLiteralString(Prop,GetAccessorName(SetterPas))); Call.AddArg(CreateLiteralString(Prop,GetAccessorName(SetterPas)));
// add option "index"
IndexExpr:=AContext.Resolver.GetPasPropertyIndex(Prop);
if IndexExpr<>nil then
begin
IndexValue:=AContext.Resolver.Eval(IndexExpr,[refConst]);
try
AddOption(FBuiltInNames[pbivnRTTIPropIndex],
ConvertConstValue(IndexValue,AContext,Prop));
finally
ReleaseEvalValue(IndexValue);
end;
end;
// add option "stored" // add option "stored"
if StoredExpr<>nil then if StoredExpr<>nil then
begin begin
@ -9928,9 +9977,7 @@ begin
try try
DefValue:=nil; DefValue:=nil;
if VarTypeResolved.BaseType=btSet then if VarTypeResolved.BaseType=btSet then
begin
DefValue:=CreateValInit(VarType,Prop.DefaultExpr,Prop.DefaultExpr,AContext); DefValue:=CreateValInit(VarType,Prop.DefaultExpr,Prop.DefaultExpr,AContext);
end;
if DefValue=nil then if DefValue=nil then
DefValue:=ConvertConstValue(PasValue,AContext,Prop); DefValue:=ConvertConstValue(PasValue,AContext,Prop);
AddOption(FBuiltInNames[pbivnRTTIPropDefault],DefValue); AddOption(FBuiltInNames[pbivnRTTIPropDefault],DefValue);
@ -10045,8 +10092,6 @@ function TPasToJSConverter.ConvertProperty(El: TPasProperty;
begin begin
Result:=Nil; Result:=Nil;
if El.IndexExpr<>nil then
RaiseNotSupported(El.IndexExpr,AContext,20170215103010,'property index expression');
if El.ImplementsFunc<>nil then if El.ImplementsFunc<>nil then
RaiseNotSupported(El.ImplementsFunc,AContext,20170215102923,'property implements function'); RaiseNotSupported(El.ImplementsFunc,AContext,20170215102923,'property implements function');
if El.DispIDExpr<>nil then if El.DispIDExpr<>nil then

View File

@ -356,6 +356,7 @@ type
Procedure TestClass_Property; Procedure TestClass_Property;
Procedure TestClass_Property_ClassMethod; Procedure TestClass_Property_ClassMethod;
Procedure TestClass_Property_Indexed; Procedure TestClass_Property_Indexed;
Procedure TestClass_Property_IndexSpec;
Procedure TestClass_PropertyOfTypeArray; Procedure TestClass_PropertyOfTypeArray;
Procedure TestClass_PropertyDefault; Procedure TestClass_PropertyDefault;
Procedure TestClass_PropertyOverride; Procedure TestClass_PropertyOverride;
@ -504,6 +505,7 @@ type
Procedure TestRTTI_PublishedClassPropertyFail; Procedure TestRTTI_PublishedClassPropertyFail;
Procedure TestRTTI_PublishedClassFieldFail; Procedure TestRTTI_PublishedClassFieldFail;
Procedure TestRTTI_PublishedFieldExternalFail; Procedure TestRTTI_PublishedFieldExternalFail;
Procedure TestRTTI_IndexModifier;
Procedure TestRTTI_StoredModifier; Procedure TestRTTI_StoredModifier;
Procedure TestRTTI_DefaultValue; Procedure TestRTTI_DefaultValue;
Procedure TestRTTI_DefaultValueSet; Procedure TestRTTI_DefaultValueSet;
@ -513,7 +515,6 @@ type
Procedure TestRTTI_Class_MethodArgFlags; Procedure TestRTTI_Class_MethodArgFlags;
Procedure TestRTTI_Class_Property; Procedure TestRTTI_Class_Property;
Procedure TestRTTI_Class_PropertyParams; Procedure TestRTTI_Class_PropertyParams;
// ToDo: property default value
Procedure TestRTTI_OverrideMethod; Procedure TestRTTI_OverrideMethod;
Procedure TestRTTI_OverloadProperty; Procedure TestRTTI_OverloadProperty;
// ToDo: array argument // ToDo: array argument
@ -7400,6 +7401,63 @@ begin
])); ]));
end; end;
procedure TTestModule.TestClass_Property_IndexSpec;
begin
StartProgram(false);
Add([
'type',
' TEnum = (red, blue);',
' TObject = class',
' function GetIntBool(Index: longint): boolean; virtual; abstract;',
' procedure SetIntBool(Index: longint; b: boolean); virtual; abstract;',
' function GetEnumBool(Index: TEnum): boolean; virtual; abstract;',
' procedure SetEnumBool(Index: TEnum; b: boolean); virtual; abstract;',
' function GetStrIntBool(A: String; I: longint): boolean; virtual; abstract;',
' procedure SetStrIntBool(A: String; I: longint; b: boolean); virtual; abstract;',
' property B1: boolean index 1 read GetIntBool write SetIntBool;',
' property B2: boolean index TEnum.blue read GetEnumBool write SetEnumBool;',
' property I1[A: String]: boolean index 2 read GetStrIntBool write SetStrIntBool;',
' end;',
'procedure DoIt(b: boolean); begin end;',
'var',
' o: TObject;',
'begin',
' o.B1:=o.B1;',
' o.B2:=o.B2;',
' o.I1[''a'']:=o.I1[''b''];',
' doit(o.b1);',
' doit(o.b2);',
' doit(o.i1[''c'']);',
'']);
ConvertProgram;
CheckSource('TestClass_Property_IndexSpec',
LinesToStr([ // statements
'this.TEnum = {',
' "0": "red",',
' red: 0,',
' "1": "blue",',
' blue: 1',
'};',
'rtl.createClass($mod, "TObject", null, function () {',
' this.$init = function () {',
' };',
' this.$final = function () {',
' };',
'});',
'this.DoIt = function (b) {',
'};',
'this.o = null;',
'']),
LinesToStr([ // $mod.$main
'$mod.o.SetIntBool(1, $mod.o.GetIntBool(1));',
'$mod.o.SetEnumBool(TEnum.blue, $mod.o.GetEnumBool(TEnum.blue));',
'$mod.o.SetStrIntBool("a", 2, $mod.o.GetStrIntBool("b", 2));',
'$mod.DoIt($mod.o.GetIntBool(1));',
'$mod.DoIt($mod.o.GetEnumBool(TEnum.blue));',
'$mod.DoIt($mod.o.GetStrIntBool("c", 2));',
'']));
end;
procedure TTestModule.TestClass_PropertyOfTypeArray; procedure TTestModule.TestClass_PropertyOfTypeArray;
begin begin
StartProgram(false); StartProgram(false);
@ -13450,6 +13508,85 @@ begin
ConvertProgram; ConvertProgram;
end; end;
procedure TTestModule.TestRTTI_IndexModifier;
begin
Converter.Options:=Converter.Options-[coNoTypeInfo];
StartProgram(false);
Add([
'type',
' TEnum = (red, blue);',
' TObject = class',
' FB: boolean;',
' procedure SetIntBool(Index: longint; b: boolean); virtual; abstract;',
' function GetBoolBool(Index: boolean): boolean; virtual; abstract;',
' procedure SetBoolBool(Index: boolean; b: boolean); virtual; abstract;',
' function GetEnumBool(Index: TEnum): boolean; virtual; abstract;',
' function GetStrIntBool(A: String; I: longint): boolean; virtual; abstract;',
' procedure SetStrIntBool(A: String; I: longint; b: boolean); virtual; abstract;',
' published',
' property B1: boolean index 1 read FB write SetIntBool;',
' property B2: boolean index TEnum.blue read GetEnumBool write FB;',
' property I1[A: String]: boolean index 2 read GetStrIntBool write SetStrIntBool;',
' end;',
'begin']);
ConvertProgram;
CheckSource('TestRTTI_IndexModifier',
LinesToStr([ // statements
'this.TEnum = {',
' "0": "red",',
' red: 0,',
' "1": "blue",',
' blue: 1',
'};',
'$mod.$rtti.$Enum("TEnum", {',
' minvalue: 0,',
' maxvalue: 1,',
' ordtype: 1,',
' enumtype: this.TEnum',
'});',
'rtl.createClass($mod, "TObject", null, function () {',
' this.$init = function () {',
' this.FB = false;',
' };',
' this.$final = function () {',
' };',
' var $r = this.$rtti;',
' $r.addProperty(',
' "B1",',
' 18,',
' rtl.boolean,',
' "FB",',
' "SetIntBool",',
' {',
' index: 1',
' }',
' );',
' $r.addProperty(',
' "B2",',
' 17,',
' rtl.boolean,',
' "GetEnumBool",',
' "FB",',
' {',
' index: $mod.TEnum.blue',
' }',
' );',
' $r.addProperty(',
' "I1",',
' 19,',
' rtl.boolean,',
' "GetStrIntBool",',
' "SetStrIntBool",',
' {',
' index: 2',
' }',
' );',
'});',
'']),
LinesToStr([ // $mod.$main
'']));
end;
procedure TTestModule.TestRTTI_StoredModifier; procedure TTestModule.TestRTTI_StoredModifier;
begin begin
Converter.Options:=Converter.Options-[coNoTypeInfo]; Converter.Options:=Converter.Options-[coNoTypeInfo];
@ -13461,7 +13598,6 @@ begin
' TObject = class', ' TObject = class',
' private', ' private',
' FB: boolean;', ' FB: boolean;',
//' FI: longint;',
' function IsBStored: boolean; virtual; abstract;', ' function IsBStored: boolean; virtual; abstract;',
' published', ' published',
' property BoolA: boolean read FB stored true;', ' property BoolA: boolean read FB stored true;',