pastojs: for c in string do

git-svn-id: trunk@37589 -
This commit is contained in:
Mattias Gaertner 2017-11-13 13:37:05 +00:00
parent 429f5346fc
commit a808ae29a8
3 changed files with 347 additions and 112 deletions

View File

@ -55,7 +55,7 @@ Works:
- read and write char aString[] - read and write char aString[]
- allow only String, no ShortString, AnsiString, UnicodeString,... - allow only String, no ShortString, AnsiString, UnicodeString,...
- allow type casting string to external class name 'String' - allow type casting string to external class name 'String'
- for loop - for int/enum do, for char do, for bool do
- repeat..until - repeat..until
- while..do - while..do
- try..finally - try..finally
@ -255,12 +255,11 @@ Works:
- enum, int, char - enum, int, char
- low(), high(), pred(), succ(), ord(), - low(), high(), pred(), succ(), ord(),
- rg(int), int(rg), enum:=rg, - rg(int), int(rg), enum:=rg,
- rg:=rg, rg1:=rg2, rg:=enum, =, <>, in - rg:=rg, rg1:=rg2, rg:=enum, =, <>,
- array[rg], low(array), high(array) - set of int/enum/char range, in
- array[rg], low(array), high(array), length(array)
ToDos: ToDos:
- for bool:=
- "use strict" must be at the beginning of the .js file
- typecast longint(highprecint) -> (value+0) & $ffffffff - typecast longint(highprecint) -> (value+0) & $ffffffff
- static arrays - static arrays
- a[] of record - a[] of record
@ -295,6 +294,7 @@ Not in Version 1.0:
- record const - record const
- enums with custom values - enums with custom values
- library - library
- constref
- option typecast checking - option typecast checking
- option verify method calls -CR - option verify method calls -CR
- option range checking -Cr - option range checking -Cr
@ -317,12 +317,16 @@ Not in Version 1.0:
Include, Exclude, Inc, Dec, +=, -=, *=, /= Include, Exclude, Inc, Dec, +=, -=, *=, /=
-O1 replace constant expression with result -O1 replace constant expression with result
-O1 pass array element by ref: when index is constant, use that directly -O1 pass array element by ref: when index is constant, use that directly
- objects, interfaces, advanced records - objects
- interfaces
- advanced records
- class helpers, type helpers, record helpers, - class helpers, type helpers, record helpers,
- generics - generics
- operator overloading - operator overloading
- inline - inline
- anonymous functions - anonymous functions
- extended RTTI
- attributes
Debugging this unit: -d<x> Debugging this unit: -d<x>
VerbosePas2JS VerbosePas2JS
@ -455,6 +459,7 @@ type
pbivnImplementation, pbivnImplementation,
pbivnLoop, pbivnLoop,
pbivnLoopEnd, pbivnLoopEnd,
pbivnLoopIn,
pbivnModule, pbivnModule,
pbivnModules, pbivnModules,
pbivnPtrClass, pbivnPtrClass,
@ -561,7 +566,8 @@ const
'$e', '$e',
'$impl', '$impl',
'$l', '$l',
'$le', '$end',
'$in',
'$mod', '$mod',
'pas', 'pas',
'$class', '$class',
@ -1229,6 +1235,8 @@ type
Function CreateUsesList(UsesSection: TPasSection; AContext : TConvertContext): TJSArrayLiteral; Function CreateUsesList(UsesSection: TPasSection; AContext : TConvertContext): TJSArrayLiteral;
Procedure AddToStatementList(var First, Last: TJSStatementList; Procedure AddToStatementList(var First, Last: TJSStatementList;
Add: TJSElement; Src: TPasElement); Add: TJSElement; Src: TPasElement);
Procedure AddToVarStatement(VarStat: TJSVariableStatement; Add: TJSElement;
Src: TPasElement);
Function CreateValInit(PasType: TPasType; Expr: TPasExpr; El: TPasElement; Function CreateValInit(PasType: TPasType; Expr: TPasExpr; El: TPasElement;
AContext: TConvertContext): TJSElement; virtual; AContext: TConvertContext): TJSElement; virtual;
Function CreateVarInit(El: TPasVariable; AContext: TConvertContext): TJSElement; virtual; Function CreateVarInit(El: TPasVariable; AContext: TConvertContext): TJSElement; virtual;
@ -3740,6 +3748,7 @@ begin
Src:=FunDecl.AFunction.Body.A as TJSSourceElements; Src:=FunDecl.AFunction.Body.A as TJSSourceElements;
if coUseStrict in Options then if coUseStrict in Options then
// "use strict" must be the first statement in a function
AddToSourceElements(Src,CreateLiteralString(El,'use strict')); AddToSourceElements(Src,CreateLiteralString(El,'use strict'));
ImplVarSt:=nil; ImplVarSt:=nil;
@ -10546,6 +10555,12 @@ function TPasToJSConverter.ConvertForStatement(El: TPasImplForLoop;
// The EndExpr must be executed exactly once at beginning. // The EndExpr must be executed exactly once at beginning.
// If the loop is not executed the Variable is not set, aka keeps its old value. // If the loop is not executed the Variable is not set, aka keeps its old value.
// After the loop the variable has the last value. // After the loop the variable has the last value.
type
TInKind = (
ikNone,
ikChar,
ikString
);
function ConvExpr(Expr: TPasExpr): TJSElement; function ConvExpr(Expr: TPasExpr): TJSElement;
var var
@ -10606,6 +10621,117 @@ function TPasToJSConverter.ConvertForStatement(El: TPasImplForLoop;
ReleaseEvalValue(OrdValue); ReleaseEvalValue(OrdValue);
end; end;
var
ResolvedVar, ResolvedIn: TPasResolverResult;
StartValue, EndValue, InValue: TResEvalValue;
StartInt, EndInt: MaxPrecInt;
HasLoopVar, HasEndVar, HasInVar: Boolean;
InKind: TInKind;
procedure InitWithResolver;
begin
AContext.Resolver.ComputeElement(El.VariableName,ResolvedVar,[rcNoImplicitProc]);
if not (ResolvedVar.IdentEl is TPasVariable) then
DoError(20170213214404,nExpectedXButFoundY,sExpectedXButFoundY,['var',
AContext.Resolver.GetResolverResultDescription(ResolvedVar)],El.VariableName);
case El.LoopType of
ltNormal,ltDown:
begin
StartValue:=AContext.Resolver.Eval(El.StartExpr,[],false);
StartInt:=GetOrd(StartValue,El.StartExpr);
EndValue:=AContext.Resolver.Eval(El.EndExpr,[],false);
EndInt:=GetOrd(EndValue,El.EndExpr);
end;
ltIn:
begin
HasInVar:=true;
AContext.Resolver.ComputeElement(El.StartExpr,ResolvedIn,[]);
InValue:=AContext.Resolver.Eval(El.StartExpr,[],false);
if InValue<>nil then
begin
// for in <constant> do
case InValue.Kind of
revkString,revkUnicodeString:
begin
// example:
// for c in 'foo' do ;
// -> for (var $l1 = 0, $li2 = 'foo'; $l1<=2; $l1++) c = $li2.charAt($l1);
InKind:=ikString;
StartInt:=0;
if InValue.Kind=revkString then
EndInt:=length(UTF8Decode(TResEvalString(InValue).S))-1
else
EndInt:=length(TResEvalUTF16(InValue).S)-1;
ReleaseEvalValue(InValue);
end;
revkRangeInt:
begin
StartInt:=TResEvalRangeInt(InValue).RangeStart;
EndInt:=TResEvalRangeInt(InValue).RangeEnd;
HasInVar:=false;
case TResEvalRangeInt(InValue).ElKind of
revskChar: InKind:=ikChar;
else
{$IFDEF VerbosePas2JS}
writeln('TPasToJSConverter.ConvertForStatement ',GetObjName(El.StartExpr),' InValue=',InValue.AsDebugString);
{$ENDIF}
RaiseNotSupported(El.StartExpr,AContext,20171113023419);
end;
end
else
{$IFDEF VerbosePas2JS}
writeln('TPasToJSConverter.ConvertForStatement ',GetObjName(El.StartExpr),' InValue=',InValue.AsDebugString);
{$ENDIF}
RaiseNotSupported(El.StartExpr,AContext,20171112161527);
end;
end
else if rrfReadable in ResolvedIn.Flags then
begin
// for v in <variable> do
if ResolvedIn.BaseType in btAllStrings then
begin
StartInt:=0;
InKind:=ikString;
end
else if ResolvedIn.BaseType=btContext then
begin
{$IFDEF VerbosePas2JS}
writeln('TPasToJSConverter.ConvertForStatement ',GetObjName(El.StartExpr),' StartValue=',StartValue.AsDebugString);
{$ENDIF}
RaiseNotSupported(El.StartExpr,AContext,20171113012226);
end;
end
else
begin
{$IFDEF VerbosePas2JS}
writeln('InitWithResolver ResolvedIn=',GetResolverResultDbg(ResolvedIn));
{$ENDIF}
RaiseNotSupported(El.StartExpr,AContext,20171112195629);
end;
end;
end;
if EndValue<>nil then
begin
HasEndVar:=false;
if (StartValue<>nil) then
begin
if StartInt<=EndInt then
begin
// loop is always executed
if StartValue.Kind in [revkInt,revkUInt,revkEnum] then
HasLoopVar:=false; // variable can be used as runner
end
else
begin
// loop is never executed
if coEliminateDeadCode in Options then exit;
end;
end;
end;
end;
Var Var
ForSt : TJSForStatement; ForSt : TJSForStatement;
List: TJSStatementList; List: TJSStatementList;
@ -10613,22 +10739,27 @@ Var
Incr: TJSUNaryExpression; Incr: TJSUNaryExpression;
BinExp : TJSBinaryExpression; BinExp : TJSBinaryExpression;
VarStat: TJSVariableStatement; VarStat: TJSVariableStatement;
CurLoopVarName, CurLoopEndVarName: String; CurLoopVarName, CurEndVarName, CurInVarName: String;
FuncContext: TConvertContext; FuncContext: TConvertContext;
ResolvedVar: TPasResolverResult; PosEl: TPasElement;
Comma: TJSCommaExpression;
LoopPosEl: TPasElement;
StartValue, EndValue: TResEvalValue;
NeedLoopVar, NeedLoopEndVar: Boolean;
StartInt, EndInt: MaxPrecInt;
Statements, V: TJSElement; Statements, V: TJSElement;
NotEqual: TJSEqualityExpressionNE; NotEqual: TJSEqualityExpressionNE;
Call: TJSCallExpression;
begin begin
Result:=Nil; Result:=Nil;
if AContext.Access<>caRead then if AContext.Access<>caRead then
RaiseInconsistency(20170213213740); RaiseInconsistency(20170213213740);
if not (El.LoopType in [ltNormal,ltDown]) then case El.LoopType of
ltNormal,ltDown: ;
ltIn:
if AContext.Resolver=nil then
RaiseNotSupported(El,AContext,20171112160707);
else
{$IFDEF VerbosePas2JS}
writeln('TPasToJSConverter.ConvertForStatement LoopType=',El.LoopType);
{$ENDIF}
RaiseNotSupported(El,AContext,20171110141937); RaiseNotSupported(El,AContext,20171110141937);
end;
// get function context // get function context
FuncContext:=AContext; FuncContext:=AContext;
@ -10636,60 +10767,42 @@ begin
FuncContext:=FuncContext.Parent; FuncContext:=FuncContext.Parent;
StartValue:=nil; StartValue:=nil;
StartInt:=0;
EndValue:=nil; EndValue:=nil;
EndInt:=0;
InValue:=nil;
InKind:=ikNone;
Statements:=nil; Statements:=nil;
try try
NeedLoopVar:=true; HasLoopVar:=true;
NeedLoopEndVar:=true; HasEndVar:=true;
HasInVar:=false;
if AContext.Resolver<>nil then if AContext.Resolver<>nil then
begin InitWithResolver;
AContext.Resolver.ComputeElement(El.VariableName,ResolvedVar,[rcNoImplicitProc]); // create unique var names $l, $end, $in
if not (ResolvedVar.IdentEl is TPasVariable) then if HasInVar then
DoError(20170213214404,nExpectedXButFoundY,sExpectedXButFoundY,['var', CurInVarName:=FuncContext.CreateLocalIdentifier(FBuiltInNames[pbivnLoopIn])
AContext.Resolver.GetResolverResultDescription(ResolvedVar)],El.VariableName); else
StartValue:=AContext.Resolver.Eval(El.StartExpr,[],false); CurInVarName:='';
StartInt:=GetOrd(StartValue,El.StartExpr); if HasLoopVar then
EndValue:=AContext.Resolver.Eval(El.EndExpr,[],false);
EndInt:=GetOrd(EndValue,El.EndExpr);
if EndValue<>nil then
begin
NeedLoopEndVar:=false;
if (StartValue<>nil) then
begin
if StartInt<=EndInt then
begin
// loop is always executed
if StartValue.Kind in [revkInt,revkUInt,revkEnum] then
NeedLoopVar:=false; // variable can be used as runner
end
else
begin
// loop is never executed
if coEliminateDeadCode in Options then exit;
end;
end;
end;
end;
// create unique var names $loop and $loopend
if NeedLoopVar then
CurLoopVarName:=FuncContext.CreateLocalIdentifier(FBuiltInNames[pbivnLoop]) CurLoopVarName:=FuncContext.CreateLocalIdentifier(FBuiltInNames[pbivnLoop])
else else
CurLoopVarName:=''; CurLoopVarName:='';
if NeedLoopEndVar then if HasEndVar then
CurLoopEndVarName:=FuncContext.CreateLocalIdentifier(FBuiltInNames[pbivnLoopEnd]) CurEndVarName:=FuncContext.CreateLocalIdentifier(FBuiltInNames[pbivnLoopEnd])
else else
CurLoopEndVarName:=''; CurEndVarName:='';
// add "for()" // add "for()"
ForSt:=TJSForStatement(CreateElement(TJSForStatement,El)); ForSt:=TJSForStatement(CreateElement(TJSForStatement,El));
Statements:=ForSt; Statements:=ForSt;
// add variable=<startexpr> // add in front of for(): variable=<startexpr>
if (not NeedLoopVar) and NeedLoopEndVar then if (not HasLoopVar) and (HasEndVar or HasInVar) then
begin begin
// for example: // for example:
// i:=<startexpr>; // i:=<startexpr>;
// for (var $le = <endexpr>; $i<$le; $i++)... // for (var $end = <endexpr>; $i<$end; $i++)...
List:=TJSStatementList(CreateElement(TJSStatementList,El)); List:=TJSStatementList(CreateElement(TJSStatementList,El));
SimpleAss:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El.VariableName)); SimpleAss:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El.VariableName));
List.A:=SimpleAss; List.A:=SimpleAss;
@ -10700,39 +10813,65 @@ begin
SimpleAss.Expr:=CreateLiteralNumber(El.StartExpr,StartInt) SimpleAss.Expr:=CreateLiteralNumber(El.StartExpr,StartInt)
else else
SimpleAss.Expr:=ConvertElement(El.StartExpr,AContext); SimpleAss.Expr:=ConvertElement(El.StartExpr,AContext);
PosEl:=El.StartExpr;
end; end;
if NeedLoopVar or NeedLoopEndVar then if HasLoopVar or HasEndVar or HasInVar then
begin begin
// add "for(var ..." // add "for(var ..."
VarStat:=TJSVariableStatement(CreateElement(TJSVariableStatement,El)); VarStat:=TJSVariableStatement(CreateElement(TJSVariableStatement,El));
ForSt.Init:=VarStat; ForSt.Init:=VarStat;
if NeedLoopVar then if HasInVar then
begin begin
// add "$loop=<StartExpr>" // add "$in=<InExpr>"
PosEl:=El.StartExpr;
if InValue<>nil then
V:=ConvertConstValue(InValue,AContext,PosEl)
else
V:=ConvertElement(El.StartExpr,AContext);
V:=CreateVarDecl(CurInVarName,V,PosEl);
AddToVarStatement(VarStat,V,PosEl);
end;
if HasLoopVar then
begin
// add "$l=<StartExpr>"
PosEl:=El.StartExpr;
if StartValue<>nil then if StartValue<>nil then
V:=CreateLiteralNumber(El.StartExpr,StartInt) V:=CreateLiteralNumber(PosEl,StartInt)
else if El.LoopType=ltIn then
case InKind of
ikChar, ikString: V:=CreateLiteralNumber(PosEl,StartInt);
end
else else
V:=ConvExpr(El.StartExpr); V:=ConvExpr(El.StartExpr);
VarStat.A:=CreateVarDecl(CurLoopVarName,V,El.StartExpr); V:=CreateVarDecl(CurLoopVarName,V,PosEl);
AddToVarStatement(VarStat,V,PosEl);
end; end;
if NeedLoopEndVar then if HasEndVar then
begin begin
// add "$loopend=<EndExpr>" // add "$end=<EndExpr>"
PosEl:=El.EndExpr;
if El.EndExpr=nil then
PosEl:=El.StartExpr;
if EndValue<>nil then if EndValue<>nil then
V:=CreateLiteralNumber(El.EndExpr,EndInt) V:=CreateLiteralNumber(PosEl,EndInt)
else if El.LoopType=ltIn then
case InKind of
ikChar: V:=CreateLiteralNumber(PosEl,EndInt);
ikString:
begin
// add "$end=$in.length-1"
V:=TJSAdditiveExpressionMinus(CreateElement(TJSAdditiveExpressionMinus,PosEl));
TJSAdditiveExpressionMinus(V).A:=CreatePrimitiveDotExpr(CurInVarName+'.length',PosEl);
TJSAdditiveExpressionMinus(V).B:=CreateLiteralNumber(PosEl,1);
end;
else
RaiseNotSupported(El.StartExpr,AContext,20171113015445);
end
else else
V:=ConvExpr(El.EndExpr); V:=ConvExpr(El.EndExpr);
V:=CreateVarDecl(CurLoopEndVarName,V,El.EndExpr); V:=CreateVarDecl(CurEndVarName,V,PosEl);
if VarStat.A=nil then AddToVarStatement(VarStat,V,PosEl);
VarStat.A:=V
else
begin
Comma:=TJSCommaExpression(CreateElement(TJSCommaExpression,El.EndExpr));
Comma.A:=VarStat.A;
Comma.B:=V;
VarStat.A:=Comma;
end;
end; end;
end end
else else
@ -10746,59 +10885,82 @@ begin
SimpleAss.Expr:=CreateLiteralNumber(El.StartExpr,StartInt) SimpleAss.Expr:=CreateLiteralNumber(El.StartExpr,StartInt)
else else
SimpleAss.Expr:=ConvertElement(El.StartExpr,AContext); SimpleAss.Expr:=ConvertElement(El.StartExpr,AContext);
PosEl:=El.StartExpr;
end; end;
// add "$loop<=$loopend" // add "$l<=$end"
if (El.EndExpr<>nil) then
PosEl:=El.EndExpr;
if El.Down then if El.Down then
BinExp:=TJSRelationalExpressionGE(CreateElement(TJSRelationalExpressionGE,El.EndExpr)) BinExp:=TJSRelationalExpressionGE(CreateElement(TJSRelationalExpressionGE,PosEl))
else else
BinExp:=TJSRelationalExpressionLE(CreateElement(TJSRelationalExpressionLE,El.EndExpr)); BinExp:=TJSRelationalExpressionLE(CreateElement(TJSRelationalExpressionLE,PosEl));
ForSt.Cond:=BinExp; ForSt.Cond:=BinExp;
if NeedLoopVar then if HasLoopVar then
BinExp.A:=CreatePrimitiveDotExpr(CurLoopVarName,El.EndExpr) BinExp.A:=CreatePrimitiveDotExpr(CurLoopVarName,PosEl)
else else
BinExp.A:=ConvertElement(El.VariableName,AContext); BinExp.A:=ConvertElement(El.VariableName,AContext);
if NeedLoopEndVar then if HasEndVar then
BinExp.B:=CreatePrimitiveDotExpr(CurLoopEndVarName,El.EndExpr) BinExp.B:=CreatePrimitiveDotExpr(CurEndVarName,PosEl)
else else
BinExp.B:=CreateLiteralNumber(El.EndExpr,EndInt); BinExp.B:=CreateLiteralNumber(PosEl,EndInt);
// add "$loop++" // add "$l++"
if El.Down then if El.Down then
Incr:=TJSUnaryPostMinusMinusExpression(CreateElement(TJSUnaryPostMinusMinusExpression,El.EndExpr)) Incr:=TJSUnaryPostMinusMinusExpression(CreateElement(TJSUnaryPostMinusMinusExpression,PosEl))
else else
Incr:=TJSUnaryPostPlusPlusExpression(CreateElement(TJSUnaryPostPlusPlusExpression,El.EndExpr)); Incr:=TJSUnaryPostPlusPlusExpression(CreateElement(TJSUnaryPostPlusPlusExpression,PosEl));
ForSt.Incr:=Incr; ForSt.Incr:=Incr;
if NeedLoopVar then if HasLoopVar then
Incr.A:=CreatePrimitiveDotExpr(CurLoopVarName,El.EndExpr) Incr.A:=CreatePrimitiveDotExpr(CurLoopVarName,PosEl)
else else
Incr.A:=ConvertElement(El.VariableName,AContext); Incr.A:=ConvertElement(El.VariableName,AContext);
// add "VariableName:=$loop;" // add "VariableName:=$l;"
if NeedLoopVar then if HasLoopVar then
begin begin
LoopPosEl:=El.Body; PosEl:=El.Body;
if LoopPosEl=nil then if PosEl=nil then
LoopPosEl:=El; PosEl:=El;
// add "VariableName:=$loop;" PosEl:=El.VariableName;
LoopPosEl:=El.VariableName; SimpleAss:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,PosEl));
SimpleAss:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,LoopPosEl));
ForSt.Body:=SimpleAss; ForSt.Body:=SimpleAss;
SimpleAss.LHS:=ConvertElement(El.VariableName,AContext); SimpleAss.LHS:=ConvertElement(El.VariableName,AContext);
SimpleAss.Expr:=CreatePrimitiveDotExpr(CurLoopVarName,LoopPosEl); SimpleAss.Expr:=CreatePrimitiveDotExpr(CurLoopVarName,PosEl);
if AContext.Resolver<>nil then if AContext.Resolver<>nil then
begin begin
if (ResolvedVar.BaseType in btAllChars) if InKind<>ikNone then
case InKind of
ikChar:
// String.fromCharCode($l)
SimpleAss.Expr:=CreateCallFromCharCode(SimpleAss.Expr,PosEl);
ikString:
begin
// $in.charAt($l)
Call:=CreateCallExpression(PosEl);
Call.Expr:=CreateDotExpression(PosEl,
CreatePrimitiveDotExpr(CurInVarName,El.StartExpr),
CreatePrimitiveDotExpr('charAt',PosEl));
Call.AddArg(SimpleAss.Expr);
SimpleAss.Expr:=Call;
end
else
{$IFDEF VerbosePas2JS}
writeln('TPasToJSConverter.ConvertForStatement InKind=',InKind);
{$ENDIF}
RaiseNotSupported(El.StartExpr,AContext,20171113002550);
end
else if (ResolvedVar.BaseType in btAllChars)
or ((ResolvedVar.BaseType=btRange) and (ResolvedVar.SubType in btAllChars)) then or ((ResolvedVar.BaseType=btRange) and (ResolvedVar.SubType in btAllChars)) then
begin begin
// convert int to char // convert int to char
SimpleAss.Expr:=CreateCallFromCharCode(SimpleAss.Expr,LoopPosEl); SimpleAss.Expr:=CreateCallFromCharCode(SimpleAss.Expr,PosEl);
end end
else if (ResolvedVar.BaseType in btAllBooleans) else if (ResolvedVar.BaseType in btAllBooleans)
or ((ResolvedVar.BaseType=btRange) and (ResolvedVar.SubType in btAllBooleans)) then or ((ResolvedVar.BaseType=btRange) and (ResolvedVar.SubType in btAllBooleans)) then
begin begin
// convert int to bool -> $loop!=0 // convert int to bool -> $l!=0
NotEqual:=TJSEqualityExpressionNE(CreateElement(TJSEqualityExpressionNE,LoopPosEl)); NotEqual:=TJSEqualityExpressionNE(CreateElement(TJSEqualityExpressionNE,PosEl));
NotEqual.A:=SimpleAss.Expr; NotEqual.A:=SimpleAss.Expr;
NotEqual.B:=CreateLiteralNumber(El,0); NotEqual.B:=CreateLiteralNumber(El,0);
SimpleAss.Expr:=NotEqual; SimpleAss.Expr:=NotEqual;
@ -10824,6 +10986,7 @@ begin
finally finally
ReleaseEvalValue(StartValue); ReleaseEvalValue(StartValue);
ReleaseEvalValue(EndValue); ReleaseEvalValue(EndValue);
ReleaseEvalValue(InValue);
if Result=nil then if Result=nil then
Statements.Free; Statements.Free;
end; end;
@ -11169,6 +11332,22 @@ begin
end; end;
end; end;
procedure TPasToJSConverter.AddToVarStatement(VarStat: TJSVariableStatement;
Add: TJSElement; Src: TPasElement);
var
Comma: TJSCommaExpression;
begin
if VarStat.A=nil then
VarStat.A:=Add
else
begin
Comma:=TJSCommaExpression(CreateElement(TJSCommaExpression,Src));
Comma.A:=VarStat.A;
Comma.B:=Add;
VarStat.A:=Comma;
end;
end;
function TPasToJSConverter.CreateValInit(PasType: TPasType; Expr: TPasExpr; function TPasToJSConverter.CreateValInit(PasType: TPasType; Expr: TPasExpr;
El: TPasElement; AContext: TConvertContext): TJSElement; El: TPasElement; AContext: TConvertContext): TJSElement;
var var

