Repository URL to install this package:
Version:
3.0.0 ▾
|
{
This file is part of the Free Component Library (FCL)
Copyright (c) 2014 by Michael Van Canneyt
Pascal to Javascript converter class.
See the file COPYING.FPC, included in this distribution,
for details about the copyright.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
**********************************************************************}
unit fppas2js;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, jsbase, jstree, pastree, pparser;
Type
EPas2JS = Class(Exception);
{ TPasToJSConverter }
TConvertContext = Class(TObject)
end;
TPasToJSConverter = Class(TObject)
private
FCurrentContext: TJSElement;
FMainFunction: TJSString;
FNameSpace: TJSString;
Procedure AddToSourceElements(Src: TJSSourceElements; El: TJSElement);
Function CreateConstDecl(El: TPasElement; AContext: TConvertContext): TJSElement;
Function CreateIdentifierExpr(AName: String; El: TPasElement; AContext: TConvertContext): TJSElement;
Function CreateTypeDecl(El: TPasElement; AContext: TConvertContext): TJSElement;
Function CreateVarDecl(El: TPasElement; AContext: TConvertContext): TJSElement;
procedure SetCurrentContext(AValue: TJSElement);
protected
// helper functions
Procedure DoError(Const Msg : String);
Procedure DoError(Const Msg : String; Const Args : Array of Const);
// Never create an element manually, always use the below function
Function CreateElement(C: TJSElementClass; Src: TPasElement): TJSElement; virtual;
Function GetExpressionValueType(El: TPasExpr; AContext: TConvertContext ): TJSType; virtual;
Function GetIdentValueType(AName: String; AContext: TConvertContext): TJSType; virtual;
Function TransFormIdent(El: TJSPrimaryExpressionIdent; AContext : TConvertContext): TJSElement;virtual;
Function CreateJSContext(AContext : TConvertContext): TJSElement;virtual;
Function TransFormVariableName(Const AName : String; AContext : TConvertContext) : String;
Function TransFormVariableName(El : TPasElement; AContext : TConvertContext) : String;
Function TransFormFunctionName(El : TPasElement; AContext : TConvertContext) : String;
Function GetExceptionObjectname(AContext : TConvertContext) : String;
Function ResolveType(El : TPasElement; AContext : TConvertContext) : TPasType;
// Statements
Function ConvertImplBlockElements(El: TPasImplBlock; AContext: TConvertContext): TJSElement;virtual;
Function ConvertBeginEndStatement(El: TPasImplBeginBlock; AContext: TConvertContext): TJSElement;virtual;
Function ConvertStatement(El: TPasImplStatement; AContext: TConvertContext ): TJSElement;virtual;
Function ConvertAssignStatement(El: TPasImplAssign; AContext: TConvertContext): TJSElement; virtual;
Function ConvertRaiseStatement(El: TPasImplRaise; AContext: TConvertContext ): TJSElement; virtual;
Function ConvertIfStatement(El: TPasImplIfElse; AContext: TConvertContext ): TJSElement; virtual;
Function ConvertWhileStatement(El: TPasImplWhileDo; AContext: TConvertContext): TJSElement; virtual;
Function ConvertRepeatStatement(El: TPasImplRepeatUntil; AContext: TConvertContext): TJSElement; virtual;
Function ConvertForStatement(El: TPasImplForLoop; AContext: TConvertContext): TJSElement; virtual;
Function ConvertFinalizationSection(El: TFinalizationSection; AContext: TConvertContext): TJSElement;virtual;
Function ConvertInitializationSection(El: TInitializationSection; AContext: TConvertContext): TJSElement;virtual;
Function ConvertSimpleStatement(El: TPasImplSimple; AContext: TConvertContext): TJSElement;virtual;
Function ConvertTryStatement(El: TPasImplTry; AContext: TConvertContext ): TJSElement;virtual;
Function ConvertWithStatement(El: TPasImplWithDo; AContext: TConvertContext): TJSElement;virtual;
Function ConvertTryFinallyStatement(El: TPasImplTryFinally; AContext: TConvertContext): TJSElement;virtual;
Function ConvertExceptOn(El: TPasImplExceptOn; AContext: TConvertContext): TJSElement;
Function ConvertTryExceptStatement(El: TPasImplTryExcept; AContext: TConvertContext): TJSElement;
// Expressions
Function ConvertArrayValues(El: TArrayValues; AContext : TConvertContext): TJSElement;virtual;
Function ConvertInheritedExpression(El: TInheritedExpr; AContext : TConvertContext): TJSElement;virtual;
Function ConvertNilExpr(El: TNilExpr; AContext : TConvertContext): TJSElement;virtual;
Function ConvertParamsExpression(El: TParamsExpr; AContext : TConvertContext): TJSElement;virtual;
Function ConvertRecordValues(El: TRecordValues; AContext : TConvertContext): TJSElement;virtual;
Function ConvertSelfExpression(El: TSelfExpr; AContext : TConvertContext): TJSElement;virtual;
Function ConvertBinaryExpression(El: TBinaryExpr; AContext : TConvertContext): TJSElement;virtual;
Function ConvertBoolConstExpression(El: TBoolConstExpr; AContext : TConvertContext): TJSElement;virtual;
Function ConvertPrimitiveExpression(El: TPrimitiveExpr; AContext : TConvertContext): TJSElement;virtual;
Function ConvertUnaryExpression(El: TUnaryExpr; AContext : TConvertContext ): TJSElement;virtual;
Function ConvertCallExpression(El: TParamsExpr; AContext : TConvertContext ): TJSElement;virtual;
Function TransFormStringLiteral(S : String) : String;
// Convert various TPasElement nodes
Function ConvertProperty(El: TPasProperty; AContext : TConvertContext ): TJSElement;virtual;
Function ConvertCommand(El: TPasImplCommand; AContext : TConvertContext): TJSElement;virtual;
Function ConvertCommands(El: TPasImplCommands; AContext : TConvertContext): TJSElement;virtual;
Function ConvertConst(El: TPasConst; AContext : TConvertContext): TJSElement;virtual;
Function ConvertDeclarations(El: TPasDeclarations; AContext : TConvertContext): TJSElement;virtual;
Function ConvertExportSymbol(El: TPasExportSymbol; AContext : TConvertContext): TJSElement;virtual;
Function ConvertExpression(El: TPasExpr; AContext : TConvertContext): TJSElement;virtual;
Function ConvertImplBlock(El: TPasImplBlock; AContext : TConvertContext ): TJSElement;virtual;
Function ConvertLabelMark(El: TPasImplLabelMark; AContext : TConvertContext): TJSElement;virtual;
Function ConvertLabels(El: TPasLabels; AContext : TConvertContext): TJSElement;virtual;
Function ConvertModule(El: TPasModule; AContext : TConvertContext): TJSElement;virtual;
Function ConvertPackage(El: TPasPackage; AContext : TConvertContext): TJSElement;virtual;
Function ConvertArgument(El: TPasArgument; AContext : TConvertContext): TJSElement;virtual;
Function ConvertProcedure(El: TPasProcedure; AContext : TConvertContext): TJSElement;virtual;
Function ConvertProcedureImpl(El: TPasProcedureImpl; AContext : TConvertContext ): TJSElement;virtual;
Function ConvertResString(El: TPasResString; AContext : TConvertContext): TJSElement;virtual;
Function ConvertResultElement(El: TPasResultElement; AContext : TConvertContext): TJSElement;virtual;
Function ConvertType(El: TPasElement; AContext : TConvertContext): TJSElement;virtual;
Function ConvertVariable(El: TPasVariable; AContext : TConvertContext): TJSElement;virtual;
Function ConvertElement(El : TPasElement; AContext : TConvertContext) : TJSElement; virtual;
Property CurrentContext : TJSElement Read FCurrentContext Write SetCurrentContext;
Public
Function ConvertElement(El : TPasElement) : TJSElement;
Property NameSpace : TJSString Read FNameSpace Write FNameSpace;
Property MainFunction : TJSString Read FMainFunction Write FMainFunction;
end;
EPasToJS = Class(Exception);
implementation
resourcestring
SErrUNknownExpressionClass = 'Unknown expression class: %s';
SErrUnexpected = 'Unexpected class: %s';
SerrInitalizedArray = 'Initialized array variables not yet supported';
{ TPasToJSConverter }
Procedure TPasToJSConverter.AddToSourceElements(Src : TJSSourceElements; El : TJSElement);
Var
L : TJSStatementList;
A : TJSElement;
begin
Repeat
if Not (EL is TJSStatementList) then
begin
A:=EL;
El:=Nil;
end
else
begin
L:=EL as TJSStatementList;
A:=L.A;
EL:=L.B;
L.A:=Nil;
L.B:=Nil;
FreeAndNil(L);
end;
Src.Statements.AddNode.Node:=A;
until (El=Nil);
end;
Function TPasToJSConverter.ConvertModule(El: TPasModule; AContext : TConvertContext): TJSElement;
Var
I : Integer;
Src : TJSSourceElements;
begin
Result:=Nil;
Src:=TJSSourceElements(CreateElement(TJSSourceElements,El));
Result:=Src;
if Assigned(El.InterfaceSection) then
AddToSourceElements(Src,ConvertElement(El.InterfaceSection,AContext));
if assigned(El.ImplementationSection) then
AddToSourceElements(Src,ConvertElement(El.ImplementationSection,AContext));
if (El is TPasProgram) then
begin
if Assigned(TPasProgram(El).ProgramSection) then
AddToSourceElements(Src,ConvertElement(TPasProgram(El).ProgramSection,AContext));
end;
if Assigned(El.InitializationSection) then
AddToSourceElements(Src,ConvertElement(El.InitializationSection,AContext));
if Assigned(El.FinalizationSection) then
AddToSourceElements(Src,ConvertElement(El.FinalizationSection,AContext));
{
TPasUnitModule = Class(TPasModule)
TPasLibrary = class(TPasModule)
}
end;
Function TPasToJSConverter.CreateElement(C : TJSElementClass; Src : TPasElement) : TJSElement;
begin
if Assigned(Src) then
Result:=C.Create(Src.SourceLinenumber,1,Src.SourceFilename)
else
Result:=C.Create(0,0,'');
end;
Function TPasToJSConverter.ConvertUnaryExpression(El: TUnaryExpr; AContext : TConvertContext): TJSElement;
Var
C : TJSElementClass;
U : TJSUnaryExpression;
E : TJSElement;
begin
Result:=Nil;
E:=ConvertElement(El.Operand);
Case el.OpCode of
eopAdd:
begin
U:=TJSUnaryPlusExpression(CreateElement(TJSUnaryPlusExpression,El));
U.A:=E;
end;
eopSubtract:
begin
U:=TJSUnaryPlusExpression(CreateElement(TJSUnaryMinusExpression,El));
U.A:=E;
end;
end;
Result:=U;
end;
Function TPasToJSConverter.ConvertCallExpression(El: TParamsExpr;
AContext: TConvertContext): TJSElement;
Var
C : TJSElementClass;
U : TJSUnaryExpression;
E : TJSElement;
Id : TJSPrimaryExpressionIdent;
begin
Raise EPasToJS.CreateFmt(SErrUnexpected,[EL.ClassName]);
Result:=Nil;
ID:=TJSPrimaryExpressionIdent(CreateElement(TJSPrimaryExpressionIdent,EL));
Case el.OpCode of
eopAdd:
begin
U:=TJSUnaryPlusExpression(CreateElement(TJSUnaryPlusExpression,El));
U.A:=E;
end;
eopSubtract:
begin
U:=TJSUnaryPlusExpression(CreateElement(TJSUnaryMinusExpression,El));
U.A:=E;
end;
end;
Result:=U;
end;
Function TPasToJSConverter.TransFormStringLiteral(S: String): String;
begin
// This needs some more complicated algorithm that handles #13"abc etc.
Result:=Copy(S,2,Length(S)-2);
Result:=StringReplace(Result,'''''','''',[rfReplaceAll]);
end;
Function TPasToJSConverter.GetIdentValueType(AName : String; AContext : TConvertContext): TJSType;
begin
Result:=jstUNDEFINED;
end;
Function TPasToJSConverter.GetExpressionValueType(El : TPasExpr; AContext : TConvertContext) : TJSType;
Function CombineValueType(A,B : TJSType) : TJSType;
begin
If (A=jstUndefined) then
Result:=B
else if (B=jstundefined) then
Result:=A
else
Result:=A; // pick the first
end;
Var
A,B : TJSType;
begin
if (El is TBoolConstExpr) then
Result:=jstBoolean
else If (EL is TPrimitiveExpr) then
begin
Case EL.Kind of
pekIdent : Result:=GetIdentValueType(El.Name,AContext);
pekNumber : Result:=jstNumber;
pekString : Result:=jstString;
pekSet : Result:=jstUNDEFINED;
pekNil : Result:=jstNull;
pekBoolConst : Result:=jstBoolean;
pekRange : Result:=jstUNDEFINED;
pekFuncParams : Result:=jstUNDEFINED;
pekArrayParams : Result:=jstUNDEFINED;
pekListOfExp : Result:=jstUNDEFINED;
pekInherited : Result:=jstUNDEFINED;
pekSelf : Result:=jstObject;
end
end
else if (EL is TUnaryExpr) then
Result:=GetExpressionValueType(TUnaryExpr(El).Operand,AContext)
else if (EL is TBinaryExpr) then
begin
A:=GetExpressionValueType(TBinaryExpr(El).Left,AContext);
B:=GetExpressionValueType(TBinaryExpr(El).Right,AContext);
Result:=CombineValueType(A,B);
end
else
result:=jstUndefined
end;
Function TPasToJSConverter.ConvertBinaryExpression(El: TBinaryExpr; AContext : TConvertContext): TJSElement;
Type
TJSBinaryClass = Class of TJSBinary;
Const
BinClasses : Array [TExprOpCode] of TJSBinaryClass = (
Nil, //eopEmpty,
TJSAdditiveExpressionPlus,
TJSAdditiveExpressionMinus,
TJSMultiplicativeExpressionMul,
TJSMultiplicativeExpressionDiv,
TJSMultiplicativeExpressionDiv,
TJSMultiplicativeExpressionMod,
Nil, //eopPower
TJSRShiftExpression,
TJSLShiftExpression,
Nil, // Not
Nil, // And
Nil, // Or
Nil, // XOr
TJSEqualityExpressionEQ,
TJSEqualityExpressionNE,
TJSRelationalExpressionLT,
TJSRelationalExpressionGT,
TJSRelationalExpressionLE,
TJSRelationalExpressionGE,
Nil, // In
TJSRelationalExpressionInstanceOf, // is
Nil, // As
Nil, // Symmetrical diff
Nil, // Address,
Nil, // Deref
Nil // SubIndent,
);
Var
R : TJSBinary;
C : TJSBinaryClass;
A,B : TJSElement;
begin
Result:=Nil;
C:=BinClasses[EL.OpCode];
A:=ConvertElement(EL.left,AContext);
try
B:=ConvertElement(EL.right,AContext);
except
FreeAndNil(A);
Raise;
end;
if (C=Nil) then
Case EL.OpCode of
eopAs : begin
Result:=ConvertElement(El.Left,AContext);
end;
eopAnd,
eopOr,
eopXor :
begin
if (GetExpressionValueType(EL.Left,AContext)=jstNumber)
or (GetExpressionValueType(EL.Right,AContext)=jstNumber) then
Case EL.OpCode of
eopAnd : C:=TJSBitwiseAndExpression;
eopOr : C:=TJSBitwiseOrExpression;
eopXor : C:=TJSBitwiseXOrExpression;
end
else
Case EL.OpCode of
eopAnd : C:=TJSLogicalAndExpression;
eopOr : C:=TJSLogicalOrExpression;
eopXOR : DoError('Logical XOR not supported yet');
end;
end;
eopSubIdent :
begin
Result:=TJSDotMemberExpression(CreateElement(TJSDotMemberExpression,El));
TJSDotMemberExpression(Result).Mexpr:=A;
if Not (B is TJSPrimaryExpressionIdent) then
DOError('Member expression must be an identifier');
TJSDotMemberExpression(Result).Name:=TJSPrimaryExpressionIdent(B).Name;
FreeAndNil(B);
end
else
DoError('Unknown/Unsupported operand type for binary expression');
end;
if (Result=Nil) and (C<>Nil) then
begin
R:=TJSBinary(CreateElement(C,EL));
R.A:=A;
R.B:=B;
Result:=R;
end;
end;
Function TPasToJSConverter.TransFormIdent(El: TJSPrimaryExpressionIdent; AContext : TConvertContext): TJSElement;
begin
EL.Name:=LowerCase(EL.Name);
Result:=El;
end;
Function TPasToJSConverter.CreateIdentifierExpr(AName : String; El : TPasElement; AContext : TConvertContext): TJSElement;
Var
I : TJSPrimaryExpressionIdent;
begin
I:=TJSPrimaryExpressionIdent(CreateElement(TJSPrimaryExpressionIdent,El));
I.Name:=AName;
Result:=TransFormIdent(I,AContext);
end;
Function TPasToJSConverter.ConvertPrimitiveExpression(El: TPrimitiveExpr; AContext : TConvertContext): TJSElement;
Var
L : TJSLiteral;
D : TJSNumber;
C : Integer;
begin
Result:=Nil;
case El.Kind of
pekString:
begin
L:=TJSLiteral(CreateElement(TJSLiteral,El));
L.Value.AsString:=TransFormStringLiteral(El.Value);
Result:=L;
end;
pekNumber:
begin
L:=TJSLiteral(CreateElement(TJSLiteral,El));
Val(El.Value,D,C);
if C<>0 then
DoError('Invalid number: %s',[EL.Value]);
L.Value.AsNumber:=D;
Result:=L;
end;
pekIdent:
begin
Result:=CreateIdentifierExpr(El.Value,El,AContext);
end;
end;
end;
Function TPasToJSConverter.ConvertBoolConstExpression(El: TBoolConstExpr; AContext : TConvertContext): TJSElement;
Var
L : TJSLiteral;
begin
Result:=Nil;
L:=TJSLiteral(CreateElement(TJSLiteral,El));
L.Value.AsBoolean:=EL.Value;
Result:=L;
end;
Function TPasToJSConverter.ConvertNilExpr(El: TNilExpr; AContext : TConvertContext): TJSElement;
Var
L : TJSLiteral;
begin
L:=TJSLiteral(CreateElement(TJSLiteral,El));
L.Value.IsNull:=True;
Result:=L;
end;
Function TPasToJSConverter.ConvertInheritedExpression(El: TInheritedExpr; AContext : TConvertContext): TJSElement;
begin
Result:=Nil;
// TInheritedExpr = class(TPasExpr)
end;
Function TPasToJSConverter.ConvertSelfExpression(El: TSelfExpr; AContext : TConvertContext): TJSElement;
begin
Result:=TJSPrimaryExpressionThis(CreateElement(TJSPrimaryExpressionThis,El));
end;
Function TPasToJSConverter.ConvertParamsExpression(El: TParamsExpr; AContext : TConvertContext): TJSElement;
Var
b,B2 : TJSBracketMemberExpression;
C : TJSCallExpression;
I : Integer;
E : TJSElement;
begin
Result:=Nil;
Case EL.Kind of
pekFuncParams :
begin
C:=TJSCallExpression(CreateElement(TJSCallExpression,El));
try
C.Expr:=ConvertElement(El.Value,AContext);
if (Length(EL.Params)>0) then
begin
C.Args:=TJSArguments(CreateElement(TJSArguments,El));
For I:=0 to Length(EL.Params)-1 do
begin
E:=ConvertElement(EL.Params[i]);
C.Args.Elements.AddElement.Expr:=E;
end;
end;
except
FreeAndNil(C);
Raise;
end;
Result:=C;
end;
pekArrayParams:
begin
if Length(EL.Params)<>1 then
Raise EPasToJS.Create('Only 1-dimensional expressions allowed at this point');
B:=TJSBracketMemberExpression(CreateElement(TJSBracketMemberExpression,El));;
B.Mexpr:=ConvertElement(El.Value,AContext);
Result:=B;
B.Name:=ConvertElement(EL.Params[0],AContext);
end
end;
end;
Function TPasToJSConverter.ConvertRecordValues(El: TRecordValues; AContext : TConvertContext): TJSElement;
Var
R : TJSObjectLiteral;
I : Integer;
It : TRecordValuesItem;
rel : TJSObjectLiteralElement;
begin
R:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,El));
For I:=0 to Length(El.Fields)-1 do
begin
it:=El.Fields[i];
Rel:=R.Elements.AddElement;
Rel.Name:=it.Name;
Rel.Expr:=ConvertElement(it.ValueExp,AContext);
end;
Result:=R;
end;
Function TPasToJSConverter.ConvertArrayValues(El: TArrayValues; AContext : TConvertContext): TJSElement;
Var
R : TJSArrayLiteral;
I : Integer;
rel : TJSArrayLiteralElement;
begin
R:=TJSArrayLiteral(CreateElement(TJSObjectLiteral,El));
For I:=0 to Length(El.Values)-1 do
begin
Rel:=R.Elements.AddElement;
Rel.ElementIndex:=i;
Rel.Expr:=ConvertElement(El.Values[i],AContext);
end;
Result:=R;
end;
Function TPasToJSConverter.ConvertExpression(El: TPasExpr; AContext : TConvertContext): TJSElement;
begin
Result:=Nil;
if (El is TUnaryExpr) then
Result:=ConvertUnaryExpression(TUnaryExpr(El),AContext)
else if (El is TBinaryExpr) then
Result:=ConvertBinaryExpression(TBinaryExpr(El),AContext)
else if (El is TPrimitiveExpr) then
Result:=ConvertPrimitiveExpression(TPrimitiveExpr(El),AContext)
else if (El is TBoolConstExpr) then
Result:=ConvertBoolConstExpression(TBoolConstExpr(El),AContext)
else if (El is TNilExpr) then
Result:=ConvertNilExpr(TNilExpr(El),AContext)
else if (El is TInheritedExpr) then
Result:=ConvertInheritedExpression(TInheritedExpr(El),AContext)
else if (El is TSelfExpr) then
Result:=ConvertSelfExpression(TSelfExpr(El),AContext)
else if (El is TParamsExpr) then
Result:=ConvertParamsExpression(TParamsExpr(El),AContext)
else if (El is TRecordValues) then
Result:=ConvertRecordValues(TRecordValues(El),AContext)
else if (El is TRecordValues) then
Result:=ConvertRecordValues(TRecordValues(El),AContext)
else
DoError(SErrUNknownExpressionClass,[EL.ClassName])
end;
Function TPasToJSConverter.CreateConstDecl(El: TPasElement; AContext : TConvertContext): TJSElement;
Var
C : TJSElement;
V : TJSVariableStatement;
begin
C:=ConvertElement(El,AContext);
V:=TJSVariableStatement(CreateElement(TJSVariableStatement,El));
V.A:=C;
Result:=V;
end;
Function TPasToJSConverter.CreateTypeDecl(El: TPasElement; AContext : TConvertContext): TJSElement;
begin
Result:=Nil;
// Need to do something for classes and records.
end;
Function TPasToJSConverter.CreateVarDecl(El: TPasElement; AContext : TConvertContext): TJSElement;
Var
C : TJSElement;
V : TJSVariableStatement;
begin
C:=ConvertElement(El,AContext);
V:=TJSVariableStatement(CreateElement(TJSVariableStatement,El));
V.A:=C;
Result:=V;
end;
Function TPasToJSConverter.ConvertDeclarations(El: TPasDeclarations; AContext : TConvertContext): TJSElement;
Var
P : TPasElement;
SL,SL2 : TJSStatementList;
E : TJSElement;
I : Integer;
Procedure AddToSL;
begin
if Assigned(E) then
begin
if Assigned(SL.A) then
begin
SL2:=TJSStatementList(CreateElement(TJSStatementList,El));
SL.B:=SL2;
SL:=SL2;
end;
SL.A:=E;
end;
end;
begin
SL:=TJSStatementList(CreateElement(TJSStatementList,El));
Result:=SL;
For I:=0 to El.Declarations.Count-1 do
begin
E:=Nil;
P:=TPasElement(El.Declarations[i]);
if P is TPasConst then
E:=CreateConstDecl(P,AContext)
else if P is TPasVariable then
E:=CreateVarDecl(P,AContext)
else if P is TPasType then
E:=CreateTypeDecl(P,AContext)
else if P is TPasProcedure then
E:=ConvertElement(P as TPasProcedure,AContext)
else
DoError('Unknown class: "%s" ',[P.ClassName]);
AddToSL;
end;
if (El is TProcedureBody) then
begin
E:=ConvertElement(TProcedureBody(El).Body,AContext);
AddToSl;
end;
{
TPasDeclarations = class(TPasElement)
TPasSection = class(TPasDeclarations)
TInterfaceSection = class(TPasSection)
TImplementationSection = class(TPasSection)
TProgramSection = class(TImplementationSection)
TLibrarySection = class(TImplementationSection)
TProcedureBody = class(TPasDeclarations)
}
end;
Function TPasToJSConverter.ConvertType(El: TPasElement; AContext : TConvertContext): TJSElement;
begin
Result:=Nil;
{
TPasType = class(TPasElement)
TPasPointerType = class(TPasType)
TPasAliasType = class(TPasType)
TPasTypeAliasType = class(TPasAliasType)
TPasClassOfType = class(TPasAliasType)
TPasRangeType = class(TPasType)
TPasArrayType = class(TPasType)
TPasFileType = class(TPasType)
TPasEnumValue = class(TPasElement)
TPasEnumType = class(TPasType)
TPasSetType = class(TPasType)
TPasVariant = class(TPasElement)
TPasRecordType = class(TPasType)
TPasClassType = class(TPasType)
TPasProcedureType = class(TPasType)
TPasFunctionType = class(TPasProcedureType)
TPasUnresolvedSymbolRef = class(TPasType)
TPasUnresolvedTypeRef = class(TPasUnresolvedSymbolRef)
TPasUnresolvedUnitRef = Class(TPasUnresolvedSymbolRef)
TPasStringType = class(TPasUnresolvedTypeRef)
TPasTypeRef = class(TPasUnresolvedTypeRef)
}
end;
Function TPasToJSConverter.ConvertProcedure(El: TPasProcedure; AContext : TConvertContext): TJSElement;
Var
FS : TJSFunctionDeclarationStatement;
FD : TJSFuncDef;
begin
FS:=TJSFunctionDeclarationStatement(CreateElement(TJSFunctionDeclarationStatement,EL));
Result:=FS;
FD:=TJSFuncDef.Create;
FD.Name:=TransFormFunctionName(El,AContext);
FS.AFunction:=FD;
FD.Body:=TJSFunctionBody(CreateElement(TJSFunctionBody,EL.Body));
FD.Body.A:=ConvertElement(El.Body,AContext);
{
TPasProcedureBase = class(TPasElement)
TPasOverloadedProc = class(TPasProcedureBase)
TPasProcedure = class(TPasProcedureBase)
TPasFunction = class(TPasProcedure)
TPasOperator = class(TPasProcedure)
TPasConstructor = class(TPasProcedure)
TPasDestructor = class(TPasProcedure)
TPasClassProcedure = class(TPasProcedure)
TPasClassFunction = class(TPasProcedure)
}
end;
Function TPasToJSConverter.ConvertProcedureImpl(El: TPasProcedureImpl; AContext : TConvertContext): TJSElement;
Var
FS : TJSFunctionDeclarationStatement;
FD : TJSFuncDef;
begin
FS:=TJSFunctionDeclarationStatement(CreateElement(TJSFunctionDeclarationStatement,EL));
Result:=FS;
FD:=TJSFuncDef.Create;
FD.Name:=TransFormFunctionName(El,AContext);
FS.AFunction:=FD;
FD.Body:=TJSFunctionBody(CreateElement(TJSFunctionBody,EL.Body));
FD.Body.A:=ConvertElement(El.Body,AContext);
{
TPasProcedureImpl = class(TPasElement)
TPasConstructorImpl = class(TPasProcedureImpl)
TPasDestructorImpl = class(TPasProcedureImpl)
}
end;
Function TPasToJSConverter.ConvertBeginEndStatement(El: TPasImplBeginBlock; AContext : TConvertContext): TJSElement;
begin
Result:=ConvertImplBlockElements(El,AContext);
end;
Function TPasToJSConverter.ConvertImplBlockElements(El: TPasImplBlock; AContext : TConvertContext): TJSElement;
var
B : TJSElement;
S,S2 : TJSStatementList;
I : Integer;
begin
if Not (Assigned(EL.Elements) and (EL.Elements.Count>0)) then
Result:=TJSEmptyBlockStatement(CreateElement(TJSEmptyBlockStatement,El))
else
begin
S:=TJSStatementList(CreateElement(TJSStatementList,TPasImplElement(EL)));
Result:=S;
For I:=0 to EL.Elements.Count-1 do
begin
B:=ConvertElement(TPasImplElement(EL.Elements[i]),AContext);
if not Assigned(S.A) then
S.A:=B
else
begin
if Assigned(S.B) then
begin
S2:=TJSStatementList(CreateElement(TJSStatementList,TPasImplElement(EL.Elements[i])));
S2.A:=S.B;
S.B:=S2;
S:=S2;
end;
S.B:=B;
end;
end;
end;
end;
Function TPasToJSConverter.ConvertInitializationSection(El: TInitializationSection; AContext : TConvertContext): TJSElement;
begin
Result:=ConvertImplBlockElements(El,AContext);
end;
Function TPasToJSConverter.ConvertFinalizationSection(El: TFinalizationSection; AContext : TConvertContext): TJSElement;
begin
Result:=ConvertImplBlockElements(El,AContext);
end;
Function TPasToJSConverter.ConvertTryStatement(El: TPasImplTry; AContext : TConvertContext): TJSElement;
Var
B,F : TJSElement;
T : TJSTryStatement;
IsFin : Boolean;
begin
F:=Nil;
B:=ConvertImplBlockElements(El,AContext);
try
F:=ConvertElement(El.FinallyExcept);
IsFin:=El.FinallyExcept is TPasImplTryFinally;
if IsFin then
T:=TJSTryFinallyStatement(CreateElement(TJSTryFinallyStatement,El))
else
begin
T:=TJSTryCatchStatement(CreateElement(TJSTryCatchStatement,El));
T.Ident:=GetExceptionObjectname(AContext);
end;
except
FreeAndNil(B);
FreeAndNil(F);
Raise;
end;
if IsFin then
T.BFinally:=F
else
T.BCatch:=F;
T.Block:=B;
Result:=T;
end;
Function TPasToJSConverter.ConvertTryFinallyStatement(El: TPasImplTryFinally; AContext : TConvertContext): TJSElement;
begin
Result:=ConvertImplBlockElements(El,AContext);
end;
Function TPasToJSConverter.ConvertTryExceptStatement(El: TPasImplTryExcept; AContext : TConvertContext): TJSElement;
begin
Result:=ConvertImplBlockElements(El,AContext);
end;
Function TPasToJSConverter.ConvertImplBlock(El: TPasImplBlock; AContext : TConvertContext): TJSElement;
begin
Result:=Nil;
if (EL is TPasImplStatement) then
Result:=ConvertStatement(TPasImplStatement(El),AContext)
else if (EL is TPasImplIfElse) then
Result:=ConvertIfStatement(TPasImplIfElse(El),AContext)
else if (El is TPasImplRepeatUntil) then
Result:=ConvertRepeatStatement(TPasImplRepeatUntil(El),AContext)
else if (El is TPasImplBeginBlock) then
Result:=ConvertBeginEndStatement(TPasImplBeginBlock(El),AContext)
else if (El is TInitializationSection) then
Result:=ConvertInitializationSection(TInitializationSection(El),AContext)
else if (El is TFinalizationSection) then
Result:=ConvertFinalizationSection(TFinalizationSection(El),AContext)
else if (El is TPasImplTry) then
Result:=ConvertTryStatement(TPasImplTry(El),AContext)
else if (El is TPasImplTryFinally) then
Result:=ConvertTryFinallyStatement(TPasImplTryFinally(El),AContext)
else if (El is TPasImplTryExcept) then
Result:=ConvertTryExceptStatement(TPasImplTryExcept(El),AContext);
(*
TPasImplBlock = class(TPasImplElement)
TPasImplCaseOf = class(TPasImplBlock)
TPasImplStatement = class(TPasImplBlock)
TPasImplCaseElse = class(TPasImplBlock)
TPasImplTry = class(TPasImplBlock)
TPasImplTryHandler = class(TPasImplBlock)
TPasImplTryFinally = class(TPasImplTryHandler)
TPasImplTryExcept = class(TPasImplTryHandler)
TPasImplTryExceptElse = class(TPasImplTryHandler)
*)
end;
Function TPasToJSConverter.ConvertPackage(El: TPasPackage; AContext : TConvertContext): TJSElement;
begin
Result:=Nil;
// TPasPackage = class(TPasElement)
end;
Function TPasToJSConverter.ConvertResString(El: TPasResString; AContext : TConvertContext): TJSElement;
begin
Result:=Nil;
// TPasPackage = class(TPasElement)
end;
Function TPasToJSConverter.ConvertArgument(El: TPasArgument; AContext : TConvertContext): TJSElement;
begin
Result:=Nil;
// TPasPackage = class(TPasElement)
end;
Function TPasToJSConverter.ConvertResultElement(El: TPasResultElement; AContext : TConvertContext): TJSElement;
begin
Result:=Nil;
// TPasPackage = class(TPasElement)
end;
Function TPasToJSConverter.ConvertVariable(El: TPasVariable; AContext : TConvertContext): TJSElement;
Var
V : TJSVarDeclaration;
T : TPasType;
L : TJSLiteral;
begin
V:=TJSVarDeclaration(CreateElement(TJSVarDeclaration,El));
V.Name:=TransFormVariableName(EL,AContext);
T:=ResolveType(EL.VarType,AContext);
if (T is TPasArrayType) then
begin
V.Init:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,EL.VarType));
If Assigned(EL.Expr) then
Raise EPasToJS.Create(SerrInitalizedArray);
end
else If Assigned(EL.Expr) then
V.Init:=ConvertElement(El.Expr,AContext);
Result:=V;
// TPasPackage = class(TPasElement)
end;
Function TPasToJSConverter.ConvertConst(El: TPasConst; AContext : TConvertContext): TJSElement;
begin
Result:=Nil;
// TPasPackage = class(TPasElement)
end;
Function TPasToJSConverter.ConvertProperty(El: TPasProperty; AContext : TConvertContext): TJSElement;
begin
Result:=Nil;
// TPasProperty = class(TPasVariable)
end;
Function TPasToJSConverter.ConvertExportSymbol(El: TPasExportSymbol; AContext : TConvertContext): TJSElement;
begin
Result:=Nil;
// TPasPackage = class(TPasElement)
end;
Function TPasToJSConverter.ConvertLabels(El: TPasLabels; AContext : TConvertContext): TJSElement;
begin
Result:=Nil;
// TPasLabels = class(TPasImplElement)
end;
Function TPasToJSConverter.ConvertRaiseStatement(El: TPasImplRaise; AContext : TConvertContext): TJSElement;
Var
E : TJSElement;
T : TJSThrowStatement;
begin
if El.ExceptObject<>Nil then
E:=ConvertElement(El.ExceptObject)
else
E:=CreateIdentifierExpr(GetExceptionObjectName(AContext),El,AContext);
T:=TJSThrowStatement(CreateElement(TJSThrowStatement,El));
T.A:=E;
Result:=T;
end;
Function TPasToJSConverter.ConvertAssignStatement(El: TPasImplAssign; AContext : TConvertContext): TJSElement;
Var
LHS,RHS : TJSElement;
T : TJSAssignStatement;
begin
LHS:=ConvertElement(El.left);
try
RHS:=ConvertElement(El.Right);
except
FreeAndNil(LHS);
Raise;
end;
T:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
T.Expr:=RHS;
T.LHS:=LHS;
Result:=T;
end;
Function TPasToJSConverter.ConvertCommand(El: TPasImplCommand; AContext : TConvertContext): TJSElement;
begin
Result:=Nil;
// TPasImplCommand = class(TPasImplElement)
end;
Function TPasToJSConverter.ConvertIfStatement(El: TPasImplIfElse; AContext : TConvertContext): TJSElement;
Var
C,BThen,BElse : TJSElement;
T : TJSIfStatement;
begin
C:=Nil;
BThen:=Nil;
BElse:=Nil;
try
C:=ConvertElement(El.ConditionExpr);
if Assigned(El.IfBranch) then
BThen:=ConvertElement(El.IfBranch)
else
BThen:=TJSEmptyBlockStatement(CreateElement(TJSEmptyBlockStatement,El));
if Assigned(El.ElseBranch) then
BElse:=ConvertElement(El.ElseBranch);
except
FreeAndNil(C);
FreeAndNil(BThen);
FreeAndNil(BElse);
Raise;
end;
T:=TJSIfStatement(CreateElement(TJSIfStatement,El));
T.Cond:=C;
T.Btrue:=BThen;
T.BFalse:=BElse;
Result:=T;
end;
Function TPasToJSConverter.ConvertWhileStatement(El: TPasImplWhileDo; AContext : TConvertContext): TJSElement;
Var
C : TJSElement;
B : TJSElement;
W : TJSWhileStatement;
begin
Result:=Nil;
C:=Nil;
B:=Nil;
try
C:=ConvertElement(EL.ConditionExpr,AContext);
if Assigned(EL.Body) then
B:=ConvertElement(EL.Body,AContext)
else
B:=TJSEmptyBlockStatement(CreateElement(TJSEmptyBlockStatement,El));
except
FreeAndNil(B);
FreeAndNil(C);
Raise;
end;
W:=TJSWhileStatement(CreateElement(TJSWhileStatement,El));
W.Cond:=C;
W.body:=B;
Result:=W;
end;
Function TPasToJSConverter.ConvertRepeatStatement(El: TPasImplRepeatUntil; AContext: TConvertContext): TJSElement;
Var
C : TJSElement;
N : TJSUnaryNotExpression;
W : TJSDoWhileStatement;
B : TJSElement;
begin
Result:=Nil;
C:=Nil;
B:=Nil;
try
C:=ConvertElement(EL.ConditionExpr,AContext);
N:=TJSUnaryNotExpression(CreateElement(TJSUnaryNotExpression,EL.ConditionExpr));
N.A:=C;
B:=ConvertImplBlockElements(El,AContext);
except
FreeAndNil(B);
FreeAndNil(C);
Raise;
end;
W:=TJSDoWhileStatement(CreateElement(TJSDoWhileStatement,El));
W.Cond:=N;
W.body:=B;
Result:=W;
end;
Function TPasToJSConverter.ConvertForStatement(El: TPasImplForLoop;
AContext: TConvertContext): TJSElement;
Var
F : TJSForStatement;
L : TJSStatementList;
I : TJSSimpleAssignStatement;
V : TJSVarDeclaration;
VD : TJSVariableStatement;
u : TJSUNaryExpression;
B : TJSBinaryExpression;
MV : String;
begin
Result:=Nil;
B:=Nil;
L:=TJSStatementList(CreateElement(TJSStatementList,El));
Result:=L;
try
VD:=TJSVariableStatement(CreateElement(TJSVariableStatement,El));
L.A:=VD;
V:=TJSVarDeclaration(CreateElement(TJSVarDeclaration,El));
VD.A:=V;
MV:=TransFormVariableName(El.VariableName,AContext)+'$endloopvalue';
V.Name:=MV;
V.Init:=ConvertElement(EL.EndExpr,AContext);
F:=TJSForStatement(CreateElement(TJSForStatement,El));
L.B:=F;
I:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El.StartExpr));
F.Init:=I;
I.LHS:=CreateIdentifierExpr(EL.VariableName,el,AContext);
I.Expr:=ConvertElement(El.StartExpr,AContext);
If El.Down then
begin
U:=TJSUnaryPostMinusMinusExpression(CreateElement(TJSUnaryPostMinusMinusExpression,El));
B:=TJSRelationalExpressionGE(CreateElement(TJSRelationalExpressionGE,El.EndExpr));
end
else
begin
U:=TJSUnaryPostPlusPlusExpression(CreateElement(TJSUnaryPostPlusPlusExpression,El));
B:=TJSRelationalExpressionLE(CreateElement(TJSRelationalExpressionLE,El.EndExpr));
end;
F.Incr:=U;
F.Cond:=B;
U.A:=CreateIdentifierExpr(EL.VariableName,El,AContext);
B.A:=CreateIdentifierExpr(EL.VariableName,El,AContext);
B.B:=CreateIdentifierExpr(MV,El.EndExpr,AContext);
F.body:=ConvertElement(EL.Body);
except
FreeAndNil(Result);
Raise;
end;
end;
Function TPasToJSConverter.ConvertSimpleStatement(El: TPasImplSimple; AContext : TConvertContext): TJSElement;
Var
E : TJSElement;
begin
E:=ConvertElement(EL.Expr,AContext);
Result:=TJSExpressionStatement(CreateElement(TJSExpressionStatement,El));
TJSExpressionStatement(Result).A:=E;
end;
Function TPasToJSConverter.ConvertWithStatement(El: TPasImplWithDo; AContext : TConvertContext): TJSElement;
Var
B,E : TJSElement;
W,W2 : TJSWithStatement;
I : Integer;
begin
W:=Nil;
Result:=Nil;
if Assigned(El.Body) then
B:=ConvertElement(El.Body,AContext)
else
B:=TJSEmptyBlockStatement(CreateElement(TJSEmptyBlockStatement,El));
try
For I:=0 to El.Expressions.Count-1 do
begin
E:=ConvertElement(TPasElement(El.Expressions[i]),AContext);
W2:=TJSWithStatement(CreateElement(TJSWithStatement,TPasElement(El.Expressions[i])));
if Not Assigned(Result) then // result is the first
Result:=W2;
if Assigned(W) then // Chain
W.B:=W2;
W:=W2; // W is the last
W.A:=E;
end;
except
FreeAndNil(E);
FreeAndNil(Result);
Raise;
end;
W.B:=B;
end;
Function TPasToJSConverter.GetExceptionObjectname(AContext: TConvertContext): String;
begin
Result:='jsexception';
end;
Function TPasToJSConverter.ResolveType(El: TPasElement;
AContext: TConvertContext): TPasType;
begin
if EL is TPasType then
Result:=TPasType(El) // TPasUnresolvedTypeRef needs handling here
else
Result:=Nil;
end;
Function TPasToJSConverter.ConvertExceptOn(El: TPasImplExceptOn; AContext : TConvertContext): TJSElement;
Var
I : TJSIfStatement;
IO : TJSRelationalExpressionInstanceOf;
L : TJSStatementList;
V : TJSVarDeclaration;
begin
I:=TJSIfStatement(CreateElement(TJSIfStatement,El));
IO:=TJSRelationalExpressionInstanceOf(CreateElement(TJSRelationalExpressionInstanceOf,EL));
IO.A:=CreateIdentifierExpr(GetExceptionObjectName(AContext),El,AContext);
IO.B:=CreateIdentifierExpr(El.TypeName,El,AContext);
I.Cond:=IO;
L:=TJSStatementList(CreateElement(TJSStatementList,EL.Body));
I.btrue:=L;
V:=TJSVarDeclaration(CreateElement(TJSVarDeclaration,EL));
L.A:=V;
V.Name:=TransFormVariableName(EL.VariableName,AContext);//
V.Init:=CreateIdentifierExpr(GetExceptionObjectName(AContext),EL,AContext);
L.B:=TJSStatementList(CreateElement(TJSStatementList,EL.Body));
L:=TJSStatementList(L.B);
L.A:=ConvertElement(EL.Body,AContext);
Result:=I;
end;
Function TPasToJSConverter.ConvertStatement(El: TPasImplStatement; AContext : TConvertContext): TJSElement;
begin
Result:=Nil;
if (El is TPasImplRaise) then
Result:=ConvertRaiseStatement(TPasImplRaise(El),AContext)
else if (El is TPasImplAssign) then
Result:=ConvertAssignStatement(TPasImplAssign(El),AContext)
else if (El is TPasImplWhileDo) then
Result:=ConvertWhileStatement(TPasImplWhileDo(El),AContext)
else if (El is TPasImplSimple) then
Result:=ConvertSimpleStatement(TPasImplSimple(El),AContext)
else if (El is TPasImplWithDo) then
Result:=ConvertWithStatement(TPasImplWithDo(El),AContext)
else if (El is TPasImplExceptOn) then
Result:=ConvertExceptOn(TPasImplExceptOn(El),AContext)
else if (El is TPasImplForLoop) then
Result:=ConvertForStatement(TPasImplForLoop(El),AContext)
else
DoError('Unknown statement Class: %s',[El.ClassName]);
{
TPasImplCaseStatement = class(TPasImplStatement)
}
end;
Function TPasToJSConverter.ConvertCommands(El: TPasImplCommands; AContext : TConvertContext): TJSElement;
begin
Result:=Nil;
// TPasImplCommands = class(TPasImplElement)
end;
Function TPasToJSConverter.ConvertLabelMark(El: TPasImplLabelMark; AContext : TConvertContext): TJSElement;
begin
Result:=Nil;
// TPasImplLabelMark = class(TPasImplLabelMark) then
end;
Function TPasToJSConverter.ConvertElement(El: TPasElement; AContext : TConvertContext): TJSElement;
begin
If (El is TPasPackage) then
Result:=ConvertPackage(TPasPackage(El),AContext)
else If (El is TPasModule) then
Result:=ConvertModule(TPasModule(El),AContext)
else if (EL is TPasExpr) then
Result:=ConvertExpression(TPasExpr(El),AContext)
else if (EL is TPasDeclarations) then
Result:=ConvertDeclarations(TPasDeclarations(El),AContext)
else if (EL is TPasType) then
Result:=ConvertType(TPasType(El),AContext)
else if (EL is TPasProcedure) then
Result:=ConvertProcedure(TPasProcedure(El),AContext)
else if (EL is TPasProcedureImpl) then
Result:=ConvertProcedureImpl(TPasProcedureImpl(El),AContext)
else if (EL is TPasImplBlock) then
Result:=ConvertImplBlock(TPasImplBlock(El),AContext)
else if (EL is TPasResString) then
Result:=ConvertResString(TPasResString(El),AContext)
else if (EL is TPasArgument) then
Result:=ConvertArgument(TPasArgument(El),AContext)
else if (EL is TPasResultElement) then
Result:=ConvertResultElement(TPasResultElement(El),AContext)
else if (EL is TPasConst) then
Result:=ConvertConst(TPasConst(El),AContext)
else if (EL is TPasProperty) then
Result:=ConvertProperty(TPasProperty(El),AContext)
else if (EL is TPasVariable) then
Result:=ConvertVariable(TPasVariable(El),AContext)
else if (EL is TPasExportSymbol) then
Result:=ConvertExportSymbol(TPasExportSymbol(El),AContext)
else if (EL is TPasLabels) then
Result:=ConvertLabels(TPasLabels(El),AContext)
else if (EL is TPasImplCommand) then
Result:=ConvertCommand(TPasImplCommand(El),AContext)
else if (EL is TPasImplCommands) then
Result:=ConvertCommands(TPasImplCommands(El),AContext)
else if (EL is TPasImplLabelMark) then
Result:=ConvertLabelMark(TPasImplLabelMark(El),AContext);
end;
Procedure TPasToJSConverter.DoError(Const Msg: String);
begin
Raise EPas2JS.Create(Msg);
end;
Procedure TPasToJSConverter.DoError(Const Msg: String;
Const Args: Array of Const);
begin
Raise EPas2JS.CreateFmt(Msg,Args);
end;
procedure TPasToJSConverter.SetCurrentContext(AValue: TJSElement);
begin
if FCurrentContext=AValue then Exit;
FCurrentContext:=AValue;
end;
Function TPasToJSConverter.CreateJSContext(AContext : TConvertContext) : TJSElement;
begin
Result:=TJSObjectLiteral.Create(0,0);
end;
Function TPasToJSConverter.TransFormVariableName(Const AName: String;
AContext: TConvertContext): String;
begin
Result:=LowerCase(AName);
end;
Function TPasToJSConverter.TransFormVariableName(El: TPasElement; AContext: TConvertContext): String;
begin
Result:=TransFormVariableName(EL.Name,AContext);
// Add to context.
end;
Function TPasToJSConverter.TransFormFunctionName(El: TPasElement;
AContext: TConvertContext): String;
begin
Result:=LowerCase(EL.Name);
end;
Function TPasToJSConverter.ConvertElement(El: TPasElement): TJSElement;
begin
// CurrentContext:=CreateJSContext(Nil);
Result:=ConvertElement(El,Nil);
end;
end.