Browse Source

fcl-passrc: $Writeableconst

git-svn-id: trunk@38872 -
Mattias Gaertner 7 years ago
parent
commit
7db9ac914f

+ 2 - 0
packages/fcl-passrc/src/pasresolveeval.pas

@@ -169,6 +169,7 @@ const
   nTypeXIsNotYetCompletelyDefined = 3107;
   nTypeXIsNotYetCompletelyDefined = 3107;
   nDuplicateCaseValueXatY = 3108;
   nDuplicateCaseValueXatY = 3108;
   nMissingFieldsX = 3109;
   nMissingFieldsX = 3109;
+  nCantAssignValuesToConstVariable = 3110;
 
 
 // resourcestring patterns of messages
 // resourcestring patterns of messages
 resourcestring
 resourcestring
@@ -270,6 +271,7 @@ resourcestring
   sTypeXIsNotYetCompletelyDefined = 'type "%s" is not yet completely defined';
   sTypeXIsNotYetCompletelyDefined = 'type "%s" is not yet completely defined';
   sDuplicateCaseValueXatY = 'Duplicate case value "%s", other at %s';
   sDuplicateCaseValueXatY = 'Duplicate case value "%s", other at %s';
   sMissingFieldsX = 'Missing fields: "%s"';
   sMissingFieldsX = 'Missing fields: "%s"';
+  sCantAssignValuesToConstVariable = 'Can''t assign values to const variable';
 
 
 type
 type
   { TResolveData - base class for data stored in TPasElement.CustomData }
   { TResolveData - base class for data stored in TPasElement.CustomData }

+ 16 - 6
packages/fcl-passrc/src/pasresolver.pp

@@ -148,6 +148,7 @@ Works:
   - TypedPointer:=@Some
   - TypedPointer:=@Some
   - pointer[index], (@i)[index]
   - pointer[index], (@i)[index]
   - dispose(pointerofrecord), new(pointerofrecord)
   - dispose(pointerofrecord), new(pointerofrecord)
+  - $PointerMath on|off
 - emit hints
 - emit hints
   - platform, deprecated, experimental, library, unimplemented
   - platform, deprecated, experimental, library, unimplemented
   - hiding ancestor method
   - hiding ancestor method
@@ -201,13 +202,12 @@ Works:
   - eval +, -, *, /, ^^
   - eval +, -, *, /, ^^
   - float*currency and currency*float computes to currency
   - float*currency and currency*float computes to currency
 - type alias type overloads
 - type alias type overloads
+- $writeableconst off $J-
 
 
 ToDo:
 ToDo:
 - $pop, $push
 - $pop, $push
-- $writableconst off $J-
 - $RTTI inherited|explicit
 - $RTTI inherited|explicit
 - range checking:
 - range checking:
-  - indexedprop[param]
   - defaultvalue
   - defaultvalue
 - fail to write a loop var inside the loop
 - fail to write a loop var inside the loop
 - nested classes
 - nested classes
@@ -14995,6 +14995,8 @@ begin
   {$ENDIF}
   {$ENDIF}
   if ResolvedEl.IdentEl is TPasProperty then
   if ResolvedEl.IdentEl is TPasProperty then
     RaiseMsg(20170216152427,nPropertyNotWritable,sPropertyNotWritable,[],ErrorEl)
     RaiseMsg(20170216152427,nPropertyNotWritable,sPropertyNotWritable,[],ErrorEl)
+  else if ResolvedEl.IdentEl is TPasConst then
+    RaiseMsg(20180430012042,nCantAssignValuesToConstVariable,sCantAssignValuesToConstVariable,[],ErrorEl)
   else
   else
     RaiseMsg(20170216152429,nVariableIdentifierExpected,sVariableIdentifierExpected,[],ErrorEl);
     RaiseMsg(20170216152429,nVariableIdentifierExpected,sVariableIdentifierExpected,[],ErrorEl);
 end;
 end;
