浏览代码

* 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 -

michael 9 年之前
父节点
当前提交
d876d1d1e7
共有 2 个文件被更改,包括 107 次插入65 次删除
  1. 55 38
      packages/pastojs/src/fppas2js.pp
  2. 52 27
      packages/pastojs/tests/tcconverter.pp

+ 55 - 38
packages/pastojs/src/fppas2js.pp

@@ -25,12 +25,14 @@
    - procs, params, local vars
    - procs, params, local vars
    - assign statements
    - assign statements
    - function results
    - function results
+   - for loop
 
 
  ToDos:
  ToDos:
    - many statements started, needs testing
    - many statements started, needs testing
    - rename overloaded procs, append $0, $1, ...
    - rename overloaded procs, append $0, $1, ...
    - records
    - records
    - arrays
    - arrays
+   - access JavaScript from Pascal
    - Optional: put implementation into $impl
    - Optional: put implementation into $impl
    - library
    - library
 
 
@@ -65,6 +67,8 @@ resourcestring
   sInitializedArraysNotSupported = 'Initialized array variables not yet supported';
   sInitializedArraysNotSupported = 'Initialized array variables not yet supported';
   sMemberExprMustBeIdentifier = 'Member expression must be an identifier';
   sMemberExprMustBeIdentifier = 'Member expression must be an identifier';
 
 
+const
+  LoopEndVar = '$loopend';
 
 
 Type
 Type
 
 
@@ -1704,54 +1708,67 @@ end;
 
 
 function TPasToJSConverter.ConvertForStatement(El: TPasImplForLoop;
 function TPasToJSConverter.ConvertForStatement(El: TPasImplForLoop;
   AContext: TConvertContext): TJSElement;
   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
 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;
   ok: Boolean;
+  VarStat: TJSVariableStatement;
 
 
 begin
 begin
   Result:=Nil;
   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;
   ok:=false;
   try
   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
     If El.Down then
-      begin
-      U:=TJSUnaryPostMinusMinusExpression(CreateElement(TJSUnaryPostMinusMinusExpression,El));
-      B:=TJSRelationalExpressionGE(CreateElement(TJSRelationalExpressionGE,El.EndExpr));
-      end
+      BinExp:=TJSRelationalExpressionGE(CreateElement(TJSRelationalExpressionGE,El.EndExpr))
     else
     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;
     ok:=true;
   finally
   finally
     if not ok then
     if not ok then

+ 52 - 27
packages/pastojs/tests/tcconverter.pp

@@ -369,35 +369,47 @@ Var
   F : TPasImplForLoop;
   F : TPasImplForLoop;
   E : TJSForStatement;
   E : TJSForStatement;
   L : TJSStatementList;
   L : TJSStatementList;
-  VS : TJSVariableStatement;
   VD : TJSVarDeclaration;
   VD : TJSVarDeclaration;
   A : TJSSimpleAssignStatement;
   A : TJSSimpleAssignStatement;
   I : TJSUnaryPostPlusPlusExpression;
   I : TJSUnaryPostPlusPlusExpression;
   C : TJSRelationalExpressionLE;
   C : TJSRelationalExpressionLE;
+  VS: TJSVariableStatement;
 
 
 begin
 begin
-  // For I:=0 to 100 do a:=b;
+  // For I:=1 to 100 do a:=b;
   F:=TPasImplForLoop.Create('',Nil);
   F:=TPasImplForLoop.Create('',Nil);
   F.Variable:=TPasVariable.Create('I',F);
   F.Variable:=TPasVariable.Create('I',F);
-  F.VariableName:='I';
+  F.VariableName:=CreateIdent('I');
   F.StartExpr:=CreateLiteral(1);
   F.StartExpr:=CreateLiteral(1);
   F.EndExpr:=CreateLiteral(100);
   F.EndExpr:=CreateLiteral(100);
   F.Body:=CreateAssignStatement();
   F.Body:=CreateAssignStatement();
   L:=TJSStatementList(Convert(F,TJSStatementList));
   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');
   AssertIdentifier('Init statement LHS is loop variable',A.LHS,'i');
+  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 '+LoopEndVar,C.B,LoopEndVar);
+
+  // i++
   I:=TJSUnaryPostPlusPlusExpression(AssertElement('Increment is ++ statement',TJSUnaryPostPlusPlusExpression,E.Incr));
   I:=TJSUnaryPostPlusPlusExpression(AssertElement('Increment is ++ statement',TJSUnaryPostPlusPlusExpression,E.Incr));
   AssertIdentifier('++ on correct variable name',I.A,'i');
   AssertIdentifier('++ on correct variable name',I.A,'i');
+
+  // body
   AssertAssignStatement('Correct body',E.Body);
   AssertAssignStatement('Correct body',E.Body);
-  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');
 end;
 end;
 
 
 Procedure TTestStatementConverter.TestForLoopDown;
 Procedure TTestStatementConverter.TestForLoopDown;
@@ -405,36 +417,49 @@ Var
   F : TPasImplForLoop;
   F : TPasImplForLoop;
   E : TJSForStatement;
   E : TJSForStatement;
   L : TJSStatementList;
   L : TJSStatementList;
-  VS : TJSVariableStatement;
   VD : TJSVarDeclaration;
   VD : TJSVarDeclaration;
   A : TJSSimpleAssignStatement;
   A : TJSSimpleAssignStatement;
   I : TJSUnaryPostMinusMinusExpression;
   I : TJSUnaryPostMinusMinusExpression;
   C : TJSRelationalExpressionGE;
   C : TJSRelationalExpressionGE;
+  VS: TJSVariableStatement;
 
 
 begin
 begin
-  // For I:=0 to 100 do a:=b;
+  // For I:=100 downto 1 do a:=b;
   F:=TPasImplForLoop.Create('',Nil);
   F:=TPasImplForLoop.Create('',Nil);
   F.Variable:=TPasVariable.Create('I',F);
   F.Variable:=TPasVariable.Create('I',F);
-  F.VariableName:='I';
+  F.VariableName:=CreateIdent('I');
   F.StartExpr:=CreateLiteral(100);
   F.StartExpr:=CreateLiteral(100);
   F.EndExpr:=CreateLiteral(1);
   F.EndExpr:=CreateLiteral(1);
   F.LoopType:=ltDown;
   F.LoopType:=ltDown;
   F.Body:=CreateAssignStatement();
   F.Body:=CreateAssignStatement();
   L:=TJSStatementList(Convert(F,TJSStatementList));
   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');
   AssertIdentifier('Init statement LHS is loop variable',A.LHS,'i');
+  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 '+LoopEndVar,C.B,LoopEndVar);
+
+  // i--
   I:=TJSUnaryPostMinusMinusExpression(AssertElement('Increment is -- statement',TJSUnaryPostMinusMinusExpression,E.Incr));
   I:=TJSUnaryPostMinusMinusExpression(AssertElement('Increment is -- statement',TJSUnaryPostMinusMinusExpression,E.Incr));
-  AssertIdentifier('++ on correct variable name',I.A,'i');
+  AssertIdentifier('-- on correct variable name',I.A,'i');
+
+  // body
   AssertAssignStatement('Correct body',E.Body);
   AssertAssignStatement('Correct body',E.Body);
-  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');
 end;
 end;
 
 
 Procedure TTestStatementConverter.TestBeginEndBlockEmpty;
 Procedure TTestStatementConverter.TestBeginEndBlockEmpty;