Skip to content

Commit

Permalink
Now successfully creating a single precision and double precision ver…
Browse files Browse the repository at this point in the history
…sion of the library with implicit casting.
  • Loading branch information
cdiggins committed Jun 5, 2024
1 parent 63640d1 commit 44dd8ab
Show file tree
Hide file tree
Showing 18 changed files with 11,190 additions and 5,067 deletions.
5 changes: 4 additions & 1 deletion Plato.CSharpWriter/CSharpWriterExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ public static class CSharpWriterExtensions
public static SymbolWriterCSharp ToCSharp(this Compiler.Compilation compilation, DirectoryPath outputFolder)
{
var writer = new SymbolWriterCSharp(compilation, outputFolder);
return writer.WriteAll();
writer.WriteAll("Ara3D.SinglePrecision.cs","float");
writer.WriteAll("Ara3D.DoublePrecision.cs", "double");
//writer.WriteAnalyses();
return writer;
}
}
}
183 changes: 183 additions & 0 deletions Plato.CSharpWriter/Intrinsics.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
public static class Intrinsics
{
public static Number Cos(Angle x) => ({{float}})System.Math.Cos(x.Value);
public static Number Sin(Angle x) => ({{float}})System.Math.Sin(x.Value);
public static Number Tan(Angle x) => ({{float}})System.Math.Tan(x.Value);

public static Number Ln(Number x) => ({{float}})System.Math.Log(x.Value);
public static Number Exp(Number x) => ({{float}})System.Math.Exp(x.Value);

public static Angle Acos(Number x) => new Angle(({{float}})System.Math.Acos(x));
public static Angle Asin(Number x) => new Angle(({{float}})System.Math.Asin(x));
public static Angle Atan(Number x) => new Angle(({{float}})System.Math.Atan(x));

public static Number Pow(Number x, Number y) => ({{float}})System.Math.Pow(x, y);
public static Number Log(Number x, Number y) => ({{float}})System.Math.Log(x, y);
public static Number NaturalLog(Number x) => ({{float}})System.Math.Log(x);
public static Number NaturalPower(Number x) => ({{float}})System.Math.Pow(x, System.Math.E);

public static Number Add(Number x, Number y) => x.Value + y.Value;
public static Number Subtract(Number x, Number y) => x.Value - y.Value;
public static Number Divide(Number x, Number y) => x.Value / y.Value;
public static Number Multiply(Number x, Number y) => x.Value * y.Value;
public static Number Modulo(Number x, Number y) => x.Value % y.Value;
public static Number Negative(Number x) => -x.Value;

public static Integer Add(Integer x, Integer y) => x.Value + y.Value;
public static Integer Subtract(Integer x, Integer y) => x.Value - y.Value;
public static Integer Divide(Integer x, Integer y) => x.Value / y.Value;
public static Integer Multiply(Integer x, Integer y) => x.Value * y.Value;
public static Integer Modulo(Integer x, Integer y) => x.Value % y.Value;
public static Integer Negative(Integer x) => -x.Value;

public static Array<Integer> Range(Integer x) => new RangeStruct(x);

public static Boolean And(Boolean x, Boolean y) => x.Value && y.Value;
public static Boolean Or(Boolean x, Boolean y) => x.Value || y.Value;
public static Boolean Not(Boolean x) => !x.Value;

public static Number ToNumber(Integer x) => x.Value;

public static string MakeString(string typeName, Array<String> fieldNames, Array<Dynamic> fieldValues)
{
var sb = new System.Text.StringBuilder();
sb.Append($"{{ _type=\"{typeName}\" ");
for (var i = 0; i < fieldNames.Count; i++)
sb.Append(", ").Append(fieldNames.At(i).Value).Append(" = ").Append(fieldValues.At(i).Value);
sb.Append(" }");
return sb.ToString();
}

public static int CombineHashCodes(params object[] objects)
{
if (objects.Length == 0) return 0;
var r = objects[0].GetHashCode();
for (var i = 1; i < objects.Length; ++i)
r = CombineHashCodes(r, objects[i].GetHashCode());
return r;
}

public static (T0, T1) Tuple2<T0, T1>(this T0 item0, T1 item1)
=> (item0, item1);

public static (T0, T1, T2) Tuple3<T0, T1, T2>(this T0 item0, T1 item1, T2 item2)
=> (item0, item1, item2);

public static (T0, T1, T2, T3) Tuple4<T0, T1, T2, T3>(this T0 item0, T1 item1, T2 item2, T3 item3)
=> (item0, item1, item2, item3);

public static Array<T> MakeArray<T>(params T[] args)
=> new PrimitiveArray<T>(args);

public static int CombineHashCodes(int h1, int h2)
{
unchecked
{
var rol5 = ((uint)h1 << 5) | ((uint)h1 >> 27);
return ((int)rol5 + h1) ^ h2;
}
}

public static Array<T1> Map<T0, T1>(this Array<T0> self, System.Func<T0, T1> f)
=> new MappedArray<T0, T1>(self, f);

public static TAcc Reduce<T, TAcc>(this Array<T> self, TAcc init, System.Func<TAcc, T, TAcc> f)
{
for (var i = 0; i < self.Count; ++i)
init = f(init, self.At(i));
return init;
}
}

