Skip to content

Commit

Permalink
Directly move functions instead of making methods
Browse files Browse the repository at this point in the history
This keeps the original functions instead of ignoring them which helps when rearranging passes - in particular when the pass for symbols is involved.

Signed-off-by: Dimitar Dobrev <dpldobrev@protonmail.com>
  • Loading branch information
ddobrev committed Nov 7, 2019
1 parent a00f34c commit f6f52ac
Show file tree
Hide file tree
Showing 5 changed files with 153 additions and 99 deletions.
18 changes: 12 additions & 6 deletions src/Generator/Generators/CLI/CLIHeaders.cs
Original file line number Diff line number Diff line change
Expand Up @@ -222,19 +222,25 @@ public void GenerateFunctions(DeclarationContext decl)
{
PushBlock(BlockKind.FunctionsClass);

WriteLine("public ref class {0}", TranslationUnit.FileNameWithoutExtension);
WriteLine("{");
WriteLine("public:");
Indent();
if (!(decl is Class))
{
WriteLine("public ref class {0}", TranslationUnit.FileNameWithoutExtension);
WriteLine("{");
WriteLine("public:");
Indent();
}

// Generate all the function declarations for the module.
foreach (var function in decl.Functions)
{
GenerateFunction(function);
}

Unindent();
WriteLine("};");
if (!(decl is Class))
{
Unindent();
WriteLine("};");
}

PopBlock(NewLineKind.BeforeNextBlock);
}
Expand Down
8 changes: 3 additions & 5 deletions src/Generator/Generators/CLI/CLISources.cs
Original file line number Diff line number Diff line change
Expand Up @@ -889,11 +889,9 @@ public void GenerateFunction(Function function, DeclarationContext @namespace)

GenerateDeclarationCommon(function);

var classSig = string.Format("{0}::{1}", QualifiedIdentifier(@namespace),
TranslationUnit.FileNameWithoutExtension);

Write("{0} {1}::{2}(", function.ReturnType, classSig,
function.Name);
Write($@"{function.ReturnType} {QualifiedIdentifier(@namespace)}::{
(@namespace is Class ? string.Empty : $@"{
TranslationUnit.FileNameWithoutExtension}::")}{function.Name}(");

for (var i = 0; i < function.Parameters.Count; ++i)
{
Expand Down
76 changes: 49 additions & 27 deletions src/Generator/Generators/CSharp/CSharpSources.cs
Original file line number Diff line number Diff line change
Expand Up @@ -239,15 +239,19 @@ private IEnumerable<Class> EnumerateClasses(DeclarationContext context)

public virtual void GenerateNamespaceFunctionsAndVariables(DeclarationContext context)
{
var hasGlobalFunctions = !(context is Class) && context.Functions.Any(
f => f.IsGenerated);

var hasGlobalVariables = !(context is Class) && context.Variables.Any(
v => v.IsGenerated && v.Access == AccessSpecifier.Public);

if (!context.Functions.Any(f => f.IsGenerated) && !hasGlobalVariables)
if (!hasGlobalFunctions && !hasGlobalVariables)
return;

PushBlock(BlockKind.Functions);
var parentName = SafeIdentifier(context.TranslationUnit.FileNameWithoutExtension);

PushBlock(BlockKind.Functions);

var keyword = "class";
var classes = EnumerateClasses().ToList();
if (classes.FindAll(cls => cls.IsValueType && cls.Name == parentName && context.QualifiedLogicalName == cls.Namespace.QualifiedLogicalName).Any())
Expand All @@ -271,12 +275,8 @@ public virtual void GenerateNamespaceFunctionsAndVariables(DeclarationContext co
UnindentAndWriteCloseBrace();
PopBlock(NewLineKind.BeforeNextBlock);

foreach (var function in context.Functions)
{
if (!function.IsGenerated) continue;

foreach (Function function in context.Functions.Where(f => f.IsGenerated))
GenerateFunction(function, parentName);
}

foreach (var variable in context.Variables.Where(
v => v.IsGenerated && v.Access == AccessSpecifier.Public))
Expand Down Expand Up @@ -443,7 +443,8 @@ public override bool VisitClassDecl(Class @class)
}

GenerateClassConstructors(@class);

foreach (Function function in @class.Functions.Where(f => f.IsGenerated))
GenerateFunction(function, @class.Name);
GenerateClassMethods(@class.Methods);
GenerateClassVariables(@class);
GenerateClassProperties(@class);
Expand Down Expand Up @@ -649,6 +650,10 @@ private void GatherClassInternalFunctions(Class @class, bool includeCtors,
&& !functions.Contains(prop.SetMethod))
tryAddOverload(prop.SetMethod);
}

functions.AddRange(from function in @class.Functions
where function.IsGenerated && !function.IsSynthetized
select function);
}

private IEnumerable<string> GatherInternalParams(Function function, out TypePrinterResult retType)
Expand Down Expand Up @@ -2323,6 +2328,8 @@ public void GenerateFunction(Function function, string parentName)

