mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-27 05:32:28 +02:00
* 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:
parent
504e4fb944
commit
d876d1d1e7
@ -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
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user