mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-09-06 07:13:32 +02:00
* Patch from Mattias Gaertner
- fixed writing UTF-8. - indent multi line literals, used by asm blocks - fixed writing (a+b).c git-svn-id: trunk@35502 -
This commit is contained in:
parent
14ba99ea09
commit
2fbe76532f
@ -20,7 +20,7 @@ unit jswriter;
|
||||
interface
|
||||
|
||||
uses
|
||||
{Classes, } SysUtils, jstoken, jsbase, jstree;
|
||||
SysUtils, jstoken, jsbase, jstree;
|
||||
|
||||
Type
|
||||
|
||||
@ -31,7 +31,7 @@ Type
|
||||
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.
|
||||
// All functions return the number of bytes copied to output stream.
|
||||
Function Write(Const S : UnicodeString) : Integer;
|
||||
Function Write(Const S : AnsiString) : Integer;
|
||||
Function WriteLn(Const S : AnsiString) : Integer;
|
||||
@ -58,6 +58,7 @@ Type
|
||||
end;
|
||||
|
||||
{ TBufferWriter }
|
||||
|
||||
TBytes = Array of byte;
|
||||
TBufferWriter = Class(TTextWriter)
|
||||
private
|
||||
@ -157,8 +158,7 @@ Type
|
||||
Procedure WritePrimaryExpression(El: TJSPrimaryExpression);virtual;
|
||||
Procedure WriteBinary(El: TJSBinary);virtual;
|
||||
Public
|
||||
Function EscapeString(const S: TJSString; Quote: TJSEscapeQuote = jseqDouble): String;
|
||||
Function JSStringToStr(const S: TJSString): string;
|
||||
Function EscapeString(const S: TJSString; Quote: TJSEscapeQuote = jseqDouble): TJSString;
|
||||
Constructor Create(AWriter : TTextWriter);
|
||||
Constructor Create(Const AFileName : String);
|
||||
Destructor Destroy; override;
|
||||
@ -172,12 +172,31 @@ Type
|
||||
end;
|
||||
EJSWriter = Class(Exception);
|
||||
|
||||
Function UTF16ToUTF8(const S: UnicodeString): string;
|
||||
|
||||
implementation
|
||||
|
||||
Resourcestring
|
||||
SErrUnknownJSClass = 'Unknown javascript element class : %s';
|
||||
SErrNilNode = 'Nil node in Javascript';
|
||||
|
||||
function HexDump(p: PChar; Count: integer): string;
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
Result:='';
|
||||
for i:=0 to Count-1 do
|
||||
Result:=Result+HexStr(ord(p[i]),2);
|
||||
end;
|
||||
|
||||
function UTF16ToUTF8(const S: UnicodeString): string;
|
||||
begin
|
||||
Result:=UTF8Encode(S);
|
||||
// prevent UTF8 codepage appear in the strings - we don't need codepage
|
||||
// conversion magic
|
||||
SetCodePage(RawByteString(Result), CP_ACP, False);
|
||||
end;
|
||||
|
||||
{ TBufferWriter }
|
||||
|
||||
function TBufferWriter.GetBufferLength: Integer;
|
||||
@ -332,13 +351,13 @@ end;
|
||||
procedure TJSWriter.Write(const U: UnicodeString);
|
||||
|
||||
Var
|
||||
S : UTF8String;
|
||||
S : String;
|
||||
|
||||
begin
|
||||
WriteIndent;
|
||||
if UseUTF8 then
|
||||
begin
|
||||
S:=UTF8Encode(U);
|
||||
S:=UTF16ToUTF8(U);
|
||||
FLinePos:=FLinePos+Writer.Write(S);
|
||||
end
|
||||
else
|
||||
@ -370,12 +389,12 @@ end;
|
||||
|
||||
procedure TJSWriter.WriteLn(const U: UnicodeString);
|
||||
Var
|
||||
S : UTF8String;
|
||||
S : String;
|
||||
|
||||
begin
|
||||
if UseUTF8 then
|
||||
begin
|
||||
S:=UTF8Encode(U);
|
||||
S:=UTF16ToUTF8(U);
|
||||
Writeln(S);
|
||||
end
|
||||
else
|
||||
@ -387,81 +406,153 @@ begin
|
||||
end;
|
||||
|
||||
function TJSWriter.EscapeString(const S: TJSString; Quote: TJSEscapeQuote
|
||||
): String;
|
||||
): TJSString;
|
||||
|
||||
Var
|
||||
I,J,L : Integer;
|
||||
P : TJSPChar;
|
||||
R: TJSString;
|
||||
|
||||
begin
|
||||
I:=1;
|
||||
J:=1;
|
||||
Result:='';
|
||||
R:='';
|
||||
L:=Length(S);
|
||||
P:=TJSPChar(S);
|
||||
While I<=L do
|
||||
begin
|
||||
if (P^ in [#0..#31,'"','''','/','\']) then
|
||||
begin
|
||||
Result:=Result+JSStringToStr(Copy(S,J,I-J));
|
||||
R:=R+Copy(S,J,I-J);
|
||||
Case P^ of
|
||||
'\' : Result:=Result+'\\';
|
||||
'/' : Result:=Result+'\/';
|
||||
'"' : if Quote=jseqSingle then Result:=Result+'"' else Result:=Result+'\"';
|
||||
'''': if Quote=jseqDouble then Result:=Result+'''' else Result:=Result+'\''';
|
||||
#0..#7,#11,#14..#31: Result:=Result+'\x'+hexStr(ord(P^),2);
|
||||
#8 : Result:=Result+'\b';
|
||||
#9 : Result:=Result+'\t';
|
||||
#10 : Result:=Result+'\n';
|
||||
#12 : Result:=Result+'\f';
|
||||
#13 : Result:=Result+'\r';
|
||||
'\' : R:=R+'\\';
|
||||
'/' : R:=R+'\/';
|
||||
'"' : if Quote=jseqSingle then R:=R+'"' else R:=R+'\"';
|
||||
'''': if Quote=jseqDouble then R:=R+'''' else R:=R+'\''';
|
||||
#0..#7,#11,#14..#31: R:=R+'\x'+TJSString(hexStr(ord(P^),2));
|
||||
#8 : R:=R+'\b';
|
||||
#9 : R:=R+'\t';
|
||||
#10 : R:=R+'\n';
|
||||
#12 : R:=R+'\f';
|
||||
#13 : R:=R+'\r';
|
||||
end;
|
||||
J:=I+1;
|
||||
end;
|
||||
Inc(I);
|
||||
Inc(P);
|
||||
end;
|
||||
Result:=Result+JSStringToStr(Copy(S,J,I-1));
|
||||
end;
|
||||
|
||||
function TJSWriter.JSStringToStr(const S: TJSString): string;
|
||||
begin
|
||||
if UseUTF8 then
|
||||
Result:=UTF8Encode(S)
|
||||
else
|
||||
Result:=String(S);
|
||||
R:=R+Copy(S,J,I-1);
|
||||
Result:=R;
|
||||
end;
|
||||
|
||||
procedure TJSWriter.WriteValue(V: TJSValue);
|
||||
const
|
||||
TabWidth = 4;
|
||||
|
||||
function GetLineIndent(var p: PWideChar): integer;
|
||||
var
|
||||
h: PWideChar;
|
||||
begin
|
||||
h:=p;
|
||||
Result:=0;
|
||||
repeat
|
||||
case h^ of
|
||||
#0: break;
|
||||
#9: Result:=Result+(TabWidth-Result mod TabWidth);
|
||||
' ': inc(Result);
|
||||
else break;
|
||||
end;
|
||||
inc(h);
|
||||
until false;
|
||||
p:=h;
|
||||
end;
|
||||
|
||||
function SkipToNextLineStart(p: PWideChar): PWideChar;
|
||||
begin
|
||||
repeat
|
||||
case p^ of
|
||||
#0: break;
|
||||
#10,#13:
|
||||
begin
|
||||
if (p[1] in [#10,#13]) and (p^<>p[1]) then
|
||||
inc(p,2)
|
||||
else
|
||||
inc(p);
|
||||
break;
|
||||
end
|
||||
else inc(p);
|
||||
end;
|
||||
until false;
|
||||
Result:=p;
|
||||
end;
|
||||
|
||||
Var
|
||||
S : String;
|
||||
JS: TJSString;
|
||||
p, StartP: PWideChar;
|
||||
MinIndent, CurLineIndent: Integer;
|
||||
begin
|
||||
if V.CustomValue<>'' then
|
||||
S:=JSStringToStr(V.CustomValue)
|
||||
else
|
||||
Case V.ValueType of
|
||||
jstUNDEFINED : S:='undefined';
|
||||
jstNull : s:='null';
|
||||
jstBoolean : if V.AsBoolean then s:='true' else s:='false';
|
||||
jstString :
|
||||
begin
|
||||
JS:=V.AsString;
|
||||
if Pos('"',JS)>0 then
|
||||
S:=''''+EscapeString(JS,jseqSingle)+''''
|
||||
else
|
||||
S:='"'+EscapeString(JS,jseqDouble)+'"';
|
||||
end;
|
||||
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 : ;
|
||||
begin
|
||||
JS:=V.CustomValue;
|
||||
if JS='' then exit;
|
||||
|
||||
p:=SkipToNextLineStart(PWideChar(JS));
|
||||
if p^=#0 then
|
||||
begin
|
||||
// simple value
|
||||
Write(JS);
|
||||
exit;
|
||||
end;
|
||||
|
||||
// multi line value
|
||||
|
||||
// find minimum indent
|
||||
MinIndent:=-1;
|
||||
repeat
|
||||
CurLineIndent:=GetLineIndent(p);
|
||||
if (MinIndent<0) or (MinIndent>CurLineIndent) then
|
||||
MinIndent:=CurLineIndent;
|
||||
p:=SkipToNextLineStart(p);
|
||||
until p^=#0;
|
||||
|
||||
// write value lines indented
|
||||
p:=PWideChar(JS);
|
||||
GetLineIndent(p); // the first line is already indented, skip
|
||||
repeat
|
||||
StartP:=p;
|
||||
p:=SkipToNextLineStart(StartP);
|
||||
Write(copy(JS,StartP-PWideChar(JS)+1,p-StartP));
|
||||
if p^=#0 then break;
|
||||
CurLineIndent:=GetLineIndent(p);
|
||||
Write(StringOfChar(FIndentChar,FCurIndent+CurLineIndent-MinIndent));
|
||||
until false;
|
||||
|
||||
exit;
|
||||
end;
|
||||
Case V.ValueType of
|
||||
jstUNDEFINED : S:='undefined';
|
||||
jstNull : s:='null';
|
||||
jstBoolean : if V.AsBoolean then s:='true' else s:='false';
|
||||
jstString :
|
||||
begin
|
||||
JS:=V.AsString;
|
||||
if Pos('"',JS)>0 then
|
||||
JS:=''''+EscapeString(JS,jseqSingle)+''''
|
||||
else
|
||||
JS:='"'+EscapeString(JS,jseqDouble)+'"';
|
||||
Write(JS);
|
||||
exit;
|
||||
end;
|
||||
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;
|
||||
|
||||
@ -680,10 +771,24 @@ end;
|
||||
|
||||
procedure TJSWriter.WriteMemberExpression(El: TJSMemberExpression);
|
||||
|
||||
var
|
||||
MExpr: TJSElement;
|
||||
begin
|
||||
if El is TJSNewMemberExpression then
|
||||
Write('new ');
|
||||
WriteJS(El.MExpr);
|
||||
MExpr:=El.MExpr;
|
||||
if (MExpr is TJSPrimaryExpression)
|
||||
or (MExpr is TJSDotMemberExpression)
|
||||
or (MExpr is TJSBracketMemberExpression)
|
||||
or (MExpr is TJSCallExpression)
|
||||
or (MExpr is TJSLiteral) then
|
||||
WriteJS(MExpr)
|
||||
else
|
||||
begin
|
||||
Write('(');
|
||||
WriteJS(MExpr);
|
||||
Write(')');
|
||||
end;
|
||||
if El is TJSDotMemberExpression then
|
||||
begin
|
||||
write('.');
|
||||
@ -1309,23 +1414,23 @@ begin
|
||||
Result:=DoWrite(S);
|
||||
end;
|
||||
|
||||
Function TTextWriter.Write(Const S: String) : integer;
|
||||
Function TTextWriter.Write(Const S: AnsiString) : integer;
|
||||
begin
|
||||
Result:=DoWrite(S);
|
||||
end;
|
||||
|
||||
Function TTextWriter.WriteLn(Const S: String) : Integer;
|
||||
Function TTextWriter.WriteLn(Const S: AnsiString) : Integer;
|
||||
begin
|
||||
Result:=DoWrite(S)+DoWrite(sLineBreak);
|
||||
end;
|
||||
|
||||
Function TTextWriter.Write(Const Fmt: String; Args: Array of const) : Integer;
|
||||
Function TTextWriter.Write(Const Fmt: AnsiString; Args: Array of const) : Integer;
|
||||
|
||||
begin
|
||||
Result:=DoWrite(Format(Fmt,Args));
|
||||
end;
|
||||
|
||||
Function TTextWriter.WriteLn(Const Fmt: String; Args: Array of const) : integer;
|
||||
Function TTextWriter.WriteLn(Const Fmt: AnsiString; Args: Array of const) : integer;
|
||||
begin
|
||||
Result:=WriteLn(Format(Fmt,Args));
|
||||
end;
|
||||
|
Loading…
Reference in New Issue
Block a user