Browse Source

fcl-passrc: resolver: var modifier absolute

git-svn-id: trunk@37812 -
Mattias Gaertner 7 years ago
parent
commit
a99790afad

+ 33 - 4
packages/fcl-passrc/src/pasresolver.pp

@@ -168,21 +168,20 @@ Works:
   - array var
   - array var
   - function: enumerator
   - function: enumerator
   - class
   - class
+- var modifier 'absolute'
 
 
 ToDo:
 ToDo:
-- Add test:  test1 uses unit1, unit1 uses unit2, test1 references an identifier 'unit2' -> fail
 - for..in..do
 - for..in..do
    - operator
    - operator
 - range checking:
 - range checking:
   - indexedprop[param]
   - indexedprop[param]
   - case-of unique
   - case-of unique
   - defaultvalue
   - defaultvalue
+- scoped enum
 - $writableconst off $J-
 - $writableconst off $J-
 - fail to write a loop var inside the loop
 - fail to write a loop var inside the loop
 - warn: create class with abstract methods
 - warn: create class with abstract methods
-- classes - TPasClassType
-   - nested var, const
-   - nested types
+- nested classes
 - records - TPasRecordType,
 - records - TPasRecordType,
    - const  TRecordValues
    - const  TRecordValues
    - function default(record type): record
    - function default(record type): record
@@ -4306,6 +4305,9 @@ begin
 end;
 end;
 
 
 procedure TPasResolver.FinishVariable(El: TPasVariable);
 procedure TPasResolver.FinishVariable(El: TPasVariable);
+var
+  ResolvedAbs: TPasResolverResult;
+  C: TClass;
 begin
 begin
   if (El.Visibility=visPublished) then
   if (El.Visibility=visPublished) then
     begin
     begin
@@ -4317,6 +4319,33 @@ begin
     ResolveExpr(El.Expr,rraRead);
     ResolveExpr(El.Expr,rraRead);
     CheckAssignCompatibility(El,El.Expr,true);
     CheckAssignCompatibility(El,El.Expr,true);
     end;
     end;
+  if El.AbsoluteExpr<>nil then
+    begin
+    if El.VarType=nil then
+      RaiseMsg(20171225235125,nVariableIdentifierExpected,sVariableIdentifierExpected,[],El.AbsoluteExpr);
+    if vmExternal in El.VarModifiers then
+      RaiseMsg(20171226104221,nXModifierMismatchY,sXModifierMismatchY,
+        ['absolute','external'],El.AbsoluteExpr);
+    {$IFDEF VerbosePasResolver}
+    writeln('TPasResolver.FinishVariable El=',GetObjName(El),' Absolute="',GetObjName(El.AbsoluteExpr),'"');
+    {$ENDIF}
+    ResolveExpr(El.AbsoluteExpr,rraRead);
+    ComputeElement(El.AbsoluteExpr,ResolvedAbs,[rcNoImplicitProc]);
+    if (not (rrfReadable in ResolvedAbs.Flags))
+        or (ResolvedAbs.IdentEl=nil) then
+      RaiseMsg(20171225234734,nVariableIdentifierExpected,sVariableIdentifierExpected,[],El.AbsoluteExpr);
+    C:=ResolvedAbs.IdentEl.ClassType;
+    if (C=TPasVariable)
+        or (C=TPasArgument)
+        or ((C=TPasConst) and (TPasConst(ResolvedAbs.IdentEl).VarType<>nil)) then
+    else
+      RaiseMsg(20171225235203,nVariableIdentifierExpected,sVariableIdentifierExpected,[],El.AbsoluteExpr);
+    if not (rrfReadable in ResolvedAbs.Flags) then
+      RaiseMsg(20171225235249,nVariableIdentifierExpected,sVariableIdentifierExpected,[],El.AbsoluteExpr);
+    // check for cycles
+    if ResolvedAbs.IdentEl=El then
+      RaiseMsg(20171226000703,nVariableIdentifierExpected,sVariableIdentifierExpected,[],El.AbsoluteExpr);
+    end;
   EmitTypeHints(El,El.VarType);
   EmitTypeHints(El,El.VarType);
 end;
 end;
 
 

+ 2 - 1
packages/fcl-passrc/src/pastree.pp

