|
@@ -294,6 +294,7 @@ type
|
|
|
private
|
|
|
const FTokenRingSize = 32;
|
|
|
type
|
|
|
+ TDeclParseType = (dptBasic,dptFull,dptInline);
|
|
|
|
|
|
{ TTokenRec }
|
|
|
|
|
@@ -336,6 +337,7 @@ type
|
|
|
procedure ParseRaise;
|
|
|
procedure ParseWhile;
|
|
|
procedure ParseWith;
|
|
|
+ procedure ParseVarStatement;
|
|
|
end;
|
|
|
//PParseStatementParams = ^TParseStatementParams;
|
|
|
private
|
|
@@ -377,12 +379,12 @@ type
|
|
|
function GetVariableModifiers(Parent: TPasElement;
|
|
|
Out VarMods: TVariableModifiers; Out LibName, ExportName: TPasExpr;
|
|
|
const AllowedMods: TVariableModifiers): string;
|
|
|
- function GetVariableValueAndLocation(Parent : TPasElement; Out Value: TPasExpr; Out AbsoluteExpr: TPasExpr; Out Location: String): Boolean;
|
|
|
+ function GetVariableValueAndLocation(Parent : TPasElement; IsUntypedInline : Boolean; Out Value: TPasExpr; Out AbsoluteExpr: TPasExpr; Out Location: String): Boolean;
|
|
|
procedure HandleProcedureModifier(Parent: TPasElement; pm : TProcedureModifier; IsBracketed : Boolean = false);
|
|
|
procedure HandleProcedureTypeModifier(ProcType: TPasProcedureType; ptm : TProcTypeModifier);
|
|
|
procedure ParseMembersLocalConsts(AType: TPasMembersType; AVisibility: TPasMemberVisibility);
|
|
|
procedure ParseMembersLocalTypes(AType: TPasMembersType; AVisibility: TPasMemberVisibility);
|
|
|
- procedure ParseVarList(Parent: TPasElement; VarList: TFPList; AVisibility: TPasMemberVisibility; Full: Boolean);
|
|
|
+ procedure ParseVarList(Parent: TPasElement; VarList: TFPList; AVisibility: TPasMemberVisibility; varParseType : TDeclParseType);
|
|
|
procedure SetOptions(AValue: TPOptions);
|
|
|
procedure OnScannerModeChanged(Sender: TObject; NewMode: TModeSwitch;
|
|
|
Before: boolean; var Handled: boolean);
|
|
@@ -509,6 +511,7 @@ type
|
|
|
function ParseTypeDecl(Parent: TPasElement): TPasType; overload;
|
|
|
function ParseTypeDecl(Parent: TPasElement; NamePos : TPasSourcePos): TPasType; overload;
|
|
|
function ParseGenericTypeDecl(Parent: TPasElement; AddToParent: boolean): TPasGenericType;
|
|
|
+ function ParseType(Parent: TPasElement; const NamePos: TPasSourcePos; const TypeName: String; DeclParseType: TDeclParseType): TPasType;
|
|
|
function ParseType(Parent: TPasElement; const NamePos: TPasSourcePos; const TypeName: String = ''; Full: Boolean = false): TPasType;
|
|
|
function ParseReferenceToProcedureType(Parent: TPasElement; Const NamePos: TPasSourcePos; Const TypeName: String): TPasProcedureType;
|
|
|
function ParseProcedureType(Parent: TPasElement; Const NamePos: TPasSourcePos; Const TypeName: String; const PT: TProcType): TPasProcedureType;
|
|
@@ -2124,6 +2127,16 @@ function TPasParser.ParseType(Parent: TPasElement;
|
|
|
const NamePos: TPasSourcePos; const TypeName: String; Full: Boolean
|
|
|
): TPasType;
|
|
|
|
|
|
+Const
|
|
|
+ TS : Array[boolean] of TDeclParseType = (dptBasic,dptFull);
|
|
|
+
|
|
|
+begin
|
|
|
+ Result:=ParseType(Parent,NamePos,TypeName,TS[Full]);
|
|
|
+end;
|
|
|
+
|
|
|
+function TPasParser.ParseType(Parent: TPasElement; const NamePos: TPasSourcePos; const TypeName: String;
|
|
|
+ DeclParseType: TDeclParseType): TPasType;
|
|
|
+
|
|
|
Type
|
|
|
TLocalClassType = (lctClass,lctObjcClass,lctObjcCategory,lctHelper);
|
|
|
|
|
@@ -2145,7 +2158,7 @@ begin
|
|
|
Result := nil;
|
|
|
// NextToken and check pack mode
|
|
|
Pm:=CheckPackMode;
|
|
|
- if Full then
|
|
|
+ if DeclParseType=dptFull then
|
|
|
CH:=Not (CurToken in NoHintTokens)
|
|
|
else
|
|
|
begin
|
|
@@ -2178,7 +2191,7 @@ begin
|
|
|
begin
|
|
|
lClassType:=lctClass;
|
|
|
NextToken;
|
|
|
- if not (Full or (CurToken=tkOf)) then
|
|
|
+ if not ((DeclParseType=dptFull) or (CurToken=tkOf)) then
|
|
|
ParseExc(nParserTypeNotAllowedHere,SParserTypeNotAllowedHere,[CurtokenText]);
|
|
|
// Parser.CurrentModeswitches:=Parser.CurrentModeswitches+[msClass];
|
|
|
|
|
@@ -2227,7 +2240,7 @@ begin
|
|
|
Result:=ParseReferencetoProcedureType(Parent,NamePos,TypeName)
|
|
|
end
|
|
|
else
|
|
|
- Result:=ParseSimpleType(Parent,NamePos,TypeName,Full);
|
|
|
+ Result:=ParseSimpleType(Parent,NamePos,TypeName,declParseType=dptFull);
|
|
|
end;
|
|
|
tkCaret: Result:=ParsePointerType(Parent,NamePos,TypeName);
|
|
|
tkFile: Result:=ParseFileType(Parent,NamePos,TypeName);
|
|
@@ -2257,7 +2270,7 @@ begin
|
|
|
tkNumber,tkMinus,tkChar:
|
|
|
begin
|
|
|
UngetToken;
|
|
|
- Result:=ParseRangeType(Parent,NamePos,TypeName,Full);
|
|
|
+ Result:=ParseRangeType(Parent,NamePos,TypeName,declParseType=dptFull);
|
|
|
end;
|
|
|
else
|
|
|
ParseExcExpectedIdentifier;
|
|
@@ -4729,19 +4742,27 @@ begin
|
|
|
end;
|
|
|
end;
|
|
|
|
|
|
-function TPasParser.GetVariableValueAndLocation(Parent: TPasElement; out
|
|
|
- Value: TPasExpr; out AbsoluteExpr: TPasExpr; out Location: String): Boolean;
|
|
|
+
|
|
|
+function TPasParser.GetVariableValueAndLocation(Parent: TPasElement; IsUntypedInline: Boolean; out Value: TPasExpr; out
|
|
|
+ AbsoluteExpr: TPasExpr; out Location: String): Boolean;
|
|
|
|
|
|
begin
|
|
|
Value:=Nil;
|
|
|
AbsoluteExpr:=Nil;
|
|
|
Location:='';
|
|
|
NextToken;
|
|
|
- Result:=CurToken=tkEqual;
|
|
|
+ if IsUntypedInline then
|
|
|
+ Result:=CurToken=tkAssign
|
|
|
+ else
|
|
|
+ Result:=CurToken=tkEqual;
|
|
|
if Result then
|
|
|
begin
|
|
|
NextToken;
|
|
|
- Value := DoParseConstValueExpression(Parent);
|
|
|
+ if IsUntypedInline then
|
|
|
+ Value := DoParseExpression(Parent)
|
|
|
+ else
|
|
|
+ Value := DoParseConstValueExpression(Parent);
|
|
|
+
|
|
|
end;
|
|
|
if (CurToken=tkAbsolute) then
|
|
|
begin
|
|
@@ -4834,8 +4855,8 @@ end;
|
|
|
|
|
|
|
|
|
// Full means that a full variable declaration is being parsed.
|
|
|
-procedure TPasParser.ParseVarList(Parent: TPasElement; VarList: TFPList;
|
|
|
- AVisibility: TPasMemberVisibility; Full : Boolean);
|
|
|
+procedure TPasParser.ParseVarList(Parent: TPasElement; VarList: TFPList; AVisibility: TPasMemberVisibility;
|
|
|
+ varParseType: TDeclParseType);
|
|
|
// on Exception the VarList is restored, no need to Release the new elements
|
|
|
|
|
|
var
|
|
@@ -4847,6 +4868,7 @@ var
|
|
|
VarMods, AllowedVarMods: TVariableModifiers;
|
|
|
D,Mods,AbsoluteLocString: string;
|
|
|
OldForceCaret,ok,ExternalStruct: Boolean;
|
|
|
+ IsUntyped : Boolean;
|
|
|
|
|
|
begin
|
|
|
Value:=Nil;
|
|
@@ -4856,6 +4878,7 @@ begin
|
|
|
AbsoluteLocString:='';
|
|
|
VarCnt:=0;
|
|
|
ok:=false;
|
|
|
+ IsUntyped:=False;
|
|
|
try
|
|
|
D:=SaveComments; // This means we support only one comment per 'list'.
|
|
|
VarEl:=nil;
|
|
@@ -4878,29 +4901,39 @@ begin
|
|
|
case CurToken of
|
|
|
tkColon: break;
|
|
|
tkComma: ExpectIdentifier;
|
|
|
+ tkAssign :
|
|
|
+ begin
|
|
|
+ if varParseType<>dptInline then
|
|
|
+ ParseExc(nParserExpectedCommaColon,SParserExpectedCommaColon);
|
|
|
+ UnGetToken; // Value parsing starts with NextToken
|
|
|
+ IsUnTyped:=True;
|
|
|
+ break;
|
|
|
+ end;
|
|
|
else
|
|
|
ParseExc(nParserExpectedCommaColon,SParserExpectedCommaColon);
|
|
|
end;
|
|
|
Until (CurToken=tkColon);
|
|
|
- OldForceCaret:=Scanner.SetForceCaret(True);
|
|
|
- try
|
|
|
- VarType := ParseVarType(VarEl); // Note: this can insert elements into VarList!
|
|
|
- {$IFDEF CheckPasTreeRefCount}if VarType.RefIds.IndexOf('CreateElement')>=0 then VarType.ChangeRefId('CreateElement','TPasVariable.VarType'){$ENDIF};
|
|
|
- finally
|
|
|
- Scanner.SetForceCaret(OldForceCaret);
|
|
|
- end;
|
|
|
- // read type
|
|
|
- for i := VarList.Count-VarCnt to VarList.Count - 1 do
|
|
|
+ if CurToken=tkColon then
|
|
|
begin
|
|
|
- VarEl:=TPasVariable(VarList[i]);
|
|
|
- // Writeln(VarEl.Name, AVisibility);
|
|
|
- VarEl.VarType := VarType;
|
|
|
- //VarType.Parent := VarEl; // this is wrong for references
|
|
|
+ OldForceCaret:=Scanner.SetForceCaret(True);
|
|
|
+ try
|
|
|
+ VarType := ParseVarType(VarEl); // Note: this can insert elements into VarList!
|
|
|
+ {$IFDEF CheckPasTreeRefCount}if VarType.RefIds.IndexOf('CreateElement')>=0 then VarType.ChangeRefId('CreateElement','TPasVariable.VarType'){$ENDIF};
|
|
|
+ finally
|
|
|
+ Scanner.SetForceCaret(OldForceCaret);
|
|
|
+ end;
|
|
|
+ // read type
|
|
|
+ for i := VarList.Count-VarCnt to VarList.Count - 1 do
|
|
|
+ begin
|
|
|
+ VarEl:=TPasVariable(VarList[i]);
|
|
|
+ // Writeln(VarEl.Name, AVisibility);
|
|
|
+ VarEl.VarType := VarType;
|
|
|
+ //VarType.Parent := VarEl; // this is wrong for references
|
|
|
+ end;
|
|
|
end;
|
|
|
-
|
|
|
H:=CheckHint(Nil,False);
|
|
|
- If Full then
|
|
|
- GetVariableValueAndLocation(VarEl,Value,AbsoluteExpr,AbsoluteLocString);
|
|
|
+ If varParseType in [dptFull,dptInline]then
|
|
|
+ GetVariableValueAndLocation(VarEl,IsUnTyped,Value,AbsoluteExpr,AbsoluteLocString);
|
|
|
if VarCnt>1 then
|
|
|
begin
|
|
|
// multiple variables
|
|
@@ -4917,7 +4950,7 @@ begin
|
|
|
and (Parent is TPasMembersType);
|
|
|
|
|
|
H:=H+CheckHint(Nil,False);
|
|
|
- if Full or ExternalStruct then
|
|
|
+ if (VarParseType=dptFull) or ExternalStruct then
|
|
|
begin
|
|
|
NextToken;
|
|
|
If Curtoken<>tkSemicolon then
|
|
@@ -5058,7 +5091,7 @@ begin
|
|
|
if ClosingBrace then
|
|
|
Include(tt,tkBraceClose);
|
|
|
try
|
|
|
- ParseVarList(Parent,List,AVisibility,False);
|
|
|
+ ParseVarList(Parent,List,AVisibility,dptBasic);
|
|
|
except
|
|
|
on E : Exception do
|
|
|
if not TryErrorRecovery(CreateRecovery(E,tt,False)) then
|
|
@@ -5073,7 +5106,7 @@ procedure TPasParser.ParseVarDecl(Parent: TPasElement; List: TFPList);
|
|
|
|
|
|
begin
|
|
|
try
|
|
|
- ParseVarList(Parent,List,visDefault,True);
|
|
|
+ ParseVarList(Parent,List,visDefault,dptFull);
|
|
|
except
|
|
|
on E : Exception do
|
|
|
if not TryErrorRecovery(CreateRecovery(E,[tkSemicolon],False)) then
|
|
@@ -6387,6 +6420,16 @@ begin
|
|
|
break;
|
|
|
tkEOF:
|
|
|
CheckToken(tkend);
|
|
|
+ tkVar:
|
|
|
+ begin
|
|
|
+ if not (msInlineVars in CurrentModeswitches) then
|
|
|
+ ParseExcSyntaxError;
|
|
|
+ CheckStatementCanStart;
|
|
|
+ NextToken;
|
|
|
+ Params.ParseVarStatement;
|
|
|
+ Params.CloseStatement(true);
|
|
|
+
|
|
|
+ end;
|
|
|
tkAt,tkAtAt,
|
|
|
tkIdentifier,tkspecialize,
|
|
|
tkNumber,tkString,tkfalse,tktrue,tkChar,
|
|
@@ -8114,14 +8157,27 @@ end;
|
|
|
|
|
|
procedure TPasParser.TParseStatementParams.ParseFor;
|
|
|
// for VarName := StartValue to EndValue do
|
|
|
+// for var VarName := StartValue to EndValue do
|
|
|
+// for var VarName : Integer := StartValue to EndValue do
|
|
|
+
|
|
|
// for VarName in Expression do
|
|
|
var
|
|
|
ForLoop: TPasImplForLoop;
|
|
|
Expr: TPasExpr;
|
|
|
lt: TLoopType;
|
|
|
SrcPos: TPasSourcePos;
|
|
|
+ isVarDef : Boolean;
|
|
|
begin
|
|
|
ForLoop:=TPasImplForLoop(CreateElement(TPasImplForLoop));
|
|
|
+ isVarDef:=False;
|
|
|
+ if (msInlineVars in Parser.CurrentModeswitches) then
|
|
|
+ begin
|
|
|
+ Parser.NextToken;
|
|
|
+ isVarDef:=Parser.CurToken=tkvar;
|
|
|
+ if not IsVarDef then
|
|
|
+ Parser.UngetToken;
|
|
|
+ end;
|
|
|
+ SrcPos:=Parser.CurTokenPos;
|
|
|
Parser.ExpectIdentifier;
|
|
|
Expr:=Parser.CreatePrimitiveExpr(ForLoop,pekIdent,Parser.CurTokenString);
|
|
|
ForLoop.VariableName:=Expr;
|
|
@@ -8131,15 +8187,26 @@ begin
|
|
|
tkAssign:
|
|
|
begin
|
|
|
lt:=ltNormal;
|
|
|
+ ForLoop.ImplicitTyped:=IsVarDef and (ForLoop.VarType=Nil);
|
|
|
break;
|
|
|
end;
|
|
|
+ tkColon:
|
|
|
+ begin
|
|
|
+ if not IsVarDef then
|
|
|
+ Parser.ParseExc(nParserExpectedAssignIn,SParserExpectedAssignIn);
|
|
|
+ ForLoop.VarType:=Parser.ParseType(ForLoop,SrcPos);
|
|
|
+ // We should be on identifier
|
|
|
+ end;
|
|
|
tkin:
|
|
|
begin
|
|
|
lt:=ltIn;
|
|
|
+ ForLoop.ImplicitTyped:=IsVarDef and (ForLoop.VarType=Nil);
|
|
|
break;
|
|
|
end;
|
|
|
tkDot:
|
|
|
begin
|
|
|
+ if IsVarDef then
|
|
|
+ Parser.ParseExc(nParserExpectedAssignIn,SParserExpectedAssignIn);
|
|
|
SrcPos:=Parser.CurTokenPos;
|
|
|
Parser.ExpectIdentifier;
|
|
|
Parser.AddToBinaryExprChain(Expr,
|
|
@@ -8276,6 +8343,41 @@ begin
|
|
|
until false;
|
|
|
end;
|
|
|
|
|
|
+procedure TPasParser.TParseStatementParams.ParseVarStatement;
|
|
|
+
|
|
|
+var
|
|
|
+ List : TFPList;
|
|
|
+ VarSt : TPasInlineVarDeclStatement;
|
|
|
+ SrcPos: TPasSourcePos;
|
|
|
+ I : Integer;
|
|
|
+ V : TPasVariable;
|
|
|
+
|
|
|
+begin
|
|
|
+ // var a : Integer;
|
|
|
+ // var a : Integer = Expr;
|
|
|
+ // var a := Expr;
|
|
|
+ SrcPos:=Parser.CurTokenPos;
|
|
|
+ VarSt:=TPasInlineVarDeclStatement(CreateElement(TPasInlineVarDeclStatement,SrcPos));
|
|
|
+ NewImplElement:=VarSt;
|
|
|
+ CurBlock.AddElement(VarSt);
|
|
|
+ List := TFPList.Create;
|
|
|
+ try
|
|
|
+ Parser.ParseVarList(VarSt,List,visDefault,dptInline);
|
|
|
+ For I:=0 to List.Count-1 do
|
|
|
+ begin
|
|
|
+ V:=TPasVariable(List[i]);
|
|
|
+ List[i]:=Nil;
|
|
|
+ VarSt.Declarations.Add(V);
|
|
|
+ end;
|
|
|
+ finally
|
|
|
+ For I:=0 to List.count-1 do
|
|
|
+ if List[i]<>Nil then
|
|
|
+ TObject(List[I]).Free;
|
|
|
+ List.Free;
|
|
|
+ end;
|
|
|
+
|
|
|
+end;
|
|
|
+
|
|
|
function TPasParser.TParseStatementParams.ParseOn: boolean;
|
|
|
// in try except:
|
|
|
// on E: Exception do
|