if (function.SynthKind == FunctionSynthKind.DefaultValueOverload)
GenerateOverloadCall(function);
else if (function.IsOperator)
GenerateOperator(function, default(QualifiedType));
else
GenerateInternalFunctionCall(function);

Expand Down Expand Up @@ -2650,24 +2657,24 @@ private string GetVirtualCallDelegate(Method method)
return delegateId;
}

private void GenerateOperator(Method method, QualifiedType returnType)
private void GenerateOperator(Function function, QualifiedType returnType)
{
if (method.SynthKind == FunctionSynthKind.ComplementOperator)
if (function.SynthKind == FunctionSynthKind.ComplementOperator)
{
if (method.Kind == CXXMethodKind.Conversion)
if (function is Method method && method.Kind == CXXMethodKind.Conversion)
{
// To avoid ambiguity when having the multiple inheritance pass enabled
var paramType = method.Parameters[0].Type.SkipPointerRefs().Desugar();
var paramType = function.Parameters[0].Type.SkipPointerRefs().Desugar();
paramType = (paramType.GetPointee() ?? paramType).Desugar();
Class paramClass;
Class @interface = null;
if (paramType.TryGetClass(out paramClass))
@interface = paramClass.GetInterface();

var paramName = string.Format("{0}{1}",
method.Parameters[0].Type.IsPrimitiveTypeConvertibleToRef() ?
function.Parameters[0].Type.IsPrimitiveTypeConvertibleToRef() ?
"ref *" : string.Empty,
method.Parameters[0].Name);
function.Parameters[0].Name);
var printedType = method.ConversionType.Visit(TypePrinter);
if (@interface != null)
{
Expand All @@ -2679,30 +2686,45 @@ private void GenerateOperator(Method method, QualifiedType returnType)
}
else
{
var @operator = Operators.GetOperatorOverloadPair(method.OperatorKind);
var @operator = Operators.GetOperatorOverloadPair(function.OperatorKind);

WriteLine("return !({0} {1} {2});", method.Parameters[0].Name,
@operator, method.Parameters[1].Name);
// handle operators for comparison which return int instead of bool
Type retType = function.OriginalReturnType.Type.Desugar();
bool regular = retType.IsPrimitiveType(PrimitiveType.Bool);
if (regular)
{
WriteLine($@"return !({function.Parameters[0].Name} {
@operator} {function.Parameters[1].Name});");
}
else
{
WriteLine($@"return global::System.Convert.ToInt32(({
function.Parameters[0].Name} {@operator} {
function.Parameters[1].Name}) == 0);");
}
}
return;
}

if (method.OperatorKind == CXXOperatorKind.EqualEqual ||
method.OperatorKind == CXXOperatorKind.ExclaimEqual)
if (function.OperatorKind == CXXOperatorKind.EqualEqual ||
function.OperatorKind == CXXOperatorKind.ExclaimEqual)
{
WriteLine("bool {0}Null = ReferenceEquals({0}, null);",
method.Parameters[0].Name);
function.Parameters[0].Name);
WriteLine("bool {0}Null = ReferenceEquals({0}, null);",
method.Parameters[1].Name);
function.Parameters[1].Name);
WriteLine("if ({0}Null || {1}Null)",
method.Parameters[0].Name, method.Parameters[1].Name);
WriteLineIndent("return {0}{1}Null && {2}Null{3};",
method.OperatorKind == CXXOperatorKind.EqualEqual ? string.Empty : "!(",
method.Parameters[0].Name, method.Parameters[1].Name,
method.OperatorKind == CXXOperatorKind.EqualEqual ? string.Empty : ")");
function.Parameters[0].Name, function.Parameters[1].Name);
Type retType = function.OriginalReturnType.Type.Desugar();
bool regular = retType.IsPrimitiveType(PrimitiveType.Bool);
WriteLineIndent($@"return {(regular ? string.Empty : "global::System.Convert.ToInt32(")}{
(function.OperatorKind == CXXOperatorKind.EqualEqual ? string.Empty : "!(")}{
function.Parameters[0].Name}Null && {function.Parameters[1].Name}Null{
(function.OperatorKind == CXXOperatorKind.EqualEqual ? string.Empty : ")")}{
(regular ? string.Empty : ")")};");
}

GenerateInternalFunctionCall(method, returnType: returnType);
GenerateInternalFunctionCall(function, returnType: returnType);
}

private void GenerateClassConstructor(Method method, Class @class)
Expand Down
117 changes: 74 additions & 43 deletions src/Generator/Passes/CheckOperatorsOverloads.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Linq;
using System.Collections.Generic;
using System.Linq;
using CppSharp.AST;
using CppSharp.AST.Extensions;
using CppSharp.Generators;
Expand Down Expand Up @@ -65,6 +66,15 @@ private void CheckInvalidOperators(Class @class)
else
CreateOperator(@class, @operator);
}

foreach (var @operator in @class.Functions.Where(
f => f.IsGenerated && f.IsOperator &&
!IsValidOperatorOverload(f) && !f.IsExplicitlyGenerated))
{
Diagnostics.Debug("Invalid operator overload {0}::{1}",
@class.OriginalName, @operator.OperatorKind);
@operator.ExplicitlyIgnore();
}
}

