Browse Source

Added much improved support for operator overloading in the C# backend.

pull/1/head
triton 12 years ago
parent
commit
a14338a8c9
  1. 20
      src/Bridge/Class.cs
  2. 6
      src/Bridge/Method.cs
  3. 81
      src/Generator/Generators/CSharp/CSharpTextTemplate.cs
  4. 170
      src/Generator/Passes/CheckOperatorsOverloads.cs

20
src/Bridge/Class.cs

@ -158,6 +158,26 @@ namespace Cxxi @@ -158,6 +158,26 @@ namespace Cxxi
}
}
public IEnumerable<Method> Operators
{
get
{
return Methods.Where(method => method.IsOperator);
}
}
public IList<Method> FindOperator(CXXOperatorKind kind)
{
return Operators.Where(method => method.OperatorKind == kind)
.ToList();
}
public IList<Function> GetFunctionOverloads(Function function)
{
return Methods.Where(method => method.Name == function.Name)
.ToList<Function>();
}
public override T Visit<T>(IDeclVisitor<T> visitor)
{
return visitor.VisitClassDecl(this);

6
src/Bridge/Method.cs

@ -73,6 +73,7 @@ namespace Cxxi @@ -73,6 +73,7 @@ namespace Cxxi
public bool IsStatic { get; set; }
public bool IsConst { get; set; }
public bool IsImplicit { get; set; }
public bool IsSynthetized { get; set; }
public CXXMethodKind Kind;
public CXXOperatorKind OperatorKind;
@ -87,6 +88,11 @@ namespace Cxxi @@ -87,6 +88,11 @@ namespace Cxxi
get { return Kind == CXXMethodKind.Destructor; }
}
public bool IsOperator
{
get { return Kind == CXXMethodKind.Operator; }
}
public bool IsDefaultConstructor;
public bool IsCopyConstructor;
public bool IsMoveConstructor;

81
src/Generator/Generators/CSharp/CSharpTextTemplate.cs

