Skip to content

Commit

Permalink
Merge pull request #391 from gircore/fixes
Browse files Browse the repository at this point in the history
Prefer symbol name for primitive value types over their ctype to detect the correct type as the symbol sometimes is more expressive (e.g. symbolname = "double" ctype = "gpointer")

Differentiate between Bitfields and Enumerations. Bitfields are transferred as ulong and Enumerations as long. They are represented as different types in the gir.rnc file, too. Additionally Bitfields can contain negative values (despite them being of type ulong). Those values must be filtered out as they are convenience functions of C which do not apply for us.

Bitfields/Enumerations need to respect the type references namespace name to avoid false positive matches.
  • Loading branch information
badcel authored Aug 5, 2021
2 parents 9016d6b + 61d2417 commit 89e4fba
Show file tree
Hide file tree
Showing 17 changed files with 153 additions and 25 deletions.
3 changes: 2 additions & 1 deletion Generator/Extensions/TypeExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ internal static string Write(this Type type, Target target, Namespace currentNam
{
PrimitiveType => type.Name,

// Enumerations do not have a native representation they
// Enumerations/Bitfields do not have a native representation they
// always live in the managed namespace (see method GetName)
Enumeration e => $"{e.Repository.Namespace.Name}.{e.Name}",
Bitfield e => $"{e.Repository.Namespace.Name}.{e.Name}",

ComplexType c when !c.Repository.Namespace.IsForeignTo(currentNamespace) => c.Name,
ComplexType c => $"{c.Repository.Namespace.GetName(target)}.{c.Name}",
Expand Down
2 changes: 1 addition & 1 deletion Generator/Services/Writer/WriterService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public void Write(Namespace ns, string outputDir, WriterOptions options)
_writeTypesService.Write(
projectName: ns.ToCanonicalName(),
outputDir: outputDir,
templateName: "enum.sbntxt",
templateName: "bitfield.sbntxt",
subfolder: Folder.Managed.Enums,
types: ns.Bitfields,
@namespace: ns
Expand Down
13 changes: 13 additions & 0 deletions Generator/Templates/bitfield.sbntxt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{{~ #Bitfields are passed as ulong via the ffi ~}}
using System;

namespace {{ namespace.name }}
{
[Flags]
public enum {{ name }} : ulong
{
{{~ for member in members }}
{{ include 'member.sbntxt' member ~}}
{{ end }}
}
}
6 changes: 2 additions & 4 deletions Generator/Templates/enum.sbntxt
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
{{~ #Enumerations are passed as long via the ffi ~}}
using System;

namespace {{ namespace.name }}
{
{{~ if has_flags ~}}
[Flags]
{{~ end ~}}
public enum {{ name }} : long
{
{{~ for member in members }}
{{ include 'enum.member.sbntxt' member ~}}
{{ include 'member.sbntxt' member ~}}
{{ end }}
}
}
File renamed without changes.
23 changes: 23 additions & 0 deletions GirLoader/Input/Model/Bitfield.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System.Collections.Generic;
using System.Xml.Serialization;

namespace GirLoader.Input.Model
{
public class Bitfield
{
[XmlAttribute("name")]
public string? Name { get; set; }

[XmlAttribute("type", Namespace = "http://www.gtk.org/introspection/c/1.0")]
public string? Type { get; set; }

[XmlAttribute("type-name", Namespace = "http://www.gtk.org/introspection/glib/1.0")]
public string? TypeName { get; set; }

[XmlElement("doc")]
public Doc? Doc { get; set; }

[XmlElement("member")]
public List<Member> Members { get; set; } = default!;
}
}
2 changes: 1 addition & 1 deletion GirLoader/Input/Model/Namespace.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public class Namespace
public List<Interface> Interfaces { get; set; } = new();

[XmlElement("bitfield")]
public List<Enum> Bitfields { get; set; } = new();
public List<Bitfield> Bitfields { get; set; } = new();

[XmlElement("enumeration")]
public List<Enum> Enumerations { get; set; } = new();
Expand Down
38 changes: 38 additions & 0 deletions GirLoader/Output/Model/Bitfield.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using System.Collections.Generic;
using System.Linq;
using GirLoader.Helper;

namespace GirLoader.Output.Model
{
public class Bitfield : ComplexType
{
public IEnumerable<Member> Members { get; }

public Bitfield(Repository repository, CType? cType, TypeName originalName, TypeName name, IEnumerable<Member> members) : base(repository, cType, name, originalName)
{
Members = members;
}

internal override IEnumerable<TypeReference> GetTypeReferences()
=> Members.SelectMany(x => x.GetTypeReferences());

internal override bool GetIsResolved()
=> Members.All(x => x.GetIsResolved());

internal override bool Matches(TypeReference typeReference)
{
if (typeReference.SymbolNameReference is not null)
{
var namespaceOk = typeReference.SymbolNameReference.NamespaceName == Repository.Namespace.Name
|| typeReference.SymbolNameReference.NamespaceName == null;

return namespaceOk && typeReference.SymbolNameReference.SymbolName == OriginalName;
}

if (typeReference.CTypeReference is not null)
return typeReference.CTypeReference.CType == CType;

return false;
}
}
}
47 changes: 47 additions & 0 deletions GirLoader/Output/Model/BitfieldFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using System;
using System.Linq;

namespace GirLoader.Output.Model
{
internal class BitfieldFactory
{
private readonly MemberFactory _memberFactory;

public BitfieldFactory(MemberFactory memberFactory)
{
_memberFactory = memberFactory;
}

public Bitfield Create(Input.Model.Bitfield bitfield, Repository repository)
{
if (bitfield.Name is null)
throw new Exception("Bitfield has no name");

if (bitfield.Type is null)
throw new Exception("Bitfield is missing a type");

var members = bitfield.Members.Select(_memberFactory.Create).ToList();

bool ValueIsULong(Member member)
{
// Bitfields are transfered as ulong and thus do not support negative values.
// Negative values can occur as C convenience members as a "mask".
// Those can safely be should be ignored.

if (ulong.TryParse(member.Value, out var _))
return true;

Log.Verbose($"{nameof(Bitfield)} - {member.OriginalName} ignored because value is no ulong: {member.Value}");
return false;
}

return new Bitfield(
repository: repository,
originalName: new TypeName(bitfield.Name),
name: new TypeName(bitfield.Name),
members: members.Where(ValueIsULong),
cType: new CType(bitfield.Type)
);
}
}
}
15 changes: 9 additions & 6 deletions GirLoader/Output/Model/Enumeration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,10 @@ namespace GirLoader.Output.Model
{
public class Enumeration : ComplexType
{
public bool HasFlags { get; }
public IEnumerable<Member> Members { get; }

public Enumeration(Repository repository, CType? cType, TypeName originalName, TypeName name, bool hasFlags, IEnumerable<Member> members) : base(repository, cType, name, originalName)
public Enumeration(Repository repository, CType? cType, TypeName originalName, TypeName name, IEnumerable<Member> members) : base(repository, cType, name, originalName)
{
HasFlags = hasFlags;
Members = members;
}

Expand All @@ -23,12 +21,17 @@ internal override bool GetIsResolved()

internal override bool Matches(TypeReference typeReference)
{
if (typeReference.SymbolNameReference is not null)
{
var namespaceOk = typeReference.SymbolNameReference.NamespaceName == Repository.Namespace.Name
|| typeReference.SymbolNameReference.NamespaceName == null;

return namespaceOk && typeReference.SymbolNameReference.SymbolName == OriginalName;
}

if (typeReference.CTypeReference is not null)
return typeReference.CTypeReference.CType == CType;

if (typeReference.SymbolNameReference is not null)
return typeReference.SymbolNameReference.SymbolName == OriginalName;

return false;
}
}
Expand Down
3 changes: 1 addition & 2 deletions GirLoader/Output/Model/EnumerationFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public EnumerationFactory(MemberFactory memberFactory)
_memberFactory = memberFactory;
}

public Enumeration Create(Input.Model.Enum @enum, Repository repository, bool hasFlags)
public Enumeration Create(Input.Model.Enum @enum, Repository repository)
{
if (@enum.Name is null)
throw new Exception("Enum has no name");
Expand All @@ -24,7 +24,6 @@ public Enumeration Create(Input.Model.Enum @enum, Repository repository, bool ha
repository: repository,
originalName: new TypeName(@enum.Name),
name: new TypeName(@enum.Name),
hasFlags: hasFlags,
members: @enum.Members.Select(_memberFactory.Create).ToList(),
cType: new CType(@enum.Type)
);
Expand Down
6 changes: 3 additions & 3 deletions GirLoader/Output/Model/Namespace.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ public class Namespace
private readonly List<Enumeration> _enumerations = new();
public IEnumerable<Enumeration> Enumerations => _enumerations;

private readonly List<Enumeration> _bitfields = new();
public IEnumerable<Enumeration> Bitfields => _bitfields;
private readonly List<Bitfield> _bitfields = new();
public IEnumerable<Bitfield> Bitfields => _bitfields;

private readonly List<Interface> _interfaces = new();
public IEnumerable<Interface> Interfaces => _interfaces;
Expand Down Expand Up @@ -69,7 +69,7 @@ internal void AddClass(Class @class)
internal void AddEnumeration(Enumeration enumeration)
=> _enumerations.Add(enumeration);

internal void AddBitfield(Enumeration enumeration)
internal void AddBitfield(Bitfield enumeration)
=> _bitfields.Add(enumeration);

internal void AddInterface(Interface @interface)
Expand Down
12 changes: 7 additions & 5 deletions GirLoader/Output/Model/NamespaceFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,20 @@ internal class NamespaceFactory
private readonly AliasFactory _aliasFactory;
private readonly CallbackFactory _callbackFactory;
private readonly EnumerationFactory _enumerationFactory;
private readonly BitfieldFactory _bitfieldFactory;
private readonly InterfaceFactory _interfaceFactory;
private readonly RecordFactory _recordFactory;
private readonly MethodFactory _methodFactory;
private readonly ConstantFactory _constantFactory;
private readonly UnionFactory _unionFactory;

public NamespaceFactory(ClassFactory classFactory, AliasFactory aliasFactory, CallbackFactory callbackFactory, EnumerationFactory enumerationFactory, InterfaceFactory interfaceFactory, RecordFactory recordFactory, MethodFactory methodFactory, ConstantFactory constantFactory, UnionFactory unionFactory)
public NamespaceFactory(ClassFactory classFactory, AliasFactory aliasFactory, CallbackFactory callbackFactory, EnumerationFactory enumerationFactory, BitfieldFactory bitfieldFactory,InterfaceFactory interfaceFactory, RecordFactory recordFactory, MethodFactory methodFactory, ConstantFactory constantFactory, UnionFactory unionFactory)
{
_classFactory = classFactory;
_aliasFactory = aliasFactory;
_callbackFactory = callbackFactory;
_enumerationFactory = enumerationFactory;
_bitfieldFactory = bitfieldFactory;
_interfaceFactory = interfaceFactory;
_recordFactory = recordFactory;
_methodFactory = methodFactory;
Expand Down Expand Up @@ -85,13 +87,13 @@ private void SetCallbacks(Repository repository, IEnumerable<Input.Model.Callbac
private void SetEnumerations(Repository repository, IEnumerable<Input.Model.Enum> enumerations)
{
foreach (Input.Model.Enum @enum in enumerations)
repository.Namespace.AddEnumeration(_enumerationFactory.Create(@enum, repository, false));
repository.Namespace.AddEnumeration(_enumerationFactory.Create(@enum, repository));
}

private void SetBitfields(Repository repository, IEnumerable<Input.Model.Enum> enumerations)
private void SetBitfields(Repository repository, IEnumerable<Input.Model.Bitfield> bitfields)
{
foreach (Input.Model.Enum @enum in enumerations)
repository.Namespace.AddBitfield(_enumerationFactory.Create(@enum, repository, true));
foreach (Input.Model.Bitfield bitfield in bitfields)
repository.Namespace.AddBitfield(_bitfieldFactory.Create(bitfield, repository));
}

private void SetInterfaces(Repository repository, IEnumerable<Input.Model.Interface> interfaces)
Expand Down
2 changes: 1 addition & 1 deletion GirLoader/Output/Model/PrimitiveValueType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ internal override bool Matches(TypeReference typeReference)
{
return typeReference switch
{
{ CTypeReference: { } cr } => cr.CType == CType,
{ SymbolNameReference: { SymbolName: { } sn } } => sn.Value == CType?.Value,
{ CTypeReference: { } cr } => cr.CType == CType,
_ => throw new Exception($"Can't match {GetType().Name} with {nameof(TypeReference)} {typeReference}")
};
}
Expand Down
3 changes: 3 additions & 0 deletions GirLoader/Output/Model/Type.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,8 @@ public string GetMetadataString(string key)
internal abstract bool Matches(TypeReference typeReference);
internal abstract IEnumerable<TypeReference> GetTypeReferences();
internal abstract bool GetIsResolved();

public override string ToString()
=> Name;
}
}
1 change: 1 addition & 0 deletions GirLoader/Output/Module.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ namespace GirLoader.Output
[Register(typeof(Model.ParameterListFactory))]
[Register(typeof(Model.CallbackFactory))]
[Register(typeof(Model.EnumerationFactory))]
[Register(typeof(Model.BitfieldFactory))]
[Register(typeof(Model.InterfaceFactory))]
[Register(typeof(Model.RecordFactory))]
[Register(typeof(Model.MethodFactory))]
Expand Down
2 changes: 1 addition & 1 deletion Libs/GObject-2.0/Records/Value.cs
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ public void Set(object? value)
public long GetLong() => Native.Value.Methods.GetLong(Handle);
public double GetDouble() => Native.Value.Methods.GetDouble(Handle);
public float GetFloat() => Native.Value.Methods.GetFloat(Handle);
public long GetFlags() => Native.Value.Methods.GetFlags(Handle);
public ulong GetFlags() => Native.Value.Methods.GetFlags(Handle);
public long GetEnum() => Native.Value.Methods.GetEnum(Handle);
public string? GetString() => StringHelper.ToNullableStringUtf8(Native.Value.Methods.GetString(Handle));

Expand Down

0 comments on commit 89e4fba

Please sign in to comment.