Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using System.Linq;
using System.Runtime.InteropServices;
using Computator.NET.Core.Autocompletion.DataSource;
using Computator.NET.Core.Properties;
using NUnit.Framework;

namespace Computator.NET.Core.Tests.AutocompletionTests
{
[TestFixture, NonParallelizable]
public class ByRefCompletionTests
{
private static class Signatures
{
public static void Produce(out long value) { value = 1; }
public static void Change(ref long value) { value++; }
public static void Observe(in long value) { }
public static void OutputBuffer([Out] byte[] value) { }
}

[TestCase("Produce", "out")]
[TestCase("Change", "ref")]
[TestCase("Observe", "in")]
public void ArgumentModifiersAreRetainedInInsertionAndTypedCaption(string method, string modifier)
{
var settings = Settings.Default;
var oldReturn = settings.ShowReturnTypeInScripting;
var oldParameters = settings.ShowParametersTypeInScripting;
try
{
settings.ShowReturnTypeInScripting = settings.ShowParametersTypeInScripting = true;
var item = new AutocompleteReflectionSource().GetFunctionsNamesWithDescription(typeof(Signatures))
.Single(candidate => candidate.Text.StartsWith(method + "("));
item.IsScripting = true;
NUnit.Framework.Assert.That(item.GetTextForReplace(), Is.EqualTo(method + "(" + modifier + " value)"));
NUnit.Framework.Assert.That(item.MenuText, Is.EqualTo("void " + method + "(" + modifier + " integer value)"));
}
finally
{
settings.ShowReturnTypeInScripting = oldReturn;
settings.ShowParametersTypeInScripting = oldParameters;
}
}

[Test]
public void InteropOutputAttributeOnAValueParameterDoesNotInsertAnOutKeyword()
{
var item = new AutocompleteReflectionSource().GetFunctionsNamesWithDescription(typeof(Signatures))
.Single(candidate => candidate.Text.StartsWith("OutputBuffer("));
NUnit.Framework.Assert.That(item.GetTextForReplace(), Is.EqualTo("OutputBuffer(value)"));
}
}
}
158 changes: 158 additions & 0 deletions Computator.NET.Core.Tests/EuclidEvaluationTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Computator.NET.Core.Autocompletion;
using Computator.NET.Core.Autocompletion.DataSource;
using Computator.NET.Core.Evaluation;
using Computator.NET.Core.Properties;
using Computator.NET.DataTypes;
using NUnit.Framework;

