pastojs: test UTF-16 surrogate

git-svn-id: trunk@38259 -
This commit is contained in:
Mattias Gaertner 2018-02-16 19:21:40 +00:00
parent fc8e95f8f5
commit fb2a664640
4 changed files with 568 additions and 84 deletions

View File

@ -3201,7 +3201,7 @@ var
begin begin
Result:=''; Result:='';
{$IFDEF VerbosePas2JS} {$IFDEF VerbosePas2JS}
writeln('TPasToJSConverter.ExtractPasStringLiteral "',S,'"'); writeln('TPasToJSConverter.ExtractPasStringLiteral S="',S,'" ',RawStrToCaption(S,100),' ',length(S));
{$ENDIF} {$ENDIF}
if S='' then if S='' then
RaiseInternalError(20170207154543); RaiseInternalError(20170207154543);
@ -3221,7 +3221,7 @@ begin
'''': '''':
begin begin
if p>StartP then if p>StartP then
Result:=Result+TJSString(copy(S,StartP-PChar(S)+1,p-StartP)); Result:=Result+TJSString(UTF8Decode(copy(S,StartP-PChar(S)+1,p-StartP)));
inc(p); inc(p);
StartP:=p; StartP:=p;
if p^<>'''' then if p^<>'''' then
@ -3235,7 +3235,7 @@ begin
end; end;
until false; until false;
if p>StartP then if p>StartP then
Result:=Result+TJSString(copy(S,StartP-PChar(S)+1,p-StartP)); Result:=Result+TJSString(UTF8Decode(copy(S,StartP-PChar(S)+1,p-StartP)));
end; end;
'#': '#':
begin begin
@ -3301,7 +3301,11 @@ begin
end; end;
until false; until false;
{$IFDEF VerbosePas2JS} {$IFDEF VerbosePas2JS}
{AllowWriteln}
writeln('TPasToJSConverter.ExtractPasStringLiteral Result="',Result,'"'); writeln('TPasToJSConverter.ExtractPasStringLiteral Result="',Result,'"');
//for i:=1 to length(Result) do
// writeln(' Result[',i,']',HexStr(ord(Result[i]),4));
{AllowWriteln-}
{$ENDIF} {$ENDIF}
end; end;

View File

