diff --git a/SwiftReflector/SwiftInterfaceReflector/SwiftInterfaceReflector.cs b/SwiftReflector/SwiftInterfaceReflector/SwiftInterfaceReflector.cs
index 5cfe3d73..4ae5e738 100644
--- a/SwiftReflector/SwiftInterfaceReflector/SwiftInterfaceReflector.cs
+++ b/SwiftReflector/SwiftInterfaceReflector/SwiftInterfaceReflector.cs
@@ -104,7 +104,6 @@ public class SwiftInterfaceReflector : SwiftInterfaceBaseListener {
internal const string kLabel = "Label";
internal const string kLiteral = "Literal";
internal const string kSeparator = "Separator";
- internal const string kVersion = "Version";
internal const string kSublist = "Sublist";
internal const string kValue = "Value";
@@ -994,9 +993,17 @@ XElement ToAttributeParameter (Balanced_tokenContext context)
return literal;
}
- if (context.Platform_name_platform_version () != null) {
- var version = new XElement (kAttribute, new XAttribute (kKind, kVersion),
- new XAttribute (kValue, context.Platform_name_platform_version ().GetText ()));
+ // make the operator look like a label
+ if (context.@operator () != null) {
+ var label = new XElement (kAttributeParameter, new XAttribute (kKind, kLabel),
+ new XAttribute (kValue, context.@operator ().GetText ()));
+ return label;
+ }
+
+ if (context.any_punctuation_for_balanced_token () != null) {
+ var label = new XElement (kAttributeParameter, new XAttribute (kKind, kLabel),
+ new XAttribute (kValue, context.any_punctuation_for_balanced_token ().GetText ()));
+ return label;
}
return null;
diff --git a/SwiftReflector/SwiftReflector.csproj b/SwiftReflector/SwiftReflector.csproj
index 28be1813..2ea531fc 100644
--- a/SwiftReflector/SwiftReflector.csproj
+++ b/SwiftReflector/SwiftReflector.csproj
@@ -180,6 +180,7 @@
+
diff --git a/SwiftReflector/SwiftXmlReflection/AttributeDeclaration.cs b/SwiftReflector/SwiftXmlReflection/AttributeDeclaration.cs
new file mode 100644
index 00000000..e5b5088c
--- /dev/null
+++ b/SwiftReflector/SwiftXmlReflection/AttributeDeclaration.cs
@@ -0,0 +1,136 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+using System.Xml.Linq;
+using Dynamo;
+using System.Linq;
+
+namespace SwiftReflector.SwiftXmlReflection {
+ public class AttributeDeclaration {
+ public AttributeDeclaration (string name)
+ {
+ Name = Exceptions.ThrowOnNull (name, nameof (name));
+ Parameters = new List ();
+ }
+
+ public AttributeDeclaration (AttributeDeclaration other)
+ : this (other.Name)
+ {
+ foreach (var parameter in other.Parameters)
+ Parameters.Add (DuplicateOf (parameter));
+ }
+
+ public static AttributeDeclaration FromXElement (XElement elem)
+ {
+ var decl = new AttributeDeclaration (elem.Attribute ("name").Value);
+ var parameters = elem.Element ("attributeparameterlist");
+ if (parameters == null)
+ return decl;
+ FromAttributeParameterList (parameters, decl.Parameters);
+ return decl;
+ }
+
+ internal static void FromAttributeParameterList (XElement parameters, List outlist)
+ {
+ foreach (var parameterElem in parameters.Elements ("attributeparameter")) {
+ var parameter = AttributeParameter.FromXElement (parameterElem);
+ outlist.Add (parameter);
+ }
+ }
+
+ public static AttributeParameter DuplicateOf(AttributeParameter other)
+ {
+ switch (other.Kind) {
+ case AttributeParameterKind.Label:
+ return new AttributeParameterLabel ((AttributeParameterLabel)other);
+ case AttributeParameterKind.Literal:
+ return new AttributeParameterLiteral ((AttributeParameterLiteral)other);
+ case AttributeParameterKind.Sublist:
+ return new AttributeParameterSublist ((AttributeParameterSublist)other);
+ case AttributeParameterKind.Unknown:
+ return new AttributeParameter ();
+ default:
+ throw new ArgumentOutOfRangeException (nameof (other), other.Kind.ToString ());
+ }
+ }
+
+ public string Name { get; private set; }
+ public List Parameters { get; private set; }
+ }
+
+ public class AttributeParameter {
+ public static AttributeParameter FromXElement (XElement elem)
+ {
+ switch (elem.Attribute ("kind").Value) {
+ case "Label":
+ return new AttributeParameterLabel (elem.Attribute ("Value").Value);
+ case "Literal":
+ return new AttributeParameterLiteral (elem.Attribute ("Value").Value);
+ case "Sublist":
+ return AttributeParameterSublist.SublistFromXElement (elem);
+ default:
+ return new AttributeParameter ();
+ }
+ }
+
+ public virtual AttributeParameterKind Kind => AttributeParameterKind.Unknown;
+ }
+
+ public class AttributeParameterLabel : AttributeParameter {
+ public AttributeParameterLabel (string label)
+ {
+ Label = Exceptions.ThrowOnNull (label, nameof (label));
+ }
+
+ public AttributeParameterLabel (AttributeParameterLabel other)
+ : this (other.Label)
+ {
+ }
+
+ public override AttributeParameterKind Kind => AttributeParameterKind.Label;
+ public string Label { get; private set; }
+ }
+
+ public class AttributeParameterLiteral : AttributeParameter {
+ public AttributeParameterLiteral (string literal)
+ {
+ Literal = Exceptions.ThrowOnNull (literal, nameof (literal));
+ }
+
+ public AttributeParameterLiteral (AttributeParameterLiteral other)
+ : this (other.Literal)
+ {
+ }
+
+ public override AttributeParameterKind Kind => AttributeParameterKind.Literal;
+ public string Literal { get; private set; }
+ }
+
+ public class AttributeParameterSublist : AttributeParameter {
+ public AttributeParameterSublist ()
+ {
+ Parameters = new List ();
+ }
+
+ public AttributeParameterSublist (AttributeParameterSublist other)
+ : this ()
+ {
+ Parameters.AddRange (other.Parameters.Select (prm => AttributeDeclaration.DuplicateOf (prm)));
+ }
+
+ public static AttributeParameterSublist SublistFromXElement (XElement elem)
+ {
+ var sublist = new AttributeParameterSublist ();
+ var parameters = elem.Element ("attributeparameterlist");
+ if (parameters == null)
+ return sublist;
+ AttributeDeclaration.FromAttributeParameterList (parameters, sublist.Parameters);
+ return sublist;
+ }
+
+ public override AttributeParameterKind Kind => AttributeParameterKind.Sublist;
+ public List Parameters { get; private set; }
+ }
+}
diff --git a/SwiftReflector/SwiftXmlReflection/BaseDeclaration.cs b/SwiftReflector/SwiftXmlReflection/BaseDeclaration.cs
index ff6c60f6..7cfbbfb2 100644
--- a/SwiftReflector/SwiftXmlReflection/BaseDeclaration.cs
+++ b/SwiftReflector/SwiftXmlReflection/BaseDeclaration.cs
@@ -15,6 +15,7 @@ public class BaseDeclaration {
protected BaseDeclaration ()
{
Generics = new GenericDeclarationCollection ();
+ Attributes = new List ();
}
protected BaseDeclaration (BaseDeclaration other)
@@ -25,6 +26,7 @@ protected BaseDeclaration (BaseDeclaration other)
Parent = other.Parent;
ParentExtension = other.ParentExtension;
Generics = new GenericDeclarationCollection ();
+ Attributes = new List ();
}
public string Name { get; set; }
@@ -39,6 +41,7 @@ public bool ContainsGenericParameters {
return Generics.Count () > 0;
}
}
+ public List Attributes { get; private set; }
public bool IsTypeSpecBoundGeneric (TypeSpec sp)
{
@@ -499,9 +502,17 @@ public static BaseDeclaration FromXElement (XElement elem, ModuleDeclaration mod
break;
}
decl.Generics.AddRange (generics);
+ decl.Attributes.AddRange (AttributesFromXElement (elem.Element ("attributes")));
return decl;
}
+ internal static IEnumerable AttributesFromXElement (XElement elem)
+ {
+ if (elem == null)
+ return Enumerable.Empty ();
+ return elem.Elements ("attribute").Select (attr => AttributeDeclaration.FromXElement (attr));
+ }
+
public virtual string ToFullyQualifiedName (bool includeModule = true)
{
var sb = new StringBuilder ();
diff --git a/SwiftReflector/SwiftXmlReflection/Enums.cs b/SwiftReflector/SwiftXmlReflection/Enums.cs
index 0e86fc71..19a2909b 100644
--- a/SwiftReflector/SwiftXmlReflection/Enums.cs
+++ b/SwiftReflector/SwiftXmlReflection/Enums.cs
@@ -70,5 +70,13 @@ public enum ConstraintKind {
Inherits,
Equal
}
+
+ public enum AttributeParameterKind {
+ None,
+ Label,
+ Literal,
+ Sublist,
+ Unknown,
+ }
}
diff --git a/swiftinterfaceparser/SwiftInterface.g4 b/swiftinterfaceparser/SwiftInterface.g4
index 2c71088c..4c55b3b6 100644
--- a/swiftinterfaceparser/SwiftInterface.g4
+++ b/swiftinterfaceparser/SwiftInterface.g4
@@ -291,7 +291,7 @@ balanced_token :
| OpLBrace balanced_tokens OpRBrace
| label_identifier
| literal
- | Platform_name_platform_version
+ | operator
| any_punctuation_for_balanced_token
;
@@ -465,23 +465,6 @@ fragment Identifier_characters : Identifier_character+ ;
Implicit_parameter_name : '$' Decimal_digits ;
-Platform_name_platform_version : Platform_name WS Platform_version ;
-
-fragment Platform_name :
- 'iOS'
- | 'iOSApplicationExtension'
- | 'macOS'
- | 'macOSApplicationExtension'
- | 'watchOS'
- | 'tvOS'
- ;
-
-fragment Platform_version :
- Pure_decimal_digits
- | Pure_decimal_digits OpDot Pure_decimal_digits
- | Pure_decimal_digits OpDot Pure_decimal_digits OpDot Pure_decimal_digits
- ;
-
generic_parameter_clause : OpLess generic_parameter_list OpGreater ;
generic_parameter_list : generic_parameter (OpComma generic_parameter)* ;
generic_parameter : type_name
diff --git a/tests/tom-swifty-test/XmlReflectionTests/SwiftInterfaceParserTests.cs b/tests/tom-swifty-test/XmlReflectionTests/SwiftInterfaceParserTests.cs
index 8ab5c626..ef122d17 100644
--- a/tests/tom-swifty-test/XmlReflectionTests/SwiftInterfaceParserTests.cs
+++ b/tests/tom-swifty-test/XmlReflectionTests/SwiftInterfaceParserTests.cs
@@ -303,5 +303,102 @@ public override init () { }
.Where (el => el.Attribute ("name").Value == "objc").FirstOrDefault ();
Assert.IsNotNull (attribute, "no function attribute");
}
+
+ [Test]
+ public void HasAttributeDeclarations ()
+ {
+ var swiftCode = @"
+import Foundation
+@objc
+public class Foo : NSObject {
+ public override init () { }
+}
+";
+ SwiftInterfaceReflector reflector;
+ var module = ReflectToModules (swiftCode, "SomeModule", out reflector).FirstOrDefault (mod => mod.Name == "SomeModule");
+ Assert.IsNotNull (module, "no module");
+
+ var cl = module.Classes.FirstOrDefault (c => c.Name == "Foo");
+ Assert.IsNotNull (cl, "no class");
+
+ Assert.AreEqual (2, cl.Attributes.Count, "wrong number of attributes");
+
+ var attr = cl.Attributes.FirstOrDefault (at => at.Name == "objc");
+ Assert.IsNotNull (attr, "no objc attribute");
+ }
+
+
+ [Test]
+ public void HasAttributeObjCSelectorParameter ()
+ {
+ var swiftCode = @"
+import Foundation
+@objc
+public class Foo : NSObject {
+ public override init () { }
+ @objc(narwhal)
+ public func DoSomething () -> Int {
+ return 1
+ }
+}
+";
+ SwiftInterfaceReflector reflector;
+ var module = ReflectToModules (swiftCode, "SomeModule", out reflector).FirstOrDefault (mod => mod.Name == "SomeModule");
+ Assert.IsNotNull (module, "no module");
+
+ var cl = module.Classes.FirstOrDefault (c => c.Name == "Foo");
+ Assert.IsNotNull (cl, "no class");
+
+ var method = cl.Members.OfType ().FirstOrDefault (fn => fn.Name == "DoSomething");
+ Assert.IsNotNull (method, "no method");
+
+ Assert.AreEqual (1, method.Attributes.Count, "wrong number of attributes");
+
+ var attr = method.Attributes.FirstOrDefault (at => at.Name == "objc");
+ Assert.IsNotNull (attr, "no objc attribute");
+ var attrParam = attr.Parameters [0] as AttributeParameterLabel;
+ Assert.IsNotNull (attrParam, "not a label");
+ Assert.AreEqual (attrParam.Label, "narwhal", "wrong label");
+ }
+
+ [Test]
+ public void HasAvailableAttributeAll ()
+ {
+ var swiftCode = @"
+import Foundation
+
+
+public class Foo {
+ public init () { }
+ @available (*, unavailable)
+ public func DoSomething () -> Int {
+ return 1
+ }
+}
+";
+ SwiftInterfaceReflector reflector;
+ var module = ReflectToModules (swiftCode, "SomeModule", out reflector).FirstOrDefault (mod => mod.Name == "SomeModule");
+ Assert.IsNotNull (module, "no module");
+
+ var cl = module.Classes.FirstOrDefault (c => c.Name == "Foo");
+ Assert.IsNotNull (cl, "no class");
+
+ var method = cl.Members.OfType ().FirstOrDefault (fn => fn.Name == "DoSomething");
+ Assert.IsNotNull (method, "no method");
+
+ Assert.AreEqual (1, method.Attributes.Count, "wrong number of attributes");
+ var attr = method.Attributes [0];
+ Assert.AreEqual (attr.Name, "available");
+ Assert.AreEqual (3, attr.Parameters.Count, "wrong number of parameters");
+ var label = attr.Parameters [0] as AttributeParameterLabel;
+ Assert.IsNotNull (label, "not a label at 0");
+ Assert.AreEqual ("*", label.Label, "not a star");
+ label = attr.Parameters [1] as AttributeParameterLabel;
+ Assert.IsNotNull (label, "not a label at 1");
+ Assert.AreEqual (",", label.Label, "not a comma");
+ label = attr.Parameters [2] as AttributeParameterLabel;
+ Assert.IsNotNull (label, "not a label at 2");
+ Assert.AreEqual ("unavailable", label.Label, "not unavailable");
+ }
}
}