@ -311,6 +311,9 @@ namespace Cxxi.Generators.CSharp @@ -311,6 +311,9 @@ namespace Cxxi.Generators.CSharp
if (method.IsConstructor)
continue;
if (method.IsSynthetized)
continue;
NewLineIfNeeded();
GeneratePInvokeMethod(method, @class);
@ -697,6 +700,9 @@ namespace Cxxi.Generators.CSharp @@ -697,6 +700,9 @@ namespace Cxxi.Generators.CSharp
Write("public ");
if (method.Kind == CXXMethodKind.Operator)
Write("static ");
var functionName = GetFunctionIdentifier(method, @class);
if (method.IsConstructor || method.IsDestructor)
@ -1054,6 +1060,72 @@ namespace Cxxi.Generators.CSharp @@ -1054,6 +1060,72 @@ namespace Cxxi.Generators.CSharp
WriteCloseBraceIndent();
}
public string GetOperatorIdentifier(CXXOperatorKind kind)
{
// These follow the order described in MSDN (Overloadable Operators).
switch (kind)
{
// These unary operators can be overloaded
case CXXOperatorKind.Plus: return "operator +";
case CXXOperatorKind.Minus: return "operator -";
case CXXOperatorKind.Exclaim: return "operator !";
case CXXOperatorKind.Tilde: return "operator ~";
case CXXOperatorKind.PlusPlus: return "operator ++";
case CXXOperatorKind.MinusMinus: return "operator --";
// These binary operators can be overloaded
case CXXOperatorKind.Star: return "operator *";
case CXXOperatorKind.Slash: return "operator /";
case CXXOperatorKind.Percent: return "operator +";
case CXXOperatorKind.Amp: return "operator &";
case CXXOperatorKind.Pipe: return "operator |";
case CXXOperatorKind.Caret: return "operator ^";
case CXXOperatorKind.LessLess: return "operator <<";
case CXXOperatorKind.GreaterGreater: return "operator >>";
// The comparison operators can be overloaded
case CXXOperatorKind.EqualEqual: return "operator ==";
case CXXOperatorKind.ExclaimEqual: return "operator !=";
case CXXOperatorKind.Less: return "operator <";
case CXXOperatorKind.Greater: return "operator >";
case CXXOperatorKind.LessEqual: return "operator <=";
case CXXOperatorKind.GreaterEqual: return "operator >=";
// Assignment operators cannot be overloaded
case CXXOperatorKind.PlusEqual:
case CXXOperatorKind.MinusEqual:
case CXXOperatorKind.StarEqual:
case CXXOperatorKind.SlashEqual:
case CXXOperatorKind.PercentEqual:
case CXXOperatorKind.AmpEqual:
case CXXOperatorKind.PipeEqual:
case CXXOperatorKind.CaretEqual:
case CXXOperatorKind.LessLessEqual:
case CXXOperatorKind.GreaterGreaterEqual:
// The array indexing operator cannot be overloaded
case CXXOperatorKind.Subscript:
// The conditional logical operators cannot be overloaded
case CXXOperatorKind.AmpAmp:
case CXXOperatorKind.PipePipe:
// These operators cannot be overloaded.
case CXXOperatorKind.Equal:
case CXXOperatorKind.Comma:
case CXXOperatorKind.ArrowStar:
case CXXOperatorKind.Arrow:
case CXXOperatorKind.Call:
case CXXOperatorKind.Conditional:
case CXXOperatorKind.New:
case CXXOperatorKind.Delete:
case CXXOperatorKind.Array_New:
case CXXOperatorKind.Array_Delete:
default: throw new NotImplementedException();
}
}
public string GetFunctionIdentifier(Function function, Class @class)
{
var identifier = SafeIdentifier(function.Name);
@ -1061,6 +1133,15 @@ namespace Cxxi.Generators.CSharp @@ -1061,6 +1133,15 @@ namespace Cxxi.Generators.CSharp
var printer = Type.TypePrinter as CSharpTypePrinter;
var isNativeContext = printer.ContextKind == CSharpTypePrinterContextKind.Native;
var method = function as Method;
if (method != null && method.Kind == CXXMethodKind.Operator)
{
if (isNativeContext)
identifier = "Operator" + method.OperatorKind.ToString();
else
identifier = GetOperatorIdentifier(method.OperatorKind);
}
var overloads = AST.Utils.GetFunctionOverloads(function, @class);
var index = overloads.IndexOf(function);

170
src/Generator/Passes/CheckOperatorsOverloads.cs

@ -0,0 +1,170 @@ @@ -0,0 +1,170 @@
using System.Linq;
namespace Cxxi.Passes
{
/// <summary>
/// Checks for missing operator overloads required by C#.
/// </summary>
class CheckOperatorsOverloadsPass : TranslationUnitPass
{
public override bool VisitClassDecl(Class @class)
{
// Check for C++ operators that cannot be represented in C#.
foreach (var @operator in @class.Operators)
{
if (!IsValidOperatorOverload(@operator.OperatorKind))
{
Driver.Diagnostics.EmitError(DiagnosticId.InvalidOperatorOverload,
"invalid operator overload");
@operator.ExplicityIgnored = true;
}
}
// The comparison operators, if overloaded, must be overloaded in pairs;
// that is, if == is overloaded, != must also be overloaded. The reverse
// is also true, and similar for < and >, and for <= and >=.
HandleMissingOperatorOverloadPair(@class, CXXOperatorKind.EqualEqual,
CXXOperatorKind.ExclaimEqual);
HandleMissingOperatorOverloadPair(@class, CXXOperatorKind.Less,
CXXOperatorKind.Greater);
HandleMissingOperatorOverloadPair(@class, CXXOperatorKind.LessEqual,
CXXOperatorKind.GreaterEqual);
return false;
}
static void HandleMissingOperatorOverloadPair(Class @class, CXXOperatorKind op1,
CXXOperatorKind op2)
{
int index;
var missingKind = CheckMissingOperatorOverloadPair(@class, out index, op1, op2);
if (missingKind == CXXOperatorKind.None)
return;
var existingKind = missingKind == op2 ? op1 : op2;
var overload = @class.FindOperator(existingKind).First();
var @params = overload.Parameters;
if (overload.IsStatic)
@params = @params.Skip(1).ToList();
var method = new Method()
{
IsSynthetized = true,
Kind = CXXMethodKind.Operator,
OperatorKind = missingKind,
ReturnType = overload.ReturnType,
Parameters = @params
};
@class.Methods.Insert(index, method);
}
static CXXOperatorKind CheckMissingOperatorOverloadPair(Class @class,
out int index, CXXOperatorKind op1, CXXOperatorKind op2)
{
var first = @class.FindOperator(op1);
var second = @class.FindOperator(op2);
var hasFirst = first.Count > 0;
var hasSecond = second.Count > 0;
if (hasFirst && !hasSecond)
{
index = @class.Methods.IndexOf(first.Last());
return op2;
}
if (hasSecond && !hasFirst)
{
index = @class.Methods.IndexOf(second.First());
return op1;
}
index = 0;
return CXXOperatorKind.None;
}
static bool IsValidOperatorOverload(CXXOperatorKind kind)
{
// These follow the order described in MSDN (Overloadable Operators).
switch (kind)
{
// These unary operators can be overloaded
case CXXOperatorKind.Plus:
case CXXOperatorKind.Minus:
case CXXOperatorKind.Exclaim:
case CXXOperatorKind.Tilde:
case CXXOperatorKind.PlusPlus:
case CXXOperatorKind.MinusMinus:
// These binary operators can be overloaded
case CXXOperatorKind.Star:
case CXXOperatorKind.Slash:
case CXXOperatorKind.Percent:
case CXXOperatorKind.Amp:
case CXXOperatorKind.Pipe:
case CXXOperatorKind.Caret:
case CXXOperatorKind.LessLess:
case CXXOperatorKind.GreaterGreater:
// The comparison operators can be overloaded
case CXXOperatorKind.EqualEqual:
case CXXOperatorKind.ExclaimEqual:
case CXXOperatorKind.Less:
case CXXOperatorKind.Greater:
case CXXOperatorKind.LessEqual:
case CXXOperatorKind.GreaterEqual:
return true;
// Assignment operators cannot be overloaded
case CXXOperatorKind.PlusEqual:
case CXXOperatorKind.MinusEqual:
case CXXOperatorKind.StarEqual:
case CXXOperatorKind.SlashEqual:
case CXXOperatorKind.PercentEqual:
case CXXOperatorKind.AmpEqual:
case CXXOperatorKind.PipeEqual:
case CXXOperatorKind.CaretEqual:
case CXXOperatorKind.LessLessEqual:
case CXXOperatorKind.GreaterGreaterEqual:
// The array indexing operator cannot be overloaded
case CXXOperatorKind.Subscript:
// The conditional logical operators cannot be overloaded
case CXXOperatorKind.AmpAmp:
case CXXOperatorKind.PipePipe:
// These operators cannot be overloaded.
case CXXOperatorKind.Equal:
case CXXOperatorKind.Comma:
case CXXOperatorKind.ArrowStar:
case CXXOperatorKind.Arrow:
case CXXOperatorKind.Call:
case CXXOperatorKind.Conditional:
case CXXOperatorKind.New:
case CXXOperatorKind.Delete:
case CXXOperatorKind.Array_New:
case CXXOperatorKind.Array_Delete:
default:
return false;
}
}
}
public static class CheckOperatorsOverloadsExtensions
{
public static void CheckOperatorOverloads(this PassBuilder builder)
{
var pass = new CheckOperatorsOverloadsPass();
builder.AddPass(pass);
}
}
}
Loading…
Cancel
Save