namespace Computator.NET.Core.Tests
{
[TestFixture(false)]
[TestFixture(true)]
[NonParallelizable]
public class EuclidEvaluationTests
{
private readonly bool _legacy;
public EuclidEvaluationTests(bool legacy) { _legacy = legacy; }

private sealed class LegacyEvaluator : ExpressionsEvaluator
{ protected override bool UsePrecompiledBuiltins => false; }
private sealed class LegacyScriptEvaluator : ScriptEvaluator
{ protected override bool UsePrecompiledBuiltins => false; }

[TestCase("Euclid.GreatestCommonDivisor(-84,30)", 6)]
[TestCase("Euclid.LeastCommonMultiple(12,18)", 36)]
[TestCase("Euclid.Modulus(-7,3)", 2)]
[TestCase("Euclid.Remainder(-7,3)", -1)]
[TestCase("Euclid.PowerOfTwo((integer)40)", 1099511627776)]
[TestCase("Euclid.IsPerfectSquare(144) ? 1 : 0", 1)]
[TestCase("((real)Euclid.GreatestCommonDivisor(System.Numerics.BigInteger.One<<80,System.Numerics.BigInteger.Zero))", 1.2089258196146292E+24)]
public void DesktopExpressionsUseTheSameQualifiedLibrary(string source, double expected)
{
ExpressionsEvaluator evaluator = _legacy ? new LegacyEvaluator() : new ExpressionsEvaluator();
Func<double, double> function = evaluator.Evaluate(source, "", CalculationsMode.Real);
NUnit.Framework.Assert.That(function(0), Is.EqualTo(expected));
}

[Test]
public void DesktopScriptRetainsExactIntegersAndOutArguments()
{
const string source = """
integer u, v;
integer divisor = Euclid.ExtendedGreatestCommonDivisor(240,46,out u,out v);
write(divisor); write(":["); write(240*u+46*v); write("]:");
write(Euclid.GreatestCommonDivisor(9007199254740993,0));
""";
ScriptEvaluator evaluator = _legacy ? new LegacyScriptEvaluator() : new ScriptEvaluator();
var output = new List<string>();
evaluator.Evaluate(source, "").Evaluate(output.Add);
NUnit.Framework.Assert.That(string.Concat(output), Is.EqualTo("2:[2]:9007199254740993"));
}

[Test]
public void ExistingUnqualifiedGcdAliasesKeepTheirLegacySurface()
{
ExpressionsEvaluator evaluator = _legacy ? new LegacyEvaluator() : new ExpressionsEvaluator();
Func<double, double> function = evaluator.Evaluate("gcd(12,18)+nwd(12,18)+lcm(4,6)+nww(4,6)", "", CalculationsMode.Real);
NUnit.Framework.Assert.That(function(0), Is.EqualTo(36));
}
}

[TestFixture, NonParallelizable]
public class EuclidCompletionTests
{
[TestCase(false)]
[TestCase(true)]
public void TypedCaptionsDistinguishEveryEuclidOverload(bool scripting)
{
var settings = Settings.Default;
var oldReturnExpression = settings.ShowReturnTypeInExpression;
var oldParametersExpression = settings.ShowParametersTypeInExpression;
var oldReturnScripting = settings.ShowReturnTypeInScripting;
var oldParametersScripting = settings.ShowParametersTypeInScripting;
try
{
settings.ShowReturnTypeInExpression = settings.ShowReturnTypeInScripting = true;
settings.ShowParametersTypeInExpression = settings.ShowParametersTypeInScripting = true;
var items = new AutocompleteReflectionSource().GetFunctionsNamesWithDescription(
typeof(MathNet.Numerics.Euclid), fullName: true);
items.ForEach(item => item.IsScripting = scripting);
NUnit.Framework.Assert.That(items.Count, Is.EqualTo(37));
NUnit.Framework.Assert.That(items.Select(item => item.MenuText), Is.Unique);
NUnit.Framework.Assert.That(items.Select(item => item.MenuText), Does.Contain(
"int Euclid.PowerOfTwo(int exponent)"));
NUnit.Framework.Assert.That(items.Select(item => item.MenuText), Does.Contain(
"integer Euclid.PowerOfTwo(integer exponent)"));
NUnit.Framework.Assert.That(items.Select(item => item.MenuText), Does.Contain(
"integer Euclid.GreatestCommonDivisor(IList<integer> integers)"));
NUnit.Framework.Assert.That(items.Select(item => item.MenuText), Does.Contain(
"BigInteger Euclid.GreatestCommonDivisor(IList<BigInteger> integers)"));
}
finally
{
settings.ShowReturnTypeInExpression = oldReturnExpression;
settings.ShowParametersTypeInExpression = oldParametersExpression;
settings.ShowReturnTypeInScripting = oldReturnScripting;
settings.ShowParametersTypeInScripting = oldParametersScripting;
}
}

[TestCase(false)]
[TestCase(true)]
public void ExtendedGcdCompletionInsertsExecutableOutputArguments(bool arbitraryPrecision)
{
var settings = Settings.Default;
var oldReturn = settings.ShowReturnTypeInScripting;
var oldParameters = settings.ShowParametersTypeInScripting;
try
{
settings.ShowReturnTypeInScripting = settings.ShowParametersTypeInScripting = true;
var items = new AutocompleteReflectionSource().GetFunctionsNamesWithDescription(
typeof(MathNet.Numerics.Euclid), fullName: true);
items.ForEach(item => item.IsScripting = true);
var type = arbitraryPrecision ? "BigInteger" : "integer";
var completion = items.Single(item => item.Text.StartsWith("Euclid.ExtendedGreatestCommonDivisor(")
&& item.MenuText.StartsWith(type + " "));

NUnit.Framework.Assert.That(completion.GetTextForReplace(),
Is.EqualTo("Euclid.ExtendedGreatestCommonDivisor(a,b,out x,out y)"));
NUnit.Framework.Assert.That(completion.MenuText,
Is.EqualTo(type + " Euclid.ExtendedGreatestCommonDivisor(" + type + " a, " + type +
" b, out " + type + " x, out " + type + " y)"));

var declarationType = arbitraryPrecision ? "System.Numerics.BigInteger" : "integer";
var script = declarationType + " a=240,b=46,x,y; var d=" + completion.GetTextForReplace() +
"; write(d); write(\":\"); write(a*x+b*y);";
var output = new List<string>();
new ScriptEvaluator().Evaluate(script, "").Evaluate(output.Add);
NUnit.Framework.Assert.That(string.Concat(output), Is.EqualTo("2:2"));
}
finally
{
settings.ShowReturnTypeInScripting = oldReturn;
settings.ShowParametersTypeInScripting = oldParameters;
}
}

[Test]
public void EveryPinnedEuclidOverloadHasQualifiedCompletionAndAuthoredHelp()
{
var reference = new FunctionsDetailsFileSource();
var provider = new AutocompleteProvider(new AutocompleteReflectionSource(), reference);
var items = provider.ScriptingAutocompleteItems.Where(item => item.Details.Type == "Euclid").ToArray();
NUnit.Framework.Assert.That(items.Length, Is.EqualTo(37));
NUnit.Framework.Assert.That(items.Select(item => item.Text.Split('(')[0]).Distinct().Count(), Is.EqualTo(12));
foreach (var item in items)
{
NUnit.Framework.Assert.That(item.Text, Does.StartWith("Euclid."));
NUnit.Framework.Assert.That(item.Details, Is.SameAs(reference.Details[item.Text]), item.Text);
NUnit.Framework.Assert.That(item.Details.Category, Is.EqualTo("Integer arithmetic"), item.Text);
}
NUnit.Framework.Assert.That(provider.ExpressionAutocompleteItems.Select(item => item.Text),
Does.Contain("Euclid.GreatestCommonDivisor(a,b)"));
}
}
}
3 changes: 2 additions & 1 deletion Computator.NET.Core/Autocompletion/AutocompleteProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ private AutocompleteItem[] GetAutocompleteItemsForExpressions(bool removeAdvance
{
var items = _autocompleteReflectionSource.GetFunctionsNamesWithDescription(typeof(ElementaryFunctions));

items.AddRange(_autocompleteReflectionSource.GetFunctionsNamesWithDescription(typeof(MathNet.Numerics.Euclid), false, true));
items.AddRange(_autocompleteReflectionSource.GetFunctionsNamesWithDescription(typeof(FunctionRoot), false, true));
items.AddRange(_autocompleteReflectionSource.GetFunctionsNamesWithDescription(typeof(Integral), false, true));
items.AddRange(_autocompleteReflectionSource.GetFunctionsNamesWithDescription(typeof(Derivative), false, true));
Expand Down Expand Up @@ -164,4 +165,4 @@ private AutocompleteItem[] GetAutocompleteItemsForScripting()
public IEnumerable<AutocompleteItem> ExpressionAutocompleteItems { get; }
public IEnumerable<AutocompleteItem> ScriptingAutocompleteItems { get; }
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,16 @@ public List<AutocompleteItem>
if (fullName)
fullNameExtension = m.ReflectedType.Name + ".";

if (m.IsGenericMethod || m.IsGenericMethodDefinition)
if (m.DeclaringType == typeof(MathNet.Numerics.Euclid))
{
// Euclid exposes both Int32 and Int64 overloads. Calling
// both "integer" makes distinct operations identical in
// completion, including PowerOfTwo's different bounds.
items.Add(new AutocompleteItem(fullNameExtension + m.Name,
MakeAddition(m, false), MakeAddition(m, true),
EuclidTypeName(m.ReturnType), GetImageIndexFromType(m.ReturnType.Name)));
}
else if (m.IsGenericMethod || m.IsGenericMethodDefinition)
{
var sigWithTypes = m.GetSignature();
var nameAndAdditionWithTypes = sigWithTypes.Split('(');
Expand Down Expand Up @@ -123,17 +132,29 @@ private static string MakeAddition(MethodInfo m, bool withType)
{
//var parameterName = parameters[i].Name + "1, " + parameters[i].Name + "2, ...";
addition += withType
? TypeNameToAlias(parameters[i].ParameterType.Name.Replace("[]", "")) + " " +
? (m.DeclaringType == typeof(MathNet.Numerics.Euclid)
? EuclidTypeName(parameters[i].ParameterType.GetElementType())
: TypeNameToAlias(parameters[i].ParameterType.Name.Replace("[]", ""))) + " " +
parameters[i].Name + j +
", "
: parameters[i].Name + j + ",";
}
addition += " ...";
}
else
{
var parameter = parameters[i];
var parameterType = parameter.ParameterType;
var modifier = parameterType.IsByRef
? (parameter.IsOut ? "out " : parameter.IsIn ? "in " : "ref ") : "";
if (parameterType.IsByRef)
parameterType = parameterType.GetElementType();

addition += withType
? TypeNameToAlias(parameters[i].ParameterType.Name) + " " + parameters[i].Name + ", "
: parameters[i].Name + ",";
? modifier + (m.DeclaringType == typeof(MathNet.Numerics.Euclid)
? EuclidTypeName(parameterType) : TypeNameToAlias(parameterType.Name)) + " " + parameter.Name + ", "
: modifier + parameter.Name + ",";
}
}


Expand All @@ -148,6 +169,18 @@ private static string MakeAddition(MethodInfo m, bool withType)
return addition;
}

private static string EuclidTypeName(Type type)
{
if (type == typeof(int))
return "int";
if (type.IsArray)
return EuclidTypeName(type.GetElementType()) + "[]";
if (type.IsGenericType)
return type.Name.Split('`')[0] + "<" +
string.Join(", ", type.GetGenericArguments().Select(EuclidTypeName)) + ">";
return TypeNameToAlias(type.Name);
}

private static void AddMetadata(MemberInfo p, Type type,
List<AutocompleteItem> items)
{
Expand Down Expand Up @@ -264,4 +297,4 @@ private static int GetImageIndexFromType(string typeName)
return imageIndex;
}
}
}
}
3 changes: 2 additions & 1 deletion Computator.NET.Core/Compilation/TSLCompiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ public class TslCompiler : ITslCompiler
using real = System.Double;
using complex = System.Numerics.Complex;
using natural = System.UInt64;
using integer = System.Int64;";
using integer = System.Int64;
using Euclid = MathNet.Numerics.Euclid;";

public static readonly string[] Keywords =
{
Expand Down
Loading
Loading