@@ -16485,7 +16487,12 @@ begin
       writeln('TPasResolver.CheckParamCompatibility NeedWritable: ',GetResolverResultDbg(ExprResolved));
       writeln('TPasResolver.CheckParamCompatibility NeedWritable: ',GetResolverResultDbg(ExprResolved));
       {$ENDIF}
       {$ENDIF}
       if RaiseOnError then
       if RaiseOnError then
-        RaiseMsg(20170216152450,nVariableIdentifierExpected,sVariableIdentifierExpected,[],Expr);
+        begin
+        if ExprResolved.IdentEl is TPasConst then
+          RaiseMsg(20180430012609,nCantAssignValuesToConstVariable,sCantAssignValuesToConstVariable,[],Expr)
+        else
+          RaiseMsg(20180430012457,nVariableIdentifierExpected,sVariableIdentifierExpected,[],Expr);
+        end;
       exit;
       exit;
       end;
       end;
     if (ParamResolved.BaseType=ExprResolved.BaseType) then
     if (ParamResolved.BaseType=ExprResolved.BaseType) then
@@ -17871,12 +17878,15 @@ begin
     // e.g. 'var a:b' -> compute b, use a as IdentEl
     // e.g. 'var a:b' -> compute b, use a as IdentEl
     if TPasConst(El).VarType<>nil then
     if TPasConst(El).VarType<>nil then
       begin
       begin
-      // typed const -> just like a var
-      if rcConstant in Flags then
+      // typed const
+      if (not TPasConst(El).IsConst) and ([rcConstant,rcType]*Flags<>[]) then
         RaiseConstantExprExp(20170216152739,StartEl);
         RaiseConstantExprExp(20170216152739,StartEl);
       ComputeElement(TPasConst(El).VarType,ResolvedEl,Flags+[rcType],StartEl);
       ComputeElement(TPasConst(El).VarType,ResolvedEl,Flags+[rcType],StartEl);
       ResolvedEl.IdentEl:=El;
       ResolvedEl.IdentEl:=El;
-      ResolvedEl.Flags:=[rrfReadable,rrfWritable];
+      if TPasConst(El).IsConst then
+        ResolvedEl.Flags:=[rrfReadable]
+      else
+        ResolvedEl.Flags:=[rrfReadable,rrfWritable];
       end
       end
     else
     else
       begin
       begin

+ 2 - 0
packages/fcl-passrc/src/pparser.pp

@@ -3649,6 +3649,8 @@ begin
     NextToken;
     NextToken;
     if CurToken = tkColon then
     if CurToken = tkColon then
       begin
       begin
+      if not (bsWriteableConst in Scanner.CurrentBoolSwitches) then
+        Result.IsConst:=true;
       OldForceCaret:=Scanner.SetForceCaret(True);
       OldForceCaret:=Scanner.SetForceCaret(True);
       try
       try
         Result.VarType := ParseType(Result,CurSourcePos);
         Result.VarType := ParseType(Result,CurSourcePos);

+ 17 - 5
packages/fcl-passrc/src/pscanner.pp

@@ -337,11 +337,11 @@ const
     );
     );
 
 
   bsAll = [low(TBoolSwitch)..high(TBoolSwitch)];
   bsAll = [low(TBoolSwitch)..high(TBoolSwitch)];
