Skip to content

Commit 19cc4c4

Browse files
committed
add support calling methods on interfaces and deref interface properties
1 parent 46cd311 commit 19cc4c4

File tree

3 files changed

+66
-4
lines changed

3 files changed

+66
-4
lines changed

src/Sempare.Template.Evaluate.pas

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1112,12 +1112,23 @@ function TEvaluationTemplateVisitor.Invoke(const AExpr: IMethodCallExpr; const A
11121112
LObjType: TRttiType;
11131113
LObject: TValue;
11141114
LMethod: TRttiMethod;
1115+
LIntf: IInterface;
11151116
begin
11161117
LObjType := FContext.RttiContext.GetType(AObject.TypeInfo);
1117-
LMethod := LObjType.GetMethod(AExpr.Method);
11181118
LObject := AObject;
1119-
if AObject.IsType<TValue> then
1120-
LObject := AObject.AsType<TValue>;
1119+
if LObject.Kind = tkInterface then
1120+
begin
1121+
LIntf := LObject.AsInterface;
1122+
LObject := TObject(LIntf);
1123+
LObjType := FContext.RttiContext.GetType(LObject.TypeInfo);
1124+
end
1125+
else
1126+
begin
1127+
if AObject.IsType<TValue> then
1128+
LObject := AObject.AsType<TValue>;
1129+
end;
1130+
LMethod := LObjType.GetMethod(AExpr.Method);
1131+
11211132
exit(DoInvoke(AExpr, LMethod, LObject, AArgs, AHasResult));
11221133
end;
11231134

src/Sempare.Template.Rtti.pas

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -915,6 +915,8 @@ function TryDeref(const APosition: IPosition; const AVar, ADeref: TValue; const
915915
var
916916
LFunctionPair: TPair<TDerefMatchInterfaceFunction, TDerefFunction>;
917917
LIntf: IInterface;
918+
LProperty: TRttiProperty;
919+
LType: TRttiType;
918920
begin
919921
LIntf := AObj.AsInterface;
920922
for LFunctionPair in GDerefInterfaceFunctions do
@@ -925,10 +927,14 @@ function TryDeref(const APosition: IPosition; const AVar, ADeref: TValue; const
925927
exit(true);
926928
end;
927929
end;
930+
LType := AContext.RttiContext.GetType(AObj.TypeInfo);
931+
LProperty := LType.GetProperty(ADeref.AsString);
932+
if assigned(LProperty) then
933+
AResult := LProperty.GetValue(AObj.AsType<pointer>);
928934
exit(ExitEmpty(AResult));
929935
end;
930936

931-
function FixTValue(var AValue: TValue; const AResult:boolean=true): boolean;
937+
function FixTValue(var AValue: TValue; const AResult: boolean = true): boolean;
932938
begin
933939
if (AValue.Kind = tkRecord) and MatchValue(AValue.TypeInfo) then
934940
begin

tests/Sempare.Template.TestDeref.pas

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,12 @@ TTestTemplateDeref = class
5454
procedure TestDerefError;
5555
[Test]
5656
procedure TestDerefNull;
57+
58+
[Test]
59+
procedure TestIntfProperty;
60+
61+
[Test]
62+
procedure TestIntfMethod;
5763
end;
5864

5965
TNullable = class
@@ -62,13 +68,30 @@ TNullable = class
6268
Other: TNullable;
6369
end;
6470

71+
ITestData = interface
72+
['{7F66CDA3-3C98-41AF-A762-8B48FEBF8700}']
73+
function GetData: string;
74+
property Data: string read GetData;
75+
end;
76+
77+
TTestData = class(TInterfacedObject, ITestData)
78+
function GetData: string;
79+
end;
80+
6581
implementation
6682

6783
uses
84+
System.Rtti,
6885
System.SysUtils,
6986
Sempare.Template.Context,
7087
Sempare.Template;
7188

89+
{ TTestData }
90+
function TTestData.GetData: string;
91+
begin
92+
exit('hello');
93+
end;
94+
7295
{ TTestTemplateDeref }
7396

7497
procedure TTestTemplateDeref.Test<T>(const AValue: T; const AExpect: string; const ATemplate: string);
@@ -129,6 +152,28 @@ procedure TTestTemplateDeref.TestExprDrefef;
129152
Test(rec, '''before 123 after ''', '''before <% suffix := ''def'' %> <% a.b[''abc'' + suffix] %> after ''');
130153
end;
131154

155+
procedure TTestTemplateDeref.TestIntfMethod;
156+
var
157+
LIntf: ITestData;
158+
begin
159+
LIntf := TTestData.Create;
160+
161+
Assert.AreEqual('hello', Template.Eval('<% _.GetData() %>', TValue.From<ITestData>(LIntf)));
162+
163+
end;
164+
165+
procedure TTestTemplateDeref.TestIntfProperty;
166+
var
167+
LIntf: ITestData;
168+
begin
169+
LIntf := TTestData.Create;
170+
Assert.WillRaise(
171+
procedure
172+
begin
173+
Assert.AreEqual('hello', Template.Eval('<% _.data %>', TValue.From<ITestData>(LIntf)));
174+
end);
175+
end;
176+
132177
procedure TTestTemplateDeref.TestSimpleDrefef;
133178
begin
134179
Assert.IsNotNull(Template.parse('before <% a.b %> after '));

0 commit comments

Comments
 (0)