-
-
Notifications
You must be signed in to change notification settings - Fork 67
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #98 from daliziql/feature/meta-attribute
Add MetaAttributes to support the parsing of AnnotateAttribute for namespaces, classes, functions, fields, etc.
- Loading branch information
Showing
14 changed files
with
814 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
using System; | ||
|
||
namespace CppAst.Tests | ||
{ | ||
|
||
public class TestMetaAttribute : InlineTestBase | ||
{ | ||
[Test] | ||
public void TestNamespaceMetaAttribute() | ||
{ | ||
ParseAssert( @" | ||
#if !defined(__cppast) | ||
#define __cppast(...) | ||
#endif | ||
namespace __cppast(script, is_browsable=true, desc=""a namespace test"") TestNs{ | ||
} | ||
", compilation => | ||
{ | ||
Assert.False(compilation.HasErrors); | ||
|
||
//annotate attribute support on namespace | ||
var ns = compilation.Namespaces[0]; | ||
|
||
Assert.IsTrue(ns.MetaAttributes.QueryArgumentAsBool("script", false)); | ||
Assert.IsFalse(!ns.MetaAttributes.QueryArgumentAsBool("is_browsable", false)); | ||
Assert.AreEqual("a namespace test", ns.MetaAttributes.QueryArgumentAsString("desc", "")); | ||
|
||
} | ||
); | ||
} | ||
|
||
[Test] | ||
public void TestClassMetaAttribute() | ||
{ | ||
|
||
ParseAssert( @" | ||
#if !defined(__cppast) | ||
#define __cppast(...) | ||
#endif | ||
class __cppast(script, is_browsable=true, desc=""a class"") TestClass | ||
{ | ||
public: | ||
__cppast(desc=""a member function"") | ||
__cppast(desc2=""a member function 2"") | ||
void TestMemberFunc(); | ||
__cppast(desc=""a member field"") | ||
__cppast(desc2=""a member field 2"") | ||
int X; | ||
}; | ||
", compilation => | ||
{ | ||
Assert.False(compilation.HasErrors); | ||
|
||
var cppClass = compilation.Classes[0]; | ||
Assert.IsTrue(cppClass.MetaAttributes.QueryArgumentAsBool("script", false)); | ||
Assert.IsFalse(!cppClass.MetaAttributes.QueryArgumentAsBool("is_browsable", false)); | ||
Assert.AreEqual("a class", cppClass.MetaAttributes.QueryArgumentAsString("desc", "")); | ||
|
||
Assert.AreEqual(1, cppClass.Functions.Count); | ||
Assert.AreEqual("a member function", cppClass.Functions[0].MetaAttributes.QueryArgumentAsString("desc", "")); | ||
Assert.AreEqual("a member function 2", cppClass.Functions[0].MetaAttributes.QueryArgumentAsString("desc2", "")); | ||
|
||
Assert.AreEqual(1, cppClass.Fields.Count); | ||
Assert.AreEqual("a member field", cppClass.Fields[0].MetaAttributes.QueryArgumentAsString("desc", "")); | ||
Assert.AreEqual("a member field 2", cppClass.Fields[0].MetaAttributes.QueryArgumentAsString("desc2", "")); | ||
|
||
} | ||
); | ||
} | ||
|
||
[Test] | ||
public void TestTemplateMetaAttribute() | ||
{ | ||
|
||
ParseAssert( @" | ||
#if !defined(__cppast) | ||
#define __cppast(...) | ||
#endif | ||
template <typename T> | ||
class TestTemplateClass | ||
{ | ||
public: | ||
__cppast(desc=""a template member field"") | ||
T X; | ||
}; | ||
using IntClass __cppast(desc=""a template class for int"") = TestTemplateClass<int>; | ||
using DoubleClass __cppast(desc=""a template class for double"") = TestTemplateClass<double>; | ||
typedef TestTemplateClass<float> __cppast(desc=""a template class for float"") FloatClass; | ||
", compilation => | ||
{ | ||
Assert.False(compilation.HasErrors); | ||
|
||
var templateClass = compilation.Classes[0]; | ||
Assert.AreEqual("a template member field", templateClass.Fields[0].MetaAttributes.QueryArgumentAsString("desc", "")); | ||
|
||
var intClass = compilation.Classes[1]; | ||
var doubleClass = compilation.Classes[2]; | ||
var floatClass = compilation.Classes[3]; | ||
Assert.AreEqual("a template class for int", intClass.MetaAttributes.QueryArgumentAsString("desc", "")); | ||
Assert.AreEqual("a template class for double", doubleClass.MetaAttributes.QueryArgumentAsString("desc", "")); | ||
Assert.AreEqual("a template class for float", floatClass.MetaAttributes.QueryArgumentAsString("desc", "")); | ||
} | ||
); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,208 @@ | ||
using System.Text; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
|
||
namespace CppAst | ||
{ | ||
public class MetaAttribute | ||
{ | ||
public string FeatureName; | ||
public Dictionary<string, object> ArgumentMap = new Dictionary<string, object>(); | ||
|
||
public override string ToString() | ||
{ | ||
var builder = new StringBuilder(); | ||
builder.Append($"{FeatureName} {{"); | ||
foreach ( var kvp in ArgumentMap ) | ||
{ | ||
builder.Append( $"{kvp.Key}: {kvp.Value}, "); | ||
} | ||
builder.Append("}"); | ||
return builder.ToString(); | ||
} | ||
|
||
public bool QueryKeyIsTrue(string key) | ||
{ | ||
return ArgumentMap.ContainsKey(key) && (((ArgumentMap[key] is bool) && (bool)ArgumentMap[key]) || ((ArgumentMap[key] is string && (string)ArgumentMap[key] == "true"))); | ||
} | ||
|
||
public bool QueryKeysAreTrue(List<string> keys) | ||
{ | ||
if (keys == null || !keys.Any()) | ||
{ | ||
return false; | ||
} | ||
|
||
foreach (string key in keys) | ||
{ | ||
if (!QueryKeyIsTrue(key)) | ||
{ | ||
return false; | ||
} | ||
} | ||
|
||
return true; | ||
} | ||
} | ||
|
||
public class MetaAttributeMap | ||
{ | ||
public List<MetaAttribute> MetaList { get; private set; } = new List<MetaAttribute>(); | ||
|
||
public bool IsNull | ||
{ | ||
get | ||
{ | ||
return MetaList.Count == 0; | ||
} | ||
} | ||
|
||
public object QueryArgument(string argName) | ||
{ | ||
if (MetaList.Count == 0) return null; | ||
|
||
foreach (var argMap in MetaList) | ||
{ | ||
if (argMap.ArgumentMap.ContainsKey(argName)) | ||
{ | ||
return argMap.ArgumentMap[argName]; | ||
} | ||
} | ||
|
||
return null; | ||
} | ||
|
||
public bool QueryArgumentAsBool(string argName, bool defaultVal) | ||
{ | ||
var obj = QueryArgument(argName); | ||
if (obj != null) | ||
{ | ||
try | ||
{ | ||
return Convert.ToBoolean(obj); | ||
} | ||
catch(Exception) | ||
{ | ||
} | ||
} | ||
|
||
return defaultVal; | ||
} | ||
|
||
public int QueryArgumentAsInteger(string argName, int defaultVal) | ||
{ | ||
var obj = QueryArgument(argName); | ||
if (obj != null) | ||
{ | ||
try | ||
{ | ||
return Convert.ToInt32(obj); | ||
} | ||
catch (Exception) | ||
{ | ||
} | ||
} | ||
|
||
return defaultVal; | ||
} | ||
|
||
public string QueryArgumentAsString(string argName, string defaultVal) | ||
{ | ||
var obj = QueryArgument(argName); | ||
if (obj != null) | ||
{ | ||
try | ||
{ | ||
return Convert.ToString(obj); | ||
} | ||
catch (Exception) | ||
{ | ||
} | ||
} | ||
|
||
return defaultVal; | ||
} | ||
} | ||
|
||
public static class CustomAttributeTool | ||
{ | ||
public const string kMetaLeaderWord = "rmeta"; | ||
public const string kMetaClassLeaderWord = "class"; | ||
public const string kMetaFunctionLeaderWord = "function"; | ||
public const string kMetaFieldLeaderWord = "field"; | ||
public const string kMetaEnumLeaderWord = "enum"; | ||
const string kMetaNotSetWord = "not_set_internal"; | ||
const string kMetaSeparate = "____"; | ||
const string kMetaArgumentSeparate = "|"; | ||
const string kMetaStartWord = kMetaLeaderWord + kMetaSeparate; | ||
|
||
public static bool IsRstudioAttribute(string meta) | ||
{ | ||
return meta.StartsWith(kMetaStartWord); | ||
} | ||
|
||
private static List<string> DivideForMetaAttribute(string meta) | ||
{ | ||
var attrArray = meta.Split(kMetaSeparate); | ||
var retList = new List<string>(); | ||
|
||
for(int i = 1; i < attrArray.Length; i++) | ||
{ | ||
retList.Add(attrArray[i]); | ||
} | ||
|
||
return retList; | ||
} | ||
|
||
public static MetaAttribute ParseMetaStringFor(string meta, string needLeaderWord, out string errorMessage) | ||
{ | ||
string feature = "", arguments = ""; | ||
errorMessage = ""; | ||
|
||
if (!IsRstudioAttribute(meta)) | ||
{ | ||
return null; | ||
} | ||
|
||
List<string> tmpList = DivideForMetaAttribute(meta); | ||
if(tmpList.Count < 2 || tmpList[0] != needLeaderWord) | ||
{ | ||
return null; | ||
} | ||
|
||
var arrVal = tmpList[1].Split(kMetaArgumentSeparate); | ||
feature = arrVal[0]; | ||
if(arrVal.Length >= 2) | ||
{ | ||
arguments = arrVal[1]; | ||
} | ||
|
||
MetaAttribute attribute = new MetaAttribute(); | ||
attribute.FeatureName = feature; | ||
bool parseSuc = NamedParameterParser.ParseNamedParameters(arguments, attribute.ArgumentMap, out errorMessage); | ||
if(parseSuc) | ||
{ | ||
return attribute; | ||
} | ||
else | ||
{ | ||
return null; | ||
} | ||
} | ||
|
||
public static MetaAttribute ParseMetaStringFor(string meta, out string errorMessage) | ||
{ | ||
errorMessage = ""; | ||
MetaAttribute attribute = new MetaAttribute(); | ||
bool parseSuc = NamedParameterParser.ParseNamedParameters(meta, attribute.ArgumentMap, out errorMessage); | ||
if(parseSuc) | ||
{ | ||
return attribute; | ||
} | ||
|
||
return null; | ||
} | ||
|
||
} | ||
} |
Oops, something went wrong.