Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
fpc-src / usr / share / fpcsrc / 3.0.0 / packages / fcl-js / src / jswriter.pp
Size: Mime:
unit jswriter;

{$mode objfpc}{$H+}
{ $DEFINE DEBUGJSWRITER}

interface

uses
  {Classes, } SysUtils, jstoken, jsbase, jstree;

Type

  { TTextWriter }

  TTextWriter = Class(TObject)
  protected
    Function DoWrite(Const S : AnsiString) : Integer; virtual; abstract;
    Function DoWrite(Const S : UnicodeString) : Integer; virtual; abstract;
  Public
    // All functions return the numberof bytes copied to output stream.
    Function Write(Const S : UnicodeString) : Integer;
    Function Write(Const S : AnsiString) : Integer;
    Function WriteLn(Const S : AnsiString) : Integer;
    Function Write(Const Fmt : AnsiString; Args : Array of const) : Integer;
    Function WriteLn(Const Fmt : AnsiString; Args : Array of const) : Integer;
    Function Write(Const Args : Array of const) : Integer;
    Function WriteLn(Const Args : Array of const) : Integer;
  end;

  { TFileWriter }

  TFileWriter = Class(TTextWriter)
  Protected
    FFile : Text;
    FFileName : String;
    Function DoWrite(Const S : AnsiString) : Integer; override;
    Function DoWrite(Const S : UnicodeString) : Integer; override;
  Public
    Constructor Create(Const AFileNAme : String);
    Destructor Destroy; override;
    Procedure Flush;
    Procedure Close;
    Property FileName : String Read FFileName;
  end;

  { TBufferWriter }
  TBytes = Array of byte;
  TBufferWriter = Class(TTextWriter)
  private
    FBufPos,
    FCapacity: Cardinal;
    FBuffer : TBytes;
    function GetAsAnsistring: AnsiString;
    function GetBuffer: Pointer;
    function GetBufferLength: Integer;
    function GetCapacity: Cardinal;
    function GetUnicodeString: UnicodeString;
    procedure SetCapacity(AValue: Cardinal);
  Protected
    Function DoWrite(Const S : AnsiString) : integer; override;
    Function DoWrite(Const S : UnicodeString) : integer; override;
  Public
    Constructor Create(Const ACapacity : Cardinal);
    Procedure SaveToFile(Const AFileName : String);
    Property Buffer : Pointer Read GetBuffer;
    Property BufferLength : Integer Read GetBufferLength;
    Property Capacity : Cardinal Read GetCapacity Write SetCapacity;
    Property AsAnsistring : AnsiString Read GetAsAnsistring;
    Property AsUnicodeString : UnicodeString Read GetUnicodeString;
  end;


  { TJSWriter }
  TWriteOption = (woCompact,
                  woUseUTF8,
                  woTabIndent,
                  woEmptyStatementAsComment,
                  woQuoteElementNames,
                  woCompactArrayLiterals,
                  woCompactObjectLiterals,
                  woCompactArguments);
  TWriteOptions = Set of TWriteOption;

  TJSWriter = Class
  private
    FCurIndent : Integer;
    FLinePos : Integer;
    FIndentSize: Byte;
    FIndentChar : Char;
    FOptions: TWriteOptions;
    FWriter: TTextWriter;
    FFreeWriter : Boolean;
    FSkipBrackets : Boolean;
    function GetUseUTF8: Boolean;
    procedure SetOptions(AValue: TWriteOptions);
  Protected
    // Helper routines
    Procedure Error(Const Msg : String);
    Procedure Error(Const Fmt : String; Args : Array of const);
    Procedure WriteIndent; // inline;
    Procedure Write(Const U : UnicodeString);
    Procedure Write(Const S : AnsiString);
    Procedure WriteLn(Const S : AnsiString);
    Procedure WriteLn(Const U : UnicodeString);
    // one per type of statement
    Procedure WriteValue(V : TJSValue);  virtual;
    Procedure WriteRegularExpressionLiteral(El: TJSRegularExpressionLiteral);
    Procedure WriteVariableStatement(el: TJSVariableStatement);
    Procedure WriteEmptyBlockStatement(El: TJSEmptyBlockStatement); virtual;
    Procedure WriteEmptyStatement(El: TJSEmptyStatement);virtual;
    Procedure WriteLiteral(El: TJSLiteral);virtual;
    Procedure WriteArrayLiteral(El: TJSArrayLiteral);virtual;
    Procedure WriteObjectLiteral(El: TJSObjectLiteral);virtual;
    Procedure WriteMemberExpression(el: TJSMemberExpression);virtual;
    Procedure WriteCallExpression(El: TJSCallExpression);virtual;
    Procedure WriteSwitchStatement(El: TJSSwitchStatement);virtual;
    Procedure WriteUnary(El: TJSUnary);virtual;
    Procedure WriteAssignStatement(El: TJSAssignStatement);virtual;
    Procedure WriteForInStatement(El: TJSForInStatement);virtual;
    Procedure WriteWhileStatement(El: TJSWhileStatement);virtual;
    Procedure WriteForStatement(El: TJSForStatement);virtual;
    Procedure WriteIfStatement(El: TJSIfStatement);virtual;
    Procedure WriteSourceElements(El: TJSSourceElements);virtual;
    Procedure WriteStatementList(El: TJSStatementList);virtual;
    Procedure WriteTryStatement(el: TJSTryStatement);virtual;
    Procedure WriteVarDeclaration(El: TJSVarDeclaration);virtual;
    Procedure WriteWithStatement(El: TJSWithStatement);virtual;
    Procedure WriteVarDeclarationList(El: TJSVariableDeclarationList);virtual;
    Procedure WriteConditionalExpression(El: TJSConditionalExpression);virtual;
    Procedure WriteFunctionBody(el: TJSFunctionBody);virtual;
    Procedure WriteFunctionDeclarationStatement(El: TJSFunctionDeclarationStatement);virtual;
    Procedure WriteLabeledStatement(El: TJSLabeledStatement);virtual;
    Procedure WriteReturnStatement(EL: TJSReturnStatement);virtual;
    Procedure WriteTargetStatement(El: TJSTargetStatement);virtual;
    Procedure WriteFuncDef(FD: TJSFuncDef);virtual;
    Procedure WritePrimaryExpression(El: TJSPrimaryExpression);virtual;
    Procedure WriteBinary(El: TJSBinary);virtual;
  Public
    Class Function EscapeString(const S: TJSString): TJSString;
    Constructor Create(AWriter : TTextWriter);
    Constructor Create(Const AFileName : String);
    Destructor Destroy; override;
    Procedure WriteJS(El : TJSElement);
    Procedure Indent;
    Procedure Undent;
    Property Writer : TTextWriter Read FWriter;
    Property options : TWriteOptions Read FOptions Write SetOptions;
    Property IndentSize : Byte Read FIndentSize Write FIndentSize;
    Property UseUTF8 : Boolean Read GetUseUTF8;
  end;
  EJSWriter = CLass(Exception);

