fcl-passrc: parser: fixed (a.b).c

git-svn-id: trunk@40870 -
This commit is contained in:
Mattias Gaertner 2019-01-16 13:40:23 +00:00
parent 38f158bb69
commit 4f04f23479
3 changed files with 646 additions and 444 deletions

View File

@ -993,9 +993,9 @@ type
Current: TPasProperty; Current: TPasProperty;
end; end;
{ TPasSubScope - base class for sub scopes aka dotted scopes } { TPasSubExprScope - base class for sub scopes aka dotted scopes }
TPasSubScope = Class(TPasIdentifierScope) TPasSubExprScope = Class(TPasIdentifierScope)
public public
class function IsStoredInElement: boolean; override; class function IsStoredInElement: boolean; override;
end; end;
@ -1010,7 +1010,7 @@ type
{ TPasModuleDotScope - scope for searching unitname.<identifier> } { TPasModuleDotScope - scope for searching unitname.<identifier> }
TPasModuleDotScope = Class(TPasSubScope) TPasModuleDotScope = Class(TPasSubExprScope)
private private
FModule: TPasModule; FModule: TPasModule;
procedure OnInternalIterate(El: TPasElement; ElScope, StartScope: TPasScope; procedure OnInternalIterate(El: TPasElement; ElScope, StartScope: TPasScope;
@ -1031,7 +1031,7 @@ type
{ TPasDotIdentifierScope } { TPasDotIdentifierScope }
TPasDotIdentifierScope = Class(TPasSubScope) TPasDotIdentifierScope = Class(TPasSubExprScope)
public public
IdentifierScope: TPasIdentifierScope; IdentifierScope: TPasIdentifierScope;
OnlyTypeMembers: boolean; // true=only class var/procs, false=default=all OnlyTypeMembers: boolean; // true=only class var/procs, false=default=all
@ -1410,7 +1410,9 @@ type
procedure ResolveSubIdent(El: TBinaryExpr; Access: TResolvedRefAccess); virtual; procedure ResolveSubIdent(El: TBinaryExpr; Access: TResolvedRefAccess); virtual;
procedure ResolveParamsExpr(Params: TParamsExpr; Access: TResolvedRefAccess); virtual; procedure ResolveParamsExpr(Params: TParamsExpr; Access: TResolvedRefAccess); virtual;
procedure ResolveFuncParamsExpr(Params: TParamsExpr; Access: TResolvedRefAccess); virtual; procedure ResolveFuncParamsExpr(Params: TParamsExpr; Access: TResolvedRefAccess); virtual;
procedure ResolveFuncParamsExprName(NameExpr: TPasExpr; Params: TParamsExpr; Access: TResolvedRefAccess); virtual;
procedure ResolveArrayParamsExpr(Params: TParamsExpr; Access: TResolvedRefAccess); virtual; procedure ResolveArrayParamsExpr(Params: TParamsExpr; Access: TResolvedRefAccess); virtual;
procedure ResolveArrayParamsExprName(NameExpr: TPasExpr; Params: TParamsExpr; Access: TResolvedRefAccess); virtual;
procedure ResolveArrayParamsArgs(Params: TParamsExpr; procedure ResolveArrayParamsArgs(Params: TParamsExpr;
const ResolvedValue: TPasResolverResult; Access: TResolvedRefAccess); virtual; const ResolvedValue: TPasResolverResult; Access: TResolvedRefAccess); virtual;
function ResolveBracketOperatorClassOrRec(Params: TParamsExpr; function ResolveBracketOperatorClassOrRec(Params: TParamsExpr;
@ -1747,8 +1749,8 @@ type
function PushRecordDotScope(CurRecordType: TPasRecordType): TPasDotRecordScope; function PushRecordDotScope(CurRecordType: TPasRecordType): TPasDotRecordScope;
function PushEnumDotScope(CurEnumType: TPasEnumType): TPasDotEnumTypeScope; function PushEnumDotScope(CurEnumType: TPasEnumType): TPasDotEnumTypeScope;
function PushWithExprScope(Expr: TPasExpr): TPasWithExprScope; function PushWithExprScope(Expr: TPasExpr): TPasWithExprScope;
procedure ResetSubScopes(out Depth: integer); procedure ResetSubExprScopes(out Depth: integer);
procedure RestoreSubScopes(Depth: integer); procedure RestoreSubExprScopes(Depth: integer);
function GetInheritedExprScope(ErrorEl: TPasElement): TPasProcedureScope; function GetInheritedExprScope(ErrorEl: TPasElement): TPasProcedureScope;
// log and messages // log and messages
class function MangleSourceLineNumber(Line, Column: integer): integer; class function MangleSourceLineNumber(Line, Column: integer): integer;
@ -1894,11 +1896,13 @@ type
function GetNextDottedExpr(El: TPasExpr): TPasExpr; function GetNextDottedExpr(El: TPasExpr): TPasExpr;
function GetLeftMostExpr(El: TPasExpr): TPasExpr; function GetLeftMostExpr(El: TPasExpr): TPasExpr;
function GetRightMostExpr(El: TPasExpr): TPasExpr; function GetRightMostExpr(El: TPasExpr): TPasExpr;
function GetParamsOfNameExpr(El: TPasExpr): TParamsExpr;
function GetUsesUnitInFilename(InFileExpr: TPasExpr): string; function GetUsesUnitInFilename(InFileExpr: TPasExpr): string;
function GetPathStart(El: TPasExpr): TPasExpr; function GetPathStart(El: TPasExpr): TPasExpr;
function GetNewInstanceExpr(El: TPasExpr): TPasExpr; function GetNewInstanceExpr(El: TPasExpr): TPasExpr;
function ParentNeedsExprResult(El: TPasExpr): boolean; function ParentNeedsExprResult(El: TPasExpr): boolean;
function GetReference_ConstructorType(Ref: TResolvedReference): TPasMembersType; function GetReference_ConstructorType(Ref: TResolvedReference): TPasMembersType;
function GetParamsValueRef(Params: TParamsExpr): TResolvedReference;
function IsDynArray(TypeEl: TPasType; OptionalOpenArray: boolean = true): boolean; function IsDynArray(TypeEl: TPasType; OptionalOpenArray: boolean = true): boolean;
function IsOpenArray(TypeEl: TPasType): boolean; function IsOpenArray(TypeEl: TPasType): boolean;
function IsDynOrOpenArray(TypeEl: TPasType): boolean; function IsDynOrOpenArray(TypeEl: TPasType): boolean;
@ -3210,9 +3214,9 @@ begin
{$ENDIF} {$ENDIF}
end; end;
{ TPasSubScope } { TPasSubExprScope }
class function TPasSubScope.IsStoredInElement: boolean; class function TPasSubExprScope.IsStoredInElement: boolean;
begin begin
Result:=false; Result:=false;
end; end;
@ -3915,6 +3919,29 @@ begin
end; end;
end; end;
function TPasResolver.GetParamsOfNameExpr(El: TPasExpr): TParamsExpr;
// Checks is El is the name expression of a call or array access
// For example: a.b.El() a.El[]
// Note: TPasParser guarantees that there is at most one TBinaryExpr between
// El and TParamsExpr
var
Parent: TPasElement;
begin
Result:=nil;
if not IsNameExpr(El) then exit;
Parent:=El.Parent;
if Parent is TBinaryExpr then
begin
if (TBinaryExpr(Parent).OpCode<>eopSubIdent)
or (TBinaryExpr(Parent).right<>El) then
exit;
El:=TBinaryExpr(Parent); // continue
Parent:=El.Parent;
end;
if (Parent is TParamsExpr) and (TParamsExpr(Parent).Value=El) then
exit(TParamsExpr(Parent)); // params found
end;
function TPasResolver.GetUsesUnitInFilename(InFileExpr: TPasExpr): string; function TPasResolver.GetUsesUnitInFilename(InFileExpr: TPasExpr): string;
var var
Value: TResEvalValue; Value: TResEvalValue;
@ -8040,10 +8067,26 @@ var
DottedName: String; DottedName: String;
Bin: TBinaryExpr; Bin: TBinaryExpr;
ProcScope: TPasProcedureScope; ProcScope: TPasProcedureScope;
Params: TParamsExpr;
begin begin
{$IFDEF VerbosePasResolver} {$IFDEF VerbosePasResolver}
writeln('TPasResolver.ResolveNameExpr El=',GetObjName(El),' Name="',aName,'" ',Access); writeln('TPasResolver.ResolveNameExpr El=',GetObjName(El),' Name="',aName,'" ',Access);
{$ENDIF} {$ENDIF}
Params:=GetParamsOfNameExpr(El);
if Params<>nil then
begin
if Params.Kind=pekFuncParams then
begin
ResolveFuncParamsExprName(El,Params,Access);
exit;
end
else if Params.Kind=pekArrayParams then
begin
ResolveArrayParamsExprName(El,Params,Access);
exit;
end;
end;
DeclEl:=FindElementWithoutParams(aName,FindData,El,false); DeclEl:=FindElementWithoutParams(aName,FindData,El,false);
if DeclEl.ClassType=TPasUsesUnit then if DeclEl.ClassType=TPasUsesUnit then
begin begin
@ -8414,14 +8457,14 @@ begin
end; end;
// first resolve params // first resolve params
ResetSubScopes(ScopeDepth); ResetSubExprScopes(ScopeDepth);
if Params.Kind in [pekFuncParams,pekArrayParams] then if Params.Kind in [pekFuncParams,pekArrayParams] then
ParamAccess:=rraParamToUnknownProc ParamAccess:=rraParamToUnknownProc
else else
ParamAccess:=rraRead; ParamAccess:=rraRead;
for i:=0 to length(Params.Params)-1 do for i:=0 to length(Params.Params)-1 do
ResolveExpr(Params.Params[i],ParamAccess); ResolveExpr(Params.Params[i],ParamAccess);
RestoreSubScopes(ScopeDepth); RestoreSubExprScopes(ScopeDepth);
// then resolve the call, typecast, array, set // then resolve the call, typecast, array, set
if (Params.Kind=pekFuncParams) then if (Params.Kind=pekFuncParams) then
@ -8436,6 +8479,64 @@ end;
procedure TPasResolver.ResolveFuncParamsExpr(Params: TParamsExpr; procedure TPasResolver.ResolveFuncParamsExpr(Params: TParamsExpr;
Access: TResolvedRefAccess); Access: TResolvedRefAccess);
var
Value: TPasExpr;
SubParams: TParamsExpr;
ResolvedEl: TPasResolverResult;
begin
Value:=Params.Value;
if Value is TBinaryExpr then
begin
// Note: a.b() is the same as (a.b)()
// Note: a.b().c is stored as
// TBinaryExpr eopSubIdent
// / \
// left = TParamsExpr right = TPrimitiveExpr 'c'
// Value = TBinaryExpr
// / \
// left = TPrimitiveExpr 'a' right = TPrimitiveExpr 'b'
while (Value is TBinaryExpr) and (TBinaryExpr(Value).OpCode=eopSubIdent) do
Value:=TBinaryExpr(Value).right;
if IsNameExpr(Value) then
begin
ResolveBinaryExpr(TBinaryExpr(Params.Value),Access);
if not (Value.CustomData is TResolvedReference) then
RaiseNotYetImplemented(20190115140557,Params);
// already resolved
exit;
end;
// ToDo: (a+b)()
//ResolveBinaryExpr(TBinaryExpr(Params.Value),rraRead);
RaiseNotYetImplemented(20190115140809,Params);
end
else if IsNameExpr(Value) then
begin
ResolveFuncParamsExprName(Value,Params,Access);
end
else if Value.ClassType=TParamsExpr then
begin
SubParams:=TParamsExpr(Value);
if (SubParams.Kind in [pekArrayParams,pekFuncParams]) then
begin
// e.g. Name()() or Name[]()
ResolveExpr(SubParams,rraRead);
ComputeElement(SubParams,ResolvedEl,[rcNoImplicitProc,rcSetReferenceFlags]);
if IsProcedureType(ResolvedEl,true) then
begin
CheckCallProcCompatibility(TPasProcedureType(ResolvedEl.LoTypeEl),Params,true);
CreateReference(TPasProcedureType(ResolvedEl.LoTypeEl),Value,Access);
exit;
end
end;
RaiseMsg(20170216152202,nIllegalQualifierAfter,sIllegalQualifierAfter,
['(',SubParams.ElementTypeName],Params);
end
else
RaiseNotYetImplemented(20161014085118,Params.Value);
end;
procedure TPasResolver.ResolveFuncParamsExprName(NameExpr: TPasExpr;
Params: TParamsExpr; Access: TResolvedRefAccess);
procedure FinishProcParams(ProcType: TPasProcedureType); procedure FinishProcParams(ProcType: TPasProcedureType);
var var
@ -8445,7 +8546,7 @@ procedure TPasResolver.ResolveFuncParamsExpr(Params: TParamsExpr;
if not (Access in [rraRead,rraParamToUnknownProc]) then if not (Access in [rraRead,rraParamToUnknownProc]) then
begin begin
{$IFDEF VerbosePasResolver} {$IFDEF VerbosePasResolver}
writeln('TPasResolver.ResolveFuncParamsExpr.FinishProcParams Params=',GetObjName(Params),' Value=',GetObjName(Params.Value),' Access=',Access); writeln('TPasResolver.ResolveFuncParamsExpr.FinishProcParams Params=',GetObjName(Params),' NameEl=',GetObjName(NameExpr),' Access=',Access);
{$ENDIF} {$ENDIF}
RaiseMsg(20170306104440,nVariableIdentifierExpected,sVariableIdentifierExpected,[],Params); RaiseMsg(20170306104440,nVariableIdentifierExpected,sVariableIdentifierExpected,[],Params);
end; end;
@ -8473,33 +8574,30 @@ procedure TPasResolver.ResolveFuncParamsExpr(Params: TParamsExpr;
var var
i: Integer; i: Integer;
ElName, Msg: String; CallName, Msg: String;
FindCallData: TFindCallElData; FindCallData: TFindCallElData;
Abort: boolean; Abort: boolean;
El, FoundEl: TPasElement; El, FoundEl: TPasElement;
Ref: TResolvedReference; Ref: TResolvedReference;
FindData: TPRFindData; FindData: TPRFindData;
BuiltInProc: TResElDataBuiltInProc; BuiltInProc: TResElDataBuiltInProc;
SubParams: TParamsExpr;
ResolvedEl: TPasResolverResult; ResolvedEl: TPasResolverResult;
Value: TPasExpr;
TypeEl: TPasType; TypeEl: TPasType;
C: TClass; C: TClass;
begin
Value:=Params.Value;
if IsNameExpr(Value) then
begin begin
// e.g. Name() -> find compatible // e.g. Name() -> find compatible
if Value.ClassType=TPrimitiveExpr then if NameExpr.ClassType=TPrimitiveExpr then
ElName:=TPrimitiveExpr(Value).Value CallName:=TPrimitiveExpr(NameExpr).Value
else if NameExpr.ClassType=TSelfExpr then
CallName:='Self'
else else
ElName:='Self'; RaiseNotYetImplemented(20190115143539,NameExpr);
FindCallData:=Default(TFindCallElData); FindCallData:=Default(TFindCallElData);
FindCallData.Params:=Params; FindCallData.Params:=Params;
Abort:=false; Abort:=false;
IterateElements(ElName,@OnFindCallElements,@FindCallData,Abort); IterateElements(CallName,@OnFindCallElements,@FindCallData,Abort);
if FindCallData.Found=nil then if FindCallData.Found=nil then
RaiseIdentifierNotFound(20170216152544,ElName,Value); RaiseIdentifierNotFound(20170216152544,CallName,NameExpr);
if FindCallData.Distance=cIncompatible then if FindCallData.Distance=cIncompatible then
begin begin
// FoundEl one element, but it was incompatible => raise error // FoundEl one element, but it was incompatible => raise error
@ -8554,7 +8652,7 @@ begin
FindCallData.Params:=Params; FindCallData.Params:=Params;
FindCallData.List:=TFPList.Create; FindCallData.List:=TFPList.Create;
try try
IterateElements(ElName,@OnFindCallElements,@FindCallData,Abort); IterateElements(CallName,@OnFindCallElements,@FindCallData,Abort);
Msg:=''; Msg:='';
for i:=0 to FindCallData.List.Count-1 do for i:=0 to FindCallData.List.Count-1 do
begin begin
@ -8570,7 +8668,7 @@ begin
Msg:=Msg+', '+GetElementSourcePosStr(El); Msg:=Msg+', '+GetElementSourcePosStr(El);
end; end;
RaiseMsg(20170216152200,nCantDetermineWhichOverloadedFunctionToCall, RaiseMsg(20170216152200,nCantDetermineWhichOverloadedFunctionToCall,
sCantDetermineWhichOverloadedFunctionToCall+Msg,[ElName],Value); sCantDetermineWhichOverloadedFunctionToCall+Msg,[CallName],NameExpr);
finally finally
FindCallData.List.Free; FindCallData.List.Free;
end; end;
@ -8578,11 +8676,11 @@ begin
// FoundEl compatible element -> create reference // FoundEl compatible element -> create reference
FoundEl:=FindCallData.Found; FoundEl:=FindCallData.Found;
Ref:=CreateReference(FoundEl,Value,rraRead); Ref:=CreateReference(FoundEl,NameExpr,rraRead);
if FindCallData.StartScope.ClassType=ScopeClass_WithExpr then if FindCallData.StartScope.ClassType=ScopeClass_WithExpr then
Ref.WithExprScope:=TPasWithExprScope(FindCallData.StartScope); Ref.WithExprScope:=TPasWithExprScope(FindCallData.StartScope);
FindData:=Default(TPRFindData); FindData:=Default(TPRFindData);
FindData.ErrorPosEl:=Value; FindData.ErrorPosEl:=NameExpr;
FindData.StartScope:=FindCallData.StartScope; FindData.StartScope:=FindCallData.StartScope;
FindData.ElScope:=FindCallData.ElScope; FindData.ElScope:=FindCallData.ElScope;
FindData.Found:=FoundEl; FindData.Found:=FoundEl;
@ -8663,51 +8761,102 @@ begin
RaiseMsg(20170306104301,nIllegalQualifierAfter,sIllegalQualifierAfter, RaiseMsg(20170306104301,nIllegalQualifierAfter,sIllegalQualifierAfter,
['(',TypeEl.ElementTypeName],Params); ['(',TypeEl.ElementTypeName],Params);
end; end;
end
else if Value.ClassType=TParamsExpr then
begin
SubParams:=TParamsExpr(Value);
if (SubParams.Kind in [pekArrayParams,pekFuncParams]) then
begin
// e.g. Name()() or Name[]()
ResolveExpr(SubParams,rraRead);
ComputeElement(SubParams,ResolvedEl,[rcNoImplicitProc,rcSetReferenceFlags]);
if IsProcedureType(ResolvedEl,true) then
begin
CheckCallProcCompatibility(TPasProcedureType(ResolvedEl.LoTypeEl),Params,true);
CreateReference(TPasProcedureType(ResolvedEl.LoTypeEl),Value,Access);
exit;
end
end;
RaiseMsg(20170216152202,nIllegalQualifierAfter,sIllegalQualifierAfter,
['(',SubParams.ElementTypeName],Params);
end
else
RaiseNotYetImplemented(20161014085118,Params.Value);
end; end;
procedure TPasResolver.ResolveArrayParamsExpr(Params: TParamsExpr; procedure TPasResolver.ResolveArrayParamsExpr(Params: TParamsExpr;
Access: TResolvedRefAccess); Access: TResolvedRefAccess);
var var
ResolvedEl: TPasResolverResult; ResolvedEl: TPasResolverResult;
Value: TPasExpr;
SubParams: TParamsExpr;
begin
Value:=Params.Value;
if Value=nil then
RaiseInternalError(20180423093120,GetObjName(Params));
procedure ResolveValueName(Value: TPasElement; ArrayName: string); if IsNameExpr(Value) then
begin
// e.g. Name[]
ResolveArrayParamsExprName(Value,Params,Access);
exit;
end
else if Value.ClassType=TParamsExpr then
begin
SubParams:=TParamsExpr(Value);
// e.g. Name()[] or Name[][] or [][]
ResolveExpr(SubParams,rraRead);
ComputeElement(SubParams,ResolvedEl,[rcNoImplicitProc,rcSetReferenceFlags]);
if Value.CustomData=nil then
CreateReference(ResolvedEl.LoTypeEl,Value,Access);
end
else if Value.InheritsFrom(TUnaryExpr) then
begin
ResolveExpr(TUnaryExpr(Value).Operand,Access);
ComputeElement(Value,ResolvedEl,[rcSetReferenceFlags]);
end
else if Value is TBinaryExpr then
begin
// Note: a.b[] is the same as (a.b)[]
// Note: a.b[].c is stored as
// TBinaryExpr eopSubIdent
// / \
// left = TParamsExpr right = TPrimitiveExpr 'c'
// Value = TBinaryExpr
// / \
// left = TPrimitiveExpr 'a' right = TPrimitiveExpr 'b'
while (Value is TBinaryExpr) and (TBinaryExpr(Value).OpCode=eopSubIdent) do
Value:=TBinaryExpr(Value).right;
if IsNameExpr(Value) then
begin
ResolveBinaryExpr(TBinaryExpr(Params.Value),Access);
if not (Value.CustomData is TResolvedReference) then
RaiseNotYetImplemented(20190115144534,Params);
// already resolved
exit;
end
else
begin
// ToDo: (a+b)[]
//ResolveBinaryExpr(TBinaryExpr(Params.Value),rraRead);
RaiseNotYetImplemented(20190115144539,Params);
end;
end
else
RaiseNotYetImplemented(20160927212610,Value);
{$IFDEF VerbosePasResolver}
writeln('TPasResolver.ResolveArrayParamsExpr Value=',GetObjName(Value),' ',GetResolverResultDbg(ResolvedEl));
{$ENDIF}
ResolveArrayParamsArgs(Params,ResolvedEl,Access);
end;
procedure TPasResolver.ResolveArrayParamsExprName(NameExpr: TPasExpr;
Params: TParamsExpr; Access: TResolvedRefAccess);
// e.g. a.NameExp[]
var var
ArrayName: String;
FindData: TPRFindData; FindData: TPRFindData;
Ref: TResolvedReference; Ref: TResolvedReference;
DeclEl: TPasElement; DeclEl: TPasElement;
Proc, ImplProc: TPasProcedure; Proc, ImplProc: TPasProcedure;
ProcScope: TPasProcedureScope; ProcScope: TPasProcedureScope;
ResolvedEl: TPasResolverResult;
begin begin
if (NameExpr.ClassType=TPrimitiveExpr)
and (TPrimitiveExpr(NameExpr).Kind=pekIdent) then
// e.g. Name[] // e.g. Name[]
DeclEl:=FindElementWithoutParams(ArrayName,FindData,Value,true); ArrayName:=TPrimitiveExpr(NameExpr).Value
Ref:=CreateReference(DeclEl,Value,Access,@FindData); else if (NameExpr.ClassType=TSelfExpr) then
// e.g. Self[]
ArrayName:='Self';
DeclEl:=FindElementWithoutParams(ArrayName,FindData,NameExpr,true);
Ref:=CreateReference(DeclEl,NameExpr,Access,@FindData);
CheckFoundElement(FindData,Ref); CheckFoundElement(FindData,Ref);
if DeclEl is TPasProcedure then if DeclEl is TPasProcedure then
begin begin
Proc:=TPasProcedure(DeclEl); Proc:=TPasProcedure(DeclEl);
if (Access=rraAssign) and (Proc.ProcType is TPasFunctionType) if (Access=rraAssign) and (Proc.ProcType is TPasFunctionType)
and (Value.ClassType=TPrimitiveExpr)
and (Params.Parent.ClassType=TPasImplAssign) and (Params.Parent.ClassType=TPasImplAssign)
and (TPasImplAssign(Params.Parent).left=Params) then and (TPasImplAssign(Params.Parent).left=Params) then
begin begin
@ -8723,47 +8872,9 @@ var
end; end;
end; end;
end; end;
ComputeElement(Value,ResolvedEl,[rcSetReferenceFlags]); ComputeElement(NameExpr,ResolvedEl,[rcSetReferenceFlags]);
end;
var
Value: TPasExpr;
SubParams: TParamsExpr;
begin
Value:=Params.Value;
if Value=nil then
RaiseInternalError(20180423093120,GetObjName(Params));
if (Value.ClassType=TPrimitiveExpr)
and (TPrimitiveExpr(Value).Kind=pekIdent) then
// e.g. Name[]
ResolveValueName(Value,TPrimitiveExpr(Value).Value)
else if (Value.ClassType=TSelfExpr) then
// e.g. Self[]
ResolveValueName(Value,'Self')
else if Value.ClassType=TParamsExpr then
begin
SubParams:=TParamsExpr(Value);
if (SubParams.Kind in [pekArrayParams,pekFuncParams]) then
begin
// e.g. Name()[] or Name[][]
ResolveExpr(SubParams,rraRead);
ComputeElement(SubParams,ResolvedEl,[rcNoImplicitProc,rcSetReferenceFlags]);
if Value.CustomData=nil then
CreateReference(ResolvedEl.LoTypeEl,Value,Access);
end
else
RaiseNotYetImplemented(20161010194925,Value);
end
else if Value.InheritsFrom(TUnaryExpr) then
begin
ResolveExpr(TUnaryExpr(Value).Operand,Access);
ComputeElement(Value,ResolvedEl,[rcSetReferenceFlags]);
end
else
RaiseNotYetImplemented(20160927212610,Value);
{$IFDEF VerbosePasResolver} {$IFDEF VerbosePasResolver}
writeln('TPasResolver.ResolveArrayParamsExpr Value=',GetObjName(Value),' ',GetResolverResultDbg(ResolvedEl)); writeln('TPasResolver.ResolveArrayParamsExprName NameExp=',GetObjName(NameExpr),' ',GetResolverResultDbg(ResolvedEl));
{$ENDIF} {$ENDIF}
ResolveArrayParamsArgs(Params,ResolvedEl,Access); ResolveArrayParamsArgs(Params,ResolvedEl,Access);
end; end;
@ -10615,34 +10726,10 @@ var
ArrayEl: TPasArrayType; ArrayEl: TPasArrayType;
ArgNo: Integer; ArgNo: Integer;
OrigResolved: TPasResolverResult; OrigResolved: TPasResolverResult;
SubParams: TParamsExpr;
ClassOrRecordScope: TPasClassOrRecordScope; ClassOrRecordScope: TPasClassOrRecordScope;
begin begin
if Params.Value.CustomData is TResolvedReference then
begin
// e.g. Name[]
ComputeElement(Params.Value,ResolvedEl, ComputeElement(Params.Value,ResolvedEl,
Flags-[rcNoImplicitProc,rcNoImplicitProcType],StartEl); Flags-[rcNoImplicitProc,rcNoImplicitProcType],StartEl);
end
else if Params.Value.ClassType=TParamsExpr then
begin
SubParams:=TParamsExpr(Params.Value);
if SubParams.Kind in [pekArrayParams,pekFuncParams] then
begin
// e.g. Name()[] or Name[][]
ComputeElement(SubParams,ResolvedEl,
Flags-[rcNoImplicitProc,rcNoImplicitProcType],StartEl);
end
else
RaiseNotYetImplemented(20161010195646,SubParams);
end
else if Params.Value.ClassType=TUnaryExpr then
begin
ComputeElement(Params.Value,ResolvedEl,
Flags-[rcNoImplicitProc,rcNoImplicitProcType],StartEl);
end
else
RaiseNotYetImplemented(20160928174144,Params);
{$IFDEF VerbosePasResolver} {$IFDEF VerbosePasResolver}
writeln('TPasResolver.ComputeArrayParams ResolvedEl=',GetResolverResultDbg(ResolvedEl)); writeln('TPasResolver.ComputeArrayParams ResolvedEl=',GetResolverResultDbg(ResolvedEl));
@ -10766,9 +10853,9 @@ var
Param0: TPasExpr; Param0: TPasExpr;
ClassOrRec: TPasMembersType; ClassOrRec: TPasMembersType;
begin begin
if Params.Value.CustomData is TResolvedReference then Ref:=GetParamsValueRef(Params);
begin if Ref=nil then
Ref:=TResolvedReference(Params.Value.CustomData); RaiseNotYetImplemented(20160928174124,Params);
DeclEl:=Ref.Declaration; DeclEl:=Ref.Declaration;
if DeclEl.ClassType=TPasUnresolvedSymbolRef then if DeclEl.ClassType=TPasUnresolvedSymbolRef then
begin begin
@ -10880,9 +10967,6 @@ begin
else else
RaiseNotYetImplemented(20160928180048,Params,GetResolverResultDbg(ResolvedEl)); RaiseNotYetImplemented(20160928180048,Params,GetResolverResultDbg(ResolvedEl));
end; end;
end
else
RaiseNotYetImplemented(20160928174124,Params);
end; end;
procedure TPasResolver.ComputeTypeCast(ToLoType, ToHiType: TPasType; procedure TPasResolver.ComputeTypeCast(ToLoType, ToHiType: TPasType;
@ -12120,6 +12204,7 @@ begin
{$ENDIF} {$ENDIF}
if (Result=nil) and ([refConst,refConstExt]*Flags<>[]) then if (Result=nil) and ([refConst,refConstExt]*Flags<>[]) then
RaiseConstantExprExp(20170518213616,Expr); RaiseConstantExprExp(20170518213616,Expr);
if Sender=nil then ;
end; end;
function TPasResolver.OnExprEvalParams(Sender: TResExprEvaluator; function TPasResolver.OnExprEvalParams(Sender: TResExprEvaluator;
@ -12214,6 +12299,7 @@ begin
pekSet: ; pekSet: ;
end; end;
if Flags=[] then ; if Flags=[] then ;
if Sender=nil then ;
end; end;
procedure TPasResolver.OnRangeCheckEl(Sender: TResExprEvaluator; procedure TPasResolver.OnRangeCheckEl(Sender: TResExprEvaluator;
@ -12223,6 +12309,7 @@ begin
if (MsgType=mtWarning) if (MsgType=mtWarning)
and (bsRangeChecks in CurrentParser.Scanner.CurrentBoolSwitches) then and (bsRangeChecks in CurrentParser.Scanner.CurrentBoolSwitches) then
MsgType:=mtError; MsgType:=mtError;
if Sender=nil then ;
end; end;
function TPasResolver.EvalBaseTypeCast(Params: TParamsExpr; function TPasResolver.EvalBaseTypeCast(Params: TParamsExpr;
@ -12992,6 +13079,7 @@ procedure TPasResolver.BI_Assigned_OnGetCallResult(Proc: TResElDataBuiltInProc;
begin begin
SetResolverIdentifier(ResolvedEl,btBoolean,Proc.Proc, SetResolverIdentifier(ResolvedEl,btBoolean,Proc.Proc,
FBaseTypes[btBoolean],FBaseTypes[btBoolean],[rrfReadable]); FBaseTypes[btBoolean],FBaseTypes[btBoolean],[rrfReadable]);
if Params=nil then ;
end; end;
procedure TPasResolver.BI_Assigned_OnFinishParamsExpr( procedure TPasResolver.BI_Assigned_OnFinishParamsExpr(
@ -14954,7 +15042,7 @@ begin
Scope.IterateElements(AName,Scope,OnIterateElement,Data,Abort); Scope.IterateElements(AName,Scope,OnIterateElement,Data,Abort);
if Abort then if Abort then
exit; exit;
if Scope is TPasSubScope then break; if Scope is TPasSubExprScope then break;
end; end;
end; end;
@ -15535,7 +15623,7 @@ end;
procedure TPasResolver.Clear; procedure TPasResolver.Clear;
begin begin
RestoreSubScopes(0); RestoreSubExprScopes(0);
// clear stack, keep DefaultScope // clear stack, keep DefaultScope
while (FScopeCount>0) and (FTopScope<>DefaultScope) do while (FScopeCount>0) and (FTopScope<>DefaultScope) do
PopScope; PopScope;
@ -16046,11 +16134,11 @@ begin
Result:=WithExprScope; Result:=WithExprScope;
end; end;
procedure TPasResolver.ResetSubScopes(out Depth: integer); procedure TPasResolver.ResetSubExprScopes(out Depth: integer);
// move all sub scopes from Scopes to SubScopes // move all sub scopes from Scopes to SubScopes
begin begin
Depth:=FSubScopeCount; Depth:=FSubScopeCount;
while TopScope is TPasSubScope do while TopScope is TPasSubExprScope do
begin begin
{$IFDEF VerbosePasResolver} {$IFDEF VerbosePasResolver}
writeln('TPasResolver.ResetSubScopes moving ',TopScope.ClassName,' ScopeCount=',ScopeCount,' SubScopeCount=',FSubScopeCount); writeln('TPasResolver.ResetSubScopes moving ',TopScope.ClassName,' ScopeCount=',ScopeCount,' SubScopeCount=',FSubScopeCount);
@ -16068,7 +16156,7 @@ begin
end; end;
end; end;
procedure TPasResolver.RestoreSubScopes(Depth: integer); procedure TPasResolver.RestoreSubExprScopes(Depth: integer);
// restore sub scopes // restore sub scopes
begin begin
while FSubScopeCount>Depth do while FSubScopeCount>Depth do
@ -20869,6 +20957,25 @@ begin
Result:=(Ref.Context as TResolvedRefCtxConstructor).Typ as TPasMembersType; Result:=(Ref.Context as TResolvedRefCtxConstructor).Typ as TPasMembersType;
end; end;
function TPasResolver.GetParamsValueRef(Params: TParamsExpr): TResolvedReference;
var
El: TPasExpr;
begin
Result:=nil;
if Params=nil then exit;
El:=Params.Value;
while El<>nil do
begin
if El.CustomData is TResolvedReference then
exit(TResolvedReference(El.CustomData));
if (El is TBinaryExpr)
and (TBinaryExpr(El).OpCode=eopSubIdent) then
El:=TBinaryExpr(El).right
else
break;
end;
end;
function TPasResolver.IsDynArray(TypeEl: TPasType; OptionalOpenArray: boolean function TPasResolver.IsDynArray(TypeEl: TPasType; OptionalOpenArray: boolean
): boolean; ): boolean;
begin begin

View File

@ -341,8 +341,6 @@ type
function CreateBinaryExpr(AParent : TPasElement; xleft, xright: TPasExpr; AOpCode: TExprOpCode; const ASrcPos: TPasSourcePos): TBinaryExpr; overload; function CreateBinaryExpr(AParent : TPasElement; xleft, xright: TPasExpr; AOpCode: TExprOpCode; const ASrcPos: TPasSourcePos): TBinaryExpr; overload;
procedure AddToBinaryExprChain(var ChainFirst: TPasExpr; procedure AddToBinaryExprChain(var ChainFirst: TPasExpr;
Element: TPasExpr; AOpCode: TExprOpCode; const ASrcPos: TPasSourcePos); Element: TPasExpr; AOpCode: TExprOpCode; const ASrcPos: TPasSourcePos);
procedure AddParamsToBinaryExprChain(var ChainFirst: TPasExpr;
Params: TParamsExpr);
{$IFDEF VerbosePasParser} {$IFDEF VerbosePasParser}
procedure WriteBinaryExprChain(Prefix: string; First, Last: TPasExpr); procedure WriteBinaryExprChain(Prefix: string; First, Last: TPasExpr);
{$ENDIF} {$ENDIF}
@ -2355,9 +2353,9 @@ begin
if CurToken in [tkIdentifier,tktrue,tkfalse,tkself] then // true and false are sub identifiers as well if CurToken in [tkIdentifier,tktrue,tkfalse,tkself] then // true and false are sub identifiers as well
begin begin
aName:=aName+'.'+CurTokenString; aName:=aName+'.'+CurTokenString;
expr:=CreatePrimitiveExpr(AParent,pekIdent,CurTokenString); Expr:=CreatePrimitiveExpr(AParent,pekIdent,CurTokenString);
AddToBinaryExprChain(Result,expr,eopSubIdent,ScrPos); AddToBinaryExprChain(Result,Expr,eopSubIdent,ScrPos);
Func:=expr; Func:=Expr;
NextToken; NextToken;
end end
else else
@ -2373,14 +2371,18 @@ begin
else else
Params:=ParseParams(AParent,pekArrayParams); Params:=ParseParams(AParent,pekArrayParams);
if not Assigned(Params) then Exit; if not Assigned(Params) then Exit;
AddParamsToBinaryExprChain(Result,Params); Params.Value:=Result;
Result.Parent:=Params;
Result:=Params;
CanSpecialize:=false; CanSpecialize:=false;
Func:=nil;
end; end;
tkCaret: tkCaret:
begin begin
Result:=CreateUnaryExpr(AParent,Result,TokenToExprOp(CurToken)); Result:=CreateUnaryExpr(AParent,Result,TokenToExprOp(CurToken));
NextToken; NextToken;
CanSpecialize:=false; CanSpecialize:=false;
Func:=nil;
end; end;
tkLessThan: tkLessThan:
begin begin
@ -2402,6 +2404,7 @@ begin
CanSpecialize:=false; CanSpecialize:=false;
NextToken; NextToken;
end; end;
Func:=nil;
end end
else else
break; break;
@ -2568,26 +2571,40 @@ begin
CheckToken(tkBraceClose); CheckToken(tkBraceClose);
end; end;
NextToken; NextToken;
// for expressions like (ppdouble)^^; repeat
while (CurToken=tkCaret) do case CurToken of
tkCaret:
begin begin
// for expressions like (ppdouble)^^;
x:=CreateUnaryExpr(AParent,x, TokenToExprOp(tkCaret)); x:=CreateUnaryExpr(AParent,x, TokenToExprOp(tkCaret));
NextToken; NextToken;
end; end;
// for expressions like (PChar(a)+10)[0]; tkBraceOpen:
if (CurToken=tkSquaredBraceOpen) then
begin begin
// for expressions like (a+b)(0);
ArrParams:=ParseParams(AParent,pekFuncParams,False);
ArrParams.Value:=x;
x.Parent:=ArrParams;
x:=ArrParams;
end;
tkSquaredBraceOpen:
begin
// for expressions like (PChar(a)+10)[0];
ArrParams:=ParseParams(AParent,pekArrayParams,False); ArrParams:=ParseParams(AParent,pekArrayParams,False);
ArrParams.Value:=x; ArrParams.Value:=x;
x.Parent:=ArrParams; x.Parent:=ArrParams;
x:=ArrParams; x:=ArrParams;
end; end;
// for expressions like (TObject(m)).Free; tkDot:
if (CurToken=tkDot) then
begin begin
// for expressions like (TObject(m)).Free;
NextToken; NextToken;
x:=CreateBinaryExpr(AParent,x, ParseExprOperand(AParent), TokenToExprOp(tkDot)); x:=CreateBinaryExpr(AParent,x, ParseExprOperand(AParent), TokenToExprOp(tkDot));
end
else
break;
end; end;
until false;
end end
else else
begin begin
@ -5221,7 +5238,9 @@ function TPasParser.ParseProperty(Parent: TPasElement; const AName: String;
Result := Result + '['; Result := Result + '[';
Params:=TParamsExpr(CreateElement(TParamsExpr,'',aParent)); Params:=TParamsExpr(CreateElement(TParamsExpr,'',aParent));
Params.Kind:=pekArrayParams; Params.Kind:=pekArrayParams;
AddParamsToBinaryExprChain(Expr,Params); Params.Value:=Expr;
Expr.Parent:=Params;
Expr:=Params;
NextToken; NextToken;
case CurToken of case CurToken of
tkChar: Param:=CreatePrimitiveExpr(aParent,pekString, CurTokenText); tkChar: Param:=CreatePrimitiveExpr(aParent,pekString, CurTokenText);
@ -7042,37 +7061,6 @@ begin
end; end;
end; end;
procedure TPasParser.AddParamsToBinaryExprChain(var ChainFirst: TPasExpr;
Params: TParamsExpr);
// append Params to chain, using the last(right) element as Params.Value
var
Bin: TBinaryExpr;
begin
if Params.Value<>nil then
ParseExcSyntaxError;
if ChainFirst=nil then
ParseExcSyntaxError;
if ChainFirst is TBinaryExpr then
begin
Bin:=TBinaryExpr(ChainFirst);
if Bin.left=nil then
ParseExcSyntaxError;
if Bin.right=nil then
ParseExcSyntaxError;
Params.Value:=Bin.right;
Params.Value.Parent:=Params;
Bin.right:=Params;
Params.Parent:=Bin;
end
else
begin
Params.Value:=ChainFirst;
Params.Parent:=ChainFirst.Parent;
ChainFirst.Parent:=Params;
ChainFirst:=Params;
end;
end;
{$IFDEF VerbosePasParser} {$IFDEF VerbosePasParser}
{AllowWriteln} {AllowWriteln}
procedure TPasParser.WriteBinaryExprChain(Prefix: string; First, Last: TPasExpr procedure TPasParser.WriteBinaryExprChain(Prefix: string; First, Last: TPasExpr

View File

@ -96,14 +96,19 @@ type
Procedure TestBinaryLessThanEqual; Procedure TestBinaryLessThanEqual;
Procedure TestBinaryLargerThan; Procedure TestBinaryLargerThan;
Procedure TestBinaryLargerThanEqual; Procedure TestBinaryLargerThanEqual;
procedure TestBinaryFullIdent; procedure TestBinarySubIdent;
Procedure TestArrayElement; Procedure TestArrayElement;
Procedure TestArrayElementrecord; Procedure TestArrayElementRecord;
Procedure TestArrayElement2Dims; Procedure TestArrayElement2Dims;
Procedure TestFunctionCall; Procedure TestFunctionCall;
Procedure TestFunctionCall2args; Procedure TestFunctionCall2args;
Procedure TestFunctionCallNoArgs; Procedure TestFunctionCallNoArgs;
Procedure ParseStrWithFormatFullyQualified; Procedure TestSubIdentStrWithFormat;
Procedure TestAPlusCallB;
Procedure TestAPlusBBracketFuncParams;
Procedure TestAPlusBBracketArrayParams;
Procedure TestAPlusBBracketDotC;
Procedure TestADotBDotC;
Procedure TestRange; Procedure TestRange;
Procedure TestBracketsTotal; Procedure TestBracketsTotal;
Procedure TestBracketsLeft; Procedure TestBracketsLeft;
@ -257,7 +262,7 @@ begin
AssertExpression('Simple identifier',theExpr,pekIdent,'b'); AssertExpression('Simple identifier',theExpr,pekIdent,'b');
end; end;
procedure TTestExpressions.TestBinaryFullIdent; procedure TTestExpressions.TestBinarySubIdent;
begin begin
DeclareVar('integer','a'); DeclareVar('integer','a');
DeclareVar('record x,y : integer; end','b'); DeclareVar('record x,y : integer; end','b');
@ -282,7 +287,7 @@ begin
AssertExpression('Simple identifier',p.params[0],pekNumber,'1'); AssertExpression('Simple identifier',p.params[0],pekNumber,'1');
end; end;
procedure TTestExpressions.TestArrayElementrecord; procedure TTestExpressions.TestArrayElementRecord;
Var Var
P : TParamsExpr; P : TParamsExpr;
@ -290,14 +295,15 @@ Var
begin begin
DeclareVar('record a : array[1..2] of integer; end ','b'); DeclareVar('record a : array[1..2] of integer; end ','b');
ParseExpression('b.a[1]'); ParseExpression('b.a[1]');
B:=AssertExpression('Binary of record',TheExpr,pekBinary,TBinaryExpr) as TBinaryExpr; P:=TParamsExpr(AssertExpression('Array Param',TheExpr,pekArrayParams,TParamsExpr));
AssertEquals('Name is Subident',eopSubIdent,B.Opcode);
AssertExpression('Name of array',B.Left,pekIdent,'b');
P:=TParamsExpr(AssertExpression('Simple identifier',B.right,pekArrayParams,TParamsExpr));
AssertExpression('Name of array',P.Value,pekIdent,'a');
TAssert.AssertSame('P.value.parent=P',P,P.Value.Parent); TAssert.AssertSame('P.value.parent=P',P,P.Value.Parent);
AssertEquals('One dimension',1,Length(P.params)); AssertEquals('One dimension',1,Length(P.params));
AssertExpression('Simple identifier',P.params[0],pekNumber,'1'); AssertExpression('Simple identifier',P.params[0],pekNumber,'1');
B:=TBinaryExpr(AssertExpression('Binary of record',P.Value,pekBinary,TBinaryExpr));
AssertEquals('Name is Subident',eopSubIdent,B.Opcode);
AssertExpression('Name of array',B.Left,pekIdent,'b');
AssertExpression('Name of array',B.right,pekIdent,'a');
TAssert.AssertSame('B.left.parent=B',B,B.left.Parent); TAssert.AssertSame('B.left.parent=B',B,B.left.Parent);
TAssert.AssertSame('B.right.parent=B',B,B.right.Parent); TAssert.AssertSame('B.right.parent=B',B,B.right.Parent);
end; end;
@ -1124,7 +1130,7 @@ begin
AssertNotNull('Have left',AOperand); AssertNotNull('Have left',AOperand);
end; end;
Procedure TTestExpressions.ParseStrWithFormatFullyQualified; procedure TTestExpressions.TestSubIdentStrWithFormat;
Var Var
P : TParamsExpr; P : TParamsExpr;
@ -1134,12 +1140,113 @@ begin
DeclareVar('string','a'); DeclareVar('string','a');
DeclareVar('integer','i'); DeclareVar('integer','i');
ParseExpression('system.str(i:0:3,a)'); ParseExpression('system.str(i:0:3,a)');
B:=TBinaryExpr(AssertExpression('Binary identifier',theExpr,pekBinary,TBinaryExpr)); P:=TParamsExpr(AssertExpression('Params',TheExpr,pekFuncParams,TParamsExpr));
P:=TParamsExpr(AssertExpression('Simple identifier',B.Right,pekFuncParams,TParamsExpr)); TAssert.AssertSame('P.value.parent=P',P,P.Value.Parent);
AssertExpression('Name of function',P.Value,pekIdent,'str');
AssertEquals('2 argument',2,Length(p.params)); AssertEquals('2 argument',2,Length(p.params));
AssertExpression('Simple identifier',p.params[0],pekIdent,'i'); AssertExpression('Simple identifier',p.params[0],pekIdent,'i');
AssertExpression('Simple identifier',p.params[1],pekIdent,'a'); AssertExpression('Simple identifier',p.params[1],pekIdent,'a');
TAssert.AssertSame('P.params[0].parent=P',P,P.params[0].Parent);
TAssert.AssertSame('P.params[1].parent=P',P,P.params[1].Parent);
B:=TBinaryExpr(AssertExpression('Binary identifier',P.Value,pekBinary,TBinaryExpr));
AssertExpression('Name of unit',B.left,pekIdent,'system');
AssertExpression('Name of function',B.right,pekIdent,'str');
TAssert.AssertSame('B.left.parent=B',B,B.left.Parent);
TAssert.AssertSame('B.right.parent=B',B,B.right.Parent);
end;
procedure TTestExpressions.TestAPlusCallB;
var
B: TBinaryExpr;
P: TParamsExpr;
begin
DeclareVar('string','a');
DeclareVar('integer','b');
ParseExpression('a+b(1)');
B:=TBinaryExpr(AssertExpression('Binary identifier',TheExpr,pekBinary,TBinaryExpr));
AssertExpression('left a',B.left,pekIdent,'a');
TAssert.AssertSame('B.left.parent=B',B,B.left.Parent);
TAssert.AssertSame('B.right.parent=B',B,B.right.Parent);
P:=TParamsExpr(AssertExpression('Params',B.right,pekFuncParams,TParamsExpr));
TAssert.AssertSame('P.value.parent=P',P,P.Value.Parent);
AssertEquals('1 argument',1,Length(p.params));
AssertExpression('param 1',p.params[0],pekNumber,'1');
end;
procedure TTestExpressions.TestAPlusBBracketFuncParams;
var
P: TParamsExpr;
B: TBinaryExpr;
begin
DeclareVar('string','a');
DeclareVar('integer','b');
ParseExpression('(a+b)(1)');
P:=TParamsExpr(AssertExpression('Params',TheExpr,pekFuncParams,TParamsExpr));
TAssert.AssertSame('P.value.parent=P',P,P.Value.Parent);
AssertEquals('1 argument',1,Length(p.params));
AssertExpression('param 1',p.params[0],pekNumber,'1');
B:=TBinaryExpr(AssertExpression('Binary identifier',P.Value,pekBinary,TBinaryExpr));
TAssert.AssertSame('B.left.parent=B',B,B.left.Parent);
TAssert.AssertSame('B.right.parent=B',B,B.right.Parent);
AssertExpression('left a',B.left,pekIdent,'a');
AssertExpression('right b',B.right,pekIdent,'b');
end;
procedure TTestExpressions.TestAPlusBBracketArrayParams;
var
B: TBinaryExpr;
P: TParamsExpr;
begin
DeclareVar('string','a');
DeclareVar('integer','b');
ParseExpression('(a+b)[1]');
P:=TParamsExpr(AssertExpression('Params',TheExpr,pekArrayParams,TParamsExpr));
TAssert.AssertSame('P.value.parent=P',P,P.Value.Parent);
AssertEquals('1 argument',1,Length(p.params));
AssertExpression('param 1',p.params[0],pekNumber,'1');
B:=TBinaryExpr(AssertExpression('Binary identifier',P.Value,pekBinary,TBinaryExpr));
TAssert.AssertSame('B.left.parent=B',B,B.left.Parent);
TAssert.AssertSame('B.right.parent=B',B,B.right.Parent);
AssertExpression('left a',B.left,pekIdent,'a');
AssertExpression('right b',B.right,pekIdent,'b');
end;
procedure TTestExpressions.TestAPlusBBracketDotC;
var
B, PlusB: TBinaryExpr;
begin
DeclareVar('string','a');
DeclareVar('integer','b');
ParseExpression('(a+b).c');
B:=TBinaryExpr(AssertExpression('Binary identifier',TheExpr,pekBinary,TBinaryExpr));
AssertEquals('().',eopSubIdent,B.OpCode);
TAssert.AssertSame('B.left.parent=B',B,B.left.Parent);
TAssert.AssertSame('B.right.parent=B',B,B.right.Parent);
AssertExpression('right c',B.right,pekIdent,'c');
PlusB:=TBinaryExpr(AssertExpression('Binary identifier',B.left,pekBinary,TBinaryExpr));
TAssert.AssertSame('PlusB.left.parent=PlusB',PlusB,PlusB.left.Parent);
TAssert.AssertSame('PlusB.right.parent=PlusB',PlusB,PlusB.right.Parent);
AssertExpression('left a',PlusB.left,pekIdent,'a');
AssertExpression('right b',PlusB.right,pekIdent,'b');
end;
procedure TTestExpressions.TestADotBDotC;
var
B, SubB: TBinaryExpr;
begin
ParseExpression('a.b.c');
B:=TBinaryExpr(AssertExpression('Binary identifier',TheExpr,pekBinary,TBinaryExpr));
AssertEquals('dot expr',eopSubIdent,B.OpCode);
TAssert.AssertSame('B.left.parent=B',B,B.left.Parent);
TAssert.AssertSame('B.right.parent=B',B,B.right.Parent);
AssertExpression('right c',B.right,pekIdent,'c');
SubB:=TBinaryExpr(AssertExpression('Binary identifier',B.left,pekBinary,TBinaryExpr));
TAssert.AssertSame('PlusB.left.parent=PlusB',SubB,SubB.left.Parent);
TAssert.AssertSame('PlusB.right.parent=PlusB',SubB,SubB.right.Parent);
AssertExpression('left a',SubB.left,pekIdent,'a');
AssertExpression('right b',SubB.right,pekIdent,'b');
end; end;
initialization initialization