Skip to content
This repository was archived by the owner on Dec 12, 2024. It is now read-only.

Read XML into attributes. #544

Merged
merged 2 commits into from
Feb 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions SwiftReflector/SwiftInterfaceReflector/SwiftInterfaceReflector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions SwiftReflector/SwiftReflector.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@
<Compile Include="SwiftXmlReflection\OperatorDeclaration.cs" />
<Compile Include="TypeMapping\ModuleDatabase.cs" />
<Compile Include="SwiftInterfaceReflector\IModuleLoader.cs" />
<Compile Include="SwiftXmlReflection\AttributeDeclaration.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
Expand Down
136 changes: 136 additions & 0 deletions SwiftReflector/SwiftXmlReflection/AttributeDeclaration.cs
Original file line number Diff line number Diff line change
@@ -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<AttributeParameter> ();
}

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<AttributeParameter> 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<AttributeParameter> 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<AttributeParameter> ();
}

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<AttributeParameter> Parameters { get; private set; }
}
}
11 changes: 11 additions & 0 deletions SwiftReflector/SwiftXmlReflection/BaseDeclaration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public class BaseDeclaration {
protected BaseDeclaration ()
{
Generics = new GenericDeclarationCollection ();
Attributes = new List<AttributeDeclaration> ();
}

protected BaseDeclaration (BaseDeclaration other)
Expand All @@ -25,6 +26,7 @@ protected BaseDeclaration (BaseDeclaration other)
Parent = other.Parent;
ParentExtension = other.ParentExtension;
Generics = new GenericDeclarationCollection ();
Attributes = new List<AttributeDeclaration> ();
}

public string Name { get; set; }
Expand All @@ -39,6 +41,7 @@ public bool ContainsGenericParameters {
return Generics.Count () > 0;
}
}
public List<AttributeDeclaration> Attributes { get; private set; }

public bool IsTypeSpecBoundGeneric (TypeSpec sp)
{
Expand Down Expand Up @@ -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<AttributeDeclaration> AttributesFromXElement (XElement elem)
{
if (elem == null)
return Enumerable.Empty<AttributeDeclaration> ();
return elem.Elements ("attribute").Select (attr => AttributeDeclaration.FromXElement (attr));
}

public virtual string ToFullyQualifiedName (bool includeModule = true)
{
var sb = new StringBuilder ();
Expand Down
8 changes: 8 additions & 0 deletions SwiftReflector/SwiftXmlReflection/Enums.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,5 +70,13 @@ public enum ConstraintKind {
Inherits,
Equal
}

public enum AttributeParameterKind {
None,
Label,
Literal,
Sublist,
Unknown,
}
}

19 changes: 1 addition & 18 deletions swiftinterfaceparser/SwiftInterface.g4
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ balanced_token :
| OpLBrace balanced_tokens OpRBrace
| label_identifier
| literal
| Platform_name_platform_version
| operator
| any_punctuation_for_balanced_token
;

Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<FunctionDeclaration> ().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<FunctionDeclaration> ().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");
}
}
}