View File

@ -204,6 +204,7 @@ type
// numbers // numbers
Procedure TestDouble; Procedure TestDouble;
Procedure TestIntegerRange; Procedure TestIntegerRange;
Procedure TestForBoolDo;
// strings // strings
Procedure TestCharConst; Procedure TestCharConst;
@ -223,7 +224,7 @@ type
Procedure TestTypeShortstring_Fail; Procedure TestTypeShortstring_Fail;
Procedure TestCharSet_Custom; Procedure TestCharSet_Custom;
Procedure TestForCharDo; Procedure TestForCharDo;
Procedure TestForBoolDo; Procedure TestForCharInDo;
// alias types // alias types
Procedure TestAliasTypeRef; Procedure TestAliasTypeRef;
@ -4111,6 +4112,25 @@ begin
''])); '']));
end; end;
procedure TTestModule.TestForBoolDo;
begin
StartProgram(false);
Add([
'var b: boolean;',
'begin',
' for b:=false to true do ;',
' for b:=b downto false do ;',
'']);
ConvertProgram;
CheckSource('TestForBoolDo',
LinesToStr([ // statements
'this.b = false;']),
LinesToStr([ // this.$main
'for (var $l1 = 0; $l1 <= 1; $l1++) $mod.b = $l1 != 0;',
'for (var $l2 = +$mod.b; $l2 >= 0; $l2--) $mod.b = $l2 != 0;',
'']));
end;
procedure TTestModule.TestCharConst; procedure TTestModule.TestCharConst;
begin begin
StartProgram(false); StartProgram(false);
@ -4547,22 +4567,58 @@ begin
''])); '']));
end; end;
procedure TTestModule.TestForBoolDo; procedure TTestModule.TestForCharInDo;
begin begin
StartProgram(false); StartProgram(false);
Add([ Add([
'var b: boolean;', 'type',
' TSetOfChar = set of char;',
' TCharRg = ''a''..''z'';',
' TSetOfCharRg = set of TCharRg;',
'const Foo = ''foo'';',
'var',
' c: char;',
' s: string;',
' a1: array of char;',
' a2: array[1..3] of char;',
' a3: array[1..3,4..5] of char;',
' soc: TSetOfChar;',
' socr: TSetOfCharRg;',
' cr: TCharRg;',
'begin', 'begin',
' for b:=false to true do ;', ' for c in foo do ;',
' for b:=b downto false do ;', ' for c in s do ;',
' for c in char do ;',
//' for c in a1 do ;',
//' for c in a2 do ;',
//' for c in a3 do ;',
//' for c in [''1''..''3''] do ;',
//' for c in TSetOfChar do ;',
//' for c in TCharRg do ;',
//' for c in soc do ;',
//' for c in TSetOfCharRg do ;',
//' for c in socr do ;',
//' for cr in TCharRg do ;',
//' for cr in TSetOfCharRg do ;',
//' for cr in socr do ;',
'']); '']);
ConvertProgram; ConvertProgram;
CheckSource('TestForBoolDo', CheckSource('TestForCharInDo',
LinesToStr([ // statements LinesToStr([ // statements
'this.b = false;']), 'this.Foo = "foo";',
'this.c = "";',
'this.s = "";',
'this.a1 = [];',
'this.a2 = rtl.arraySetLength(null, "", 3);',
'this.a3 = rtl.arraySetLength(null, "", 3, 2);',
'this.soc = {};',
'this.socr = {};',
'this.cr = "a";',
'']),
LinesToStr([ // this.$main LinesToStr([ // this.$main
'for (var $l1 = 0; $l1 <= 1; $l1++) $mod.b = $l1 != 0;', 'for (var ($in1 = $mod.Foo, $l2 = 0), $end3 = $in1.length - 1; $l2 <= $end3; $l2++) $mod.c = $in1.charAt($l2);',
'for (var $l2 = +$mod.b; $l2 >= 0; $l2--) $mod.b = $l2 != 0;', 'for (var ($in4 = $mod.s, $l5 = 0), $end6 = $in4.length - 1; $l5 <= $end6; $l5++) $mod.c = $in4.charAt($l5);',
'for (var $l7 = 0, $end8 = 65535; $l7 <= $end8; $l7++) $mod.c = String.fromCharCode($l7);',
''])); '']));
end; end;
@ -4693,7 +4749,7 @@ begin
LinesToStr([ // this.$main LinesToStr([ // this.$main
' $mod.vJ = 0;', ' $mod.vJ = 0;',
' $mod.vN = 3;', ' $mod.vN = 3;',
' for (var $l1 = 1, $le2 = $mod.vN; $l1 <= $le2; $l1++) {', ' for (var $l1 = 1, $end2 = $mod.vN; $l1 <= $end2; $l1++) {',
' $mod.vI = $l1;', ' $mod.vI = $l1;',
' $mod.vJ = $mod.vJ + $mod.vI;', ' $mod.vJ = $mod.vJ + $mod.vI;',
' };', ' };',
@ -4723,7 +4779,7 @@ begin
' var vI = 0;', ' var vI = 0;',
' var vJ = 0;', ' var vJ = 0;',
' vJ = 0;', ' vJ = 0;',
' for (var $l1 = 1, $le2 = Count; $l1 <= $le2; $l1++) {', ' for (var $l1 = 1, $end2 = Count; $l1 <= $end2; $l1++) {',
' vI = $l1;', ' vI = $l1;',
' vJ = vJ + vI;', ' vJ = vJ + vI;',
' };', ' };',
@ -4781,9 +4837,9 @@ begin
' var vJ = 0;', ' var vJ = 0;',
' var vK = 0;', ' var vK = 0;',
' vK = 0;', ' vK = 0;',
' for (var $l1 = 1, $le2 = Count; $l1 <= $le2; $l1++) {', ' for (var $l1 = 1, $end2 = Count; $l1 <= $end2; $l1++) {',
' vI = $l1;', ' vI = $l1;',
' for (var $l3 = 1, $le4 = vI; $l3 <= $le4; $l3++) {', ' for (var $l3 = 1, $end4 = vI; $l3 <= $end4; $l3++) {',
' vJ = $l3;', ' vJ = $l3;',
' vK = vK + vI;', ' vK = vK + vI;',
' };', ' };',
@ -5799,7 +5855,7 @@ begin
'this.DoIt = function (a) {', 'this.DoIt = function (a) {',
' var i = 0;', ' var i = 0;',
' var s = "";', ' var s = "";',
' for (var $l1 = 0, $le2 = rtl.length(a) - 1; $l1 <= $le2; $l1++) {', ' for (var $l1 = 0, $end2 = rtl.length(a) - 1; $l1 <= $end2; $l1++) {',
' i = $l1;', ' i = $l1;',
' s = a[(rtl.length(a) - i) - 1];', ' s = a[(rtl.length(a) - i) - 1];',
' };', ' };',

View File

@ -421,7 +421,7 @@ begin
' var Runner = 0;', ' var Runner = 0;',
' var j = 0;', ' var j = 0;',
' j = 0;', ' j = 0;',
' for (var $l1 = 3, $le2 = j; $l1 <= $le2; $l1++) {', ' for (var $l1 = 3, $end2 = j; $l1 <= $end2; $l1++) {',
' Runner = $l1;', ' Runner = $l1;',
' j += 1;', ' j += 1;',
' };', ' };',