diff --git a/DataScraping/XML/Dummy/ScrapXML.pas b/DataScraping/XML/Dummy/ScrapXML.pas index 502fa852..3bfbe1f7 100644 --- a/DataScraping/XML/Dummy/ScrapXML.pas +++ b/DataScraping/XML/Dummy/ScrapXML.pas @@ -1,9 +1,9 @@ uses System; +uses '../../../Utils/ThoroughXML'; uses '../../../POCGL_Utils'; uses '../ScrapUtils'; -uses '../XMLUtils'; // uses '../XMLItems'; uses '../ItemSources'; @@ -20,7 +20,7 @@ inherited Create(name); public static procedure InitAll(types_n: XmlNode) := - foreach var type_n in types_n.Nodes['type'] do + foreach var type_n in types_n.SubNodes['type'] do new BasicTypeSource(type_n['name']); protected function MakeNewItem: BasicType; override := @@ -46,8 +46,8 @@ end; public static procedure InitAll(groups_n: XmlNode) := - foreach var group_n in groups_n.Nodes['group'] do - new GroupSource(group_n['name'], group_n['etype'], group_n.Nodes['enum']); + foreach var group_n in groups_n.SubNodes['group'] do + new GroupSource(group_n['name'], group_n['etype'], group_n.SubNodes['enum']); protected function MakeNewItem: Group; override; @@ -70,10 +70,10 @@ end; public static procedure InitAll(commands_n: XmlNode) := - foreach var command_n in commands_n.Nodes['command'] do + foreach var command_n in commands_n.SubNodes['command'] do new FuncSource( - command_n.Nodes['proto'].Single.Nodes['name'].Single.Text, - command_n.Nodes['proto'] + command_n.Nodes['param'] + command_n.SubNodes['proto'].Single.SubNodes['name'].Single.Text, + command_n.SubNodes['proto'] + command_n.SubNodes['param'] ); protected function MakeNewItem: Func; override; @@ -87,7 +87,7 @@ FeatureSource = sealed class(ItemSource) public static procedure InitAll(features_n: XmlNode) := - foreach var feature_n in features_n.Nodes['feature'] do + foreach var feature_n in features_n.SubNodes['feature'] do new FeatureSource(feature_n['name']); protected function MakeNewItem: Feature; override; @@ -196,7 +196,7 @@ function FuncSource.MakeNewItem: Func; var pars := par_ns.Select((par_n,par_i)-> begin - var par_name := par_n.Nodes['name'].Single.Text; + var par_name := par_n.SubNodes['name'].Single.Text; var text := par_n.Text; var sz := default(ParArrSize); @@ -210,7 +210,7 @@ function FuncSource.MakeNewItem: Func; text := text.RemoveEnd(par_name).TrimEnd; if par_i=0 then par_name := nil; - Result := TypeHelper.MakePar(par_name, par_n.Nodes['type'].Single.Text, text, sz); + Result := TypeHelper.MakePar(par_name, par_n.SubNodes['type'].Single.Text, text, sz); end).ToArray; Result := new Func(new FuncName('', nil, self.Name), self.Name, pars, nil); @@ -239,21 +239,21 @@ function FeatureSource.MakeNewItem: Feature; procedure ScrapXmlFile; begin Otp($'Parsing XML'); - var root := new XmlNode(GetFullPathRTA('xml/Dummy.xml')); + var root := ScrapUtils.GetXml('Dummy'); - BasicTypeSource.InitAll(root.Nodes['types'].Single); + BasicTypeSource.InitAll(root.SubNodes['types'].Single); - GroupSource.InitAll(root.Nodes['groups'].Single); + GroupSource.InitAll(root.SubNodes['groups'].Single); - FuncSource.InitAll(root.Nodes['commands'].Single); + FuncSource.InitAll(root.SubNodes['commands'].Single); - FeatureSource.InitAll(root.Nodes['features'].Single); + FeatureSource.InitAll(root.SubNodes['features'].Single); end; begin try - XMLUtils.Init('../XML/Dummy'); + ScrapUtils.Init('../XML/Dummy'); ScrapXmlFile; diff --git a/DataScraping/XML/OpenCL/ScrapXML.pas b/DataScraping/XML/OpenCL/ScrapXML.pas index 822bd0ad..daedad85 100644 --- a/DataScraping/XML/OpenCL/ScrapXML.pas +++ b/DataScraping/XML/OpenCL/ScrapXML.pas @@ -1,11 +1,11 @@ uses System; +uses '../../../Utils/ThoroughXML'; uses '../../../Utils/AOtp'; uses '../../../POCGL_Utils'; uses '../ScrapUtils'; -uses '../XMLUtils'; // uses '../XMLItems'; uses '../ItemSources'; @@ -70,7 +70,7 @@ private constructor(allow_bitpos: boolean; n: XmlNode); begin inherited Create(MakeName(n['name'], false)); - n.DiscardAttribute('comment'); + n.TryDiscardAttrib('comment'); // self.allow_bitpos := allow_bitpos; var val_s := n['value']; @@ -89,10 +89,16 @@ foreach var enums_n in enums_ns do begin - enums_n.DiscardAttribute('start'); - enums_n.DiscardAttribute('end'); - enums_n.DiscardNodes('comment'); - enums_n.DiscardNodes('unused'); + enums_n.TryDiscardAttrib('start'); + enums_n.TryDiscardAttrib('end'); + enums_n.TryDiscardSubNodes('comment'); + + foreach var unused_n in enums_n.SubNodes['unused'] do + begin + unused_n.TryDiscardAttrib('comment'); + unused_n.DiscardAttrib('start'); + unused_n.TryDiscardAttrib('end'); + end; if enums_n['vendor'] is string(var vendor) then VendorSuffixSource.RequireName(vendor); @@ -101,16 +107,16 @@ begin if enums_n['name'] <> 'Constants' then raise new System.InvalidOperationException; - foreach var enum_n in enums_n.Nodes['enum'] do + foreach var enum_n in enums_n.SubNodes['enum'] do begin - enum_n.DiscardAttribute('value'); + enum_n.DiscardAttrib('value'); if not external_enum_names.Add(enum_n['name']) then raise new System.InvalidOperationException; end; end else begin - enums_n.DiscardAttribute('name'); + enums_n.DiscardAttrib('name'); var allow_bitpos := false; if enums_n['type'] is string(var enums_type) then @@ -119,7 +125,7 @@ else Otp($'WARNING: Unknown enums type [{enums_type}]'); end; - foreach var enum_n in enums_n.Nodes['enum'] do + foreach var enum_n in enums_n.SubNodes['enum'] do new EnumSource(allow_bitpos, enum_n); end; @@ -206,7 +212,7 @@ else raise new System.NotImplementedException(etype); end; - foreach var enum_n in n.Nodes['enum'] do + foreach var enum_n in n.SubNodes['enum'] do begin var ename := EnumSource.MakeName(enum_n['name'], false); var esource := EnumSource.FindOrMakeSource(ename, nil); @@ -288,7 +294,7 @@ public constructor(n: XmlNode); begin inherited Create(MakeName(n['name'], false)); - self.member_ns := n.Nodes['member'].ToArray; + self.member_ns := n.SubNodes['member'].ToArray; end; protected function MakeNewItem: Struct; override; @@ -309,8 +315,8 @@ begin inherited Create(MakeName(n['name'], false)); self.par_ns := ( - n.Nodes['proto'].Single + - n.Nodes['param'] + n.SubNodes['proto'].Single + + n.SubNodes['param'] ).ToArray; end; @@ -339,16 +345,16 @@ public static procedure InitAll(commands_n: XmlNode); begin - foreach var command_n in commands_n.Nodes['command'] do + foreach var command_n in commands_n.SubNodes['command'] do begin - command_n.DiscardAttribute('comment'); - command_n.DiscardAttribute('prefix'); - command_n.DiscardAttribute('suffix'); - var name := command_n.Nodes['proto'].Single.Nodes['name'].Single.Text; + command_n.TryDiscardAttrib('comment'); + command_n.TryDiscardAttrib('prefix'); + command_n.TryDiscardAttrib('suffix'); + var name := command_n.SubNodes['proto'].Single.SubNodes['name'].Single.Text; new FuncSource(MakeName(name, false), name, - command_n.Nodes['proto'] + - command_n.Nodes['param'] + command_n.SubNodes['proto'] + + command_n.SubNodes['param'] ); end; @@ -382,7 +388,7 @@ if feature_n['name'] <> $'CL_VERSION_{name.Major}_{name.Minor}' then raise new System.InvalidOperationException; - new FeatureSource(name, feature_n.Nodes['require']); + new FeatureSource(name, feature_n.SubNodes['require']); end; protected function MakeNewItem: Feature; override; @@ -412,14 +418,14 @@ end; public static procedure InitAll(extensions_n: XmlNode) := - foreach var extension_n in extensions_n.Nodes['extension'] do + foreach var extension_n in extensions_n.SubNodes['extension'] do begin - extension_n.DiscardAttribute('comment'); - extension_n.DiscardAttribute('condition'); + extension_n.TryDiscardAttrib('comment'); + extension_n.TryDiscardAttrib('condition'); if extension_n['supported'] <> 'opencl' then raise new System.NotImplementedException; var name := extension_n['name']; - new ExtensionSource(MakeName(name, false), name, extension_n.Nodes['require'], extension_n['requires']); + new ExtensionSource(MakeName(name, false), name, extension_n.SubNodes['require'], extension_n['requires']); end; protected function MakeNewItem: Extension; override; @@ -559,7 +565,7 @@ function EnumSource.MakeNewItem: Enum; public static procedure InitNode(type_n: XmlNode); begin - type_n.DiscardAttribute('comment'); + type_n.TryDiscardAttrib('comment'); var category := type_n['category']; case category of @@ -571,7 +577,7 @@ function EnumSource.MakeNewItem: Enum; if type_n.Text.StartsWith('#include ') then exit; if type_n.Text<>'' then raise new System.InvalidOperationException($'[{type_n.Text}]'); - type_n.DiscardAttribute('requires'); + type_n.TryDiscardAttrib('requires'); new BasicTypeSource(name); end; @@ -591,8 +597,8 @@ function EnumSource.MakeNewItem: Enum; if 'const' in type_n.Text then raise new System.NotImplementedException(type_n.Text); - var base_t := type_n.Nodes['type'].SingleOrDefault?.Text; - var name := type_n.Nodes['name'].Single.Text; + var base_t := type_n.SubNodes['type'].SingleOrDefault?.Text; + var name := type_n.SubNodes['name'].Single.Text; unreq_type_names += name; var base_ptr := type_n.Text.CountOf('*'); @@ -619,7 +625,7 @@ function EnumSource.MakeNewItem: Enum; end else if type_n.Text.StartsWith('#define ') then begin - var tname := type_n.Nodes['name'].Single.Text; + var tname := type_n.SubNodes['name'].Single.Text; unreq_type_names += tname; if not BasicTypeSource.enum_abusing_type_tag.Add(tname) then raise new System.InvalidOperationException; @@ -645,10 +651,10 @@ function EnumSource.MakeNewItem: Enum; public static procedure InitAll(types_n: XmlNode); begin - types_n.DiscardAttribute('comment'); - types_n.DiscardNodes('comment'); + types_n.DiscardAttrib('comment'); + types_n.TryDiscardSubNodes('comment'); - foreach var type_n in types_n.Nodes['type'] do + foreach var type_n in types_n.SubNodes['type'] do InitNode(type_n); end; @@ -666,7 +672,7 @@ function GroupSource.MakeNewItem: Group; foreach var rn in self.definitions do begin var new_enums := new HashSet; - foreach var enum_n in rn.Nodes['enum'] do + foreach var enum_n in rn.SubNodes['enum'] do begin var ename := enum_n['name']; if ename in EnumSource.external_enum_names then @@ -813,8 +819,8 @@ function StructSource.MakeNewItem: Struct; var fields := member_ns.ConvertAll(member_n-> begin var text := member_n.Text; - var name := member_n.Nodes['name'].SingleOrDefault?.Text; - var tname := member_n.Nodes['type'].SingleOrDefault?.Text; + var name := member_n.SubNodes['name'].SingleOrDefault?.Text; + var tname := member_n.SubNodes['type'].SingleOrDefault?.Text; if (name=nil) and (tname=nil) then begin @@ -832,7 +838,7 @@ function StructSource.MakeNewItem: Struct; end; var len := default(ParArrSize); - if member_n.Nodes['enum'].SingleOrDefault?.Text is string(var static_len_enum_name) then + if member_n.SubNodes['enum'].SingleOrDefault?.Text is string(var static_len_enum_name) then begin var text_end := $'[{static_len_enum_name}]'; if not text.EndsWith(text_end) then raise new System.InvalidOperationException; @@ -860,7 +866,7 @@ function DelegateSource.MakeNewItem: Delegate; var pars := par_ns.ConvertAll((par_n,par_i)-> begin var par_name := if par_i=0 then nil else - par_n.Nodes['name'].Single.Text; + par_n.SubNodes['name'].Single.Text; var text := par_n.Text; var len := default(ParArrSize); @@ -878,7 +884,7 @@ function DelegateSource.MakeNewItem: Delegate; text := text.RemoveEnd(par_name).TrimEnd; end; - Result := TypeHelper.MakePar(par_name, par_n.Nodes['type'].Single.Text, text, len); + Result := TypeHelper.MakePar(par_name, par_n.SubNodes['type'].Single.Text, text, len); end); var res_name := new DelegateName(self.Name.ApiName, self.Name.VendorSuffix, @@ -896,7 +902,7 @@ function FuncSource.MakeNewItem: Func; var pars := par_ns.ConvertAll((par_n,par_i)-> begin - var par_name := par_n.Nodes['name'].Single.Text; + var par_name := par_n.SubNodes['name'].Single.Text; var text := par_n.Text; var len := default(ParArrSize); @@ -910,7 +916,7 @@ function FuncSource.MakeNewItem: Func; text := text.RemoveEnd(par_name).TrimEnd; if par_i=0 then par_name := nil; - Result := TypeHelper.MakePar(par_name, par_n.Nodes['type'].Single.Text, text, len); + Result := TypeHelper.MakePar(par_name, par_n.SubNodes['type'].Single.Text, text, len); end); Result := new Func(self.Name, self.entry_point_name, pars, nil); @@ -957,10 +963,10 @@ function FuncSource.MakeNewItem: Func; var processed_node_types := new HashSet; {$region type} - foreach var type_n in rn.Nodes['type'] do + foreach var type_n in rn.SubNodes['type'] do begin processed_node_types += 'type'; - type_n.DiscardAttribute('comment'); + type_n.TryDiscardAttrib('comment'); var name := type_n['name']; if name.EndsWith('.h') then continue; @@ -975,10 +981,10 @@ function FuncSource.MakeNewItem: Func; {$region enum} if rn['group'] is string(var group) then used_type_names += group; - foreach var enum_n in rn.Nodes['enum'] do + foreach var enum_n in rn.SubNodes['enum'] do begin processed_node_types += 'enum'; - enum_n.DiscardAttribute('comment'); + enum_n.TryDiscardAttrib('comment'); var ename := enum_n['name']; if ename in EnumSource.external_enum_names then continue; @@ -988,15 +994,15 @@ function FuncSource.MakeNewItem: Func; used_type_names += |enum_n['followed'],enum_n['info_type'],enum_n['input_type']|.Where(tname->tname<>nil).Select(tname->tname.TrimEnd('[]*'.ToCharArray)); end; if ('enum' in processed_node_types) <> (rn in GroupSource.group_nodes) then - raise new System.InvalidOperationException($'{rn in GroupSource.group_nodes}: '+rn.Nodes['enum'].Select(n->n['name']).JoinToString); + raise new System.InvalidOperationException($'{rn in GroupSource.group_nodes}: '+rn.SubNodes['enum'].Select(n->n['name']).JoinToString); {$endregion enum} {$region func} - foreach var func_n in rn.Nodes['command'] do + foreach var func_n in rn.SubNodes['command'] do begin processed_node_types += 'func'; - func_n.DiscardAttribute('comment'); - func_n.DiscardAttribute('requires'); + func_n.TryDiscardAttrib('comment'); + func_n.TryDiscardAttrib('requires'); var name := func_n['name']; Result.funcs += FuncSource.FindOrMakeItem(FuncSource.MakeName(name, false)); @@ -1005,14 +1011,14 @@ function FuncSource.MakeNewItem: Func; {$endregion func} case processed_node_types.Count of - 0: raise new System.InvalidOperationException(rn['comment'] ?? rn.Nodes['enum'].Select(n->n['name']).JoinToString ?? 'no comment'); + 0: raise new System.InvalidOperationException(rn['comment'] ?? rn.SubNodes['enum'].Select(n->n['name']).JoinToString ?? 'no comment'); 1: ; else raise new System.NotImplementedException(processed_node_types.JoinToString); end; - rn.DiscardAttribute('comment'); - rn.DiscardAttribute('condition'); - rn.DiscardNodes('comment'); + rn.TryDiscardAttrib('comment'); + rn.TryDiscardAttrib('condition'); + rn.TryDiscardSubNodes('comment'); end; //TODO Uncomment @@ -1062,31 +1068,31 @@ function ExtensionSource.MakeNewItem := procedure ScrapXmlFile(api_name: string); begin Otp($'Parsing "{api_name}"'); - var root := new XmlNode(GetFullPathRTA($'../../Reps/OpenCL-Docs/xml/{api_name}.xml')); - root.DiscardNodes('comment'); + var root := ScrapUtils.GetXml(api_name); + root.TryDiscardSubNodes('comment'); VendorSuffixSource.InitAll; - EnumSource.InitAll(root.Nodes['enums']); + EnumSource.InitAll(root.SubNodes['enums']); - TypeHelper.InitAll(root.Nodes['types'].Single); + TypeHelper.InitAll(root.SubNodes['types'].Single); GroupSource.InitAll( - (root.Nodes['feature'] + root.Nodes['extensions'].Single.Nodes['extension']) - .SelectMany(n->n.Nodes['require']) + (root.SubNodes['feature'] + root.SubNodes['extensions'].Single.SubNodes['extension']) + .SelectMany(n->n.SubNodes['require']) ); - FuncSource.InitAll(root.Nodes['commands'].Single); + FuncSource.InitAll(root.SubNodes['commands'].Single); - FeatureSource.InitAll(root.Nodes['feature']); + FeatureSource.InitAll(root.SubNodes['feature']); - ExtensionSource.InitAll(root.Nodes['extensions'].Single); + ExtensionSource.InitAll(root.SubNodes['extensions'].Single); end; begin try - XMLUtils.Init('OpenCL-Docs'); + ScrapUtils.Init('OpenCL-Docs'); ScrapXmlFile(api); diff --git a/DataScraping/XML/OpenGL/ScrapXML.pas b/DataScraping/XML/OpenGL/ScrapXML.pas index 7656c372..9711ad11 100644 --- a/DataScraping/XML/OpenGL/ScrapXML.pas +++ b/DataScraping/XML/OpenGL/ScrapXML.pas @@ -1,11 +1,11 @@ uses System; +uses '../../../Utils/ThoroughXML'; uses '../../../Utils/AOtp'; uses '../../../POCGL_Utils'; uses '../ScrapUtils'; -uses '../XMLUtils'; // uses '../XMLItems'; uses '../ItemSources'; @@ -137,7 +137,7 @@ private static mentioned := new HashSet; public static procedure InitAll(kinds_n: XmlNode) := - foreach var kind_n in kinds_n.Nodes['kind'] do + foreach var kind_n in kinds_n.SubNodes['kind'] do begin var name := kind_n['name']; var desc := kind_n['desc']; @@ -245,21 +245,21 @@ public static procedure InitAll(api: string; enums_ns: sequence of XmlNode) := foreach var enums_n in enums_ns do begin - enums_n.DiscardAttribute('namespace'); - enums_n.DiscardAttribute('comment'); - enums_n.DiscardAttribute('group'); - enums_n.DiscardAttribute('start'); - enums_n.DiscardAttribute('end'); + enums_n.DiscardAttrib('namespace'); + enums_n.TryDiscardAttrib('comment'); + enums_n.TryDiscardAttrib('group'); + enums_n.TryDiscardAttrib('start'); + enums_n.TryDiscardAttrib('end'); if enums_n['vendor'] is string(var vendors_s) then foreach var vendor_s in vendors_s.Split('/') do VendorSuffixSource.RequireName(vendor_s); - foreach var unused_n in enums_n.Nodes['unused'] do + foreach var unused_n in enums_n.SubNodes['unused'] do begin - unused_n.DiscardAttribute('comment'); - unused_n.DiscardAttribute('start'); - unused_n.DiscardAttribute('end'); + unused_n.TryDiscardAttrib('comment'); + unused_n.DiscardAttrib('start'); + unused_n.TryDiscardAttrib('end'); if unused_n['vendor'] is string(var vendor_s) then VendorSuffixSource.RequireName(vendor_s); end; @@ -271,14 +271,15 @@ else raise new System.NotImplementedException(etype); end; - foreach var enum_n in enums_n.Nodes['enum'] do + foreach var enum_n in enums_n.SubNodes['enum'] do begin - enum_n.DiscardAttribute('comment'); + enum_n.TryDiscardAttrib('comment'); var flat_ename := enum_n['name']; if flat_ename='GLX_EXTENSION_NAME' then begin - enum_n.DiscardAttribute('value'); + if enum_n['value'] <> '"GLX"' then + raise new System.NotSupportedException; continue; // #define GLX_EXTENSION_NAME "GLX" end; var ename := EnumSource.MakeName(enum_n['api'], flat_ename, api, false); @@ -354,7 +355,7 @@ public constructor(api, func_descr: string; n: XmlNode); begin - self.name := n.Nodes['name'].Single.Text; + self.name := n.SubNodes['name'].Single.Text; self.context_api := api; self.func_descr := func_descr; @@ -363,7 +364,7 @@ (tname, ptr, readonly_lvls) := ParData.ParsePtrLvls(n.Text.RemoveEnd(name)); - if n.Nodes['ptype'].SingleOrDefault?.Text is string(var ptype) then + if n.SubNodes['ptype'].SingleOrDefault?.Text is string(var ptype) then begin if ptype <> tname then raise new System.InvalidOperationException; @@ -417,18 +418,18 @@ end; private constructor(api: string; n: XmlNode); begin - inherited Create(MakeName(api, n.Nodes['proto'].Single.Nodes['name'].Single.Text, false)); - n.DiscardAttribute('comment'); - n.DiscardNodes('glx'); // GLX protocol + inherited Create(MakeName(api, n.SubNodes['proto'].Single.SubNodes['name'].Single.Text, false)); + n.TryDiscardAttrib('comment'); + n.TryDiscardSubNodes('glx'); // GLX protocol - self.entry_point_name := n.Nodes['proto'].Single.Nodes['name'].Single.Text; + self.entry_point_name := n.SubNodes['proto'].Single.SubNodes['name'].Single.Text; - foreach var par_n in n.Nodes['proto']+n.Nodes['param'] do + foreach var par_n in n.SubNodes['proto']+n.SubNodes['param'] do self.pars_source += new FuncParamSource(api, self.ToString, par_n); - self.alias_name := MakeName(api, n.Nodes['alias'].SingleOrDefault?.Attribute['name'], true); + self.alias_name := MakeName(api, n.SubNodes['alias'].SingleOrDefault?.AttribData['name'], true); - var vec_equiv_n := n.Nodes['vecequiv'].SingleOrDefault; + var vec_equiv_n := n.SubNodes['vecequiv'].SingleOrDefault; if vec_equiv_n<>nil then vec_equiv_n.Discard; // Not useful end; @@ -438,7 +439,7 @@ if commands_n['namespace'] <> api.ToUpper then raise new InvalidOperationException; - foreach var command_n in commands_n.Nodes['command'] do + foreach var command_n in commands_n.SubNodes['command'] do new FuncSource(api, command_n); end; @@ -465,14 +466,14 @@ RequiredListSource = record else raise new InvalidOperationException(rn['profile']); end; - foreach var type_n in rn.Nodes['type'] do + foreach var type_n in rn.SubNodes['type'] do begin var tname := type_n['name']; if BasicTypeSource.FindOrMakeSource(tname, nil) = nil then raise new InvalidOperationException(tname); end; - foreach var enum_n in rn.Nodes['enum'] do + foreach var enum_n in rn.SubNodes['enum'] do begin var ename := enum_n['name']; // #define GLX_EXTENSION_NAME "GLX" @@ -480,7 +481,7 @@ RequiredListSource = record enum_names += EnumSource.MakeName(rn['api'], ename, file_api, true); end; - foreach var func_n in rn.Nodes['command'] do + foreach var func_n in rn.SubNodes['command'] do begin var fname := func_n['name']; func_names += FuncSource.MakeName(file_api, fname, false); @@ -518,14 +519,14 @@ RequiredListSource = record if feature_n['name'] <> expected_verb_name then raise new InvalidOperationException; - var add_ns := feature_n.Nodes['require']; - var rem_ns := feature_n.Nodes['remove']; + var add_ns := feature_n.SubNodes['require']; + var rem_ns := feature_n.SubNodes['remove']; foreach var rn in add_ns+rem_ns do begin - rn.DiscardAttribute('comment'); - foreach var type_n in rn.Nodes['type']+rn.Nodes['enum'] do - type_n.DiscardAttribute('comment'); + rn.TryDiscardAttrib('comment'); + foreach var type_n in rn.SubNodes['type']+rn.SubNodes['enum'] do + type_n.TryDiscardAttrib('comment'); end; var f := new FeatureSource(name); @@ -549,27 +550,27 @@ RequiredListSource = record inherited MakeName&(own_api, name, context_api, allow_nil, true, VendorSuffixSource.known_suffixes, 'e_*','E_*'); public static procedure InitAll(file_api: string; extensions_n: XmlNode) := - foreach var extension_n in extensions_n.Nodes['extension'] do + foreach var extension_n in extensions_n.SubNodes['extension'] do begin - extension_n.DiscardAttribute('comment'); - extension_n.DiscardAttribute('protect'); + extension_n.TryDiscardAttrib('comment'); + extension_n.TryDiscardAttrib('protect'); var name := extension_n['name']; - var add_ns := extension_n.Nodes['require']; - - foreach var rn in add_ns do - begin - rn.DiscardAttribute('comment'); - foreach var type_n in rn.Nodes['command']+rn.Nodes['enum'] do - type_n.DiscardAttribute('comment'); - end; - var apis := extension_n['supported'].ToWords('|').ToList; if apis.SequenceEqual(|'disabled'|) then begin - extension_n.DiscardNodes('require'); + extension_n.TryDiscardSubNodes('require'); continue; end; + + var add_ns := extension_n.SubNodes['require']; + foreach var rn in add_ns do + begin + rn.TryDiscardAttrib('comment'); + foreach var type_n in rn.SubNodes['command']+rn.SubNodes['enum'] do + type_n.TryDiscardAttrib('comment'); + end; + if apis.Remove('glcore') and ('gl' not in apis) then raise new System.InvalidOperationException(name); if apis.Count=0 then raise new System.InvalidOperationException(name); @@ -603,32 +604,30 @@ function VendorSuffixSource.MakeNewItem := TypeHelper = static class public static procedure InitAll(api: string; types_n: XmlNode) := - foreach var type_n in types_n.Nodes['type'] do + foreach var type_n in types_n.SubNodes['type'] do if type_n['name'] is string(var tname) then begin if type_n.Text.StartsWith('#include') then continue; - if type_n.Text.StartsWith('#ifndef GLEXT_64_TYPES_DEFINED') then - begin - type_n.Discard; - continue; - end; - type_n.DiscardAttribute('comment'); - type_n.DiscardAttribute('requires'); + if type_n.Text.StartsWith('#ifndef GLEXT_64_TYPES_DEFINED') then continue; + type_n.TryDiscardAttrib('comment'); + type_n.TryDiscardAttrib('requires'); BasicTypeSource.TryDefine(api, tname); end else begin - type_n.DiscardAttribute('comment'); - type_n.DiscardAttribute('requires'); - var tname := type_n.Nodes['name'].Single.Text; + type_n.TryDiscardAttrib('comment'); + type_n.TryDiscardAttrib('requires'); + var tname := type_n.SubNodes['name'].Single.Text; //TODO Struct and IdClass // - Use IdClassSource.extra_defined, for MakeTypeRef type lookup - case type_n.Nodes['apientry'].Count - Ord(tname='__GLXextFuncPtr') of - 0: BasicTypeSource.TryDefine(api, tname); - 1: new DelegateSource(api, tname, type_n.Text); - else raise new NotSupportedException; - end; + var n_apientry := type_n.SubNodes['apientry'].SingleOrDefault; + if n_apientry<>nil then n_apientry.Discard; + if tname='__GLXextFuncPtr' then n_apientry := nil; + + if n_apientry=nil then + BasicTypeSource.TryDefine(api, tname) else + new DelegateSource(api, tname, type_n.Text); end; @@ -1071,21 +1070,21 @@ procedure ScrapXmlFiles(params api_names: array of string); foreach var api in api_names do begin Otp($'Parsing "{api}"'); - var root := new XmlNode(GetFullPathRTA($'../../Reps/OpenGL-Registry/xml/{api}.xml')); - root.Nodes['comment'].Single.Discard; + var root := ScrapUtils.GetXml(api); + root.SubNodes['comment'].Single.Discard; - TypeHelper.InitAll(api, root.Nodes['types'].Single); + TypeHelper.InitAll(api, root.SubNodes['types'].Single); - if root.Nodes['kinds'].SingleOrDefault is XmlNode(var kinds_n) then + if root.SubNodes['kinds'].SingleOrDefault is XmlNode(var kinds_n) then Kind.InitAll(kinds_n); - EnumSource.InitAll(api, root.Nodes['enums']); + EnumSource.InitAll(api, root.SubNodes['enums']); - FuncSource.InitAll(api, root.Nodes['commands'].Single); + FuncSource.InitAll(api, root.SubNodes['commands'].Single); - FeatureSource.InitAll(api, root.Nodes['feature']); + FeatureSource.InitAll(api, root.SubNodes['feature']); - ExtensionSource.InitAll(api, root.Nodes['extensions'].Single); + ExtensionSource.InitAll(api, root.SubNodes['extensions'].Single); end; @@ -1093,7 +1092,7 @@ procedure ScrapXmlFiles(params api_names: array of string); begin try - XMLUtils.Init('OpenGL-Registry'); + ScrapUtils.Init('OpenGL-Registry'); ScrapXmlFiles('gl', 'wgl', 'glx'); diff --git a/DataScraping/XML/ScrapUtils.pas b/DataScraping/XML/ScrapUtils.pas index 84c3aa3a..384e0aec 100644 --- a/DataScraping/XML/ScrapUtils.pas +++ b/DataScraping/XML/ScrapUtils.pas @@ -1,10 +1,18 @@ unit ScrapUtils; +interface + +uses '../../Utils/ThoroughXML'; uses '../../Utils/AOtp'; uses '../../POCGL_Utils'; var log := new FileLogger(GetFullPathRTA('xml.log')); +procedure Init(repo_name: string); +function GetXml(name: string): XmlNode; + +implementation + function RemoveBeg(self, s: string; ignore_case: boolean := false): string; extensionmethod; begin var comp := if ignore_case then @@ -21,4 +29,62 @@ function RemoveEnd(self, s: string): string; extensionmethod; Result := self.SubString(0,self.Length-s.Length); end; +var all_xml_files: Dictionary; +procedure Init(repo_name: string); +begin + if all_xml_files<>nil then raise new System.InvalidOperationException; + var path := System.IO.Path.GetFullPath(GetFullPathRTA($'../../Reps/{repo_name}/xml')); + all_xml_files := EnumerateFiles(path, '*.xml') + .Select(fname->fname.Replace('\','/')) + .ToDictionary(System.IO.Path.GetFileNameWithoutExtension, fname->(fname, + new XmlNode(ReadAllText(fname, enc).Replace(#13#10,#10)) + )); +end; +function GetXml(name: string): XmlNode; +begin + Result := all_xml_files.Get(name)?.Item2; + if Result=nil then + raise new System.InvalidOperationException($'XML namespace [{name}] is not defined'); +end; + +procedure Finalize := +try + + var max_xml_body_size := 250; + var attrib_descr := function(a: XmlAttrib): string -> + a.ToString; + var node_descr := function(n: XmlNode): string -> + begin + + var body := n.Text; + if body.Length>max_xml_body_size then + body := body.Remove(max_xml_body_size); + body := body.Replace(#10,'\n'); + + Result := n.FullPath + + '< ' + n.GetAllAttribs.Select(kvp->$'{kvp.Key}="{kvp.Value.Data}"').JoinToString + ' >' + + ': ' + body + end; + + foreach var (fname, n) in all_xml_files.Values do + begin + if n.IsDiscarded then raise new System.NotImplementedException; + if not n.WasUsed then + log.Otp($'File [{fname}] wasn''t used') else + n.ThoroughCheck(()->Otp($'=== {fname} ===') + , a->Otp($'WARNING: Unused attribute | {attrib_descr(a)}') + , a->Otp($'WARNING: Attribute was used and discarded | {attrib_descr(a)}') + , n->Otp($'WARNING: Unused node | {node_descr(n)}') + , n->Otp($'WARNING: Node was used and discarded | {node_descr(n)}') + ); + end; + + log.Close; +except + on e: Exception do ErrOtp(e); +end; + +initialization +finalization + Finalize; end. \ No newline at end of file diff --git a/DataScraping/XML/XMLUtils.pas b/DataScraping/XML/XMLUtils.pas deleted file mode 100644 index f553106e..00000000 --- a/DataScraping/XML/XMLUtils.pas +++ /dev/null @@ -1,161 +0,0 @@ -unit XMLUtils; -{$reference System.XML.dll} - -uses '../../POCGL_Utils'; - -uses ScrapUtils; - -var unprocessed_xml_files: HashSet; -procedure Init(repo_name: string); -begin - var path := System.IO.Path.GetFullPath(GetFullPathRTA($'../../Reps/{repo_name}/xml')); - unprocessed_xml_files := EnumerateFiles(path, '*.xml').Select(fname->fname.Replace('\','/')).ToHashSet; -end; - -type - {$region XmlNode} - - XmlNode = sealed class - private t: string; - private atrbs := new Dictionary; - private txt: string; - private nds: array of XmlNode; - - private used := false; - private atrbs_used := new HashSet; - private atrbs_discarded := new HashSet; - - private procedure InitFrom(el: System.Xml.XmlNode); - begin - self.t := el.Name; - if t='#comment' then - self.Discard; - - if el.Attributes<>nil then - foreach var atrb: System.Xml.XmlAttribute in el.Attributes do - atrbs.Add(atrb.Name, atrb.Value); - - txt := el.InnerText; - - nds := (0..el.ChildNodes.Count-1).Select(el.ChildNodes.Item) - .Where(sub_el->sub_el.Name not in |'#comment', '#text'|) - .Select(sub_el-> - begin - Result := new XmlNode; - Result.InitFrom(sub_el); - end).ToArray; - - end; - - private static AllRoots := new Dictionary; - public constructor(fname: string); - begin - fname := GetFullPath(fname).Replace('\','/'); - if not unprocessed_xml_files.Remove(fname) then Otp($'WARNING: File [{fname}] isn''t expected as input'); - var d := new System.Xml.XmlDocument; - d.LoadXml(ReadAllText(fname).Replace(#13#10,#10)); - InitFrom(d.DocumentElement); - AllRoots.Add(fname, self); - self.used := true; - end; - - public constructor; - begin - nds := new XmlNode[0]; - end; - - public property Text: string read txt; - - private function GetAttribute(name: string): string; - begin - if name in atrbs_discarded then - raise new System.InvalidOperationException; - if not atrbs.TryGetValue(name, Result) then exit; - atrbs_used += name; - end; - public property Attribute[name: string]: string read GetAttribute; default; - - public procedure DiscardAttribute(name: string); - begin - if not atrbs_discarded.Add(name) then - raise new System.InvalidOperationException($'Double discard of [{name}]'); - atrbs.Remove(name); - end; - - private function GetNodes(t: string): sequence of XmlNode; - begin - foreach var n in nds do - begin - if n.t<>t then continue; - n.used := true; - yield n; - end; - end; - public property Nodes[t: string]: sequence of XmlNode read GetNodes; - - public property NodeTypes: sequence of string - read nds.Select(n->n.t).Distinct; - - public procedure Discard; - begin - self.used := true; - self.atrbs.Clear; - SetLength(self.nds, 0); - end; - public procedure DiscardNodes(t: string) := - foreach var n in Nodes[t] do n.Discard; - - private procedure ReportUnused(write_header: Action0; prev: Stack); - begin - prev.Push(self); - - if not used then - begin - write_header; - log.Otp($'Unused node '+prev.Reverse.Select(n->n.t).JoinToString('=>')+'< '+atrbs.Select(kvp->$'{kvp.Key}="{kvp.Value}"').JoinToString+' >: '+self.Text.Replace(#10,'\n')?[:250+1]); - end else - begin - - foreach var atrb in atrbs.Keys do - begin - if atrb in atrbs_used then continue; - write_header; - log.Otp($'Unused attribute in '+prev.Reverse.Select(n->n.t).JoinToString('=>')+$': {atrb}="{atrbs[atrb]}"'); - end; - - foreach var n in nds do - n.ReportUnused(write_header, prev); - - end; - - if prev.Pop <> self then raise new System.InvalidOperationException; - end; - private procedure ReportUnused(fname: string); - begin - ReportUnused(()-> - begin - if fname=nil then exit; - log.Otp($'=== {System.IO.Path.GetFileName(fname)} ==='); - fname := nil; - end, new Stack); - end; - - end; - - {$endregion XmlNode} - -initialization -finalization - try - - foreach var fname in unprocessed_xml_files do - log.Otp($'File [{fname}] wasn''t used'); - - foreach var fname in XmlNode.AllRoots.Keys do - XmlNode.AllRoots[fname].ReportUnused(fname); - - log.Close; - except - on e: Exception do ErrOtp(e); - end; -end. \ No newline at end of file diff --git a/Utils/ThoroughXML.pas b/Utils/ThoroughXML.pas new file mode 100644 index 00000000..3b12928a --- /dev/null +++ b/Utils/ThoroughXML.pas @@ -0,0 +1,274 @@ +unit ThoroughXML; + +{$reference System.XML.dll} + +interface + +type + + {$region Basic def} + + XmlItem = abstract class + + {$region MarkUsed} + + private was_used := false; + public property WasUsed: boolean read was_used; + public function TryMarkUsed: boolean; + begin + Result := not WasUsed; + was_used := true; + end; + public procedure MarkUsed := if not TryMarkUsed then + raise new System.InvalidOperationException; + + protected function GetContent(f: ()->T): T; + begin + self.TryMarkUsed; + Result := f; + end; + + {$endregion MarkUsed} + + {$region Discard} + + private is_discarded := false; + public property IsDiscarded: boolean read is_discarded; + public function TryDiscard: boolean; + begin + Result := not IsDiscarded; + is_discarded := true; + end; + public procedure Discard := if not TryDiscard then + raise new System.InvalidOperationException; + + {$endregion Discard} + + end; + + XmlNode = sealed partial class(XmlItem) + private _parent: XmlNode; + private _raw: System.Xml.XmlNode; + + {$region Constructors} + + private constructor(_parent: XmlNode; _raw: System.Xml.XmlNode); + begin + self._parent := _parent; + self._raw := _raw; + end; + public constructor(xml_text: string); + begin + var d := new System.Xml.XmlDocument; + d.LoadXml(xml_text); + self._parent := nil; + self._raw := d.DocumentElement; + end; + private constructor := raise new System.InvalidOperationException; + + {$endregion Constructors} + + public property Parent: XmlNode read _parent; + + public property Tag: string read _raw.Name; + public property Text: string read GetContent(()->_raw.InnerText); + + public function IterateParents: sequence of XmlNode; + begin + var curr := self; + repeat + yield curr; + curr := curr.Parent; + until curr=nil; + end; + public property FullPath: string read IterateParents.Reverse.Select(n->n.Tag).JoinToString('=>'); + public function ToString: string; override := FullPath; + + end; + + XmlAttrib = sealed partial class(XmlItem) + private _node: XmlNode; + private _raw: System.Xml.XmlAttribute; + + {$region Constructors} + + private constructor(_node: XmlNode; _raw: System.Xml.XmlAttribute); + begin + self._node := _node; + self._raw := _raw; + end; + private constructor := raise new System.InvalidOperationException; + + {$endregion Constructors} + + public property Node: XmlNode read _node; + + public property Name: string read _raw.Name; + public property Data: string read GetContent(()->_raw.Value); + + public function ToString: string; override := $'{Node.FullPath}: {Name}="{Data}"'; + + end; + + {$endregion Basic def} + + {$region Node Children} + + XmlNode = sealed partial class + + {$region Attribs} + + private attribs_cache: Dictionary; + public function GetAllAttribs: Dictionary; + begin + Result := attribs_cache; + if Result<>nil then exit; + + if _raw.Attributes=nil then + Result := new Dictionary else + begin + Result := new Dictionary(_raw.Attributes.Count); + for var i := 0 to _raw.Attributes.Count-1 do + begin + var a := new XmlAttrib(self, _raw.Attributes[i]); + Result.Add(a.Name, a); + end; + end; + + attribs_cache := Result; + end; + //TODO #????: self. + public property Attrib[name: string]: XmlAttrib read GetContent(()->self.GetAllAttribs.Get(name)); + //TODO #2461: string(...) + public property AttribData[name: string]: string read string(Attrib[name]?.Data); default; + + public function TryDiscardAttrib(name: string): boolean := + (Attrib[name] is XmlAttrib(var a)) and a.TryDiscard; + public procedure DiscardAttrib(name: string) := if not TryDiscardAttrib(name) then + raise new System.InvalidOperationException(name); + + {$endregion Attribs} + + {$region SubNodes} + + private sub_nodes_cache: array of XmlNode; + public function GetAllSubNodes: IList; + begin + Result := sub_nodes_cache; + if Result<>nil then exit; + + Result := new List(_raw.ChildNodes.Count); + for var i := 0 to _raw.ChildNodes.Count-1 do + begin + var n := new XmlNode(self, _raw.ChildNodes[i]); + if n.Tag.StartsWith('#') then + begin + if n.Tag not in |'#comment', '#text', '#cdata-section'| then + raise new System.NotImplementedException(n.Tag); + continue; + end; + Result.Add(n); + end; + + sub_nodes_cache := Result.ToArray; + end; + //TODO #????: self. + public property SubNodes[tag: string]: sequence of XmlNode read GetContent(()->self.GetAllSubNodes.Where(n->n.Tag=tag)); + + public function TryDiscardSubNodes(tag: string) := SubNodes[tag].Count(n->n.TryDiscard); + + {$endregion SubNodes} + + end; + + {$endregion Node Children} + + {$region Visitor} + + XmlVisitor = abstract class + + public procedure VisitAttrib(a: XmlAttrib); abstract; + + public function VisitNode(n: XmlNode): boolean; abstract; + + public static function MakeBasic(visit_attrib: XmlAttrib->(); visit_node: XmlNode->boolean): XmlVisitor; + + end; + + XmlNode = sealed partial class + + public procedure Visit(v: XmlVisitor); + begin + if not v.VisitNode(self) then exit; + + foreach var a in GetAllAttribs.Values do + v.VisitAttrib(a); + + foreach var n in GetAllSubNodes do + n.Visit(v); + + end; + + public procedure ThoroughCheck(header: ()->() + ; attrib_lost, attrib_used_and_discarded: XmlAttrib->() + ; node_lost, node_used_and_discarded: XmlNode->() + ) := Visit(XmlVisitor.MakeBasic( + a-> + begin + if a.WasUsed xor a.IsDiscarded then exit; + + if header<>nil then header(); + header := nil; + + if not a.WasUsed then + attrib_lost(a) else + attrib_used_and_discarded(a); + + end, + n-> + begin + Result := not n.IsDiscarded; + if n.WasUsed xor n.IsDiscarded then exit; + + if header<>nil then header(); + header := nil; + + if not n.WasUsed then + node_lost(n) else + node_used_and_discarded(n); + + end + )); + + end; + + {$endregion Visitor} + +implementation + +{$region BasicVisitor} + +type + BasicXmlVisitor = sealed class(XmlVisitor) + private visit_attrib: XmlAttrib->(); + private visit_node: XmlNode->boolean; + + public constructor(visit_attrib: XmlAttrib->(); visit_node: XmlNode->boolean); + begin + self.visit_attrib := visit_attrib; + self.visit_node := visit_node; + end; + private constructor := raise new System.InvalidOperationException; + + public procedure VisitAttrib(a: XmlAttrib); override := visit_attrib(a); + + public function VisitNode(n: XmlNode): boolean; override := visit_node(n); + + end; + +static function XmlVisitor.MakeBasic(visit_attrib: XmlAttrib->(); visit_node: XmlNode->boolean) := + new BasicXmlVisitor(visit_attrib, visit_node); + +{$endregion BasicVisitor} + +end. \ No newline at end of file