* Patch from Mattias Gaertner, implementing

*  with..do
  * is and as operator for class
  * inherited call
  * basic type checks for binary operators
  * type checks for if..then, while..do, repeat..until, on..do, raise

git-svn-id: trunk@34569 -
This commit is contained in:
michael 2016-09-27 19:15:27 +00:00
parent 7f3ac8bf51
commit ea421c6874
9 changed files with 2585 additions and 886 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -73,6 +73,7 @@ const
nParserDuplicateIdentifier = 2046; nParserDuplicateIdentifier = 2046;
nParserDefaultParameterRequiredFor = 2047; nParserDefaultParameterRequiredFor = 2047;
nParserOnlyOneVariableCanBeInitialized = 2048; nParserOnlyOneVariableCanBeInitialized = 2048;
nParserExpectedTypeButGot = 2049;
// resourcestring patterns of messages // resourcestring patterns of messages
@ -125,6 +126,7 @@ resourcestring
SParserDuplicateIdentifier = 'Duplicate identifier "%s"'; SParserDuplicateIdentifier = 'Duplicate identifier "%s"';
SParserDefaultParameterRequiredFor = 'Default parameter required for "%s"'; SParserDefaultParameterRequiredFor = 'Default parameter required for "%s"';
SParserOnlyOneVariableCanBeInitialized = 'Only one variable can be initialized'; SParserOnlyOneVariableCanBeInitialized = 'Only one variable can be initialized';
SParserExpectedTypeButGot = 'Expected type, but got %s';
type type
TPasScopeType = ( TPasScopeType = (
@ -1088,7 +1090,21 @@ begin
Ref:=Nil; Ref:=Nil;
SS:=(not (po_resolvestandardtypes in FOptions)) and isSimpleTypeToken(Name); SS:=(not (po_resolvestandardtypes in FOptions)) and isSimpleTypeToken(Name);
if not SS then if not SS then
begin
Ref:=Engine.FindElement(Name); Ref:=Engine.FindElement(Name);
if Ref=nil then
begin
{$IFDEF VerbosePasResolver}
if po_resolvestandardtypes in FOptions then
begin
writeln('ERROR: TPasParser.ParseSimpleType resolver failed to raise an error');
ParseExcExpectedIdentifier;
end;
{$ENDIF}
end
else if not (Ref is TPasType) then
ParseExc(nParserExpectedTypeButGot,SParserExpectedTypeButGot,[Ref.ElementTypeName]);
end;
if (Ref=Nil) then if (Ref=Nil) then
Ref:=TPasUnresolvedTypeRef(CreateElement(TPasUnresolvedTypeRef,Name,Parent)) Ref:=TPasUnresolvedTypeRef(CreateElement(TPasUnresolvedTypeRef,Name,Parent))
else else
@ -2341,7 +2357,8 @@ begin
if Assigned(TypeEl) then // !!! if Assigned(TypeEl) then // !!!
begin begin
Declarations.Declarations.Add(TypeEl); Declarations.Declarations.Add(TypeEl);
if TypeEl.ClassType = TPasClassType then if (TypeEl.ClassType = TPasClassType)
and (not (po_keepclassforward in Options)) then
begin begin
// Remove previous forward declarations, if necessary // Remove previous forward declarations, if necessary
for i := 0 to Declarations.Classes.Count - 1 do for i := 0 to Declarations.Classes.Count - 1 do
@ -2407,7 +2424,7 @@ begin
begin begin
PropEl:=ParseProperty(Declarations,CurtokenString,visDefault); PropEl:=ParseProperty(Declarations,CurtokenString,visDefault);
Declarations.Declarations.Add(PropEl); Declarations.Declarations.Add(PropEl);
Declarations.properties.add(PropEl); Declarations.properties.Add(PropEl);
end; end;
else else
ParseExcSyntaxError; ParseExcSyntaxError;
@ -3666,6 +3683,9 @@ var
ak : TAssignKind; ak : TAssignKind;
lt : TLoopType; lt : TLoopType;
ok: Boolean; ok: Boolean;
SrcPos: TPasSourcePos;
Name: String;
TypeEl: TPasType;
begin begin
NewImplElement:=nil; NewImplElement:=nil;
@ -3819,10 +3839,11 @@ begin
begin begin
// with Expr do // with Expr do
// with Expr, Expr do // with Expr, Expr do
SrcPos:=Scanner.CurSourcePos;
NextToken; NextToken;
Left:=DoParseExpression(Parent); Left:=DoParseExpression(Parent);
//writeln(i,'WITH Expr="',Expr,'" Token=',CurTokenText); //writeln(i,'WITH Expr="',Expr,'" Token=',CurTokenText);
El:=TPasImplWithDo(CreateElement(TPasImplWithDo,'',CurBlock)); El:=TPasImplWithDo(CreateElement(TPasImplWithDo,'',CurBlock,SrcPos));
TPasImplWithDo(El).AddExpression(Left); TPasImplWithDo(El).AddExpression(Left);
CreateBlock(TPasImplWithDo(El)); CreateBlock(TPasImplWithDo(El));
repeat repeat
@ -3955,23 +3976,28 @@ begin
// on Exception do // on Exception do
if CurBlock is TPasImplTryExcept then if CurBlock is TPasImplTryExcept then
begin begin
ExpectIdentifier;
El:=TPasImplExceptOn(CreateElement(TPasImplExceptOn,'',CurBlock));
SrcPos:=Scanner.CurSourcePos;
Name:=CurTokenString;
NextToken; NextToken;
Left:=Nil; //writeln('ON t=',Name,' Token=',CurTokenText);
Right:=DoParseExpression(Parent);
//writeln(i,'ON t=',TypeName,' Token=',CurTokenText);
// NextToken;
if CurToken=tkColon then if CurToken=tkColon then
begin begin
// the first expression was the variable name
NextToken; NextToken;
Left:=Right; TypeEl:=ParseSimpleType(El,SrcPos,'');
Right:=DoParseExpression(Parent); TPasImplExceptOn(El).TypeEl:=TypeEl;
//writeln(i,'ON v=',VarName,' t=',TypeName,' Token=',CurTokenText); TPasImplExceptOn(El).VarEl:=TPasVariable(CreateElement(TPasVariable,
Name,El,SrcPos));
TPasImplExceptOn(El).VarEl.VarType:=TypeEl;
TypeEl.AddRef;
end
else
begin
UngetToken;
TPasImplExceptOn(El).TypeEl:=ParseSimpleType(El,SrcPos,'');
end; end;
// else
UngetToken;
El:=TPasImplExceptOn(CreateElement(TPasImplExceptOn,'',CurBlock));
TPasImplExceptOn(El).VarExpr:=Left;
TPasImplExceptOn(El).TypeExpr:=Right;
Engine.FinishScope(stExceptOnExpr,El); Engine.FinishScope(stExceptOnExpr,El);
CurBlock.AddElement(El); CurBlock.AddElement(El);
CurBlock:=TPasImplExceptOn(El); CurBlock:=TPasImplExceptOn(El);

