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

View File

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

View File

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