@@ -831,7 +831,8 @@ type
     LibraryName : TPasExpr; // libname of modifier external
     LibraryName : TPasExpr; // libname of modifier external
     ExportName : TPasExpr; // symbol name of modifier external, export and public
     ExportName : TPasExpr; // symbol name of modifier external, export and public
     Modifiers : string;
     Modifiers : string;
-    AbsoluteLocation : String;
+    AbsoluteLocation : String deprecated; // deprecated in fpc 3.1.1
+    AbsoluteExpr: TPasExpr;
     Expr: TPasExpr;
     Expr: TPasExpr;
     Function Value : String;
     Function Value : String;
   end;
   end;

+ 13 - 1
packages/fcl-passrc/src/pasuseanalyzer.pas

@@ -984,7 +984,7 @@ var
   Params: TPasExprArray;
   Params: TPasExprArray;
   i: Integer;
   i: Integer;
   BuiltInProc: TResElDataBuiltInProc;
   BuiltInProc: TResElDataBuiltInProc;
-  ParamResolved: TPasResolverResult;
+  ParamResolved, ResolvedAbs: TPasResolverResult;
   Decl: TPasElement;
   Decl: TPasElement;
 begin
 begin
   if El=nil then exit;
   if El=nil then exit;
@@ -998,6 +998,13 @@ begin
     Decl:=Ref.Declaration;
     Decl:=Ref.Declaration;
     UseElement(Decl,Ref.Access,false);
     UseElement(Decl,Ref.Access,false);
 
 
+    if (Decl is TPasVariable) and (TPasVariable(Decl).AbsoluteExpr<>nil) then
+      begin
+      Resolver.ComputeElement(TPasVariable(Decl).AbsoluteExpr,ResolvedAbs,[rcNoImplicitProc]);
+      if ResolvedAbs.IdentEl is TPasVariable then
+        UseVariable(TPasVariable(ResolvedAbs.IdentEl),Ref.Access,false);
+      end;
+
     if Resolver.IsNameExpr(El) then
     if Resolver.IsNameExpr(El) then
       begin
       begin
       if Ref.WithExprScope<>nil then
       if Ref.WithExprScope<>nil then
@@ -1050,6 +1057,7 @@ begin
       or (C=TSelfExpr)
       or (C=TSelfExpr)
       or (C=TBoolConstExpr)
       or (C=TBoolConstExpr)
       or (C=TNilExpr) then
       or (C=TNilExpr) then
+    // ok
   else if C=TBinaryExpr then
   else if C=TBinaryExpr then
     begin
     begin
     UseExpr(TBinaryExpr(El).left);
     UseExpr(TBinaryExpr(El).left);
@@ -1514,6 +1522,10 @@ begin
       // ToDo: Prop.ImplementsFunc
       // ToDo: Prop.ImplementsFunc
       // ToDo: Prop.DispIDExpr
       // ToDo: Prop.DispIDExpr
       // see UsePublished: Prop.StoredAccessor, Prop.DefaultExpr
       // see UsePublished: Prop.StoredAccessor, Prop.DefaultExpr
+      end;
+    if El.AbsoluteExpr<>nil then
+      begin
+
       end;
       end;
     end
     end
   else
   else

+ 30 - 11
packages/fcl-passrc/src/pparser.pp

@@ -79,6 +79,7 @@ const
   nParserNoConstRangeAllowed = 2052;
   nParserNoConstRangeAllowed = 2052;
   nErrRecordVariablesNotAllowed = 2053;
   nErrRecordVariablesNotAllowed = 2053;
   nParserResourcestringsMustBeGlobal = 2054;
   nParserResourcestringsMustBeGlobal = 2054;
+  nParserOnlyOneVariableCanBeAbsolute = 2055;
 
 
 // resourcestring patterns of messages
 // resourcestring patterns of messages
 resourcestring
 resourcestring
@@ -136,6 +137,7 @@ resourcestring
   SParserExpectedExternalClassName = 'Expected external class name';
   SParserExpectedExternalClassName = 'Expected external class name';
   SParserNoConstRangeAllowed = 'Const ranges are not allowed';
   SParserNoConstRangeAllowed = 'Const ranges are not allowed';
   SParserResourcestringsMustBeGlobal = 'Resourcestrings can be only static or global';
   SParserResourcestringsMustBeGlobal = 'Resourcestrings can be only static or global';