View File

@ -330,7 +330,8 @@ type
po_cassignments, // allow C-operators += -= *= /= po_cassignments, // allow C-operators += -= *= /=
po_resolvestandardtypes, // search for 'longint', 'string', etc., do not use dummies, TPasResolver sets this to use its declarations po_resolvestandardtypes, // search for 'longint', 'string', etc., do not use dummies, TPasResolver sets this to use its declarations
po_asmwhole, // store whole text between asm..end in TPasImplAsmStatement.Tokens po_asmwhole, // store whole text between asm..end in TPasImplAsmStatement.Tokens
po_nooverloadedprocs // do not create TPasOverloadedProc for procs with same name po_nooverloadedprocs, // do not create TPasOverloadedProc for procs with same name
po_keepclassforward // default: delete class fowards when there is a class declaration
); );
TPOptions = set of TPOption; TPOptions = set of TPOption;
@ -849,7 +850,8 @@ Procedure TStreamLineReader.InitFromStream(AStream : TStream);
begin begin
SetLength(FContent,AStream.Size); SetLength(FContent,AStream.Size);
AStream.Read(FContent[1],AStream.Size); if FContent<>'' then
AStream.Read(FContent[1],length(FContent));
FPos:=0; FPos:=0;
end; end;

View File

@ -599,6 +599,8 @@ end;
procedure TTestParser.StartParsing; procedure TTestParser.StartParsing;
var
i: Integer;
begin begin
If FIsUnit then If FIsUnit then
StartImplementation; StartImplementation;
@ -608,7 +610,8 @@ begin
FResolver.AddStream(FFileName,TStringStream.Create(FSource.Text)); FResolver.AddStream(FFileName,TStringStream.Create(FSource.Text));
FScanner.OpenFile(FFileName); FScanner.OpenFile(FFileName);
Writeln('// Test : ',Self.TestName); Writeln('// Test : ',Self.TestName);
Writeln(FSource.Text); for i:=0 to FSource.Count-1 do
Writeln(Format('%:4d: ',[i+1]),FSource[i]);
end; end;
procedure TTestParser.ParseDeclarations; procedure TTestParser.ParseDeclarations;

