Browse Source

Evaluate expressions for enums generated using GenerateEnumFromMacros (#1048)

* Evaluate expressions when generating enum from macros

ExpressionEvaluator taken from https://github.com/codingseb/ExpressionEvaluator

* Set namespace for enums generated from macros.

* Add Tests
pull/1135/head
TheLastRar 9 years ago committed by João Matos
parent
commit
430bbdb257
  1. 33
      src/Generator/Library.cs
  2. 1446
      src/Generator/Utils/ExpressionEvaluator.cs
  3. 1
      src/Generator/premake5.lua
  4. 17
      tests/CSharp/CSharp.Tests.cs
  5. 3
      tests/CSharp/CSharp.cs
  6. 10
      tests/CSharp/CSharp.h

33
src/Generator/Library.cs

@ -91,13 +91,14 @@ namespace CppSharp
{ {
Name = macro.Name, Name = macro.Name,
Expression = macro.Expression, Expression = macro.Expression,
Value = ParseMacroExpression(macro.Expression), Value = ParseMacroExpression(macro.Expression, @enum),
Namespace = @enum Namespace = @enum
}; };
} }
static bool ParseToNumber(string num, out long val) static bool ParseToNumber(string num, Enumeration @enum, out long val)
{ {
//ExpressionEvaluator does not work with hex
if (num.StartsWith("0x", StringComparison.CurrentCultureIgnoreCase)) if (num.StartsWith("0x", StringComparison.CurrentCultureIgnoreCase))
{ {
num = num.Substring(2); num = num.Substring(2);
@ -106,17 +107,35 @@ namespace CppSharp
CultureInfo.CurrentCulture, out val); CultureInfo.CurrentCulture, out val);
} }
return long.TryParse(num, out val); ExpressionEvaluator evaluator = new ExpressionEvaluator();
//Include values of past items
evaluator.Variables = new Dictionary<string, object>();
foreach (Enumeration.Item item in @enum.Items)
{
//ExpressionEvaluator is requires lowercase variables
evaluator.Variables.Add(item.Name.ToLower(), item.Value);
}
try
{
var ret = evaluator.Evaluate("(long)" + num.ReplaceLineBreaks(" ").Replace('\\',' '));
val = (long)ret;
return true;
}
catch (ExpressionEvaluatorSyntaxErrorException)
{
val = 0;
return false;
}
} }
static ulong ParseMacroExpression(string expression) static ulong ParseMacroExpression(string expression, Enumeration @enum)
{ {
// TODO: Handle string expressions // TODO: Handle string expressions
if (expression.Length == 3 && expression[0] == '\'' && expression[2] == '\'') // '0' || 'A' if (expression.Length == 3 && expression[0] == '\'' && expression[2] == '\'') // '0' || 'A'
return expression[1]; // return the ASCI code of this character return expression[1]; // return the ASCI code of this character
long val; long val;
return ParseToNumber(expression, out val) ? (ulong)val : 0; return ParseToNumber(expression, @enum, out val) ? (ulong)val : 0;
} }
public static Enumeration GenerateEnumFromMacros(this ASTContext context, string name, public static Enumeration GenerateEnumFromMacros(this ASTContext context, string name,
@ -141,6 +160,10 @@ namespace CppSharp
if (@enum.Items.Exists(it => it.Name == macro.Name)) if (@enum.Items.Exists(it => it.Name == macro.Name))
continue; continue;
// Set the namespace to the namespace we found the 1st item in
if (@enum.Namespace == null)
@enum.Namespace = unit;
var item = @enum.GenerateEnumItemFromMacro(macro); var item = @enum.GenerateEnumItemFromMacro(macro);
@enum.AddItem(item); @enum.AddItem(item);

1446
src/Generator/Utils/ExpressionEvaluator.cs

File diff suppressed because it is too large Load Diff

1
src/Generator/premake5.lua

@ -15,6 +15,7 @@ project "CppSharp.Generator"
{ {
"System", "System",
"System.Core", "System.Core",
"Microsoft.CSharp",
"CppSharp", "CppSharp",
"CppSharp.AST", "CppSharp.AST",
"CppSharp.Parser" "CppSharp.Parser"

17
tests/CSharp/CSharp.Tests.cs

@ -988,6 +988,23 @@ public unsafe class CSharpTests : GeneratorTestFixture
Assert.IsTrue(a == MyMacroTestEnum.MY_MACRO_TEST_1 && b == MyMacroTestEnum.MY_MACRO_TEST_2); Assert.IsTrue(a == MyMacroTestEnum.MY_MACRO_TEST_1 && b == MyMacroTestEnum.MY_MACRO_TEST_2);
} }
[Test]
public void TestMyMacro2TestEnum()
{
var a = (MyMacroTest2Enum)0;
var b = (MyMacroTest2Enum)1;
var c = (MyMacroTest2Enum)0x2;
var d = (MyMacroTest2Enum)(1 << 2);
var e = (MyMacroTest2Enum)(b | c);
var f = (MyMacroTest2Enum)(b | c | d);
var g = (MyMacroTest2Enum)(1 << 3);
var h = (MyMacroTest2Enum)((1 << 4) - 1);
Assert.IsTrue(a == MyMacroTest2Enum.MY_MACRO_TEST2_0 && b == MyMacroTest2Enum.MY_MACRO_TEST2_1 &&
c == MyMacroTest2Enum.MY_MACRO_TEST2_2 && d == MyMacroTest2Enum.MY_MACRO_TEST2_3 &&
e == MyMacroTest2Enum.MY_MACRO_TEST2_1_2 && f == MyMacroTest2Enum.MY_MACRO_TEST2_1_2_3 &&
g == MyMacroTest2Enum.MY_MACRO_TEST2_4 && h == MyMacroTest2Enum.MY_MACRO_TEST2ALL);
}
[Test] [Test]
public void TestGenerationOfArraySetter() public void TestGenerationOfArraySetter()
{ {

3
tests/CSharp/CSharp.cs

@ -55,6 +55,9 @@ namespace CppSharp.Tests
where macroRegex.IsMatch(macro.Name) where macroRegex.IsMatch(macro.Name)
select macro.Name).ToList(); select macro.Name).ToList();
var enumTest = ctx.GenerateEnumFromMacros("MyMacroTestEnum", list.ToArray()); var enumTest = ctx.GenerateEnumFromMacros("MyMacroTestEnum", list.ToArray());
var enumTest2 = ctx.GenerateEnumFromMacros("MyMacroTest2Enum", "MY_MACRO_TEST2_*");
enumTest.Namespace = new Namespace() enumTest.Namespace = new Namespace()
{ {
Name = "MacroTest", Name = "MacroTest",

10
tests/CSharp/CSharp.h

@ -1198,6 +1198,16 @@ struct StructTestArrayTypeFromTypedef
#define MY_MACRO_TEST_1 '1' #define MY_MACRO_TEST_1 '1'
#define MY_MACRO_TEST_2 '2' #define MY_MACRO_TEST_2 '2'
#define MY_MACRO_TEST2_0 0_invalid
#define MY_MACRO_TEST2_1 1
#define MY_MACRO_TEST2_2 0x2
#define MY_MACRO_TEST2_3 (1 << 2)
#define MY_MACRO_TEST2_1_2 (MY_MACRO_TEST2_1 | MY_MACRO_TEST2_2)
#define MY_MACRO_TEST2_1_2_3 (MY_MACRO_TEST2_1 | MY_MACRO_TEST2_2 | \
MY_MACRO_TEST2_3)
#define MY_MACRO_TEST2_4 (1 << 3)
#define MY_MACRO_TEST2_ALL (1 << 4) - 1
struct ComplexArrayElement struct ComplexArrayElement
{ {
bool BoolField; bool BoolField;

Loading…
Cancel
Save