Skip to content

Commit 3eb5963

Browse files
authored
Merge pull request #98 from daliziql/feature/meta-attribute
Add MetaAttributes to support the parsing of AnnotateAttribute for namespaces, classes, functions, fields, etc.
2 parents bb0f83a + 49ed24f commit 3eb5963

14 files changed

+814
-16
lines changed
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
using System;
2+
3+
namespace CppAst.Tests
4+
{
5+
6+
public class TestMetaAttribute : InlineTestBase
7+
{
8+
[Test]
9+
public void TestNamespaceMetaAttribute()
10+
{
11+
ParseAssert( @"
12+
13+
#if !defined(__cppast)
14+
#define __cppast(...)
15+
#endif
16+
17+
namespace __cppast(script, is_browsable=true, desc=""a namespace test"") TestNs{
18+
19+
}
20+
21+
", compilation =>
22+
{
23+
Assert.False(compilation.HasErrors);
24+
25+
//annotate attribute support on namespace
26+
var ns = compilation.Namespaces[0];
27+
28+
Assert.IsTrue(ns.MetaAttributes.QueryArgumentAsBool("script", false));
29+
Assert.IsFalse(!ns.MetaAttributes.QueryArgumentAsBool("is_browsable", false));
30+
Assert.AreEqual("a namespace test", ns.MetaAttributes.QueryArgumentAsString("desc", ""));
31+
32+
}
33+
);
34+
}
35+
36+
[Test]
37+
public void TestClassMetaAttribute()
38+
{
39+
40+
ParseAssert( @"
41+
42+
#if !defined(__cppast)
43+
#define __cppast(...)
44+
#endif
45+
46+
class __cppast(script, is_browsable=true, desc=""a class"") TestClass
47+
{
48+
public:
49+
__cppast(desc=""a member function"")
50+
__cppast(desc2=""a member function 2"")
51+
void TestMemberFunc();
52+
53+
__cppast(desc=""a member field"")
54+
__cppast(desc2=""a member field 2"")
55+
int X;
56+
};
57+
58+
", compilation =>
59+
{
60+
Assert.False(compilation.HasErrors);
61+
62+
var cppClass = compilation.Classes[0];
63+
Assert.IsTrue(cppClass.MetaAttributes.QueryArgumentAsBool("script", false));
64+
Assert.IsFalse(!cppClass.MetaAttributes.QueryArgumentAsBool("is_browsable", false));
65+
Assert.AreEqual("a class", cppClass.MetaAttributes.QueryArgumentAsString("desc", ""));
66+
67+
Assert.AreEqual(1, cppClass.Functions.Count);
68+
Assert.AreEqual("a member function", cppClass.Functions[0].MetaAttributes.QueryArgumentAsString("desc", ""));
69+
Assert.AreEqual("a member function 2", cppClass.Functions[0].MetaAttributes.QueryArgumentAsString("desc2", ""));
70+
71+
Assert.AreEqual(1, cppClass.Fields.Count);
72+
Assert.AreEqual("a member field", cppClass.Fields[0].MetaAttributes.QueryArgumentAsString("desc", ""));
73+
Assert.AreEqual("a member field 2", cppClass.Fields[0].MetaAttributes.QueryArgumentAsString("desc2", ""));
74+
75+
}
76+
);
77+
}
78+
79+
[Test]
80+
public void TestTemplateMetaAttribute()
81+
{
82+
83+
ParseAssert( @"
84+
85+
#if !defined(__cppast)
86+
#define __cppast(...)
87+
#endif
88+
89+
template <typename T>
90+
class TestTemplateClass
91+
{
92+
public:
93+
94+
__cppast(desc=""a template member field"")
95+
T X;
96+
};
97+
98+
using IntClass __cppast(desc=""a template class for int"") = TestTemplateClass<int>;
99+
using DoubleClass __cppast(desc=""a template class for double"") = TestTemplateClass<double>;
100+
101+
typedef TestTemplateClass<float> __cppast(desc=""a template class for float"") FloatClass;
102+
", compilation =>
103+
{
104+
Assert.False(compilation.HasErrors);
105+
106+
var templateClass = compilation.Classes[0];
107+
Assert.AreEqual("a template member field", templateClass.Fields[0].MetaAttributes.QueryArgumentAsString("desc", ""));
108+
109+
var intClass = compilation.Classes[1];
110+
var doubleClass = compilation.Classes[2];
111+
var floatClass = compilation.Classes[3];
112+
Assert.AreEqual("a template class for int", intClass.MetaAttributes.QueryArgumentAsString("desc", ""));
113+
Assert.AreEqual("a template class for double", doubleClass.MetaAttributes.QueryArgumentAsString("desc", ""));
114+
Assert.AreEqual("a template class for float", floatClass.MetaAttributes.QueryArgumentAsString("desc", ""));
115+
}
116+
);
117+
}
118+
}
119+
}
Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
using System.Text;
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
6+
namespace CppAst
7+
{
8+
public class MetaAttribute
9+
{
10+
public string FeatureName;
11+
public Dictionary<string, object> ArgumentMap = new Dictionary<string, object>();
12+
13+
public override string ToString()
14+
{
15+
var builder = new StringBuilder();
16+
builder.Append($"{FeatureName} {{");
17+
foreach ( var kvp in ArgumentMap )
18+
{
19+
builder.Append( $"{kvp.Key}: {kvp.Value}, ");
20+
}
21+
builder.Append("}");
22+
return builder.ToString();
23+
}
24+
25+
public bool QueryKeyIsTrue(string key)
26+
{
27+
return ArgumentMap.ContainsKey(key) && (((ArgumentMap[key] is bool) && (bool)ArgumentMap[key]) || ((ArgumentMap[key] is string && (string)ArgumentMap[key] == "true")));
28+
}
29+
30+
public bool QueryKeysAreTrue(List<string> keys)
31+
{
32+
if (keys == null || !keys.Any())
33+
{
34+
return false;
35+
}
36+
37+
foreach (string key in keys)
38+
{
39+
if (!QueryKeyIsTrue(key))
40+
{
41+
return false;
42+
}
43+
}
44+
45+
return true;
46+
}
47+
}
48+
49+
public class MetaAttributeMap
50+
{
51+
public List<MetaAttribute> MetaList { get; private set; } = new List<MetaAttribute>();
52+
53+
public bool IsNull
54+
{
55+
get
56+
{
57+
return MetaList.Count == 0;
58+
}
59+
}
60+
61+
public object QueryArgument(string argName)
62+
{
63+
if (MetaList.Count == 0) return null;
64+
65+
foreach (var argMap in MetaList)
66+
{
67+
if (argMap.ArgumentMap.ContainsKey(argName))
68+
{
69+
return argMap.ArgumentMap[argName];
70+
}
71+
}
72+
73+
return null;
74+
}
75+
76+
public bool QueryArgumentAsBool(string argName, bool defaultVal)
77+
{
78+
var obj = QueryArgument(argName);
79+
if (obj != null)
80+
{
81+
try
82+
{
83+
return Convert.ToBoolean(obj);
84+
}
85+
catch(Exception)
86+
{
87+
}
88+
}
89+
90+
return defaultVal;
91+
}
92+
93+
public int QueryArgumentAsInteger(string argName, int defaultVal)
94+
{
95+
var obj = QueryArgument(argName);
96+
if (obj != null)
97+
{
98+
try
99+
{
100+
return Convert.ToInt32(obj);
101+
}
102+
catch (Exception)
103+
{
104+
}
105+
}
106+
107+
return defaultVal;
108+
}
109+
110+
public string QueryArgumentAsString(string argName, string defaultVal)
111+
{
112+
var obj = QueryArgument(argName);
113+
if (obj != null)
114+
{
115+
try
116+
{
117+
return Convert.ToString(obj);
118+
}
119+
catch (Exception)
120+
{
121+
}
122+
}
123+
124+
return defaultVal;
125+
}
126+
}
127+
128+
public static class CustomAttributeTool
129+
{
130+
public const string kMetaLeaderWord = "rmeta";
131+
public const string kMetaClassLeaderWord = "class";
132+
public const string kMetaFunctionLeaderWord = "function";
133+
public const string kMetaFieldLeaderWord = "field";
134+
public const string kMetaEnumLeaderWord = "enum";
135+
const string kMetaNotSetWord = "not_set_internal";
136+
const string kMetaSeparate = "____";
137+
const string kMetaArgumentSeparate = "|";
138+
const string kMetaStartWord = kMetaLeaderWord + kMetaSeparate;
139+
140+
public static bool IsRstudioAttribute(string meta)
141+
{
142+
return meta.StartsWith(kMetaStartWord);
143+
}
144+
145+
private static List<string> DivideForMetaAttribute(string meta)
146+
{
147+
var attrArray = meta.Split(kMetaSeparate);
148+
var retList = new List<string>();
149+
150+
for(int i = 1; i < attrArray.Length; i++)
151+
{
152+
retList.Add(attrArray[i]);
153+
}
154+
155+
return retList;
156+
}
157+
158+
public static MetaAttribute ParseMetaStringFor(string meta, string needLeaderWord, out string errorMessage)
159+
{
160+
string feature = "", arguments = "";
161+
errorMessage = "";
162+
163+
if (!IsRstudioAttribute(meta))
164+
{
165+
return null;
166+
}
167+
168+
List<string> tmpList = DivideForMetaAttribute(meta);
169+
if(tmpList.Count < 2 || tmpList[0] != needLeaderWord)
170+
{
171+
return null;
172+
}
173+
174+
var arrVal = tmpList[1].Split(kMetaArgumentSeparate);
175+
feature = arrVal[0];
176+
if(arrVal.Length >= 2)
177+
{
178+
arguments = arrVal[1];
179+
}
180+
181+
MetaAttribute attribute = new MetaAttribute();
182+
attribute.FeatureName = feature;
183+
bool parseSuc = NamedParameterParser.ParseNamedParameters(arguments, attribute.ArgumentMap, out errorMessage);
184+
if(parseSuc)
185+
{
186+
return attribute;
187+
}
188+
else
189+
{
190+
return null;
191+
}
192+
}
193+
194+
public static MetaAttribute ParseMetaStringFor(string meta, out string errorMessage)
195+
{
196+
errorMessage = "";
197+
MetaAttribute attribute = new MetaAttribute();
198+
bool parseSuc = NamedParameterParser.ParseNamedParameters(meta, attribute.ArgumentMap, out errorMessage);
199+
if(parseSuc)
200+
{
201+
return attribute;
202+
}
203+
204+
return null;
205+
}
206+
207+
}
208+
}

0 commit comments

Comments
 (0)