View File

@ -763,28 +763,28 @@ procedure TTestClassType.TestConstructor;
begin begin
AddMember('Constructor Create'); AddMember('Constructor Create');
ParseClass; ParseClass;
AssertEquals('1 members',1,TheClass.members.Count); AssertEquals('1 members',1,TheClass.Members.Count);
AssertEquals('1 class procedure',TPasConstructor,members[0].ClassType); AssertEquals('1 class procedure',TPasConstructor,Members[0].ClassType);
AssertEquals('Default visibility',visDefault,Members[0].Visibility); AssertEquals('Default visibility',visDefault,Members[0].Visibility);
AssertMemberName('Create'); AssertMemberName('Create');
AssertEquals('No modifiers',[],TPasClassProcedure(Members[0]).Modifiers); AssertEquals('No modifiers',[],TPasConstructor(Members[0]).Modifiers);
AssertEquals('Default calling convention',ccDefault, TPasClassProcedure(Members[0]).ProcType.CallingConvention); AssertEquals('Default calling convention',ccDefault, TPasConstructor(Members[0]).ProcType.CallingConvention);
AssertNotNull('Method proc type',TPasClassProcedure(Members[0]).ProcType); AssertNotNull('Method proc type',TPasConstructor(Members[0]).ProcType);
AssertEquals('No arguments',0,TPasClassProcedure(Members[0]).ProcType.Args.Count) AssertEquals('No arguments',0,TPasConstructor(Members[0]).ProcType.Args.Count)
end; end;
procedure TTestClassType.TestClassConstructor; procedure TTestClassType.TestClassConstructor;
begin begin
AddMember('Class Constructor Create'); AddMember('Class Constructor Create');
ParseClass; ParseClass;
AssertEquals('1 members',1,TheClass.members.Count); AssertEquals('1 members',1,TheClass.Members.Count);
AssertEquals('1 class procedure',TPasClassConstructor,members[0].ClassType); AssertEquals('1 class procedure',TPasClassConstructor,Members[0].ClassType);
AssertEquals('Default visibility',visDefault,Members[0].Visibility); AssertEquals('Default visibility',visDefault,Members[0].Visibility);
AssertMemberName('Create'); AssertMemberName('Create');
AssertEquals('No modifiers',[],TPasClassProcedure(Members[0]).Modifiers); AssertEquals('No modifiers',[],TPasClassConstructor(Members[0]).Modifiers);
AssertEquals('Default calling convention',ccDefault, TPasClassProcedure(Members[0]).ProcType.CallingConvention); AssertEquals('Default calling convention',ccDefault, TPasClassConstructor(Members[0]).ProcType.CallingConvention);
AssertNotNull('Method proc type',TPasClassProcedure(Members[0]).ProcType); AssertNotNull('Method proc type',TPasClassConstructor(Members[0]).ProcType);
AssertEquals('No arguments',0,TPasClassProcedure(Members[0]).ProcType.Args.Count) AssertEquals('No arguments',0,TPasClassConstructor(Members[0]).ProcType.Args.Count)
end; end;
procedure TTestClassType.TestDestructor; procedure TTestClassType.TestDestructor;
@ -795,24 +795,24 @@ begin
AssertEquals('1 class procedure',TPasDestructor,members[0].ClassType); AssertEquals('1 class procedure',TPasDestructor,members[0].ClassType);
AssertEquals('Default visibility',visDefault,Members[0].Visibility); AssertEquals('Default visibility',visDefault,Members[0].Visibility);
AssertMemberName('Destroy'); AssertMemberName('Destroy');
AssertEquals('No modifiers',[],TPasClassProcedure(Members[0]).Modifiers); AssertEquals('No modifiers',[],TPasDestructor(Members[0]).Modifiers);
AssertEquals('Default calling convention',ccDefault, TPasClassProcedure(Members[0]).ProcType.CallingConvention); AssertEquals('Default calling convention',ccDefault, TPasDestructor(Members[0]).ProcType.CallingConvention);
AssertNotNull('Method proc type',TPasClassProcedure(Members[0]).ProcType); AssertNotNull('Method proc type',TPasDestructor(Members[0]).ProcType);
AssertEquals('No arguments',0,TPasClassProcedure(Members[0]).ProcType.Args.Count) AssertEquals('No arguments',0,TPasDestructor(Members[0]).ProcType.Args.Count)
end; end;
procedure TTestClassType.TestClassDestructor; procedure TTestClassType.TestClassDestructor;
begin begin
AddMember('Class Destructor Destroy'); AddMember('Class Destructor Destroy');
ParseClass; ParseClass;
AssertEquals('1 members',1,TheClass.members.Count); AssertEquals('1 members',1,TheClass.Members.Count);
AssertEquals('1 class procedure',TPasClassDestructor,members[0].ClassType); AssertEquals('1 class procedure',TPasClassDestructor,Members[0].ClassType);
AssertEquals('Default visibility',visDefault,Members[0].Visibility); AssertEquals('Default visibility',visDefault,Members[0].Visibility);
AssertMemberName('Destroy'); AssertMemberName('Destroy');
AssertEquals('No modifiers',[],TPasClassProcedure(Members[0]).Modifiers); AssertEquals('No modifiers',[],TPasClassDestructor(Members[0]).Modifiers);
AssertEquals('Default calling convention',ccDefault, TPasClassProcedure(Members[0]).ProcType.CallingConvention); AssertEquals('Default calling convention',ccDefault, TPasClassDestructor(Members[0]).ProcType.CallingConvention);
AssertNotNull('Method proc type',TPasClassProcedure(Members[0]).ProcType); AssertNotNull('Method proc type',TPasClassDestructor(Members[0]).ProcType);
AssertEquals('No arguments',0,TPasClassProcedure(Members[0]).ProcType.Args.Count) AssertEquals('No arguments',0,TPasClassDestructor(Members[0]).ProcType.Args.Count)
end; end;
procedure TTestClassType.TestFunctionMethodSimple; procedure TTestClassType.TestFunctionMethodSimple;