implementation

Resourcestring
  SErrUnknownJSClass = 'Unknown javascript element class : %s';
  SErrNilNode = 'Nil node in Javascript';

{ TBufferWriter }

function TBufferWriter.GetBufferLength: Integer;
begin
  Result:=FBufPos;
end;

function TBufferWriter.GetAsAnsistring: AnsiString;
begin
  SetLength(Result,BufferLength);
  if (BufferLength>0) then
    Move(FBuffer[0],Result[1],BufferLength);
end;

function TBufferWriter.GetBuffer: Pointer;
begin
  Result:=Pointer(FBuffer);
end;

function TBufferWriter.GetCapacity: Cardinal;
begin
  Result:=Length(FBuffer);
end;

function TBufferWriter.GetUnicodeString: UnicodeString;

Var
  SL : Integer;

begin
  SL:=BufferLength div SizeOf(UnicodeChar); // Silently ignores last byte
  SetLength(Result,SL);
  if (SL>0) then
    Move(FBuffer[0],Result[1],SL*SizeOf(UnicodeChar));
end;

procedure TBufferWriter.SetCapacity(AValue: Cardinal);
begin
  if FCapacity=AValue then Exit;
  SetLength(FBuffer,AValue);
  if (FBufPos>Capacity) then
    FBufPos:=Capacity;
end;

Function TBufferWriter.DoWrite(Const S: AnsiString): integer;

Var
  DesLen,MinLen : Integer;

begin
  Result:=Length(S)*SizeOf(Char);
  MinLen:=Result+FBufPos;
  If (MinLen>Capacity) then
    begin
    DesLen:=Round(FCapacity*1.25);
    if DesLen>MinLen then
      MinLen:=DesLen;
    Capacity:=MinLen;
    end;
  Move(S[1],FBuffer[FBufPos],Result);
  FBufPos:=FBufPos+Result;
end;

Function TBufferWriter.DoWrite(Const S: UnicodeString): integer;