public readonly struct PrimitiveArray<T> : Array<T>
{
private readonly T[] _data;
public Integer Count => _data.Length;
public T At(Integer n) => _data[n];
public PrimitiveArray(T[] data) => _data = data;
public static Array<T> Default = new PrimitiveArray<T>(System.Array.Empty<T>());
}

public readonly struct MappedArray<T0, T1> : Array<T1>
{
public System.Func<T0, T1> MapFunc { get; }
public Array<T0> Original { get; }
public Integer Count => Original.Count;
public T1 At(Integer n) => MapFunc(Original.At(n));

public MappedArray(Array<T0> input, System.Func<T0, T1> f)
{
Original = input;
MapFunc = f;
}
}

public readonly struct RangeStruct : Array<Integer>
{
public Integer Count { get; }
public Integer At(Integer n) => n;
public RangeStruct(Integer n) => Count = n;
}

public readonly partial struct String
{
public Integer Compare(String other) => Value.CompareTo(other.Value);
public Character At(Integer n) => Value[n];
public Integer Count => Value.Length;
}

public readonly partial struct Boolean
{
public static bool operator true(Boolean b) => b.Value;
public static bool operator false(Boolean b) => !b.Value;
}

public readonly partial struct Number
{
public Number Zero => 0;
public Number One => 1;
public Number MinValue => {{float}}.MinValue;
public Number MaxValue => {{float}}.MaxValue;
public Integer Compare(Number other) => Value.CompareTo(other.Value);
public Number Unlerp(Number a, Number b) => ({{float}})(this - a) / ({{float}})(b - a);
}

public readonly partial struct Integer
{
public Integer Zero => 0;
public Integer One => 1;
public Integer MinValue => int.MinValue;
public Integer MaxValue => int.MaxValue;
public Number Magnitude => Value;
public static implicit operator Number(Integer self) => self.Value;
public Integer Compare(Integer other) => Value.CompareTo(other.Value);
public Integer Lerp(Integer b, Number t) => (int)(Value * (1.0 - t) + b * t);
public Number Unlerp(Integer a, Integer b) => ({{float}})(this - a) / ({{float}})(b - a);
}

public readonly partial struct Character
{
public Character Zero => (char)0;
public Character One => (char)1;
public Character MinValue => char.MinValue;
public Character MaxValue => char.MaxValue;
public Number Magnitude => Value;
public static implicit operator Number(Character self) => self.Value;
public Integer Compare(Character other) => Value.CompareTo(other.Value);
public Number Unlerp(Character a, Character b) => ({{float}})(this - a) / ({{float}})(b - a);
public Boolean Equals(Character x) => Value.Equals(x.Value);
public Boolean NotEquals(Character x) => !Equals(x);
}

public readonly partial struct Dynamic
{
public readonly object Value;
public Dynamic WithValue(object value) => new Dynamic(value);
public Dynamic(object value) => (Value) = (value);
public static Dynamic Default = new Dynamic();
public static Dynamic New(object value) => new Dynamic(value);
public String TypeName => "Dynamic";
public Array<String> FieldNames => Intrinsics.MakeArray<String>("Value");
public Array<Dynamic> FieldValues => Intrinsics.MakeArray<Dynamic>(new Dynamic(Value));
public T As<T>() => (T)Value;
}
47 changes: 36 additions & 11 deletions Plato.CSharpWriter/SymbolWriterCSharp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ public class SymbolWriterCSharp : CodeBuilder<SymbolWriterCSharp>
public const bool EmitInterfaces = true;
public const bool EmitStructsInsteadOfClasses = true;
public const bool UseSelfConstraints = true;
public string FloatType;
public string Namespace;
public string OtherPrecisionFloatType;
public string OtherPrecisionNamespace;