File diff suppressed because it is too large Load Diff

View File

@ -1326,8 +1326,8 @@ begin
O:=TPasImplExceptOn(E.Elements[0]); O:=TPasImplExceptOn(E.Elements[0]);
AssertEquals(1,O.Elements.Count); AssertEquals(1,O.Elements.Count);
AssertEquals('Simple statement',TPasImplSimple,TPasElement(O.Elements[0]).ClassType); AssertEquals('Simple statement',TPasImplSimple,TPasElement(O.Elements[0]).ClassType);
AssertExpression('Exception Variable name',O.VarExpr,pekIdent,'E'); AssertEquals('Exception Variable name','E',O.VariableName);
AssertExpression('Exception Type name',O.TypeExpr,pekIdent,'Exception'); AssertEquals('Exception Type name','Exception',O.TypeName);
S:=TPasImplSimple(O.Elements[0]); S:=TPasImplSimple(O.Elements[0]);
AssertExpression('DoSomethingElse call',S.Expr,pekIdent,'DoSomethingElse'); AssertExpression('DoSomethingElse call',S.Expr,pekIdent,'DoSomethingElse');
// AssertEquals('Variable name', // AssertEquals('Variable name',
@ -1364,8 +1364,8 @@ begin
O:=TPasImplExceptOn(E.Elements[0]); O:=TPasImplExceptOn(E.Elements[0]);
AssertEquals(1,O.Elements.Count); AssertEquals(1,O.Elements.Count);
AssertEquals('Simple statement',TPasImplSimple,TPasElement(O.Elements[0]).ClassType); AssertEquals('Simple statement',TPasImplSimple,TPasElement(O.Elements[0]).ClassType);
AssertExpression('Exception Variable name',O.VarExpr,pekIdent,'E'); AssertEquals('Exception Variable name','E',O.VariableName);
AssertExpression('Exception Type name',O.TypeExpr,pekIdent,'Exception'); AssertEquals('Exception Type name','Exception',O.TypeName);
S:=TPasImplSimple(O.Elements[0]); S:=TPasImplSimple(O.Elements[0]);
AssertExpression('DoSomethingElse call',S.Expr,pekIdent,'DoSomethingElse'); AssertExpression('DoSomethingElse call',S.Expr,pekIdent,'DoSomethingElse');
// Exception handler 2 // Exception handler 2
@ -1373,8 +1373,8 @@ begin
O:=TPasImplExceptOn(E.Elements[1]); O:=TPasImplExceptOn(E.Elements[1]);
AssertEquals(1,O.Elements.Count); AssertEquals(1,O.Elements.Count);
AssertEquals('Simple statement',TPasImplSimple,TPasElement(O.Elements[0]).ClassType); AssertEquals('Simple statement',TPasImplSimple,TPasElement(O.Elements[0]).ClassType);
AssertExpression('Exception Variable name',O.VarExpr,pekIdent,'Y'); AssertEquals('Exception Variable name','Y',O.VariableName);
AssertExpression('Exception Type name',O.TypeExpr,pekIdent,'Exception2'); AssertEquals('Exception Type name','Exception2',O.TypeName);
S:=TPasImplSimple(O.Elements[0]); S:=TPasImplSimple(O.Elements[0]);
AssertExpression('DoSomethingElse call',S.Expr,pekIdent,'DoSomethingElse2'); AssertExpression('DoSomethingElse call',S.Expr,pekIdent,'DoSomethingElse2');
end; end;
@ -1407,8 +1407,8 @@ begin
AssertEquals(1,E.Elements.Count); AssertEquals(1,E.Elements.Count);
AssertEquals('Except on handler',TPasImplExceptOn,TPasElement(E.Elements[0]).ClassType); AssertEquals('Except on handler',TPasImplExceptOn,TPasElement(E.Elements[0]).ClassType);
O:=TPasImplExceptOn(E.Elements[0]); O:=TPasImplExceptOn(E.Elements[0]);
AssertExpression('Exception Variable name',O.VarExpr,pekIdent,'E'); AssertEquals('Exception Variable name','E',O.VariableName);
AssertExpression('Exception Type name',O.TypeExpr,pekIdent,'Exception'); AssertEquals('Exception Type name','Exception',O.TypeName);
AssertEquals(1,O.Elements.Count); AssertEquals(1,O.Elements.Count);
AssertEquals('Simple statement',TPasImplIfElse,TPasElement(O.Elements[0]).ClassType); AssertEquals('Simple statement',TPasImplIfElse,TPasElement(O.Elements[0]).ClassType);
I:=TPasImplIfElse(O.Elements[0]); I:=TPasImplIfElse(O.Elements[0]);
@ -1450,8 +1450,8 @@ begin
AssertEquals(1,E.Elements.Count); AssertEquals(1,E.Elements.Count);
AssertEquals('Except on handler',TPasImplExceptOn,TPasElement(E.Elements[0]).ClassType); AssertEquals('Except on handler',TPasImplExceptOn,TPasElement(E.Elements[0]).ClassType);
O:=TPasImplExceptOn(E.Elements[0]); O:=TPasImplExceptOn(E.Elements[0]);
AssertExpression('Exception Variable name',O.VarExpr,pekIdent,'E'); AssertEquals('Exception Variable name','E',O.VariableName);
AssertExpression('Exception Type name',O.TypeExpr,pekIdent,'Exception'); AssertEquals('Exception Type name','Exception',O.TypeName);
AssertEquals(1,O.Elements.Count); AssertEquals(1,O.Elements.Count);
AssertEquals('Simple statement',TPasImplSimple,TPasElement(O.Elements[0]).ClassType); AssertEquals('Simple statement',TPasImplSimple,TPasElement(O.Elements[0]).ClassType);
S:=TPasImplSimple(O.Elements[0]); S:=TPasImplSimple(O.Elements[0]);