+  SParserOnlyOneVariableCanBeAbsolute = 'Only one variable can be absolute';
 
 
 type
 type
   TPasScopeType = (
   TPasScopeType = (
@@ -263,7 +265,7 @@ type
     function GetCurrentModeSwitches: TModeSwitches;
     function GetCurrentModeSwitches: TModeSwitches;
     Procedure SetCurrentModeSwitches(AValue: TModeSwitches);
     Procedure SetCurrentModeSwitches(AValue: TModeSwitches);
     function GetVariableModifiers(Parent: TPasElement; Out VarMods: TVariableModifiers; Out LibName, ExportName: TPasExpr; ExternalClass : Boolean): string;
     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;
+    function GetVariableValueAndLocation(Parent : TPasElement; Out Value: TPasExpr; Out AbsoluteExpr: TPasExpr; Out Location: String): Boolean;
     procedure HandleProcedureModifier(Parent: TPasElement; pm : TProcedureModifier);
     procedure HandleProcedureModifier(Parent: TPasElement; pm : TProcedureModifier);
     procedure HandleProcedureTypeModifier(ProcType: TPasProcedureType; ptm : TProcTypeModifier);
     procedure HandleProcedureTypeModifier(ProcType: TPasProcedureType; ptm : TProcTypeModifier);
     procedure ParseClassLocalConsts(AType: TPasClassType; AVisibility: TPasMemberVisibility);
     procedure ParseClassLocalConsts(AType: TPasClassType; AVisibility: TPasMemberVisibility);
@@ -3764,28 +3766,31 @@ begin
 end;
 end;
 
 
 function TPasParser.GetVariableValueAndLocation(Parent: TPasElement; out
 function TPasParser.GetVariableValueAndLocation(Parent: TPasElement; out
-  Value: TPasExpr; out Location: String): Boolean;
+  Value: TPasExpr; out AbsoluteExpr: TPasExpr; out Location: String): Boolean;
 
 
 begin
 begin
   Value:=Nil;
   Value:=Nil;
+  AbsoluteExpr:=Nil;
+  Location:='';
   NextToken;
   NextToken;
   Result:=CurToken=tkEqual;
   Result:=CurToken=tkEqual;
   if Result then
   if Result then
     begin
     begin
     NextToken;
     NextToken;
     Value := DoParseConstValueExpression(Parent);
     Value := DoParseConstValueExpression(Parent);
-//    NextToken;
     end;
     end;
   if (CurToken=tkAbsolute) then
   if (CurToken=tkAbsolute) then
     begin
     begin
     Result:=True;
     Result:=True;
     ExpectIdentifier;
     ExpectIdentifier;
     Location:=CurTokenText;
     Location:=CurTokenText;
+    AbsoluteExpr:=CreatePrimitiveExpr(Parent,pekIdent,CurTokenText);
     NextToken;
     NextToken;
     While CurToken=tkDot do
     While CurToken=tkDot do
       begin
       begin
       ExpectIdentifier;
       ExpectIdentifier;
       Location:=Location+'.'+CurTokenText;
       Location:=Location+'.'+CurTokenText;
+      AbsoluteExpr:=CreateBinaryExpr(Parent,AbsoluteExpr,CreatePrimitiveExpr(Parent,pekIdent,CurTokenText),eopSubIdent);
       NextToken;
       NextToken;
       end;
       end;
     UnGetToken;
     UnGetToken;
@@ -3866,18 +3871,20 @@ procedure TPasParser.ParseVarList(Parent: TPasElement; VarList: TFPList;
 
 
 var
 var
   i, OldListCount: Integer;
   i, OldListCount: Integer;
-  Value , aLibName, aExpName: TPasExpr;
+  Value , aLibName, aExpName, AbsoluteExpr: TPasExpr;
   VarType: TPasType;
   VarType: TPasType;
   VarEl: TPasVariable;
   VarEl: TPasVariable;
   H : TPasMemberHints;
   H : TPasMemberHints;
   VarMods: TVariableModifiers;
   VarMods: TVariableModifiers;
-  D,Mods,Loc: string;
+  D,Mods,AbsoluteLocString: string;
   OldForceCaret,ok,ExternalClass: Boolean;
   OldForceCaret,ok,ExternalClass: Boolean;
 
 
 begin
 begin
   Value:=Nil;
   Value:=Nil;
   aLibName:=nil;
   aLibName:=nil;
   aExpName:=nil;
   aExpName:=nil;
+  AbsoluteExpr:=nil;
+  AbsoluteLocString:='';
   OldListCount:=VarList.Count;
   OldListCount:=VarList.Count;
   ok:=false;
   ok:=false;
   try
   try
@@ -3913,9 +3920,15 @@ begin
 
 
     H:=CheckHint(Nil,False);
     H:=CheckHint(Nil,False);
     If Full then
     If Full then
-      GetVariableValueAndLocation(Parent,Value,Loc);
-    if (Value<>nil) and (VarList.Count>OldListCount+1) then
-      ParseExc(nParserOnlyOneVariableCanBeInitialized,SParserOnlyOneVariableCanBeInitialized);
+      GetVariableValueAndLocation(Parent,Value,AbsoluteExpr,AbsoluteLocString);
+    if (VarList.Count>OldListCount+1) then
+      begin
+      // multiple variables
+      if Value<>nil then
+        ParseExc(nParserOnlyOneVariableCanBeAbsolute,SParserOnlyOneVariableCanBeAbsolute);
+      if Value<>nil then
+        ParseExc(nParserOnlyOneVariableCanBeInitialized,SParserOnlyOneVariableCanBeInitialized);
+      end;
     TPasVariable(VarList[OldListCount]).Expr:=Value;
     TPasVariable(VarList[OldListCount]).Expr:=Value;
     Value:=nil;
     Value:=nil;
 
 
@@ -3953,22 +3966,28 @@ begin
         VarEl.Hints:=H;
         VarEl.Hints:=H;
       VarEl.Modifiers:=Mods;
       VarEl.Modifiers:=Mods;
       VarEl.VarModifiers:=VarMods;
       VarEl.VarModifiers:=VarMods;
-      VarEl.AbsoluteLocation:=Loc;
+      VarEl.{%H-}AbsoluteLocation:=AbsoluteLocString;
+      if AbsoluteExpr<>nil then
+        begin
+        VarEl.AbsoluteExpr:=AbsoluteExpr;
+        AbsoluteExpr:=nil;
+        end;
       if aLibName<>nil then
       if aLibName<>nil then
         begin
         begin
         VarEl.LibraryName:=aLibName;
         VarEl.LibraryName:=aLibName;
-        aLibName.AddRef;
+        aLibName:=nil;
         end;
         end;
       if aExpName<>nil then
       if aExpName<>nil then
         begin
         begin
         VarEl.ExportName:=aExpName;
         VarEl.ExportName:=aExpName;
-        aExpName.AddRef;
+        aExpName:=nil;
         end;
         end;
       end;
       end;
     ok:=true;
     ok:=true;
   finally
   finally
     if aLibName<>nil then aLibName.Release;
     if aLibName<>nil then aLibName.Release;
     if aExpName<>nil then aExpName.Release;
     if aExpName<>nil then aExpName.Release;
+    if AbsoluteExpr<>nil then AbsoluteExpr.Release;
     if not ok then
     if not ok then
       begin
       begin
         if Value<>nil then Value.Release;
         if Value<>nil then Value.Release;

+ 10 - 2
packages/fcl-passrc/tests/tcbaseparser.pas

@@ -67,11 +67,12 @@ Type
     Procedure CheckHint(AHint : TPasMemberHint);
     Procedure CheckHint(AHint : TPasMemberHint);
     Function AssertExpression(Const Msg: String; AExpr : TPasExpr; aKind : TPasExprKind; AClass : TClass) : TPasExpr;
     Function AssertExpression(Const Msg: String; AExpr : TPasExpr; aKind : TPasExprKind; AClass : TClass) : TPasExpr;
     Function AssertExpression(Const Msg: String; AExpr : TPasExpr; aKind : TPasExprKind; AValue : String) : TPrimitiveExpr;
     Function AssertExpression(Const Msg: String; AExpr : TPasExpr; aKind : TPasExprKind; AValue : String) : TPrimitiveExpr;
+    Function AssertExpression(Const Msg: String; AExpr : TPasExpr; OpCode : TExprOpCode) : TBinaryExpr;
     Procedure AssertExportSymbol(Const Msg: String; AIndex : Integer; AName,AExportName : String; AExportIndex : Integer = -1);
     Procedure AssertExportSymbol(Const Msg: String; AIndex : Integer; AName,AExportName : String; AExportIndex : Integer = -1);
     Procedure AssertEquals(Const Msg : String; AExpected, AActual: TPasExprKind); overload;
     Procedure AssertEquals(Const Msg : String; AExpected, AActual: TPasExprKind); overload;
     Procedure AssertEquals(Const Msg : String; AExpected, AActual: TLoopType); overload;
     Procedure AssertEquals(Const Msg : String; AExpected, AActual: TLoopType); overload;
     Procedure AssertEquals(Const Msg : String; AExpected, AActual: TPasObjKind); overload;
     Procedure AssertEquals(Const Msg : String; AExpected, AActual: TPasObjKind); overload;
-    Procedure AssertEquals(Const Msg : String; AExpected, AActual: TexprOpcode); overload;
+    Procedure AssertEquals(Const Msg : String; AExpected, AActual: TExprOpCode); overload;
     Procedure AssertEquals(Const Msg : String; AExpected, AActual: TPasMemberHint); overload;
     Procedure AssertEquals(Const Msg : String; AExpected, AActual: TPasMemberHint); overload;
     Procedure AssertEquals(Const Msg : String; AExpected, AActual: TCallingConvention); overload;
     Procedure AssertEquals(Const Msg : String; AExpected, AActual: TCallingConvention); overload;
     Procedure AssertEquals(Const Msg : String; AExpected, AActual: TArgumentAccess); overload;
     Procedure AssertEquals(Const Msg : String; AExpected, AActual: TArgumentAccess); overload;
@@ -711,6 +712,13 @@ begin
   AssertEquals(Msg+': Primitive expression value',AValue,TPrimitiveExpr(AExpr).Value);
   AssertEquals(Msg+': Primitive expression value',AValue,TPrimitiveExpr(AExpr).Value);
 end;
 end;
 
 
+function TTestParser.AssertExpression(const Msg: String; AExpr: TPasExpr;
+  OpCode: TExprOpCode): TBinaryExpr;
+begin
+  Result:=AssertExpression(Msg,AExpr,pekBinary,TBinaryExpr) as TBinaryExpr;
+  AssertEquals(Msg+': Binary opcode',OpCode,TBinaryExpr(AExpr).OpCode);
+end;
+
 procedure TTestParser.AssertExportSymbol(const Msg: String; AIndex: Integer;
 procedure TTestParser.AssertExportSymbol(const Msg: String; AIndex: Integer;
   AName, AExportName: String; AExportIndex: Integer);
   AName, AExportName: String; AExportIndex: Integer);
 
 
@@ -765,7 +773,7 @@ begin
 end;
 end;
 
 
 procedure TTestParser.AssertEquals(const Msg: String; AExpected,
 procedure TTestParser.AssertEquals(const Msg: String; AExpected,
-  AActual: TexprOpcode);
+  AActual: TExprOpCode);
 begin
 begin
   AssertEquals(Msg,GetEnumName(TypeInfo(TexprOpcode),Ord(AExpected)),
   AssertEquals(Msg,GetEnumName(TypeInfo(TexprOpcode),Ord(AExpected)),
                    GetEnumName(TypeInfo(TexprOpcode),Ord(AActual)));
                    GetEnumName(TypeInfo(TexprOpcode),Ord(AActual)));

+ 14 - 0
packages/fcl-passrc/tests/tcresolver.pas

@@ -393,6 +393,7 @@ type
     Procedure TestProc_FunctionResult_DeclProc;
     Procedure TestProc_FunctionResult_DeclProc;
     Procedure TestProc_TypeCastFunctionResult;
     Procedure TestProc_TypeCastFunctionResult;
     Procedure TestProc_ImplicitCalls;
     Procedure TestProc_ImplicitCalls;
+    Procedure TestProc_Absolute;
     // ToDo: fail builtin functions in constant with non const param
     // ToDo: fail builtin functions in constant with non const param
 
 
     // record
     // record
@@ -5964,6 +5965,19 @@ begin
     end;
     end;
 end;
 end;
 
 
+procedure TTestResolver.TestProc_Absolute;
+begin
+  StartProgram(false);
+  Add([
+  'procedure DoIt(p: Pointer);',
+  'var',
+  '  s: string absolute p;',
+  '  t: array of char absolute s;',
+  'begin',
+  'end;',
+  'begin']);
+end;
+
 procedure TTestResolver.TestRecord;
 procedure TTestResolver.TestRecord;
 begin
 begin
   StartProgram(false);
   StartProgram(false);

+ 17 - 1
packages/fcl-passrc/tests/tcuseanalyzer.pas

@@ -109,6 +109,7 @@ type
     procedure TestM_Hint_FunctionResultDoesNotSeemToBeSet_Abstract;
     procedure TestM_Hint_FunctionResultDoesNotSeemToBeSet_Abstract;
     procedure TestM_Hint_FunctionResultRecord;
     procedure TestM_Hint_FunctionResultRecord;
     procedure TestM_Hint_FunctionResultPassRecordElement;
     procedure TestM_Hint_FunctionResultPassRecordElement;
+    procedure TestM_Hint_AbsoluteVar;
 
 
     // whole program optimization
     // whole program optimization
     procedure TestWP_LocalVar;
     procedure TestWP_LocalVar;
@@ -249,7 +250,6 @@ begin
       end;
       end;
     aMarker:=aMarker^.Next;
     aMarker:=aMarker^.Next;
     end;
     end;
-
 end;
 end;
 
 
 procedure TCustomTestUseAnalyzer.CheckUseAnalyzerHint(MsgType: TMessageType;
 procedure TCustomTestUseAnalyzer.CheckUseAnalyzerHint(MsgType: TMessageType;
@@ -1550,6 +1550,22 @@ begin
   CheckUseAnalyzerUnexpectedHints;
   CheckUseAnalyzerUnexpectedHints;
 end;
 end;
 
 
+procedure TTestUseAnalyzer.TestM_Hint_AbsoluteVar;
+begin
+  StartProgram(false);
+  Add([
+  'procedure {#DoIt_used}DoIt({#p_used}p: pointer);',
+  'var',
+  '  {#i_used}i: longint absolute p;',
+  '  {#j_used}j: longint absolute i;',
+  'begin',
+  '  if j=3 then ;',
+  'end;',
+  'begin',
+  '  DoIt(nil);']);
+  CheckUseAnalyzerUnexpectedHints;
+end;
+
 procedure TTestUseAnalyzer.TestWP_LocalVar;
 procedure TTestUseAnalyzer.TestWP_LocalVar;
 begin
 begin
   StartProgram(false);
   StartProgram(false);

+ 13 - 3
packages/fcl-passrc/tests/tcvarparser.pas

@@ -189,21 +189,31 @@ procedure TTestVarParser.TestSimpleVarAbsolute;
 begin
 begin
   ParseVar('q absolute v','');
   ParseVar('q absolute v','');
   AssertVariableType('q');
   AssertVariableType('q');
-  AssertEquals('correct absolute location','v',TheVar.AbsoluteLocation);
+  AssertExpression('correct absolute location',TheVar.AbsoluteExpr,pekIdent,'v');
 end;
 end;
 
 
 procedure TTestVarParser.TestSimpleVarAbsoluteDot;
 procedure TTestVarParser.TestSimpleVarAbsoluteDot;
+var
+  B: TBinaryExpr;
 begin
 begin
   ParseVar('q absolute v.w','');
   ParseVar('q absolute v.w','');
   AssertVariableType('q');
   AssertVariableType('q');
-  AssertEquals('correct absolute location','v.w',TheVar.AbsoluteLocation);
+  B:=AssertExpression('binary',TheVar.AbsoluteExpr,eopSubIdent);
+  AssertExpression('correct absolute expr v',B.left,pekIdent,'v');
+  AssertExpression('correct absolute expr w',B.right,pekIdent,'w');
 end;
 end;
 
 
 procedure TTestVarParser.TestSimpleVarAbsolute2Dots;
 procedure TTestVarParser.TestSimpleVarAbsolute2Dots;
+var
+  B: TBinaryExpr;
 begin
 begin
   ParseVar('q absolute v.w.x','');
   ParseVar('q absolute v.w.x','');
   AssertVariableType('q');
   AssertVariableType('q');
-  AssertEquals('correct absolute location','v.w.x',TheVar.AbsoluteLocation);
+  B:=AssertExpression('binary',TheVar.AbsoluteExpr,eopSubIdent);
+  AssertExpression('correct absolute expr x',B.right,pekIdent,'x');
+  B:=AssertExpression('binary',B.left,eopSubIdent);
+  AssertExpression('correct absolute expr w',B.right,pekIdent,'w');
+  AssertExpression('correct absolute expr v',B.left,pekIdent,'v');
 end;
 end;
 
 
 procedure TTestVarParser.TestVarProcedure;
 procedure TTestVarParser.TestVarProcedure;