mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-13 17:59:27 +02:00
405 lines
12 KiB
ObjectPascal
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.
|
|
|