View File

@ -644,7 +644,7 @@ begin
T:=TPasImplTry.Create('',Nil); T:=TPasImplTry.Create('',Nil);
T.AddElement(CreateAssignStatement('a','b')); T.AddElement(CreateAssignStatement('a','b'));
F:=T.AddExcept; F:=T.AddExcept;
O:=F.AddExceptOn(CreateIdent('E'),CreateIdent('Exception')); O:=F.AddExceptOn('E','Exception');
O.Body:=CreateAssignStatement('b','c'); O.Body:=CreateAssignStatement('b','c');
// Convert // Convert
El:=TJSTryFinallyStatement(Convert(T,TJSTryCatchStatement)); El:=TJSTryFinallyStatement(Convert(T,TJSTryCatchStatement));
@ -692,7 +692,7 @@ begin
T:=TPasImplTry.Create('',Nil); T:=TPasImplTry.Create('',Nil);
T.AddElement(CreateAssignStatement('a','b')); T.AddElement(CreateAssignStatement('a','b'));
F:=T.AddExcept; F:=T.AddExcept;
O:=F.AddExceptOn(CreateIdent('E'),CreateIdent('Exception')); O:=F.AddExceptOn('E','Exception');
O.Body:=TPasImplRaise.Create('',Nil); O.Body:=TPasImplRaise.Create('',Nil);
// Convert // Convert
El:=TJSTryFinallyStatement(Convert(T,TJSTryCatchStatement)); El:=TJSTryFinallyStatement(Convert(T,TJSTryCatchStatement));