fpc/utils/fpgmake/fpmakeparsejson.pas
2012-03-22 16:40:58 +00:00

405 lines
12 KiB
ObjectPascal

unit fpmakeParseJSon;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils,
fpmkunit,
jsonparser, fpjson;
function ParseFpmake(AJsonData : TJSONData) : TPackages;
function ParseFpmakeFile(AFileName: string) : TPackages;
function ExtStringToOSes(AString: String) : TOSes;
function ExtOSesToString(AOSes: TOSes) : string;
function ExtStringToCPUs(AString: String) : TCpus;
function ExtCPUsToString(ACPUs: TCPUs) : string;
implementation
var GSetStrings: TStringList;
function SetStrings: TstringList;
begin
if not assigned(GSetStrings) then
GSetStrings := TStringList.Create;
result := GSetStrings;
end;
function ExtStringToOSes(AString: String) : TOSes;
var
i: dword;
begin
try
result := OSesToString(AString);
except
i := SetStrings.Add(AString)+1;
result:=TOSes(dword(dword(AllOSes)+dword(i)));
end;
end;
function ExtOSesToString(AOSes: TOSes) : string;
var
i: dword;
begin
if DWord(AOSes) < DWord(AllOSes) then
result := '[' + OSesToString(AOSes) + ']'
else
begin
i := (dword(AOSes) - dword(AllOSes)) -1;
if i < SetStrings.Count then
result := SetStrings[i]
else
raise exception.Create('Invalid set of OSes.');
end;
end;
function ExtStringToCPUs(AString: String) : TCpus;
var
i: dword;
begin
try
result := StringToCPUS(AString);
except
i := SetStrings.Add(AString)+1;
result:=TCPUS(dword(dword(AllCPUs)+dword(i)));
end;
end;
function ExtCPUsToString(ACPUs: TCPUs) : string;
var
i: dword;
begin
if DWord(ACPUs) < DWord(AllCPUs) then
result := '[' + CPUSToString(ACPUs) + ']'
else
begin
i := (dword(ACPUs) - dword(AllCPUs)) -1;
if i < SetStrings.Count then
result := SetStrings[i]
else
raise exception.Create('Invalid set of CPUs.');
end;
end;
procedure ParseConditionalString(ADependency: TConditionalString; AJsonData: TJSonData; ValueCaption: string);
var
AJsonObject: TJSONObject;
m: Integer;
begin
if AJsonData.JSONType = jtString then
begin
ADependency.Value := AJsonData.AsString;
end
else if AJsonData.JSONType = jtObject then
begin
AJsonObject := AJsonData as TJSONObject;
for m := 0 to AJsonObject.Count-1 do
begin
case AJsonObject.Names[m] of
'oses' : ADependency.oses := ExtStringToOSes(AJsonObject.Items[m].AsString);
'cpus' : ADependency.CPUs := ExtStringToCPUS(AJsonObject.Items[m].AsString);
else if AJsonObject.Names[m] = ValueCaption then
ADependency.Value := AJsonObject.Items[m].AsString
else
raise Exception.CreateFmt('Unknown conditional property ''%s''.',[AJsonObject.Names[m]]);
end {case}
end;
end
else
raise Exception.CreateFmt('Invalid conditional. (%s)',[AJsonData.AsString]);
end;
procedure ParseConditionalArray(ACondStrings: TConditionalStrings; AJsonData: TJSonData; ValueCaption: string);
var
AJSonArray: TJSONArray;
n: Integer;
begin
if AJsonData.JSONType = jtArray then
begin
AJSonArray := AJsonData as TJSONArray;
for n := 0 to AJSonArray.Count-1 do
ParseConditionalString(ACondStrings.add(''), AJSonArray.Items[n], ValueCaption);
end
else
ParseConditionalString(ACondStrings.add(''), AJsonData, ValueCaption);
end;
procedure ParseDependenciesArray(ACondStrings: TDependencies; AJsonData: TJSonData; ValueCaption: string; aDepType: TDependencyType);
var
AJSonArray: TJSONArray;
n: Integer;
function GetDep: TDependency;
begin
if aDepType=depInclude then
result := ACondStrings.AddInclude('')
else if aDepType=depUnit then
result := ACondStrings.AddUnit('')
else
result := ACondStrings.Add('');
end;
begin
if AJsonData.JSONType = jtArray then
begin
AJSonArray := AJsonData as TJSONArray;
for n := 0 to AJSonArray.Count-1 do
ParseConditionalString(GetDep, AJSonArray.Items[n], ValueCaption);
end
else
ParseConditionalString(GetDep, AJsonData, ValueCaption);
end;
procedure ParseDependencies(aDependencies: TDependencies; aJSONData: TJSONData);
var
AJsonObject: TJSONObject;
m: Integer;
begin
if aJSONData.JSONType<>jtObject then
raise exception.create('A target''s dependency has to be an object which encapsulated the different types of dependencies.')
else
begin
AJsonObject := aJSONData as TJSONObject;
for m := 0 to AJsonObject.Count-1 do
begin
case AJsonObject.Names[m] of
'includefiles' : ParseDependenciesArray(aDependencies, AJsonObject.items[m],'filename', depInclude);
'units' : ParseDependenciesArray(aDependencies, AJsonObject.items[m],'filename', depUnit);
else
raise Exception.CreateFmt('Unknown dependency property ''%s''.',[AJsonObject.Names[m]]);
end {case}
end;
end
end;
procedure ParseUnitTarget(aTarget: TTarget; aJSONData: TJSONData);
var
AJsonObject: TJSONObject;
m: Integer;
begin
if aJSONData.JSONType=jtString then
aTarget.Name := aJSONData.AsString
else if aJSONData.JSONType=jtObject then
begin
AJsonObject := aJSONData as TJSONObject;
for m := 0 to AJsonObject.Count-1 do
begin
case AJsonObject.Names[m] of
'name' : aTarget.name := AJsonObject.items[m].asstring;
'resourcestrings' : atarget.ResourceStrings := (AJsonObject.items[m] as TJSONBoolean).AsBoolean;
'oses' : aTarget.OSes := ExtStringToOSes(AJsonObject.Items[m].AsString);
'cpus' : aTarget.cpus := ExtStringToCPUs(AJsonObject.Items[m].AsString);
'dependencies' : ParseDependencies(aTarget.Dependencies, AJsonObject.Items[m]);
else
raise Exception.CreateFmt('Unknown targets property ''%s''.',[AJsonObject.Names[m]]);
end {case}
end;
end
else
raise Exception.CreateFmt('Invalid target ''%s''',[aJSONData.AsString]);
end;
procedure ParseUnitTargets(aTargets: TTargets; aJSONData: TJSONData);
var
AJsonArray: TJSONArray;
AJsonObject: TJSONObject;
AResourceStrings: boolean;
ACPUs: TCPUS;
AOSes: TOSes;
m: Integer;
LastTargetItem: integer;
ATarget: ttarget;
begin
if aJSONData.JSONType=jtArray then
begin
AJsonArray := aJSONData as TJSONArray;
for m := 0 to AJsonArray.Count-1 do
ParseUnitTarget(aTargets.AddUnit(''), AJsonArray.Items[m]);
end
else if aJSONData.JSONType=jtObject then
begin
AJsonObject := aJSONData as TJSONObject;
AresourceStrings:=false;
ACpus:=AllCPUs;
AOses:=AllOSes;
LastTargetItem:=aTargets.Count;
for m := 0 to AJsonObject.Count-1 do
begin
case AJsonObject.Names[m] of
'resourcestrings' : AresourceStrings := (AJsonObject.items[m] as TJSONBoolean).AsBoolean;
'cpus' : ACPUs := ExtStringToCPUs(AJsonObject.items[m].AsString);
'oses' : AOSes := ExtStringToOSes(AJsonObject.items[m].AsString);
'targets' : ParseUnitTargets(aTargets, AJsonObject.items[m])
else
raise Exception.CreateFmt('Unknown targets property ''%s''.',[AJsonObject.Names[m]]);
end {case}
end;
for m := LastTargetItem to aTargets.Count-1 do
begin
aTarget := aTargets.Items[m] as TTarget;
if AresourceStrings then
aTarget.ResourceStrings := AresourceStrings;
if ACPUs<>AllCPUs then
ATarget.CPUs := ACpus;
if AOSes<>AllOSes then
ATarget.OSes := AOses;
end;
end
else
raise Exception.CreateFmt('Invalid unit target ''%s''',[aJSONData.AsString]);
end;
procedure ParseTargets(aTargets: TTargets; aJSONData: TJSONData);
var
AJsonObject: TJSONObject;
m: Integer;
begin
if aJSONData.JSONType<>jtObject then
raise Exception.Create('Invalid targets');
AJsonObject := aJSONData as TJSONObject;
for m := 0 to AJsonObject.Count-1 do
begin
case AJsonObject.Names[m] of
'units' : ParseUnitTargets(aTargets, AJsonObject.items[m]);
else
raise Exception.CreateFmt('Unknown targets property ''%s''.',[AJsonObject.Names[m]]);
end {case}
end;
end;
function ParseFpmakeFile(AFileName: string) : TPackages;
var
AJsonData : TJSONData;
F : TFileStream;
P: TJSONParser;
begin
result := nil;
// Parse the JSON-file
F:=TFileStream.Create(AFileName,fmopenRead);
try
P:=TJSONParser.Create(F);
try
try
AJsonData := P.Parse;
except
on E: Exception do
begin
writeln(Format('Error: Syntax of JSON-file %s is incorrect (%s)', [AFileName, e.Message]));
exit;
end;
end;
finally
P.Free;
end;
finally
F.Free;
end;
try
result := ParseFpmake(AJsonData);
except
on E: Exception do
begin
writeln(Format('Error, problem in file %s: %s',[AFileName,e.Message]));
exit;
end;
end;
end;
function ParseFpmake(AJsonData : TJSONData) : TPackages;
Var
P : TJSONParser;
MainObject : TJSONObject;
ItemObject : TJSONObject;
i: Integer;
APackages: TPackages;
n: Integer;
procedure AddDependencies(APackage: TPackage; AJsonDependencies: TJSONData);
var
AJsonDependenciesObj: TJSONObject;
m,n,o: Integer;
ADependency: TDependency;
begin
if AJsonDependencies.JSONType<>jtObject then
raise Exception.CreateFmt('Invalid dependencies for package %s',[APackage.Name]);
AJsonDependenciesObj := AJsonDependencies as TJSONObject;
for m := 0 to AJsonDependenciesObj.Count-1 do
begin
case AJsonDependenciesObj.Names[m] of
'packages' : ParseConditionalArray(APackage.Dependencies, AJsonDependenciesObj.items[m],'name');
else
raise Exception.CreateFmt('Unknown dependency property ''%s''.',[ItemObject.Names[m]]);
end {case}
end;
end;
var
APackage: TPackage;
begin
// Convert the JSON-Data to a packages-class
if AJsonData.JSONType <> jtObject then
raise Exception.Create('File does not contain any objects.');
APackages := TPackages.Create(TPackage);
try
MainObject := AJsonData as TJSONObject;
for i := 0 to MainObject.Count-1 do
begin
if MainObject.Names[i]='package' then
begin
AJsonData := MainObject.Items[i];
if (AJsonData.JSONType <> jtObject) then
raise Exception.Create('File does not contain any objects.');
ItemObject := AJsonData as TJSONObject;
APackage := APackages.AddPackage('');
for n := 0 to ItemObject.Count-1 do
begin
case ItemObject.Names[n] of
'title' : APackage.Name := ItemObject.items[n].AsString;
'directory' : APackage.Directory := ItemObject.items[n].AsString;
'version' : APackage.version := ItemObject.items[n].AsString;
'oses' : APackage.OSes := ExtStringToOSes(ItemObject.items[n].AsString);
'cpus' : APackage.CPUs := ExtStringToCPUs(ItemObject.items[n].AsString);
'dependencies' : AddDependencies(APackage, ItemObject.items[n]);
'sourcepaths' : ParseConditionalArray(APackage.SourcePath, ItemObject.items[n],'path');
'targets' : ParseTargets(APackage.Targets, ItemObject.items[n]);
'email' : APackage.Email := ItemObject.items[n].AsString;
'author' : APackage.Author := ItemObject.items[n].AsString;
'license' : APackage.License := ItemObject.items[n].AsString;
'homepageurl' : APackage.HomepageURL := ItemObject.items[n].AsString;
'description' : APackage.Description := ItemObject.items[n].AsString;
'needlibc' : APackage.NeedLibC := (ItemObject.items[n] as TJSONBoolean).AsBoolean;
else
raise Exception.CreateFmt('Unknown package property ''%s''.',[ItemObject.Names[n]]);
end {case}
end;
end;
end;
Result := APackages;
except
APackages.Free;
raise;
end;
end;
initialization
GSetStrings := nil;
finalization
GSetStrings.Free;
end.