@ -16,18 +16,32 @@
Abstract: Abstract:
Write and read a precompiled module (pju). Write and read a precompiled module (pju).
Default format is gzipped json Works:
- store used source files and checksums
- store compiler flags
- restore module as json
- restore types
- references to built in symbols via Id
- references to module's TPasElement via Id
- resolving forward references
- restore resolver scopes
- restore resolved references and access flags
Store whole unit, except all ToDo:
procedure declarations, proc bodies, finalization/initialization sections are - test restoring types
replaced by - test restoring expressions
-precompiled code - interface/implementation references
-lists of references - store converted proc implementation
-local consts - store references
The useanalyzer needs the references - TPas2jsUseAnalyzer. - local const
- use stored converted proc implementation
- store converted initialization/finalization
- use stored converted initialization/finalization
- uses section
- external references
- stop after uses section and continue reading
- gzipped json
Due to uses cycles, ability to stop read after interface uses and implementation uses
Needs function to find out where it stopped, and a procedure ReadContinue
} }
unit Pas2JsFiler; unit Pas2JsFiler;
@ -411,6 +425,16 @@ const
'ParamToUnknownProc' 'ParamToUnknownProc'
); );
PJUResolvedReferenceFlagNames: array[TResolvedReferenceFlag] of string = (
'Dot',
'ImplicitCall',
'NoImplicitCall',
'NewInst',
'FreeInst',
'VMT',
'ConstInh'
);
type type
{ TPJUInitialFlags } { TPJUInitialFlags }
@ -514,6 +538,7 @@ type
function GetDefaultClassScopeFlags(Scope: TPas2JSClassScope): TPasClassScopeFlags; virtual; function GetDefaultClassScopeFlags(Scope: TPas2JSClassScope): TPasClassScopeFlags; virtual;
function GetDefaultProcModifiers(Proc: TPasProcedure): TProcedureModifiers; virtual; function GetDefaultProcModifiers(Proc: TPasProcedure): TProcedureModifiers; virtual;
function GetDefaultProcTypeModifiers(Proc: TPasProcedureType): TProcTypeModifiers; virtual; function GetDefaultProcTypeModifiers(Proc: TPasProcedureType): TProcTypeModifiers; virtual;
function GetDefaultExprHasEvalValue(Expr: TPasExpr): boolean; virtual;
function GetSrcCheckSum(aFilename: string): TPJUSourceFileChecksum; virtual; function GetSrcCheckSum(aFilename: string): TPJUSourceFileChecksum; virtual;
function GetElementReference(El: TPasElement; AutoCreate: boolean = true): TPJUFilerElementRef; function GetElementReference(El: TPasElement; AutoCreate: boolean = true): TPJUFilerElementRef;
public public
@ -594,6 +619,8 @@ type
procedure WriteElement(Obj: TJSONObject; El: TPasElement; aContext: TPJUWriterContext); virtual; procedure WriteElement(Obj: TJSONObject; El: TPasElement; aContext: TPJUWriterContext); virtual;
procedure WriteElType(Obj: TJSONObject; El: TPasElement; const PropName: string; aType: TPasType; aContext: TPJUWriterContext); virtual; procedure WriteElType(Obj: TJSONObject; El: TPasElement; const PropName: string; aType: TPasType; aContext: TPJUWriterContext); virtual;
procedure WriteVarModifiers(Obj: TJSONObject; const PropName: string; const Value, DefaultValue: TVariableModifiers); virtual; procedure WriteVarModifiers(Obj: TJSONObject; const PropName: string; const Value, DefaultValue: TVariableModifiers); virtual;
procedure WriteResolvedRefFlags(Obj: TJSONObject; const PropName: string; const Value, DefaultValue: TResolvedReferenceFlags); virtual;
procedure WriteExprCustomData(Obj: TJSONObject; Expr: TPasExpr; aContext: TPJUWriterContext); virtual;
procedure WriteExpr(Obj: TJSONObject; Parent: TPasElement; procedure WriteExpr(Obj: TJSONObject; Parent: TPasElement;
const PropName: string; Expr: TPasExpr; aContext: TPJUWriterContext); virtual; const PropName: string; Expr: TPasExpr; aContext: TPJUWriterContext); virtual;
procedure WritePasExpr(Obj: TJSONObject; Expr: TPasExpr; procedure WritePasExpr(Obj: TJSONObject; Expr: TPasExpr;
@ -647,7 +674,7 @@ type
destructor Destroy; override; destructor Destroy; override;
procedure Clear; override; procedure Clear; override;
procedure WritePJU(aResolver: TPas2JSResolver; procedure WritePJU(aResolver: TPas2JSResolver;
InitFlags: TPJUInitialFlags; aStream: TStream); virtual; InitFlags: TPJUInitialFlags; aStream: TStream; Compressed: boolean); virtual;
function WriteJSON(aResolver: TPas2JSResolver; function WriteJSON(aResolver: TPas2JSResolver;
InitFlags: TPJUInitialFlags): TJSONObject; virtual; InitFlags: TPJUInitialFlags): TJSONObject; virtual;
function IndexOfSourceFile(const Filename: string): integer; function IndexOfSourceFile(const Filename: string): integer;
@ -716,6 +743,7 @@ type
procedure Set_ModScope_RangeErrorConstructor(RefEl: TPasElement; Data: TObject); procedure Set_ModScope_RangeErrorConstructor(RefEl: TPasElement; Data: TObject);
procedure Set_PropertyScope_AncestorProp(RefEl: TPasElement; Data: TObject); procedure Set_PropertyScope_AncestorProp(RefEl: TPasElement; Data: TObject);
procedure Set_ProcedureScope_Overridden(RefEl: TPasElement; Data: TObject); procedure Set_ProcedureScope_Overridden(RefEl: TPasElement; Data: TObject);
procedure Set_ResolvedReference_Declaration(RefEl: TPasElement; Data: TObject);
protected protected
procedure RaiseMsg(Id: int64; const Msg: string = ''); overload; override; procedure RaiseMsg(Id: int64; const Msg: string = ''); overload; override;
function CheckJSONArray(Data: TJSONData; El: TPasElement; const PropName: string): TJSONArray; function CheckJSONArray(Data: TJSONData; El: TPasElement; const PropName: string): TJSONArray;
@ -744,7 +772,6 @@ type
procedure ReadSectionScope(Obj: TJSONObject; Scope: TPasSectionScope; aContext: TPJUReaderContext); virtual; procedure ReadSectionScope(Obj: TJSONObject; Scope: TPasSectionScope; aContext: TPJUReaderContext); virtual;
procedure ReadSection(Obj: TJSONObject; Section: TPasSection; aContext: TPJUReaderContext); virtual; procedure ReadSection(Obj: TJSONObject; Section: TPasSection; aContext: TPJUReaderContext); virtual;
procedure ReadDeclarations(Obj: TJSONObject; Section: TPasSection; aContext: TPJUReaderContext); virtual; procedure ReadDeclarations(Obj: TJSONObject; Section: TPasSection; aContext: TPJUReaderContext); virtual;
procedure ReadDeclaration(Obj: TJSONObject; Section: TPasSection; aContext: TPJUReaderContext); virtual;
function ReadElement(Obj: TJSONObject; Parent: TPasElement; aContext: TPJUReaderContext): TPasElement; virtual; function ReadElement(Obj: TJSONObject; Parent: TPasElement; aContext: TPJUReaderContext): TPasElement; virtual;
function ReadElementProperty(Obj: TJSONObject; Parent: TPasElement; function ReadElementProperty(Obj: TJSONObject; Parent: TPasElement;
const PropName: string; BaseClass: TPTreeElement; aContext: TPJUReaderContext): TPasElement; virtual; const PropName: string; BaseClass: TPTreeElement; aContext: TPJUReaderContext): TPasElement; virtual;
@ -754,6 +781,9 @@ type
const PropName: string; ListOfElements: TFPList; aContext: TPJUReaderContext); virtual; const PropName: string; ListOfElements: TFPList; aContext: TPJUReaderContext); virtual;
procedure ReadElType(Obj: TJSONObject; const PropName: string; El: TPasElement; procedure ReadElType(Obj: TJSONObject; const PropName: string; El: TPasElement;
const Setter: TOnSetElReference; aContext: TPJUReaderContext); virtual; const Setter: TOnSetElReference; aContext: TPJUReaderContext); virtual;
function ReadResolvedRefFlags(Obj: TJSONObject; El: TPasElement;
const PropName: string; const DefaultValue: TResolvedReferenceFlags): TResolvedReferenceFlags; virtual;
procedure ReadExprCustomData(Obj: TJSONObject; Expr: TPasExpr; aContext: TPJUReaderContext); virtual;
function ReadExpr(Obj: TJSONObject; Parent: TPasElement; const PropName: string; function ReadExpr(Obj: TJSONObject; Parent: TPasElement; const PropName: string;
aContext: TPJUReaderContext): TPasExpr; virtual; aContext: TPJUReaderContext): TPasExpr; virtual;
procedure ReadPasScope(Obj: TJSONObject; Scope: TPasScope; aContext: TPJUReaderContext); virtual; procedure ReadPasScope(Obj: TJSONObject; Scope: TPasScope; aContext: TPJUReaderContext); virtual;
@ -815,6 +845,7 @@ type
procedure ReadOperator(Obj: TJSONObject; El: TPasOperator; aContext: TPJUReaderContext); virtual; procedure ReadOperator(Obj: TJSONObject; El: TPasOperator; aContext: TPJUReaderContext); virtual;
// ToDo: procedure ReadExternalReferences(ParentJSON: TJSONObject); virtual; // ToDo: procedure ReadExternalReferences(ParentJSON: TJSONObject); virtual;
procedure ResolvePending; virtual; procedure ResolvePending; virtual;
procedure ReadSystemSymbols(Obj: TJSONObject; ErrorEl: TPasElement); virtual;
public public
constructor Create; override; constructor Create; override;
destructor Destroy; override; destructor Destroy; override;
@ -1257,6 +1288,17 @@ begin
if Proc=nil then ; if Proc=nil then ;
end; end;
function TPJUFiler.GetDefaultExprHasEvalValue(Expr: TPasExpr): boolean;
var
C: TClass;
begin
if Expr.Parent is TPasExpr then exit(false);
C:=Expr.ClassType;
if C=TArrayValues then exit(false);
if C=TRecordValues then exit(false);
Result:=true;
end;
function TPJUFiler.GetSrcCheckSum(aFilename: string): TPJUSourceFileChecksum; function TPJUFiler.GetSrcCheckSum(aFilename: string): TPJUSourceFileChecksum;
var var
p: PChar; p: PChar;
@ -1270,19 +1312,21 @@ function TPJUFiler.GetElementReference(El: TPasElement; AutoCreate: boolean
): TPJUFilerElementRef; ): TPJUFilerElementRef;
var var
Node: TAVLTreeNode; Node: TAVLTreeNode;
Data: TObject; MyEl: TPasElement;
begin begin
{$IFDEF VerbosePJUFiler}
//writeln('TPJUFiler.GetElementReference ',GetObjName(El));
{$ENDIF}
if El.CustomData is TResElDataBuiltInSymbol then if El.CustomData is TResElDataBuiltInSymbol then
begin begin
// built-in symbol -> redirect to symbol of this module // built-in symbol -> redirect to symbol of this module
Data:=El.CustomData; MyEl:=Resolver.FindLocalBuiltInSymbol(El);
if Data is TResElDataBaseType then if MyEl=nil then
El:=Resolver.BaseTypes[TResElDataBaseType(Data).BaseType] RaiseMsg(20180207121004,El,GetObjName(El.CustomData));
else if Data is TResElDataBuiltInProc then El:=MyEl;
El:=TResElDataBuiltInProc(Data).Proc end
else else if El is TPasUnresolvedSymbolRef then
RaiseMsg(20180207121004,El,Data.ClassName); RaiseMsg(20180215190054,El,GetObjName(El));
end;
Node:=FElementRefs.FindKey(El,@CompareElWithPJUFilerElementRef); Node:=FElementRefs.FindKey(El,@CompareElWithPJUFilerElementRef);
if Node<>nil then if Node<>nil then
Result:=TPJUFilerElementRef(Node.Data) Result:=TPJUFilerElementRef(Node.Data)
@ -1656,8 +1700,6 @@ begin
Obj.Add('HintMessage',El.HintMessage); Obj.Add('HintMessage',El.HintMessage);
// not needed El.DocComment // not needed El.DocComment
// ToDo: El.CustomData
end; end;
procedure TPJUWriter.WriteModuleScopeFlags(Obj: TJSONObject; const Value, procedure TPJUWriter.WriteModuleScopeFlags(Obj: TJSONObject; const Value,
@ -2171,7 +2213,6 @@ begin
// reference // reference
AddReferenceToObj(Obj,PropName,aType); AddReferenceToObj(Obj,PropName,aType);
end; end;
RaiseMsg(20180206183542,El);
end; end;
procedure TPJUWriter.WriteVarModifiers(Obj: TJSONObject; procedure TPJUWriter.WriteVarModifiers(Obj: TJSONObject;
@ -2187,6 +2228,69 @@ begin
AddArrayFlag(Obj,Arr,PropName,PJUVarModifierNames[f],f in Value); AddArrayFlag(Obj,Arr,PropName,PJUVarModifierNames[f],f in Value);
end; end;
procedure TPJUWriter.WriteResolvedRefFlags(Obj: TJSONObject;
const PropName: string; const Value, DefaultValue: TResolvedReferenceFlags);
var
Arr: TJSONArray;
f: TResolvedReferenceFlag;
begin
if Value=DefaultValue then exit;
Arr:=nil;
for f in TResolvedReferenceFlag do
if (f in Value)<>(f in DefaultValue) then
AddArrayFlag(Obj,Arr,PropName,PJUResolvedReferenceFlagNames[f],f in Value);
end;
procedure TPJUWriter.WriteExprCustomData(Obj: TJSONObject; Expr: TPasExpr;
aContext: TPJUWriterContext);
procedure CheckNext(Data: TObject);
var
Value: TResEvalValue;
DefHasEvalValue: Boolean;
begin
DefHasEvalValue:=GetDefaultExprHasEvalValue(Expr);
//writeln('TPJUWriter.WriteExprCustomData.CheckNext Expr=',GetObjName(Expr),' Parent=',GetObjName(Expr.Parent),' Def=',DefHasEvalValue,' Data=',GetObjName(Data));
if Data=nil then
begin
if DefHasEvalValue then
Obj.Add('Eval',false);
end
else if Data is TResEvalValue then
begin
Value:=TResEvalValue(Data);
if not DefHasEvalValue then
Obj.Add('Eval',true);
// value is not stored
if Value.CustomData<>nil then
RaiseMsg(20180215143045,Expr,GetObjName(Data));
end
else
RaiseMsg(20180215143108,Expr,GetObjName(Data));
end;
var
Ref: TResolvedReference;
begin
if Expr.CustomData=nil then exit;
if Expr.CustomData is TResolvedReference then
begin
Ref:=TResolvedReference(Expr.CustomData);
WriteResolvedRefFlags(Obj,'RefFlags',Ref.Flags,[]);
if Ref.Access<>rraRead then
Obj.Add('RefAccess',PJUResolvedRefAccessNames[Ref.Access]);
if Ref.WithExprScope<>nil then
RaiseMsg(20180215132828,Expr);
if Ref.Context<>nil then
RaiseMsg(20180215132849,Expr,GetObjName(Ref.Context));
AddReferenceToObj(Obj,'RefDecl',Ref.Declaration);
CheckNext(Ref.CustomData);
end
else
CheckNext(Expr.CustomData);
if aContext<>nil then ;
end;
procedure TPJUWriter.WriteExpr(Obj: TJSONObject; Parent: TPasElement; procedure TPJUWriter.WriteExpr(Obj: TJSONObject; Parent: TPasElement;
const PropName: string; Expr: TPasExpr; aContext: TPJUWriterContext); const PropName: string; Expr: TPasExpr; aContext: TPJUWriterContext);
var var
@ -2199,6 +2303,7 @@ begin
SubObj:=TJSONObject.Create; SubObj:=TJSONObject.Create;
Obj.Add(PropName,SubObj); Obj.Add(PropName,SubObj);
WriteElement(SubObj,Expr,aContext); WriteElement(SubObj,Expr,aContext);
WriteExprCustomData(SubObj,Expr,aContext);
end; end;
procedure TPJUWriter.WritePasExpr(Obj: TJSONObject; Expr: TPasExpr; procedure TPJUWriter.WritePasExpr(Obj: TJSONObject; Expr: TPasExpr;
@ -2246,8 +2351,8 @@ end;
procedure TPJUWriter.WriteBinaryExpr(Obj: TJSONObject; Expr: TBinaryExpr; procedure TPJUWriter.WriteBinaryExpr(Obj: TJSONObject; Expr: TBinaryExpr;
aContext: TPJUWriterContext); aContext: TPJUWriterContext);
begin begin
WriteExpr(Obj,Expr,'left',Expr.left,aContext); WriteExpr(Obj,Expr,'Left',Expr.left,aContext);
WriteExpr(Obj,Expr,'right',Expr.right,aContext); WriteExpr(Obj,Expr,'Right',Expr.right,aContext);
WritePasExpr(Obj,Expr,false,eopAdd,aContext); WritePasExpr(Obj,Expr,false,eopAdd,aContext);
end; end;
@ -2718,22 +2823,24 @@ begin
begin begin
Ref:=TPJUFilerElementRef(Node.Data); Ref:=TPJUFilerElementRef(Node.Data);
Node:=FElementRefs.FindSuccessor(Node); Node:=FElementRefs.FindSuccessor(Node);
if Ref.Pending=nil then continue; if Ref.Pending=nil then
continue; // not used
El:=Ref.Element; El:=Ref.Element;
Data:=El.CustomData; Data:=El.CustomData;
if Data is TResElDataBuiltInSymbol then if Data is TResElDataBuiltInSymbol then
begin begin
// add built-in symbol to System array // add built-in symbol to System array
if El.GetModule<>Resolver.RootElement then if El<>Resolver.FindLocalBuiltInSymbol(El) then
RaiseMsg(20180207124914,El); RaiseMsg(20180207124914,El);
if SystemArr=nil then if SystemArr=nil then
begin begin
SystemArr:=TJSONArray.Create; SystemArr:=TJSONArray.Create;
ParentJSON.Add('System'); ParentJSON.Add('System',SystemArr);
end; end;
Obj:=TJSONObject.Create; Obj:=TJSONObject.Create;
SystemArr.Add(Obj); SystemArr.Add(Obj);
Obj.Add('Name',El.Name); Obj.Add('Name',El.Name);
// Ref.Id is written in ResolvePendingElRefs
if Data is TResElDataBuiltInProc then if Data is TResElDataBuiltInProc then
case TResElDataBuiltInProc(Data).BuiltIn of case TResElDataBuiltInProc(Data).BuiltIn of
bfStrFunc: Obj.Add('Type','Func'); bfStrFunc: Obj.Add('Type','Func');
@ -2748,7 +2855,7 @@ begin
if ExtArr=nil then if ExtArr=nil then
begin begin
ExtArr:=TJSONArray.Create; ExtArr:=TJSONArray.Create;
ParentJSON.Add('External'); ParentJSON.Add('External',ExtArr);
end; end;
Obj:=TJSONObject.Create; Obj:=TJSONObject.Create;
ExtArr.Add(Obj); ExtArr.Add(Obj);
@ -2757,6 +2864,7 @@ begin
// ToDo // ToDo
RaiseMsg(20180207115730,Ref.Element); RaiseMsg(20180207115730,Ref.Element);
Ref.Obj:=Obj; Ref.Obj:=Obj;
// Ref.Id is written in ResolvePendingElRefs
ResolvePendingElRefs(Ref); ResolvePendingElRefs(Ref);
end; end;
end; end;
@ -2781,13 +2889,141 @@ begin
end; end;
procedure TPJUWriter.WritePJU(aResolver: TPas2JSResolver; procedure TPJUWriter.WritePJU(aResolver: TPas2JSResolver;
InitFlags: TPJUInitialFlags; aStream: TStream); InitFlags: TPJUInitialFlags; aStream: TStream; Compressed: boolean);
var
CurIndent: integer;
Spaces: string;
procedure WriteString(const s: string);
begin
if s='' then exit;
aStream.Write(s[1],length(s));
end;
procedure WriteChar(const c: char);
begin
aStream.Write(c,1);
end;
procedure WriteLn;
begin
WriteString(sLineBreak);
if CurIndent>0 then
aStream.Write(Spaces[1],CurIndent);
end;
procedure Indent;
begin
if Compressed then exit;
inc(CurIndent,2);
if CurIndent>length(Spaces) then
Spaces:=Spaces+' ';
end;
procedure Unindent;
begin
if Compressed then exit;
dec(CurIndent,2);
end;
procedure WriteData(Data: TJSONData); forward;
procedure WriteObj(Obj: TJSONObject);
var
i: Integer;
Name: String;
begin
WriteChar('{');
if not Compressed then
begin
Indent;
WriteLn;
end;
for i:=0 to Obj.Count-1 do
begin
if i>0 then
begin
WriteChar(',');
if not Compressed then
WriteLn;
end;
Name:=Obj.Names[i];
WriteChar('"');
if IsValidIdent(Name) then
WriteString(Name)
else
WriteString(StringToJSONString(Name,false));
WriteString('":');
WriteData(Obj.Elements[Name]);
end;
if not Compressed then
begin
Unindent;
WriteLn;
end;
WriteChar('}');
end;
procedure WriteArray(Arr: TJSONArray);
var
i: Integer;
begin
WriteChar('[');
if not Compressed then
begin
Indent;
WriteLn;
end;
for i:=0 to Arr.Count-1 do
begin
if i>0 then
begin
WriteChar(',');
if not Compressed then
WriteLn;
end;
WriteData(Arr[i]);
end;
if not Compressed then
begin
Unindent;
WriteLn;
end;
WriteChar(']');
end;
procedure WriteData(Data: TJSONData);
var
C: TClass;
begin
C:=Data.ClassType;
if C=TJSONObject then
WriteObj(TJSONObject(Data))
else if C=TJSONArray then
WriteArray(TJSONArray(Data))
else if C.InheritsFrom(TJSONNumber)
or (C=TJSONBoolean)
then
WriteString(Data.AsString)
else if (C=TJSONNull) then
WriteString('null')
else if C=TJSONString then
begin
WriteChar('"');
WriteString(StringToJSONString(Data.AsString));
WriteChar('"');
end
else
raise EPas2JsWriteError.Create('unknown JSON data '+GetObjName(Data));
end;
var var
aJSON: TJSONObject; aJSON: TJSONObject;
begin begin
CurIndent:=0;
aJSON:=WriteJSON(aResolver,InitFlags); aJSON:=WriteJSON(aResolver,InitFlags);
try try
aJSON.DumpJSON(aStream); WriteObj(aJSON);
finally finally
aJSON.Free; aJSON.Free;
end; end;
@ -3114,6 +3350,14 @@ begin
RaiseMsg(20180213215959,Scope.Element,GetObjName(RefEl)); RaiseMsg(20180213215959,Scope.Element,GetObjName(RefEl));
end; end;
procedure TPJUReader.Set_ResolvedReference_Declaration(RefEl: TPasElement;
Data: TObject);
var
Ref: TResolvedReference absolute Data;
begin
Ref.Declaration:=RefEl;
end;
procedure TPJUReader.RaiseMsg(Id: int64; const Msg: string); procedure TPJUReader.RaiseMsg(Id: int64; const Msg: string);
var var
E: EPas2JsReadError; E: EPas2JsReadError;
@ -3789,6 +4033,7 @@ var
Arr: TJSONArray; Arr: TJSONArray;
i: Integer; i: Integer;
Data: TJSONData; Data: TJSONData;
El: TPasElement;
begin begin
if not ReadArray(Obj,'Declarations',Arr,Section) then exit; if not ReadArray(Obj,'Declarations',Arr,Section) then exit;
{$IFDEF VerbosePJUFiler} {$IFDEF VerbosePJUFiler}
@ -3799,32 +4044,8 @@ begin
Data:=Arr[i]; Data:=Arr[i];
if not (Data is TJSONObject) then if not (Data is TJSONObject) then
RaiseMsg(20180207182304,Section,IntToStr(i)+' '+GetObjName(Data)); RaiseMsg(20180207182304,Section,IntToStr(i)+' '+GetObjName(Data));
ReadDeclaration(TJSONObject(Data),Section,aContext); El:=ReadElement(TJSONObject(Data),Section,aContext);
end;
end;
procedure TPJUReader.ReadDeclaration(Obj: TJSONObject; Section: TPasSection;
aContext: TPJUReaderContext);
var
aType, Name: string;
El: TPasConst;
begin
if not ReadString(Obj,'Type',aType,Section) then
RaiseMsg(20180207183050,Section);
if not ReadString(Obj,'Name',Name,Section) then
RaiseMsg(20180207183415,Section);
{$IFDEF VerbosePJUFiler}
writeln('TPJUReader.ReadDeclaration ',GetObjName(Section),' Type="',aType,'" Name="',Name,'"');
{$ENDIF}
case aType of
'Const':
begin
El:=TPasConst.Create(Name,Section);
Section.Declarations.Add(El); Section.Declarations.Add(El);
ReadConst(Obj,TPasConst(El),aContext);
end
else
RaiseMsg(20180207183141,Section,'unknown type "'+LeftStr(aType,100)+'"');
end; end;
end; end;
@ -3885,6 +4106,8 @@ begin
'Binary': 'Binary':
begin begin
Result:=TBinaryExpr.Create(Name,Parent); Result:=TBinaryExpr.Create(Name,Parent);
TBinaryExpr(Result).Kind:=pekBinary;
TBinaryExpr(Result).OpCode:=eopAdd;
ReadBinaryExpr(Obj,TBinaryExpr(Result),aContext); ReadBinaryExpr(Obj,TBinaryExpr(Result),aContext);
end; end;
'Ident': ReadPrimitive(pekIdent); 'Ident': ReadPrimitive(pekIdent);
@ -3918,26 +4141,31 @@ begin
'A[]': 'A[]':
begin begin
Result:=TParamsExpr.Create(Parent,pekArrayParams); Result:=TParamsExpr.Create(Parent,pekArrayParams);
Result.Name:='';
ReadParamsExpr(Obj,TParamsExpr(Result),aContext); ReadParamsExpr(Obj,TParamsExpr(Result),aContext);
end; end;
'F()': 'F()':
begin begin
Result:=TParamsExpr.Create(Parent,pekFuncParams); Result:=TParamsExpr.Create(Parent,pekFuncParams);
Result.Name:='';
ReadParamsExpr(Obj,TParamsExpr(Result),aContext); ReadParamsExpr(Obj,TParamsExpr(Result),aContext);
end; end;
'[]': '[]':
begin begin
Result:=TParamsExpr.Create(Parent,pekSet); Result:=TParamsExpr.Create(Parent,pekSet);
Result.Name:='';
ReadParamsExpr(Obj,TParamsExpr(Result),aContext); ReadParamsExpr(Obj,TParamsExpr(Result),aContext);
end; end;
'RecValues': 'RecValues':
begin begin
Result:=TRecordValues.Create(Parent); Result:=TRecordValues.Create(Parent);
Result.Name:='';
ReadRecordValues(Obj,TRecordValues(Result),aContext); ReadRecordValues(Obj,TRecordValues(Result),aContext);
end; end;
'ArrValues': 'ArrValues':
begin begin
Result:=TArrayValues.Create(Parent); Result:=TArrayValues.Create(Parent);
Result.Name:='';
ReadArrayValues(Obj,TArrayValues(Result),aContext); ReadArrayValues(Obj,TArrayValues(Result),aContext);
end; end;
'ResString': 'ResString':
@ -4193,6 +4421,88 @@ begin
RaiseMsg(20180207185313,El,PropName+':'+GetObjName(Data)); RaiseMsg(20180207185313,El,PropName+':'+GetObjName(Data));
end; end;
function TPJUReader.ReadResolvedRefFlags(Obj: TJSONObject; El: TPasElement;
const PropName: string; const DefaultValue: TResolvedReferenceFlags
): TResolvedReferenceFlags;
var
Names: TStringDynArray;
Enable: TBooleanDynArray;
s: String;
f: TResolvedReferenceFlag;
i: Integer;
Found: Boolean;
Data: TJSONData;
begin
Result:=DefaultValue;
{$IFDEF VerbosePJUFiler}
writeln('TPJUReader.ReadResolvedRefFlags START');
{$ENDIF}
Data:=Obj.Find(PropName);
if Data=nil then exit;
ReadArrayFlags(Data,El,PropName,Names,Enable);
for i:=0 to length(Names)-1 do
begin
s:=Names[i];
Found:=false;
for f in TResolvedReferenceFlag do
if s=PJUResolvedReferenceFlagNames[f] then
begin
if Enable[i] then
Include(Result,f)
else
Exclude(Result,f);
Found:=true;
break;
end;
if not Found then
RaiseMsg(20180215134501,'unknown resolvedreference flag "'+s+'"');
end;
end;
procedure TPJUReader.ReadExprCustomData(Obj: TJSONObject; Expr: TPasExpr;
aContext: TPJUReaderContext);
var
Ref: TResolvedReference;
s: string;
Found, NeedEvalValue: Boolean;
a: TResolvedRefAccess;
Value: TResEvalValue;
begin
Ref:=TResolvedReference(Expr.CustomData);
if Obj.Find('RefDecl')<>nil then
begin
Ref:=TResolvedReference.Create;
Resolver.AddResolveData(Expr,Ref,lkModule);
ReadElementReference(Obj,Ref,'RefDecl',@Set_ResolvedReference_Declaration);
Ref.Flags:=ReadResolvedRefFlags(Obj,Expr,'RefFlags',[]);
Ref.Access:=rraRead;
if ReadString(Obj,'RefAccess',s,Expr) then
begin
Found:=false;
for a in TResolvedRefAccess do
if s=PJUResolvedRefAccessNames[a] then
begin
Ref.Access:=a;
Found:=true;
break;
end;
if not Found then
RaiseMsg(20180215134804,Expr,s);
end;
end;
if not ReadBoolean(Obj,'Eval',NeedEvalValue,Expr) then
NeedEvalValue:=GetDefaultExprHasEvalValue(Expr);
if NeedEvalValue then
begin
Value:=Resolver.Eval(Expr,[refAutoConst]);
if Value<>nil then
ReleaseEvalValue(Value);
end;
if aContext=nil then ;
end;
function TPJUReader.ReadExpr(Obj: TJSONObject; Parent: TPasElement; function TPJUReader.ReadExpr(Obj: TJSONObject; Parent: TPasElement;
const PropName: string; aContext: TPJUReaderContext): TPasExpr; const PropName: string; aContext: TPJUReaderContext): TPasExpr;
var var
@ -4214,6 +4524,7 @@ begin
RaiseMsg(20180210152134,Parent,PropName+' got '+s); RaiseMsg(20180210152134,Parent,PropName+' got '+s);
end; end;
Result:=TPasExpr(El); Result:=TPasExpr(El);
ReadExprCustomData(SubObj,Result,aContext);
end end
else else
RaiseMsg(20180207190200,Parent,PropName+':'+GetObjName(Data)); RaiseMsg(20180207190200,Parent,PropName+':'+GetObjName(Data));
@ -4391,12 +4702,14 @@ begin
RaiseMsg(20180203100748); RaiseMsg(20180203100748);
end; end;
Resolver.RootElement:=aModule; Resolver.RootElement:=aModule;
ReadPasElement(Obj,aModule,aContext); ReadPasElement(Obj,aModule,aContext);
// modscope
ModScope:=TPasModuleScope(Resolver.CreateScope(aModule,TPasModuleScope)); ModScope:=TPasModuleScope(Resolver.CreateScope(aModule,TPasModuleScope));
ReadModuleScope(Obj,ModScope,aContext); ReadModuleScope(Obj,ModScope,aContext);
ReadSystemSymbols(Obj,aModule);
// modscope
OldBoolSwitches:=aContext.BoolSwitches; OldBoolSwitches:=aContext.BoolSwitches;
aContext.BoolSwitches:=ModScope.BoolSwitches; aContext.BoolSwitches:=ModScope.BoolSwitches;
try try
@ -4519,8 +4832,8 @@ procedure TPJUReader.ReadBinaryExpr(Obj: TJSONObject; Expr: TBinaryExpr;
aContext: TPJUReaderContext); aContext: TPJUReaderContext);
begin begin
ReadPasExpr(Obj,Expr,false,aContext); ReadPasExpr(Obj,Expr,false,aContext);
Expr.left:=ReadExpr(Obj,Expr,'left',aContext); Expr.left:=ReadExpr(Obj,Expr,'Left',aContext);
Expr.right:=ReadExpr(Obj,Expr,'right',aContext); Expr.right:=ReadExpr(Obj,Expr,'Right',aContext);
end; end;
procedure TPJUReader.ReadBoolConstExpr(Obj: TJSONObject; Expr: TBoolConstExpr; procedure TPJUReader.ReadBoolConstExpr(Obj: TJSONObject; Expr: TBoolConstExpr;
@ -5251,12 +5564,12 @@ begin
while Node<>nil do while Node<>nil do
begin begin
Ref:=TPJUFilerElementRef(Node.Data); Ref:=TPJUFilerElementRef(Node.Data);
{$IFDEF VerbosePJUFiler}
write('TPJUReader.ResolvePending Ref.Id=',Ref.Id,' Ref.Element=',GetObjName(Ref.Element));
{$ENDIF}
Node:=FElementRefs.FindSuccessor(Node); Node:=FElementRefs.FindSuccessor(Node);
if Ref.Pending<>nil then if Ref.Pending<>nil then
begin begin
{$IFDEF VerbosePJUFiler}
writeln('TPJUReader.ResolvePending Ref.Id=',Ref.Id,' Ref.Element=',GetObjName(Ref.Element));
{$ENDIF}
if Ref.Pending.ErrorEl<>nil then if Ref.Pending.ErrorEl<>nil then
RaiseMsg(20180207194340,Ref.Pending.ErrorEl,IntToStr(Ref.Id)) RaiseMsg(20180207194340,Ref.Pending.ErrorEl,IntToStr(Ref.Id))
else else
@ -5265,6 +5578,64 @@ begin
end; end;
end; end;
procedure TPJUReader.ReadSystemSymbols(Obj: TJSONObject; ErrorEl: TPasElement);
var
Arr: TJSONArray;
Data: TJSONData;
SubObj: TJSONObject;
aName, s: string;
bt: TResolverBaseType;
El: TPasElement;
Id, i: integer;
Found: Boolean;
BuiltInProc: TResElDataBuiltInProc;
bp: TResolverBuiltInProc;
begin
if not ReadArray(Obj,'System',Arr,ErrorEl) then exit;
for i:=0 to Arr.Count-1 do
begin
Data:=Arr[i];
if not (Data is TJSONObject) then
RaiseMsg(20180215152600,ErrorEl);
SubObj:=TJSONObject(Data);
if not ReadString(SubObj,'Name',aName,ErrorEl) then
RaiseMsg(20180215153027,ErrorEl);
if not ReadInteger(SubObj,'Id',Id,ErrorEl) then
RaiseMsg(20180215153028,ErrorEl,aName);
Found:=false;
for bt in TResolverBaseType do
begin
El:=Resolver.BaseTypes[bt];
if (El<>nil) and (CompareText(El.Name,aName)=0) then
begin
AddElReference(Id,ErrorEl,El);
Found:=true;
break;
end;
end;
if not Found then
begin
for bp in TResolverBuiltInProc do
begin
BuiltInProc:=Resolver.BuiltInProcs[bp];
El:=BuiltInProc.Element;
if (El<>nil) and (CompareText(El.Name,aName)=0) then
begin
if bp in [bfStrProc,bfStrFunc] then
begin
if not ReadString(SubObj,'Type',s,ErrorEl) then
s:='Proc';
if (s='Func')<>(bp=bfStrFunc) then continue;
end;
AddElReference(Id,ErrorEl,El);
Found:=true;
break;
end;
end;
end;
end;
end;
constructor TPJUReader.Create; constructor TPJUReader.Create;
begin begin
inherited Create; inherited Create;

View File

@ -62,7 +62,8 @@ type
procedure CheckRestoredProcScope(const Path: string; Orig, Rest: TPas2JSProcedureScope); virtual; procedure CheckRestoredProcScope(const Path: string; Orig, Rest: TPas2JSProcedureScope); virtual;
procedure CheckRestoredPropertyScope(const Path: string; Orig, Rest: TPasPropertyScope); virtual; procedure CheckRestoredPropertyScope(const Path: string; Orig, Rest: TPasPropertyScope); virtual;
procedure CheckRestoredResolvedReference(const Path: string; Orig, Rest: TResolvedReference); virtual; procedure CheckRestoredResolvedReference(const Path: string; Orig, Rest: TResolvedReference); virtual;
procedure CheckRestoredCustomData(const Path: string; El: TPasElement; Orig, Rest: TObject); virtual; procedure CheckRestoredEvalValue(const Path: string; Orig, Rest: TResEvalValue); virtual;
procedure CheckRestoredCustomData(const Path: string; RestoredEl: TPasElement; Orig, Rest: TObject); virtual;
procedure CheckRestoredReference(const Path: string; Orig, Rest: TPasElement); virtual; procedure CheckRestoredReference(const Path: string; Orig, Rest: TPasElement); virtual;
procedure CheckRestoredElOrRef(const Path: string; Orig, OrigProp, Rest, RestProp: TPasElement); virtual; procedure CheckRestoredElOrRef(const Path: string; Orig, OrigProp, Rest, RestProp: TPasElement); virtual;
procedure CheckRestoredElement(const Path: string; Orig, Rest: TPasElement); virtual; procedure CheckRestoredElement(const Path: string; Orig, Rest: TPasElement); virtual;
@ -117,6 +118,7 @@ type
procedure TestPC_EmptyUnit; procedure TestPC_EmptyUnit;
procedure TestPC_Const; procedure TestPC_Const;
procedure TestPC_Var;
end; end;
implementation implementation
@ -175,7 +177,7 @@ begin
try try
try try
PJUWriter.OnGetSrc:=@OnFilerGetSrc; PJUWriter.OnGetSrc:=@OnFilerGetSrc;
PJUWriter.WritePJU(Engine,InitialFlags,ms); PJUWriter.WritePJU(Engine,InitialFlags,ms,false);
except except
on E: Exception do on E: Exception do
begin begin
@ -292,7 +294,7 @@ procedure TCustomTestPrecompile.CheckRestoredSection(const Path: string; Orig,
begin begin
if length(Orig.UsesClause)>0 then if length(Orig.UsesClause)>0 then
; // ToDo ; // ToDo
CheckRestoredDeclarations(Path,Rest,Orig); CheckRestoredDeclarations(Path,Orig,Rest);
end; end;
procedure TCustomTestPrecompile.CheckRestoredModule(const Path: string; Orig, procedure TCustomTestPrecompile.CheckRestoredModule(const Path: string; Orig,
@ -500,8 +502,69 @@ begin
CheckRestoredResolveData(Path,Orig,Rest); CheckRestoredResolveData(Path,Orig,Rest);
end; end;
procedure TCustomTestPrecompile.CheckRestoredEvalValue(const Path: string;
Orig, Rest: TResEvalValue);
var
i: Integer;
begin
if not CheckRestoredObject(Path,Orig,Rest) then exit;
if Orig.Kind<>Rest.Kind then
Fail(Path+'.Kind');
if not CheckRestoredObject(Path+'.Element',Orig.Element,Rest.Element) then exit;
CheckRestoredReference(Path+'.IdentEl',Orig.IdentEl,Rest.IdentEl);
case Orig.Kind of
revkNone: Fail(Path+'.Kind=revkNone');
revkCustom: Fail(Path+'.Kind=revkNone');
revkNil: ;
revkBool: AssertEquals(Path+'.B',TResEvalBool(Orig).B,TResEvalBool(Rest).B);
revkInt: AssertEquals(Path+'.Int',TResEvalInt(Orig).Int,TResEvalInt(Rest).Int);
revkUInt:
if TResEvalUInt(Orig).UInt<>TResEvalUInt(Rest).UInt then
Fail(Path+'.UInt');
revkFloat: AssertEquals(Path+'.FloatValue',TResEvalFloat(Orig).FloatValue,TResEvalFloat(Rest).FloatValue);
revkString: AssertEquals(Path+'.S,Raw',TResEvalString(Orig).S,TResEvalString(Rest).S);
revkUnicodeString: AssertEquals(Path+'.S,UTF16',String(TResEvalUTF16(Orig).S),String(TResEvalUTF16(Rest).S));
revkEnum:
begin
AssertEquals(Path+'.Index',TResEvalEnum(Orig).Index,TResEvalEnum(Rest).Index);
CheckRestoredReference(Path+'.ElType',TResEvalEnum(Orig).ElType,TResEvalEnum(Rest).ElType);
end;
revkRangeInt:
begin
if TResEvalRangeInt(Orig).ElKind<>TResEvalRangeInt(Rest).ElKind then
Fail(Path+'.Int/ElKind');
CheckRestoredReference(Path+'.Int/ElType',TResEvalRangeInt(Orig).ElType,TResEvalRangeInt(Rest).ElType);
AssertEquals(Path+'.Int/RangeStart',TResEvalRangeInt(Orig).RangeStart,TResEvalRangeInt(Rest).RangeStart);
AssertEquals(Path+'.Int/RangeEnd',TResEvalRangeInt(Orig).RangeEnd,TResEvalRangeInt(Rest).RangeEnd);
end;
revkRangeUInt:
begin
if TResEvalRangeUInt(Orig).RangeStart<>TResEvalRangeUInt(Rest).RangeStart then
Fail(Path+'.UInt/RangeStart');
if TResEvalRangeUInt(Orig).RangeEnd<>TResEvalRangeUInt(Rest).RangeEnd then
Fail(Path+'.UInt/RangeEnd');
end;
revkSetOfInt:
begin
if TResEvalSet(Orig).ElKind<>TResEvalSet(Rest).ElKind then
Fail(Path+'.SetInt/ElKind');
CheckRestoredReference(Path+'.SetInt/ElType',TResEvalSet(Orig).ElType,TResEvalSet(Rest).ElType);
AssertEquals(Path+'.SetInt/RangeStart',TResEvalSet(Orig).RangeStart,TResEvalSet(Rest).RangeStart);
AssertEquals(Path+'.SetInt/RangeEnd',TResEvalSet(Orig).RangeEnd,TResEvalSet(Rest).RangeEnd);
AssertEquals(Path+'.SetInt/length(Items)',length(TResEvalSet(Orig).Ranges),length(TResEvalSet(Rest).Ranges));
for i:=0 to length(TResEvalSet(Orig).Ranges)-1 do
begin
AssertEquals(Path+'.SetInt/Items['+IntToStr(i)+'].RangeStart',
TResEvalSet(Orig).Ranges[i].RangeStart,TResEvalSet(Rest).Ranges[i].RangeStart);
AssertEquals(Path+'.SetInt/Items['+IntToStr(i)+'].RangeEnd',
TResEvalSet(Orig).Ranges[i].RangeEnd,TResEvalSet(Rest).Ranges[i].RangeEnd);
end;
end;
end;
end;
procedure TCustomTestPrecompile.CheckRestoredCustomData(const Path: string; procedure TCustomTestPrecompile.CheckRestoredCustomData(const Path: string;
El: TPasElement; Orig, Rest: TObject); RestoredEl: TPasElement; Orig, Rest: TObject);
var var
C: TClass; C: TClass;
begin begin
@ -524,8 +587,10 @@ begin
CheckRestoredProcScope(Path+'[TPas2JSProcedureScope]',TPas2JSProcedureScope(Orig),TPas2JSProcedureScope(Rest)) CheckRestoredProcScope(Path+'[TPas2JSProcedureScope]',TPas2JSProcedureScope(Orig),TPas2JSProcedureScope(Rest))
else if C=TPasPropertyScope then else if C=TPasPropertyScope then
CheckRestoredPropertyScope(Path+'[TPasPropertyScope]',TPasPropertyScope(Orig),TPasPropertyScope(Rest)) CheckRestoredPropertyScope(Path+'[TPasPropertyScope]',TPasPropertyScope(Orig),TPasPropertyScope(Rest))
else if C.InheritsFrom(TResEvalValue) then
CheckRestoredEvalValue(Path+'['+Orig.ClassName+']',TResEvalValue(Orig),TResEvalValue(Rest))
else else
Fail(Path+': unknown CustomData "'+GetObjName(Orig)+'" El='+GetObjName(El)); Fail(Path+': unknown CustomData "'+GetObjName(Orig)+'" El='+GetObjName(RestoredEl));
end; end;
procedure TCustomTestPrecompile.CheckRestoredReference(const Path: string; procedure TCustomTestPrecompile.CheckRestoredReference(const Path: string;
@ -558,9 +623,14 @@ procedure TCustomTestPrecompile.CheckRestoredElement(const Path: string; Orig,
Rest: TPasElement); Rest: TPasElement);
var var
C: TClass; C: TClass;
AModule: TPasModule;
begin begin
if not CheckRestoredObject(Path,Orig,Rest) then exit; if not CheckRestoredObject(Path,Orig,Rest) then exit;
AModule:=Orig.GetModule;
if AModule<>Module then
Fail(Path+' wrong module: Orig='+GetObjName(AModule)+' '+GetObjName(Module));
AssertEquals(Path+': Name',Orig.Name,Rest.Name); AssertEquals(Path+': Name',Orig.Name,Rest.Name);
AssertEquals(Path+': SourceFilename',Orig.SourceFilename,Rest.SourceFilename); AssertEquals(Path+': SourceFilename',Orig.SourceFilename,Rest.SourceFilename);
AssertEquals(Path+': SourceLinenumber',Orig.SourceLinenumber,Rest.SourceLinenumber); AssertEquals(Path+': SourceLinenumber',Orig.SourceLinenumber,Rest.SourceLinenumber);
@ -1069,7 +1139,24 @@ begin
StartUnit(false); StartUnit(false);
Add([ Add([
'interface', 'interface',
'const c = 3;', 'const',
' Three = 3;',
' FourPlusFive: longint = 4+5 deprecated ''deprtext'';',
' Four: byte = 6-2*2 platform;',
'implementation']);
WriteReadUnit;
end;
procedure TTestPrecompile.TestPC_Var;
begin
StartUnit(false);
Add([
'interface',
'var',
' FourPlusFive: longint = 4+5 deprecated ''deprtext'';',
' e: double external name ''Math.e'';',
' AnoArr: array of longint = (1,2,3);',
' s: string = ''aaaäö'';',
'implementation']); 'implementation']);
WriteReadUnit; WriteReadUnit;
end; end;

View File

@ -217,6 +217,7 @@ type
Procedure TestChar_Ord; Procedure TestChar_Ord;
Procedure TestChar_Chr; Procedure TestChar_Chr;
Procedure TestStringConst; Procedure TestStringConst;
Procedure TestStringConstSurrogate;
Procedure TestString_Length; Procedure TestString_Length;
Procedure TestString_Compare; Procedure TestString_Compare;
Procedure TestString_SetLength; Procedure TestString_SetLength;
@ -4801,16 +4802,18 @@ end;
procedure TTestModule.TestStringConst; procedure TTestModule.TestStringConst;
begin begin
StartProgram(false); StartProgram(false);
Add('var'); Add([
Add(' s: string = ''abc'';'); 'var',
Add('begin'); ' s: string = ''abc'';',
Add(' s:='''';'); 'begin',
Add(' s:=#13#10;'); ' s:='''';',
Add(' s:=#9''foo'';'); ' s:=#13#10;',
Add(' s:=#$A9;'); ' s:=#9''foo'';',
Add(' s:=''foo''#13''bar'';'); ' s:=#$A9;',
Add(' s:=''"'';'); ' s:=''foo''#13''bar'';',
Add(' s:=''"''''"'';'); ' s:=''"'';',
' s:=''"''''"'';',
'']);
ConvertProgram; ConvertProgram;
CheckSource('TestStringConst', CheckSource('TestStringConst',
LinesToStr([ LinesToStr([
@ -4827,6 +4830,25 @@ begin
])); ]));
end; end;
procedure TTestModule.TestStringConstSurrogate;
begin
StartProgram(false);
Add([
'var',
' s: string;',
'begin',
' s:=''😊'';', // 1F60A
'']);
ConvertProgram;
CheckSource('TestStringConstSurrogate',
LinesToStr([
'this.s="";'
]),
LinesToStr([
'$mod.s="😊";'
]));
end;
procedure TTestModule.TestString_Length; procedure TTestModule.TestString_Length;
begin begin
StartProgram(false); StartProgram(false);