private static void CreateOperator(Class @class, Method @operator)
Expand Down Expand Up @@ -128,64 +138,85 @@ private void CreateIndexer(Class @class, Method @operator)
@operator.GenerationKind = GenerationKind.Internal;
}

private static void HandleMissingOperatorOverloadPair(Class @class, CXXOperatorKind op1,
CXXOperatorKind op2)
private static void HandleMissingOperatorOverloadPair(Class @class,
CXXOperatorKind op1, CXXOperatorKind op2)
{
foreach (var op in @class.Operators.Where(
List<Method> methods = HandleMissingOperatorOverloadPair(
@class, @class.Operators, op1, op2);
foreach (Method @operator in methods)
{
int index = @class.Methods.IndexOf(
(Method) @operator.OriginalFunction);
@class.Methods.Insert(index, @operator);
}

List<Function> functions = HandleMissingOperatorOverloadPair(
@class, @class.Functions, op1, op2);
foreach (Method @operator in functions)
{
int index = @class.Declarations.IndexOf(
@operator.OriginalFunction);
@class.Methods.Insert(index, @operator);
}
}

private static List<T> HandleMissingOperatorOverloadPair<T>(Class @class,
IEnumerable<T> functions, CXXOperatorKind op1,
CXXOperatorKind op2) where T : Function, new()
{
List<T> fs = new List<T>();
foreach (var op in functions.Where(
o => o.OperatorKind == op1 || o.OperatorKind == op2).ToList())
{
int index;
var missingKind = CheckMissingOperatorOverloadPair(@class, out index, op1, op2,
op.Parameters.First().Type, op.Parameters.Last().Type);
var missingKind = CheckMissingOperatorOverloadPair(functions,
op1, op2, op.Parameters.First().Type, op.Parameters.Last().Type);

if (missingKind == CXXOperatorKind.None || !op.IsGenerated)
continue;

var method = new Method()
{
Name = Operators.GetOperatorIdentifier(missingKind),
Namespace = @class,
SynthKind = FunctionSynthKind.ComplementOperator,
Kind = CXXMethodKind.Operator,
OperatorKind = missingKind,
ReturnType = op.ReturnType
};

method.Parameters.AddRange(op.Parameters.Select(
p => new Parameter(p) { Namespace = method }));

@class.Methods.Insert(index, method);
var function = new T()
{
Name = Operators.GetOperatorIdentifier(missingKind),
Namespace = @class,
SynthKind = FunctionSynthKind.ComplementOperator,
OperatorKind = missingKind,
ReturnType = op.ReturnType,
OriginalFunction = op
};

var method = function as Method;
if (method != null)
method.Kind = CXXMethodKind.Operator;

function.Parameters.AddRange(op.Parameters.Select(
p => new Parameter(p) { Namespace = function }));

fs.Add(function);
}
return fs;
}

static CXXOperatorKind CheckMissingOperatorOverloadPair(Class @class, out int index,
CXXOperatorKind op1, CXXOperatorKind op2, Type typeLeft, Type typeRight)

private static CXXOperatorKind CheckMissingOperatorOverloadPair(
IEnumerable<Function> functions,
CXXOperatorKind op1, CXXOperatorKind op2,
Type typeLeft, Type typeRight)
{
var first = @class.Operators.FirstOrDefault(o => o.IsGenerated && o.OperatorKind == op1 &&
o.Parameters.First().Type.Equals(typeLeft) && o.Parameters.Last().Type.Equals(typeRight));
var second = @class.Operators.FirstOrDefault(o => o.IsGenerated && o.OperatorKind == op2 &&
o.Parameters.First().Type.Equals(typeLeft) && o.Parameters.Last().Type.Equals(typeRight));
var first = functions.FirstOrDefault(
o => o.IsGenerated && o.OperatorKind == op1 &&
o.Parameters.First().Type.Equals(typeLeft) &&
o.Parameters.Last().Type.Equals(typeRight));
var second = functions.FirstOrDefault(
o => o.IsGenerated && o.OperatorKind == op2 &&
o.Parameters.First().Type.Equals(typeLeft) &&
o.Parameters.Last().Type.Equals(typeRight));

var hasFirst = first != null;
var hasSecond = second != null;

if (hasFirst && !hasSecond)
{
index = @class.Methods.IndexOf(first);
return op2;
}

if (hasSecond && !hasFirst)
{
index = @class.Methods.IndexOf(second);
return op1;
}

index = 0;
return CXXOperatorKind.None;
return hasFirst && !hasSecond ? op2 : hasSecond && !hasFirst ? op1 : CXXOperatorKind.None;
}

private bool IsValidOperatorOverload(Method @operator)
private bool IsValidOperatorOverload(Function @operator)
{
// These follow the order described in MSDN (Overloadable Operators).

Expand Down
Loading

0 comments on commit f6f52ac

Please sign in to comment.