Var
  DesLen,MinLen : Integer;

begin
  Result:=Length(S)*SizeOf(UnicodeChar);
  MinLen:=Result+FBufPos;
  If (MinLen>Capacity) then
    begin
    DesLen:=Round(FCapacity*1.25);
    if DesLen>MinLen then
      MinLen:=DesLen;
    Capacity:=MinLen;
    end;
  Move(S[1],FBuffer[FBufPos],Result);
  FBufPos:=FBufPos+Result;
end;

Constructor TBufferWriter.Create(Const ACapacity: Cardinal);
begin
  Capacity:=ACapacity;
end;

Procedure TBufferWriter.SaveToFile(Const AFileName: String);

Var
  F : File;

begin
  Assign(F,AFileName);
  Rewrite(F,1);
  try
    BlockWrite(F,FBuffer[0],FBufPos);
  finally
    Close(F);
  end;
end;

{ TJSWriter }

procedure TJSWriter.SetOptions(AValue: TWriteOptions);
begin
  if FOptions=AValue then Exit;
  FOptions:=AValue;
  If woTabIndent in Foptions then
    FIndentChar:=#9
  else
    FIndentChar:=' ';
end;

function TJSWriter.GetUseUTF8: Boolean;
begin
  Result:=(woUseUTF8 in Options)
end;

Procedure TJSWriter.Error(Const Msg: String);
begin
  Raise EJSWriter.Create(Msg);
end;

Procedure TJSWriter.Error(Const Fmt: String; Args: Array of const);
begin
  Raise EJSWriter.CreateFmt(Fmt,Args);
end;

Procedure TJSWriter.WriteIndent;

begin
  If (FLinePos=0) then
    FLinePos:=Writer.Write(StringOfChar(FIndentChar,FCurIndent));
end;

Procedure TJSWriter.Indent;
begin
  Inc(FCurIndent,FIndentSIze);
end;

Procedure TJSWriter.Undent;
begin
  if (FCurIndent>=FIndentSIze) then
    Dec(FCurIndent,FIndentSIze)
  else
    FCurIndent:=0;
end;

Procedure TJSWriter.Write(Const U: UnicodeString);

Var
  S : UTF8String;

begin
  WriteIndent;
  if UseUTF8 then
    begin
    S:=UTF8Encode(U);
    FLinePos:=FLinePos+Writer.Write(S);
    end
  else
    FLinePos:=FLinePos+Writer.Write(U);
end;

Procedure TJSWriter.Write(Const S: AnsiString);
begin
  if Not (woUseUTF8 in Options) then
    Write(UnicodeString(S))
  else
    begin
    WriteIndent;
    FLinePos:=FLinePos+Writer.Write(S);
    end;
end;

Procedure TJSWriter.WriteLn(Const S: AnsiString);
begin
  if Not (woUseUTF8 in Options) then
    Writeln(UnicodeString(S))
  else
    begin
    WriteIndent;
    Writer.WriteLn(S);
    FLinePos:=0;
    end;
end;

Procedure TJSWriter.WriteLn(Const U: UnicodeString);
Var
  S : UTF8String;

begin
  if UseUTF8 then
    begin
    S:=UTF8Encode(U);
    Writeln(S);
    end
  else
    begin
    WriteIndent;
    FLinePos:=FLinePos+Writer.Write(U);
    FLinePos:=0;
    end;
end;

Class Function TJSWriter.EscapeString(const S : TJSString) : TJSString;

Var
  I,J,L : Integer;
  P : PWideChar;

