mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-12-05 00:28:25 +01:00
pastojs: external class field with brackets
git-svn-id: trunk@38958 -
This commit is contained in:
parent
e283024ad7
commit
cc7983d781
@ -1333,6 +1333,8 @@ type
|
||||
TDotContext = Class(TConvertContext)
|
||||
public
|
||||
LeftResolved: TPasResolverResult;
|
||||
// created by ConvertElement if subident needs special translation:
|
||||
JS: TJSElement;
|
||||
end;
|
||||
|
||||
{ TAssignContext - used for left side of an assign statement }
|
||||
@ -1343,7 +1345,7 @@ type
|
||||
LeftResolved: TPasResolverResult;
|
||||
RightResolved: TPasResolverResult;
|
||||
RightSide: TJSElement;
|
||||
// created by ConvertElement:
|
||||
// created by ConvertElement if assign needs a call:
|
||||
PropertyEl: TPasProperty;
|
||||
Setter: TPasElement;
|
||||
Call: TJSCallExpression;
|
||||
@ -1531,6 +1533,7 @@ type
|
||||
Function CreateLiteralBoolean(El: TPasElement; b: boolean): TJSLiteral; virtual;
|
||||
Function CreateLiteralNull(El: TPasElement): TJSLiteral; virtual;
|
||||
Function CreateLiteralUndefined(El: TPasElement): TJSLiteral; virtual;
|
||||
Function CreateLiteralCustomValue(El: TPasElement; const s: TJSString): TJSLiteral; virtual;
|
||||
Function CreateSetLiteralElement(Expr: TPasExpr; AContext: TConvertContext): TJSElement; virtual;
|
||||
Procedure ConvertCharLiteralToInt(Lit: TJSLiteral; ErrorEl: TPasElement; AContext: TConvertContext); virtual;
|
||||
Function ClonePrimaryExpression(El: TJSPrimaryExpression; Src: TPasElement): TJSPrimaryExpression;
|
||||
@ -6087,6 +6090,7 @@ var
|
||||
RightRef: TResolvedReference;
|
||||
ParamsExpr: TParamsExpr;
|
||||
RightEl: TPasExpr;
|
||||
RightRefDecl: TPasElement;
|
||||
begin
|
||||
Result:=nil;
|
||||
|
||||
@ -6098,11 +6102,14 @@ begin
|
||||
RightEl:=ParamsExpr.Value;
|
||||
end;
|
||||
|
||||
RightRef:=nil;
|
||||
RightRefDecl:=nil;
|
||||
if (RightEl.ClassType=TPrimitiveExpr)
|
||||
and (RightEl.CustomData is TResolvedReference) then
|
||||
begin
|
||||
RightRef:=TResolvedReference(RightEl.CustomData);
|
||||
if IsExternalClassConstructor(RightRef.Declaration) then
|
||||
RightRefDecl:=RightRef.Declaration;
|
||||
if IsExternalClassConstructor(RightRefDecl) then
|
||||
begin
|
||||
if ParamsExpr<>nil then
|
||||
begin
|
||||
@ -6137,14 +6144,20 @@ begin
|
||||
Left:=ConvertElement(El.left,AContext);
|
||||
if Left=nil then
|
||||
RaiseInconsistency(20170201140821,El);
|
||||
|
||||
AContext.Access:=OldAccess;
|
||||
|
||||
// convert right side
|
||||
DotContext:=TDotContext.Create(El,Left,AContext);
|
||||
Right:=nil;
|
||||
try
|
||||
DotContext.LeftResolved:=LeftResolved;
|
||||
Right:=ConvertElement(El.right,DotContext);
|
||||
if DotContext.JS<>nil then
|
||||
begin
|
||||
Left:=nil;
|
||||
Right:=nil;
|
||||
exit(DotContext.JS);
|
||||
end;
|
||||
finally
|
||||
DotContext.Free;
|
||||
if Right=nil then
|
||||
@ -6358,6 +6371,7 @@ var
|
||||
FuncScope: TPas2JSProcedureScope;
|
||||
Value: TResEvalValue;
|
||||
aResolver: TPas2JSResolver;
|
||||
BracketExpr: TJSBracketMemberExpression;
|
||||
begin
|
||||
Result:=nil;
|
||||
if not (El.CustomData is TResolvedReference) then
|
||||
@ -6467,6 +6481,7 @@ begin
|
||||
begin
|
||||
if TPasConst(Decl).IsConst and (TPasConst(Decl).Expr<>nil) then
|
||||
begin
|
||||
// const with expression
|
||||
Value:=aResolver.Eval(TPasConst(Decl).Expr,[refConst]);
|
||||
if (Value<>nil)
|
||||
and (Value.Kind in [revkNil,revkBool,revkInt,revkUInt,revkFloat,revkEnum]) then
|
||||
@ -6478,7 +6493,7 @@ begin
|
||||
end;
|
||||
if vmExternal in TPasConst(Decl).VarModifiers then
|
||||
begin
|
||||
// external constant are always added by value, not by reference
|
||||
// external constant with expression is always added by value, not by reference
|
||||
Result:=ConvertElement(TPasConst(Decl).Expr,AContext);
|
||||
exit;
|
||||
end;
|
||||
@ -6550,8 +6565,28 @@ begin
|
||||
Name:=AContext.GetLocalName(Decl)
|
||||
else
|
||||
Name:=CreateReferencePath(Decl,AContext,rpkPathAndName,false,Ref);
|
||||
if Name='' then
|
||||
RaiseNotSupported(El,AContext,20180509134804,GetObjName(Decl));
|
||||
|
||||
if Result=nil then
|
||||
begin
|
||||
if (Name[1]='[') and (Name[length(Name)]=']')
|
||||
and (AContext is TDotContext)
|
||||
and (AContext.JSElement<>nil) then
|
||||
begin
|
||||
// e.g. Obj.A and A is defined as: A: t external name '["name"]';
|
||||
// -> Obj["name"]
|
||||
if IsImplicitCall then
|
||||
RaiseNotSupported(El,AContext,20180509134951,Name);
|
||||
BracketExpr:=TJSBracketMemberExpression(CreateElement(TJSBracketMemberExpression,El));
|
||||
TDotContext(AContext).JS:=BracketExpr;
|
||||
BracketExpr.MExpr:=AContext.JSElement;
|
||||
Result:=CreateLiteralCustomValue(El,TJSString(copy(Name,2,length(Name)-2)));
|
||||
BracketExpr.Name:=Result;
|
||||
exit;
|
||||
end;
|
||||
Result:=CreatePrimitiveDotExpr(Name,El);
|
||||
end;
|
||||
|
||||
if IsImplicitCall then
|
||||
CallImplicit(Decl);
|
||||
@ -7272,7 +7307,7 @@ var
|
||||
begin
|
||||
AccessEl:=aResolver.GetPasPropertySetter(Prop);
|
||||
if IsJSBracketAccessorAndConvert(Prop,AccessEl,AContext,true) then
|
||||
exit;
|
||||
exit;
|
||||
AssignContext:=AContext.AccessContext as TAssignContext;
|
||||
AssignContext.PropertyEl:=Prop;
|
||||
AssignContext.Setter:=AccessEl;
|
||||
@ -7410,6 +7445,8 @@ var
|
||||
DotContext:=TDotContext.Create(El.Value,Left,AContext);
|
||||
DotContext.LeftResolved:=ResolvedEl;
|
||||
ConvertIndexedProperty(Prop,DotContext);
|
||||
if DotContext.JS<>nil then
|
||||
RaiseNotSupported(El,AContext,20180509134226,GetObjName(DotContext.JS));
|
||||
Right:=Result;
|
||||
Result:=nil;
|
||||
finally
|
||||
@ -13057,8 +13094,13 @@ begin
|
||||
AssignSt.LHS:=ConvertElement(El.VariableName,AContext); // beware: might fail
|
||||
|
||||
DotContext:=TDotContext.Create(El.StartExpr,nil,AContext);
|
||||
GetCurrent:=CreatePropertyGet(CurrentProp,nil,DotContext,PosEl); // beware: might fail
|
||||
FreeAndNil(DotContext);
|
||||
try
|
||||
GetCurrent:=CreatePropertyGet(CurrentProp,nil,DotContext,PosEl); // beware: might fail
|
||||
if DotContext.JS<>nil then
|
||||
RaiseNotSupported(El,AContext,20180509134302,GetObjName(DotContext.JS));
|
||||
finally
|
||||
FreeAndNil(DotContext);
|
||||
end;
|
||||
AssignSt.Expr:=CreateDotExpression(PosEl,CreateInName,GetCurrent,true);
|
||||
|
||||
// add body
|
||||
@ -16213,6 +16255,13 @@ begin
|
||||
Result.Value.IsUndefined:=true;
|
||||
end;
|
||||
|
||||
function TPasToJSConverter.CreateLiteralCustomValue(El: TPasElement;
|
||||
const s: TJSString): TJSLiteral;
|
||||
begin
|
||||
Result:=TJSLiteral(CreateElement(TJSLiteral,El));
|
||||
Result.Value.CustomValue:=s;
|
||||
end;
|
||||
|
||||
function TPasToJSConverter.CreateSetLiteralElement(Expr: TPasExpr;
|
||||
AContext: TConvertContext): TJSElement;
|
||||
var
|
||||
@ -16533,7 +16582,7 @@ function TPasToJSConverter.CreateReferencePath(El: TPasElement;
|
||||
|
||||
procedure Prepend(var aPath: string; Prefix: string);
|
||||
begin
|
||||
if aPath<>'' then
|
||||
if (aPath<>'') and (aPath[1]<>'[') then
|
||||
aPath:='.'+aPath;
|
||||
aPath:=Prefix+aPath;
|
||||
end;
|
||||
@ -16789,10 +16838,21 @@ begin
|
||||
ParentEl:=ParentEl.Parent;
|
||||
end;
|
||||
end;
|
||||
if (Result<>'') and (Kind in [rpkPathWithDot,rpkPathAndName]) then
|
||||
Result:=Result+'.';
|
||||
if Kind=rpkPathAndName then
|
||||
Result:=Result+TransformVariableName(El,AContext);
|
||||
|
||||
case Kind of
|
||||
rpkPathWithDot:
|
||||
if Result<>'' then Result:=Result+'.';
|
||||
rpkPathAndName:
|
||||
begin
|
||||
ShortName:=TransformVariableName(El,AContext);
|
||||
if Result='' then
|
||||
Result:=ShortName
|
||||
else if (ShortName<>'') and (ShortName[1] in ['[','(']) then
|
||||
Result:=Result+ShortName
|
||||
else
|
||||
Result:=Result+'.'+ShortName;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TPasToJSConverter.CreateReferencePathExpr(El: TPasElement;
|
||||
|
||||
@ -10381,35 +10381,40 @@ begin
|
||||
' TObject = class',
|
||||
' public',
|
||||
' Intern: longint external name ''$Intern'';',
|
||||
' Bracket: longint external name ''["A B"]'';',
|
||||
' end;',
|
||||
'']),
|
||||
LinesToStr([
|
||||
'']));
|
||||
|
||||
StartUnit(true);
|
||||
Add('interface');
|
||||
Add('uses unit2;');
|
||||
Add('{$modeswitch externalclass}');
|
||||
Add('type');
|
||||
Add(' TCar = class(tobject)');
|
||||
Add(' public');
|
||||
Add(' Intern2: longint external name ''$Intern2'';');
|
||||
Add(' procedure DoIt;');
|
||||
Add(' end;');
|
||||
Add('implementation');
|
||||
Add('procedure tcar.doit;');
|
||||
Add('begin');
|
||||
Add(' Intern:=Intern+1;');
|
||||
Add(' Intern2:=Intern2+2;');
|
||||
Add('end;');
|
||||
Add('var Obj: TCar;');
|
||||
Add('begin');
|
||||
Add(' obj.intern:=obj.intern+1;');
|
||||
Add(' obj.intern2:=obj.intern2+2;');
|
||||
Add(' with obj do begin');
|
||||
Add(' intern:=intern+1;');
|
||||
Add(' intern2:=intern2+2;');
|
||||
Add(' end;');
|
||||
Add([
|
||||
'interface',
|
||||
'uses unit2;',
|
||||
'{$modeswitch externalclass}',
|
||||
'type',
|
||||
' TCar = class(tobject)',
|
||||
' public',
|
||||
' Intern2: longint external name ''$Intern2'';',
|
||||
' procedure DoIt;',
|
||||
' end;',
|
||||
'implementation',
|
||||
'procedure tcar.doit;',
|
||||
'begin',
|
||||
' Intern:=Intern+1;',
|
||||
' Intern2:=Intern2+2;',
|
||||
' Bracket:=Bracket+3;',
|
||||
'end;',
|
||||
'var Obj: TCar;',
|
||||
'begin',
|
||||
' obj.intern:=obj.intern+1;',
|
||||
' obj.intern2:=obj.intern2+2;',
|
||||
' obj.Bracket:=obj.Bracket+3;',
|
||||
' with obj do begin',
|
||||
' intern:=intern+1;',
|
||||
' intern2:=intern2+2;',
|
||||
' Bracket:=Bracket+3;',
|
||||
' end;']);
|
||||
ConvertUnit;
|
||||
CheckSource('TestClass_ExternalVar',
|
||||
LinesToStr([
|
||||
@ -10418,15 +10423,18 @@ begin
|
||||
' this.DoIt = function () {',
|
||||
' this.$Intern = this.$Intern + 1;',
|
||||
' this.$Intern2 = this.$Intern2 + 2;',
|
||||
' this["A B"] = this["A B"] + 3;',
|
||||
' };',
|
||||
' });',
|
||||
'']),
|
||||
LinesToStr([
|
||||
'$impl.Obj.$Intern = $impl.Obj.$Intern + 1;',
|
||||
'$impl.Obj.$Intern2 = $impl.Obj.$Intern2 + 2;',
|
||||
'$impl.Obj["A B"] = $impl.Obj["A B"] + 3;',
|
||||
'var $with1 = $impl.Obj;',
|
||||
'$with1.$Intern = $with1.$Intern + 1;',
|
||||
'$with1.$Intern2 = $with1.$Intern2 + 2;',
|
||||
'$with1["A B"] = $with1["A B"] + 3;',
|
||||
'']),
|
||||
LinesToStr([ // implementation
|
||||
'$impl.Obj = null;',
|
||||
|
||||
@ -2399,9 +2399,10 @@ function(){
|
||||
type
|
||||
TWrapper = class
|
||||
private
|
||||
// let's assume this object has a $Handle and an $id
|
||||
// let's assume this object has the properties "$Handle", "$id", and "0"
|
||||
public
|
||||
Id: NativeInt; external name '$Id';
|
||||
x: NativeInt; external name '[0]';
|
||||
function GetState(typ: longint): NativeInt; external name '$Handle.GetState';
|
||||
procedure DoIt;
|
||||
end;
|
||||
@ -2413,7 +2414,8 @@ var
|
||||
W: TWrapper;
|
||||
Begin
|
||||
W.Id := 2;
|
||||
W.GetState(3);
|
||||
W.x := 3;
|
||||
W.GetState(4);
|
||||
End.
|
||||
</pre>
|
||||
</td>
|
||||
@ -2430,7 +2432,8 @@ function(){
|
||||
this.W = null;
|
||||
$mod.$main = function(){
|
||||
$mod.W.$Id = 2;
|
||||
$mod.W.$Handle.GetState(3);
|
||||
$mod.W[0] = 3;
|
||||
$mod.W.$Handle.GetState(4);
|
||||
};
|
||||
},
|
||||
[]);
|
||||
@ -2439,6 +2442,9 @@ function(){
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<ul>
|
||||
<li>Non identifiers like "0" or "A B" must be enclosed in brackets.</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
|
||||
Loading…
Reference in New Issue
Block a user