-  bsFPCMode: TBoolSwitches = [bsPointerMath];
-  bsObjFPCMode: TBoolSwitches = [bsPointerMath];
-  bsDelphiMode: TBoolSwitches = [];
-  bsDelphiUnicodeMode: TBoolSwitches = [];
-  bsMacPasMode: TBoolSwitches = [bsPointerMath];
+  bsFPCMode: TBoolSwitches = [bsPointerMath,bsWriteableConst];
+  bsObjFPCMode: TBoolSwitches = [bsPointerMath,bsWriteableConst];
+  bsDelphiMode: TBoolSwitches = [bsWriteableConst];
+  bsDelphiUnicodeMode: TBoolSwitches = [bsWriteableConst];
+  bsMacPasMode: TBoolSwitches = [bsPointerMath,bsWriteableConst];
 
 
 type
 type
   TValueSwitch = (
   TValueSwitch = (
@@ -3150,6 +3150,8 @@ begin
           Result:=HandleInclude(Param);
           Result:=HandleInclude(Param);
         'INTERFACES':
         'INTERFACES':
           HandleInterfaces(Param);
           HandleInterfaces(Param);
+        'LONGSTRINGS':
+          DoBoolDirective(bsLongStrings);
         'MACRO':
         'MACRO':
           DoBoolDirective(bsMacro);
           DoBoolDirective(bsMacro);
         'MESSAGE':
         'MESSAGE':
@@ -3162,8 +3164,16 @@ begin
           DoLog(mtNote,nUserDefined,SUserDefined,[Param]);
           DoLog(mtNote,nUserDefined,SUserDefined,[Param]);
         'NOTES':
         'NOTES':
           DoBoolDirective(bsNotes);
           DoBoolDirective(bsNotes);
+        'OBJECTCHECKS':
+          DoBoolDirective(bsObjectChecks);
+        'POINTERMATH':
+          DoBoolDirective(bsPointerMath);
+        'RANGECHECKS':
+          DoBoolDirective(bsRangeChecks);
         'SCOPEDENUMS':
         'SCOPEDENUMS':
           DoBoolDirective(bsScopedEnums);
           DoBoolDirective(bsScopedEnums);
+        'TYPEDADDRESS':
+          DoBoolDirective(bsTypedAddress);
         'TYPEINFO':
         'TYPEINFO':
           DoBoolDirective(bsTypeInfo);
           DoBoolDirective(bsTypeInfo);
         'UNDEF':
         'UNDEF':
@@ -3172,6 +3182,8 @@ begin
           DoLog(mtWarning,nUserDefined,SUserDefined,[Param]);
           DoLog(mtWarning,nUserDefined,SUserDefined,[Param]);
         'WARNINGS':
         'WARNINGS':
           DoBoolDirective(bsWarnings);
           DoBoolDirective(bsWarnings);
+        'WRITEABLECONST':
+          DoBoolDirective(bsWriteableConst);
       else
       else
         Handled:=false;
         Handled:=false;
       end;
       end;

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

@@ -207,6 +207,9 @@ type
     Procedure TestConstFloatOperators;
     Procedure TestConstFloatOperators;
     Procedure TestFloatTypeCast;
     Procedure TestFloatTypeCast;
     Procedure TestCurrency;
     Procedure TestCurrency;
+    Procedure TestWritableConst;
+    Procedure TestWritableConst_AssignFail;
+    Procedure TestWritableConst_PassVarFail;
 
 
     // boolean
     // boolean
     Procedure TestBoolTypeCast;
     Procedure TestBoolTypeCast;
@@ -2646,6 +2649,42 @@ begin
   CheckResolverUnexpectedHints;
   CheckResolverUnexpectedHints;
 end;
 end;
 
 
+procedure TTestResolver.TestWritableConst;
+begin
+  StartProgram(false);
+  Add([
+  '{$writeableconst off}',
+  'const i: longint = 3;',
+  'begin',
+  '']);
+  ParseProgram;
+end;
+
+procedure TTestResolver.TestWritableConst_AssignFail;
+begin
+  StartProgram(false);
+  Add([
+  '{$writeableconst off}',
+  'const i: longint = 3;',
+  'begin',
+  '  i:=4;',
+  '']);
+  CheckResolverException(sCantAssignValuesToConstVariable,nCantAssignValuesToConstVariable);
+end;
+
+procedure TTestResolver.TestWritableConst_PassVarFail;
+begin
+  StartProgram(false);
+  Add([
+  '{$writeableconst off}',
+  'const i: longint = 3;',
+  'procedure DoIt(var j: longint); external;',
+  'begin',
+  '  DoIt(i);',
+  '']);
+  CheckResolverException(sCantAssignValuesToConstVariable,nCantAssignValuesToConstVariable);
+end;
+
 procedure TTestResolver.TestBoolTypeCast;
 procedure TTestResolver.TestBoolTypeCast;
 begin
 begin
   StartProgram(false);
   StartProgram(false);

+ 5 - 3
packages/pastojs/src/fppas2js.pp

@@ -343,7 +343,7 @@ Works:
 
 
 ToDos:
 ToDos:
 - option typecast checking -Ct
 - option typecast checking -Ct
-- writable const
+- $writableconst
 - 'new', 'Function' -> class var use .prototype
 - 'new', 'Function' -> class var use .prototype
 - btArrayLit
 - btArrayLit
   a: array of jsvalue;
   a: array of jsvalue;
@@ -391,13 +391,14 @@ Not in Version 1.0:
   - set operators on literals without temporary arrays, a in [b], [a]*b<>[]
   - set operators on literals without temporary arrays, a in [b], [a]*b<>[]
   - nested procs without var, instead as "function name(){}"
   - nested procs without var, instead as "function name(){}"
   - combine multiple var a=0,b=0
   - combine multiple var a=0,b=0
+  - skip clone record for new record
+  - SetLength(scope.a,l) -> read scope only once, same for
+    Include, Exclude, Inc, Dec, +=, -=, *=, /=
   -O1 insert local/unit vars for global type references:
   -O1 insert local/unit vars for global type references:
       at start of intf var $r1;
       at start of intf var $r1;
       at end of impl: $r1=path;
       at end of impl: $r1=path;
   -O1 insert unit vars for complex literals
   -O1 insert unit vars for complex literals
   -O1 no function Result var when assigned only once
   -O1 no function Result var when assigned only once
-  - SetLength(scope.a,l) -> read scope only once, same for
-    Include, Exclude, Inc, Dec, +=, -=, *=, /=
   -O1 replace constant expression with result
   -O1 replace constant expression with result
   -O1 pass array element by ref: when index is constant, use that directly
   -O1 pass array element by ref: when index is constant, use that directly
 - objects
 - objects
@@ -1031,6 +1032,7 @@ const
   msAllPas2jsBoolSwitches = [
   msAllPas2jsBoolSwitches = [
     bsAssertions,
     bsAssertions,
     bsRangeChecks,
     bsRangeChecks,
+    bsWriteableConst,
     bsTypeInfo,
     bsTypeInfo,
     bsOverflowChecks,
     bsOverflowChecks,
     bsHints,
     bsHints,

+ 1 - 1
packages/pastojs/src/pas2jscompiler.pp

@@ -767,7 +767,7 @@ function TPas2jsCompilerFile.GetInitialBoolSwitches: TBoolSwitches;
 var
 var
   bs: TBoolSwitches;
   bs: TBoolSwitches;
 begin
 begin
-  bs:=[];
+  bs:=[bsWriteableConst];
   if coOverflowChecks in Compiler.Options then
   if coOverflowChecks in Compiler.Options then
     Include(bs,bsOverflowChecks);
     Include(bs,bsOverflowChecks);
   if coRangeChecks in Compiler.Options then
   if coRangeChecks in Compiler.Options then

+ 1 - 1
packages/pastojs/tests/tcmodules.pas

@@ -1038,7 +1038,7 @@ begin
   aScanner.CurrentModeSwitches:=OBJFPCModeSwitches*msAllPas2jsModeSwitches+msAllPas2jsModeSwitchesReadOnly;
   aScanner.CurrentModeSwitches:=OBJFPCModeSwitches*msAllPas2jsModeSwitches+msAllPas2jsModeSwitchesReadOnly;
 
 
   aScanner.AllowedBoolSwitches:=msAllPas2jsBoolSwitches;
   aScanner.AllowedBoolSwitches:=msAllPas2jsBoolSwitches;
-  aScanner.CurrentBoolSwitches:=[bsHints,bsNotes,bsWarnings];
+  aScanner.CurrentBoolSwitches:=[bsHints,bsNotes,bsWarnings,bsWriteableConst];
 end;
 end;
 
 
 procedure TCustomTestModule.TearDown;
 procedure TCustomTestModule.TearDown;