Skip to content

[WIP] [2.0] A maths library for Silk.NET #190

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 19 commits into from
Closed
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
9 changes: 9 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,21 @@ insert_final_newline=false
indent_style=space
indent_size=4

[*.cs]
# Microsoft .NET properties
csharp_new_line_before_members_in_object_initializers=false
csharp_preferred_modifier_order=public, private, protected, internal, new, abstract, virtual, sealed, override, static, readonly, extern, unsafe, volatile, async:suggestion
csharp_style_var_elsewhere=true:hint
csharp_style_var_for_built_in_types=true:hint
csharp_style_var_when_type_is_apparent=true:hint
csharp_style_expression_bodied_methods = when_on_single_line:hint
csharp_style_expression_bodied_constructors = when_on_single_line:hint
csharp_style_expression_bodied_operators = when_on_single_line:hint
csharp_style_expression_bodied_properties = true:suggestion
csharp_style_expression_bodied_indexers = true:suggestion
csharp_style_expression_bodied_accessors = true:suggestion
csharp_style_expression_bodied_lambdas = true:silent
csharp_style_expression_bodied_local_functions = when_on_single_line:hint
dotnet_style_predefined_type_for_locals_parameters_members=true:hint
dotnet_style_predefined_type_for_member_access=true:hint
dotnet_style_qualification_for_event=false:warning
Expand Down
7 changes: 7 additions & 0 deletions .github/codecov.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
coverage:
range: "85...100"
status:
project:
Maths:
paths:
- src/Maths
17 changes: 17 additions & 0 deletions Silk.NET.sln
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Silk.NET.Input.Extensions",
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Silk.NET.Windowing.Extensions.Veldrid", "src\Windowing\Extensions\Silk.NET.Windowing.Extensions.Veldrid\Silk.NET.Windowing.Extensions.Veldrid.csproj", "{F5D5B4B4-58B7-48D9-881B-DD6A4001793E}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Maths", "Maths", "{2A735960-513E-44D8-A39D-4D17DB3D201F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Silk.NET.Maths", "src\Maths\Silk.NET.Maths\Silk.NET.Maths.csproj", "{D7F331FB-8609-4C6B-9DA6-CAF251DD1321}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FramebufferResized", "src\Lab\FramebufferResized\FramebufferResized.csproj", "{7AF3C6CA-64FE-43F3-BD7B-C57C83AFAB79}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "OpenXR", "OpenXR", "{ABD1AF6D-D9D1-4157-A1FF-AC98A054DA92}"
Expand Down Expand Up @@ -1653,6 +1657,18 @@ Global
{F5D5B4B4-58B7-48D9-881B-DD6A4001793E}.Release|x64.Build.0 = Release|Any CPU
{F5D5B4B4-58B7-48D9-881B-DD6A4001793E}.Release|x86.ActiveCfg = Release|Any CPU
{F5D5B4B4-58B7-48D9-881B-DD6A4001793E}.Release|x86.Build.0 = Release|Any CPU
{D7F331FB-8609-4C6B-9DA6-CAF251DD1321}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D7F331FB-8609-4C6B-9DA6-CAF251DD1321}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D7F331FB-8609-4C6B-9DA6-CAF251DD1321}.Debug|x64.ActiveCfg = Debug|Any CPU
{D7F331FB-8609-4C6B-9DA6-CAF251DD1321}.Debug|x64.Build.0 = Debug|Any CPU
{D7F331FB-8609-4C6B-9DA6-CAF251DD1321}.Debug|x86.ActiveCfg = Debug|Any CPU
{D7F331FB-8609-4C6B-9DA6-CAF251DD1321}.Debug|x86.Build.0 = Debug|Any CPU
{D7F331FB-8609-4C6B-9DA6-CAF251DD1321}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D7F331FB-8609-4C6B-9DA6-CAF251DD1321}.Release|Any CPU.Build.0 = Release|Any CPU
{D7F331FB-8609-4C6B-9DA6-CAF251DD1321}.Release|x64.ActiveCfg = Release|Any CPU
{D7F331FB-8609-4C6B-9DA6-CAF251DD1321}.Release|x64.Build.0 = Release|Any CPU
{D7F331FB-8609-4C6B-9DA6-CAF251DD1321}.Release|x86.ActiveCfg = Release|Any CPU
{D7F331FB-8609-4C6B-9DA6-CAF251DD1321}.Release|x86.Build.0 = Release|Any CPU
{7AF3C6CA-64FE-43F3-BD7B-C57C83AFAB79}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7AF3C6CA-64FE-43F3-BD7B-C57C83AFAB79}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7AF3C6CA-64FE-43F3-BD7B-C57C83AFAB79}.Debug|x64.ActiveCfg = Debug|Any CPU
Expand Down Expand Up @@ -1929,6 +1945,7 @@ Global
{8D84B804-168F-4EAA-BC09-F55A35A29887} = {FA9D1C95-5585-4DEC-B226-1447A486C376}
{8DCB2EB4-D0DE-4EF9-ACB3-332055D594CB} = {8D84B804-168F-4EAA-BC09-F55A35A29887}
{F5D5B4B4-58B7-48D9-881B-DD6A4001793E} = {3501BAD6-406A-49BC-BE0E-5A49A3AAAE6A}
{D7F331FB-8609-4C6B-9DA6-CAF251DD1321} = {2A735960-513E-44D8-A39D-4D17DB3D201F}
{7AF3C6CA-64FE-43F3-BD7B-C57C83AFAB79} = {DFA0E841-33E5-4533-AF00-964E21A141B8}
{B6017708-8E8C-4230-95AD-2D06237D68D4} = {ABD1AF6D-D9D1-4157-A1FF-AC98A054DA92}
{90471225-AC23-424E-B62E-F6EC4C6ECAC0} = {ABD1AF6D-D9D1-4157-A1FF-AC98A054DA92}
Expand Down
4 changes: 4 additions & 0 deletions azure-pipelines-cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ jobs:
inputs:
version: $(dotnetCoreVersion)
includePreviewVersions: true
- script: dotnet restore
displayName: 'Restore'
- script: dotnet test --configuration $(buildConfiguration)
displayName: 'Build/Test'
- script: dotnet pack --configuration $(buildConfiguration)
displayName: 'Build/Pack'
- script: dotnet nuget push **/Silk.NET.*.nupkg -s https://api.nuget.org/v3/index.json -k $(NUGET_API_KEY) -n true --skip-duplicate true
Expand Down
22 changes: 22 additions & 0 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,28 @@ jobs:
inputs:
includePreviewVersions: true
version: $(dotnetCoreVersion)