begin
  I:=1;
  J:=1;
  Result:='';
  L:=Length(S);
  P:=PWideChar(S);
  While I<=L do
    begin
    if (AnsiChar(P^) in ['"','/','\',#8,#9,#10,#12,#13]) then
      begin
      Result:=Result+Copy(S,J,I-J);
      Case P^ of
        '\' : Result:=Result+'\\';
        '/' : Result:=Result+'\/';
        '"' : Result:=Result+'\"';
        #8  : Result:=Result+'\b';
        #9  : Result:=Result+'\t';
        #10 : Result:=Result+'\n';
        #12 : Result:=Result+'\f';
        #13 : Result:=Result+'\r';
      end;
      J:=I+1;
      end;
    Inc(I);
    Inc(P);
    end;
  Result:=Result+Copy(S,J,I-1);
end;

Procedure TJSWriter.WriteValue(V: TJSValue);

Var
  S : String;
begin
  Case V.ValueType of
     jstUNDEFINED : S:='undefined';
     jstNull : s:='null';
     jstBoolean : if V.AsBoolean then s:='true' else s:='false';
     jstString : S:='"'+EscapeString(V.AsString)+'"';
     jstNumber :
       if Frac(V.AsNumber)=0 then // this needs to be improved
         Str(Round(V.AsNumber),S)
       else
         Str(V.AsNumber,S);
     jstObject : ;
     jstReference : ;
     JSTCompletion : ;
  end;
  Write(S);
end;

Constructor TJSWriter.Create(AWriter: TTextWriter);
begin
  FWriter:=AWriter;
  FIndentChar:=' ';
  FOptions:=[woUseUTF8];
end;

Constructor TJSWriter.Create(Const AFileName: String);
begin
  Create(TFileWriter.Create(AFileName));
  FFreeWriter:=True;
end;

Destructor TJSWriter.Destroy;
begin
  If FFreeWriter then
    begin
    FWriter.Free;
    FWriter:=Nil;
    end;
  inherited Destroy;
end;

Procedure TJSWriter.WriteFuncDef(FD: TJSFuncDef);

Var
  C : Boolean;
  I : Integer;

begin
  C:=(woCompact in Options);
  Write('function ');
  If (FD.Name<>'') then
    Write(FD.Name);
  Write('(');
  if Assigned(FD.Params) then
    For I:=0 to FD.Params.Count-1 do
      begin
      write(FD.Params[i]);
      if I<FD.Params.Count-1 then
        if C then Write(',') else Write (', ');
      end;
  Write(') {');
  if Not (C or FD.IsEmpty) then
    begin
    Writeln('');
    indent;
    end;
  if Assigned(FD.Body) then
    begin
    FSkipBrackets:=True;
    WriteJS(FD.Body);
    If not (FD.Body.A is TJSStatementList) then
      if C then
        Write('; ')
      else
        Writeln(';');
    end;
  if C then
    Write('}')
  else
    begin
    undent;
    Writeln('}');
    end;
end;

Procedure TJSWriter.WriteEmptyBlockStatement(El: TJSEmptyBlockStatement);
begin
  if woCompact in Options then
    Write('{}')
  else
    begin
    Writeln('{');
    Write('}');
    end;
end;

Procedure TJSWriter.WriteEmptyStatement(El: TJSEmptyStatement);
begin
  if woEmptyStatementAsComment in options then
    Write('/* Empty statement */')
end;

Procedure TJSWriter.WriteRegularExpressionLiteral(El: TJSRegularExpressionLiteral);

begin
  Write('/');
  Write(EscapeString(EL.Pattern.AsString));
  Write('/');
  If Assigned(EL.PatternFlags) then
    Write(EscapeString(EL.PatternFlags.AsString));
end;

Procedure TJSWriter.WriteLiteral(El: TJSLiteral);
begin
  WriteValue(el.Value);
end;

Procedure TJSWriter.WritePrimaryExpression(El: TJSPrimaryExpression);

begin
  if El is TJSPrimaryExpressionThis then
    Write('this')
  else if el is TJSPrimaryExpressionIdent then
    Write(TJSPrimaryExpressionIdent(El).Name);
end;

Procedure TJSWriter.WriteArrayLiteral(El : TJSArrayLiteral);



Var
  Chars : Array[Boolean] of string[2] = ('[]','()');

Var
  i,C : Integer;
  isArgs,WC : Boolean;
  BC : String[2];

begin
  isArgs:=el is TJSArguments;
  BC:=Chars[isArgs];
  C:=EL.Elements.Count-1;
  if C=-1 then
    begin
    if isArgs then
      Write(bc)
    else
      Write(bc);
    Exit;
    end;
  WC:=(woCompact in Options) or
      ((Not isArgs) and (woCompactArrayLiterals in Options)) or
      (isArgs and (woCompactArguments in Options)) ;
  if WC then
    Write(Copy(BC,1,1))
  else
    begin
    Writeln(Copy(BC,1,1));
    Indent;
    end;
  For I:=0 to C do
   begin
   WriteJS(EL.Elements[i].Expr);
   if I<C then
     if WC then Write(', ') else Writeln(',')
   end;
  if not WC then
    begin
    Writeln('');
    Undent;
    end;
  Write(Copy(BC,2,1));
end;


Procedure TJSWriter.WriteObjectLiteral(El : TJSObjectLiteral);


Var
  i,C : Integer;
  QE,WC : Boolean;
  S : TJSString;

begin
  C:=EL.Elements.Count-1;
  QE:=(woQuoteElementNames in Options);
  if C=-1 then
    begin
    Write('{}');
    Exit;
    end;
  WC:=(woCompact in Options) or (woCompactObjectLiterals in Options);
  if WC then
    Write('{')
  else
    begin
    Writeln('{');
    Indent;
    end;
  For I:=0 to C do
   begin
   S:=EL.Elements[i].Name;
   if QE then
     S:='"'+S+'"';
   Write(S+': ');
   Indent;
   WriteJS(EL.Elements[i].Expr);
   if I<C then
     if WC then Write(', ') else Writeln(',');
   Undent;
   end;
  if not WC then
    begin
    Writeln('');
    Undent;
    end;
  Write('}');
end;

Procedure TJSWriter.WriteMemberExpression(el : TJSMemberExpression);

Var
  I : integer;
  A : TJSArguments;
begin
  if el is TJSNewMemberExpression then
    Write('new ');
  WriteJS(el.mexpr);
  if el is TJSDotMemberExpression then
    begin
    write('.');
    Write(TJSDotMemberExpression(el).Name);
    end
  else if el is TJSBracketMemberExpression then
    begin
    write('[');
    WriteJS(TJSBracketMemberExpression(el).Name);
    write(']');
    end
  else if (el is TJSNewMemberExpression) then
    begin
    if (Assigned(TJSNewMemberExpression(el).Args)) then
      WriteArrayLiteral(TJSNewMemberExpression(el).Args)
    else
      Write('()');
    end;
end;

Procedure TJSWriter.WriteCallExpression(El : TJSCallExpression);

Var
  I : integer;
  A : TJSArguments;
begin
  WriteJS(El.Expr);
  if Assigned(El.Args) then
    WriteArrayLiteral(EL.Args)
  else
    Write('()');
end;

Procedure TJSWriter.WriteUnary(El : TJSUnary);

Var
  S : String;

begin
  S:=El.PreFixOperator;
  if (S<>'') then
    Write(S);
  WriteJS(El.A);
  if (S='') then
    begin
    S:=El.PostFixOperator;
    if (S<>'') then
      Write(S);
    end;
end;

Procedure TJSWriter.WriteStatementList(El : TJSStatementList);

Var
  C : Boolean;
  B : Boolean;

begin
  C:=(woCompact in Options);
  B:= Not FSkipBrackets;
  if B then
    begin
    Write('{');
    if not C then writeln('');
    end;
  if Assigned(EL.A) then
    begin
    WriteJS(EL.A);
    if Assigned(EL.B) then
      begin
      if C then
        Write('; ')
      else
        Writeln(';');
      FSkipBrackets:=True;
      WriteJS(EL.B);
      end;
    if not C then writeln(';');
    end;
  if B then
    begin
    Write('}');
    if not C then writeln('');
    end;
end;

Procedure TJSWriter.WriteWithStatement(El : TJSWithStatement);
begin
   Write('with (');
   WriteJS(EL.A);
   if (woCompact in Options) then
     Write(') ')
   else
     WriteLn(')');
   Indent;
   WriteJS(EL.B);
   Undent;
end;

Procedure TJSWriter.WriteVarDeclarationList(El : TJSVariableDeclarationList);

begin
  WriteJS(EL.A);
  If Assigned(EL.B) then
    begin
    Write(', ');
    WriteJS(EL.B);
    end;
end;

Procedure TJSWriter.WriteBinary(El : TJSBinary);

Var
  S : AnsiString;
  B : Boolean;
  T : TJSToken;

begin
  Write('(');
  WriteJS(EL.A);
  B:=False;
  if (el is TJSBinaryExpression) then
    begin
    S:=TJSBinaryExpression(El).OperatorString;
    B:=TJSBinaryExpression(El).AllowCompact;
    end;
  If Not (B and (woCompact in Options)) then
    S:=' '+S+' ';
  Write(s);
  WriteJS(EL.B);
  Write(')');
end;

Procedure TJSWriter.WriteConditionalExpression(El : TJSConditionalExpression);

begin
  write('(');
  WriteJS(EL.A);
  write(' ? ');
  WriteJS(EL.B);
  write(' : ');
  WriteJS(EL.C);
  write(')');
end;

Procedure TJSWriter.WriteAssignStatement(El : TJSAssignStatement);

Var
  S : AnsiString;
  T : TJSToken;
begin
  WriteJS(EL.LHS);
  S:=El.OperatorString;
  If Not (woCompact in Options) then
      S:=' '+S+' ';
  Write(s);
  WriteJS(EL.Expr);
end;

Procedure TJSWriter.WriteVarDeclaration(El : TJSVarDeclaration);

begin
  Write(EL.Name);
  if Assigned(EL.Init) then
    begin
    Write(' = ');
    WriteJS(EL.Init);
    end;
end;

Procedure TJSWriter.WriteIfStatement(El : TJSIfStatement);

begin
  Write('if (');
  WriteJS(EL.Cond);
  Write(') ');
  WriteJS(El.BTrue);
  if Assigned(El.BFalse) then
    begin
    Write(' else ');
    WriteJS(El.BFalse)
    end;
end;

Procedure TJSWriter.WriteForInStatement(El : TJSForInStatement);

begin
  Write('for (');
  if Assigned(El.LHS) then
    WriteJS(El.LHS);
  Write(' in ');
  if Assigned(El.List) then
    WriteJS(El.List);
  Write(') ');
  if Assigned(El.body) then
    WriteJS(El.Body);
end;

Procedure TJSWriter.WriteForStatement(El : TJSForStatement);

begin
  Write('for (');
  if Assigned(El.Init) then
    WriteJS(El.Init);
  Write('; ');
  if Assigned(El.Cond) then
    WriteJS(El.Cond);
  Write('; ');
  if Assigned(El.Incr) then
    WriteJS(El.Incr);
  Write(') ');
  if Assigned(El.body) then
    WriteJS(El.Body);
end;

Procedure TJSWriter.WriteWhileStatement(El : TJSWhileStatement);


begin
  if El is TJSDoWhileStatement then
    begin
    Write('do ');
    if Assigned(El.body) then
      WriteJS(El.Body);
    Write(' while (');
    If Assigned(El.Cond) then
      WriteJS(EL.Cond);
    Write(')');
    end
  else
    begin
    Write('while (');
    If Assigned(El.Cond) then
      WriteJS(EL.Cond);
    Write(') ');
    if Assigned(El.body) then
      WriteJS(El.Body);
    end;
end;

Procedure TJSWriter.WriteSwitchStatement(El : TJSSwitchStatement);

Var
  C : Boolean;

  Procedure WriteCaseLabel(L : TJSString);

  begin
    Write(l);
  end;

Var
  I : Integer;
  EC : TJSCaseElement;

begin
  C:=(woCompact in Options);
  Write('switch (');
  If Assigned(El.Cond) then
    WriteJS(EL.Cond);
  if C then
    Write(') {')
  else
    Writeln(') {');
  For I:=0 to EL.Cases.Count-1 do
    begin
    EC:=EL.Cases[i];
    if EC=EL.TheDefault then
      Write('default')
    else
      begin
      Write('case ');
      WriteJS(EC.Expr);
      end;
    If C then
      Write(': ')
    else
      Writeln(':');
    if Assigned(EC.Body) then
      begin
      WriteJS(EC.Body);
      if C then
        begin
        if Not ((EC.Body is TJSStatementList) or (EC.Body is TJSEmptyBlockStatement)) then
          write('; ')
        end
      else
        Writeln('');
      end;
    end;
  Write('}');
end;

Procedure TJSWriter.WriteTargetStatement(El : TJSTargetStatement);

Var
  TN : TJSString;

begin
  TN:=EL.TargetName;
  if (El is TJSForStatement) then
    WriteForStatement(TJSForStatement(El))
  else if (El is TJSSwitchStatement) then
    WriteSwitchStatement(TJSSwitchStatement(El))
  else if (El is TJSForInStatement) then
    WriteForInStatement(TJSForInStatement(El))
  else if EL is TJSWhileStatement then
    WriteWhileStatement(TJSWhileStatement(El))
  else if (EL is TJSContinueStatement) then
    begin
    if (TN<>'') then
      Write('continue '+TN)
    else
      Write('continue');
    end
  else if (EL is TJSBreakStatement) then
    begin
   if (TN<>'') then
      Write('break '+TN)
    else
      Write('break');
    end
  else
    Error('Unknown target statement class: "%s"',[EL.ClassName])
end;

Procedure TJSWriter.WriteReturnStatement(EL: TJSReturnStatement);

begin
  Write('return ');
  WriteJS(EL.Expr);
end;

Procedure TJSWriter.WriteLabeledStatement(El : TJSLabeledStatement);
begin
  if Assigned(EL.TheLabel) then
    begin
    Write(EL.TheLabel.Name);
    if woCompact in Options then
      Write(': ')
    else
      Writeln(':');
    end;
  // Target ??
  WriteJS(EL.A);
end;

Procedure TJSWriter.WriteTryStatement(el :TJSTryStatement);

Var
  C : Boolean;

begin
  C:=woCompact in Options;
  Write('try {');
  if Not C then writeln('');
  FSkipBrackets:=True;
  Indent;
  WriteJS(El.Block);
  Undent;
  If C then
    Write('} ')
  else
    begin
    Writeln('');
    Writeln('}');
    end;
  If (El is TJSTryCatchFinallyStatement) or (El is TJSTryCatchStatement) then
    begin
    Write('catch ('+El.Ident);
    If C then
      Write(') {')
    else
      Writeln(') {');
    Indent;
    WriteJS(EL.BCatch);
    Undent;
    If C then
      if (El is TJSTryCatchFinallyStatement) then
        Write('} ')
      else
        Write('}')
    else
      begin
      Writeln('');
      Writeln('}');
      end;
    end;
  If (El is TJSTryCatchFinallyStatement) or (El is TJSTryFinallyStatement) then
    begin
    If C then
      Write('finally {')
    else
      Writeln('finally {');
    Indent;
    WriteJS(EL.BFinally);
    Undent;
    If C then
      Write('}')
    else
      begin
      Writeln('');
      Writeln('}');
      end;
    end;
end;

Procedure TJSWriter.WriteFunctionBody(el : TJSFunctionBody);

begin
  if Assigned(EL.A) then
    WriteJS(EL.A);
end;

Procedure TJSWriter.WriteFunctionDeclarationStatement(El : TJSFunctionDeclarationStatement);

begin
  if Assigned(EL.AFunction) then
    WriteFuncDef(EL.AFunction);
end;

Procedure TJSWriter.WriteSourceElements(El :TJSSourceElements);

Var
  I : Integer;
  C : Boolean;
  E : TJSElement;

begin
  C:=(woCompact in Options);
  For I:=0 to EL.Statements.Count-1 do
    begin
    E:=EL.Statements.Nodes[i].Node;
    WriteJS(E);
    if Not C then
      WriteLn(';')
    else
      if I<EL.Statements.Count-1 then
        Write('; ')
      else
        Write(';')
    end;
end;


Procedure TJSWriter.WriteVariableStatement(el : TJSVariableStatement);

begin
  Write('var ');
  WriteJS(EL.A);
end;

Procedure TJSWriter.WriteJS(El: TJSElement);
begin
{$IFDEF DEBUGJSWRITER}
  if (EL<>Nil) then
    system.Writeln('WriteJS : ',EL.ClassName)
  else
    system.Writeln('WriteJS : El = Nil');
{$ENDIF}
  if (El is TJSEmptyBlockStatement ) then
    WriteEmptyBlockStatement(TJSEmptyBlockStatement(el))
  else if (El is TJSEmptyStatement) then
    WriteEmptyStatement(TJSEmptyStatement(el))
  else if (el is TJSLiteral) then
    WriteLiteral(TJSLiteral(el))
  else if (el is TJSPrimaryExpression) then
    WritePrimaryExpression(TJSPrimaryExpression(el))
  else if (el is TJSArrayLiteral) then
    WriteArrayLiteral(TJSArrayLiteral(el))
  else if (el is TJSObjectLiteral) then
    WriteObjectLiteral(TJSObjectLiteral(el))
  else if (el is TJSMemberExpression) then
    WriteMemberExpression(TJSMemberExpression(el))
  else if (el is TJSRegularExpressionLiteral) then
    WriteRegularExpressionLiteral(TJSRegularExpressionLiteral(El))
  else if (el is TJSCallExpression) then
    WriteCallExpression(TJSCallExpression(el))
  else if (el is TJSLabeledStatement) then // Before unary
    WriteLabeledStatement(TJSLabeledStatement(el))
  else if (el is TJSFunctionBody) then // Before unary
    WriteFunctionBody(TJSFunctionBody(el))
  else if (el is TJSVariableStatement) then // Before unary
    WriteVariableStatement(TJSVariableStatement(el))
  else if (el is TJSUNary) then
    WriteUnary(TJSUnary(el))
  else if (el is TJSVariableDeclarationList) then
    WriteVarDeclarationList(TJSVariableDeclarationList(el)) // Must be before binary
  else if (el is TJSStatementList) then
    WriteStatementList(TJSStatementList(el)) // Must be before binary
  else if (el is TJSWithStatement) then
    WriteWithStatement(TJSWithStatement(El)) // Must be before binary
  else if (el is TJSBinary) then
    WriteBinary(TJSBinary(el))
  else if (el is TJSConditionalExpression) then
    WriteConditionalExpression(TJSConditionalExpression(el))
  else if (el is TJSAssignStatement) then
    WriteAssignStatement(TJSAssignStatement(el))
  else if (el is TJSVarDeclaration) then
    WriteVarDeclaration(TJSVarDeclaration(el))
  else if (el is TJSIfStatement) then
    WriteIfStatement(TJSIfStatement(el))
  else if (el is TJSTargetStatement) then
    WriteTargetStatement(TJSTargetStatement(el))
  else if (el is TJSReturnStatement) then
    WriteReturnStatement(TJSReturnStatement(el))
  else if (el is TJSTryStatement) then
    WriteTryStatement(TJSTryStatement(el))
  else if (el is TJSFunctionDeclarationStatement) then
    WriteFunctionDeclarationStatement(TJSFunctionDeclarationStatement(el))
  else if (el is TJSSourceElements) then
    WriteSourceElements(TJSSourceElements(el))
  else if EL=Nil then
    Error(SErrNilNode)
  else
    Error(SErrUnknownJSClass,[El.ClassName]);
//  Write('/* '+EL.ClassName+' */');
  FSkipBrackets:=False;
end;

{ TFileWriter }

Function TFileWriter.DoWrite(Const S: AnsiString) : Integer;
begin
  Result:=Length(S);
  system.Write(FFile,S);
end;

Function TFileWriter.DoWrite(Const S: UnicodeString) : Integer;
begin
  Result:=Length(S)*SizeOf(UnicodeChar);
  system.Write(FFile,S);
end;

Constructor TFileWriter.Create(Const AFileNAme: String);
begin
  FFileName:=AFileName;
  Assign(FFile,AFileName);
  Rewrite(FFile);
end;

Destructor TFileWriter.Destroy;
begin
  Close;
  Inherited;
end;

Procedure TFileWriter.Flush;
begin
  system.Flush(FFile);
end;

Procedure TFileWriter.Close;
begin
  system.Close(FFile);
end;

{ TTextWriter }

Function TTextWriter.Write(Const S: UnicodeString) : Integer;
begin
  Result:=DoWrite(S);
end;

Function TTextWriter.Write(Const S: String) : integer;
begin
  Result:=DoWrite(S);
end;

Function TTextWriter.WriteLn(Const S: String) : Integer;
begin
  Result:=DoWrite(S)+DoWrite(sLineBreak);
end;

Function TTextWriter.Write(Const Fmt: String; Args: Array of const) : Integer;

begin
  Result:=DoWrite(Format(Fmt,Args));
end;

Function TTextWriter.WriteLn(Const Fmt: String; Args: Array of const) : integer;
begin
  Result:=WriteLn(Format(Fmt,Args));
end;

Function TTextWriter.Write(Const Args: Array of const) : Integer;

Var
  I : Integer;
  V : TVarRec;
  S : String;
  U : UnicodeString;


begin
  Result:=0;
  For I:=Low(Args) to High(Args) do
    begin
    V:=Args[i];
    S:='';
    U:='';
    case V.VType of
       vtInteger       : Str(V.VInteger,S);
       vtBoolean       : if V.VBoolean then s:='true' else s:='false';
       vtChar          : s:=V.VChar;
       vtWideChar      : U:=V.VWideChar;
       vtExtended      : Str(V.VExtended^,S);
       vtString        : S:=V.VString^;
       vtPChar         : S:=V.VPChar;
       vtPWideChar     : U:=V.VPWideChar;
       vtAnsiString    : S:=PChar(V.VAnsiString);
       vtCurrency      : Str(V.VCurrency^,S);
       vtVariant       : S:=V.VVariant^;
       vtWideString    : U:=PWideChar(V.VWideString);
       vtInt64         : Str(V.VInt64^,S);
       vtUnicodeString : U:=PWideChar(V.VUnicodeString);
       vtQWord         : Str(V.VQWord^,S);
    end;
    if (U<>'') then
      Result:=Result+Write(u)
    else if (S<>'') then
      Result:=Result+write(s);
    end;
end;

Function TTextWriter.WriteLn(Const Args: Array of const) : integer;
begin
  Result:=Write(Args)+Writeln('');
end;

end.