* Patch from Mattias Gaertner:

New conversion of for loop:

  i=<StartExpr>;
  for(var $loopend=<EndExpr>; i<=$loopend; i++){}

  Because StartExpr and EndExpr must be executed exactly once.

git-svn-id: trunk@34430 -
This commit is contained in:
michael 2016-09-05 05:57:51 +00:00
parent 504e4fb944
commit d876d1d1e7
2 changed files with 109 additions and 67 deletions

View File

@ -25,12 +25,14 @@
- procs, params, local vars
- assign statements
- function results
- for loop
ToDos:
- many statements started, needs testing
- rename overloaded procs, append $0, $1, ...
- records
- arrays
- access JavaScript from Pascal
- Optional: put implementation into $impl
- library
@ -65,6 +67,8 @@ resourcestring
sInitializedArraysNotSupported = 'Initialized array variables not yet supported';
sMemberExprMustBeIdentifier = 'Member expression must be an identifier';
const
LoopEndVar = '$loopend';
Type
@ -1704,54 +1708,67 @@ end;
function TPasToJSConverter.ConvertForStatement(El: TPasImplForLoop;
AContext: TConvertContext): TJSElement;
// Creates the following code:
// LoopVar=<StartExpr>;
// for(var $loopend=<EndExpr>; LoopVar<=$loopend; LoopVar++){}
//
// The StartExpr must be executed exactly once at beginning.
// The EndExpr must be executed exactly once at beginning.
// The $loopend variable is local to the FOR block. It's only used within
// the for header, so the name can be the same in other for loops.
// LoopVar can be a varname or programname.varname
Var
F : TJSForStatement;
L : TJSStatementList;
I : TJSSimpleAssignStatement;
V : TJSVarDeclaration;
VD : TJSVariableStatement;
u : TJSUNaryExpression;
B : TJSBinaryExpression;
MV : String;
ForSt : TJSForStatement;
List : TJSStatementList;
SimpleAss : TJSSimpleAssignStatement;
VarDecl : TJSVarDeclaration;
Incr : TJSUNaryExpression;
BinExp : TJSBinaryExpression;
ok: Boolean;
VarStat: TJSVariableStatement;
begin
Result:=Nil;
B:=Nil;
L:=TJSStatementList(CreateElement(TJSStatementList,El));
Result:=L;
BinExp:=Nil;
// loopvar:=
// for (statementlist...
List:=TJSStatementList(CreateElement(TJSStatementList,El));
Result:=List;
ok:=false;
try
VD:=TJSVariableStatement(CreateElement(TJSVariableStatement,El));
L.A:=VD;
V:=TJSVarDeclaration(CreateElement(TJSVarDeclaration,El));
VD.A:=V;
MV:=TransformVariableName(El.VariableName,AContext)+'$endloopvalue';
V.Name:=MV;
V.Init:=ConvertElement(El.EndExpr,AContext);
F:=TJSForStatement(CreateElement(TJSForStatement,El));
L.B:=F;
I:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El.StartExpr));
F.Init:=I;
I.LHS:=CreateIdentifierExpr(El.VariableName,El);
I.Expr:=ConvertElement(El.StartExpr,AContext);
// add "LoopVar:=<StartExpr>;"
SimpleAss:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El.StartExpr));
SimpleAss.LHS:=ConvertElement(El.VariableName,AContext);
SimpleAss.Expr:=ConvertElement(El.StartExpr,AContext);
List.A:=SimpleAss;
// add "for()"
ForSt:=TJSForStatement(CreateElement(TJSForStatement,El));
List.B:=ForSt;
// add "var $loopend=<EndExpr>"
VarStat:=TJSVariableStatement(CreateElement(TJSVariableStatement,El));
VarDecl:=TJSVarDeclaration(CreateElement(TJSVarDeclaration,El));
VarStat.A:=VarDecl;
VarDecl.Name:=LoopEndVar;
VarDecl.Init:=ConvertElement(El.EndExpr,AContext);
ForSt.Init:=VarStat;
// add "LoopVar<=$loopend"
If El.Down then
begin
U:=TJSUnaryPostMinusMinusExpression(CreateElement(TJSUnaryPostMinusMinusExpression,El));
B:=TJSRelationalExpressionGE(CreateElement(TJSRelationalExpressionGE,El.EndExpr));
end
BinExp:=TJSRelationalExpressionGE(CreateElement(TJSRelationalExpressionGE,El.EndExpr))
else
begin
U:=TJSUnaryPostPlusPlusExpression(CreateElement(TJSUnaryPostPlusPlusExpression,El));
B:=TJSRelationalExpressionLE(CreateElement(TJSRelationalExpressionLE,El.EndExpr));
end;
F.Incr:=U;
F.Cond:=B;
U.A:=CreateIdentifierExpr(El.VariableName,El);
B.A:=CreateIdentifierExpr(El.VariableName,El);
B.B:=CreateIdentifierExpr(MV,El.EndExpr);
F.Body:=ConvertElement(El.Body,AContext);
BinExp:=TJSRelationalExpressionLE(CreateElement(TJSRelationalExpressionLE,El.EndExpr));
BinExp.A:=ConvertElement(El.VariableName,AContext);
BinExp.B:=CreateIdentifierExpr(LoopEndVar,El.EndExpr);
ForSt.Cond:=BinExp;
// add "LoopVar++"
If El.Down then
Incr:=TJSUnaryPostMinusMinusExpression(CreateElement(TJSUnaryPostMinusMinusExpression,El))
else
Incr:=TJSUnaryPostPlusPlusExpression(CreateElement(TJSUnaryPostPlusPlusExpression,El));
Incr.A:=ConvertElement(El.VariableName,AContext);
ForSt.Incr:=Incr;
// add body
ForSt.Body:=ConvertElement(El.Body,AContext);
ok:=true;
finally
if not ok then