# Silk.NET.Maths Tests
- script: dotnet run --project ./src/Maths/Silk.NET.Maths.Tests/Silk.NET.Maths.Tests.fsproj --configuration Release -- --nunit-summary TestResults.xml
displayName: 'Run Tests and Export NUnit'
- task: PublishTestResults@2
condition: succeededOrFailed()
displayName: 'Publish Maths Tests'
inputs:
testRunner: NUnit
testResultsFiles: 'TestResults.xml'
- script: dotnet test ./src/Maths/Silk.NET.Maths.Tests/Silk.NET.Maths.Tests.fsproj --configuration Release /p:AltCover=true /p:AltCoverCobertura="cobertura.xml" -- --nunit-summary TestResults.xml
displayName: 'Collect Coverage'
condition: succeededOrFailed()
- task: PublishCodeCoverageResults@1
condition: succeededOrFailed()
inputs:
codeCoverageTool: 'cobertura'
summaryFileLocation: ./src/Maths/Silk.NET.Maths.Tests/cobertura.xml
- script: bash <(curl -s https://codecov.io/bash)
displayName: 'Upload to codecov.io'
condition: succeededOrFailed()

- script: dotnet pack --configuration $(buildConfiguration) --version-suffix build$(Build.BuildId)
displayName: 'Build/Pack'
- publish: build/output_packages
Expand Down
1 change: 1 addition & 0 deletions build/docs.gl
Submodule docs.gl added at f97bd0
12 changes: 12 additions & 0 deletions src/Maths/ConvertHelper/ConvertHelper.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Superpower" Version="2.3.0" />
</ItemGroup>

</Project>
89 changes: 89 additions & 0 deletions src/Maths/ConvertHelper/Parser.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// This file is part of Silk.NET.
//
// You may modify and distribute Silk.NET under the terms
// of the MIT license. See the LICENSE file for details.

using Superpower;
using Superpower.Parsers;

namespace ConvertHelper
{
internal class ArithmeticExpressionParser
{
private static readonly TokenListParser<ArithmeticExpressionToken, ExpressionType> Add = Operator
(ArithmeticExpressionToken.Plus, ExpressionType.Add);

private static readonly TokenListParser<ArithmeticExpressionToken, ExpressionType> Subtract = Operator
(ArithmeticExpressionToken.Minus, ExpressionType.Subtract);

private static readonly TokenListParser<ArithmeticExpressionToken, ExpressionType> Multiply = Operator
(ArithmeticExpressionToken.Times, ExpressionType.Multiply);

private static readonly TokenListParser<ArithmeticExpressionToken, ExpressionType> Divide = Operator
(ArithmeticExpressionToken.Divide, ExpressionType.Divide);

private static readonly TokenListParser<ArithmeticExpressionToken, ExpressionType> Comma = Operator
(ArithmeticExpressionToken.Comma, ExpressionType.Comma);

private static readonly TokenListParser<ArithmeticExpressionToken, string> Variable = Token.EqualTo
(ArithmeticExpressionToken.None)
.Apply(Character.LetterOrDigit.Or(Character.EqualTo('.')).AtLeastOnce())
.Select(n => new string(n))
.Named("variable");

private static readonly TokenListParser<ArithmeticExpressionToken, string> Constant = Token.EqualTo
(ArithmeticExpressionToken.Number)
.Apply(Numerics.Decimal)
.Select(n => $"Scalar.As<T>({n.ToString()})")
.Named("constant")
.Or(Variable);

private static readonly TokenListParser<ArithmeticExpressionToken, string> Factor =
(from lparen in Token.EqualTo
(ArithmeticExpressionToken.LParen)
from expr in Parse.Ref(() => Expr)
from rparen in Token.EqualTo(ArithmeticExpressionToken.RParen)
select $"({expr})").Or(Constant);

private static readonly TokenListParser<ArithmeticExpressionToken, string> Operand = (from sign in Token.EqualTo
(ArithmeticExpressionToken.Minus)
from factor in Factor
select $"Scalar.Negate<T>({factor})").Or(Factor)
.Named("expression");

private static readonly TokenListParser<ArithmeticExpressionToken, string> Term = Parse.Chain
(Multiply.Or(Divide), Operand, AddParenthese);

private static readonly TokenListParser<ArithmeticExpressionToken, string> Expr = Parse.Chain
(Add.Or(Subtract), Term, AddParenthese);

private static readonly TokenListParser<ArithmeticExpressionToken, string> Exprs = Parse.Chain
(Comma, Expr, AddParenthese);

public static readonly TokenListParser<ArithmeticExpressionToken, string> Transform = Exprs.AtEnd();

private static TokenListParser<ArithmeticExpressionToken, ExpressionType> Operator
(ArithmeticExpressionToken op, ExpressionType opType)
=> Token.EqualTo(op).Value(opType);

private static string AddParenthese(ExpressionType type, string left, string right)
=> type switch
{
ExpressionType.Add => $"Scalar.Add<T>({left}, {right})",
ExpressionType.Subtract => $"Scalar.Subtract<T>({left}, {right})",
ExpressionType.Multiply => $"Scalar.Multiply<T>({left}, {right})",
ExpressionType.Divide => $"Scalar.Divide<T>({left}, {right})",
ExpressionType.Comma => $"({left}), ({right})",
_ => $"Scalar.???<T>({left}, {right})"
};

private enum ExpressionType
{
Add,
Subtract,
Multiply,
Divide,
Comma
}
}
}
54 changes: 54 additions & 0 deletions src/Maths/ConvertHelper/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// This file is part of Silk.NET.
//
// You may modify and distribute Silk.NET under the terms
// of the MIT license. See the LICENSE file for details.

using System;
using System.Text;

namespace ConvertHelper
{
internal class Program
{
private static void Main(string[] args)
{
Console.WriteLine
("Hey! I'll try to convert any normal C# expression to a Silk.NET.Maths.Scalar using expression!");
Console.WriteLine("Simply paste your code below, and I'll translate line-by-line. I'll try to keep `,`");
Console.WriteLine("A single empty line will start translation");

var tokenizer = new ArithmeticExpressionTokenizer();

while (true)
{
var sb = new StringBuilder();
while (true)
{
var i = Console.ReadLine();
if (string.IsNullOrWhiteSpace(i))
{
break;
}

sb.AppendLine(i);
}

var result = tokenizer.TryTokenize(sb.ToString());
if (!result.HasValue)
{
Console.WriteLine(result.FormatErrorMessageFragment());
continue;
}

var transform = ArithmeticExpressionParser.Transform(result.Value);
if (!transform.HasValue)
{
Console.WriteLine(result.FormatErrorMessageFragment());
continue;
}

Console.WriteLine(transform.Value);
}
}
}
}
34 changes: 34 additions & 0 deletions src/Maths/ConvertHelper/Token.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// This file is part of Silk.NET.
//
// You may modify and distribute Silk.NET under the terms
// of the MIT license. See the LICENSE file for details.

using Superpower.Display;

namespace ConvertHelper
{
internal enum ArithmeticExpressionToken
{
None,

Number,

[Token(Category = "operator", Example = "+")]
Plus,

[Token(Category = "operator", Example = "-")]
Minus,

[Token(Category = "operator", Example = "*")]
Times,

[Token(Category = "operator", Example = "-")]
Divide,

[Token(Example = "(")] LParen,

[Token(Example = ")")] RParen,

[Token(Example = ",")] Comma
}
}
78 changes: 78 additions & 0 deletions src/Maths/ConvertHelper/Tokenizer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// This file is part of Silk.NET.
//
// You may modify and distribute Silk.NET under the terms
// of the MIT license. See the LICENSE file for details.

using System.Collections.Generic;
using Superpower;
using Superpower.Model;
using Superpower.Parsers;

namespace ConvertHelper
{
internal class ArithmeticExpressionTokenizer : Tokenizer<ArithmeticExpressionToken>
{
private readonly Dictionary<char, ArithmeticExpressionToken> _operators =
new Dictionary<char, ArithmeticExpressionToken>
{
['+'] = ArithmeticExpressionToken.Plus,
['-'] = ArithmeticExpressionToken.Minus,
['*'] = ArithmeticExpressionToken.Times,
['/'] = ArithmeticExpressionToken.Divide,
['('] = ArithmeticExpressionToken.LParen,
[')'] = ArithmeticExpressionToken.RParen,
[','] = ArithmeticExpressionToken.Comma
};

protected override IEnumerable<Result<ArithmeticExpressionToken>> Tokenize(TextSpan span)
{
var next = SkipWhiteSpace(span);
if (!next.HasValue)
{
yield break;
}

do
{
ArithmeticExpressionToken charToken;

var ch = next.Value;
if (ch >= '0' && ch <= '9')
{
var integer = Numerics.Integer(next.Location);
next = integer.Remainder.ConsumeChar();
yield return Result.Value(ArithmeticExpressionToken.Number, integer.Location, integer.Remainder);
}
else if (_operators.TryGetValue(ch, out charToken))
{
yield return Result.Value(charToken, next.Location, next.Remainder);
next = next.Remainder.ConsumeChar();
}
else
{
var start = next.Location;
while (true)
{
var c = next.Location.ConsumeChar();
if (!c.HasValue || _operators.TryGetValue(c.Value, out _))
{
break;
}

if (char.IsWhiteSpace(c.Value))
{
break;
}

next = c.Remainder.ConsumeChar();
}

var location = start.Until(next.Location);
yield return Result.Value(ArithmeticExpressionToken.None, location, next.Location);
}

next = SkipWhiteSpace(next.Location);
} while (next.HasValue);
}
}
}
Loading