Files
lazarus-ccr/bindings/android-sdk/android_sdk_bindings_gen.pas
sekelsenmat 2dbb8ee493 More advances for the android sdk bindings gen
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@1679 8e941d3f-bd1b-0410-a28a-d453659cc2b4
2011-06-15 13:32:40 +00:00

347 lines
9.9 KiB
ObjectPascal

unit android_sdk_bindings_gen;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils;
type
{ TAndroidSDKBindingsGen }
TAndroidSDKBindingsGen = class
private
FSourceFile, FPasOutputClasses, FPasOutputIDs, FPasOutputImpl: TStringList;
FJavaOutputIDs, FJavaOutputMethods: TStringList;
FClassName: string; // Class name of the class currently being parsed
FClassNum, FMethodNum: Integer;
procedure ProcessModelFile(ASourceFile, APasOutputFile, AJavaOutputFile: string);
procedure ProcessModelLine(ASourceLine: string);
procedure ProcessModelMethodClass(ASourceLine: string);
procedure ProcessModelMethodLine(ASourceLine: string);
function GetNextWord(ALine: string; var AStartPos: Integer): string;
function GetPascalTypeName(ABaseName: string): string;
public
constructor Create;
destructor Destroy; override;
procedure GenerateAllBindings(AInputDir, APasOutputDir, AJavaOutputDir: string);
end;
var
AndroidSDKBindingsGen: TAndroidSDKBindingsGen;
implementation
{ TAndroidSDKBindingsGen }
procedure TAndroidSDKBindingsGen.ProcessModelFile(ASourceFile, APasOutputFile,
AJavaOutputFile: string);
var
i: Integer;
lPasOutputFile: TStringList;
lJavaOutputFile: TStringList;
begin
lPasOutputFile := TStringList.Create;
lJavaOutputFile := TStringList.Create;
try
FSourceFile.LoadFromFile(ASourceFile);
// Preparations
FClassName := '';
for i := 0 to FSourceFile.Count - 1 do
begin
ProcessModelLine(FSourceFile.Strings[i]);
end;
// Now save the Pascal file
lPasOutputFile.Add('unit ;');
lPasOutputFile.Add('');
lPasOutputFile.Add('interface');
lPasOutputFile.Add('');
lPasOutputFile.Add('type');
lPasOutputFile.AddStrings(FPasOutputClasses);
lPasOutputFile.Add(' end;');
lPasOutputFile.Add('');
lPasOutputFile.Add('implementation');
lPasOutputFile.Add('');
lPasOutputFile.Add('const');
lPasOutputFile.AddStrings(FPasOutputIDs);
lPasOutputFile.Add('');
lPasOutputFile.AddStrings(FPasOutputImpl);
lPasOutputFile.Add('');
lPasOutputFile.Add('end.');
lPasOutputFile.SaveToFile(APasOutputFile);
// Now save the Java file
lJavaOutputFile.Add('');
lJavaOutputFile.AddStrings(FJavaOutputIDs);
lJavaOutputFile.Add('');
lJavaOutputFile.AddStrings(FJavaOutputMethods);
lJavaOutputFile.Add('');
lJavaOutputFile.SaveToFile(AJavaOutputFile);
finally
lJavaOutputFile.Free;
lPasOutputFile.Free;
end;
end;
procedure TAndroidSDKBindingsGen.ProcessModelLine(ASourceLine: string);
var
lReaderPos: Integer = 1;
lCurWord: string;
begin
if ASourceLine = '' then Exit;
lCurWord := GetNextWord(ASourceLine, lReaderPos);
// Comments
if ASourceLine[1] = '#' then Exit;
// Starting a new class
if ASourceLine[1] = '[' then
begin
ProcessModelMethodClass(ASourceLine);
Exit;
end;
// Adding methods to a class
if lCurWord = 'method' then
begin
ProcessModelMethodLine(ASourceLine);
Exit;
end;
end;
procedure TAndroidSDKBindingsGen.ProcessModelMethodClass(ASourceLine: string);
var
lReaderPos: Integer = 1;
lCurWord, lParentClassName: string;
begin
if ASourceLine = '' then Exit;
lCurWord := GetNextWord(ASourceLine, lReaderPos);
if FClassName <> '' then
begin
FPasOutputClasses.Add(' end;');
FPasOutputClasses.Add('');
end;
FClassName := GetPascalTypeName(lCurWord);
lParentClassName := GetNextWord(ASourceLine, lReaderPos);
lParentClassName := GetPascalTypeName(lParentClassName);
FPasOutputClasses.Add(Format(' %s = class(%s)', [FClassName, lParentClassName]));
FPasOutputClasses.Add(' public');
lCurWord := GetNextWord(ASourceLine, lReaderPos);
Inc(FClassNum);
FMethodNum := 0;
FPasOutputIDs.Add(' // ' + FClassName);
FJavaOutputIDs.Add(' // ' + FClassName);
end;
procedure TAndroidSDKBindingsGen.ProcessModelMethodLine(
ASourceLine: string);
var
lReaderPos: Integer = 1;
lParamNum: Integer = 1;
lCurWord, lParentClassName: string;
lMethodReturn, lMethodName, lParamType, lParamName: string;
DeclarationBase, TmpStr, lIDString: string;
FPasOutputImplCurLine: Integer;
lJavaParamVar, lJavaParams, lJavaParamSelf: string;
begin
if ASourceLine = '' then Exit;
lCurWord := GetNextWord(ASourceLine, lReaderPos);
// Method type and name
lMethodReturn := GetNextWord(ASourceLine, lReaderPos);
lMethodReturn := GetPascalTypeName(lMethodReturn);
lMethodName := GetNextWord(ASourceLine, lReaderPos);
if lMethodReturn = 'void' then DeclarationBase := 'procedure '
else DeclarationBase := 'function ';
// Beginning of the implementation part
FPasOutputImplCurLine := FPasOutputImpl.Count;
lIDString := 'amkUI_' + FClassName + '_' + lMethodName;
FPasOutputImpl.Add('begin');
FPasOutputImpl.Add(' vAndroidPipesComm.SendByte(ShortInt(amkUICommand));');
FPasOutputImpl.Add(' vAndroidPipesComm.SendInt(' + lIDString + ');');
FPasOutputImpl.Add(' vAndroidPipesComm.SendInt(Index); // Self, Java Pointer');
lJavaParamSelf := 'param_self_' + FClassName;
FJavaOutputMethods.Add(' // ' + ASourceLine);
FJavaOutputMethods.Add(' case ' + lIDString + ':');
FJavaOutputMethods.Add(' DebugOut("' + lIDString + '");');
FJavaOutputMethods.Add(' // Self');
FJavaOutputMethods.Add(' lInt = MyAndroidPipesComm.GetInt();');
FJavaOutputMethods.Add(' ' + lJavaParamSelf + ' = (' + FClassName + ') ViewElements.get(lInt);');
FJavaOutputMethods.Add(' // params');
// Lists of constants for the IDs
FPasOutputIDs.Add(' ' + lIDString + ' = 0' + IntToHex(FClassNum*$1000+FMethodNum, 8) + ';');
FJavaOutputIDs.Add(' static final int ' + lIDString + ' = 0x0' + IntToHex(FClassNum*$1000+FMethodNum, 8) + ';');
// Add all parameters
TmpStr := lMethodName + '(';
repeat
lParamType := GetNextWord(ASourceLine, lReaderPos);
lParamType := GetPascalTypeName(lParamType);
lParamName := GetNextWord(ASourceLine, lReaderPos);
if lParamName = '' then Break;
TmpStr := TmpStr + lParamName + ': ' + lParamType + '; ';
// Pascal parameter sending
FPasOutputImpl.Add(' vAndroidPipesComm.SendInt(Integer(' + lParamName + '));');
// Java parameter reading
lJavaParamVar := 'l' + lParamType + '_' + IntToStr(lParamNum);
FJavaOutputMethods.Add(' ' + lJavaParamVar + ' = MyAndroidPipesComm.GetInt();');
lJavaParams := lJavaParams + lJavaParamVar + ', ';
Inc(lParamNum);
until lParamName = '';
// Remove the last ; for the parameters, if necessary
if TmpStr[Length(TmpStr)-1] = ';' then TmpStr := System.Copy(TmpStr, 0, Length(TmpStr)-2);
// And for Java params too
lJavaParams := System.Copy(lJavaParams, 0, Length(lJavaParams)-2);
// Add the return
if lMethodReturn = 'void' then
begin
TmpStr := TmpStr + ');';
FPasOutputImpl.Add(' vAndroidPipesComm.WaitForReturn();');
end
else
begin
TmpStr := TmpStr + '): ' + lMethodReturn + ';';
FPasOutputImpl.Add(' Result := Boolean(vAndroidPipesComm.WaitForIntReturn());');
end;
FPasOutputClasses.Add(' ' + DeclarationBase + TmpStr);
FPasOutputImpl.Insert(FPasOutputImplCurLine, DeclarationBase + FClassName + '.' + TmpStr);
FPasOutputImpl.Add('end;');
FPasOutputImpl.Add('');
FJavaOutputMethods.Add(' //');
if lMethodReturn = 'void' then
begin
FJavaOutputMethods.Add(' ' + lJavaParamSelf + '.' + lMethodName + '(' + lJavaParams + ');');
FJavaOutputMethods.Add(' MyAndroidPipesComm.SendResult();');
end
else
begin
FJavaOutputMethods.Add(' lResult_' + lMethodReturn + ' ' + lJavaParamSelf + '.' + lMethodName + '(' + lJavaParams + ');');
FJavaOutputMethods.Add(' MyAndroidPipesComm.SendIntResult(lResult_' + lMethodReturn + ');');
end;
FJavaOutputMethods.Add(' break;');
Inc(FMethodNum);
end;
{ Reads one word in a string, starting at AStartPos (1-based index)
and going up to a space or comma or ( or ) or another separator }
function TAndroidSDKBindingsGen.GetNextWord(ALine: string;
var AStartPos: Integer): string;
const
WordSeparators = [' ','(',')','[',']',',',#9];
var
lState: Integer = 0;
begin
Result := '';
while AStartPos <= Length(ALine) do
begin
// Searching the word start
if lState = 0 then
begin
if ALine[AStartPos] in WordSeparators then Inc(AStartPos)
else
begin
Result := ALine[AStartPos];
Inc(AStartPos);
lState := 1;
end;
end
// Reading until the word finishes
else
begin
if ALine[AStartPos] in WordSeparators then Exit
else
begin
Result := Result + ALine[AStartPos];
Inc(AStartPos);
end;
end;
end;
end;
function TAndroidSDKBindingsGen.GetPascalTypeName(ABaseName: string): string;
begin
if ABaseName = '' then Exit('');
if ABaseName = 'int' then Result := 'Integer'
else if ABaseName = 'boolean' then Result := 'Boolean'
else if ABaseName = 'void' then Result := ABaseName
else if ABaseName = 'CharSequence' then Result := 'string'
else if ABaseName = 'TJavaObject' then Result := ABaseName
else Result := 'T' + ABaseName;
end;
constructor TAndroidSDKBindingsGen.Create;
begin
FSourceFile := TStringList.Create;
FPasOutputClasses := TStringList.Create;
FPasOutputImpl := TStringList.Create;
FPasOutputIDs := TStringList.Create;
FJavaOutputIDs := TStringList.Create;
FJavaOutputMethods := TStringList.Create;
FClassNum := $100;
end;
destructor TAndroidSDKBindingsGen.Destroy;
begin
FSourceFile.Free;
FPasOutputClasses.Free;
FPasOutputImpl.Free;
FPasOutputIDs.Free;
FJavaOutputIDs.Free;
FJavaOutputMethods.Free;
inherited Destroy;
end;
procedure TAndroidSDKBindingsGen.GenerateAllBindings(AInputDir, APasOutputDir,
AJavaOutputDir: string);
begin
ProcessModelFile(IncludeTrailingPathDelimiter(AInputDir) + 'android_view.txt',
IncludeTrailingPathDelimiter(APasOutputDir) + 'android_view.pas',
IncludeTrailingPathDelimiter(AJavaOutputDir) + 'android_view.java');
end;
initialization
AndroidSDKBindingsGen := TAndroidSDKBindingsGen.Create;
finalization
AndroidSDKBindingsGen.Free;
end.