View File

@ -369,35 +369,47 @@ Var
F : TPasImplForLoop;
E : TJSForStatement;
L : TJSStatementList;
VS : TJSVariableStatement;
VD : TJSVarDeclaration;
A : TJSSimpleAssignStatement;
I : TJSUnaryPostPlusPlusExpression;
C : TJSRelationalExpressionLE;
VS: TJSVariableStatement;
begin
// For I:=0 to 100 do a:=b;
// For I:=1 to 100 do a:=b;
F:=TPasImplForLoop.Create('',Nil);
F.Variable:=TPasVariable.Create('I',F);
F.VariableName:='I';
F.VariableName:=CreateIdent('I');
F.StartExpr:=CreateLiteral(1);
F.EndExpr:=CreateLiteral(100);
F.Body:=CreateAssignStatement();
L:=TJSStatementList(Convert(F,TJSStatementList));
VS:=TJSVariableStatement(AssertElement('Start with upper limit temp var',TJSVariableStatement,L.A));
VD:=TJSVarDeclaration(AssertElement('Have variable',TJSVarDeclaration,VS.A));
AssertEquals('Correct name for end value','i$endloopvalue',VD.Name);
AssertLiteral('Correct end value',VD.Init,100);
E:=TJSForStatement(AssertElement('Second in list is for statement',TJSForStatement,L.B));
A:=TJSSimpleAssignStatement(AssertElement('Init statement is assign statement',TJSSimpleAssignStatement,E.Init));
AssertLiteral('Init statement RHS is start value',A.Expr,1);
// Should be a list of two statements:
// i:=1;
// for(var $loopend=100; i<=$loopend; i++){ a:=b; }
A:=TJSSimpleAssignStatement(AssertElement('First in list is Init statement',TJSSimpleAssignStatement,L.A));
AssertIdentifier('Init statement LHS is loop variable',A.LHS,'i');
I:=TJSUnaryPostPlusPlusExpression(AssertElement('Increment is ++ statement',TJSUnaryPostPlusPlusExpression,E.Incr));
AssertIdentifier('++ on correct variable name',I.A,'i');
AssertAssignStatement('Correct body',E.Body);
AssertLiteral('Init statement RHS is start value',A.Expr,1);
E:=TJSForStatement(AssertElement('Second in list is "for" statement',TJSForStatement,L.B));
// "var $loopend=100"
VS:=TJSVariableStatement(AssertElement('var '+LoopEndVar,TJSVariableStatement,E.Init));
VD:=TJSVarDeclaration(AssertElement('var '+LoopEndVar,TJSVarDeclaration,VS.A));
AssertEquals('Correct name for '+LoopEndVar,LoopEndVar,VD.Name);
AssertLiteral('Correct end value',VD.Init,100);
// i<=$loopend
C:=TJSRelationalExpressionLE(AssertElement('Condition is <= expression',TJSRelationalExpressionLE,E.Cond));
AssertIdentifier('Cond LHS is loop variable',C.A,'i');
AssertIdentifier('Cond RHS is end loop value variable',C.B,'i$endloopvalue');
AssertIdentifier('Cond RHS is '+LoopEndVar,C.B,LoopEndVar);
// i++
I:=TJSUnaryPostPlusPlusExpression(AssertElement('Increment is ++ statement',TJSUnaryPostPlusPlusExpression,E.Incr));
AssertIdentifier('++ on correct variable name',I.A,'i');
// body
AssertAssignStatement('Correct body',E.Body);
end;
Procedure TTestStatementConverter.TestForLoopDown;
@ -405,36 +417,49 @@ Var
F : TPasImplForLoop;
E : TJSForStatement;
L : TJSStatementList;
VS : TJSVariableStatement;
VD : TJSVarDeclaration;
A : TJSSimpleAssignStatement;
I : TJSUnaryPostMinusMinusExpression;
C : TJSRelationalExpressionGE;
VS: TJSVariableStatement;
begin
// For I:=0 to 100 do a:=b;
// For I:=100 downto 1 do a:=b;
F:=TPasImplForLoop.Create('',Nil);
F.Variable:=TPasVariable.Create('I',F);
F.VariableName:='I';
F.VariableName:=CreateIdent('I');
F.StartExpr:=CreateLiteral(100);
F.EndExpr:=CreateLiteral(1);
F.LoopType:=ltDown;
F.Body:=CreateAssignStatement();
L:=TJSStatementList(Convert(F,TJSStatementList));
VS:=TJSVariableStatement(AssertElement('Start with upper limit temp var',TJSVariableStatement,L.A));
VD:=TJSVarDeclaration(AssertElement('Have variable',TJSVarDeclaration,VS.A));
AssertEquals('Correct name for end value','i$endloopvalue',VD.Name);
AssertLiteral('Correct end value',VD.Init,1);
E:=TJSForStatement(AssertElement('Second in list is for statement',TJSForStatement,L.B));
A:=TJSSimpleAssignStatement(AssertElement('Init statement is assign statement',TJSSimpleAssignStatement,E.Init));
AssertLiteral('Init statement RHS is start value',A.Expr,100);
// Should be a list of two statements:
// i:=100;
// for(var $loopend=1; i>=$loopend; i--){ a:=b; }
A:=TJSSimpleAssignStatement(AssertElement('First in list is Init statement',TJSSimpleAssignStatement,L.A));
AssertIdentifier('Init statement LHS is loop variable',A.LHS,'i');
I:=TJSUnaryPostMinusMinusExpression(AssertElement('Increment is -- statement',TJSUnaryPostMinusMinusExpression,E.Incr));
AssertIdentifier('++ on correct variable name',I.A,'i');
AssertAssignStatement('Correct body',E.Body);
C:=TJSRelationalExpressionGE(AssertElement('Condition is <= expression',TJSRelationalExpressionGE,E.Cond));
AssertLiteral('Init statement RHS is start value',A.Expr,100);
E:=TJSForStatement(AssertElement('Second in list is "for" statement',TJSForStatement,L.B));
// "var $loopend=1"
VS:=TJSVariableStatement(AssertElement('var '+LoopEndVar,TJSVariableStatement,E.Init));
VD:=TJSVarDeclaration(AssertElement('var '+LoopEndVar,TJSVarDeclaration,VS.A));
AssertEquals('Correct name for '+LoopEndVar,LoopEndVar,VD.Name);
AssertLiteral('Correct end value',VD.Init,1);
// i>=$loopend
C:=TJSRelationalExpressionGE(AssertElement('Condition is >= expression',TJSRelationalExpressionGE,E.Cond));
AssertIdentifier('Cond LHS is loop variable',C.A,'i');
AssertIdentifier('Cond RHS is end loop value variable',C.B,'i$endloopvalue');
AssertIdentifier('Cond RHS is '+LoopEndVar,C.B,LoopEndVar);
// i--
I:=TJSUnaryPostMinusMinusExpression(AssertElement('Increment is -- statement',TJSUnaryPostMinusMinusExpression,E.Incr));
AssertIdentifier('-- on correct variable name',I.A,'i');
// body
AssertAssignStatement('Correct body',E.Body);
end;
Procedure TTestStatementConverter.TestBeginEndBlockEmpty;