mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-14 17:49:09 +02:00
pastojs: default(record)
git-svn-id: trunk@38882 -
This commit is contained in:
parent
78d12d1b5e
commit
7ea975a869
@ -1528,6 +1528,8 @@ type
|
|||||||
Function CreateDotExpression(aParent: TPasElement; Left, Right: TJSElement;
|
Function CreateDotExpression(aParent: TPasElement; Left, Right: TJSElement;
|
||||||
CheckRightIntfRef: boolean = false): TJSElement; virtual;
|
CheckRightIntfRef: boolean = false): TJSElement; virtual;
|
||||||
Function CreateReferencedSet(El: TPasElement; SetExpr: TJSElement): TJSElement; virtual;
|
Function CreateReferencedSet(El: TPasElement; SetExpr: TJSElement): TJSElement; virtual;
|
||||||
|
Function CreateNewRecord(El: TPasElement; RecTypeEl: TPasRecordType;
|
||||||
|
AContext: TConvertContext): TJSNewMemberExpression; virtual;
|
||||||
Function CreateCloneRecord(El: TPasElement; RecTypeEl: TPasRecordType;
|
Function CreateCloneRecord(El: TPasElement; RecTypeEl: TPasRecordType;
|
||||||
RecordExpr: TJSElement; AContext: TConvertContext): TJSElement; virtual;
|
RecordExpr: TJSElement; AContext: TConvertContext): TJSElement; virtual;
|
||||||
Function CreateCallback(El: TPasElement; ResolvedEl: TPasResolverResult;
|
Function CreateCallback(El: TPasElement; ResolvedEl: TPasResolverResult;
|
||||||
@ -1633,6 +1635,7 @@ type
|
|||||||
Function ConvertBuiltIn_Assert(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
|
Function ConvertBuiltIn_Assert(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
|
||||||
Function ConvertBuiltIn_New(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
|
Function ConvertBuiltIn_New(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
|
||||||
Function ConvertBuiltIn_Dispose(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
|
Function ConvertBuiltIn_Dispose(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
|
||||||
|
Function ConvertBuiltIn_Default(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
|
||||||
Function ConvertRecordValues(El: TRecordValues; AContext: TConvertContext): TJSElement; virtual;
|
Function ConvertRecordValues(El: TRecordValues; AContext: TConvertContext): TJSElement; virtual;
|
||||||
Function ConvertSelfExpression(El: TSelfExpr; AContext: TConvertContext): TJSElement; virtual;
|
Function ConvertSelfExpression(El: TSelfExpr; AContext: TConvertContext): TJSElement; virtual;
|
||||||
Function ConvertBinaryExpression(El: TBinaryExpr; AContext: TConvertContext): TJSElement; virtual;
|
Function ConvertBinaryExpression(El: TBinaryExpr; AContext: TConvertContext): TJSElement; virtual;
|
||||||
@ -1744,6 +1747,8 @@ var
|
|||||||
function CodePointToJSString(u: longword): TJSString;
|
function CodePointToJSString(u: longword): TJSString;
|
||||||
function PosLast(c: char; const s: string): integer;
|
function PosLast(c: char; const s: string): integer;
|
||||||
|
|
||||||
|
function JSEquals(A, B: TJSElement): boolean;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
const
|
const
|
||||||
@ -1766,6 +1771,27 @@ begin
|
|||||||
while (Result>0) and (s[Result]<>c) do dec(Result);
|
while (Result>0) and (s[Result]<>c) do dec(Result);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function JSEquals(A, B: TJSElement): boolean;
|
||||||
|
begin
|
||||||
|
if A=nil then
|
||||||
|
exit(B=nil)
|
||||||
|
else if B=nil then
|
||||||
|
exit(false)
|
||||||
|
else if A.ClassType<>B.ClassType then
|
||||||
|
exit(false);
|
||||||
|
if A.ClassType=TJSPrimaryExpressionIdent then
|
||||||
|
exit(TJSPrimaryExpressionIdent(A).Name=TJSPrimaryExpressionIdent(B).Name)
|
||||||
|
else if A.ClassType=TJSPrimaryExpressionThis then
|
||||||
|
else if A.ClassType=TJSDotMemberExpression then
|
||||||
|
Result:=JSEquals(TJSDotMemberExpression(A).MExpr,TJSDotMemberExpression(B).MExpr)
|
||||||
|
and (TJSDotMemberExpression(A).Name=TJSDotMemberExpression(B).Name)
|
||||||
|
else if A.ClassType=TJSBracketMemberExpression then
|
||||||
|
Result:=JSEquals(TJSBracketMemberExpression(A).MExpr,TJSBracketMemberExpression(B).MExpr)
|
||||||
|
and (TJSBracketMemberExpression(A).Name=TJSBracketMemberExpression(B).Name)
|
||||||
|
else
|
||||||
|
exit(false);
|
||||||
|
end;
|
||||||
|
|
||||||
{ TPas2JSSectionScope }
|
{ TPas2JSSectionScope }
|
||||||
|
|
||||||
procedure TPas2JSSectionScope.InternalAddElevatedLocal(Item: TPasIdentifier);
|
procedure TPas2JSSectionScope.InternalAddElevatedLocal(Item: TPasIdentifier);
|
||||||
@ -7495,7 +7521,8 @@ begin
|
|||||||
begin
|
begin
|
||||||
Result:=ConvertBuiltIn_Dispose(El,AContext);
|
Result:=ConvertBuiltIn_Dispose(El,AContext);
|
||||||
if Result=nil then exit;
|
if Result=nil then exit;
|
||||||
end
|
end;
|
||||||
|
bfDefault: Result:=ConvertBuiltIn_Default(El,AContext);
|
||||||
else
|
else
|
||||||
RaiseNotSupported(El,AContext,20161130164955,'built in proc '+ResolverBuiltInProcNames[BuiltInProc.BuiltIn]);
|
RaiseNotSupported(El,AContext,20161130164955,'built in proc '+ResolverBuiltInProcNames[BuiltInProc.BuiltIn]);
|
||||||
end;
|
end;
|
||||||
@ -9700,7 +9727,6 @@ var
|
|||||||
TypeEl, SubTypeEl: TPasType;
|
TypeEl, SubTypeEl: TPasType;
|
||||||
aResolveR: TPas2JSResolver;
|
aResolveR: TPas2JSResolver;
|
||||||
RecType: TPasRecordType;
|
RecType: TPasRecordType;
|
||||||
NewJS: TJSNewMemberExpression;
|
|
||||||
begin
|
begin
|
||||||
Result:=nil;
|
Result:=nil;
|
||||||
Param0:=El.Params[0];
|
Param0:=El.Params[0];
|
||||||
@ -9727,9 +9753,7 @@ begin
|
|||||||
AssignContext.RightResolved:=AssignContext.LeftResolved;
|
AssignContext.RightResolved:=AssignContext.LeftResolved;
|
||||||
|
|
||||||
// create right side new TRecord()
|
// create right side new TRecord()
|
||||||
NewJS:=TJSNewMemberExpression(CreateElement(TJSNewMemberExpression,El));
|
AssignContext.RightSide:=CreateNewRecord(El,RecType,AContext);
|
||||||
NewJS.MExpr:=CreateReferencePathExpr(RecType,AContext);
|
|
||||||
AssignContext.RightSide:=NewJS;
|
|
||||||
|
|
||||||
Result:=CreateAssignStatement(Param0,AssignContext);
|
Result:=CreateAssignStatement(Param0,AssignContext);
|
||||||
finally
|
finally
|
||||||
@ -9789,6 +9813,115 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TPasToJSConverter.ConvertBuiltIn_Default(El: TParamsExpr;
|
||||||
|
AContext: TConvertContext): TJSElement;
|
||||||
|
|
||||||
|
procedure CreateEnumValue(TypeEl: TPasEnumType);
|
||||||
|
var
|
||||||
|
EnumValue: TPasEnumValue;
|
||||||
|
begin
|
||||||
|
EnumValue:=TPasEnumValue(TypeEl.Values[0]);
|
||||||
|
Result:=CreateReferencePathExpr(EnumValue,AContext);
|
||||||
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
ResolvedEl: TPasResolverResult;
|
||||||
|
Param: TPasExpr;
|
||||||
|
TypeEl: TPasType;
|
||||||
|
Value: TResEvalValue;
|
||||||
|
MinVal, MaxVal: MaxPrecInt;
|
||||||
|
begin
|
||||||
|
Result:=nil;
|
||||||
|
if AContext.Resolver=nil then
|
||||||
|
RaiseInconsistency(20180501011029,El);
|
||||||
|
Param:=El.Params[0];
|
||||||
|
AContext.Resolver.ComputeElement(Param,ResolvedEl,[]);
|
||||||
|
case ResolvedEl.BaseType of
|
||||||
|
btContext:
|
||||||
|
begin
|
||||||
|
TypeEl:=ResolvedEl.LoTypeEl;
|
||||||
|
if TypeEl.ClassType=TPasEnumType then
|
||||||
|
begin
|
||||||
|
CreateEnumValue(TPasEnumType(TypeEl));
|
||||||
|
exit;
|
||||||
|
end
|
||||||
|
else if (TypeEl.ClassType=TPasSetType) then
|
||||||
|
begin
|
||||||
|
Result:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,El));
|
||||||
|
exit;
|
||||||
|
end
|
||||||
|
else if TypeEl.ClassType=TPasArrayType then
|
||||||
|
begin
|
||||||
|
Result:=CreateArrayInit(TPasArrayType(TypeEl),nil,El,AContext);
|
||||||
|
exit;
|
||||||
|
end
|
||||||
|
else if TypeEl.ClassType=TPasRecordType then
|
||||||
|
begin
|
||||||
|
Result:=CreateRecordInit(TPasRecordType(TypeEl),nil,El,AContext);
|
||||||
|
exit;
|
||||||
|
end
|
||||||
|
else if (TypeEl.ClassType=TPasRangeType) then
|
||||||
|
// a custom range without initial value -> use first value
|
||||||
|
begin
|
||||||
|
Value:=AContext.Resolver.Eval(TPasRangeType(TypeEl).RangeExpr.left,[refConst]);
|
||||||
|
try
|
||||||
|
Result:=ConvertConstValue(Value,AContext,El);
|
||||||
|
finally
|
||||||
|
ReleaseEvalValue(Value);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
btBoolean,btByteBool,btWordBool,btLongBool:
|
||||||
|
begin
|
||||||
|
Result:=CreateLiteralBoolean(El,LowJSBoolean);
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
btChar,
|
||||||
|
btWideChar:
|
||||||
|
begin
|
||||||
|
Result:=CreateLiteralJSString(El,#0);
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
btByte..btInt64:
|
||||||
|
begin
|
||||||
|
TypeEl:=ResolvedEl.LoTypeEl;
|
||||||
|
if TypeEl.ClassType=TPasUnresolvedSymbolRef then
|
||||||
|
begin
|
||||||
|
if TypeEl.CustomData is TResElDataBaseType then
|
||||||
|
begin
|
||||||
|
AContext.Resolver.GetIntegerRange(ResolvedEl.BaseType,MinVal,MaxVal);
|
||||||
|
Result:=CreateLiteralNumber(El,MinVal);
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
end
|
||||||
|
else if TypeEl.ClassType=TPasRangeType then
|
||||||
|
begin
|
||||||
|
Value:=AContext.Resolver.EvalRangeLimit(TPasRangeType(TypeEl).RangeExpr,
|
||||||
|
[refConst],true,El);
|
||||||
|
try
|
||||||
|
case Value.Kind of
|
||||||
|
revkInt:
|
||||||
|
Result:=CreateLiteralNumber(El,TResEvalInt(Value).Int);
|
||||||
|
revkUInt:
|
||||||
|
Result:=CreateLiteralNumber(El,TResEvalUInt(Value).UInt);
|
||||||
|
else
|
||||||
|
RaiseNotSupported(El,AContext,20180501011646);
|
||||||
|
end;
|
||||||
|
exit;
|
||||||
|
finally
|
||||||
|
ReleaseEvalValue(Value);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
{$IFDEF VerbosePas2JS}
|
||||||
|
writeln('TPasToJSConverter.ConvertBuiltIn_Default ',GetResolverResultDbg(ResolvedEl));
|
||||||
|
{$ENDIF}
|
||||||
|
RaiseNotSupported(El,AContext,20180501011649);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
DoError(20180501011723,nXExpectedButYFound,sXExpectedButYFound,['record',
|
||||||
|
AContext.Resolver.GetResolverResultDescription(ResolvedEl)],Param);
|
||||||
|
end;
|
||||||
|
|
||||||
function TPasToJSConverter.ConvertRecordValues(El: TRecordValues;
|
function TPasToJSConverter.ConvertRecordValues(El: TRecordValues;
|
||||||
AContext: TConvertContext): TJSElement;
|
AContext: TConvertContext): TJSElement;
|
||||||
var
|
var
|
||||||
@ -9818,9 +9951,8 @@ begin
|
|||||||
RaiseNotSupported(El,AContext,20180429210932);
|
RaiseNotSupported(El,AContext,20180429210932);
|
||||||
RecType:=TPasRecordType(ResolvedEl.LoTypeEl);
|
RecType:=TPasRecordType(ResolvedEl.LoTypeEl);
|
||||||
|
|
||||||
NewMemE:=TJSNewMemberExpression(CreateElement(TJSNewMemberExpression,El));
|
NewMemE:=CreateNewRecord(El,RecType,AContext);
|
||||||
Result:=NewMemE;
|
Result:=NewMemE;
|
||||||
NewMemE.MExpr:=CreateReferencePathExpr(RecType,AContext);
|
|
||||||
ObjLit:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,El));
|
ObjLit:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,El));
|
||||||
NewMemE.AddArg(ObjLit);
|
NewMemE.AddArg(ObjLit);
|
||||||
end
|
end
|
||||||
@ -12477,15 +12609,37 @@ begin
|
|||||||
Result:=Call;
|
Result:=Call;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TPasToJSConverter.CreateNewRecord(El: TPasElement;
|
||||||
|
RecTypeEl: TPasRecordType; AContext: TConvertContext): TJSNewMemberExpression;
|
||||||
|
var
|
||||||
|
Expr: TJSElement;
|
||||||
|
begin
|
||||||
|
Expr:=CreateReferencePathExpr(RecTypeEl,AContext);
|
||||||
|
Result:=TJSNewMemberExpression(CreateElement(TJSNewMemberExpression,El));
|
||||||
|
Result.MExpr:=Expr;
|
||||||
|
end;
|
||||||
|
|
||||||
function TPasToJSConverter.CreateCloneRecord(El: TPasElement;
|
function TPasToJSConverter.CreateCloneRecord(El: TPasElement;
|
||||||
RecTypeEl: TPasRecordType; RecordExpr: TJSElement; AContext: TConvertContext
|
RecTypeEl: TPasRecordType; RecordExpr: TJSElement; AContext: TConvertContext
|
||||||
): TJSElement;
|
): TJSElement;
|
||||||
// create "new RecordType(RecordExpr)
|
// create "new RecordType(RecordExpr)
|
||||||
var
|
var
|
||||||
NewExpr: TJSNewMemberExpression;
|
NewExpr: TJSNewMemberExpression;
|
||||||
|
Expr: TJSElement;
|
||||||
begin
|
begin
|
||||||
|
Expr:=CreateReferencePathExpr(RecTypeEl,AContext);
|
||||||
|
if RecordExpr is TJSNewMemberExpression then
|
||||||
|
begin
|
||||||
|
if JSEquals(Expr,TJSNewMemberExpression(RecordExpr).MExpr) then
|
||||||
|
begin
|
||||||
|
// RecordExpr is already a new RecordType(...) -> skip clone
|
||||||
|
Expr.Free;
|
||||||
|
exit(RecordExpr);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
NewExpr:=TJSNewMemberExpression(CreateElement(TJSNewMemberExpression,El));
|
NewExpr:=TJSNewMemberExpression(CreateElement(TJSNewMemberExpression,El));
|
||||||
NewExpr.MExpr:=CreateReferencePathExpr(RecTypeEl,AContext);
|
NewExpr.MExpr:=Expr;
|
||||||
NewExpr.AddArg(RecordExpr);
|
NewExpr.AddArg(RecordExpr);
|
||||||
Result:=NewExpr;
|
Result:=NewExpr;
|
||||||
end;
|
end;
|
||||||
@ -14188,9 +14342,8 @@ begin
|
|||||||
if aResolver.GetAssignGUIDString(TPasRecordType(LeftTypeEl),El.right,GUID) then
|
if aResolver.GetAssignGUIDString(TPasRecordType(LeftTypeEl),El.right,GUID) then
|
||||||
begin
|
begin
|
||||||
// guidvar:='{...}'; -> guidvar:=new TGUID(){ D1:x12345678, D2:0x1234,...}
|
// guidvar:='{...}'; -> guidvar:=new TGUID(){ D1:x12345678, D2:0x1234,...}
|
||||||
NewMemE:=TJSNewMemberExpression(CreateElement(TJSNewMemberExpression,El));
|
NewMemE:=CreateNewRecord(El,TPasRecordType(LeftTypeEl),AContext);
|
||||||
AssignContext.RightSide:=NewMemE;
|
AssignContext.RightSide:=NewMemE;
|
||||||
NewMemE.MExpr:=CreateReferencePathExpr(LeftTypeEl,AContext);
|
|
||||||
ObjLit:=CreateGUIDObjLit(TPasRecordType(LeftTypeEl),GUID,El,AContext);
|
ObjLit:=CreateGUIDObjLit(TPasRecordType(LeftTypeEl),GUID,El,AContext);
|
||||||
NewMemE.AddArg(ObjLit);
|
NewMemE.AddArg(ObjLit);
|
||||||
end
|
end
|
||||||
@ -14260,8 +14413,7 @@ begin
|
|||||||
and SameText(LeftTypeEl.Name,'TGUID') then
|
and SameText(LeftTypeEl.Name,'TGUID') then
|
||||||
begin
|
begin
|
||||||
// GUIDRecord:=IntfTypeOrVar -> new TGuid(rtl.getIntfGUIDR(IntfTypeOrVar))
|
// GUIDRecord:=IntfTypeOrVar -> new TGuid(rtl.getIntfGUIDR(IntfTypeOrVar))
|
||||||
NewME:=TJSNewMemberExpression(CreateElement(TJSNewMemberExpression,El));
|
NewME:=CreateNewRecord(El,TPasRecordType(LeftTypeEl),AContext);
|
||||||
NewME.MExpr:=CreateReferencePathExpr(LeftTypeEl,AContext);
|
|
||||||
Call:=CreateCallExpression(El);
|
Call:=CreateCallExpression(El);
|
||||||
NewME.AddArg(Call);
|
NewME.AddArg(Call);
|
||||||
Call.Expr:=CreatePrimitiveDotExpr(FBuiltInNames[pbivnRTL]+'.'+FBuiltInNames[pbifnIntfGetGUIDR],El);
|
Call.Expr:=CreatePrimitiveDotExpr(FBuiltInNames[pbivnRTL]+'.'+FBuiltInNames[pbifnIntfGetGUIDR],El);
|
||||||
@ -15429,7 +15581,7 @@ var
|
|||||||
else if C=TJSNewMemberExpression then
|
else if C=TJSNewMemberExpression then
|
||||||
with TJSNewMemberExpression(El).Args.Elements do
|
with TJSNewMemberExpression(El).Args.Elements do
|
||||||
for i:=0 to Count-1 do
|
for i:=0 to Count-1 do
|
||||||
Find(Elements[i].Expr)
|
Find(Elements[i].Expr);
|
||||||
end
|
end
|
||||||
else if C=TJSCallExpression then
|
else if C=TJSCallExpression then
|
||||||
begin
|
begin
|
||||||
@ -16194,9 +16346,8 @@ begin
|
|||||||
begin
|
begin
|
||||||
// new TGuid({ D1:...})
|
// new TGuid({ D1:...})
|
||||||
ObjLit:=CreateGUIDObjLit(aRecord,GUID,El,AContext);
|
ObjLit:=CreateGUIDObjLit(aRecord,GUID,El,AContext);
|
||||||
NewMemE:=TJSNewMemberExpression(CreateElement(TJSNewMemberExpression,El));
|
NewMemE:=CreateNewRecord(El,aRecord,AContext);
|
||||||
Result:=NewMemE;
|
Result:=NewMemE;
|
||||||
NewMemE.MExpr:=CreateReferencePathExpr(aRecord,AContext);
|
|
||||||
NewMemE.AddArg(ObjLit);
|
NewMemE.AddArg(ObjLit);
|
||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
@ -16210,9 +16361,7 @@ begin
|
|||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
// new TRecord()
|
// new TRecord()
|
||||||
NewMemE:=TJSNewMemberExpression(CreateElement(TJSNewMemberExpression,El));
|
Result:=CreateNewRecord(El,aRecord,AContext);
|
||||||
Result:=NewMemE;
|
|
||||||
NewMemE.MExpr:=CreateReferencePathExpr(aRecord,AContext);
|
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
@ -7515,6 +7515,8 @@ begin
|
|||||||
Add(' r, s: TBigRec;');
|
Add(' r, s: TBigRec;');
|
||||||
Add('begin');
|
Add('begin');
|
||||||
Add(' r:=s;');
|
Add(' r:=s;');
|
||||||
|
Add(' r:=default(TBigRec);');
|
||||||
|
Add(' r:=default(s);');
|
||||||
ConvertProgram;
|
ConvertProgram;
|
||||||
CheckSource('TestRecord_Assign',
|
CheckSource('TestRecord_Assign',
|
||||||
LinesToStr([ // statements
|
LinesToStr([ // statements
|
||||||
@ -7561,6 +7563,8 @@ begin
|
|||||||
]),
|
]),
|
||||||
LinesToStr([ // $mod.$main
|
LinesToStr([ // $mod.$main
|
||||||
'$mod.r = new $mod.TBigRec($mod.s);',
|
'$mod.r = new $mod.TBigRec($mod.s);',
|
||||||
|
'$mod.r = new $mod.TBigRec();',
|
||||||
|
'$mod.r = new $mod.TBigRec();',
|
||||||
'']));
|
'']));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
@ -663,7 +663,8 @@ function(){
|
|||||||
<ul>
|
<ul>
|
||||||
<li>The record variable creates a JavaScript object.</li>
|
<li>The record variable creates a JavaScript object.</li>
|
||||||
<li>Variant records are not supported.</li>
|
<li>Variant records are not supported.</li>
|
||||||
<li>Supported: Assign, pass as argument, equal, not equal, array of record, pointer of record, const.</li>
|
<li>Supported: Assign, pass as argument, equal, not equal,
|
||||||
|
array of record, pointer of record, const, default().</li>
|
||||||
<li>Not yet implemented: advanced records, operators.</li>
|
<li>Not yet implemented: advanced records, operators.</li>
|
||||||
<li>When assigning a record it is cloned. This is compatible with Delphi and FPC.</li>
|
<li>When assigning a record it is cloned. This is compatible with Delphi and FPC.</li>
|
||||||
<li>Since record types are JS objects it is possible to typecast a record type
|
<li>Since record types are JS objects it is possible to typecast a record type
|
||||||
|
Loading…
Reference in New Issue
Block a user