public Compiler.Compilation Compilation { get; }
public string CurrentType { get; set; }
Expand Down Expand Up @@ -64,7 +68,7 @@ public SymbolWriterCSharp WriteStaticOrLambdaBody(Symbol sym)

public static Dictionary<string, string> PrimitiveTypes = new Dictionary<string, string>()
{
{ "Number", "double" },
{ "Number", "{{float}}" },
{ "Boolean", "bool" },
{ "Integer", "int" },
{ "Character", "char" },
Expand All @@ -79,16 +83,35 @@ public SymbolWriterCSharp(Compiler.Compilation compilation, DirectoryPath output
OutputFolder = outputFolder;
}


public SymbolWriterCSharp WriteAll()
public SymbolWriterCSharp WriteAll(string fileName, string floatType)
{
FloatType = floatType;
Namespace = floatType == "float"
? "Ara3D.SinglePrecision"
: floatType == "double"
? "Ara3D.DoublePrecision"
: throw new NotImplementedException("Only 'float' and 'double' are supported");
OtherPrecisionFloatType = floatType == "float" ? "double" : "float";
OtherPrecisionNamespace = floatType == "float" ? "Ara3D.DoublePrecision" : "Ara3D.SinglePrecision";
StartNewFile(fileName);
WriteLine($"namespace {Namespace}");
WriteStartBlock();
WriteConceptInterfaces();
WriteTypeImplementations();
WriteLibraryMethods();
WriteAnalyses();
WriteIntrinsics();
WriteEndBlock();
sb.Replace("{{float}}", floatType);
return this;
}

public SymbolWriterCSharp WriteIntrinsics()
{
var intrinsicsFile = PathUtil.GetCallerSourceFolder().RelativeFile("Intrinsics.txt");
var intrinsicsContent = intrinsicsFile.ReadAllText();
return WriteLine(intrinsicsContent);
}

public void WriteAnalysis(FunctionInstance fa, string indent = " ")
{
var parameters = fa.Implementation.Parameters.Select(p => $"{p.Type} {p.Name}").JoinStringsWithComma();
Expand Down Expand Up @@ -423,9 +446,6 @@ public SymbolWriterCSharp WriteFunction(FunctionInstance f, ConcreteType t, bool

public SymbolWriterCSharp WriteLibraryMethods()
{
StartNewFile(OutputFolder.RelativeFile("Library.cs"));
WriteLine("using System;");

WriteLine($"public static class Constants");
WriteStartBlock();
foreach (var f in Compilation.Libraries.AllConstants())
Expand Down Expand Up @@ -465,7 +485,6 @@ public SymbolWriterCSharp WriteLibraryMethods()

public SymbolWriterCSharp WriteConceptInterfaces()
{
StartNewFile(OutputFolder.RelativeFile("Concepts.cs"));
if (!EmitInterfaces)
WriteLine("/*");
foreach (var c in Compilation.AllTypeAndLibraryDefinitions)
Expand Down Expand Up @@ -539,8 +558,6 @@ public SymbolWriterCSharp WriteConceptInterface(TypeDef type)

public SymbolWriterCSharp WriteTypeImplementations()
{
StartNewFile(OutputFolder.RelativeFile("Types.cs"));
WriteLine("using System;");
foreach (var c in Compilation.ConcreteTypes)
if (!IgnoredTypes.Contains(c.Type.Name))
WriteTypeImplementation(c);
Expand Down Expand Up @@ -636,7 +653,15 @@ public SymbolWriterCSharp WriteTypeImplementation(ConcreteType concreteType)

// Static factory function (New)
WriteLine($"public static {name} New({parametersStr}) => new {name}({parameterNamesStr});");


// Precision changes
if (t.TypeParameters.Count == 0 && fieldNames.Count != 0 && !fieldTypes.Any(ft => ft.Contains("<")))
{
var changeFields = fieldNames.Select(f => $"{f}.ChangePrecision()").JoinStringsWithComma();
WriteLine($"public {OtherPrecisionNamespace}.{t.Name} ChangePrecision() => ({changeFields});");
WriteLine($"public static implicit operator {OtherPrecisionNamespace}.{t.Name}({t.Name} self) => self.ChangePrecision();");
}

// Implicit operators
if (fieldNames.Count > 1)
{
Expand Down
Loading

0 comments on commit 44dd8ab

Please sign in to comment.