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

Commit 64deb0a

Browse files
new files too, steve
1 parent 9e73364 commit 64deb0a

File tree

2 files changed

+193
-0
lines changed

2 files changed

+193
-0
lines changed

SwiftReflector/Naming/CSSafeNaming.cs

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Globalization;
4+
using System.Linq;
5+
using System.Text;
6+
using Dynamo.CSLang;
7+
using SwiftReflector.TypeMapping;
8+
9+
#nullable enable
10+
11+
namespace SwiftReflector.Naming
12+
{
13+
public class CSSafeNaming {
14+
15+
static UnicodeCategory [] validStarts = {
16+
UnicodeCategory.UppercaseLetter,
17+
UnicodeCategory.LowercaseLetter,
18+
UnicodeCategory.TitlecaseLetter,
19+
UnicodeCategory.ModifierLetter,
20+
UnicodeCategory.OtherLetter,
21+
UnicodeCategory.LetterNumber
22+
};
23+
24+
static bool ValidIdentifierStart (UnicodeCategory cat)
25+
{
26+
return validStarts.Contains (cat);
27+
}
28+
29+
static UnicodeCategory [] validContent = {
30+
UnicodeCategory.DecimalDigitNumber,
31+
UnicodeCategory.ConnectorPunctuation,
32+
UnicodeCategory.Format
33+
};
34+
35+
static bool ValidIdentifierContent (UnicodeCategory cat)
36+
{
37+
return ValidIdentifierStart (cat) || validContent.Contains (cat);
38+
}
39+
40+
static bool IsValidIdentifier (int position, UnicodeCategory cat)
41+
{
42+
if (position == 0)
43+
return ValidIdentifierStart (cat);
44+
else
45+
return ValidIdentifierContent (cat);
46+
}
47+
48+
static bool IsHighUnicode (string s)
49+
{
50+
// Steve says: this is arbitrary, but it solves an issue
51+
// with mcs and csc not liking certain Ll and Lu class
52+
// unicode characters (for now).
53+
// Open issue: https://github.com/dotnet/roslyn/issues/27986
54+
var encoding = Encoding.UTF32;
55+
var bytes = encoding.GetBytes (s);
56+
var utf32Value = BitConverter.ToUInt32 (bytes, 0);
57+
return utf32Value > 0xffff;
58+
}
59+
60+
public static string SafeIdentifier (string name, ScopedNaming? naming = null)
61+
{
62+
var sb = new StringBuilder ();
63+
64+
var characterEnum = StringInfo.GetTextElementEnumerator (name);
65+
while (characterEnum.MoveNext ()) {
66+
string c = characterEnum.GetTextElement ();
67+
int i = characterEnum.ElementIndex;
68+
69+
var cat = CharUnicodeInfo.GetUnicodeCategory (name, i);
70+
71+
if (IsValidIdentifier (i, cat) && !IsHighUnicode (c))
72+
sb.Append (i == 0 && cat == UnicodeCategory.LowercaseLetter ? c.ToUpper () : c);
73+
else
74+
sb.Append (UnicodeMapper.MapToUnicodeName (c));
75+
}
76+
77+
if (CSKeywords.IsKeyword (sb.ToString ()))
78+
sb.Append ('_');
79+
return naming is not null ? naming.GenSym (sb.ToString ()) : sb.ToString ();
80+
}
81+
82+
public static CSIdentifier SafeCSIdentifier (string name, ScopedNaming? naming)
83+
{
84+
return new CSIdentifier (SafeIdentifier (name, naming));
85+
}
86+
87+
static Dictionary<char, string> operatorMap = new Dictionary<char, string> {
88+
{ '/', "Slash" },
89+
{ '=', "Equals" },
90+
{ '+', "Plus" },
91+
{ '-', "Minus" },
92+
{ '!', "Bang" },
93+
{ '*', "Star" },
94+
{ '%', "Percent" },
95+
{ '<', "LessThan" },
96+
{ '>', "GreaterThan" },
97+
{ '&', "Ampersand" },
98+
{ '|', "Pipe" },
99+
{ '^', "Hat" },
100+
{ '~', "Tilde" },
101+
{ '?', "QuestionMark"},
102+
{ '.', "Dot" },
103+
};
104+
105+
static string OperatorCharToSafeString (char c)
106+
{
107+
return operatorMap.TryGetValue (c, out var result) ? result : c.ToString ();
108+
}
109+
110+
public static string SafeOperatorName (string s)
111+
{
112+
var sb = new StringBuilder ();
113+
foreach (var c in s) {
114+
sb.Append (OperatorCharToSafeString (c));
115+
}
116+
return SafeIdentifier (sb.ToString ());
117+
}
118+
119+
public static UnicodeMapper UnicodeMapper = UnicodeMapper.Default;
120+
}
121+
}
122+

SwiftReflector/Naming/ScopedNaming.cs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using Dynamo.CSLang;
4+
5+
#nullable enable
6+
7+
namespace SwiftReflector.Naming
8+
{
9+
public class ScopedNaming
10+
{
11+
string autoSymPrefix;
12+
Stack<HashSet<string>> names = new Stack<HashSet<string>> ();
13+
14+
public ScopedNaming (string? autoSymPrefix = null)
15+
{
16+
this.autoSymPrefix = string.IsNullOrEmpty (autoSymPrefix) ? "_symbol" : autoSymPrefix;
17+
names.Push (new HashSet<string> ());
18+
}
19+
20+
public void EnterScope ()
21+
{
22+
names.Push (new HashSet<string> (names.Peek ()));
23+
}
24+
25+
public void ExitScope ()
26+
{
27+
if (names.Count == 0)
28+
throw new Exception ("exited top level scope - that's bad");
29+
}
30+
31+
HashSet<string> Top => names.Peek ();
32+
33+
bool Contains (string symbol)
34+
{
35+
return Top.Contains (symbol);
36+
}
37+
38+
public string GenSym (string prefix)
39+
{
40+
if (string.IsNullOrEmpty (prefix))
41+
throw new ArgumentException ("prefix must not be empty", nameof (prefix));
42+
lock (names) {
43+
if (Contains (prefix)) {
44+
var index = 1;
45+
while (true) {
46+
var candidate = $"{prefix}{index}";
47+
if (!Contains (candidate)) {
48+
prefix = candidate;
49+
break;
50+
}
51+
index++;
52+
}
53+
}
54+
Top.Add (prefix);
55+
return prefix;
56+
}
57+
}
58+
59+
public CSIdentifier GenID (string prefix)
60+
{
61+
return new CSIdentifier (GenSym (prefix));
62+
}
63+
64+
65+
public string GenSym ()
66+
{
67+
return GenSym (autoSymPrefix);
68+
}
69+
}
70+
}
71+

0 commit comments

Comments
 (0)