From ff044ef65090e1661e63936bc710aaa6b028beaf Mon Sep 17 00:00:00 2001 From: kev Date: Tue, 23 Jan 2024 16:44:49 +0000 Subject: [PATCH 01/29] Added Program --- CLVMDotNet/src/CLVM/Program.cs | 194 +++++++++++++++++++++++++++++++-- CLVMDotNet/src/CLVM/SExp.cs | 4 +- 2 files changed, 189 insertions(+), 9 deletions(-) diff --git a/CLVMDotNet/src/CLVM/Program.cs b/CLVMDotNet/src/CLVM/Program.cs index a44434d..b0e3fff 100644 --- a/CLVMDotNet/src/CLVM/Program.cs +++ b/CLVMDotNet/src/CLVM/Program.cs @@ -1,13 +1,193 @@ +using System.Numerics; + namespace CLVMDotNet.CLVM; -public class Program +public static class Program { - //RunProgram - //TraversePath - //SwapOp - //ConsOp - //ApplyOp - //to_pre_eval_op + public static Tuple RunProgram(SExp program, SExp args, BigInteger? maxCost = null) + { + var prog = SExp.To(program); + Stack, BigInteger>> opStack = new Stack, BigInteger>>(); + + var valueStack = new Stack(); + valueStack.Push(args); + opStack.Push(stack => EvalOp(opStack, valueStack)); + + BigInteger cost = 0; + + while (opStack.Count != 0) + { + var f = opStack.Pop(); + cost += f(valueStack); + if (maxCost.HasValue && cost > maxCost) + { + throw new EvalError("cost exceeded", SExp.To(maxCost)); + } + } + + return Tuple.Create(new BigInteger(1), prog); + } + + public static (BigInteger, SExp) TraversePath(SExp sexp, SExp env) + { + BigInteger cost = Costs.PATH_LOOKUP_BASE_COST; + cost += Costs.PATH_LOOKUP_COST_PER_LEG; + + if (sexp.Nullp()) + { + return (cost, SExp.NULL); + } + + byte[] b = sexp.Atom; + + int endByteCursor = 0; + while (endByteCursor < b.Length && b[endByteCursor] == 0) + { + endByteCursor++; + } + + cost += endByteCursor * Costs.PATH_LOOKUP_COST_PER_ZERO_BYTE; + if (endByteCursor == b.Length) + { + return (cost, SExp.NULL); + } + + // Create a bitmask for the most significant *set* bit + // in the last non-zero byte + byte endBitmask = MSBMask(b[endByteCursor]); + int byteCursor = b.Length - 1; + byte bitmask = 0x01; + while (byteCursor > endByteCursor || bitmask < endBitmask) + { + if (env.Pair == null) + { + throw new EvalError("path into atom", env); + } + + if ((b[byteCursor] & bitmask) != 0) + { + env = env.Rest(); + } + else + { + env = env.First(); + } + + cost += Costs.PATH_LOOKUP_COST_PER_LEG; + bitmask <<= 1; + + if (bitmask == 0x100) + { + byteCursor--; + bitmask = 0x01; + } + } + return (cost, env); + } + + public static BigInteger EvalOp(Stack, BigInteger>> opStack, Stack valueStack) + { + var pair = valueStack.Pop(); + var sexp = pair.First(); + var args = pair.Rest(); + + if (sexp.Pair == null) + { + // sexp is an atom + var (cost, r) = TraversePath(sexp, args); + valueStack.Push(r); + return cost; + } + + var op = sexp.First(); + if (op.Pair != null) + { + var operatorPair = op.AsPair(); //newOperator,must_be_nil + var (newOperator, mustBeNil) = (operatorPair.Item1, operatorPair.Item2); + if (newOperator.Pair != null || mustBeNil.Atom != Array.Empty()) + { + throw new EvalError("in ((X)...) syntax X must be lone atom", sexp); + } + + var newOperandList = sexp.Rest(); + valueStack.Append(newOperator); + valueStack.Append(newOperandList); + opStack.Push(stack => ApplyOp(opStack, valueStack)); + return Costs.APPLY_COST; + } + + var op1 = op.AsAtom(); + var operand_list = sexp.Rest(); + if (op1 == Operator.QuoteAtom) + { + valueStack.Append(operand_list); + return Costs.QUOTE_COST; + } + + opStack.Append(stack => ConsOp(opStack, valueStack)); + valueStack.Append(op); + while (operand_list.Nullp()) + { + var ex = operand_list.First(); + valueStack.Append(ex.Cons(args)); + opStack.Push(stack => ConsOp(opStack, valueStack)); + opStack.Push(stack => EvalOp(opStack, valueStack)); + opStack.Push(stack => SwapOp(opStack, valueStack)); + operand_list = operand_list.Rest(); + valueStack.Append(SExp.NULL); + } + return BigInteger.Parse("1"); + } + + public static BigInteger ApplyOp(Stack, BigInteger>> opStack, Stack valueStack) + { + var operandList = valueStack.Pop(); + var oper = valueStack.Pop(); + + if (oper.Pair != null) + { + throw new EvalError("internal error", oper); + } + + var op = oper.AsAtom(); + + if (op == Operator.ApplyAtom) + { + if (operandList.ListLength() != 2) + { + throw new EvalError("apply requires exactly 2 parameters", operandList); + } + + var newProgram = operandList.First(); + var newArgs = operandList.Rest().First(); + + valueStack.Push(newProgram.Cons(newArgs)); + opStack.Push(stack => EvalOp(opStack, valueStack)); + return Costs.APPLY_COST; // Assuming APPLY_COST is defined elsewhere. + } + + var result = Operator.ApplyOperator(op, operandList); + valueStack.Push(result.Item2); + return result.Item1; + } + + public static BigInteger SwapOp(Stack, BigInteger>> opStack, Stack valueStack) + { + var v2 = valueStack.Pop(); + var v1 = valueStack.Pop(); + valueStack.Push(v2); + valueStack.Push(v1); + return 0; + } + + public static int ConsOp(Stack, BigInteger>> opStack, Stack valueStack) + { + var v1 = valueStack.Pop(); + var v2 = valueStack.Pop(); + var result = v1.Cons(v2); + valueStack.Push(result); + return 0; + } public static byte MSBMask(byte inputByte) { diff --git a/CLVMDotNet/src/CLVM/SExp.cs b/CLVMDotNet/src/CLVM/SExp.cs index 1013c92..51077e8 100644 --- a/CLVMDotNet/src/CLVM/SExp.cs +++ b/CLVMDotNet/src/CLVM/SExp.cs @@ -59,7 +59,7 @@ public SExp Cons(SExp right) return To(new Tuple(this, right)); } - public dynamic First() + public SExp First() { if (Pair is (_,_)) { @@ -69,7 +69,7 @@ public dynamic First() throw new EvalError("first of non-cons", this); } - public dynamic Rest() + public SExp Rest() { if (Pair is (_,_)) { From a45a089fcb10056084863908c186067d64431b20 Mon Sep 17 00:00:00 2001 From: kev Date: Tue, 23 Jan 2024 23:55:46 +0000 Subject: [PATCH 02/29] Added stub methods for IRReader to validate methods do what they are supposed to do --- CLVMDotNet/src/CLVM/Operators.cs | 7 ++- CLVMDotNet/src/CLVM/Program.cs | 2 +- CLVMDotNet/src/Tools/IR/Clvmc.cs | 22 +++++++--- CLVMDotNet/src/Tools/IR/IRReader.cs | 15 +++---- .../CLVM/Operators/ApplyOperatorTests.cs | 6 +-- .../tests/Tools/Clvmc/CompileCLVMText.cs | 1 + CLVMDotNet/tests/Tools/IRReader/IrNewTests.cs | 26 +++++++++++ .../tests/Tools/IRReader/ReadIRTests.cs | 43 ++++++++++++++++++- .../tests/Tools/IRReader/TokenStreamTests.cs | 2 + .../tests/Tools/IRReader/TokenizeConsTests.cs | 9 ++++ .../tests/Tools/IRReader/TokenizeHexTests.cs | 8 ++++ .../tests/Tools/IRReader/TokenizeIntTests.cs | 33 ++++++++++++++ .../Tools/IRReader/TokenizeQuotesTests.cs | 6 +++ .../tests/Tools/IRReader/TokenizeSexpTests.cs | 22 ++++++++++ 14 files changed, 178 insertions(+), 24 deletions(-) create mode 100644 CLVMDotNet/tests/Tools/IRReader/IrNewTests.cs create mode 100644 CLVMDotNet/tests/Tools/IRReader/TokenizeConsTests.cs create mode 100644 CLVMDotNet/tests/Tools/IRReader/TokenizeHexTests.cs create mode 100644 CLVMDotNet/tests/Tools/IRReader/TokenizeIntTests.cs create mode 100644 CLVMDotNet/tests/Tools/IRReader/TokenizeQuotesTests.cs create mode 100644 CLVMDotNet/tests/Tools/IRReader/TokenizeSexpTests.cs diff --git a/CLVMDotNet/src/CLVM/Operators.cs b/CLVMDotNet/src/CLVM/Operators.cs index 84518ab..e2d3117 100644 --- a/CLVMDotNet/src/CLVM/Operators.cs +++ b/CLVMDotNet/src/CLVM/Operators.cs @@ -105,7 +105,6 @@ public static Tuple ApplyOperator(byte[] atom, SExp args) else if (atom.AsSpan().SequenceEqual(new byte[] { 0x0F })) { //. - //return MoreOps.OpSubtract(args); throw new ArgumentException("Op Not Implemented!"); } @@ -124,12 +123,12 @@ public static Tuple ApplyOperator(byte[] atom, SExp args) else if (atom.AsSpan().SequenceEqual(new byte[] { 0x12 })) { //* - return MoreOps.OpDiv(args); + return MoreOps.OpMultiply(args); } else if (atom.AsSpan().SequenceEqual(new byte[] { 0x13 })) { - // divide - return MoreOps.OpMultiply(args); + //divide + return MoreOps.OpDiv(args); } else if (atom.AsSpan().SequenceEqual(new byte[] { 0x14 })) { diff --git a/CLVMDotNet/src/CLVM/Program.cs b/CLVMDotNet/src/CLVM/Program.cs index b0e3fff..063e770 100644 --- a/CLVMDotNet/src/CLVM/Program.cs +++ b/CLVMDotNet/src/CLVM/Program.cs @@ -163,7 +163,7 @@ public static BigInteger ApplyOp(Stack, BigInteger>> opStack, S valueStack.Push(newProgram.Cons(newArgs)); opStack.Push(stack => EvalOp(opStack, valueStack)); - return Costs.APPLY_COST; // Assuming APPLY_COST is defined elsewhere. + return Costs.APPLY_COST; } var result = Operator.ApplyOperator(op, operandList); diff --git a/CLVMDotNet/src/Tools/IR/Clvmc.cs b/CLVMDotNet/src/Tools/IR/Clvmc.cs index 4dde14a..5f123ab 100644 --- a/CLVMDotNet/src/Tools/IR/Clvmc.cs +++ b/CLVMDotNet/src/Tools/IR/Clvmc.cs @@ -7,14 +7,26 @@ public class Clvmc public static SExp CompileCLVMText(string text, string[] searchPaths) { var ir_src = IRReader.ReadIR(text); - var assembled_sexp = BinUtils.AssembleFromIR(ir_src); - var input_sexp = SExp.To((assembled_sexp, Array.Empty())); - //run_program_for_search_paths - //run_program - return null; + + + + + + + + + + + + + var assembled_sexp = BinUtils.AssembleFromIR(ir_src); + var input_sexp = SExp.To((assembled_sexp, Array.Empty())); + + var result = Program.RunProgram(null, input_sexp); + return result.Item2; } public static void CompileCLVM(string inputPath, string outputPath, string[] searchPaths) diff --git a/CLVMDotNet/src/Tools/IR/IRReader.cs b/CLVMDotNet/src/Tools/IR/IRReader.cs index 89cae78..d909d86 100644 --- a/CLVMDotNet/src/Tools/IR/IRReader.cs +++ b/CLVMDotNet/src/Tools/IR/IRReader.cs @@ -117,13 +117,6 @@ public static (string, int) NextConsToken(IEnumerator<(string, int)> stream) int offset = -1; stream.MoveNext(); - // foreach (var item in stream.) - // { - // token = item.Item1; - // offset = item.Item2; - // break; - // } - token = stream.Current.Item1; offset = stream.Current.Item2; @@ -185,7 +178,8 @@ public static (string, int) NextConsToken(IEnumerator<(string, int)> stream) var (t, o) = NextConsToken(stream); token = t; offset = o; - return TokenizeCons(token, offset, stream); + var cons = TokenizeCons(token, offset, stream); + return cons; } var result = TokenizeInt(token, offset); @@ -295,7 +289,7 @@ public static bool TryParseHex(string token, out byte[] result) } char c = s[offset]; - if (c == '(' || c == ')') + if ("(.)".Contains(c)) { yield return (c.ToString(), offset); offset++; @@ -340,7 +334,8 @@ public static SExp ReadIR(string s) { var item = enumerator.Current; var ts = TokenizeSexp(item.token, item.offset, enumerator); - return SExp.To(ts); + var sexp = SExp.To(ts); + return sexp; } throw new ArgumentException("unexpected end of stream"); diff --git a/CLVMDotNet/tests/CLVM/Operators/ApplyOperatorTests.cs b/CLVMDotNet/tests/CLVM/Operators/ApplyOperatorTests.cs index d95f7cb..59b1a95 100644 --- a/CLVMDotNet/tests/CLVM/Operators/ApplyOperatorTests.cs +++ b/CLVMDotNet/tests/CLVM/Operators/ApplyOperatorTests.cs @@ -45,7 +45,7 @@ public void OpDivide() // Arrange // Act - var result = x.Operator.ApplyOperator(new byte[] { 0x12 }, x.SExp.To(new List { 10, 2 })); + var result = x.Operator.ApplyOperator(new byte[] { 0x13}, x.SExp.To(new List { 10, 2 })); // Assert } @@ -58,7 +58,7 @@ public void OpDivideThrowsExceptionIfDividingByZero() // Act var errorMessage = Assert.Throws(() => - x.Operator.ApplyOperator(new byte[] { 0x12 }, x.SExp.To(new List { 10, 0 })) + x.Operator.ApplyOperator(new byte[] { 0x13 }, x.SExp.To(new List { 10, 0 })) ); // Assert @@ -73,7 +73,7 @@ public void OpDivideThrowsExceptionWithNegativeOperand1() // Act var errorMessage = Assert.Throws(() => - x.Operator.ApplyOperator(new byte[] { 0x12 }, x.SExp.To(new List { -1, 5 })) + x.Operator.ApplyOperator(new byte[] { 0x13 }, x.SExp.To(new List { -1, 5 })) ); // Assert diff --git a/CLVMDotNet/tests/Tools/Clvmc/CompileCLVMText.cs b/CLVMDotNet/tests/Tools/Clvmc/CompileCLVMText.cs index 706f7c8..9a28048 100644 --- a/CLVMDotNet/tests/Tools/Clvmc/CompileCLVMText.cs +++ b/CLVMDotNet/tests/Tools/Clvmc/CompileCLVMText.cs @@ -8,5 +8,6 @@ public class CompileCLVMText public void RunBasicProgram() { var result = CLVMDotNet.Tools.IR.Clvmc.CompileCLVMText("(/ 10 2)", Array.Empty()); + var rs = result; } } \ No newline at end of file diff --git a/CLVMDotNet/tests/Tools/IRReader/IrNewTests.cs b/CLVMDotNet/tests/Tools/IRReader/IrNewTests.cs new file mode 100644 index 0000000..6e0f03f --- /dev/null +++ b/CLVMDotNet/tests/Tools/IRReader/IrNewTests.cs @@ -0,0 +1,26 @@ +using Xunit; +using x = CLVMDotNet.Tools.IR; + +namespace CLVMDotNet.Tests.Tools.IRReader +{ + + public class IrNewTests + { + [Fact] + public void IrNewWithValidIntegerAndOffset() + { + // arrange + + // act + var result = x.Utils.IrNew(x.IRType.INT, 100, 1); + + // assert + Assert.Null(result.Atom); + Assert.NotNull(result.Pair); + Assert.NotNull(result.Pair.Item1); + Assert.True(result.AsPair().Item1.AsPair().Item1.Atom.SequenceEqual(new byte[] { 73, 78, 84 })); //INT + Assert.True(result.AsPair().Item1.AsPair().Item2.Atom.SequenceEqual(new byte[] { 0x01 })); //1 (offset) + Assert.True(result.AsPair().Item2.Atom.SequenceEqual(new byte[] {0x64})); //100 + } + } +} \ No newline at end of file diff --git a/CLVMDotNet/tests/Tools/IRReader/ReadIRTests.cs b/CLVMDotNet/tests/Tools/IRReader/ReadIRTests.cs index 4104130..c4457bf 100644 --- a/CLVMDotNet/tests/Tools/IRReader/ReadIRTests.cs +++ b/CLVMDotNet/tests/Tools/IRReader/ReadIRTests.cs @@ -13,7 +13,7 @@ public void IRReader_ignores_comments() // Arrange var script_source = "(equal 7 (+ 5 ;foo bar\n 2))"; var expected_output = "(equal 7 (+ 5 2))"; - + // Act var t = x.IRReader.ReadIR(script_source); var s = x.IRReader.ReadIR(expected_output); @@ -24,5 +24,46 @@ public void IRReader_ignores_comments() //character offsets from source. Assert.False(areEqual); } + + [Fact] + public void ReadIREmptyStringThrowsError() + { + // Arrange + + // Act + var errorMessage = + Assert.Throws(() => + x.IRReader.ReadIR("")); + + // Assert + Assert.Contains("unexpected end of stream", errorMessage.Message); + } + + [Fact(Skip = "Skipping for now!")] + public void ConsList() + { + // Arrange + string sexp_source = "foo"; + + // Act + var sexp = x.IRReader.ReadIR(sexp_source); + + // Assert + var s = sexp; + } + + [Fact (Skip= "Skipping for now!")] + + public void ConsList1() + { + // Arrange + string sexp_source = "(c (quote 100) (c (quote \"foo\") (quote ())))"; + + // Act + var sexp = x.IRReader.ReadIR(sexp_source); + + // Assert + var s = sexp; + } } } \ No newline at end of file diff --git a/CLVMDotNet/tests/Tools/IRReader/TokenStreamTests.cs b/CLVMDotNet/tests/Tools/IRReader/TokenStreamTests.cs index db38dfa..4aa972d 100644 --- a/CLVMDotNet/tests/Tools/IRReader/TokenStreamTests.cs +++ b/CLVMDotNet/tests/Tools/IRReader/TokenStreamTests.cs @@ -24,5 +24,7 @@ public void TokenStreamReader_matches_python_stream_length(string input, int len // Assert Assert.Equal(lengthOfStream, count); } + + } } \ No newline at end of file diff --git a/CLVMDotNet/tests/Tools/IRReader/TokenizeConsTests.cs b/CLVMDotNet/tests/Tools/IRReader/TokenizeConsTests.cs new file mode 100644 index 0000000..1deb06c --- /dev/null +++ b/CLVMDotNet/tests/Tools/IRReader/TokenizeConsTests.cs @@ -0,0 +1,9 @@ +using Xunit; +using x = CLVMDotNet.Tools.IR; + +namespace CLVMDotNet.Tests.Tools.IRReader; + +public class TokenizeConsTests +{ + +} \ No newline at end of file diff --git a/CLVMDotNet/tests/Tools/IRReader/TokenizeHexTests.cs b/CLVMDotNet/tests/Tools/IRReader/TokenizeHexTests.cs new file mode 100644 index 0000000..1f67016 --- /dev/null +++ b/CLVMDotNet/tests/Tools/IRReader/TokenizeHexTests.cs @@ -0,0 +1,8 @@ +using Xunit; +using x = CLVMDotNet.Tools.IR; +namespace CLVMDotNet.Tests.Tools.IRReader; + +public class TokenizeHexTests +{ + +} \ No newline at end of file diff --git a/CLVMDotNet/tests/Tools/IRReader/TokenizeIntTests.cs b/CLVMDotNet/tests/Tools/IRReader/TokenizeIntTests.cs new file mode 100644 index 0000000..c431968 --- /dev/null +++ b/CLVMDotNet/tests/Tools/IRReader/TokenizeIntTests.cs @@ -0,0 +1,33 @@ +using Xunit; +using x = CLVMDotNet.Tools.IR; + +namespace CLVMDotNet.Tests.Tools.IRReader; + +public class TokenizeIntTests +{ + [Fact] + public void TokenizeInt_returns_null_when_passing_none_int() + { + // Arrange + var noneNumber = "a"; + + // Act + var tokenized = x.IRReader.TokenizeInt(noneNumber, 0); + + // Assert + Assert.Null(tokenized); + } + + // [Fact] + // public void TokenizeInt_returns_null_when_passing_none_int() + // { + // // Arrange + // var noneNumber = "a"; + // + // // Act + // var tokenized = x.IRReader.TokenizeInt(noneNumber, 0); + // + // // Assert + // Assert.Null(tokenized); + // } +} \ No newline at end of file diff --git a/CLVMDotNet/tests/Tools/IRReader/TokenizeQuotesTests.cs b/CLVMDotNet/tests/Tools/IRReader/TokenizeQuotesTests.cs new file mode 100644 index 0000000..b3b70bf --- /dev/null +++ b/CLVMDotNet/tests/Tools/IRReader/TokenizeQuotesTests.cs @@ -0,0 +1,6 @@ +namespace CLVMDotNet.Tests.Tools.IRReader; + +public class TokenizeQuotesTests +{ + +} \ No newline at end of file diff --git a/CLVMDotNet/tests/Tools/IRReader/TokenizeSexpTests.cs b/CLVMDotNet/tests/Tools/IRReader/TokenizeSexpTests.cs new file mode 100644 index 0000000..cad63b3 --- /dev/null +++ b/CLVMDotNet/tests/Tools/IRReader/TokenizeSexpTests.cs @@ -0,0 +1,22 @@ +using Xunit; +using x = CLVMDotNet.Tools.IR; + +namespace CLVMDotNet.Tests.Tools.IRReader; + +public class TokenizeSexpTests +{ + [Fact] + public void TestTokenizeSexp() + { + // arrange + var stream = x.IRReader.TokenStream("(100 0x0100)"); + + // act + foreach (var item in stream) + { + + } + + // assert + } +} \ No newline at end of file From 3b68022e035f2a9947569fac4a66f63e60bdeaa8 Mon Sep 17 00:00:00 2001 From: kev Date: Wed, 24 Jan 2024 00:17:34 +0000 Subject: [PATCH 03/29] Added a json parser to make it easier to parse objects --- CLVMDotNet/tests/CLVMDotNet.Tests.csproj | 1 + CLVMDotNet/tests/Helpers/JSONHelpers.cs | 54 +++++++++++++++++++ .../tests/Tools/Clvmc/CompileCLVMText.cs | 7 +++ 3 files changed, 62 insertions(+) create mode 100644 CLVMDotNet/tests/Helpers/JSONHelpers.cs diff --git a/CLVMDotNet/tests/CLVMDotNet.Tests.csproj b/CLVMDotNet/tests/CLVMDotNet.Tests.csproj index 58ad867..c1a56fe 100644 --- a/CLVMDotNet/tests/CLVMDotNet.Tests.csproj +++ b/CLVMDotNet/tests/CLVMDotNet.Tests.csproj @@ -12,6 +12,7 @@ + runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/CLVMDotNet/tests/Helpers/JSONHelpers.cs b/CLVMDotNet/tests/Helpers/JSONHelpers.cs new file mode 100644 index 0000000..99fb269 --- /dev/null +++ b/CLVMDotNet/tests/Helpers/JSONHelpers.cs @@ -0,0 +1,54 @@ +using CLVMDotNet.CLVM; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Xunit; + +namespace CLVMDotNet.Tests.Helpers; + +public static class JSONHelpers +{ + public static string ConvertToJSON(this SExp sexp) + { + return JsonConvert.SerializeObject(sexp); + } + + public static async Task AssertExpectedJSONResult(this SExp sexp, Object expectObject) + { + var targetJObject = JObject.FromObject(expectObject); + var sourceJObject = JObject.FromObject(sexp); + + if (!JToken.DeepEquals(sourceJObject, targetJObject)) + { + //actual doesn't match expected properties, values + foreach (var targetProp in targetJObject.Properties()) + { + JProperty source = sourceJObject.Property(targetProp.Name); + if (source == null) + { + throw new Exception($"expceted property: {targetProp.Name} - {targetProp.Value} but not present"); + } + + if (!JToken.DeepEquals(source.Value, targetProp.Value)) + { + throw new Exception($"{targetProp.Name} value is {source.Value}, expected {targetProp.Value} but got { source.Value}"); + } + } + + //extra property on response + foreach (var sourceProp in sourceJObject.Properties()) + { + JProperty source = targetJObject.Property(sourceProp.Name); + if (source == null) + { + throw new Exception($"extra property on response : {sourceProp.Name} - {sourceProp.Value}"); + } + } + + } + else + { + Console.WriteLine("Objects are same"); + } + Assert.Equal(1, 1); + } +} \ No newline at end of file diff --git a/CLVMDotNet/tests/Tools/Clvmc/CompileCLVMText.cs b/CLVMDotNet/tests/Tools/Clvmc/CompileCLVMText.cs index 9a28048..afd69ed 100644 --- a/CLVMDotNet/tests/Tools/Clvmc/CompileCLVMText.cs +++ b/CLVMDotNet/tests/Tools/Clvmc/CompileCLVMText.cs @@ -1,3 +1,5 @@ +using CLVMDotNet.CLVM; +using CLVMDotNet.Tests.Helpers; using Xunit; namespace CLVMDotNet.Tests.Tools.Clvmc; @@ -8,6 +10,11 @@ public class CompileCLVMText public void RunBasicProgram() { var result = CLVMDotNet.Tools.IR.Clvmc.CompileCLVMText("(/ 10 2)", Array.Empty()); + + + var sexp = SExp.To(new List { "+", 1, 2 }); + var json = sexp.ConvertToJSON(); + var rs = result; } } \ No newline at end of file From c0e208cf74acf33cd3e74ceb1c34caf5a4069cf6 Mon Sep 17 00:00:00 2001 From: kev Date: Wed, 24 Jan 2024 11:21:24 +0000 Subject: [PATCH 04/29] Added TokenizeInt Tests --- CLVMDotNet/src/CLVMDotNet.csproj | 1 + CLVMDotNet/src/Extensions/SExpExtensions.cs | 14 +++++++ CLVMDotNet/src/Tools/IR/Clvmc.cs | 19 ++-------- CLVMDotNet/src/Tools/IR/IRReader.cs | 2 +- .../tests/Tools/Clvmc/CompileCLVMText.cs | 4 -- .../tests/Tools/IRReader/ReadIRTests.cs | 4 +- .../tests/Tools/IRReader/TokenStreamTests.cs | 3 +- .../tests/Tools/IRReader/TokenizeIntTests.cs | 37 +++++++++++++------ 8 files changed, 48 insertions(+), 36 deletions(-) create mode 100644 CLVMDotNet/src/Extensions/SExpExtensions.cs diff --git a/CLVMDotNet/src/CLVMDotNet.csproj b/CLVMDotNet/src/CLVMDotNet.csproj index e1adaf4..5d6d8dd 100644 --- a/CLVMDotNet/src/CLVMDotNet.csproj +++ b/CLVMDotNet/src/CLVMDotNet.csproj @@ -9,6 +9,7 @@ + diff --git a/CLVMDotNet/src/Extensions/SExpExtensions.cs b/CLVMDotNet/src/Extensions/SExpExtensions.cs new file mode 100644 index 0000000..8b2d739 --- /dev/null +++ b/CLVMDotNet/src/Extensions/SExpExtensions.cs @@ -0,0 +1,14 @@ +using CLVMDotNet.CLVM; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace CLVMDotNet.Extensions; + +public static class SExpExtensions +{ + public static string AsJSON(this SExp sexp) + { + var sourceJObject = JsonConvert.SerializeObject(sexp); + return sourceJObject; + } +} \ No newline at end of file diff --git a/CLVMDotNet/src/Tools/IR/Clvmc.cs b/CLVMDotNet/src/Tools/IR/Clvmc.cs index 5f123ab..5477bb2 100644 --- a/CLVMDotNet/src/Tools/IR/Clvmc.cs +++ b/CLVMDotNet/src/Tools/IR/Clvmc.cs @@ -1,4 +1,5 @@ using CLVMDotNet.CLVM; +using CLVMDotNet.Extensions; namespace CLVMDotNet.Tools.IR { @@ -7,24 +8,12 @@ public class Clvmc public static SExp CompileCLVMText(string text, string[] searchPaths) { var ir_src = IRReader.ReadIR(text); - - - - - - - - - - - - - - + + + var s = ir_src.AsJSON(); var assembled_sexp = BinUtils.AssembleFromIR(ir_src); var input_sexp = SExp.To((assembled_sexp, Array.Empty())); - var result = Program.RunProgram(null, input_sexp); return result.Item2; } diff --git a/CLVMDotNet/src/Tools/IR/IRReader.cs b/CLVMDotNet/src/Tools/IR/IRReader.cs index d909d86..f4a49fa 100644 --- a/CLVMDotNet/src/Tools/IR/IRReader.cs +++ b/CLVMDotNet/src/Tools/IR/IRReader.cs @@ -200,7 +200,7 @@ public static (string, int) NextConsToken(IEnumerator<(string, int)> stream) public static SExp? TokenizeInt(string token, int offset) { - if (int.TryParse(token, out int result)) + if (BigInteger.TryParse(token, out BigInteger result)) { return Utils.IrNew(IRType.INT, result, offset); } diff --git a/CLVMDotNet/tests/Tools/Clvmc/CompileCLVMText.cs b/CLVMDotNet/tests/Tools/Clvmc/CompileCLVMText.cs index afd69ed..6b49097 100644 --- a/CLVMDotNet/tests/Tools/Clvmc/CompileCLVMText.cs +++ b/CLVMDotNet/tests/Tools/Clvmc/CompileCLVMText.cs @@ -11,10 +11,6 @@ public void RunBasicProgram() { var result = CLVMDotNet.Tools.IR.Clvmc.CompileCLVMText("(/ 10 2)", Array.Empty()); - - var sexp = SExp.To(new List { "+", 1, 2 }); - var json = sexp.ConvertToJSON(); - var rs = result; } } \ No newline at end of file diff --git a/CLVMDotNet/tests/Tools/IRReader/ReadIRTests.cs b/CLVMDotNet/tests/Tools/IRReader/ReadIRTests.cs index c4457bf..8c5787f 100644 --- a/CLVMDotNet/tests/Tools/IRReader/ReadIRTests.cs +++ b/CLVMDotNet/tests/Tools/IRReader/ReadIRTests.cs @@ -52,12 +52,12 @@ public void ConsList() var s = sexp; } - [Fact (Skip= "Skipping for now!")] + [Fact] public void ConsList1() { // Arrange - string sexp_source = "(c (quote 100) (c (quote \"foo\") (quote ())))"; + string sexp_source = "(/ 10 2)"; // Act var sexp = x.IRReader.ReadIR(sexp_source); diff --git a/CLVMDotNet/tests/Tools/IRReader/TokenStreamTests.cs b/CLVMDotNet/tests/Tools/IRReader/TokenStreamTests.cs index 4aa972d..60df0f6 100644 --- a/CLVMDotNet/tests/Tools/IRReader/TokenStreamTests.cs +++ b/CLVMDotNet/tests/Tools/IRReader/TokenStreamTests.cs @@ -13,6 +13,7 @@ public class TokenStreamTests [InlineData("(equal 7 (+ 5 (+ 1 5)))", 13)] [InlineData("(- 5 4)", 5)] [InlineData("(- 5 (- 6 (- 5 (- 5 6))))", 17)] + [InlineData("(/ 10 2)", 5)] public void TokenStreamReader_matches_python_stream_length(string input, int lengthOfStream) { // Arrange @@ -24,7 +25,5 @@ public void TokenStreamReader_matches_python_stream_length(string input, int len // Assert Assert.Equal(lengthOfStream, count); } - - } } \ No newline at end of file diff --git a/CLVMDotNet/tests/Tools/IRReader/TokenizeIntTests.cs b/CLVMDotNet/tests/Tools/IRReader/TokenizeIntTests.cs index c431968..d473006 100644 --- a/CLVMDotNet/tests/Tools/IRReader/TokenizeIntTests.cs +++ b/CLVMDotNet/tests/Tools/IRReader/TokenizeIntTests.cs @@ -18,16 +18,29 @@ public void TokenizeInt_returns_null_when_passing_none_int() Assert.Null(tokenized); } - // [Fact] - // public void TokenizeInt_returns_null_when_passing_none_int() - // { - // // Arrange - // var noneNumber = "a"; - // - // // Act - // var tokenized = x.IRReader.TokenizeInt(noneNumber, 0); - // - // // Assert - // Assert.Null(tokenized); - // } + [Theory] + [InlineData("1", new byte[] { 0x01})] + [InlineData("256", new byte[] { 0x01, 0x00 })] + [InlineData("12345678910", new byte[] { 0x02, 0xdf, 0xdc, 0x1c, (byte)'>'})] + [InlineData("1234567891012345678910", new byte[] { 0x42, 0xed, 0x12, 0x3b, 0xda, 0xce, 0x08, 0x4c, (byte)'>' })] + public void TokenizeInt_Builds_CorrectObject(string number, byte[] expectedBytes) + { + // Arrange + + // Act + var tokenized = x.IRReader.TokenizeInt(number, 0); + + // Assert + Assert.Null(tokenized.Atom); + Assert.NotNull(tokenized.Pair); + Assert.Null(tokenized.AsPair().Item1.Atom); + Assert.NotNull(tokenized.AsPair().Item1); + Assert.NotNull(tokenized.AsPair().Item1.AsPair()); + + //INT as bytes + Assert.True(tokenized.AsPair().Item1.AsPair().Item1.Atom.SequenceEqual(new byte[] { 73, 78, 84})); // INT + + //NUMBER as bytes + Assert.True(tokenized.AsPair().Item2.Atom.SequenceEqual(expectedBytes)); // INT + } } \ No newline at end of file From 7c2b1b39f217be2dfad9dda22f58586ef9fcc1f9 Mon Sep 17 00:00:00 2001 From: kev Date: Wed, 24 Jan 2024 13:23:01 +0000 Subject: [PATCH 05/29] added TokenizeHex tests --- CLVMDotNet/src/Tools/IR/IRReader.cs | 4 +- .../tests/Tools/IRReader/TokenizeConsTests.cs | 44 +++++++++++++++ .../tests/Tools/IRReader/TokenizeHexTests.cs | 53 +++++++++++++++++++ 3 files changed, 99 insertions(+), 2 deletions(-) diff --git a/CLVMDotNet/src/Tools/IR/IRReader.cs b/CLVMDotNet/src/Tools/IR/IRReader.cs index f4a49fa..655aee6 100644 --- a/CLVMDotNet/src/Tools/IR/IRReader.cs +++ b/CLVMDotNet/src/Tools/IR/IRReader.cs @@ -128,7 +128,7 @@ public static (string, int) NextConsToken(IEnumerator<(string, int)> stream) return (token, offset); } - public static dynamic? TokenizeCons(string token, int offset, IEnumerator<(string, int)> stream) + public static SExp? TokenizeCons(string token, int offset, IEnumerator<(string, int)> stream) { if (token == ")") { @@ -224,7 +224,7 @@ public static (string, int) NextConsToken(IEnumerator<(string, int)> stream) } else { - throw new SyntaxException("invalid hex at " + offset + ": 0x" + token); + throw new SyntaxException($"invalid hex at {offset}:{token}"); } } diff --git a/CLVMDotNet/tests/Tools/IRReader/TokenizeConsTests.cs b/CLVMDotNet/tests/Tools/IRReader/TokenizeConsTests.cs index 1deb06c..d11829f 100644 --- a/CLVMDotNet/tests/Tools/IRReader/TokenizeConsTests.cs +++ b/CLVMDotNet/tests/Tools/IRReader/TokenizeConsTests.cs @@ -5,5 +5,49 @@ namespace CLVMDotNet.Tests.Tools.IRReader; public class TokenizeConsTests { + [Fact] + public void TokenizeCons_ClosingBracket() + { + // Arrange + var stream = x.IRReader.TokenStream("(+ 1 3)"); + + // Act + var tokenized = x.IRReader.TokenizeCons(")", 6, stream.GetEnumerator()); + + // Assert + Assert.Null(tokenized.Atom); + Assert.NotNull(tokenized.Pair); + Assert.NotNull(tokenized.AsPair().Item1); + Assert.Null(tokenized.AsPair().Item1.Atom); + Assert.NotNull(tokenized.AsPair().Item1.Pair); + Assert.NotNull(tokenized.AsPair().Item1.AsPair()); + Assert.True(tokenized.AsPair().Item1.AsPair().Item1.Atom.SequenceEqual(new byte[] {78, 85, 76, 76 })); + Assert.True(tokenized.AsPair().Item2.Atom.SequenceEqual(new byte []{ })); + } + // [Theory] + // [InlineData("1", new byte[] { 0x01})] + // [InlineData("256", new byte[] { 0x01, 0x00 })] + // [InlineData("12345678910", new byte[] { 0x02, 0xdf, 0xdc, 0x1c, (byte)'>'})] + // [InlineData("1234567891012345678910", new byte[] { 0x42, 0xed, 0x12, 0x3b, 0xda, 0xce, 0x08, 0x4c, (byte)'>' })] + // public void TokenizeInt_Builds_CorrectObject(string number, byte[] expectedBytes) + // { + // // Arrange + // + // // Act + // var tokenized = x.IRReader.TokenizeInt(number, 0); + // + // // Assert + // Assert.Null(tokenized.Atom); + // Assert.NotNull(tokenized.Pair); + // Assert.Null(tokenized.AsPair().Item1.Atom); + // Assert.NotNull(tokenized.AsPair().Item1); + // Assert.NotNull(tokenized.AsPair().Item1.AsPair()); + // + // //INT as bytes + // Assert.True(tokenized.AsPair().Item1.AsPair().Item1.Atom.SequenceEqual(new byte[] { 73, 78, 84})); // INT + // + // //NUMBER as bytes + // Assert.True(tokenized.AsPair().Item2.Atom.SequenceEqual(expectedBytes)); // INT + // } } \ No newline at end of file diff --git a/CLVMDotNet/tests/Tools/IRReader/TokenizeHexTests.cs b/CLVMDotNet/tests/Tools/IRReader/TokenizeHexTests.cs index 1f67016..a9c5d36 100644 --- a/CLVMDotNet/tests/Tools/IRReader/TokenizeHexTests.cs +++ b/CLVMDotNet/tests/Tools/IRReader/TokenizeHexTests.cs @@ -1,8 +1,61 @@ +using CLVMDotNet.Tools; using Xunit; using x = CLVMDotNet.Tools.IR; namespace CLVMDotNet.Tests.Tools.IRReader; public class TokenizeHexTests { + [Fact] + public void TokenizeHex_DoesNotLook_like_hex_returns_null() + { + // ArrangeA + var invalidHex = "xxxx"; + + // ActW + var result = x.IRReader.TokenizeHex(invalidHex, 0); + + // Assert + Assert.Null(result); + } + + [Fact] + public void TokenizeHex_Invalid_Hex_throws_exception() + { + // ArrangeA + var invalidHex = "0Xzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"; + int offset = 1; + + // ActW + var errorMessage = + Assert.Throws(() => + x.IRReader.TokenizeHex(invalidHex, offset)); + + // Assert + Assert.Equal($"invalid hex at {offset}:{invalidHex}",errorMessage.Message); + } + + [Theory] + [InlineData("0x01", new byte[] { 0x01})] + [InlineData("0x2DE684E38", new byte[] { 0x02, 0xde, 0x68, 0x4e, 0x38})] + [InlineData("0x1BFEA1277EF63F25B9D65E79", new byte[] { 0x1b, 0xfe, 0xa1, (byte)'\'', (byte)'~', 0xf6, (byte)'?', (byte)'%', 0xb9, 0xd6, (byte)'^', (byte)'y'})] + public void TokenizeHex_Valid(string number, byte[] expectedBytes) + { + // Arrange + + // Act + var tokenized = x.IRReader.TokenizeHex(number, 0); + // Assert + Assert.Null(tokenized.Atom); + Assert.NotNull(tokenized.Pair); + Assert.Null(tokenized.AsPair().Item1.Atom); + Assert.NotNull(tokenized.AsPair().Item1); + Assert.NotNull(tokenized.AsPair().Item1.AsPair()); + + //HEX as bytes + Assert.True(tokenized.AsPair().Item1.AsPair().Item1.Atom.SequenceEqual(new byte[] { 72, 69, 88})); // HEX + + //NUMBER as bytes + Assert.True(tokenized.AsPair().Item2.Atom.SequenceEqual(expectedBytes)); //bytes + } } \ No newline at end of file From b2a8502a0a139e4169f01a9678f4b2d609e05b17 Mon Sep 17 00:00:00 2001 From: kev Date: Wed, 24 Jan 2024 14:09:21 +0000 Subject: [PATCH 06/29] Added test for TokenizeSymbol --- CLVMDotNet/src/Tools/IR/IRReader.cs | 5 ++-- .../Tools/IRReader/TokenizeSymbolTests.cs | 24 +++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 CLVMDotNet/tests/Tools/IRReader/TokenizeSymbolTests.cs diff --git a/CLVMDotNet/src/Tools/IR/IRReader.cs b/CLVMDotNet/src/Tools/IR/IRReader.cs index 655aee6..82e0cf1 100644 --- a/CLVMDotNet/src/Tools/IR/IRReader.cs +++ b/CLVMDotNet/src/Tools/IR/IRReader.cs @@ -272,9 +272,10 @@ public static bool TryParseHex(string token, out byte[] result) return null; } - public static Tuple<(BigInteger, int), string>? TokenizeSymbol(string token, int offset) + public static Tuple<(BigInteger, int), byte[]>? TokenizeSymbol(string token, int offset) { - return Tuple.Create((IRType.SYMBOL, offset), token); + var tokenAsBytes = Encoding.UTF8.GetBytes(token); + return Tuple.Create((IRType.SYMBOL, offset), tokenAsBytes); } public static IEnumerable<(string token, int offset)> TokenStream(string s) diff --git a/CLVMDotNet/tests/Tools/IRReader/TokenizeSymbolTests.cs b/CLVMDotNet/tests/Tools/IRReader/TokenizeSymbolTests.cs new file mode 100644 index 0000000..9889fb7 --- /dev/null +++ b/CLVMDotNet/tests/Tools/IRReader/TokenizeSymbolTests.cs @@ -0,0 +1,24 @@ +using Xunit; +using x = CLVMDotNet.Tools.IR; + +namespace CLVMDotNet.Tests.Tools.IRReader +{ + + public class TokenizeSymbolTests + { + [Fact] + public void TokenizeSymbol_returns_sexp() + { + // Arrange + var offset = 2; + + // Act + var tokenized = x.IRReader.TokenizeSymbol("+", offset); + + // Assert + Assert.Equal(x.IRType.SYMBOL, tokenized.Item1.Item1); + Assert.Equal(offset, tokenized.Item1.Item2); + Assert.True(tokenized.Item2.SequenceEqual(new byte[] { (byte)'+'})); + } + } +} \ No newline at end of file From 2f1fcde778c1e199be465ef66b345e1abfd133cc Mon Sep 17 00:00:00 2001 From: kev Date: Wed, 24 Jan 2024 14:40:31 +0000 Subject: [PATCH 07/29] fix assert --- CLVMDotNet/tests/Tools/IRReader/IrNewTests.cs | 6 +- .../tests/Tools/IRReader/TokenizeConsTests.cs | 90 ++++++++++--------- 2 files changed, 50 insertions(+), 46 deletions(-) diff --git a/CLVMDotNet/tests/Tools/IRReader/IrNewTests.cs b/CLVMDotNet/tests/Tools/IRReader/IrNewTests.cs index 6e0f03f..ad885dc 100644 --- a/CLVMDotNet/tests/Tools/IRReader/IrNewTests.cs +++ b/CLVMDotNet/tests/Tools/IRReader/IrNewTests.cs @@ -10,9 +10,11 @@ public class IrNewTests public void IrNewWithValidIntegerAndOffset() { // arrange + var val = "100"; + var offset = 1; // act - var result = x.Utils.IrNew(x.IRType.INT, 100, 1); + var result = x.Utils.IrNew(x.IRType.INT, val, offset); // assert Assert.Null(result.Atom); @@ -20,7 +22,7 @@ public void IrNewWithValidIntegerAndOffset() Assert.NotNull(result.Pair.Item1); Assert.True(result.AsPair().Item1.AsPair().Item1.Atom.SequenceEqual(new byte[] { 73, 78, 84 })); //INT Assert.True(result.AsPair().Item1.AsPair().Item2.Atom.SequenceEqual(new byte[] { 0x01 })); //1 (offset) - Assert.True(result.AsPair().Item2.Atom.SequenceEqual(new byte[] {0x64})); //100 + Assert.True(result.AsPair().Item2.Atom.SequenceEqual(new byte[] {49,48,48})); //100 } } } \ No newline at end of file diff --git a/CLVMDotNet/tests/Tools/IRReader/TokenizeConsTests.cs b/CLVMDotNet/tests/Tools/IRReader/TokenizeConsTests.cs index d11829f..9be1cad 100644 --- a/CLVMDotNet/tests/Tools/IRReader/TokenizeConsTests.cs +++ b/CLVMDotNet/tests/Tools/IRReader/TokenizeConsTests.cs @@ -1,53 +1,55 @@ using Xunit; using x = CLVMDotNet.Tools.IR; -namespace CLVMDotNet.Tests.Tools.IRReader; - -public class TokenizeConsTests +namespace CLVMDotNet.Tests.Tools.IRReader { - [Fact] - public void TokenizeCons_ClosingBracket() + + public class TokenizeConsTests { - // Arrange - var stream = x.IRReader.TokenStream("(+ 1 3)"); + [Fact] + public void TokenizeCons_ClosingBracket() + { + // Arrange + var stream = x.IRReader.TokenStream("(+ 1 3)"); + + // Act + var tokenized = x.IRReader.TokenizeCons(")", 6, stream.GetEnumerator()); - // Act - var tokenized = x.IRReader.TokenizeCons(")", 6, stream.GetEnumerator()); + // Assert + Assert.Null(tokenized.Atom); + Assert.NotNull(tokenized.Pair); + Assert.NotNull(tokenized.AsPair().Item1); + Assert.Null(tokenized.AsPair().Item1.Atom); + Assert.NotNull(tokenized.AsPair().Item1.Pair); + Assert.NotNull(tokenized.AsPair().Item1.AsPair()); + Assert.True(tokenized.AsPair().Item1.AsPair().Item1.Atom.SequenceEqual(new byte[] { 78, 85, 76, 76 })); + Assert.True(tokenized.AsPair().Item2.Atom.SequenceEqual(new byte[] { })); + } - // Assert - Assert.Null(tokenized.Atom); - Assert.NotNull(tokenized.Pair); - Assert.NotNull(tokenized.AsPair().Item1); - Assert.Null(tokenized.AsPair().Item1.Atom); - Assert.NotNull(tokenized.AsPair().Item1.Pair); - Assert.NotNull(tokenized.AsPair().Item1.AsPair()); - Assert.True(tokenized.AsPair().Item1.AsPair().Item1.Atom.SequenceEqual(new byte[] {78, 85, 76, 76 })); - Assert.True(tokenized.AsPair().Item2.Atom.SequenceEqual(new byte []{ })); + // [Theory] + // [InlineData("1", new byte[] { 0x01})] + // [InlineData("256", new byte[] { 0x01, 0x00 })] + // [InlineData("12345678910", new byte[] { 0x02, 0xdf, 0xdc, 0x1c, (byte)'>'})] + // [InlineData("1234567891012345678910", new byte[] { 0x42, 0xed, 0x12, 0x3b, 0xda, 0xce, 0x08, 0x4c, (byte)'>' })] + // public void TokenizeInt_Builds_CorrectObject(string number, byte[] expectedBytes) + // { + // // Arrange + // + // // Act + // var tokenized = x.IRReader.TokenizeInt(number, 0); + // + // // Assert + // Assert.Null(tokenized.Atom); + // Assert.NotNull(tokenized.Pair); + // Assert.Null(tokenized.AsPair().Item1.Atom); + // Assert.NotNull(tokenized.AsPair().Item1); + // Assert.NotNull(tokenized.AsPair().Item1.AsPair()); + // + // //INT as bytes + // Assert.True(tokenized.AsPair().Item1.AsPair().Item1.Atom.SequenceEqual(new byte[] { 73, 78, 84})); // INT + // + // //NUMBER as bytes + // Assert.True(tokenized.AsPair().Item2.Atom.SequenceEqual(expectedBytes)); // INT + // } } - - // [Theory] - // [InlineData("1", new byte[] { 0x01})] - // [InlineData("256", new byte[] { 0x01, 0x00 })] - // [InlineData("12345678910", new byte[] { 0x02, 0xdf, 0xdc, 0x1c, (byte)'>'})] - // [InlineData("1234567891012345678910", new byte[] { 0x42, 0xed, 0x12, 0x3b, 0xda, 0xce, 0x08, 0x4c, (byte)'>' })] - // public void TokenizeInt_Builds_CorrectObject(string number, byte[] expectedBytes) - // { - // // Arrange - // - // // Act - // var tokenized = x.IRReader.TokenizeInt(number, 0); - // - // // Assert - // Assert.Null(tokenized.Atom); - // Assert.NotNull(tokenized.Pair); - // Assert.Null(tokenized.AsPair().Item1.Atom); - // Assert.NotNull(tokenized.AsPair().Item1); - // Assert.NotNull(tokenized.AsPair().Item1.AsPair()); - // - // //INT as bytes - // Assert.True(tokenized.AsPair().Item1.AsPair().Item1.Atom.SequenceEqual(new byte[] { 73, 78, 84})); // INT - // - // //NUMBER as bytes - // Assert.True(tokenized.AsPair().Item2.Atom.SequenceEqual(expectedBytes)); // INT - // } } \ No newline at end of file From a075c1e7e86908078e9f7bc583b973499294e84a Mon Sep 17 00:00:00 2001 From: kev Date: Wed, 24 Jan 2024 15:53:06 +0000 Subject: [PATCH 08/29] Added tests for TypeForAtoms --- CLVMDotNet/src/Tools/IR/BinUtils.cs | 3 +- CLVMDotNet/src/Tools/IR/IRType.cs | 4 +- .../Tools/BinUtils/AssembleFromIRTests.cs | 7 +++ .../tests/Tools/BinUtils/TypeForAtomTests.cs | 45 ++++++++++++++----- 4 files changed, 46 insertions(+), 13 deletions(-) create mode 100644 CLVMDotNet/tests/Tools/BinUtils/AssembleFromIRTests.cs diff --git a/CLVMDotNet/src/Tools/IR/BinUtils.cs b/CLVMDotNet/src/Tools/IR/BinUtils.cs index fc8b483..f08c8f2 100644 --- a/CLVMDotNet/src/Tools/IR/BinUtils.cs +++ b/CLVMDotNet/src/Tools/IR/BinUtils.cs @@ -82,7 +82,8 @@ public static BigInteger TypeForAtom(byte[] atom) return IRType.HEX; } - if (BitConverter.ToUInt32(atom, 0) == BitConverter.ToUInt32(atom, 0)) + + if(x.Casts.IntToBytes(x.Casts.IntFromBytes(atom)).SequenceEqual(atom)) { return IRType.INT; } diff --git a/CLVMDotNet/src/Tools/IR/IRType.cs b/CLVMDotNet/src/Tools/IR/IRType.cs index 421f59e..11b4426 100644 --- a/CLVMDotNet/src/Tools/IR/IRType.cs +++ b/CLVMDotNet/src/Tools/IR/IRType.cs @@ -3,7 +3,7 @@ namespace CLVMDotNet.Tools.IR { - public class IRType + public static class IRType { public static BigInteger CONS = Utils.ConvertToBase256("CONS"); // Equivalent to b"CONS" public static BigInteger NULL = Utils.ConvertToBase256("NULL"); // Equivalent to b"NULL" @@ -23,7 +23,7 @@ public static bool Listp() return false; } - public byte[] AsAtom(BigInteger val) + public static byte[] AsAtom(BigInteger val) { return Casts.IntToBytes(val); } diff --git a/CLVMDotNet/tests/Tools/BinUtils/AssembleFromIRTests.cs b/CLVMDotNet/tests/Tools/BinUtils/AssembleFromIRTests.cs new file mode 100644 index 0000000..c8fabb8 --- /dev/null +++ b/CLVMDotNet/tests/Tools/BinUtils/AssembleFromIRTests.cs @@ -0,0 +1,7 @@ +namespace CLVMDotNet.Tests.Tools.BinUtils +{ + public class AssembleFromIRTests + { + + } +} \ No newline at end of file diff --git a/CLVMDotNet/tests/Tools/BinUtils/TypeForAtomTests.cs b/CLVMDotNet/tests/Tools/BinUtils/TypeForAtomTests.cs index ac7f849..3f3da89 100644 --- a/CLVMDotNet/tests/Tools/BinUtils/TypeForAtomTests.cs +++ b/CLVMDotNet/tests/Tools/BinUtils/TypeForAtomTests.cs @@ -10,15 +10,40 @@ namespace CLVMDotNet.Tests.Tools.BinUtils [Trait("BinUtils", "TypeForAtom")] public class TypeForAtomTests { - // [Theory] - // [InlineData(4736344, "abdde")] //Quote - // [InlineData(4736344, "134567")] //Hex - // [InlineData(4736344,"23456")] //Int - // public void TestTypeForAtomReturnsCorrectType(BigInteger type, string value) - // { - // byte[] bytes = Encoding.UTF8.GetBytes(value); - // var t = x.BinUtils.TypeForAtom(bytes); - // Assert.Equal(type, t); - // } + [Theory] + [InlineData("this is a test")] + [InlineData("178884")] + [InlineData("aaaa")] + [InlineData("100")] + [InlineData("126")] + public void TypeForAtomReturnsQuote(string value) + { + // Arrange + byte[] bytes = Encoding.UTF8.GetBytes(value); + + // Act + var t = x.BinUtils.TypeForAtom(bytes); + + // Assert + Assert.Equal(IRType.QUOTES, t); + } + + [Theory] + [InlineData("1")] + [InlineData("4")] + [InlineData("99")] + public void TypeForAtomReturnsInt(string value) + { + // Arrange + byte[] bytes = Encoding.UTF8.GetBytes(value); + + // Act + var t = x.BinUtils.TypeForAtom(bytes); + + // Assert + Assert.Equal(IRType.INT, t); + } + + //TODO: ADD Test to check that IRType.HEX is returned } } \ No newline at end of file From d4a8ea55ac7c8a6e1e7407359698e710e9d17664 Mon Sep 17 00:00:00 2001 From: kev Date: Wed, 24 Jan 2024 17:48:21 +0000 Subject: [PATCH 09/29] Added fixed dictionary for keywords to/from atoms --- CLVMDotNet/src/CLVM/Keywords.cs | 140 ++++++++++++++++++++++------ CLVMDotNet/src/Tools/IR/BinUtils.cs | 2 +- CLVMDotNet/src/Tools/IR/Clvmc.cs | 4 - 3 files changed, 113 insertions(+), 33 deletions(-) diff --git a/CLVMDotNet/src/CLVM/Keywords.cs b/CLVMDotNet/src/CLVM/Keywords.cs index 60d4c31..44c659c 100644 --- a/CLVMDotNet/src/CLVM/Keywords.cs +++ b/CLVMDotNet/src/CLVM/Keywords.cs @@ -1,58 +1,142 @@ namespace CLVMDotNet.CLVM { - public static class Keywords { - public static string[] KEYWORDS = new string[] { // core opcodes 0x01-x08 - ". q a i c f r l x ", + ".", + "q", + "a", + "i", + "c", + "f", + "r", + "l", + "x", // opcodes on atoms as strings 0x09-0x0f - "= >s sha256 substr strlen concat . ", + "=", + ">s", + "sha256", + "substr", + "strlen", + "concat", + //"." // opcodes on atoms as ints 0x10-0x17 - "+ - * / divmod > ash lsh ", + "+", + "-", + "*", + "/", + "divmod", + ">", + "ash", + "lsh", // opcodes on atoms as vectors of bools 0x18-0x1c - "logand logior logxor lognot . ", + "logand", + "logior", + "logxor", + "lognot", + // ".", // opcodes for bls 1381 0x1d-0x1f - "point_add pubkey_for_exp . ", + "point_add", + "pubkey_for_exp", + // ".", // bool opcodes 0x20-0x23 - "not any all . ", + "not", + "any", + "all", + ".", // misc 0x24 - "softfork " + "softfork" }; - public static Dictionary KEYWORD_FROM_ATOM => InitializeKeywordFromAtom(); - public static Dictionary KEYWORD_TO_ATOM => InitializeKeywordToAtom(); + public static Dictionary KEYWORD_FROM_ATOM => InitializeKeywordFromAtom(); + public static Dictionary KEYWORD_TO_ATOM => InitializeKeywordToAtom(); - private static Dictionary InitializeKeywordFromAtom() + private static Dictionary InitializeKeywordFromAtom() { - var keywordFromAtom = new Dictionary(); - - for (int k = 0; k < KEYWORDS.Length; k++) - { - byte[] keyBytes = BitConverter.GetBytes(k); - keywordFromAtom[keyBytes] = KEYWORDS[k]; - } - + var keywordFromAtom = new Dictionary(); + keywordFromAtom.Add(0x00, "."); + keywordFromAtom.Add(0x01, "q"); + keywordFromAtom.Add(0x02, "a"); + keywordFromAtom.Add(0x03, "i"); + keywordFromAtom.Add(0x04, "c"); + keywordFromAtom.Add(0x05, "f"); + keywordFromAtom.Add(0x06, "r"); + keywordFromAtom.Add(0x07, "l"); + keywordFromAtom.Add(0x08, "x"); + keywordFromAtom.Add(0x09, "="); + keywordFromAtom.Add(0x0a, ">s"); + keywordFromAtom.Add(0x0b, "sha256"); + keywordFromAtom.Add(0x0c, "substr"); + keywordFromAtom.Add(0x0d, "strlen"); + keywordFromAtom.Add(0x0e, "concat"); + keywordFromAtom.Add(0x0f, "."); + keywordFromAtom.Add(0x10, "+"); + keywordFromAtom.Add(0x11, "-"); + keywordFromAtom.Add(0x12, "*"); + keywordFromAtom.Add(0x13, "/"); + keywordFromAtom.Add(0x14, "divmod"); + keywordFromAtom.Add(0x15, ">"); + keywordFromAtom.Add(0x16, "ash"); + keywordFromAtom.Add(0x17, "lsh"); + keywordFromAtom.Add(0x18, "logand"); + keywordFromAtom.Add(0x19, "logior"); + keywordFromAtom.Add(0x1a, "logxor"); + keywordFromAtom.Add(0x1b, "lognot"); + keywordFromAtom.Add(0x1c, "."); + keywordFromAtom.Add(0x1d, "point_add"); + keywordFromAtom.Add(0x1e, "pubkey_for_exp"); + keywordFromAtom.Add(0x1f, "."); + keywordFromAtom.Add(0x20, "not"); + keywordFromAtom.Add(0x21, "any"); + keywordFromAtom.Add(0x22, "all"); + keywordFromAtom.Add(0x23, "."); return keywordFromAtom; } - private static Dictionary InitializeKeywordToAtom() + private static Dictionary InitializeKeywordToAtom() { - var keywordToAtom = new Dictionary(); - - for (int k = 0; k < KEYWORDS.Length; k++) - { - keywordToAtom[KEYWORDS[k]] = BitConverter.GetBytes(k); - } - + var keywordToAtom = new Dictionary(); + keywordToAtom.Add(".", 0x00); + keywordToAtom.Add("q", 0x01); + keywordToAtom.Add("a", 0x02); + keywordToAtom.Add("i", 0x03); + keywordToAtom.Add("c", 0x04); + keywordToAtom.Add("f", 0x05); + keywordToAtom.Add("r", 0x06); + keywordToAtom.Add("l", 0x07); + keywordToAtom.Add("x", 0x08); + keywordToAtom.Add("=", 0x09); + keywordToAtom.Add(">s", 0x0a); + keywordToAtom.Add("sha256", 0x0b); + keywordToAtom.Add("substr", 0x0c); + keywordToAtom.Add("strlen", 0x0d); + keywordToAtom.Add("concat", 0x0e); + keywordToAtom.Add("+", 0x10); + keywordToAtom.Add("-", 0x11); + keywordToAtom.Add("*", 0x12); + keywordToAtom.Add("/", 0x13); + keywordToAtom.Add("divmod", 0x14); + keywordToAtom.Add(">", 0x15); + keywordToAtom.Add("ash", 0x16); + keywordToAtom.Add("lsh", 0x17); + keywordToAtom.Add("logand", 0x18); + keywordToAtom.Add("logior", 0x19); + keywordToAtom.Add("logxor", 0x1a); + keywordToAtom.Add("lognot", 0x1b); + keywordToAtom.Add("point_add", 0x1d); + keywordToAtom.Add("pubkey_for_exp", 0x1e); + keywordToAtom.Add("not", 0x20); + keywordToAtom.Add("any", 0x21); + keywordToAtom.Add("all", 0x22); + keywordToAtom.Add("softfork", 0x24); return keywordToAtom; } } diff --git a/CLVMDotNet/src/Tools/IR/BinUtils.cs b/CLVMDotNet/src/Tools/IR/BinUtils.cs index f08c8f2..11b2175 100644 --- a/CLVMDotNet/src/Tools/IR/BinUtils.cs +++ b/CLVMDotNet/src/Tools/IR/BinUtils.cs @@ -21,7 +21,7 @@ public static SExp AssembleFromIR(SExp ir_sexp) keyword = keyword.Substring(1); } - var atom = x.Keywords.KEYWORD_TO_ATOM.ContainsKey(keyword) ? x.Keywords.KEYWORD_TO_ATOM[keyword] : null; + var atom = x.Keywords.KEYWORD_TO_ATOM[keyword]; if (atom != null) { return SExp.To(atom); diff --git a/CLVMDotNet/src/Tools/IR/Clvmc.cs b/CLVMDotNet/src/Tools/IR/Clvmc.cs index 5477bb2..40dbb2c 100644 --- a/CLVMDotNet/src/Tools/IR/Clvmc.cs +++ b/CLVMDotNet/src/Tools/IR/Clvmc.cs @@ -8,10 +8,6 @@ public class Clvmc public static SExp CompileCLVMText(string text, string[] searchPaths) { var ir_src = IRReader.ReadIR(text); - - - var s = ir_src.AsJSON(); - var assembled_sexp = BinUtils.AssembleFromIR(ir_src); var input_sexp = SExp.To((assembled_sexp, Array.Empty())); var result = Program.RunProgram(null, input_sexp); From 0db26aaba4c5c8d9298640d467245856df3bc1b9 Mon Sep 17 00:00:00 2001 From: kev Date: Wed, 24 Jan 2024 21:18:10 +0000 Subject: [PATCH 10/29] . --- CLVMDotNet/src/CLVM/Keywords.cs | 1 - CLVMDotNet/src/CLVM/Operators.cs | 28 ------------- .../CLVM/Operators/KeywordFromAtomTests.cs | 36 ++++++++++++++--- .../CLVM/Operators/KeywordToAtomTests.cs | 39 +++++++++++++++---- 4 files changed, 61 insertions(+), 43 deletions(-) diff --git a/CLVMDotNet/src/CLVM/Keywords.cs b/CLVMDotNet/src/CLVM/Keywords.cs index 44c659c..460c8d7 100644 --- a/CLVMDotNet/src/CLVM/Keywords.cs +++ b/CLVMDotNet/src/CLVM/Keywords.cs @@ -62,7 +62,6 @@ public static class Keywords private static Dictionary InitializeKeywordFromAtom() { var keywordFromAtom = new Dictionary(); - keywordFromAtom.Add(0x00, "."); keywordFromAtom.Add(0x01, "q"); keywordFromAtom.Add(0x02, "a"); keywordFromAtom.Add(0x03, "i"); diff --git a/CLVMDotNet/src/CLVM/Operators.cs b/CLVMDotNet/src/CLVM/Operators.cs index e2d3117..6a71f0a 100644 --- a/CLVMDotNet/src/CLVM/Operators.cs +++ b/CLVMDotNet/src/CLVM/Operators.cs @@ -220,34 +220,6 @@ public static Tuple ApplyOperator(byte[] atom, SExp args) throw new Exception($"{BitConverter.ToString(atom).Replace("-", "")} Operator not found or is unsupported!"); } - - public static string KEYWORD_FROM_ATOM(byte atom) => atom switch - { - 0x23 => ".", - 0x02 => "a", - 0x01 => "q", - 0x03 => "i", - 0x04 => "c", - 0x05 => "f", - 0x06 => "r", - 0x07 => "l", - 0x08 => "x", - _ => throw new Exception("Invalid Atom") - }; - - public static byte KEYWORD_TO_ATOM(string keyword) => keyword switch - { - "." => 0x23, - "a" => 0x02, - "q" => 0x01, - "i" => 0x03, - "c" => 0x04, - "f" => 0x05, - "r" => 0x06, - "l" => 0x07, - "x" => 0x08, - _ => throw new Exception("Invalid Keyword") - }; } diff --git a/CLVMDotNet/tests/CLVM/Operators/KeywordFromAtomTests.cs b/CLVMDotNet/tests/CLVM/Operators/KeywordFromAtomTests.cs index 76ac69b..e8c2aae 100644 --- a/CLVMDotNet/tests/CLVM/Operators/KeywordFromAtomTests.cs +++ b/CLVMDotNet/tests/CLVM/Operators/KeywordFromAtomTests.cs @@ -1,5 +1,5 @@ using Xunit; -using x = CLVMDotNet.CLVM.Operator; +using x = CLVMDotNet.CLVM; namespace CLVMDotNet.Tests.CLVM.Operators; @@ -15,10 +15,34 @@ public class KeywordFromAtomTests [InlineData(0x06, "r")] [InlineData(0x07, "l")] [InlineData(0x08, "x")] + [InlineData(0x0b, "sha256")] + [InlineData(0x0c, "substr")] + [InlineData(0x0d, "strlen")] + [InlineData(0x0e, "concat")] + [InlineData(0x0f, ".")] + [InlineData(0x10, "+")] + [InlineData(0x11, "-")] + [InlineData(0x12, "*")] + [InlineData(0x13, "/")] + [InlineData(0x14, "divmod")] + [InlineData(0x15, ">")] + [InlineData(0x16, "ash")] + [InlineData(0x17, "lsh")] + [InlineData(0x18, "logand")] + [InlineData(0x19, "logior")] + [InlineData(0x1a, "logxor")] + [InlineData(0x1b, "lognot")] + [InlineData(0x1c, ".")] + [InlineData(0x1d, "point_add")] + [InlineData(0x1e, "pubkey_for_exp")] + [InlineData(0x1f, ".")] + [InlineData(0x20, "not")] + [InlineData(0x21, "any")] + [InlineData(0x22, "all")] public void KeywordToAtom_Returns_correct_byte(byte atom, string expectedKeyword) { - var result = x.KEYWORD_FROM_ATOM(atom); - Assert.Equal(result, expectedKeyword); + var result = x.Keywords.KEYWORD_FROM_ATOM[atom]; + Assert.Equal(expectedKeyword, result); } [Fact] @@ -28,10 +52,10 @@ public void UnknownAtom_ThrowsError() // Act var errorMessage = - Assert.Throws(() => - x.KEYWORD_FROM_ATOM(0xaa)); + Assert.Throws(() => + x.Keywords.KEYWORD_FROM_ATOM[0xaa]); // Assert - Assert.Contains("Invalid Atom", errorMessage.Message); + Assert.Contains("The given key '170' was not present in the dictionary", errorMessage.Message); } } \ No newline at end of file diff --git a/CLVMDotNet/tests/CLVM/Operators/KeywordToAtomTests.cs b/CLVMDotNet/tests/CLVM/Operators/KeywordToAtomTests.cs index 081195b..75e5e37 100644 --- a/CLVMDotNet/tests/CLVM/Operators/KeywordToAtomTests.cs +++ b/CLVMDotNet/tests/CLVM/Operators/KeywordToAtomTests.cs @@ -1,12 +1,12 @@ using Xunit; -using clvm = CLVMDotNet.CLVM.Operator; +using clvm = CLVMDotNet.CLVM; -namespace CLVMDotNet.Tests.CLVM.Operators; +namespace CLVMDotNet.Tests.CLVM; public class KeywordToAtomTests { [Theory] - [InlineData(".", 0x23)] + [InlineData(".", 0x00)] [InlineData("a", 0x02)] [InlineData("q", 0x01)] [InlineData("i", 0x03)] @@ -15,10 +15,33 @@ public class KeywordToAtomTests [InlineData("r", 0x06)] [InlineData("l", 0x07)] [InlineData("x", 0x08)] + [InlineData("=", 0x09)] + [InlineData("sha256", 0x0b)] + [InlineData("substr", 0x0c)] + [InlineData("strlen", 0x0d)] + [InlineData("concat", 0x0e)] + // [InlineData("#", 0x0f)] + [InlineData("+", 0x10)] + [InlineData("-", 0x11)] + [InlineData("*", 0x12)] + [InlineData("/", 0x13)] + [InlineData("divmod", 0x14)] + [InlineData(">", 0x15)] + [InlineData("ash", 0x16)] + [InlineData("lsh", 0x17)] + [InlineData("logand", 0x18)] + [InlineData("logior", 0x19)] + [InlineData("logxor", 0x1a)] + [InlineData("lognot", 0x1b)] + [InlineData("point_add", 0x1d)] + [InlineData("pubkey_for_exp", 0x1e)] + [InlineData("not", 0x20)] + [InlineData("any", 0x21)] + [InlineData("all", 0x22)] public void KeywordToAtom_Returns_correct_byte(string keyword, byte expectedByte) { - var result = clvm.KEYWORD_TO_ATOM(keyword); - Assert.Equal(result, expectedByte); + var result = clvm.Keywords.KEYWORD_TO_ATOM[keyword]; + Assert.Equal(expectedByte, result); } [Fact] @@ -28,11 +51,11 @@ public void UnknownKeyword_ThrowsError() // Act var errorMessage = - Assert.Throws(() => - clvm.KEYWORD_TO_ATOM("SomeInvalidKeyword")); + Assert.Throws(() => + clvm.Keywords.KEYWORD_TO_ATOM["SomeInvalidKeyword"]); // Assert - Assert.Contains("Invalid Keyword", errorMessage.Message); + Assert.Contains("given key 'SomeInvalidKeyword' was not present in the dictionary", errorMessage.Message); } } From 6cb40ce95eaa5653973894ce3151157e1ddcb5ec Mon Sep 17 00:00:00 2001 From: kev Date: Sat, 27 Jan 2024 13:03:27 +0000 Subject: [PATCH 11/29] Added brun & test --- CLVMDotNet/src/CLVM/Program.cs | 2 +- CLVMDotNet/src/CLVMDotNet.csproj | 4 -- CLVMDotNet/src/Tools/IR/BinUtils.cs | 4 +- CLVMDotNet/src/Tools/IR/Utils.cs | 3 +- .../src/Tools/Stages/{ => Stage0}/Stage0.cs | 0 .../src/Tools/Stages/Stage2/Bindings.cs | 11 +++++ CLVMDotNet/src/Tools/Stages/Stage2/Compile.cs | 6 +++ .../src/Tools/Stages/Stage2/Defaults.cs | 6 +++ CLVMDotNet/src/Tools/Stages/Stage2/Helpers.cs | 6 +++ CLVMDotNet/src/Tools/Stages/Stage2/Mod.cs | 6 +++ .../src/Tools/Stages/Stage2/Operators.cs | 6 +++ .../src/Tools/Stages/Stage2/Optimize.cs | 9 ++++ .../tests/Tools/Stages/Stage0/Stage0.cs | 6 +++ .../tests/Tools/Stages/Stage2/BindingTests.cs | 49 +++++++++++++++++++ .../tests/Tools/Stages/Stage2/CompileTests.cs | 6 +++ .../Tools/Stages/Stage2/DefaultsTests.cs | 6 +++ .../tests/Tools/Stages/Stage2/HelperTests.cs | 6 +++ .../tests/Tools/Stages/Stage2/ModTests.cs | 6 +++ .../Tools/Stages/Stage2/OperatorTests.cs | 6 +++ .../Tools/Stages/Stage2/OptimizeTests.cs | 6 +++ 20 files changed, 146 insertions(+), 8 deletions(-) rename CLVMDotNet/src/Tools/Stages/{ => Stage0}/Stage0.cs (100%) create mode 100644 CLVMDotNet/src/Tools/Stages/Stage2/Bindings.cs create mode 100644 CLVMDotNet/src/Tools/Stages/Stage2/Compile.cs create mode 100644 CLVMDotNet/src/Tools/Stages/Stage2/Defaults.cs create mode 100644 CLVMDotNet/src/Tools/Stages/Stage2/Helpers.cs create mode 100644 CLVMDotNet/src/Tools/Stages/Stage2/Mod.cs create mode 100644 CLVMDotNet/src/Tools/Stages/Stage2/Operators.cs create mode 100644 CLVMDotNet/src/Tools/Stages/Stage2/Optimize.cs create mode 100644 CLVMDotNet/tests/Tools/Stages/Stage0/Stage0.cs create mode 100644 CLVMDotNet/tests/Tools/Stages/Stage2/BindingTests.cs create mode 100644 CLVMDotNet/tests/Tools/Stages/Stage2/CompileTests.cs create mode 100644 CLVMDotNet/tests/Tools/Stages/Stage2/DefaultsTests.cs create mode 100644 CLVMDotNet/tests/Tools/Stages/Stage2/HelperTests.cs create mode 100644 CLVMDotNet/tests/Tools/Stages/Stage2/ModTests.cs create mode 100644 CLVMDotNet/tests/Tools/Stages/Stage2/OperatorTests.cs create mode 100644 CLVMDotNet/tests/Tools/Stages/Stage2/OptimizeTests.cs diff --git a/CLVMDotNet/src/CLVM/Program.cs b/CLVMDotNet/src/CLVM/Program.cs index 063e770..101508e 100644 --- a/CLVMDotNet/src/CLVM/Program.cs +++ b/CLVMDotNet/src/CLVM/Program.cs @@ -10,7 +10,7 @@ public static Tuple RunProgram(SExp program, SExp args, BigInt Stack, BigInteger>> opStack = new Stack, BigInteger>>(); var valueStack = new Stack(); - valueStack.Push(args); + valueStack.Push(prog.Cons(args)); opStack.Push(stack => EvalOp(opStack, valueStack)); BigInteger cost = 0; diff --git a/CLVMDotNet/src/CLVMDotNet.csproj b/CLVMDotNet/src/CLVMDotNet.csproj index 5d6d8dd..dca9ac3 100644 --- a/CLVMDotNet/src/CLVMDotNet.csproj +++ b/CLVMDotNet/src/CLVMDotNet.csproj @@ -12,8 +12,4 @@ - - - - diff --git a/CLVMDotNet/src/Tools/IR/BinUtils.cs b/CLVMDotNet/src/Tools/IR/BinUtils.cs index 11b2175..4ae196c 100644 --- a/CLVMDotNet/src/Tools/IR/BinUtils.cs +++ b/CLVMDotNet/src/Tools/IR/BinUtils.cs @@ -45,8 +45,8 @@ public static SExp AssembleFromIR(SExp ir_sexp) // handle "q" var first = Utils.IrFirst(ir_sexp); - var keyword2 = Utils.IrAsSymbol(first) as string; - if (keyword2 == "q") + keyword = Utils.IrAsSymbol(first) as string; + if (keyword == "q") { // TODO: note that any symbol is legal after this point } diff --git a/CLVMDotNet/src/Tools/IR/Utils.cs b/CLVMDotNet/src/Tools/IR/Utils.cs index 7a5e6c2..1ec571d 100644 --- a/CLVMDotNet/src/Tools/IR/Utils.cs +++ b/CLVMDotNet/src/Tools/IR/Utils.cs @@ -25,7 +25,8 @@ public static BigInteger ConvertToBase256(string s) { if (irSexp.Listp() && IrType(irSexp) == IRType.SYMBOL) { - return Encoding.UTF8.GetString(IrAsSexp(irSexp).AsAtom()); + var sexp = IrAsSexp(irSexp); + return Encoding.UTF8.GetString(sexp.AsAtom()); } return null; diff --git a/CLVMDotNet/src/Tools/Stages/Stage0.cs b/CLVMDotNet/src/Tools/Stages/Stage0/Stage0.cs similarity index 100% rename from CLVMDotNet/src/Tools/Stages/Stage0.cs rename to CLVMDotNet/src/Tools/Stages/Stage0/Stage0.cs diff --git a/CLVMDotNet/src/Tools/Stages/Stage2/Bindings.cs b/CLVMDotNet/src/Tools/Stages/Stage2/Bindings.cs new file mode 100644 index 0000000..71bd07d --- /dev/null +++ b/CLVMDotNet/src/Tools/Stages/Stage2/Bindings.cs @@ -0,0 +1,11 @@ +using CLVMDotNet.CLVM; +using CLVMDotNet.Tools.IR; + +namespace CLVMDotNet.Tools.Stages.Stage2; + +public static class Bindings +{ + public static SExp Brun => BinUtils.Assemble("(a 2 3)"); + + public static SExp Run => BinUtils.Assemble("(a (opt (com 2)) 3)"); +} \ No newline at end of file diff --git a/CLVMDotNet/src/Tools/Stages/Stage2/Compile.cs b/CLVMDotNet/src/Tools/Stages/Stage2/Compile.cs new file mode 100644 index 0000000..4eb4a97 --- /dev/null +++ b/CLVMDotNet/src/Tools/Stages/Stage2/Compile.cs @@ -0,0 +1,6 @@ +namespace CLVMDotNet.Tools.Stages.Stage2; + +public class Compile +{ + +} \ No newline at end of file diff --git a/CLVMDotNet/src/Tools/Stages/Stage2/Defaults.cs b/CLVMDotNet/src/Tools/Stages/Stage2/Defaults.cs new file mode 100644 index 0000000..2e1d7ac --- /dev/null +++ b/CLVMDotNet/src/Tools/Stages/Stage2/Defaults.cs @@ -0,0 +1,6 @@ +namespace CLVMDotNet.Tools.Stages.Stage2; + +public class Defaults +{ + +} \ No newline at end of file diff --git a/CLVMDotNet/src/Tools/Stages/Stage2/Helpers.cs b/CLVMDotNet/src/Tools/Stages/Stage2/Helpers.cs new file mode 100644 index 0000000..5e75c83 --- /dev/null +++ b/CLVMDotNet/src/Tools/Stages/Stage2/Helpers.cs @@ -0,0 +1,6 @@ +namespace CLVMDotNet.Tools.Stages.Stage2; + +public class Helpers +{ + +} \ No newline at end of file diff --git a/CLVMDotNet/src/Tools/Stages/Stage2/Mod.cs b/CLVMDotNet/src/Tools/Stages/Stage2/Mod.cs new file mode 100644 index 0000000..99c4b63 --- /dev/null +++ b/CLVMDotNet/src/Tools/Stages/Stage2/Mod.cs @@ -0,0 +1,6 @@ +namespace CLVMDotNet.Tools.Stages.Stage2; + +public class Mod +{ + +} \ No newline at end of file diff --git a/CLVMDotNet/src/Tools/Stages/Stage2/Operators.cs b/CLVMDotNet/src/Tools/Stages/Stage2/Operators.cs new file mode 100644 index 0000000..602693b --- /dev/null +++ b/CLVMDotNet/src/Tools/Stages/Stage2/Operators.cs @@ -0,0 +1,6 @@ +namespace CLVMDotNet.Tools.Stages.Stage2; + +public class Operators +{ + +} \ No newline at end of file diff --git a/CLVMDotNet/src/Tools/Stages/Stage2/Optimize.cs b/CLVMDotNet/src/Tools/Stages/Stage2/Optimize.cs new file mode 100644 index 0000000..23329d0 --- /dev/null +++ b/CLVMDotNet/src/Tools/Stages/Stage2/Optimize.cs @@ -0,0 +1,9 @@ +using CLVMDotNet.CLVM; +using CLVMDotNet.Tools.IR; + +namespace CLVMDotNet.Tools.Stages.Stage2; + +public class Optimize +{ + +} \ No newline at end of file diff --git a/CLVMDotNet/tests/Tools/Stages/Stage0/Stage0.cs b/CLVMDotNet/tests/Tools/Stages/Stage0/Stage0.cs new file mode 100644 index 0000000..8bc509a --- /dev/null +++ b/CLVMDotNet/tests/Tools/Stages/Stage0/Stage0.cs @@ -0,0 +1,6 @@ +namespace CLVMDotNet.Tests.Tools.Stages.Stage0; + +public class Stage0 +{ + +} \ No newline at end of file diff --git a/CLVMDotNet/tests/Tools/Stages/Stage2/BindingTests.cs b/CLVMDotNet/tests/Tools/Stages/Stage2/BindingTests.cs new file mode 100644 index 0000000..de0615e --- /dev/null +++ b/CLVMDotNet/tests/Tools/Stages/Stage2/BindingTests.cs @@ -0,0 +1,49 @@ +using CLVMDotNet.Tools.Stages.Stage2; +using Xunit; + +namespace CLVMDotNet.Tests.Tools.Stages.Stage2; + +public class BindingTests +{ + [Fact] + public void TestBrun() + { + // Arrange + + // Act + var brun = Bindings.Brun; + + // Assert + Assert.Null(brun.Atom); + Assert.NotNull(brun.Pair); + Assert.True(brun.AsPair().Item1.AsAtom().SequenceEqual(new byte[] { 0x02 })); + Assert.Null(brun.AsPair().Item1.Pair); + Assert.Null(brun.AsPair().Item2.Atom); + Assert.NotNull(brun.AsPair().Item2.Pair); + Assert.True(brun.AsPair().Item2.AsPair().Item1.AsAtom().SequenceEqual(new byte[] { 0x02})); + Assert.Null(brun.AsPair().Item2.AsPair().Item2.Atom); + Assert.NotNull(brun.AsPair().Item2.AsPair().Item2.Pair); + Assert.True(brun.AsPair().Item2.AsPair().Item2.AsPair().Item1.AsAtom().SequenceEqual(new byte []{ 0x03})); + Assert.Empty(brun.AsPair().Item2.AsPair().Item2.AsPair().Item2.AsAtom()); + } + + [Fact(Skip = "Skipping for now")] + public void TestRun() + { + // Arrange + + // Act + var run = Bindings.Run; + + // Assert + Assert.Null(run.Atom); + Assert.True(run.AsPair().Item1.AsAtom().SequenceEqual(new byte[] { 0x02 })); + Assert.Null(run.AsPair().Item1.Pair); + Assert.Null(run.AsPair().Item2.Atom); + Assert.NotNull(run.AsPair().Item2.Pair); + Assert.NotNull(run.AsPair().Item2.AsPair().Item2); + Assert.NotNull(run.AsPair().Item2.AsPair().Item1); + + + } +} \ No newline at end of file diff --git a/CLVMDotNet/tests/Tools/Stages/Stage2/CompileTests.cs b/CLVMDotNet/tests/Tools/Stages/Stage2/CompileTests.cs new file mode 100644 index 0000000..4969c94 --- /dev/null +++ b/CLVMDotNet/tests/Tools/Stages/Stage2/CompileTests.cs @@ -0,0 +1,6 @@ +namespace CLVMDotNet.Tests.Tools.Stages.Stage2; + +public class CompileTests +{ + +} \ No newline at end of file diff --git a/CLVMDotNet/tests/Tools/Stages/Stage2/DefaultsTests.cs b/CLVMDotNet/tests/Tools/Stages/Stage2/DefaultsTests.cs new file mode 100644 index 0000000..80e9c55 --- /dev/null +++ b/CLVMDotNet/tests/Tools/Stages/Stage2/DefaultsTests.cs @@ -0,0 +1,6 @@ +namespace CLVMDotNet.Tests.Tools.Stages.Stage2; + +public class DefaultsTests +{ + +} \ No newline at end of file diff --git a/CLVMDotNet/tests/Tools/Stages/Stage2/HelperTests.cs b/CLVMDotNet/tests/Tools/Stages/Stage2/HelperTests.cs new file mode 100644 index 0000000..3715c44 --- /dev/null +++ b/CLVMDotNet/tests/Tools/Stages/Stage2/HelperTests.cs @@ -0,0 +1,6 @@ +namespace CLVMDotNet.Tests.Tools.Stages.Stage2; + +public class HelperTests +{ + +} \ No newline at end of file diff --git a/CLVMDotNet/tests/Tools/Stages/Stage2/ModTests.cs b/CLVMDotNet/tests/Tools/Stages/Stage2/ModTests.cs new file mode 100644 index 0000000..b445c61 --- /dev/null +++ b/CLVMDotNet/tests/Tools/Stages/Stage2/ModTests.cs @@ -0,0 +1,6 @@ +namespace CLVMDotNet.Tests.Tools.Stages.Stage2; + +public class ModTests +{ + +} \ No newline at end of file diff --git a/CLVMDotNet/tests/Tools/Stages/Stage2/OperatorTests.cs b/CLVMDotNet/tests/Tools/Stages/Stage2/OperatorTests.cs new file mode 100644 index 0000000..ef8fb9a --- /dev/null +++ b/CLVMDotNet/tests/Tools/Stages/Stage2/OperatorTests.cs @@ -0,0 +1,6 @@ +namespace CLVMDotNet.Tests.Tools.Stages.Stage2; + +public class OperatorTests +{ + +} \ No newline at end of file diff --git a/CLVMDotNet/tests/Tools/Stages/Stage2/OptimizeTests.cs b/CLVMDotNet/tests/Tools/Stages/Stage2/OptimizeTests.cs new file mode 100644 index 0000000..54bb1f6 --- /dev/null +++ b/CLVMDotNet/tests/Tools/Stages/Stage2/OptimizeTests.cs @@ -0,0 +1,6 @@ +namespace CLVMDotNet.Tests.Tools.Stages.Stage2; + +public class OptimizeTests +{ + +} \ No newline at end of file From dea43043cc7c1ed05996eb420b6b1f06cb57ed01 Mon Sep 17 00:00:00 2001 From: kev Date: Sat, 27 Jan 2024 16:52:23 +0000 Subject: [PATCH 12/29] Added Quote --- CLVMDotNet/src/Tools/Stages/Stage2/Helpers.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/CLVMDotNet/src/Tools/Stages/Stage2/Helpers.cs b/CLVMDotNet/src/Tools/Stages/Stage2/Helpers.cs index 5e75c83..0dd0561 100644 --- a/CLVMDotNet/src/Tools/Stages/Stage2/Helpers.cs +++ b/CLVMDotNet/src/Tools/Stages/Stage2/Helpers.cs @@ -1,6 +1,14 @@ +using CLVMDotNet.CLVM; + namespace CLVMDotNet.Tools.Stages.Stage2; -public class Helpers +public static class Helpers { - + public static byte QUOTE_ATOM => Keywords.KEYWORD_TO_ATOM["q"]; + public static byte APPLY_ATOM => Keywords.KEYWORD_TO_ATOM["a"]; + + public static Tuple Quote(SExp sexp) + { + return Tuple.Create(QUOTE_ATOM, sexp); + } } \ No newline at end of file From ac312d1dacb82eb43502c846b8a87332c62ecedd Mon Sep 17 00:00:00 2001 From: kev Date: Sat, 27 Jan 2024 17:05:05 +0000 Subject: [PATCH 13/29] Added NonNil --- CLVMDotNet/src/Tools/NodePath.cs | 6 ++++++ CLVMDotNet/src/Tools/Stages/Stage2/Optimize.cs | 16 ++++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 CLVMDotNet/src/Tools/NodePath.cs diff --git a/CLVMDotNet/src/Tools/NodePath.cs b/CLVMDotNet/src/Tools/NodePath.cs new file mode 100644 index 0000000..9a989c5 --- /dev/null +++ b/CLVMDotNet/src/Tools/NodePath.cs @@ -0,0 +1,6 @@ +namespace CLVMDotNet.Tools; + +public class NodePath +{ + +} \ No newline at end of file diff --git a/CLVMDotNet/src/Tools/Stages/Stage2/Optimize.cs b/CLVMDotNet/src/Tools/Stages/Stage2/Optimize.cs index 23329d0..7e4543f 100644 --- a/CLVMDotNet/src/Tools/Stages/Stage2/Optimize.cs +++ b/CLVMDotNet/src/Tools/Stages/Stage2/Optimize.cs @@ -3,7 +3,19 @@ namespace CLVMDotNet.Tools.Stages.Stage2; -public class Optimize +public static class Optimize { - + public static byte QUOTE_ATOM => Keywords.KEYWORD_TO_ATOM["q"]; + public static byte APPLY_ATOM => Keywords.KEYWORD_TO_ATOM["a"]; + public static byte FIRST_ATOM => Keywords.KEYWORD_TO_ATOM["f"]; + public static byte REST_ATOM => Keywords.KEYWORD_TO_ATOM["r"]; + public static byte CONS_ATOM => Keywords.KEYWORD_TO_ATOM["c"]; + public static byte RAISE_ATOM => Keywords.KEYWORD_TO_ATOM["x"]; + public static int DEBUG_OPTIMIZATIONS = 0; + public static SExp CONS_Q_A_OPTIMIZER_PATTERN => BinUtils.Assemble("(a (q . (: . sexp)) (: . args))"); + + public static bool NonNil(SExp sexp) + { + return sexp.Listp() || (sexp.AsAtom().Length > 0); + } } \ No newline at end of file From 5cb16e1e67a8941024576baf4889725c89535b5b Mon Sep 17 00:00:00 2001 From: kev Date: Sat, 27 Jan 2024 17:11:34 +0000 Subject: [PATCH 14/29] Added IsArgsCall --- CLVMDotNet/src/Tools/Stages/Stage2/Optimize.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/CLVMDotNet/src/Tools/Stages/Stage2/Optimize.cs b/CLVMDotNet/src/Tools/Stages/Stage2/Optimize.cs index 7e4543f..5cfa853 100644 --- a/CLVMDotNet/src/Tools/Stages/Stage2/Optimize.cs +++ b/CLVMDotNet/src/Tools/Stages/Stage2/Optimize.cs @@ -13,9 +13,25 @@ public static class Optimize public static byte RAISE_ATOM => Keywords.KEYWORD_TO_ATOM["x"]; public static int DEBUG_OPTIMIZATIONS = 0; public static SExp CONS_Q_A_OPTIMIZER_PATTERN => BinUtils.Assemble("(a (q . (: . sexp)) (: . args))"); + public static SExp CONS_PATTERN = BinUtils.Assemble("(c (: . first) (: . rest)))"); + public static SExp VAR_CHANGE_OPTIMIZER_CONS_EVAL_PATTERN = BinUtils.Assemble("(a (q . (: . sexp)) (: . args))"); + public static SExp CONS_OPTIMIZER_PATTERN_FIRST = BinUtils.Assemble("(f (c (: . first) (: . rest)))"); + public static SExp CONS_OPTIMIZER_PATTERN_REST = BinUtils.Assemble("(r (c (: . first) (: . rest)))"); + public static SExp FIRST_ATOM_PATTERN = BinUtils.Assemble("(f ($ . atom))"); + public static SExp REST_ATOM_PATTERN = BinUtils.Assemble("(r ($ . atom))"); + public static SExp QUOTE_PATTERN_1 = BinUtils.Assemble("(q . 0)"); + public static SExp APPLY_NULL_PATTERN_1 = BinUtils.Assemble("(a 0 . (: . rest))"); + public static bool NonNil(SExp sexp) { return sexp.Listp() || (sexp.AsAtom().Length > 0); } + + public static bool IsArgsCall(SExp r) + { + if (!r.Listp() && r.AsInt() == 1) + return true; + return false; + } } \ No newline at end of file From bab35bf4518d2a5e5c1f69084a63a8b6530f12f7 Mon Sep 17 00:00:00 2001 From: kev Date: Sat, 27 Jan 2024 17:25:31 +0000 Subject: [PATCH 15/29] . --- CLVMDotNet/src/Tools/Stages/Stage2/Compile.cs | 8 ++++++-- CLVMDotNet/src/Tools/Stages/Stage2/Operators.cs | 7 +++++-- CLVMDotNet/src/Tools/Stages/Stage2/PatternMatch.cs | 6 ++++++ 3 files changed, 17 insertions(+), 4 deletions(-) create mode 100644 CLVMDotNet/src/Tools/Stages/Stage2/PatternMatch.cs diff --git a/CLVMDotNet/src/Tools/Stages/Stage2/Compile.cs b/CLVMDotNet/src/Tools/Stages/Stage2/Compile.cs index 4eb4a97..440f826 100644 --- a/CLVMDotNet/src/Tools/Stages/Stage2/Compile.cs +++ b/CLVMDotNet/src/Tools/Stages/Stage2/Compile.cs @@ -1,6 +1,10 @@ +using CLVMDotNet.CLVM; + namespace CLVMDotNet.Tools.Stages.Stage2; -public class Compile +public static class Compile { - + public static byte QUOTE_ATOM => Keywords.KEYWORD_TO_ATOM["q"]; + public static byte APPLY_ATOM => Keywords.KEYWORD_TO_ATOM["a"]; + public static byte CONS_ATOM => Keywords.KEYWORD_TO_ATOM["c"]; } \ No newline at end of file diff --git a/CLVMDotNet/src/Tools/Stages/Stage2/Operators.cs b/CLVMDotNet/src/Tools/Stages/Stage2/Operators.cs index 602693b..af76c60 100644 --- a/CLVMDotNet/src/Tools/Stages/Stage2/Operators.cs +++ b/CLVMDotNet/src/Tools/Stages/Stage2/Operators.cs @@ -1,6 +1,9 @@ +using System.Numerics; +using System.Runtime.InteropServices.JavaScript; +using CLVMDotNet.CLVM; + namespace CLVMDotNet.Tools.Stages.Stage2; -public class Operators +public static class Operators { - } \ No newline at end of file diff --git a/CLVMDotNet/src/Tools/Stages/Stage2/PatternMatch.cs b/CLVMDotNet/src/Tools/Stages/Stage2/PatternMatch.cs new file mode 100644 index 0000000..4338299 --- /dev/null +++ b/CLVMDotNet/src/Tools/Stages/Stage2/PatternMatch.cs @@ -0,0 +1,6 @@ +namespace CLVMDotNet.Tools.Stages.Stage2; + +public class PatternMatch +{ + +} \ No newline at end of file From 49e88c31c15e6d1677be005f62ce737bfb04fc80 Mon Sep 17 00:00:00 2001 From: kev Date: Sun, 28 Jan 2024 20:57:06 +0000 Subject: [PATCH 16/29] Interim nodepath --- CLVMDotNet/src/Tools/NodePath.cs | 38 +++++++++++++++++++ .../src/Tools/Stages/Stage2/Defaults.cs | 5 ++- CLVMDotNet/src/Tools/Stages/Stage2/Helpers.cs | 3 ++ CLVMDotNet/src/Tools/Stages/Stage2/Mod.cs | 22 ++++++++++- .../src/Tools/Stages/Stage2/Optimize.cs | 19 ++++++++++ CLVMDotNet/tests/Tools/NodePathTests.cs | 6 +++ 6 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 CLVMDotNet/tests/Tools/NodePathTests.cs diff --git a/CLVMDotNet/src/Tools/NodePath.cs b/CLVMDotNet/src/Tools/NodePath.cs index 9a989c5..cce1387 100644 --- a/CLVMDotNet/src/Tools/NodePath.cs +++ b/CLVMDotNet/src/Tools/NodePath.cs @@ -1,6 +1,44 @@ +using System.Numerics; + namespace CLVMDotNet.Tools; public class NodePath { + public static NodePath TOP => new NodePath(); + public static NodePath Left => NodePath.First(); + public static NodePath Right => NodePath.Rest(); + public BigInteger ByteCount { get; private set; } + public byte[] Blob { get; private set; } + public int _index { get; private set; } + + public NodePath(int index = 0) + { + if (index < 0) + { + //bytecount + //blob + //index + } + else + { + _index = index; + } + } + + public static NodePath First() + { + return null; + } + + public static NodePath Rest() + { + return null; + } + + //ComposePath + //AsShortPath + //Add + //Str + //Repr } \ No newline at end of file diff --git a/CLVMDotNet/src/Tools/Stages/Stage2/Defaults.cs b/CLVMDotNet/src/Tools/Stages/Stage2/Defaults.cs index 2e1d7ac..0db56f3 100644 --- a/CLVMDotNet/src/Tools/Stages/Stage2/Defaults.cs +++ b/CLVMDotNet/src/Tools/Stages/Stage2/Defaults.cs @@ -2,5 +2,8 @@ namespace CLVMDotNet.Tools.Stages.Stage2; public class Defaults { - + //DEFAULT_MACROS_SRC + //DEFAULT_MACRO_LOOKUP + //build_default_macro_lookup + //default_macro_lookup } \ No newline at end of file diff --git a/CLVMDotNet/src/Tools/Stages/Stage2/Helpers.cs b/CLVMDotNet/src/Tools/Stages/Stage2/Helpers.cs index 0dd0561..12521ab 100644 --- a/CLVMDotNet/src/Tools/Stages/Stage2/Helpers.cs +++ b/CLVMDotNet/src/Tools/Stages/Stage2/Helpers.cs @@ -11,4 +11,7 @@ public static Tuple Quote(SExp sexp) { return Tuple.Create(QUOTE_ATOM, sexp); } + + //Run + //Brun } \ No newline at end of file diff --git a/CLVMDotNet/src/Tools/Stages/Stage2/Mod.cs b/CLVMDotNet/src/Tools/Stages/Stage2/Mod.cs index 99c4b63..b639cd2 100644 --- a/CLVMDotNet/src/Tools/Stages/Stage2/Mod.cs +++ b/CLVMDotNet/src/Tools/Stages/Stage2/Mod.cs @@ -1,6 +1,26 @@ +using CLVMDotNet.CLVM; + namespace CLVMDotNet.Tools.Stages.Stage2; -public class Mod +public static class Mod { + public static byte QUOTE_ATOM => Keywords.KEYWORD_TO_ATOM["q"]; + public static byte CONS_ATOM => Keywords.KEYWORD_TO_ATOM["c"]; + public static byte[] MAIN_NAME => new byte[] { }; + + //BuildTree (Tuple) + //BuildTreeProgram + //Flattern + //BuildUsedConstantNames + //ParseInclude + //UnquoteArgs + //DefunInlineToMacro + //ParseModSexp + //CompileModStage1 + //SymbolTableToTree + //BuildMacroLookupTable + //CompileFunctions + //CompileMod + } \ No newline at end of file diff --git a/CLVMDotNet/src/Tools/Stages/Stage2/Optimize.cs b/CLVMDotNet/src/Tools/Stages/Stage2/Optimize.cs index 5cfa853..fa4c103 100644 --- a/CLVMDotNet/src/Tools/Stages/Stage2/Optimize.cs +++ b/CLVMDotNet/src/Tools/Stages/Stage2/Optimize.cs @@ -34,4 +34,23 @@ public static bool IsArgsCall(SExp r) return true; return false; } + + //DoRead + //DoWrite + //RunProgramForSearchPaths + //SeemsConstant + //ConstantOptimizer + //IsArgsCall + //ConsF + //ConsR + //PathFromArgs + //SubArgs + //var_change_optimizer_cons_eval + //children_optimizer + //cons_optimizer + //path_optimizer + //def quote_null_optimizer(r, eval) + //apply_null_optimizer + //optimize_sexp + //make_do_opt } \ No newline at end of file diff --git a/CLVMDotNet/tests/Tools/NodePathTests.cs b/CLVMDotNet/tests/Tools/NodePathTests.cs new file mode 100644 index 0000000..203eb8b --- /dev/null +++ b/CLVMDotNet/tests/Tools/NodePathTests.cs @@ -0,0 +1,6 @@ +namespace CLVMDotNet.Tests.Tools; + +public class NodePathTests +{ + +} \ No newline at end of file From 5fe44e50e928012bf4910f411c447ad17fb0da45 Mon Sep 17 00:00:00 2001 From: kev Date: Mon, 29 Jan 2024 11:40:35 +0000 Subject: [PATCH 17/29] Added NodePath --- CLVMDotNet/src/Tools/NodePath.cs | 114 ++++++++++++++++++++---- CLVMDotNet/tests/Tools/NodePathTests.cs | 18 +++- 2 files changed, 113 insertions(+), 19 deletions(-) diff --git a/CLVMDotNet/src/Tools/NodePath.cs b/CLVMDotNet/src/Tools/NodePath.cs index cce1387..b24aa33 100644 --- a/CLVMDotNet/src/Tools/NodePath.cs +++ b/CLVMDotNet/src/Tools/NodePath.cs @@ -4,20 +4,25 @@ namespace CLVMDotNet.Tools; public class NodePath { - public static NodePath TOP => new NodePath(); - public static NodePath Left => NodePath.First(); - public static NodePath Right => NodePath.Rest(); - public BigInteger ByteCount { get; private set; } + public static NodePath TOP => new NodePath(1); + public static NodePath Left => TOP.First(); + public static NodePath Right => TOP.Rest(); + public BigInteger ByteCount { get; private set; } public byte[] Blob { get; private set; } - public int _index { get; private set; } + public BigInteger _index { get; private set; } - public NodePath(int index = 0) + public NodePath(BigInteger index) { if (index < 0) { - //bytecount - //blob - //index + var log = index + 1; + int byteCount = (int)Math.Ceiling(BigInteger.Log(log, 256) / 8); + byteCount = (byteCount + 7) / 8; + byte[] blob = index.ToByteArray(); + Array.Reverse(blob); + byte[] resultBlob = new byte[byteCount + 1]; + Array.Copy(blob, 0, resultBlob, 1, byteCount); + _index = new BigInteger(resultBlob); } else { @@ -25,20 +30,93 @@ public NodePath(int index = 0) } } - public static NodePath First() + public NodePath First() { - return null; + BigInteger newIndex = _index * 2; + return new NodePath(newIndex); } - public static NodePath Rest() + public NodePath Rest() { - return null; + BigInteger newIndex = _index * 2 + 1; + return new NodePath(newIndex); } + public static string ByteArrayToHexString(byte[] byteArray) + { + return string.Concat(byteArray.Select(b => b.ToString("X2"))); + } + + public byte[] AsShortPath() + { + BigInteger index = _index; + int byteCount = Math.Max(1, (int)Math.Ceiling(BigInteger.Log(index, 256) / 8)); + byte[] byteArray = index.ToByteArray(); + Array.Reverse(byteArray); // Reverse the byte array if needed + + // Ensure the result has the correct byteCount + if (byteArray.Length > byteCount) + { + Array.Resize(ref byteArray, byteCount); + } + else if (byteArray.Length < byteCount) + { + // If the byte array is shorter than required, add leading zeros + byte[] paddedArray = new byte[byteCount]; + byteArray.CopyTo(paddedArray, byteCount - byteArray.Length); + byteArray = paddedArray; + } + + return byteArray; + } + + public NodePath Add(NodePath otherNode) + { + BigInteger resultIndex = ComposePaths(_index, otherNode._index); + return new NodePath(resultIndex); + } + + + /// + /// The binary representation of a path is a 1 (which means "stop"), followed by the path as binary digits, + /// where 0 is "left" and 1 is "right". + /// + /// Look at the diagram at the top for these examples. + /// + /// Example: 9 = 0b1001, so right, left, left + /// Example: 10 = 0b1010, so left, right, left + /// + /// How it works: we write both numbers as binary. We ignore the terminal in path_0, since it's + /// not the terminating condition anymore. We shift path_1 enough places to OR in the rest of path_0. + /// + /// Example: path_0 = 9 = 0b1001, path_1 = 10 = 0b1010. + /// + /// Shift path_1 three places (so there is room for 0b001) to 0b1010000. + /// Then OR in 0b001 to yield 0b1010001 = 81, which is right, left, left, left, right, left. + /// + /// + /// + /// + public BigInteger ComposePaths(BigInteger path0, BigInteger path1) + { + BigInteger mask = 1; + BigInteger temp_path = path0; + + while (temp_path > 1) + { + path1 <<= 1; + mask <<= 1; + temp_path >>= 1; + } + + mask -= 1; + BigInteger path = path1 | (path0 & mask); + + return path; + } - //ComposePath - //AsShortPath - //Add - //Str - //Repr + public override string ToString() + { + return $"NodePath: {_index}"; + } } \ No newline at end of file diff --git a/CLVMDotNet/tests/Tools/NodePathTests.cs b/CLVMDotNet/tests/Tools/NodePathTests.cs index 203eb8b..eda3bab 100644 --- a/CLVMDotNet/tests/Tools/NodePathTests.cs +++ b/CLVMDotNet/tests/Tools/NodePathTests.cs @@ -1,6 +1,22 @@ +using CLVMDotNet.Tools; +using Xunit; + namespace CLVMDotNet.Tests.Tools; public class NodePathTests { - + [Fact] + public void TestNodePath() + { + // Arrange + var top = NodePath.TOP; + var n = top; + n.Add(NodePath.Left); + + // Act + var path = n.AsShortPath(); + + // Assert + Assert.Equal("01", NodePath.ByteArrayToHexString(path)); + } } \ No newline at end of file From 5bf40c671232088de04e30758d854a0fe5c1467a Mon Sep 17 00:00:00 2001 From: kev Date: Mon, 29 Jan 2024 12:56:43 +0000 Subject: [PATCH 18/29] Tests --- CLVMDotNet/src/Tools/NodePath.cs | 18 +- CLVMDotNet/tests/Tools/NodePathTests.cs | 238 ++++++++++++++++++++++++ 2 files changed, 240 insertions(+), 16 deletions(-) diff --git a/CLVMDotNet/src/Tools/NodePath.cs b/CLVMDotNet/src/Tools/NodePath.cs index b24aa33..5e15a9c 100644 --- a/CLVMDotNet/src/Tools/NodePath.cs +++ b/CLVMDotNet/src/Tools/NodePath.cs @@ -44,28 +44,14 @@ public NodePath Rest() public static string ByteArrayToHexString(byte[] byteArray) { - return string.Concat(byteArray.Select(b => b.ToString("X2"))); + return string.Join("", byteArray.SkipWhile(b => b == 0).Select(b => b.ToString("X2"))); } public byte[] AsShortPath() { BigInteger index = _index; - int byteCount = Math.Max(1, (int)Math.Ceiling(BigInteger.Log(index, 256) / 8)); byte[] byteArray = index.ToByteArray(); - Array.Reverse(byteArray); // Reverse the byte array if needed - - // Ensure the result has the correct byteCount - if (byteArray.Length > byteCount) - { - Array.Resize(ref byteArray, byteCount); - } - else if (byteArray.Length < byteCount) - { - // If the byte array is shorter than required, add leading zeros - byte[] paddedArray = new byte[byteCount]; - byteArray.CopyTo(paddedArray, byteCount - byteArray.Length); - byteArray = paddedArray; - } + Array.Reverse(byteArray); return byteArray; } diff --git a/CLVMDotNet/tests/Tools/NodePathTests.cs b/CLVMDotNet/tests/Tools/NodePathTests.cs index eda3bab..92e29b9 100644 --- a/CLVMDotNet/tests/Tools/NodePathTests.cs +++ b/CLVMDotNet/tests/Tools/NodePathTests.cs @@ -1,3 +1,5 @@ +using System.Globalization; +using System.Numerics; using CLVMDotNet.Tools; using Xunit; @@ -5,10 +7,57 @@ namespace CLVMDotNet.Tests.Tools; public class NodePathTests { + public NodePath Reset(NodePath n) + { + byte[] pathBlob = n.AsShortPath(); + BigInteger index = new BigInteger(pathBlob); + NodePath newNodePath = new NodePath(index); + return newNodePath; + } + + + public static bool IsValidBinaryString(string binaryString) + { + foreach (char c in binaryString) + { + if (c != '0' && c != '1') + { + return false; + } + } + return true; + } + + public bool CmpToBits(NodePath n, string bits) + { + byte[] pathBlob = n.AsShortPath(); + var hex = NodePath.ByteArrayToHexString(pathBlob); + BigInteger nAsInt = BigInteger.Parse(hex, NumberStyles.HexNumber); + + if (!IsValidBinaryString(bits)) + { + throw new ArgumentException("Invalid binary string", nameof(bits)); + } + + BigInteger result = 0; + for (int i = bits.Length - 1, j = 0; i >= 0; i--, j++) + { + if (bits[i] == '1') + { + result += BigInteger.Pow(2, j); + } + } + + return nAsInt == result; + } + [Fact] public void TestNodePath() { // Arrange + var left_right_left = NodePath.Left + .Add(NodePath.Right) + .Add(NodePath.Left); var top = NodePath.TOP; var n = top; n.Add(NodePath.Left); @@ -19,4 +68,193 @@ public void TestNodePath() // Assert Assert.Equal("01", NodePath.ByteArrayToHexString(path)); } + + [Fact] + public void TestTopPlusLeft() + { + // Arrange + var n = NodePath.TOP + .Add(NodePath.Left); + + // Act + var path = n.AsShortPath(); + + // Assert + Assert.Equal("02", NodePath.ByteArrayToHexString(path)); + } + + [Fact] + public void TestToplusLeftPlusRight() + { + // Arrange + var n = NodePath.TOP + .Add(NodePath.Left) + .Add(NodePath.Right); + + // Act + var path = n.AsShortPath(); + + // Assert + Assert.Equal("06", NodePath.ByteArrayToHexString(path)); + } + + [Fact] + public void TestToplusLeftPlusRightPlusRight() + { + // Arrange + var n = NodePath.TOP + .Add(NodePath.Left) + .Add(NodePath.Right) + .Add(NodePath.Right); + + // Act + var path = n.AsShortPath(); + + // Assert + Assert.Equal("0E", NodePath.ByteArrayToHexString(path)); + } + + [Fact] + public void TestToplusLeftPlusRightPlusRightPlusLeft() + { + // Arrange + var n = NodePath.TOP + .Add(NodePath.Left) + .Add(NodePath.Right) + .Add(NodePath.Right) + .Add(NodePath.Left); + + // Act + var path = n.AsShortPath(); + + // Assert + Assert.Equal("16", NodePath.ByteArrayToHexString(path)); + } + + [Fact] + public void TestToplusLeftPlusRightPlusRightPlusLeftPlusLeft() + { + // Arrange + var n = NodePath.TOP + .Add(NodePath.Left) + .Add(NodePath.Right) + .Add(NodePath.Right) + .Add(NodePath.Left) + .Add(NodePath.Left); + + // Act + var path = n.AsShortPath(); + + // Assert + Assert.Equal("26", NodePath.ByteArrayToHexString(path)); + } + + [Fact] + public void TestToplusLeftPlusRightPlusRightPlusLeftPlusLeftPlusLeft() + { + // Arrange + var n = NodePath.TOP + .Add(NodePath.Left) + .Add(NodePath.Right) + .Add(NodePath.Right) + .Add(NodePath.Left) + .Add(NodePath.Left) + .Add(NodePath.Left); + + // Act + var path = n.AsShortPath(); + + // Assert + Assert.Equal("46", NodePath.ByteArrayToHexString(path)); + } + + [Fact] public void TestToplusLeftPlusRightPlusRightPlusLeftPlusLeftPlusLeftPlusRight() + { + // Arrange + var n = NodePath.TOP + .Add(NodePath.Left) + .Add(NodePath.Right) + .Add(NodePath.Right) + .Add(NodePath.Left) + .Add(NodePath.Left) + .Add(NodePath.Left) + .Add(NodePath.Right); + + // Act + var path = n.AsShortPath(); + + // Assert + Assert.Equal("C6", NodePath.ByteArrayToHexString(path)); + } + + [Fact] public void TestToplusLeftPlusRightPlusRightPlusLeftPlusLeftPlusLeftPlusRightPlusLeft() + { + // Arrange + var n = NodePath.TOP + .Add(NodePath.Left) + .Add(NodePath.Right) + .Add(NodePath.Right) + .Add(NodePath.Left) + .Add(NodePath.Left) + .Add(NodePath.Left) + .Add(NodePath.Right) + .Add(NodePath.Left); + + // Act + var path = n.AsShortPath(); + + // Assert + Assert.True(CmpToBits(n, "101000110")); + } + + [Fact] public void TestToplusLeftPlusRightPlusRightPlusLeftPlusLeftPlusLeftPlusRightPlusLeftPlusLeftRightLeft() + { + // Arrange + var LeftRightLeft = NodePath.Left + .Add(NodePath.Right) + .Add(NodePath.Left); + var n = NodePath.TOP + .Add(NodePath.Left) + .Add(NodePath.Right) + .Add(NodePath.Right) + .Add(NodePath.Left) + .Add(NodePath.Left) + .Add(NodePath.Left) + .Add(NodePath.Right) + .Add(NodePath.Left) + .Add(LeftRightLeft); + + // Act + var path = n.AsShortPath(); + + // Assert + Assert.True(CmpToBits(n, "101001000110")); + } + + [Fact] public void AddLeftRightLeft() + { + // Arrange + var leftRightLeft = NodePath.Left + .Add(NodePath.Right) + .Add(NodePath.Left); + + var n = NodePath.TOP + .Add(NodePath.Left) + .Add(NodePath.Right) + .Add(NodePath.Right) + .Add(NodePath.Left) + .Add(NodePath.Left) + .Add(NodePath.Left) + .Add(NodePath.Right) + .Add(NodePath.Left) + .Add(leftRightLeft) + .Add(leftRightLeft) + .Add(leftRightLeft); + + // Act + var isSameBits = CmpToBits(n, "101001001001000110"); + + // Assert + Assert.True(isSameBits); + } } \ No newline at end of file From 7e002ecd6a05b712e6a475d996f804166e323000 Mon Sep 17 00:00:00 2001 From: kev Date: Mon, 29 Jan 2024 18:53:59 +0000 Subject: [PATCH 19/29] added default_macros_src --- .../src/Tools/Stages/Stage2/Defaults.cs | 64 ++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/CLVMDotNet/src/Tools/Stages/Stage2/Defaults.cs b/CLVMDotNet/src/Tools/Stages/Stage2/Defaults.cs index 0db56f3..b3c9ccc 100644 --- a/CLVMDotNet/src/Tools/Stages/Stage2/Defaults.cs +++ b/CLVMDotNet/src/Tools/Stages/Stage2/Defaults.cs @@ -2,7 +2,69 @@ namespace CLVMDotNet.Tools.Stages.Stage2; public class Defaults { - //DEFAULT_MACROS_SRC + public static List DefaultMacrosSrc => new List + { + @" + // we have to compile this externally, since it uses itself + // (defmacro defmacro (name params body) + // (qq (list (unquote name) (mod (unquote params) (unquote body)))) + // ) + (q . (""defmacro"" + (c (q . ""list"") + (c (f 1) + (c (c (q . ""mod"") + (c (f (r 1)) + (c (f (r (r 1))) + (q . ())))) + (q . ())))))) + ", + @" + // (defmacro list ARGS + // ((c (mod args + // (defun compile-list + // (args) + // (if args + // (qq (c (unquote (f args)) + // (unquote (compile-list (r args))))) + // ())) + // (compile-list args) + // ) + // ARGS + // )) + // ) + (q ""list"" + (a (q #a (q #a 2 (c 2 (c 3 (q)))) + (c (q #a (i 5 + (q #c (q . 4) + (c 9 (c (a 2 (c 2 (c 13 (q)))) + (q))) + ) + (q 1)) + 1)) + 1)) + ", + @" + (defmacro function (BODY) + (qq (opt (com (q . (unquote BODY)) + (qq (unquote (macros))) + (qq (unquote (symbols))))))) + ", + @" + (defmacro if (A B C) + (qq (a + (i (unquote A) + (function (unquote B)) + (function (unquote C))) + @))) + ", + // / operator at the clvm layer is becoming deprecated and + // will be implemented using divmod. + @" + (defmacro / (A B) (qq (f (divmod (unquote A) (unquote B))))) + " + }; + + //DEFAULT_MACRO_LOOKUP //build_default_macro_lookup //default_macro_lookup From ef1ac1bcc74e71802ab53e1a2334bffd1092fa98 Mon Sep 17 00:00:00 2001 From: kev Date: Mon, 29 Jan 2024 19:39:53 +0000 Subject: [PATCH 20/29] Added Flatten & build_tree_program --- CLVMDotNet/src/Tools/Stages/Stage2/Helpers.cs | 6 +++ CLVMDotNet/src/Tools/Stages/Stage2/Mod.cs | 53 ++++++++++++++++++- .../src/Tools/Stages/Stage2/Operators.cs | 22 +++++++- 3 files changed, 78 insertions(+), 3 deletions(-) diff --git a/CLVMDotNet/src/Tools/Stages/Stage2/Helpers.cs b/CLVMDotNet/src/Tools/Stages/Stage2/Helpers.cs index 12521ab..1847ad2 100644 --- a/CLVMDotNet/src/Tools/Stages/Stage2/Helpers.cs +++ b/CLVMDotNet/src/Tools/Stages/Stage2/Helpers.cs @@ -11,6 +11,12 @@ public static Tuple Quote(SExp sexp) { return Tuple.Create(QUOTE_ATOM, sexp); } + + public static SExp Eval(SExp prog, dynamic args) + { + var eval = SExp.To(new List() { APPLY_ATOM, prog, args }); + return eval; + } //Run //Brun diff --git a/CLVMDotNet/src/Tools/Stages/Stage2/Mod.cs b/CLVMDotNet/src/Tools/Stages/Stage2/Mod.cs index b639cd2..a612c88 100644 --- a/CLVMDotNet/src/Tools/Stages/Stage2/Mod.cs +++ b/CLVMDotNet/src/Tools/Stages/Stage2/Mod.cs @@ -8,8 +8,57 @@ public static class Mod public static byte CONS_ATOM => Keywords.KEYWORD_TO_ATOM["c"]; public static byte[] MAIN_NAME => new byte[] { }; - //BuildTree (Tuple) - //BuildTreeProgram + /// + /// This function takes a Python list of items and turns it into a binary tree + /// of the items, suitable for casting to an s-expression. + /// + /// + public dynamic BuildTree(List items) + { + var size = items.Count; + if (size == 0) + return new List(); + if (size == 1) + return items[0]; + + int halfSize = size / 2; + dynamic left = BuildTree(items.GetRange(0, halfSize)); + dynamic right = BuildTree(items.GetRange(halfSize, size - halfSize)); + return new Tuple(left, right); + } + + /// + /// his function takes a Python list of items and turns it into a program that + /// builds a binary tree of the items, suitable for casting to an s-expression. + /// + /// + public List BuildTreeProgram(List items) + { + var size = items.Count; + if (size == 0) + return new List(); + if (size == 1) + return items[0]; + + int halfSize = size / 2; + dynamic left = BuildTreeProgram(items.GetRange(0, halfSize)); + dynamic right = BuildTreeProgram(items.GetRange(halfSize, size - halfSize)); + return new List { CONS_ATOM, left, right }; + } + + public List Flatten(SExp sexp) + { + if (sexp.Listp()) + { + List result = new List(); + result.AddRange(Flatten(sexp.First())); + result.AddRange(Flatten(sexp.Rest())); + return result; + } + return new List { sexp.AsAtom() }; + } + + //Flattern //BuildUsedConstantNames //ParseInclude diff --git a/CLVMDotNet/src/Tools/Stages/Stage2/Operators.cs b/CLVMDotNet/src/Tools/Stages/Stage2/Operators.cs index af76c60..1ecc79a 100644 --- a/CLVMDotNet/src/Tools/Stages/Stage2/Operators.cs +++ b/CLVMDotNet/src/Tools/Stages/Stage2/Operators.cs @@ -1,9 +1,29 @@ using System.Numerics; -using System.Runtime.InteropServices.JavaScript; +using System.Text; using CLVMDotNet.CLVM; +using CLVMDotNet.Tools.IR; namespace CLVMDotNet.Tools.Stages.Stage2; public static class Operators { + public static Tuple DoRead(SExp args) + { + var filename = args.First().AsAtom(); + string filepath = Encoding.UTF8.GetString(filename); + string s = File.ReadAllText(filepath); + var irSexp = SExp.To(IR.IRReader.ReadIR(s)); + var sexp = BinUtils.AssembleFromIR(irSexp); + return new Tuple(1, sexp); + } + + public static Tuple DoWrite(SExp args) + { + var filename = args.First().AsAtom(); + string filepath = Encoding.UTF8.GetString(filename); + string s = File.ReadAllText(filepath); + var irSexp = SExp.To(IR.IRReader.ReadIR(s)); + var sexp = BinUtils.AssembleFromIR(irSexp); + return new Tuple(1, sexp); + } } \ No newline at end of file From 6063381dcd9fc6840496f0ecc5103de8ad815932 Mon Sep 17 00:00:00 2001 From: kev Date: Mon, 29 Jan 2024 19:42:54 +0000 Subject: [PATCH 21/29] Fix build --- CLVMDotNet/src/Tools/Stages/Stage2/Mod.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CLVMDotNet/src/Tools/Stages/Stage2/Mod.cs b/CLVMDotNet/src/Tools/Stages/Stage2/Mod.cs index a612c88..da0180e 100644 --- a/CLVMDotNet/src/Tools/Stages/Stage2/Mod.cs +++ b/CLVMDotNet/src/Tools/Stages/Stage2/Mod.cs @@ -13,7 +13,7 @@ public static class Mod /// of the items, suitable for casting to an s-expression. /// /// - public dynamic BuildTree(List items) + public static dynamic BuildTree(List items) { var size = items.Count; if (size == 0) @@ -32,7 +32,7 @@ public dynamic BuildTree(List items) /// builds a binary tree of the items, suitable for casting to an s-expression. /// /// - public List BuildTreeProgram(List items) + public static List BuildTreeProgram(List items) { var size = items.Count; if (size == 0) @@ -46,7 +46,7 @@ public List BuildTreeProgram(List items) return new List { CONS_ATOM, left, right }; } - public List Flatten(SExp sexp) + public static List Flatten(SExp sexp) { if (sexp.Listp()) { From da5beb5ee525175e4a4520bef50b8ea94b1622c3 Mon Sep 17 00:00:00 2001 From: kev Date: Mon, 29 Jan 2024 19:49:51 +0000 Subject: [PATCH 22/29] Added SeemsConstant --- .../src/Tools/Stages/Stage2/Optimize.cs | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/CLVMDotNet/src/Tools/Stages/Stage2/Optimize.cs b/CLVMDotNet/src/Tools/Stages/Stage2/Optimize.cs index fa4c103..bbf3dca 100644 --- a/CLVMDotNet/src/Tools/Stages/Stage2/Optimize.cs +++ b/CLVMDotNet/src/Tools/Stages/Stage2/Optimize.cs @@ -35,6 +35,36 @@ public static bool IsArgsCall(SExp r) return false; } + public static bool SeemsConstant(SExp sexp) + { + if (!sexp.Listp()) + { + // note that `0` is a constant + return !NonNil(sexp); + } + var operatorSexp = sexp.First(); + if (!operatorSexp.Listp()) + { + //TODO: test that a byte array can be compared to a byte + var asAtom = operatorSexp.AsAtom(); + if (asAtom.Equals(QUOTE_ATOM)) + { + return true; + } + + if (asAtom.Equals(RAISE_ATOM)) + { + return false; + } + } + else if (!SeemsConstant(operatorSexp)) + { + return false; + } + return sexp.Rest().AsIter().All(childSexp => SeemsConstant(childSexp)); + } + + //DoRead //DoWrite //RunProgramForSearchPaths From 877fac43f948507810516e1667a40ec89d6293f1 Mon Sep 17 00:00:00 2001 From: kev Date: Mon, 29 Jan 2024 20:45:31 +0000 Subject: [PATCH 23/29] Added cons_r and cons_f --- .../src/Tools/Stages/Stage2/Optimize.cs | 67 ++++++++++++++- .../src/Tools/Stages/Stage2/PatternMatch.cs | 83 +++++++++++++++++++ 2 files changed, 148 insertions(+), 2 deletions(-) diff --git a/CLVMDotNet/src/Tools/Stages/Stage2/Optimize.cs b/CLVMDotNet/src/Tools/Stages/Stage2/Optimize.cs index bbf3dca..5e148e2 100644 --- a/CLVMDotNet/src/Tools/Stages/Stage2/Optimize.cs +++ b/CLVMDotNet/src/Tools/Stages/Stage2/Optimize.cs @@ -64,6 +64,71 @@ public static bool SeemsConstant(SExp sexp) return sexp.Rest().AsIter().All(childSexp => SeemsConstant(childSexp)); } + public static SExp PathFromArgs(SExp sexp, dynamic newArgs) + { + var v = sexp.AsInt(); + if (v <= 1) + { + return newArgs; + } + sexp = SExp.To(v >> 1); + if ((v & 1) == 1) + { + return PathFromArgs(sexp, ConsR(newArgs)); + } + return PathFromArgs(sexp, ConsF(newArgs)); + } + + public static SExp ConsF(SExp args) + { + Dictionary t = PatternMatch.Match(CONS_PATTERN, args); + + if (t != null && t.ContainsKey("first")) + { + return t["first"]; + } + return SExp.To(new List { FIRST_ATOM, args}); + } + + public static SExp ConsR(SExp args) + { + Dictionary t = PatternMatch.Match(CONS_PATTERN, args); + + if (t != null && t.ContainsKey("rest")) + { + return t["rest"]; + } + return SExp.To(new List{ REST_ATOM, args}); + } + + public static SExp SubArgs(SExp sexp, List newArgs) + { + if (sexp.Nullp() || !sexp.Listp()) + { + return PathFromArgs(sexp, newArgs); + } + + var first = sexp.First(); + if (first.Listp()) + { + first = SubArgs(first, newArgs); + } + else + { + object op = first.AsAtom(); + + if (op.Equals(QUOTE_ATOM)) + { + return sexp; + } + } + + List newSexp = new List { first }; + newSexp.AddRange(sexp.Rest().AsIter().Select(_ => SubArgs(_, newArgs))); + + return SExp.To(newSexp); + } + //DoRead //DoWrite @@ -71,8 +136,6 @@ public static bool SeemsConstant(SExp sexp) //SeemsConstant //ConstantOptimizer //IsArgsCall - //ConsF - //ConsR //PathFromArgs //SubArgs //var_change_optimizer_cons_eval diff --git a/CLVMDotNet/src/Tools/Stages/Stage2/PatternMatch.cs b/CLVMDotNet/src/Tools/Stages/Stage2/PatternMatch.cs index 4338299..e3d5b72 100644 --- a/CLVMDotNet/src/Tools/Stages/Stage2/PatternMatch.cs +++ b/CLVMDotNet/src/Tools/Stages/Stage2/PatternMatch.cs @@ -1,6 +1,89 @@ +using System.Text; +using CLVMDotNet.CLVM; + namespace CLVMDotNet.Tools.Stages.Stage2; public class PatternMatch { + public static byte[] ATOM_MATCH => Encoding.UTF8.GetBytes("$"); + public static byte[] SEXP_MATCH => Encoding.UTF8.GetBytes(":"); + public static Dictionary? UnifyBindings(Dictionary bindings, byte[] newKey, + SExp newValue) + { + string newKeyString = System.Text.Encoding.UTF8.GetString(newKey); + if (bindings.ContainsKey(newKeyString)) + { + var obj = bindings[newKeyString]; + if (!obj.Equals(newValue)) + { + return null; + } + + return bindings; + } + + Dictionary newBindings = new Dictionary(bindings); + newBindings[newKeyString] = newValue; + return newBindings; + } + + public static Dictionary? Match(SExp pattern, SExp sexp, Dictionary knownBindings = null) + { + if (knownBindings == null) + { + knownBindings = new Dictionary(); + } + + if (!pattern.Listp()) + { + if (!sexp.Listp()) + { + return pattern.AsAtom() == sexp.AsAtom() ? knownBindings : null; + } + + return null; + } + + var left = pattern.First(); + var right = pattern.Rest(); + object atom = sexp.AsAtom(); + + if (left.AsAtom() == ATOM_MATCH) + { + if (!sexp.Listp()) + { + return null; + } + + if (right.AsAtom() == ATOM_MATCH) + { + return atom is string ? UnifyBindings(knownBindings, right.AsAtom(), sexp) : null; + } + + return UnifyBindings(knownBindings, right.AsAtom(), sexp); + } + + if (left.AsAtom() == SEXP_MATCH) + { + if (right.AsAtom() == SEXP_MATCH) + { + return atom is string ? UnifyBindings(knownBindings, right.AsAtom(), sexp) : null; + } + + return UnifyBindings(knownBindings, right.AsAtom(), sexp); + } + + if (!sexp.Listp()) + { + return null; + } + + Dictionary newBindings = Match(left, sexp.First(), knownBindings); + if (newBindings == null) + { + return newBindings; + } + return Match(right, sexp.Rest(), newBindings); + } } \ No newline at end of file From f0751fd6fc46caa872775cba141eec38cb0e27a5 Mon Sep 17 00:00:00 2001 From: kev Date: Mon, 29 Jan 2024 20:55:26 +0000 Subject: [PATCH 24/29] . --- .../src/Tools/Stages/Stage2/Optimize.cs | 31 ++++++++++++++----- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/CLVMDotNet/src/Tools/Stages/Stage2/Optimize.cs b/CLVMDotNet/src/Tools/Stages/Stage2/Optimize.cs index 5e148e2..b27e012 100644 --- a/CLVMDotNet/src/Tools/Stages/Stage2/Optimize.cs +++ b/CLVMDotNet/src/Tools/Stages/Stage2/Optimize.cs @@ -22,6 +22,23 @@ public static class Optimize public static SExp QUOTE_PATTERN_1 = BinUtils.Assemble("(q . 0)"); public static SExp APPLY_NULL_PATTERN_1 = BinUtils.Assemble("(a 0 . (: . rest))"); + /// + /// This applies the transform `(a 0 ARGS)` => `0` + /// + /// + /// + /// + public static SExp ApplyNullOptimizer(SExp r, Func> eval) + { + Dictionary t1 = PatternMatch.Match(APPLY_NULL_PATTERN_1, r); // Define Match method accordingly + + if (t1 != null) + { + return SExp.To(0); + } + return r; + } + public static bool NonNil(SExp sexp) { @@ -83,9 +100,9 @@ public static SExp ConsF(SExp args) { Dictionary t = PatternMatch.Match(CONS_PATTERN, args); - if (t != null && t.ContainsKey("first")) + if (t != null && t.TryGetValue("first", out var f)) { - return t["first"]; + return f; } return SExp.To(new List { FIRST_ATOM, args}); } @@ -94,9 +111,9 @@ public static SExp ConsR(SExp args) { Dictionary t = PatternMatch.Match(CONS_PATTERN, args); - if (t != null && t.ContainsKey("rest")) + if (t != null && t.TryGetValue("rest", out var r)) { - return t["rest"]; + return r; } return SExp.To(new List{ REST_ATOM, args}); } @@ -115,17 +132,15 @@ public static SExp SubArgs(SExp sexp, List newArgs) } else { - object op = first.AsAtom(); + var op = first.AsAtom(); if (op.Equals(QUOTE_ATOM)) { return sexp; } } - - List newSexp = new List { first }; + List newSexp = new List { first }; newSexp.AddRange(sexp.Rest().AsIter().Select(_ => SubArgs(_, newArgs))); - return SExp.To(newSexp); } From 498741575fd6887bf3bdc69f7f38466dabd6e93f Mon Sep 17 00:00:00 2001 From: kev Date: Mon, 29 Jan 2024 21:19:34 +0000 Subject: [PATCH 25/29] . --- .../src/Tools/Stages/Stage2/Optimize.cs | 150 ++++++++++++++++-- 1 file changed, 134 insertions(+), 16 deletions(-) diff --git a/CLVMDotNet/src/Tools/Stages/Stage2/Optimize.cs b/CLVMDotNet/src/Tools/Stages/Stage2/Optimize.cs index b27e012..cc4591a 100644 --- a/CLVMDotNet/src/Tools/Stages/Stage2/Optimize.cs +++ b/CLVMDotNet/src/Tools/Stages/Stage2/Optimize.cs @@ -1,3 +1,4 @@ +using System.Text; using CLVMDotNet.CLVM; using CLVMDotNet.Tools.IR; @@ -21,7 +22,7 @@ public static class Optimize public static SExp REST_ATOM_PATTERN = BinUtils.Assemble("(r ($ . atom))"); public static SExp QUOTE_PATTERN_1 = BinUtils.Assemble("(q . 0)"); public static SExp APPLY_NULL_PATTERN_1 = BinUtils.Assemble("(a 0 . (: . rest))"); - + /// /// This applies the transform `(a 0 ARGS)` => `0` /// @@ -36,10 +37,120 @@ public static SExp ApplyNullOptimizer(SExp r, Func> { return SExp.To(0); } + + return r; + } + + /// + /// This applies the transform + /// (f N) => A + /// and + /// (r N) => B + /// + /// + /// + /// + public static SExp PathOptimizer(SExp r, Func> eval) + { + Dictionary t1 = PatternMatch.Match(FIRST_ATOM_PATTERN, r); + + if (t1 != null && NonNil(t1["atom"])) + { + var nodeValue = t1["atom"].AsInt(); + NodePath node = new NodePath(nodeValue); + node = node.Add(NodePath.Left); + return SExp.To(node.AsShortPath()); + } + + t1 = PatternMatch.Match(REST_ATOM_PATTERN, r); + if (t1 != null && NonNil(t1["atom"])) + { + var nodeValue = t1["atom"].AsInt(); + NodePath node = new NodePath(nodeValue); + node = node.Add(NodePath.Right); + return SExp.To(node.AsShortPath()); + } + + return r; + } + + /// + /// Recursively apply optimizations to all non-quoted child nodes. + /// + /// + /// + /// + public static SExp ChildrenOptimizer(SExp r, Func> eval) + { + if (!r.Listp()) + { + return r; + } + var operatorSexp = r.First(); + if (!operatorSexp.Listp()) + { + var op = operatorSexp.AsAtom(); + if (op.SequenceEqual(new byte[] { QUOTE_ATOM })) + { + return r; + } + } + + List optimizedChildren = new List(); + foreach (SExp child in r.AsIter()) + { + //TODO: Write OptimizeSexp + //optimizedChildren.Add(OptimizeSexp(child, eval)); + } + + return SExp.To(optimizedChildren); + } + + + /// + /// This applies the transform + /// (f (c A B)) => A + /// and + /// (r (c A B)) => B + /// + /// + public static SExp ConsOptimizer(SExp r, Func> eval) + { + Dictionary t1 = PatternMatch.Match(CONS_OPTIMIZER_PATTERN_FIRST, r); + if (t1 != null) + { + return t1["first"]; + } + + t1 = PatternMatch.Match(CONS_OPTIMIZER_PATTERN_REST, r); + if (t1 != null) + { + return t1["rest"]; + } + + return r; + } + + + /// + /// This applies the transform `(q . 0)` => `0` + /// + /// + /// + /// + public static SExp QuoteNullOptimizer(SExp r, Func> eval) + { + Dictionary t1 = PatternMatch.Match(QUOTE_PATTERN_1, r); // Define Match method accordingly + + if (t1 != null) + { + return SExp.To(0); + } + return r; } - - + + public static bool NonNil(SExp sexp) { return sexp.Listp() || (sexp.AsAtom().Length > 0); @@ -51,7 +162,7 @@ public static bool IsArgsCall(SExp r) return true; return false; } - + public static bool SeemsConstant(SExp sexp) { if (!sexp.Listp()) @@ -59,6 +170,7 @@ public static bool SeemsConstant(SExp sexp) // note that `0` is a constant return !NonNil(sexp); } + var operatorSexp = sexp.First(); if (!operatorSexp.Listp()) { @@ -78,9 +190,10 @@ public static bool SeemsConstant(SExp sexp) { return false; } + return sexp.Rest().AsIter().All(childSexp => SeemsConstant(childSexp)); } - + public static SExp PathFromArgs(SExp sexp, dynamic newArgs) { var v = sexp.AsInt(); @@ -88,36 +201,40 @@ public static SExp PathFromArgs(SExp sexp, dynamic newArgs) { return newArgs; } + sexp = SExp.To(v >> 1); if ((v & 1) == 1) { - return PathFromArgs(sexp, ConsR(newArgs)); + return PathFromArgs(sexp, ConsR(newArgs)); } - return PathFromArgs(sexp, ConsF(newArgs)); + + return PathFromArgs(sexp, ConsF(newArgs)); } - + public static SExp ConsF(SExp args) { - Dictionary t = PatternMatch.Match(CONS_PATTERN, args); + Dictionary t = PatternMatch.Match(CONS_PATTERN, args); if (t != null && t.TryGetValue("first", out var f)) { return f; } - return SExp.To(new List { FIRST_ATOM, args}); + + return SExp.To(new List { FIRST_ATOM, args }); } - + public static SExp ConsR(SExp args) { - Dictionary t = PatternMatch.Match(CONS_PATTERN, args); + Dictionary t = PatternMatch.Match(CONS_PATTERN, args); if (t != null && t.TryGetValue("rest", out var r)) { return r; } - return SExp.To(new List{ REST_ATOM, args}); + + return SExp.To(new List { REST_ATOM, args }); } - + public static SExp SubArgs(SExp sexp, List newArgs) { if (sexp.Nullp() || !sexp.Listp()) @@ -139,12 +256,13 @@ public static SExp SubArgs(SExp sexp, List newArgs) return sexp; } } + List newSexp = new List { first }; newSexp.AddRange(sexp.Rest().AsIter().Select(_ => SubArgs(_, newArgs))); return SExp.To(newSexp); } - - + + //DoRead //DoWrite //RunProgramForSearchPaths From ae876380738ed92a23435124e9e2dba85e2ee409 Mon Sep 17 00:00:00 2001 From: kev Date: Tue, 6 Feb 2024 22:16:14 +0000 Subject: [PATCH 26/29] Start of refactor how ops are run --- CLVMDotNet/src/CLVM/HelperFunctions.cs | 113 +++++++++++++++++++-- CLVMDotNet/src/CLVM/OperatorDict.cs | 132 +++++++++++++++++++++++++ CLVMDotNet/src/Tools/IR/Clvmc.cs | 6 ++ CLVMDotNet/tests/CLVM/SExp/To.cs | 12 +-- CLVMDotNet/tests/Common.cs | 99 ------------------- 5 files changed, 249 insertions(+), 113 deletions(-) create mode 100644 CLVMDotNet/src/CLVM/OperatorDict.cs diff --git a/CLVMDotNet/src/CLVM/HelperFunctions.cs b/CLVMDotNet/src/CLVM/HelperFunctions.cs index df62a6b..a56eb35 100644 --- a/CLVMDotNet/src/CLVM/HelperFunctions.cs +++ b/CLVMDotNet/src/CLVM/HelperFunctions.cs @@ -8,16 +8,111 @@ namespace CLVMDotNet.CLVM public static class HelperFunctions { private static byte[] nullBytes = new byte[0]; + + public static string PrintLeaves(SExp tree) + { + var a = tree.AsAtom(); + if (a != null) + { + if (a.Length == 0) + return "() "; + + return $"{a[0]} "; + } + + var ret = ""; + var pairs = tree.AsPair(); + var list = new List() { pairs.Item1, pairs.Item2 }; + if (pairs != null) + { + foreach (SExp i in list) + { + ret += PrintLeaves(i); + } + } + + return ret; + } + + public static string PrintTree(SExp tree) + { + var a = tree.AsAtom(); + if (a != null) + { + if (a.Length == 0) + { + return "() "; + } + + return $"{a[0]} "; + } + + var ret = "("; + var pairs = tree.AsPair(); + var list = new List() { pairs!.Item1, pairs.Item2 }; + if (pairs != null) + { + foreach (var i in list) + { + ret += PrintTree(i); + } + } + + ret += ")"; + return ret; + } + + public static void ValidateSExp(SExp sexp) + { + Stack validateStack = new Stack(); + validateStack.Push(sexp); + + while (validateStack.Count > 0) + { + dynamic v = validateStack.Pop(); + + if (!(v is SExp)) + { + throw new InvalidOperationException("v is not an instance of SExp"); + } + + if (v.Pair != null) + { + if (v.Pair.GetType() != typeof(Tuple)) + { + throw new InvalidOperationException("v.pair is not a Tuple"); + } + + Tuple pair = v.Pair; + + if (!HelperFunctions.LooksLikeCLVMObject(pair.Item1) || + !HelperFunctions.LooksLikeCLVMObject(pair.Item2)) + { + throw new InvalidOperationException("One or both elements do not look like CLVM objects"); + } + + var sPair = v.AsPair(); + validateStack.Push(sPair.Item1); + validateStack.Push(sPair.Item2); + } + else + { + if (!(v.Atom is byte[])) + { + throw new InvalidOperationException("v.atom is not a byte array"); + } + } + } + } private static bool IsTuple(dynamic? obj) { var isTuple = false; Type type = obj?.GetType(); - - + + if (type != null) { - if (!isTuple) isTuple = type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Tuple<,>); @@ -49,6 +144,7 @@ private static bool IsTuple(dynamic? obj) } } } + return null; } @@ -73,6 +169,7 @@ private static bool IsTuple(dynamic? obj) } } } + return null; } @@ -126,8 +223,8 @@ private static bool IsTuple(dynamic? obj) } if (value is System.Collections.IList list && - list.GetType().IsGenericType && - list.GetType().GetGenericTypeDefinition() == typeof(List<>)) + list.GetType().IsGenericType && + list.GetType().GetGenericTypeDefinition() == typeof(List<>)) { target = stack.Count; stack.Add(new CLVMObject(nullBytes)); @@ -157,19 +254,18 @@ private static bool IsTuple(dynamic? obj) var leftValue = new CLVMObject(stack[stack.Count - 1]); stack.RemoveAt(stack.Count - 1); var rightValue = stack[target].Pair.Item2; - stack[target].Pair = Tuple.Create(leftValue, rightValue); + stack[target].Pair = Tuple.Create(leftValue, rightValue); continue; } if (op == 2) // set right { - var leftValue = stack[target].Pair.Item1; var right = stack[stack.Count - 1]; stack.RemoveAt(stack.Count - 1); var rightValue = new CLVMObject(right); - stack[target].Pair = Tuple.Create(leftValue, rightValue); + stack[target].Pair = Tuple.Create(leftValue, rightValue); continue; } @@ -207,6 +303,7 @@ public static byte[] ConvertAtomToBytes(dynamic? v) { return Encoding.UTF8.GetBytes(str); } + if (v is string[] strarray && strarray.Length == 1) { return Encoding.UTF8.GetBytes(strarray[0]); diff --git a/CLVMDotNet/src/CLVM/OperatorDict.cs b/CLVMDotNet/src/CLVM/OperatorDict.cs new file mode 100644 index 0000000..f5f8b69 --- /dev/null +++ b/CLVMDotNet/src/CLVM/OperatorDict.cs @@ -0,0 +1,132 @@ +using System.Numerics; + +namespace CLVMDotNet.CLVM; + +public class OperatorDict +{ + private delegate Tuple DictDelegate(SExp sexp); + private Dictionary Dictionary = new Dictionary(); + + public OperatorDict(OperatorDict dict) + { + + } + + public static IEnumerable ArgsLen(string op_name, SExp args) + { + foreach (var arg in args.AsIter()) + { + if (arg.Pair != null) + { + throw new EvalError($"{op_name} requires int args", arg); + } + yield return arg.Atom!.Length; + } + } + + public static Tuple DefaultUnknownOp(byte[] op, SExp args) + { + // any opcode starting with ffff is reserved (i.e. fatal error) + // opcodes are not allowed to be empty + if (op.Length == 0 || (op[0] == 0xff && op[1] == 0xff)) + { + throw new EvalError("reserved operator"); + } + + // all other unknown opcodes are no-ops + // the cost of the no-ops is determined by the opcode number, except the + // 6 least significant bits. + + byte costFunction = (byte)((op[op.Length - 1] & 0b11000000) >> 6); + // the multiplier cannot be 0. it starts at 1 + + if (op.Length > 5) + { + throw new EvalError("invalid operator"); + } + + BigInteger costMultiplier = new BigInteger(op.Take(op.Length - 1).ToArray()) + 1; + + // 0 = constant + // 1 = like op_add/op_sub + // 2 = like op_multiply + // 3 = like op_concat + BigInteger cost; + switch (costFunction) + { + case 0: + cost = 1; + break; + case 1: + // like op_add + cost = Costs.ARITH_BASE_COST; + int argSize = 0; + foreach (int l in ArgsLen("unknown op", args)) + { + argSize += l; + cost += Costs.ARITH_COST_PER_ARG; + } + cost += argSize * Costs.ARITH_COST_PER_BYTE; + break; + case 2: + // like op_multiply + cost = Costs.MUL_BASE_COST; + IEnumerator operands = ArgsLen("unknown op", args).GetEnumerator(); + try + { + int vs = operands.MoveNext() ? operands.Current : 0; + while (operands.MoveNext()) + { + int rs = operands.Current; + cost += Costs.MUL_COST_PER_OP; + cost += (rs + vs) * Costs.MUL_LINEAR_COST_PER_BYTE; + cost += (rs * vs) / Costs.MUL_SQUARE_COST_PER_BYTE_DIVIDER; + // this is an estimate, since we don't want to actually multiply the + // values + vs += rs; + } + } + catch (Exception){} + break; + case 3: + // like concat + cost = Costs.CONCAT_BASE_COST; + int length = 0; + foreach (SExp arg in args.AsIter()) + { + if (arg.AsPair() != null) + { + throw new EvalError("unknown op on list"); + } + cost += Costs.CONCAT_COST_PER_ARG; + length += arg.AsAtom().Length; + } + cost += length * Costs.CONCAT_COST_PER_BYTE; + break; + default: + throw new EvalError("Invalid cost function"); + } + + cost = (int)(cost * costMultiplier); + if (cost >= (1 << 32)) + { + throw new EvalError("invalid operator"); + } + + return Tuple.Create(cost, SExp.NULL); + } + + public Tuple ApplyOperator(byte[] op, SExp arguments) + { + var func = Dictionary[op]; + if (func != null) + { + var result = func(arguments); + return result; + } + else + { + return DefaultUnknownOp(op, arguments); + } + } +} \ No newline at end of file diff --git a/CLVMDotNet/src/Tools/IR/Clvmc.cs b/CLVMDotNet/src/Tools/IR/Clvmc.cs index 40dbb2c..1399781 100644 --- a/CLVMDotNet/src/Tools/IR/Clvmc.cs +++ b/CLVMDotNet/src/Tools/IR/Clvmc.cs @@ -10,7 +10,13 @@ public static SExp CompileCLVMText(string text, string[] searchPaths) var ir_src = IRReader.ReadIR(text); var assembled_sexp = BinUtils.AssembleFromIR(ir_src); var input_sexp = SExp.To((assembled_sexp, Array.Empty())); + + // everthing above here matches python + var tree = HelperFunctions.PrintTree(input_sexp); var result = Program.RunProgram(null, input_sexp); + + //Need a RunProgramForSearchPaths + return result.Item2; } diff --git a/CLVMDotNet/tests/CLVM/SExp/To.cs b/CLVMDotNet/tests/CLVM/SExp/To.cs index 49e9d90..bc82921 100644 --- a/CLVMDotNet/tests/CLVM/SExp/To.cs +++ b/CLVMDotNet/tests/CLVM/SExp/To.cs @@ -15,7 +15,7 @@ public void builds_correct_tree() // Act var s = clvm.SExp.To(new List { "+", 1, 2 }); - var tree = Common.PrintTree(s); + var tree = clvm.HelperFunctions.PrintTree(s); // Assert Assert.Equal("(43 (1 (2 () )))", tree); @@ -31,7 +31,7 @@ public void test_case_1() var t1 = clvm.SExp.To(new List { 1, sexp }); // Assert - Common.ValidateSExp(t1); + clvm.HelperFunctions.ValidateSExp(t1); } [Fact] @@ -69,7 +69,7 @@ public void TestListConversions() // Act var a = clvm.SExp.To(new List { 1, 2, 3 }); string expectedOutput = "(1 (2 (3 () )))"; - string result = Common.PrintTree(a); + string result = clvm.HelperFunctions.PrintTree(a); // Assert Assert.Equal(expectedOutput, result); @@ -135,10 +135,10 @@ public void arbitrary_underlying_tree() var tree3 = clvm.SExp.To(gentree3); // Assert - Assert.Equal(Common.PrintTree(tree1), + Assert.Equal(clvm.HelperFunctions.PrintTree(tree1), "(((((0 1 )(2 3 ))((4 5 )(6 7 )))(((8 9 )(10 11 ))((12 13 )(14 15 ))))((((16 17 )(18 19 ))((20 21 )(22 23 )))(((24 25 )(26 27 ))((28 29 )(30 31 )))))"); - Assert.Equal(Common.PrintTree(tree2), "(((0 1 )(2 3 ))((4 5 )(6 7 )))"); - Assert.Equal(Common.PrintTree(tree3), "(((10 11 )(12 13 ))((14 15 )(16 17 )))"); + Assert.Equal(clvm.HelperFunctions.PrintTree(tree2), "(((0 1 )(2 3 ))((4 5 )(6 7 )))"); + Assert.Equal(clvm.HelperFunctions.PrintTree(tree3), "(((10 11 )(12 13 ))((14 15 )(16 17 )))"); } } } \ No newline at end of file diff --git a/CLVMDotNet/tests/Common.cs b/CLVMDotNet/tests/Common.cs index a672452..ee6b95f 100644 --- a/CLVMDotNet/tests/Common.cs +++ b/CLVMDotNet/tests/Common.cs @@ -4,104 +4,5 @@ namespace CLVMDotNet.Tests { public static class Common { - #region test helpers that should probably go into SExp object - - public static string PrintLeaves(clvm.SExp tree) - { - var a = tree.AsAtom(); - if (a != null) - { - if (a.Length == 0) - return "() "; - - return $"{a[0]} "; - } - - var ret = ""; - var pairs = tree.AsPair(); - var list = new List() { pairs.Item1, pairs.Item2 }; - if (pairs != null) - { - foreach (clvm.SExp i in list) - { - ret += PrintLeaves(i); - } - } - - return ret; - } - - public static string PrintTree(clvm.SExp tree) - { - var a = tree.AsAtom(); - if (a != null) - { - if (a.Length == 0) - { - return "() "; - } - - return $"{a[0]} "; - } - - var ret = "("; - var pairs = tree.AsPair(); - var list = new List() { pairs!.Item1, pairs.Item2 }; - if (pairs != null) - { - foreach (var i in list) - { - ret += PrintTree(i); - } - } - - ret += ")"; - return ret; - } - - public static void ValidateSExp(clvm.SExp sexp) - { - Stack validateStack = new Stack(); - validateStack.Push(sexp); - - while (validateStack.Count > 0) - { - dynamic v = validateStack.Pop(); - - if (!(v is clvm.SExp)) - { - throw new InvalidOperationException("v is not an instance of SExp"); - } - - if (v.Pair != null) - { - if (v.Pair.GetType() != typeof(Tuple)) - { - throw new InvalidOperationException("v.pair is not a Tuple"); - } - - Tuple pair = v.Pair; - - if (!clvm.HelperFunctions.LooksLikeCLVMObject(pair.Item1) || - !clvm.HelperFunctions.LooksLikeCLVMObject(pair.Item2)) - { - throw new InvalidOperationException("One or both elements do not look like CLVM objects"); - } - - var sPair = v.AsPair(); - validateStack.Push(sPair.Item1); - validateStack.Push(sPair.Item2); - } - else - { - if (!(v.Atom is byte[])) - { - throw new InvalidOperationException("v.atom is not a byte array"); - } - } - } - } - - #endregion } } \ No newline at end of file From da733d0e6df0b6765521fb69193e9a66b1f1b4e9 Mon Sep 17 00:00:00 2001 From: kev Date: Tue, 6 Feb 2024 23:07:11 +0000 Subject: [PATCH 27/29] removed some compiler warnings --- CLVMDotNet/src/CLVM/MoreOps.cs | 4 +-- CLVMDotNet/src/CLVM/OperatorDict.cs | 15 ++++++++-- CLVMDotNet/tests/Tools/IRReader/IrNewTests.cs | 6 ++-- .../tests/Tools/IRReader/TokenizeConsTests.cs | 14 ++++----- .../tests/Tools/IRReader/TokenizeHexTests.cs | 12 ++++---- .../tests/Tools/IRReader/TokenizeIntTests.cs | 12 ++++---- .../tests/Tools/Stages/Stage2/BindingTests.cs | 30 +++++++++---------- 7 files changed, 51 insertions(+), 42 deletions(-) diff --git a/CLVMDotNet/src/CLVM/MoreOps.cs b/CLVMDotNet/src/CLVM/MoreOps.cs index b616732..1a540dc 100644 --- a/CLVMDotNet/src/CLVM/MoreOps.cs +++ b/CLVMDotNet/src/CLVM/MoreOps.cs @@ -269,7 +269,7 @@ public static Tuple OpGrBytes(SExp args) var b0 = a0.AsAtom(); var b1 = a1.AsAtom(); BigInteger cost = Costs.GRS_BASE_COST; - cost += (b0.Length + b1.Length) * Costs.GRS_COST_PER_BYTE; + cost += (b0!.Length + b1!.Length) * Costs.GRS_COST_PER_BYTE; int comparisonResult = b0.AsSpan().SequenceCompareTo(b1.AsSpan()); @@ -358,7 +358,7 @@ public static Tuple OpStrlen(SExp args) throw new EvalError("strlen on list", a0); } - int size = a0.AsAtom().Length; + int size = a0.AsAtom()!.Length; BigInteger cost = Costs.STRLEN_BASE_COST + size * Costs.STRLEN_COST_PER_BYTE; return MallocCost(cost, SExp.To(size)); } diff --git a/CLVMDotNet/src/CLVM/OperatorDict.cs b/CLVMDotNet/src/CLVM/OperatorDict.cs index f5f8b69..3714529 100644 --- a/CLVMDotNet/src/CLVM/OperatorDict.cs +++ b/CLVMDotNet/src/CLVM/OperatorDict.cs @@ -4,12 +4,21 @@ namespace CLVMDotNet.CLVM; public class OperatorDict { - private delegate Tuple DictDelegate(SExp sexp); + public delegate Tuple DictDelegate(byte[] op, SExp sexp); + public DictDelegate? UnknownOpHandler; private Dictionary Dictionary = new Dictionary(); - public OperatorDict(OperatorDict dict) + public byte[] QuoteAtom { get; set; } = new byte[0]; + public byte[] ApplyAtom { get; set; } = new byte[0]; + + public OperatorDict(OperatorDict d, Dictionary args, DictDelegate unknownOp = null) { + // Set quote_atom and apply_atom properties using kwargs or defaults from d + this.QuoteAtom = args.ContainsKey("quote") ? (byte[])args["quote"] : d.QuoteAtom; + this.ApplyAtom = args.ContainsKey("apply") ? (byte[])args["apply"] : d.ApplyAtom; + // Set unknown_op_handler property using kwargs or default + this.UnknownOpHandler = unknownOp ?? DefaultUnknownOp; } public static IEnumerable ArgsLen(string op_name, SExp args) @@ -121,7 +130,7 @@ public Tuple ApplyOperator(byte[] op, SExp arguments) var func = Dictionary[op]; if (func != null) { - var result = func(arguments); + var result = func(Array.Empty(), arguments); return result; } else diff --git a/CLVMDotNet/tests/Tools/IRReader/IrNewTests.cs b/CLVMDotNet/tests/Tools/IRReader/IrNewTests.cs index ad885dc..6c16c54 100644 --- a/CLVMDotNet/tests/Tools/IRReader/IrNewTests.cs +++ b/CLVMDotNet/tests/Tools/IRReader/IrNewTests.cs @@ -20,9 +20,9 @@ public void IrNewWithValidIntegerAndOffset() Assert.Null(result.Atom); Assert.NotNull(result.Pair); Assert.NotNull(result.Pair.Item1); - Assert.True(result.AsPair().Item1.AsPair().Item1.Atom.SequenceEqual(new byte[] { 73, 78, 84 })); //INT - Assert.True(result.AsPair().Item1.AsPair().Item2.Atom.SequenceEqual(new byte[] { 0x01 })); //1 (offset) - Assert.True(result.AsPair().Item2.Atom.SequenceEqual(new byte[] {49,48,48})); //100 + Assert.True(result.AsPair()!.Item1.AsPair()!.Item1.Atom!.SequenceEqual(new byte[] { 73, 78, 84 })); //INT + Assert.True(result.AsPair()!.Item1.AsPair()!.Item2.Atom!.SequenceEqual(new byte[] { 0x01 })); //1 (offset) + Assert.True(result.AsPair()!.Item2.Atom!.SequenceEqual(new byte[] {49,48,48})); //100 } } } \ No newline at end of file diff --git a/CLVMDotNet/tests/Tools/IRReader/TokenizeConsTests.cs b/CLVMDotNet/tests/Tools/IRReader/TokenizeConsTests.cs index 9be1cad..dd99795 100644 --- a/CLVMDotNet/tests/Tools/IRReader/TokenizeConsTests.cs +++ b/CLVMDotNet/tests/Tools/IRReader/TokenizeConsTests.cs @@ -16,14 +16,14 @@ public void TokenizeCons_ClosingBracket() var tokenized = x.IRReader.TokenizeCons(")", 6, stream.GetEnumerator()); // Assert - Assert.Null(tokenized.Atom); + Assert.Null(tokenized!.Atom); Assert.NotNull(tokenized.Pair); - Assert.NotNull(tokenized.AsPair().Item1); - Assert.Null(tokenized.AsPair().Item1.Atom); - Assert.NotNull(tokenized.AsPair().Item1.Pair); - Assert.NotNull(tokenized.AsPair().Item1.AsPair()); - Assert.True(tokenized.AsPair().Item1.AsPair().Item1.Atom.SequenceEqual(new byte[] { 78, 85, 76, 76 })); - Assert.True(tokenized.AsPair().Item2.Atom.SequenceEqual(new byte[] { })); + Assert.NotNull(tokenized.AsPair()!.Item1); + Assert.Null(tokenized.AsPair()!.Item1.Atom); + Assert.NotNull(tokenized.AsPair()!.Item1.Pair); + Assert.NotNull(tokenized.AsPair()!.Item1.AsPair()); + Assert.True(tokenized.AsPair()!.Item1.AsPair()!.Item1.Atom!.SequenceEqual(new byte[] { 78, 85, 76, 76 })); + Assert.True(tokenized.AsPair()!.Item2.Atom!.SequenceEqual(new byte[] { })); } // [Theory] diff --git a/CLVMDotNet/tests/Tools/IRReader/TokenizeHexTests.cs b/CLVMDotNet/tests/Tools/IRReader/TokenizeHexTests.cs index a9c5d36..69a53ee 100644 --- a/CLVMDotNet/tests/Tools/IRReader/TokenizeHexTests.cs +++ b/CLVMDotNet/tests/Tools/IRReader/TokenizeHexTests.cs @@ -46,16 +46,16 @@ public void TokenizeHex_Valid(string number, byte[] expectedBytes) var tokenized = x.IRReader.TokenizeHex(number, 0); // Assert - Assert.Null(tokenized.Atom); + Assert.Null(tokenized!.Atom); Assert.NotNull(tokenized.Pair); - Assert.Null(tokenized.AsPair().Item1.Atom); - Assert.NotNull(tokenized.AsPair().Item1); - Assert.NotNull(tokenized.AsPair().Item1.AsPair()); + Assert.Null(tokenized.AsPair()!.Item1.Atom); + Assert.NotNull(tokenized.AsPair()!.Item1); + Assert.NotNull(tokenized.AsPair()!.Item1.AsPair()!); //HEX as bytes - Assert.True(tokenized.AsPair().Item1.AsPair().Item1.Atom.SequenceEqual(new byte[] { 72, 69, 88})); // HEX + Assert.True(tokenized.AsPair()!.Item1.AsPair()!.Item1.Atom!.SequenceEqual(new byte[] { 72, 69, 88})); // HEX //NUMBER as bytes - Assert.True(tokenized.AsPair().Item2.Atom.SequenceEqual(expectedBytes)); //bytes + Assert.True(tokenized.AsPair()!.Item2.Atom!.SequenceEqual(expectedBytes)); //bytes } } \ No newline at end of file diff --git a/CLVMDotNet/tests/Tools/IRReader/TokenizeIntTests.cs b/CLVMDotNet/tests/Tools/IRReader/TokenizeIntTests.cs index d473006..c9efd28 100644 --- a/CLVMDotNet/tests/Tools/IRReader/TokenizeIntTests.cs +++ b/CLVMDotNet/tests/Tools/IRReader/TokenizeIntTests.cs @@ -31,16 +31,16 @@ public void TokenizeInt_Builds_CorrectObject(string number, byte[] expectedBytes var tokenized = x.IRReader.TokenizeInt(number, 0); // Assert - Assert.Null(tokenized.Atom); + Assert.Null(tokenized!.Atom); Assert.NotNull(tokenized.Pair); - Assert.Null(tokenized.AsPair().Item1.Atom); - Assert.NotNull(tokenized.AsPair().Item1); - Assert.NotNull(tokenized.AsPair().Item1.AsPair()); + Assert.Null(tokenized.AsPair()!.Item1.Atom); + Assert.NotNull(tokenized.AsPair()!.Item1); + Assert.NotNull(tokenized.AsPair()!.Item1.AsPair()); //INT as bytes - Assert.True(tokenized.AsPair().Item1.AsPair().Item1.Atom.SequenceEqual(new byte[] { 73, 78, 84})); // INT + Assert.True(tokenized.AsPair()!.Item1.AsPair()!.Item1.Atom!.SequenceEqual(new byte[] { 73, 78, 84})); // INT //NUMBER as bytes - Assert.True(tokenized.AsPair().Item2.Atom.SequenceEqual(expectedBytes)); // INT + Assert.True(tokenized.AsPair()!.Item2.Atom!.SequenceEqual(expectedBytes)); // INT } } \ No newline at end of file diff --git a/CLVMDotNet/tests/Tools/Stages/Stage2/BindingTests.cs b/CLVMDotNet/tests/Tools/Stages/Stage2/BindingTests.cs index de0615e..a1c5b73 100644 --- a/CLVMDotNet/tests/Tools/Stages/Stage2/BindingTests.cs +++ b/CLVMDotNet/tests/Tools/Stages/Stage2/BindingTests.cs @@ -16,15 +16,15 @@ public void TestBrun() // Assert Assert.Null(brun.Atom); Assert.NotNull(brun.Pair); - Assert.True(brun.AsPair().Item1.AsAtom().SequenceEqual(new byte[] { 0x02 })); - Assert.Null(brun.AsPair().Item1.Pair); - Assert.Null(brun.AsPair().Item2.Atom); - Assert.NotNull(brun.AsPair().Item2.Pair); - Assert.True(brun.AsPair().Item2.AsPair().Item1.AsAtom().SequenceEqual(new byte[] { 0x02})); - Assert.Null(brun.AsPair().Item2.AsPair().Item2.Atom); - Assert.NotNull(brun.AsPair().Item2.AsPair().Item2.Pair); - Assert.True(brun.AsPair().Item2.AsPair().Item2.AsPair().Item1.AsAtom().SequenceEqual(new byte []{ 0x03})); - Assert.Empty(brun.AsPair().Item2.AsPair().Item2.AsPair().Item2.AsAtom()); + Assert.True(brun.AsPair()!.Item1.AsAtom()!.SequenceEqual(new byte[] { 0x02 })); + Assert.Null(brun.AsPair()!.Item1.Pair); + Assert.Null(brun.AsPair()!.Item2.Atom); + Assert.NotNull(brun.AsPair()!.Item2.Pair); + Assert.True(brun.AsPair()!.Item2.AsPair()!.Item1.AsAtom()!.SequenceEqual(new byte[] { 0x02})); + Assert.Null(brun.AsPair()!.Item2.AsPair()!.Item2.Atom); + Assert.NotNull(brun.AsPair()!.Item2.AsPair()!.Item2.Pair); + Assert.True(brun.AsPair()!.Item2.AsPair()!.Item2.AsPair()!.Item1.AsAtom()!.SequenceEqual(new byte []{ 0x03})); + Assert.Empty(brun.AsPair()!.Item2.AsPair()!.Item2.AsPair()!.Item2.AsAtom()!); } [Fact(Skip = "Skipping for now")] @@ -37,12 +37,12 @@ public void TestRun() // Assert Assert.Null(run.Atom); - Assert.True(run.AsPair().Item1.AsAtom().SequenceEqual(new byte[] { 0x02 })); - Assert.Null(run.AsPair().Item1.Pair); - Assert.Null(run.AsPair().Item2.Atom); - Assert.NotNull(run.AsPair().Item2.Pair); - Assert.NotNull(run.AsPair().Item2.AsPair().Item2); - Assert.NotNull(run.AsPair().Item2.AsPair().Item1); + Assert.True(run.AsPair()!.Item1.AsAtom()!.SequenceEqual(new byte[] { 0x02 })); + Assert.Null(run.AsPair()!.Item1.Pair); + Assert.Null(run.AsPair()!.Item2.Atom); + Assert.NotNull(run.AsPair()!.Item2.Pair); + Assert.NotNull(run.AsPair()!.Item2.AsPair()!.Item2); + Assert.NotNull(run.AsPair()!.Item2.AsPair()!.Item1); } From 1e3ca6f747ef0ebfd251d9f2cdb79dc2a7b27d0f Mon Sep 17 00:00:00 2001 From: kev Date: Sat, 10 Feb 2024 00:00:43 +0000 Subject: [PATCH 28/29] Change how operators are applied --- CLVMDotNet/src/CLVM/Keywords.cs | 142 ----- CLVMDotNet/src/CLVM/OperatorDict.cs | 98 +++- CLVMDotNet/src/CLVM/Operators.cs | 493 +++++++++++------- CLVMDotNet/src/CLVM/Program.cs | 398 +++++++------- CLVMDotNet/src/Tools/IR/BinUtils.cs | 2 +- CLVMDotNet/src/Tools/IR/Clvmc.cs | 70 +-- CLVMDotNet/src/Tools/Stages/Stage2/Compile.cs | 6 +- CLVMDotNet/src/Tools/Stages/Stage2/Helpers.cs | 6 +- CLVMDotNet/src/Tools/Stages/Stage2/Mod.cs | 4 +- .../src/Tools/Stages/Stage2/Optimize.cs | 14 +- .../CLVM/Operators/ApplyOperatorTests.cs | 438 +++++++++------- .../CLVM/Operators/KeywordFromAtomTests.cs | 19 +- .../CLVM/Operators/KeywordToAtomTests.cs | 16 +- .../tests/CLVM/Operators/OperatorDictTests.cs | 19 + .../tests/Tools/Clvmc/CompileCLVMText.cs | 32 +- 15 files changed, 927 insertions(+), 830 deletions(-) delete mode 100644 CLVMDotNet/src/CLVM/Keywords.cs create mode 100644 CLVMDotNet/tests/CLVM/Operators/OperatorDictTests.cs diff --git a/CLVMDotNet/src/CLVM/Keywords.cs b/CLVMDotNet/src/CLVM/Keywords.cs deleted file mode 100644 index 460c8d7..0000000 --- a/CLVMDotNet/src/CLVM/Keywords.cs +++ /dev/null @@ -1,142 +0,0 @@ -namespace CLVMDotNet.CLVM -{ - public static class Keywords - { - public static string[] KEYWORDS = new string[] - { - // core opcodes 0x01-x08 - ".", - "q", - "a", - "i", - "c", - "f", - "r", - "l", - "x", - - // opcodes on atoms as strings 0x09-0x0f - "=", - ">s", - "sha256", - "substr", - "strlen", - "concat", - //"." - - // opcodes on atoms as ints 0x10-0x17 - "+", - "-", - "*", - "/", - "divmod", - ">", - "ash", - "lsh", - - // opcodes on atoms as vectors of bools 0x18-0x1c - "logand", - "logior", - "logxor", - "lognot", - // ".", - - // opcodes for bls 1381 0x1d-0x1f - "point_add", - "pubkey_for_exp", - // ".", - - // bool opcodes 0x20-0x23 - "not", - "any", - "all", - ".", - - // misc 0x24 - "softfork" - }; - - public static Dictionary KEYWORD_FROM_ATOM => InitializeKeywordFromAtom(); - public static Dictionary KEYWORD_TO_ATOM => InitializeKeywordToAtom(); - - private static Dictionary InitializeKeywordFromAtom() - { - var keywordFromAtom = new Dictionary(); - keywordFromAtom.Add(0x01, "q"); - keywordFromAtom.Add(0x02, "a"); - keywordFromAtom.Add(0x03, "i"); - keywordFromAtom.Add(0x04, "c"); - keywordFromAtom.Add(0x05, "f"); - keywordFromAtom.Add(0x06, "r"); - keywordFromAtom.Add(0x07, "l"); - keywordFromAtom.Add(0x08, "x"); - keywordFromAtom.Add(0x09, "="); - keywordFromAtom.Add(0x0a, ">s"); - keywordFromAtom.Add(0x0b, "sha256"); - keywordFromAtom.Add(0x0c, "substr"); - keywordFromAtom.Add(0x0d, "strlen"); - keywordFromAtom.Add(0x0e, "concat"); - keywordFromAtom.Add(0x0f, "."); - keywordFromAtom.Add(0x10, "+"); - keywordFromAtom.Add(0x11, "-"); - keywordFromAtom.Add(0x12, "*"); - keywordFromAtom.Add(0x13, "/"); - keywordFromAtom.Add(0x14, "divmod"); - keywordFromAtom.Add(0x15, ">"); - keywordFromAtom.Add(0x16, "ash"); - keywordFromAtom.Add(0x17, "lsh"); - keywordFromAtom.Add(0x18, "logand"); - keywordFromAtom.Add(0x19, "logior"); - keywordFromAtom.Add(0x1a, "logxor"); - keywordFromAtom.Add(0x1b, "lognot"); - keywordFromAtom.Add(0x1c, "."); - keywordFromAtom.Add(0x1d, "point_add"); - keywordFromAtom.Add(0x1e, "pubkey_for_exp"); - keywordFromAtom.Add(0x1f, "."); - keywordFromAtom.Add(0x20, "not"); - keywordFromAtom.Add(0x21, "any"); - keywordFromAtom.Add(0x22, "all"); - keywordFromAtom.Add(0x23, "."); - return keywordFromAtom; - } - - private static Dictionary InitializeKeywordToAtom() - { - var keywordToAtom = new Dictionary(); - keywordToAtom.Add(".", 0x00); - keywordToAtom.Add("q", 0x01); - keywordToAtom.Add("a", 0x02); - keywordToAtom.Add("i", 0x03); - keywordToAtom.Add("c", 0x04); - keywordToAtom.Add("f", 0x05); - keywordToAtom.Add("r", 0x06); - keywordToAtom.Add("l", 0x07); - keywordToAtom.Add("x", 0x08); - keywordToAtom.Add("=", 0x09); - keywordToAtom.Add(">s", 0x0a); - keywordToAtom.Add("sha256", 0x0b); - keywordToAtom.Add("substr", 0x0c); - keywordToAtom.Add("strlen", 0x0d); - keywordToAtom.Add("concat", 0x0e); - keywordToAtom.Add("+", 0x10); - keywordToAtom.Add("-", 0x11); - keywordToAtom.Add("*", 0x12); - keywordToAtom.Add("/", 0x13); - keywordToAtom.Add("divmod", 0x14); - keywordToAtom.Add(">", 0x15); - keywordToAtom.Add("ash", 0x16); - keywordToAtom.Add("lsh", 0x17); - keywordToAtom.Add("logand", 0x18); - keywordToAtom.Add("logior", 0x19); - keywordToAtom.Add("logxor", 0x1a); - keywordToAtom.Add("lognot", 0x1b); - keywordToAtom.Add("point_add", 0x1d); - keywordToAtom.Add("pubkey_for_exp", 0x1e); - keywordToAtom.Add("not", 0x20); - keywordToAtom.Add("any", 0x21); - keywordToAtom.Add("all", 0x22); - keywordToAtom.Add("softfork", 0x24); - return keywordToAtom; - } - } -} \ No newline at end of file diff --git a/CLVMDotNet/src/CLVM/OperatorDict.cs b/CLVMDotNet/src/CLVM/OperatorDict.cs index 3714529..1f615aa 100644 --- a/CLVMDotNet/src/CLVM/OperatorDict.cs +++ b/CLVMDotNet/src/CLVM/OperatorDict.cs @@ -6,20 +6,100 @@ public class OperatorDict { public delegate Tuple DictDelegate(byte[] op, SExp sexp); public DictDelegate? UnknownOpHandler; - private Dictionary Dictionary = new Dictionary(); + private Dictionary OpDictionary = new Dictionary(); public byte[] QuoteAtom { get; set; } = new byte[0]; public byte[] ApplyAtom { get; set; } = new byte[0]; - public OperatorDict(OperatorDict d, Dictionary args, DictDelegate unknownOp = null) + public OperatorDict(OperatorDict d, Dictionary? args, DictDelegate? unknownOp = null) { // Set quote_atom and apply_atom properties using kwargs or defaults from d this.QuoteAtom = args.ContainsKey("quote") ? (byte[])args["quote"] : d.QuoteAtom; this.ApplyAtom = args.ContainsKey("apply") ? (byte[])args["apply"] : d.ApplyAtom; + OpDictionary = d.OpDictionary; // Set unknown_op_handler property using kwargs or default this.UnknownOpHandler = unknownOp ?? DefaultUnknownOp; } + + public OperatorDict() + { + } + + public static OperatorDict OPERATOR_LOOKUP() + { + Dictionary ops = new Dictionary(); + var QUOTE_ATOM = Operators.KEYWORD_TO_ATOM()["q"]; + var APPLY_ATOM = Operators.KEYWORD_TO_ATOM()["a"]; + + + //core ops + // ops["0x01"] = (op, sexp) => CoreOps.OpIf(sexp); + // ops["0x02"] = (op, sexp) => CoreOps.OpIf(sexp); + ops["0x03"] = (op, sexp) => CoreOps.OpIf(sexp); + ops["0x04"] = (op, sexp) => CoreOps.OpCons(sexp); + ops["0x05"] = (op, sexp) => CoreOps.OpFirst(sexp); + ops["0x06"] = (op, sexp) => CoreOps.OpRest(sexp); + ops["0x07"] = (op, sexp) => CoreOps.OpListp(sexp); + ops["0x08"] = (op, sexp) => CoreOps.OpRaise(sexp); + ops["0x09"] = (op, sexp) => CoreOps.OpEq(sexp); + + //more ops + ops["0x10"] = (op, sexp) => MoreOps.OpAdd(sexp); + ops["0x11"] = (op, sexp) => MoreOps.OpSubtract(sexp); + ops["0x12"] = (op, sexp) => MoreOps.OpMultiply(sexp); + ops["0x13"] = (op, sexp) => MoreOps.OpDiv(sexp); + ops["0x14"] = (op, sexp) => MoreOps.OpDivmod(sexp); + ops["0x15"] = (op, sexp) => MoreOps.OpGr(sexp); + ops["0x16"] = (op, sexp) => MoreOps.OpAsh(sexp); + ops["0x17"] = (op, sexp) => MoreOps.OpLsh(sexp); + ops["0x18"] = (op, sexp) => MoreOps.OpLogand(sexp); + ops["0x19"] = (op, sexp) => MoreOps.OpLogior(sexp); + ops["0x20"] = (op, sexp) => MoreOps.OpNot(sexp); + ops["0x1A"] = (op, sexp) => MoreOps.OpLogxor(sexp); + ops["0x1B"] = (op, sexp) => MoreOps.OpLogNot(sexp); + ops["0x1D"] = (op, sexp) => MoreOps.OpPointAdd(sexp); + ops["0x1E"] = (op, sexp) => MoreOps.OpPubkeyForExp(sexp); + ops["0x0A"] = (op, sexp) => MoreOps.OpGrBytes(sexp); + ops["0x0B"] = (op, sexp) => MoreOps.OpSha256(sexp); + ops["0x0C"] = (op, sexp) => MoreOps.OpSubstr(sexp); + ops["0x0D"] = (op, sexp) => MoreOps.OpStrlen(sexp); + ops["0x0E"] = (op, sexp) => MoreOps.OpConcat(sexp); + ops["0x21"] = (op, sexp) => MoreOps.OpAny(sexp); + ops["0x22"] = (op, sexp) => MoreOps.OpAll(sexp); + ops["0x23"] = (op, sexp) => MoreOps.OpNot(sexp); + ops["0x24"] = (op, sexp) => MoreOps.OpSoftfork(sexp); + + var d = new Dictionary + { + { "quote", QUOTE_ATOM }, + { "apply", APPLY_ATOM } + }; + + OperatorDict p = new OperatorDict(); + p.OpDictionary = ops; + + return new OperatorDict(p, d); + } + + + public Tuple ApplyOperator(byte[] op, SExp args) + { + string hexString = "0x"; + foreach (byte b in op) + { + hexString += b.ToString("X2"); + } + + var f = OpDictionary[hexString]; + if (f is null) + return UnknownOpHandler(op, args); + else + { + return f(Array.Empty(), args); + } + } + public static IEnumerable ArgsLen(string op_name, SExp args) { @@ -124,18 +204,4 @@ public static Tuple DefaultUnknownOp(byte[] op, SExp args) return Tuple.Create(cost, SExp.NULL); } - - public Tuple ApplyOperator(byte[] op, SExp arguments) - { - var func = Dictionary[op]; - if (func != null) - { - var result = func(Array.Empty(), arguments); - return result; - } - else - { - return DefaultUnknownOp(op, arguments); - } - } } \ No newline at end of file diff --git a/CLVMDotNet/src/CLVM/Operators.cs b/CLVMDotNet/src/CLVM/Operators.cs index 6a71f0a..cf6f50e 100644 --- a/CLVMDotNet/src/CLVM/Operators.cs +++ b/CLVMDotNet/src/CLVM/Operators.cs @@ -1,226 +1,317 @@ using System.Numerics; +using System.Linq; namespace CLVMDotNet.CLVM { - public static class Operator + public static class Operators { - public static byte[] QuoteAtom { get; set; } = new byte[0]; - public static byte[] ApplyAtom { get; set; } = new byte[0]; - - /// - /// Apply Operator to an atom. - /// - /// This is not the tidiest or most efficient way of executing an operator. The - /// python version uses a dictionary to lookup the function. This will likely be changed to that - /// to make it more efficient, rather than executing 30 if statements which ultimately slows down the function. - /// - /// - /// - /// - /// - /// - public static Tuple ApplyOperator(byte[] atom, SExp args) + public static List KEYWORDS = new List { - // core op codes 0x01-x08 + // core opcodes 0x01-x08 + ".", "q", "a", "i", "c", "f", "r", "l", "x", - if (atom.AsSpan().SequenceEqual(new byte[] { 0x23 })) - { - //. (#) - return CoreOps.OpDefaultUnknown(atom,args); - } - else if (atom.AsSpan().SequenceEqual(new byte[] { 0x01 })) - { - //q - return CoreOps.OpDefaultUnknown(atom,args); - } - else if (atom.AsSpan().SequenceEqual(new byte[] { 0x02 })) - { - //a - return CoreOps.OpDefaultUnknown(atom, args); - } + // opcodes on atoms as strings 0x09-0x0f + "=", ">s", "sha256", "substr" , "strlen", "concat", ".", - else if (atom.AsSpan().SequenceEqual(new byte[] { 0x03 })) - { - //i - return CoreOps.OpIf(args); - } - else if (atom.AsSpan().SequenceEqual(new byte[] { 0x04 })) - { - //c - return CoreOps.OpCons(args); - } - else if (atom.AsSpan().SequenceEqual(new byte[] { 0x05 })) - { - //f - return CoreOps.OpFirst(args); - } - else if (atom.AsSpan().SequenceEqual(new byte[] { 0x06 })) - { - //r - return CoreOps.OpRest(args); - } - else if (atom.AsSpan().SequenceEqual(new byte[] { 0x07 })) - { - //l - return CoreOps.OpListp(args); - } - else if (atom.AsSpan().SequenceEqual(new byte[] { 0x08 })) - { - //x - return CoreOps.OpRaise(args); - } + // opcodes on atoms as ints 0x10-0x17 + "+", "-", "*", "/", "divmod", ">", "ash", "lsh", + // opcodes on atoms as vectors of bools 0x18-0x1c + "logand", "logior", "logxor", "lognot", ".", - //opcodes on atoms as strings 0x09-0x0f - if (atom.AsSpan().SequenceEqual(new byte[] { 0x09 })) - { - //= - return CoreOps.OpEq(args); - } - else if (atom.AsSpan().SequenceEqual(new byte[] { 0x0A })) - { - //>s - return MoreOps.OpGrBytes(args); - } - else if (atom.AsSpan().SequenceEqual(new byte[] { 0x0B })) - { - //sha256 - return MoreOps.OpSha256(args); - } - else if (atom.AsSpan().SequenceEqual(new byte[] { 0x0C })) - { - //substr - return MoreOps.OpSubstr(args); - } - else if (atom.AsSpan().SequenceEqual(new byte[] { 0x0D })) - { - //strlen - return MoreOps.OpStrlen(args); - } - else if (atom.AsSpan().SequenceEqual(new byte[] { 0x0E })) - { - //concat - return MoreOps.OpConcat(args); - } - else if (atom.AsSpan().SequenceEqual(new byte[] { 0x0F })) - { - //. - throw new ArgumentException("Op Not Implemented!"); - } + // opcodes for bls 1381 0x1d-0x1f + "point_add", "pubkey_for_exp", ".", + // bool opcodes 0x20-0x23 + "not", "any", "all", ".", - //op codes on atoms as ints - if (atom.AsSpan().SequenceEqual(new byte[] { 0x10 })) - { - //+ - return MoreOps.OpAdd(args); - } - else if (atom.AsSpan().SequenceEqual(new byte[] { 0x11 })) - { - //- - return MoreOps.OpSubtract(args); - } - else if (atom.AsSpan().SequenceEqual(new byte[] { 0x12 })) - { - //* - return MoreOps.OpMultiply(args); - } - else if (atom.AsSpan().SequenceEqual(new byte[] { 0x13 })) - { - //divide - return MoreOps.OpDiv(args); - } - else if (atom.AsSpan().SequenceEqual(new byte[] { 0x14 })) - { - //divmod - return MoreOps.OpDivmod(args); - } - else if (atom.AsSpan().SequenceEqual(new byte[] { 0x15 })) - { - //> - return MoreOps.OpGr(args); - } - else if (atom.AsSpan().SequenceEqual(new byte[] { 0x16 })) - { - //ash - return MoreOps.OpAsh(args); - } - else if (atom.AsSpan().SequenceEqual(new byte[] { 0x17 })) - { - //lsh - return MoreOps.OpLsh(args); - } + // misc 0x24 + "softfork" + }; - // opcodes on atoms as vectors of bools 0x18-0x1c - if (atom.AsSpan().SequenceEqual(new byte[] { 0x18 })) - { - //logand - return MoreOps.OpLogand(args); - } - else if (atom.AsSpan().SequenceEqual(new byte[] { 0x19 })) - { - //logior - return MoreOps.OpLogior(args); - } - else if (atom.AsSpan().SequenceEqual(new byte[] { 0x1A })) - { - //logxor - return MoreOps.OpLogxor(args); - } - else if (atom.AsSpan().SequenceEqual(new byte[] { 0x1B })) - { - //lognot - return MoreOps.OpLogNot(args); - } - else if (atom.AsSpan().SequenceEqual(new byte[] { 0x1C })) + public static Dictionary KEYWORD_FROM_ATOM => KEYWORDS.Select((keyword, index) => new { Index = index, Keyword = keyword }) + .ToDictionary(item => Casts.IntToBytes(item.Index), item => item.Keyword, new ByteArrayComparer()); + + public static Dictionary KEYWORD_TO_ATOM() + { + var dic = new Dictionary(); + foreach (var item in KEYWORD_FROM_ATOM) { - //. - throw new ArgumentException("Op Not Implemented!"); + dic[item.Value] = item.Key; } + return dic; + } + + public static Dictionary OpRewrite => new Dictionary + { + { "+", "add" }, + { "-", "subtract" }, + { "*", "multiply" }, + { "/", "div" }, + { "i", "if" }, + { "c", "cons" }, + { "f", "first" }, + { "r", "rest" }, + { "l", "listp" }, + { "x", "raise" }, + { "=", "eq" }, + { ">", "gr" }, + { ">s", "gr_bytes" } + }; - //opcodes for bls 1381 0x1d-0x1f - if (atom.AsSpan().SequenceEqual(new byte[] { 0x1D })) - { - //point_add - return MoreOps.OpPointAdd(args); - } - else if (atom.AsSpan().SequenceEqual(new byte[] { 0x1E })) - { - //pubkey_for_exp - return MoreOps.OpPubkeyForExp(args); - } - else if (atom.AsSpan().SequenceEqual(new byte[] { 0x1F })) - { - //. - throw new ArgumentException("Op Not Implemented!"); - } + public static byte[] QUOTE_ATOM => KEYWORD_TO_ATOM()["q"]; + public static byte[] APPLY_ATOM => KEYWORD_TO_ATOM()["a"]; - // bool opcodes 0x20-0x23 - if (atom.AsSpan().SequenceEqual(new byte[] { 0x20 })) - { - //not - return MoreOps.OpNot(args); - } - else if (atom.AsSpan().SequenceEqual(new byte[] { 0x21 })) - { - //any - return MoreOps.OpAny(args); - } - else if (atom.AsSpan().SequenceEqual(new byte[] { 0x22 })) + // { + // public static byte[] QuoteAtom { get; set; } = new byte[0]; + // public static byte[] ApplyAtom { get; set; } = new byte[0]; + // + // /// + // /// Apply Operator to an atom. + // /// + // /// This is not the tidiest or most efficient way of executing an operator. The + // /// python version uses a dictionary to lookup the function. This will likely be changed to that + // /// to make it more efficient, rather than executing 30 if statements which ultimately slows down the function. + // /// + // /// + // /// + // /// + // /// + // /// + // public static Tuple ApplyOperator(byte[] atom, SExp args) + // { + // // core op codes 0x01-x08 + // + // if (atom.AsSpan().SequenceEqual(new byte[] { 0x23 })) + // { + // //. (#) + // return CoreOps.OpDefaultUnknown(atom,args); + // } + // else if (atom.AsSpan().SequenceEqual(new byte[] { 0x01 })) + // { + // //q + // return CoreOps.OpDefaultUnknown(atom,args); + // } + // else if (atom.AsSpan().SequenceEqual(new byte[] { 0x02 })) + // { + // //a + // return CoreOps.OpDefaultUnknown(atom, args); + // } + // + // else if (atom.AsSpan().SequenceEqual(new byte[] { 0x03 })) + // { + // //i + // return CoreOps.OpIf(args); + // } + // else if (atom.AsSpan().SequenceEqual(new byte[] { 0x04 })) + // { + // //c + // return CoreOps.OpCons(args); + // } + // else if (atom.AsSpan().SequenceEqual(new byte[] { 0x05 })) + // { + // //f + // return CoreOps.OpFirst(args); + // } + // else if (atom.AsSpan().SequenceEqual(new byte[] { 0x06 })) + // { + // //r + // return CoreOps.OpRest(args); + // } + // else if (atom.AsSpan().SequenceEqual(new byte[] { 0x07 })) + // { + // //l + // return CoreOps.OpListp(args); + // } + // else if (atom.AsSpan().SequenceEqual(new byte[] { 0x08 })) + // { + // //x + // return CoreOps.OpRaise(args); + // } + // + // + // //opcodes on atoms as strings 0x09-0x0f + // if (atom.AsSpan().SequenceEqual(new byte[] { 0x09 })) + // { + // //= + // return CoreOps.OpEq(args); + // } + // else if (atom.AsSpan().SequenceEqual(new byte[] { 0x0A })) + // { + // //>s + // return MoreOps.OpGrBytes(args); + // } + // else if (atom.AsSpan().SequenceEqual(new byte[] { 0x0B })) + // { + // //sha256 + // return MoreOps.OpSha256(args); + // } + // else if (atom.AsSpan().SequenceEqual(new byte[] { 0x0C })) + // { + // //substr + // return MoreOps.OpSubstr(args); + // } + // else if (atom.AsSpan().SequenceEqual(new byte[] { 0x0D })) + // { + // //strlen + // return MoreOps.OpStrlen(args); + // } + // else if (atom.AsSpan().SequenceEqual(new byte[] { 0x0E })) + // { + // //concat + // return MoreOps.OpConcat(args); + // } + // else if (atom.AsSpan().SequenceEqual(new byte[] { 0x0F })) + // { + // //. + // throw new ArgumentException("Op Not Implemented!"); + // } + // + // + // //op codes on atoms as ints + // if (atom.AsSpan().SequenceEqual(new byte[] { 0x10 })) + // { + // //+ + // return MoreOps.OpAdd(args); + // } + // else if (atom.AsSpan().SequenceEqual(new byte[] { 0x11 })) + // { + // //- + // return MoreOps.OpSubtract(args); + // } + // else if (atom.AsSpan().SequenceEqual(new byte[] { 0x12 })) + // { + // //* + // return MoreOps.OpMultiply(args); + // } + // else if (atom.AsSpan().SequenceEqual(new byte[] { 0x13 })) + // { + // //divide + // return MoreOps.OpDiv(args); + // } + // else if (atom.AsSpan().SequenceEqual(new byte[] { 0x14 })) + // { + // //divmod + // return MoreOps.OpDivmod(args); + // } + // else if (atom.AsSpan().SequenceEqual(new byte[] { 0x15 })) + // { + // //> + // return MoreOps.OpGr(args); + // } + // else if (atom.AsSpan().SequenceEqual(new byte[] { 0x16 })) + // { + // //ash + // return MoreOps.OpAsh(args); + // } + // else if (atom.AsSpan().SequenceEqual(new byte[] { 0x17 })) + // { + // //lsh + // return MoreOps.OpLsh(args); + // } + // + // // opcodes on atoms as vectors of bools 0x18-0x1c + // if (atom.AsSpan().SequenceEqual(new byte[] { 0x18 })) + // { + // //logand + // return MoreOps.OpLogand(args); + // } + // else if (atom.AsSpan().SequenceEqual(new byte[] { 0x19 })) + // { + // //logior + // return MoreOps.OpLogior(args); + // } + // else if (atom.AsSpan().SequenceEqual(new byte[] { 0x1A })) + // { + // //logxor + // return MoreOps.OpLogxor(args); + // } + // else if (atom.AsSpan().SequenceEqual(new byte[] { 0x1B })) + // { + // //lognot + // return MoreOps.OpLogNot(args); + // } + // else if (atom.AsSpan().SequenceEqual(new byte[] { 0x1C })) + // { + // //. + // throw new ArgumentException("Op Not Implemented!"); + // } + // + // + // //opcodes for bls 1381 0x1d-0x1f + // if (atom.AsSpan().SequenceEqual(new byte[] { 0x1D })) + // { + // //point_add + // return MoreOps.OpPointAdd(args); + // } + // else if (atom.AsSpan().SequenceEqual(new byte[] { 0x1E })) + // { + // //pubkey_for_exp + // return MoreOps.OpPubkeyForExp(args); + // } + // else if (atom.AsSpan().SequenceEqual(new byte[] { 0x1F })) + // { + // //. + // throw new ArgumentException("Op Not Implemented!"); + // } + // + // // bool opcodes 0x20-0x23 + // if (atom.AsSpan().SequenceEqual(new byte[] { 0x20 })) + // { + // //not + // return MoreOps.OpNot(args); + // } + // else if (atom.AsSpan().SequenceEqual(new byte[] { 0x21 })) + // { + // //any + // return MoreOps.OpAny(args); + // } + // else if (atom.AsSpan().SequenceEqual(new byte[] { 0x22 })) + // { + // //all + // return MoreOps.OpAll(args); + // } + // if (atom.AsSpan().SequenceEqual(new byte[] { 0x24 })) + // { + // //softfork + // return MoreOps.OpSoftfork(args); + // } + // + // throw new Exception($"{BitConverter.ToString(atom).Replace("-", "")} Operator not found or is unsupported!"); + // } + } + + public class ByteArrayComparer : IEqualityComparer + { + public bool Equals(byte[] x, byte[] y) + { + if (x == null || y == null) + return x == y; + + if (x.Length != y.Length) + return false; + + for (int i = 0; i < x.Length; i++) { - //all - return MoreOps.OpAll(args); + if (x[i] != y[i]) + return false; } - if (atom.AsSpan().SequenceEqual(new byte[] { 0x24 })) + + return true; + } + + public int GetHashCode(byte[] obj) + { + if (obj == null) + throw new ArgumentNullException(nameof(obj)); + + int hash = 17; + foreach (byte b in obj) { - //softfork - return MoreOps.OpSoftfork(args); + hash = hash * 31 + b; } - - throw new Exception($"{BitConverter.ToString(atom).Replace("-", "")} Operator not found or is unsupported!"); + return hash; } } - - } \ No newline at end of file diff --git a/CLVMDotNet/src/CLVM/Program.cs b/CLVMDotNet/src/CLVM/Program.cs index 101508e..e8a5e98 100644 --- a/CLVMDotNet/src/CLVM/Program.cs +++ b/CLVMDotNet/src/CLVM/Program.cs @@ -1,199 +1,199 @@ -using System.Numerics; - -namespace CLVMDotNet.CLVM; - -public static class Program -{ - public static Tuple RunProgram(SExp program, SExp args, BigInteger? maxCost = null) - { - var prog = SExp.To(program); - Stack, BigInteger>> opStack = new Stack, BigInteger>>(); - - var valueStack = new Stack(); - valueStack.Push(prog.Cons(args)); - opStack.Push(stack => EvalOp(opStack, valueStack)); - - BigInteger cost = 0; - - while (opStack.Count != 0) - { - var f = opStack.Pop(); - cost += f(valueStack); - if (maxCost.HasValue && cost > maxCost) - { - throw new EvalError("cost exceeded", SExp.To(maxCost)); - } - } - - return Tuple.Create(new BigInteger(1), prog); - } - - public static (BigInteger, SExp) TraversePath(SExp sexp, SExp env) - { - BigInteger cost = Costs.PATH_LOOKUP_BASE_COST; - cost += Costs.PATH_LOOKUP_COST_PER_LEG; - - if (sexp.Nullp()) - { - return (cost, SExp.NULL); - } - - byte[] b = sexp.Atom; - - int endByteCursor = 0; - while (endByteCursor < b.Length && b[endByteCursor] == 0) - { - endByteCursor++; - } - - cost += endByteCursor * Costs.PATH_LOOKUP_COST_PER_ZERO_BYTE; - if (endByteCursor == b.Length) - { - return (cost, SExp.NULL); - } - - // Create a bitmask for the most significant *set* bit - // in the last non-zero byte - byte endBitmask = MSBMask(b[endByteCursor]); - int byteCursor = b.Length - 1; - byte bitmask = 0x01; - while (byteCursor > endByteCursor || bitmask < endBitmask) - { - if (env.Pair == null) - { - throw new EvalError("path into atom", env); - } - - if ((b[byteCursor] & bitmask) != 0) - { - env = env.Rest(); - } - else - { - env = env.First(); - } - - cost += Costs.PATH_LOOKUP_COST_PER_LEG; - bitmask <<= 1; - - if (bitmask == 0x100) - { - byteCursor--; - bitmask = 0x01; - } - } - return (cost, env); - } - - public static BigInteger EvalOp(Stack, BigInteger>> opStack, Stack valueStack) - { - var pair = valueStack.Pop(); - var sexp = pair.First(); - var args = pair.Rest(); - - if (sexp.Pair == null) - { - // sexp is an atom - var (cost, r) = TraversePath(sexp, args); - valueStack.Push(r); - return cost; - } - - var op = sexp.First(); - if (op.Pair != null) - { - var operatorPair = op.AsPair(); //newOperator,must_be_nil - var (newOperator, mustBeNil) = (operatorPair.Item1, operatorPair.Item2); - if (newOperator.Pair != null || mustBeNil.Atom != Array.Empty()) - { - throw new EvalError("in ((X)...) syntax X must be lone atom", sexp); - } - - var newOperandList = sexp.Rest(); - valueStack.Append(newOperator); - valueStack.Append(newOperandList); - opStack.Push(stack => ApplyOp(opStack, valueStack)); - return Costs.APPLY_COST; - } - - var op1 = op.AsAtom(); - var operand_list = sexp.Rest(); - if (op1 == Operator.QuoteAtom) - { - valueStack.Append(operand_list); - return Costs.QUOTE_COST; - } - - opStack.Append(stack => ConsOp(opStack, valueStack)); - valueStack.Append(op); - while (operand_list.Nullp()) - { - var ex = operand_list.First(); - valueStack.Append(ex.Cons(args)); - opStack.Push(stack => ConsOp(opStack, valueStack)); - opStack.Push(stack => EvalOp(opStack, valueStack)); - opStack.Push(stack => SwapOp(opStack, valueStack)); - operand_list = operand_list.Rest(); - valueStack.Append(SExp.NULL); - } - return BigInteger.Parse("1"); - } - - public static BigInteger ApplyOp(Stack, BigInteger>> opStack, Stack valueStack) - { - var operandList = valueStack.Pop(); - var oper = valueStack.Pop(); - - if (oper.Pair != null) - { - throw new EvalError("internal error", oper); - } - - var op = oper.AsAtom(); - - if (op == Operator.ApplyAtom) - { - if (operandList.ListLength() != 2) - { - throw new EvalError("apply requires exactly 2 parameters", operandList); - } - - var newProgram = operandList.First(); - var newArgs = operandList.Rest().First(); - - valueStack.Push(newProgram.Cons(newArgs)); - opStack.Push(stack => EvalOp(opStack, valueStack)); - return Costs.APPLY_COST; - } - - var result = Operator.ApplyOperator(op, operandList); - valueStack.Push(result.Item2); - return result.Item1; - } - - public static BigInteger SwapOp(Stack, BigInteger>> opStack, Stack valueStack) - { - var v2 = valueStack.Pop(); - var v1 = valueStack.Pop(); - valueStack.Push(v2); - valueStack.Push(v1); - return 0; - } - - public static int ConsOp(Stack, BigInteger>> opStack, Stack valueStack) - { - var v1 = valueStack.Pop(); - var v2 = valueStack.Pop(); - var result = v1.Cons(v2); - valueStack.Push(result); - return 0; - } - - public static byte MSBMask(byte inputByte) - { - inputByte |= (byte)(inputByte >> 1); - inputByte |= (byte)(inputByte >> 2); - inputByte |= (byte)(inputByte >> 4); - return (byte)((inputByte + 1) >> 1); - } -} \ No newline at end of file +// using System.Numerics; +// +// namespace CLVMDotNet.CLVM; +// +// public static class Program +// { +// public static Tuple RunProgram(SExp program, SExp args, BigInteger? maxCost = null) +// { +// var prog = SExp.To(program); +// Stack, BigInteger>> opStack = new Stack, BigInteger>>(); +// +// var valueStack = new Stack(); +// valueStack.Push(prog.Cons(args)); +// opStack.Push(stack => EvalOp(opStack, valueStack)); +// +// BigInteger cost = 0; +// +// while (opStack.Count != 0) +// { +// var f = opStack.Pop(); +// cost += f(valueStack); +// if (maxCost.HasValue && cost > maxCost) +// { +// throw new EvalError("cost exceeded", SExp.To(maxCost)); +// } +// } +// +// return Tuple.Create(new BigInteger(1), prog); +// } +// +// public static (BigInteger, SExp) TraversePath(SExp sexp, SExp env) +// { +// BigInteger cost = Costs.PATH_LOOKUP_BASE_COST; +// cost += Costs.PATH_LOOKUP_COST_PER_LEG; +// +// if (sexp.Nullp()) +// { +// return (cost, SExp.NULL); +// } +// +// byte[] b = sexp.Atom; +// +// int endByteCursor = 0; +// while (endByteCursor < b.Length && b[endByteCursor] == 0) +// { +// endByteCursor++; +// } +// +// cost += endByteCursor * Costs.PATH_LOOKUP_COST_PER_ZERO_BYTE; +// if (endByteCursor == b.Length) +// { +// return (cost, SExp.NULL); +// } +// +// // Create a bitmask for the most significant *set* bit +// // in the last non-zero byte +// byte endBitmask = MSBMask(b[endByteCursor]); +// int byteCursor = b.Length - 1; +// byte bitmask = 0x01; +// while (byteCursor > endByteCursor || bitmask < endBitmask) +// { +// if (env.Pair == null) +// { +// throw new EvalError("path into atom", env); +// } +// +// if ((b[byteCursor] & bitmask) != 0) +// { +// env = env.Rest(); +// } +// else +// { +// env = env.First(); +// } +// +// cost += Costs.PATH_LOOKUP_COST_PER_LEG; +// bitmask <<= 1; +// +// if (bitmask == 0x100) +// { +// byteCursor--; +// bitmask = 0x01; +// } +// } +// return (cost, env); +// } +// +// public static BigInteger EvalOp(Stack, BigInteger>> opStack, Stack valueStack) +// { +// var pair = valueStack.Pop(); +// var sexp = pair.First(); +// var args = pair.Rest(); +// +// if (sexp.Pair == null) +// { +// // sexp is an atom +// var (cost, r) = TraversePath(sexp, args); +// valueStack.Push(r); +// return cost; +// } +// +// var op = sexp.First(); +// if (op.Pair != null) +// { +// var operatorPair = op.AsPair(); //newOperator,must_be_nil +// var (newOperator, mustBeNil) = (operatorPair.Item1, operatorPair.Item2); +// if (newOperator.Pair != null || mustBeNil.Atom != Array.Empty()) +// { +// throw new EvalError("in ((X)...) syntax X must be lone atom", sexp); +// } +// +// var newOperandList = sexp.Rest(); +// valueStack.Append(newOperator); +// valueStack.Append(newOperandList); +// opStack.Push(stack => ApplyOp(opStack, valueStack)); +// return Costs.APPLY_COST; +// } +// +// var op1 = op.AsAtom(); +// var operand_list = sexp.Rest(); +// if (op1 == Operator.QuoteAtom) +// { +// valueStack.Append(operand_list); +// return Costs.QUOTE_COST; +// } +// +// opStack.Append(stack => ConsOp(opStack, valueStack)); +// valueStack.Append(op); +// while (operand_list.Nullp()) +// { +// var ex = operand_list.First(); +// valueStack.Append(ex.Cons(args)); +// opStack.Push(stack => ConsOp(opStack, valueStack)); +// opStack.Push(stack => EvalOp(opStack, valueStack)); +// opStack.Push(stack => SwapOp(opStack, valueStack)); +// operand_list = operand_list.Rest(); +// valueStack.Append(SExp.NULL); +// } +// return BigInteger.Parse("1"); +// } +// +// public static BigInteger ApplyOp(Stack, BigInteger>> opStack, Stack valueStack) +// { +// var operandList = valueStack.Pop(); +// var oper = valueStack.Pop(); +// +// if (oper.Pair != null) +// { +// throw new EvalError("internal error", oper); +// } +// +// var op = oper.AsAtom(); +// +// if (op == Operator.ApplyAtom) +// { +// if (operandList.ListLength() != 2) +// { +// throw new EvalError("apply requires exactly 2 parameters", operandList); +// } +// +// var newProgram = operandList.First(); +// var newArgs = operandList.Rest().First(); +// +// valueStack.Push(newProgram.Cons(newArgs)); +// opStack.Push(stack => EvalOp(opStack, valueStack)); +// return Costs.APPLY_COST; +// } +// +// var result = Operator.ApplyOperator(op, operandList); +// valueStack.Push(result.Item2); +// return result.Item1; +// } +// +// public static BigInteger SwapOp(Stack, BigInteger>> opStack, Stack valueStack) +// { +// var v2 = valueStack.Pop(); +// var v1 = valueStack.Pop(); +// valueStack.Push(v2); +// valueStack.Push(v1); +// return 0; +// } +// +// public static int ConsOp(Stack, BigInteger>> opStack, Stack valueStack) +// { +// var v1 = valueStack.Pop(); +// var v2 = valueStack.Pop(); +// var result = v1.Cons(v2); +// valueStack.Push(result); +// return 0; +// } +// +// public static byte MSBMask(byte inputByte) +// { +// inputByte |= (byte)(inputByte >> 1); +// inputByte |= (byte)(inputByte >> 2); +// inputByte |= (byte)(inputByte >> 4); +// return (byte)((inputByte + 1) >> 1); +// } +// } \ No newline at end of file diff --git a/CLVMDotNet/src/Tools/IR/BinUtils.cs b/CLVMDotNet/src/Tools/IR/BinUtils.cs index 4ae196c..48bc22c 100644 --- a/CLVMDotNet/src/Tools/IR/BinUtils.cs +++ b/CLVMDotNet/src/Tools/IR/BinUtils.cs @@ -21,7 +21,7 @@ public static SExp AssembleFromIR(SExp ir_sexp) keyword = keyword.Substring(1); } - var atom = x.Keywords.KEYWORD_TO_ATOM[keyword]; + var atom = CLVM.Operators.KEYWORD_TO_ATOM()[keyword]; if (atom != null) { return SExp.To(atom); diff --git a/CLVMDotNet/src/Tools/IR/Clvmc.cs b/CLVMDotNet/src/Tools/IR/Clvmc.cs index 1399781..65c49b9 100644 --- a/CLVMDotNet/src/Tools/IR/Clvmc.cs +++ b/CLVMDotNet/src/Tools/IR/Clvmc.cs @@ -1,35 +1,35 @@ -using CLVMDotNet.CLVM; -using CLVMDotNet.Extensions; - -namespace CLVMDotNet.Tools.IR -{ - public class Clvmc - { - public static SExp CompileCLVMText(string text, string[] searchPaths) - { - var ir_src = IRReader.ReadIR(text); - var assembled_sexp = BinUtils.AssembleFromIR(ir_src); - var input_sexp = SExp.To((assembled_sexp, Array.Empty())); - - // everthing above here matches python - var tree = HelperFunctions.PrintTree(input_sexp); - var result = Program.RunProgram(null, input_sexp); - - //Need a RunProgramForSearchPaths - - return result.Item2; - } - - public static void CompileCLVM(string inputPath, string outputPath, string[] searchPaths) - { - - } - - - /// - /// - //compile_clvm_text - //compile_clvm - //find_files - } -} \ No newline at end of file +// using CLVMDotNet.CLVM; +// using CLVMDotNet.Extensions; +// +// namespace CLVMDotNet.Tools.IR +// { +// public class Clvmc +// { +// public static SExp CompileCLVMText(string text, string[] searchPaths) +// { +// var ir_src = IRReader.ReadIR(text); +// var assembled_sexp = BinUtils.AssembleFromIR(ir_src); +// var input_sexp = SExp.To((assembled_sexp, Array.Empty())); +// +// // everthing above here matches python +// var tree = HelperFunctions.PrintTree(input_sexp); +// var result = Program.RunProgram(null, input_sexp); +// +// //Need a RunProgramForSearchPaths +// +// return result.Item2; +// } +// +// public static void CompileCLVM(string inputPath, string outputPath, string[] searchPaths) +// { +// +// } +// +// +// /// +// /// +// //compile_clvm_text +// //compile_clvm +// //find_files +// } +// } \ No newline at end of file diff --git a/CLVMDotNet/src/Tools/Stages/Stage2/Compile.cs b/CLVMDotNet/src/Tools/Stages/Stage2/Compile.cs index 440f826..d2f588d 100644 --- a/CLVMDotNet/src/Tools/Stages/Stage2/Compile.cs +++ b/CLVMDotNet/src/Tools/Stages/Stage2/Compile.cs @@ -4,7 +4,7 @@ namespace CLVMDotNet.Tools.Stages.Stage2; public static class Compile { - public static byte QUOTE_ATOM => Keywords.KEYWORD_TO_ATOM["q"]; - public static byte APPLY_ATOM => Keywords.KEYWORD_TO_ATOM["a"]; - public static byte CONS_ATOM => Keywords.KEYWORD_TO_ATOM["c"]; + public static byte[] QUOTE_ATOM => CLVM.Operators.KEYWORD_TO_ATOM()["q"]; + public static byte[] APPLY_ATOM => CLVM.Operators.KEYWORD_TO_ATOM()["a"]; + public static byte[] CONS_ATOM => CLVM.Operators.KEYWORD_TO_ATOM()["c"]; } \ No newline at end of file diff --git a/CLVMDotNet/src/Tools/Stages/Stage2/Helpers.cs b/CLVMDotNet/src/Tools/Stages/Stage2/Helpers.cs index 1847ad2..a20cb3a 100644 --- a/CLVMDotNet/src/Tools/Stages/Stage2/Helpers.cs +++ b/CLVMDotNet/src/Tools/Stages/Stage2/Helpers.cs @@ -4,10 +4,10 @@ namespace CLVMDotNet.Tools.Stages.Stage2; public static class Helpers { - public static byte QUOTE_ATOM => Keywords.KEYWORD_TO_ATOM["q"]; - public static byte APPLY_ATOM => Keywords.KEYWORD_TO_ATOM["a"]; + public static byte[] QUOTE_ATOM => CLVM.Operators.KEYWORD_TO_ATOM()["q"]; + public static byte[] APPLY_ATOM => CLVM.Operators.KEYWORD_TO_ATOM()["a"]; - public static Tuple Quote(SExp sexp) + public static Tuple Quote(SExp sexp) { return Tuple.Create(QUOTE_ATOM, sexp); } diff --git a/CLVMDotNet/src/Tools/Stages/Stage2/Mod.cs b/CLVMDotNet/src/Tools/Stages/Stage2/Mod.cs index da0180e..953d11c 100644 --- a/CLVMDotNet/src/Tools/Stages/Stage2/Mod.cs +++ b/CLVMDotNet/src/Tools/Stages/Stage2/Mod.cs @@ -4,8 +4,8 @@ namespace CLVMDotNet.Tools.Stages.Stage2; public static class Mod { - public static byte QUOTE_ATOM => Keywords.KEYWORD_TO_ATOM["q"]; - public static byte CONS_ATOM => Keywords.KEYWORD_TO_ATOM["c"]; + public static byte[] QUOTE_ATOM => CLVM.Operators.KEYWORD_TO_ATOM()["q"]; + public static byte[] CONS_ATOM => CLVM.Operators.KEYWORD_TO_ATOM()["c"]; public static byte[] MAIN_NAME => new byte[] { }; /// diff --git a/CLVMDotNet/src/Tools/Stages/Stage2/Optimize.cs b/CLVMDotNet/src/Tools/Stages/Stage2/Optimize.cs index cc4591a..08de91e 100644 --- a/CLVMDotNet/src/Tools/Stages/Stage2/Optimize.cs +++ b/CLVMDotNet/src/Tools/Stages/Stage2/Optimize.cs @@ -6,12 +6,12 @@ namespace CLVMDotNet.Tools.Stages.Stage2; public static class Optimize { - public static byte QUOTE_ATOM => Keywords.KEYWORD_TO_ATOM["q"]; - public static byte APPLY_ATOM => Keywords.KEYWORD_TO_ATOM["a"]; - public static byte FIRST_ATOM => Keywords.KEYWORD_TO_ATOM["f"]; - public static byte REST_ATOM => Keywords.KEYWORD_TO_ATOM["r"]; - public static byte CONS_ATOM => Keywords.KEYWORD_TO_ATOM["c"]; - public static byte RAISE_ATOM => Keywords.KEYWORD_TO_ATOM["x"]; + public static byte[] QUOTE_ATOM => CLVM.Operators.KEYWORD_TO_ATOM()["q"]; + public static byte[] APPLY_ATOM => CLVM.Operators.KEYWORD_TO_ATOM()["a"]; + public static byte[] FIRST_ATOM => CLVM.Operators.KEYWORD_TO_ATOM()["f"]; + public static byte[] REST_ATOM => CLVM.Operators.KEYWORD_TO_ATOM()["r"]; + public static byte[] CONS_ATOM => CLVM.Operators.KEYWORD_TO_ATOM()["c"]; + public static byte[] RAISE_ATOM => CLVM.Operators.KEYWORD_TO_ATOM()["x"]; public static int DEBUG_OPTIMIZATIONS = 0; public static SExp CONS_Q_A_OPTIMIZER_PATTERN => BinUtils.Assemble("(a (q . (: . sexp)) (: . args))"); public static SExp CONS_PATTERN = BinUtils.Assemble("(c (: . first) (: . rest)))"); @@ -90,7 +90,7 @@ public static SExp ChildrenOptimizer(SExp r, Func> if (!operatorSexp.Listp()) { var op = operatorSexp.AsAtom(); - if (op.SequenceEqual(new byte[] { QUOTE_ATOM })) + if (op.SequenceEqual(QUOTE_ATOM)) { return r; } diff --git a/CLVMDotNet/tests/CLVM/Operators/ApplyOperatorTests.cs b/CLVMDotNet/tests/CLVM/Operators/ApplyOperatorTests.cs index 59b1a95..748f2cc 100644 --- a/CLVMDotNet/tests/CLVM/Operators/ApplyOperatorTests.cs +++ b/CLVMDotNet/tests/CLVM/Operators/ApplyOperatorTests.cs @@ -1,3 +1,4 @@ +using System.Globalization; using System.Numerics; using System.Text; using Xunit; @@ -12,55 +13,82 @@ public class OperatorTests { #region OpAdd - [Fact] - public void OpAdd() + [Theory] + [InlineData("1,2,10", new byte[] { 13 }, "1078")] + //[InlineData("12323232,211112323232323,1111468899990", new byte[] { 0x00, 0xC1, 0x04, 0x7A, 0x3A, 0x79 }, "1180")] + public void OpAdd(string numbersToAdd, byte[] resultAtom, string expectedCostStr) { // Arrange - + BigInteger expectedCost = BigInteger.Parse(expectedCostStr); + List ints = numbersToAdd.Split(',') + .Select(s => BigInteger.Parse(s.Trim())) + .ToList(); + + // Act - var result = x.Operator.ApplyOperator(new byte[] { 0x10 }, x.SExp.To(new List { 3, 4, 5 })); - + var result = x.OperatorDict.OPERATOR_LOOKUP() + .ApplyOperator(new byte[] { 0x10 }, x.SExp.To(ints)); + // Assert + Assert.Equal(expectedCost, result.Item1); + Assert.True(result.Item2.AsAtom().SequenceEqual(resultAtom)); } #endregion - [Fact] - public void OpSubtract() + [Theory] + [InlineData("3,1", new byte[] { 2 }, "755")] + public void OpSubtract(string numbersToSubtract, byte[] resultAtom, string expectedCostStr) { // Arrange - + BigInteger expectedCost = BigInteger.Parse(expectedCostStr); + List ints = numbersToSubtract.Split(',') + .Select(s => BigInteger.Parse(s.Trim())) + .ToList(); + // Act - var result = x.Operator.ApplyOperator(new byte[] { 0x11 }, x.SExp.To(new List { 3, 1 })); - + var result = x.OperatorDict.OPERATOR_LOOKUP() + .ApplyOperator(new byte[] { 0x11 }, x.SExp.To(ints)); + // Assert + Assert.Equal(expectedCost, result.Item1); + Assert.True(result.Item2.AsAtom().SequenceEqual(resultAtom)); } #region OpDivide - [Fact] - public void OpDivide() + [Theory] + [InlineData("10,2", new byte[] { 5 }, "1006")] + public void OpDivide(string numbersToDivide, byte[] resultAtom, string expectedCostStr) { // Arrange - + BigInteger expectedCost = BigInteger.Parse(expectedCostStr); + List ints = numbersToDivide.Split(',') + .Select(s => BigInteger.Parse(s.Trim())) + .ToList(); + // Act - var result = x.Operator.ApplyOperator(new byte[] { 0x13}, x.SExp.To(new List { 10, 2 })); + var result = x.OperatorDict.OPERATOR_LOOKUP() + .ApplyOperator(new byte[] { 0x13 }, x.SExp.To(ints)); // Assert + Assert.Equal(expectedCost, result.Item1); + Assert.True(result.Item2.AsAtom().SequenceEqual(resultAtom)); } [Fact] public void OpDivideThrowsExceptionIfDividingByZero() { // Arrange - + // Act var errorMessage = Assert.Throws(() => - x.Operator.ApplyOperator(new byte[] { 0x13 }, x.SExp.To(new List { 10, 0 })) + x.OperatorDict.OPERATOR_LOOKUP() + .ApplyOperator(new byte[] { 0x13 }, x.SExp.To(new List { 10, 0 })) ); - + // Assert Assert.Contains("div with 0", errorMessage.Message); } @@ -69,37 +97,47 @@ public void OpDivideThrowsExceptionIfDividingByZero() public void OpDivideThrowsExceptionWithNegativeOperand1() { // Arrange - + // Act var errorMessage = Assert.Throws(() => - x.Operator.ApplyOperator(new byte[] { 0x13 }, x.SExp.To(new List { -1, 5 })) + x.OperatorDict.OPERATOR_LOOKUP() + .ApplyOperator(new byte[] { 0x13 }, x.SExp.To(new List { -1, 5 })) ); - + // Assert Assert.Contains("div operator with negative operands is deprecated", errorMessage.Message); } #endregion - [Fact] - public void OpMultiply() + [Theory] + [InlineData("30,5", new byte[] { 0x00, 0x96 }, "1009")] + public void OpMultiply(string numbersToMultiply, byte[] resultAtom, string expectedCostStr) { // Arrange - + BigInteger expectedCost = BigInteger.Parse(expectedCostStr); + List ints = numbersToMultiply.Split(',') + .Select(s => BigInteger.Parse(s.Trim())) + .ToList(); + // Act - var result = x.Operator.ApplyOperator(new byte[] { 0x12 }, x.SExp.To(new List { 10, 3 })); + var result = x.OperatorDict.OPERATOR_LOOKUP() + .ApplyOperator(new byte[] { 0x12 }, x.SExp.To(ints)); // Assert + Assert.Equal(expectedCost, result.Item1); + Assert.True(result.Item2.AsAtom().SequenceEqual(resultAtom)); } [Fact] public void OpDivMod() { // Arrange - + // Act - var result = x.Operator.ApplyOperator(new byte[] { 0x14 }, x.SExp.To(new List { 3, 5 })); + var result = x.OperatorDict.OPERATOR_LOOKUP() + .ApplyOperator(new byte[] { 0x14 }, x.SExp.To(new List { 3, 5 })); // Assert } @@ -108,9 +146,10 @@ public void OpDivMod() public void OpConcat() { // Arrange - + // Act - var result = x.Operator.ApplyOperator(new byte[] { 0x0E }, x.SExp.To(new List { "test", "ing" })); + var result = x.OperatorDict.OPERATOR_LOOKUP() + .ApplyOperator(new byte[] { 0x0E }, x.SExp.To(new List { "test", "ing" })); // Assert } @@ -123,13 +162,14 @@ public void OpConcat() public void OpSubstrThrowsWhenOutOfBounds(int startIndex) { // Arrange - + // Act var errorMessage = Assert.Throws(() => - x.Operator.ApplyOperator(new byte[] { 0x0C }, x.SExp.To(new List { "kevin", startIndex })) + x.OperatorDict.OPERATOR_LOOKUP().ApplyOperator(new byte[] { 0x0C }, + x.SExp.To(new List { "kevin", startIndex })) ); - + // Assert Assert.Contains("invalid indices for substr", errorMessage.Message); } @@ -138,13 +178,14 @@ public void OpSubstrThrowsWhenOutOfBounds(int startIndex) public void OpSubstrThrowsWithTwoManyArgs() { // Arrange - + // Act var errorMessage = Assert.Throws(() => - x.Operator.ApplyOperator(new byte[] { 0x0C }, x.SExp.To(new List { "kevin", 1, 2, 3 })) + x.OperatorDict.OPERATOR_LOOKUP().ApplyOperator(new byte[] { 0x0C }, + x.SExp.To(new List { "kevin", 1, 2, 3 })) ); - + // Assert Assert.Contains("substr takes exactly 2 or 3 arguments", errorMessage.Message); } @@ -153,13 +194,14 @@ public void OpSubstrThrowsWithTwoManyArgs() public void OpSubstrThrowsWithTooFewArgs() { // Arrange - + // Act var errorMessage = Assert.Throws(() => - x.Operator.ApplyOperator(new byte[] { 0x0C }, x.SExp.To(new List { "kevin" })) + x.OperatorDict.OPERATOR_LOOKUP() + .ApplyOperator(new byte[] { 0x0C }, x.SExp.To(new List { "kevin" })) ); - + // Assert Assert.Contains("substr takes exactly 2 or 3 arguments", errorMessage.Message); } @@ -168,17 +210,19 @@ public void OpSubstrThrowsWithTooFewArgs() [InlineData("1", "somelongstring", 4, "longstring")] [InlineData("1", "somelongstring", 0, "somelongstring")] [InlineData("1", "somelongstring", 13, "g")] - public void OpSubstrReturnsSubStringWithCost(string stringCost, string val, int startindex, string expectedResult) + public void OpSubstrReturnsSubStringWithCost(string stringCost, string val, int startindex, + string expectedResult) { // Arrange BigInteger cost = BigInteger.Parse(stringCost); - + // Act var result = - x.Operator.ApplyOperator(new byte[] { 0x0C }, x.SExp.To(new List { val, startindex })); + x.OperatorDict.OPERATOR_LOOKUP() + .ApplyOperator(new byte[] { 0x0C }, x.SExp.To(new List { val, startindex })); var atom = result.Item2.AsAtom(); string text = Encoding.UTF8.GetString(atom); - + // Assert Assert.Equal(expectedResult, text); Assert.Equal(cost, result.Item1); @@ -194,13 +238,13 @@ public void OpSubstrReturnsSubStringOfNumberOfCharactersWithCost(string stringCo { // Arrange BigInteger cost = BigInteger.Parse(stringCost); - + // Act - var result = x.Operator.ApplyOperator(new byte[] { 0x0C }, + var result = x.OperatorDict.OPERATOR_LOOKUP().ApplyOperator(new byte[] { 0x0C }, x.SExp.To(new List { val, startindex, endIndex })); var atom = result.Item2.AsAtom(); string text = Encoding.UTF8.GetString(atom!); - + // Assert Assert.Equal(expectedResult, text); Assert.Equal(cost, result.Item1); @@ -218,31 +262,30 @@ public void OpSubstrReturnsSubStringOfNumberOfCharactersWithCost(string stringCo public void OpStrLen(string val, int length, int cost) { // Arrange - + // Act - var result = x.Operator.ApplyOperator(new byte[] { 0x0D }, + var result = x.OperatorDict.OPERATOR_LOOKUP().ApplyOperator(new byte[] { 0x0D }, x.SExp.To(new List { val })); var atom = result.Item2.AsAtom(); var actualLength = new BigInteger(atom!); - + // Assert Assert.Equal(length, actualLength); Assert.Equal(cost, result.Item1); } - [Fact] public void OpStrLenThrowsWithTooManyArgs() { // Arrange - + // Act var errorMessage = Assert.Throws(() => - x.Operator.ApplyOperator(new byte[] { 0x0D }, + x.OperatorDict.OPERATOR_LOOKUP().ApplyOperator(new byte[] { 0x0D }, x.SExp.To(new List { "THIS", "WILL THROW AN EXCEPTION" })) ); - + // Assert Assert.Contains("strlen takes exactly 1 argument", errorMessage.Message); } @@ -251,29 +294,32 @@ public void OpStrLenThrowsWithTooManyArgs() public void OpStrLenThrowsIfPair() { // Arrange - + // Act var errorMessage = Assert.Throws(() => - x.Operator.ApplyOperator(new byte[] { 0x0D }, x.SExp.To(new List { 3, 1 })) + x.OperatorDict.OPERATOR_LOOKUP() + .ApplyOperator(new byte[] { 0x0D }, x.SExp.To(new List { 3, 1 })) ); - + // Assert Assert.Contains("strlen takes exactly 1 argument", errorMessage.Message); } #endregion + #region OpSHA256 [Fact] public void OpSHA256() { // Arrange - + // Act var result = - x.Operator.ApplyOperator(new byte[] { 0x0B }, x.SExp.To(new List { "THIS IS A SHA256 HASH" })); + x.OperatorDict.OPERATOR_LOOKUP().ApplyOperator(new byte[] { 0x0B }, + x.SExp.To(new List { "THIS IS A SHA256 HASH" })); var atom = result.Item2.AsAtom(); // Assert @@ -289,69 +335,73 @@ public void OpSHA256() public void OpSHA256OnList_ThrowsError() { // Arrange - + // Act var errorMessage = Assert.Throws(() => - x.Operator.ApplyOperator(new byte[] { 0x0B }, + x.OperatorDict.OPERATOR_LOOKUP().ApplyOperator(new byte[] { 0x0B }, x.SExp.To(new List { "SOME", "ERror" }))); - + // Assert Assert.Contains("sha256 on list", errorMessage.Message); } #endregion - + #region GrBytes + [Theory] [InlineData(119, "a", "b")] [InlineData(131, "testing", "testing")] public void OpGrBytesReturnsFalse(int expectedCost, string val1, string val2) { // Arrange - + // Act - var result = x.Operator.ApplyOperator(new byte[] { 0x0A }, x.SExp.To(new List { val1, val2 })); + var result = x.OperatorDict.OPERATOR_LOOKUP() + .ApplyOperator(new byte[] { 0x0A }, x.SExp.To(new List { val1, val2 })); var areEqual = x.SExp.False.Equals(result.Item2); - + // Assert Assert.True(areEqual); Assert.Equal(expectedCost, result.Item1); } - + [Theory] [InlineData(119, "b", "a")] public void OpGrBytesReturnsTrue(int expectedCost, string val1, string val2) { // Arrange - + // Act - var result = x.Operator.ApplyOperator(new byte[] { 0x0A }, x.SExp.To(new List { val1, val2 })); + var result = x.OperatorDict.OPERATOR_LOOKUP() + .ApplyOperator(new byte[] { 0x0A }, x.SExp.To(new List { val1, val2 })); var areEqual = x.SExp.True.Equals(result.Item2); - + // Assert Assert.True(areEqual); Assert.Equal(expectedCost, result.Item1); } - + [Fact] public void OpGrBytesThrowsWithMoreThanTwoParameters() { // Arrange - + // Act var errorMessage = Assert.Throws(() => - x.Operator.ApplyOperator(new byte[] { 0x0A }, + x.OperatorDict.OPERATOR_LOOKUP().ApplyOperator(new byte[] { 0x0A }, x.SExp.To(new List { "val1", "val", "val3" }))); - + // Assert Assert.Contains(">s takes exactly 2 arguments", errorMessage.Message); } - + //TODO: Add test to throw when OpGrBytes is called on a pair + #endregion - + #region OpGr [Theory] @@ -362,16 +412,17 @@ public void OpGrReturnsFalse(int expectedCost, string strVal1, string strVal2, b // Arrange BigInteger val1 = BigInteger.Parse(strVal1); BigInteger val2 = BigInteger.Parse(strVal2); - + // Act - var result = x.Operator.ApplyOperator(new byte[] { 0x15 }, x.SExp.To(new List { val1, val2 })); + var result = x.OperatorDict.OPERATOR_LOOKUP() + .ApplyOperator(new byte[] { 0x15 }, x.SExp.To(new List { val1, val2 })); var areEqual = x.SExp.False.Equals(result.Item2); - + // Assert Assert.True(areEqual); Assert.Equal(expectedCost, result.Item1); } - + [Theory] [InlineData(502, "4", "2", true)] [InlineData(502, "-1", "2", true, @@ -381,11 +432,12 @@ public void OpGrReturnsTrue(int expectedCost, string strVal1, string strVal2, bo // Arrange BigInteger val1 = BigInteger.Parse(strVal1); BigInteger val2 = BigInteger.Parse(strVal2); - + // Act - var result = x.Operator.ApplyOperator(new byte[] { 0x15 }, x.SExp.To(new List { val1, val2 })); + var result = x.OperatorDict.OPERATOR_LOOKUP() + .ApplyOperator(new byte[] { 0x15 }, x.SExp.To(new List { val1, val2 })); var areEqual = x.SExp.True.Equals(result.Item2); - + // Assert Assert.True(areEqual); Assert.Equal(expectedCost, result.Item1); @@ -395,12 +447,13 @@ public void OpGrReturnsTrue(int expectedCost, string strVal1, string strVal2, bo public void OpGrThrowIfMoreThan2ArgumentsPassed() { // Arrange - + // Act var errorMessage = Assert.Throws(() => - x.Operator.ApplyOperator(new byte[] { 0x15 }, x.SExp.To(new List { 1, 2, 3 }))); - + x.OperatorDict.OPERATOR_LOOKUP() + .ApplyOperator(new byte[] { 0x15 }, x.SExp.To(new List { 1, 2, 3 }))); + // Assert Assert.Contains("> takes exactly 2 arguments", errorMessage.Message); } @@ -409,12 +462,13 @@ public void OpGrThrowIfMoreThan2ArgumentsPassed() public void OpGrThrowIfLessThan2ArgumentsPassed() { // Arrange - + // Act var errorMessage = Assert.Throws(() => - x.Operator.ApplyOperator(new byte[] { 0x15 }, x.SExp.To(new List { 1 }))); - + x.OperatorDict.OPERATOR_LOOKUP() + .ApplyOperator(new byte[] { 0x15 }, x.SExp.To(new List { 1 }))); + // Assert Assert.Contains("> takes exactly 2 arguments", errorMessage.Message); } @@ -427,12 +481,12 @@ public void OpGrThrowIfLessThan2ArgumentsPassed() public void OpEqReturnsTrueWhenTwoStringsMatch() { // Arrange - + // Act - var result = x.Operator.ApplyOperator(new byte[] { 0x09 }, + var result = x.OperatorDict.OPERATOR_LOOKUP().ApplyOperator(new byte[] { 0x09 }, x.SExp.To(new List { "SomeString", "SomeString" })); var areEqual = x.SExp.True.Equals(result.Item2); - + // Assert Assert.True(areEqual); Assert.Equal(137, result.Item1); @@ -442,12 +496,12 @@ public void OpEqReturnsTrueWhenTwoStringsMatch() public void OpEqReturnsFalseWhenTwoStringsDoNotMatch() { // Arrange - + // Act - var result = x.Operator.ApplyOperator(new byte[] { 0x09 }, + var result = x.OperatorDict.OPERATOR_LOOKUP().ApplyOperator(new byte[] { 0x09 }, x.SExp.To(new List { "val1", "DOTNOTMATCH" })); var areEqual = x.SExp.False.Equals(result.Item2); - + // Assert Assert.True(areEqual); Assert.Equal(132, result.Item1); @@ -457,12 +511,12 @@ public void OpEqReturnsFalseWhenTwoStringsDoNotMatch() public void OpEqReturnTrueWhenTwoEmptyStringsMatchMatch() { // Arrange - + // Act - var result = x.Operator.ApplyOperator(new byte[] { 0x09 }, + var result = x.OperatorDict.OPERATOR_LOOKUP().ApplyOperator(new byte[] { 0x09 }, x.SExp.To(new List { "", x.SExp.To(new List()) })); var areEqual = x.SExp.True.Equals(result.Item2); - + // Assert Assert.True(areEqual); Assert.Equal(117, result.Item1); @@ -472,13 +526,13 @@ public void OpEqReturnTrueWhenTwoEmptyStringsMatchMatch() public void OpEqThrowsWhenMoreThanTwoArguments() { // Arrange - + // Act var errorMessage = Assert.Throws(() => - x.Operator.ApplyOperator(new byte[] { 0x09 }, + x.OperatorDict.OPERATOR_LOOKUP().ApplyOperator(new byte[] { 0x09 }, x.SExp.To(new List { "1", "1", x.SExp.To("") }))); - + // Assert Assert.Contains("= takes exactly 2 arguments", errorMessage.Message); } @@ -488,19 +542,20 @@ public void OpEqThrowsWhenMoreThanTwoArguments() public void OpEqThrowsWhenLessThanTwoArguments() { // Arrange - + // Act var errorMessage = Assert.Throws(() => - x.Operator.ApplyOperator(new byte[] { 0x09 }, + x.OperatorDict.OPERATOR_LOOKUP().ApplyOperator(new byte[] { 0x09 }, x.SExp.To(new List { "SOMESTRING" }))); - + // Assert Assert.Contains("= takes exactly 2 arguments", errorMessage.Message); } #endregion + #region OpLogand [Fact] @@ -509,7 +564,7 @@ public void OpLogAndInt() // Arrange // Act - var result = x.Operator.ApplyOperator(new byte[] { 0x18 }, x.SExp.To(new List { 15, 244 })); + var result = x.OperatorDict.OPERATOR_LOOKUP().ApplyOperator(new byte[] { 0x18 }, x.SExp.To(new List { 15, 244 })); var atom = result.Item2.AsAtom(); // Assert @@ -526,7 +581,7 @@ public void OpLogEmptyList() // Arrange // Act - var result = x.Operator.ApplyOperator(new byte[] { 0x18 }, x.SExp.To(new List { })); + var result = x.OperatorDict.OPERATOR_LOOKUP().ApplyOperator(new byte[] { 0x18 }, x.SExp.To(new List { })); var atom = result.Item2.AsAtom(); // Assert @@ -547,7 +602,7 @@ public void OpLogior() // Arrange // Act - var result = x.Operator.ApplyOperator(new byte[] { 0x19 }, x.SExp.To(new List { })); + var result = x.OperatorDict.OPERATOR_LOOKUP().ApplyOperator(new byte[] { 0x19 }, x.SExp.To(new List { })); var atom = result.Item2.AsAtom(); // Assert @@ -563,7 +618,7 @@ public void OpLogiorInt() // Arrange // Act - var result = x.Operator.ApplyOperator(new byte[] { 0x19 }, x.SExp.To(new List { 35, 689 })); + var result = x.OperatorDict.OPERATOR_LOOKUP().ApplyOperator(new byte[] { 0x19 }, x.SExp.To(new List { 35, 689 })); var atom = result.Item2.AsAtom(); // Assert @@ -584,7 +639,7 @@ public void OpLogxor() // Arrange // Act - var result = x.Operator.ApplyOperator(new byte[] { 0x1A }, x.SExp.To(new List { })); + var result = x.OperatorDict.OPERATOR_LOOKUP().ApplyOperator(new byte[] { 0x1A }, x.SExp.To(new List { })); var atom = result.Item2.AsAtom(); // Assert @@ -600,7 +655,7 @@ public void OpLogxorInt() // Arrange // Act - var result = x.Operator.ApplyOperator(new byte[] { 0x1A }, + var result = x.OperatorDict.OPERATOR_LOOKUP().ApplyOperator(new byte[] { 0x1A }, x.SExp.To(new List { 111111, 67452345657 })); var atom = result.Item2.AsAtom(); @@ -622,7 +677,7 @@ public void OpLogNot() // Arrange // Act - var result = x.Operator.ApplyOperator(new byte[] { 0x1B }, x.SExp.To(new List { 1 })); + var result = x.OperatorDict.OPERATOR_LOOKUP().ApplyOperator(new byte[] { 0x1B }, x.SExp.To(new List { 1 })); var atom = result.Item2.AsAtom(); // Assert @@ -639,7 +694,7 @@ public void OpLogNotNegativeNumbers() // Arrange // Act - var result = x.Operator.ApplyOperator(new byte[] { 0x1B }, x.SExp.To(new List { -1111 })); + var result = x.OperatorDict.OPERATOR_LOOKUP().ApplyOperator(new byte[] { 0x1B }, x.SExp.To(new List { -1111 })); var atom = result.Item2.AsAtom(); // Assert @@ -658,7 +713,7 @@ public void OpLogNotThrowsWithNoParameters() // Act var errorMessage = Assert.Throws(() => - x.Operator.ApplyOperator(new byte[] { 0x1B }, + x.OperatorDict.OPERATOR_LOOKUP().ApplyOperator(new byte[] { 0x1B }, x.SExp.To(new List { }))); // Assert @@ -680,7 +735,7 @@ public void OpPubKeyForExp() // Act var result = - x.Operator.ApplyOperator(new byte[] { 0x1E }, x.SExp.To(new List { "this is a test" })); + x.OperatorDict.OPERATOR_LOOKUP().ApplyOperator(new byte[] { 0x1E }, x.SExp.To(new List { "this is a test" })); var atom = result.Item2.AsAtom(); // Assert @@ -701,7 +756,7 @@ public void OpPubKeyThrowsWithNoArgumentsp() // Act var errorMessage = Assert.Throws(() => - x.Operator.ApplyOperator(new byte[] { 0x1E }, x.SExp.To(new List { }))); + x.OperatorDict.OPERATOR_LOOKUP().ApplyOperator(new byte[] { 0x1E }, x.SExp.To(new List { }))); // Assert Assert.Contains("pubkey_for_exp takes exactly 1 arguments", errorMessage.Message); @@ -717,7 +772,7 @@ public void OpAnyReturnsTrueIfListIsNotEmpty() // Arrange // Act - var result = x.Operator.ApplyOperator(new byte[] { 0x21 }, + var result = x.OperatorDict.OPERATOR_LOOKUP().ApplyOperator(new byte[] { 0x21 }, x.SExp.To(new List { 1 })); var areEqual = x.SExp.True.Equals(result.Item2); @@ -732,7 +787,7 @@ public void OpAnyReturnsTrueWithMoreThanOneArg() // Arrange // Act - var result = x.Operator.ApplyOperator(new byte[] { 0x21 }, + var result = x.OperatorDict.OPERATOR_LOOKUP().ApplyOperator(new byte[] { 0x21 }, x.SExp.To(new List { 1, 3, 4, 5 })); var areEqual = x.SExp.True.Equals(result.Item2); @@ -747,7 +802,7 @@ public void OpAnyReturnsFalseWithNoArgs() // Arrange // Act - var result = x.Operator.ApplyOperator(new byte[] { 0x21 }, + var result = x.OperatorDict.OPERATOR_LOOKUP().ApplyOperator(new byte[] { 0x21 }, x.SExp.To(new List { })); var areEqual = x.SExp.False.Equals(result.Item2); @@ -766,7 +821,7 @@ public void OpAllAtomsReturnsTrue() // Arrange // Act - var result = x.Operator.ApplyOperator(new byte[] { 0x22 }, x.SExp.To(new List { 1, 2, 3 })); + var result = x.OperatorDict.OPERATOR_LOOKUP().ApplyOperator(new byte[] { 0x22 }, x.SExp.To(new List { 1, 2, 3 })); var areEqual = x.SExp.True.Equals(result.Item2); // Assert @@ -780,7 +835,7 @@ public void OpAllWithEmptyAtomsReturnsTrue() // Arrange // Act - var result = x.Operator.ApplyOperator(new byte[] { 0x22 }, x.SExp.To(new List { })); + var result = x.OperatorDict.OPERATOR_LOOKUP().ApplyOperator(new byte[] { 0x22 }, x.SExp.To(new List { })); var areEqual = x.SExp.True.Equals(result.Item2); // Assert @@ -794,7 +849,7 @@ public void OpAllWithPairReturnsFalse() // Arrange // Act - var result = x.Operator.ApplyOperator(new byte[] { 0x22 }, x.SExp.To(new List { "+", 1, 2 })); + var result = x.OperatorDict.OPERATOR_LOOKUP().ApplyOperator(new byte[] { 0x22 }, x.SExp.To(new List { "+", 1, 2 })); var areEqual = x.SExp.True.Equals(result.Item2); // Assert @@ -812,7 +867,7 @@ public void OpNotNoneEmptyBytes() // Arrange // Act - var result = x.Operator.ApplyOperator(new byte[] { 0x20 }, x.SExp.To(new List { 0x01 })); + var result = x.OperatorDict.OPERATOR_LOOKUP().ApplyOperator(new byte[] { 0x20 }, x.SExp.To(new List { 0x01 })); var areEqual = x.SExp.False.Equals(result.Item2); // Assert @@ -828,7 +883,7 @@ public void OpNotThrowsIfEmptyBytes() // Act var errorMessage = Assert.Throws(() => - x.Operator.ApplyOperator(new byte[] { 0x20 }, x.SExp.To(new List { }))); + x.OperatorDict.OPERATOR_LOOKUP().ApplyOperator(new byte[] { 0x20 }, x.SExp.To(new List { }))); // Assert Assert.Contains("not takes exactly 1 arguments", errorMessage.Message); @@ -841,10 +896,10 @@ public void OpNotThrowsIfMoreThanOneByte() // Act var s = x.SExp.To(new byte[] { 0x01, 0x01 }); - + var errorMessage = Assert.Throws(() => - x.Operator.ApplyOperator(new byte[] { 0x20 }, x.SExp.To(new List { 0x01, 0x01 }))); + x.OperatorDict.OPERATOR_LOOKUP().ApplyOperator(new byte[] { 0x20 }, x.SExp.To(new List { 0x01, 0x01 }))); // Assert Assert.Contains("not takes exactly 1 arguments", errorMessage.Message); @@ -852,15 +907,17 @@ public void OpNotThrowsIfMoreThanOneByte() #endregion + #region OpAsh [Fact] public void OpAsh() { // Arrange - + // Act - var result = x.Operator.ApplyOperator(new byte[] { 0x16 }, x.SExp.To(new List { 1, 2 })); + var result = x.OperatorDict.OPERATOR_LOOKUP() + .ApplyOperator(new byte[] { 0x16 }, x.SExp.To(new List { 1, 2 })); // Assert Assert.Equal(new byte[] { 0x04 }, result.Item2.AsAtom()); @@ -871,11 +928,11 @@ public void OpAsh() public void OpAshThrowsWhenMoreThanTwoArguments() { // Arrange - + // Act var errorMessage = Assert.Throws(() => - x.Operator.ApplyOperator(new byte[] { 0x16 }, + x.OperatorDict.OPERATOR_LOOKUP().ApplyOperator(new byte[] { 0x16 }, x.SExp.To(new List { 1, 2, 4 }))); Assert.Contains("ash takes exactly 2 arguments", errorMessage.Message); } @@ -884,13 +941,13 @@ public void OpAshThrowsWhenMoreThanTwoArguments() public void OpAshThrowsWhenLessThanTwoArguments() { // Arrange - + // Act var errorMessage = Assert.Throws(() => - x.Operator.ApplyOperator(new byte[] { 0x16 }, + x.OperatorDict.OPERATOR_LOOKUP().ApplyOperator(new byte[] { 0x16 }, x.SExp.To(new List { 1, 2, 4 }))); - + // Assert Assert.Contains("ash takes exactly 2 arguments", errorMessage.Message); } @@ -903,9 +960,10 @@ public void OpAshThrowsWhenLessThanTwoArguments() public void OpLsh() { // Arrange - + // Act - var result = x.Operator.ApplyOperator(new byte[] { 0x17 }, x.SExp.To(new List { 1, 45 })); + var result = x.OperatorDict.OPERATOR_LOOKUP() + .ApplyOperator(new byte[] { 0x17 }, x.SExp.To(new List { 1, 45 })); // Assert Assert.Equal(new byte[] { 32, 0, 0, 0, 0, 0 }, result.Item2.AsAtom()); @@ -914,63 +972,65 @@ public void OpLsh() #endregion - #region OpDefaultUnknown - - [Fact] - public void UnsupportedOpThrowsException() - { - // Arrange - - // Act - var errorMessage = - Assert.Throws(() => - x.Operator.ApplyOperator(new byte[] { 0x3a }, - x.SExp.NULL)); - - // Assert - Assert.Contains("3A Operator not found or is unsupported!", errorMessage.Message); - } - - [Fact] - public void OpDefaultUnknownAtom() - { - // Arrange - - // Act - var result = x.Operator.ApplyOperator(new byte[] { 0x02 }, x.SExp.To(new List { 1, 2 })); - - // Assert - Assert.Null(result.Item2.AsAtom()); - Assert.Equal(1, result.Item1); - } - - [Fact] - public void OpDefaultUnknownQuote() - { - // Arrange - - // Act - var result = x.Operator.ApplyOperator(new byte[] { 0x01 }, x.SExp.To(new List { 1, 2 })); - - // Assert - Assert.Null(result.Item2.AsAtom()); - Assert.Equal(1, result.Item1); - } - - [Fact] - public void OpDefaultUnknownDot() - { - //Arrange - - // Act - var result = x.Operator.ApplyOperator(new byte[] { 0x23 }, x.SExp.To(new List { 1, 2 })); - - // Assert - Assert.Null(result.Item2.AsAtom()); - Assert.Equal(1, result.Item1); - } - - //TODO: Determine how apply operator can be called to call OpdefaultUnknown with op other than 0x01,0x02,0x23 - #endregion +// +// #region OpDefaultUnknown +// +// [Fact] +// public void UnsupportedOpThrowsException() +// { +// // Arrange +// +// // Act +// var errorMessage = +// Assert.Throws(() => +// x.Operator.ApplyOperator(new byte[] { 0x3a }, +// x.SExp.NULL)); +// +// // Assert +// Assert.Contains("3A Operator not found or is unsupported!", errorMessage.Message); +// } +// +// [Fact] +// public void OpDefaultUnknownAtom() +// { +// // Arrange +// +// // Act +// var result = x.Operator.ApplyOperator(new byte[] { 0x02 }, x.SExp.To(new List { 1, 2 })); +// +// // Assert +// Assert.Null(result.Item2.AsAtom()); +// Assert.Equal(1, result.Item1); +// } +// +// [Fact] +// public void OpDefaultUnknownQuote() +// { +// // Arrange +// +// // Act +// var result = x.Operator.ApplyOperator(new byte[] { 0x01 }, x.SExp.To(new List { 1, 2 })); +// +// // Assert +// Assert.Null(result.Item2.AsAtom()); +// Assert.Equal(1, result.Item1); +// } +// +// [Fact] +// public void OpDefaultUnknownDot() +// { +// //Arrange +// +// // Act +// var result = x.Operator.ApplyOperator(new byte[] { 0x23 }, x.SExp.To(new List { 1, 2 })); +// +// // Assert +// Assert.Null(result.Item2.AsAtom()); +// Assert.Equal(1, result.Item1); +// } +// +// //TODO: Determine how apply operator can be called to call OpdefaultUnknown with op other than 0x01,0x02,0x23 +// #endregion +// } } } \ No newline at end of file diff --git a/CLVMDotNet/tests/CLVM/Operators/KeywordFromAtomTests.cs b/CLVMDotNet/tests/CLVM/Operators/KeywordFromAtomTests.cs index e8c2aae..0ca2384 100644 --- a/CLVMDotNet/tests/CLVM/Operators/KeywordFromAtomTests.cs +++ b/CLVMDotNet/tests/CLVM/Operators/KeywordFromAtomTests.cs @@ -6,12 +6,11 @@ namespace CLVMDotNet.Tests.CLVM.Operators; public class KeywordFromAtomTests { [Theory] - [InlineData(0x23, ".")] - [InlineData(0x02, "a")] - [InlineData(0x01, "q")] - [InlineData(0x03, "i")] - [InlineData(0x04, "c")] - [InlineData(0x05, "f")] + [InlineData(01, "q")] + [InlineData(2, "a")] + [InlineData(3, "i")] + [InlineData(4, "c")] + [InlineData(5, "f")] [InlineData(0x06, "r")] [InlineData(0x07, "l")] [InlineData(0x08, "x")] @@ -39,9 +38,11 @@ public class KeywordFromAtomTests [InlineData(0x20, "not")] [InlineData(0x21, "any")] [InlineData(0x22, "all")] + [InlineData(0x23, ".")] public void KeywordToAtom_Returns_correct_byte(byte atom, string expectedKeyword) { - var result = x.Keywords.KEYWORD_FROM_ATOM[atom]; + var bytes = new byte[] { atom }; + var result = x.Operators.KEYWORD_FROM_ATOM[bytes]; Assert.Equal(expectedKeyword, result); } @@ -53,9 +54,9 @@ public void UnknownAtom_ThrowsError() // Act var errorMessage = Assert.Throws(() => - x.Keywords.KEYWORD_FROM_ATOM[0xaa]); + x.Operators.KEYWORD_FROM_ATOM[new byte[] {0xaa}]); // Assert - Assert.Contains("The given key '170' was not present in the dictionary", errorMessage.Message); + Assert.Contains("was not present in the dictionary", errorMessage.Message); } } \ No newline at end of file diff --git a/CLVMDotNet/tests/CLVM/Operators/KeywordToAtomTests.cs b/CLVMDotNet/tests/CLVM/Operators/KeywordToAtomTests.cs index 75e5e37..3e8eb4c 100644 --- a/CLVMDotNet/tests/CLVM/Operators/KeywordToAtomTests.cs +++ b/CLVMDotNet/tests/CLVM/Operators/KeywordToAtomTests.cs @@ -1,14 +1,15 @@ using Xunit; -using clvm = CLVMDotNet.CLVM; +using x = CLVMDotNet.CLVM; namespace CLVMDotNet.Tests.CLVM; public class KeywordToAtomTests { [Theory] - [InlineData(".", 0x00)] - [InlineData("a", 0x02)] + + [InlineData("q", 0x01)] + [InlineData("a", 0x02)] [InlineData("i", 0x03)] [InlineData("c", 0x04)] [InlineData("f", 0x05)] @@ -20,7 +21,6 @@ public class KeywordToAtomTests [InlineData("substr", 0x0c)] [InlineData("strlen", 0x0d)] [InlineData("concat", 0x0e)] - // [InlineData("#", 0x0f)] [InlineData("+", 0x10)] [InlineData("-", 0x11)] [InlineData("*", 0x12)] @@ -38,10 +38,12 @@ public class KeywordToAtomTests [InlineData("not", 0x20)] [InlineData("any", 0x21)] [InlineData("all", 0x22)] + [InlineData(".", 0x23)] public void KeywordToAtom_Returns_correct_byte(string keyword, byte expectedByte) { - var result = clvm.Keywords.KEYWORD_TO_ATOM[keyword]; - Assert.Equal(expectedByte, result); + var bytes = new byte[] { expectedByte }.Reverse(); + var result = x.Operators.KEYWORD_TO_ATOM()[keyword]; + Assert.True(bytes.SequenceEqual(result)); } [Fact] @@ -52,7 +54,7 @@ public void UnknownKeyword_ThrowsError() // Act var errorMessage = Assert.Throws(() => - clvm.Keywords.KEYWORD_TO_ATOM["SomeInvalidKeyword"]); + x.Operators.KEYWORD_TO_ATOM()["SomeInvalidKeyword"]); // Assert Assert.Contains("given key 'SomeInvalidKeyword' was not present in the dictionary", errorMessage.Message); diff --git a/CLVMDotNet/tests/CLVM/Operators/OperatorDictTests.cs b/CLVMDotNet/tests/CLVM/Operators/OperatorDictTests.cs new file mode 100644 index 0000000..510c786 --- /dev/null +++ b/CLVMDotNet/tests/CLVM/Operators/OperatorDictTests.cs @@ -0,0 +1,19 @@ +// using CLVMDotNet.CLVM; +// using Xunit; +// +// namespace CLVMDotNet.Tests.CLVM.Operators; +// +// public class OperatorDictTests +// { +// [Fact] +// public void TestConstructor1() +// { +// var d = new Dictionary() +// { +// { "1", "hello"}, +// { "2", "goodbye" }, +// }; +// +// Assert.Throws(() => new OperatorDict(d, null)); +// } +// } \ No newline at end of file diff --git a/CLVMDotNet/tests/Tools/Clvmc/CompileCLVMText.cs b/CLVMDotNet/tests/Tools/Clvmc/CompileCLVMText.cs index 6b49097..e4d89db 100644 --- a/CLVMDotNet/tests/Tools/Clvmc/CompileCLVMText.cs +++ b/CLVMDotNet/tests/Tools/Clvmc/CompileCLVMText.cs @@ -1,16 +1,16 @@ -using CLVMDotNet.CLVM; -using CLVMDotNet.Tests.Helpers; -using Xunit; - -namespace CLVMDotNet.Tests.Tools.Clvmc; - -public class CompileCLVMText -{ - [Fact] - public void RunBasicProgram() - { - var result = CLVMDotNet.Tools.IR.Clvmc.CompileCLVMText("(/ 10 2)", Array.Empty()); - - var rs = result; - } -} \ No newline at end of file +// using CLVMDotNet.CLVM; +// using CLVMDotNet.Tests.Helpers; +// using Xunit; +// +// namespace CLVMDotNet.Tests.Tools.Clvmc; +// +// public class CompileCLVMText +// { +// [Fact] +// public void RunBasicProgram() +// { +// var result = CLVMDotNet.Tools.IR.Clvmc.CompileCLVMText("(/ 10 2)", Array.Empty()); +// +// var rs = result; +// } +// } \ No newline at end of file From 15589adfbdc536b348037c06d14dd59cc70b302b Mon Sep 17 00:00:00 2001 From: kev Date: Sat, 10 Feb 2024 15:06:13 +0000 Subject: [PATCH 29/29] Add stub code compile methods --- CLVMDotNet/src/Tools/IR/Clvmc.cs | 71 +++---- CLVMDotNet/src/Tools/Stages/Stage2/Compile.cs | 194 +++++++++++++++++- CLVMDotNet/src/Tools/Stages/Stage2/Helpers.cs | 13 +- .../src/Tools/Stages/Stage2/Operators.cs | 32 ++- .../HelperFunctions/ConvertAtomToBytes.cs | 10 - .../ConvertAtomToBytesTests.cs | 25 +++ ...MObject.cs => LooksLikeCLVMObjectTests.cs} | 2 +- .../{MSBMask.cs => MSBMaskTests.cs} | 2 +- .../{ToSexpType.cs => ToSexpTypeTests.cs} | 2 +- .../tests/Tools/Clvmc/CompileCLVMText.cs | 32 +-- 10 files changed, 306 insertions(+), 77 deletions(-) delete mode 100644 CLVMDotNet/tests/CLVM/HelperFunctions/ConvertAtomToBytes.cs create mode 100644 CLVMDotNet/tests/CLVM/HelperFunctions/ConvertAtomToBytesTests.cs rename CLVMDotNet/tests/CLVM/HelperFunctions/{LooksLikeCLVMObject.cs => LooksLikeCLVMObjectTests.cs} (79%) rename CLVMDotNet/tests/CLVM/HelperFunctions/{MSBMask.cs => MSBMaskTests.cs} (96%) rename CLVMDotNet/tests/CLVM/HelperFunctions/{ToSexpType.cs => ToSexpTypeTests.cs} (82%) diff --git a/CLVMDotNet/src/Tools/IR/Clvmc.cs b/CLVMDotNet/src/Tools/IR/Clvmc.cs index 65c49b9..9848d2b 100644 --- a/CLVMDotNet/src/Tools/IR/Clvmc.cs +++ b/CLVMDotNet/src/Tools/IR/Clvmc.cs @@ -1,35 +1,36 @@ -// using CLVMDotNet.CLVM; -// using CLVMDotNet.Extensions; -// -// namespace CLVMDotNet.Tools.IR -// { -// public class Clvmc -// { -// public static SExp CompileCLVMText(string text, string[] searchPaths) -// { -// var ir_src = IRReader.ReadIR(text); -// var assembled_sexp = BinUtils.AssembleFromIR(ir_src); -// var input_sexp = SExp.To((assembled_sexp, Array.Empty())); -// -// // everthing above here matches python -// var tree = HelperFunctions.PrintTree(input_sexp); -// var result = Program.RunProgram(null, input_sexp); -// -// //Need a RunProgramForSearchPaths -// -// return result.Item2; -// } -// -// public static void CompileCLVM(string inputPath, string outputPath, string[] searchPaths) -// { -// -// } -// -// -// /// -// /// -// //compile_clvm_text -// //compile_clvm -// //find_files -// } -// } \ No newline at end of file +using CLVMDotNet.CLVM; +using CLVMDotNet.Extensions; + +namespace CLVMDotNet.Tools.IR +{ + public class Clvmc + { + public static SExp CompileCLVMText(string text, string[] searchPaths) + { + var ir_src = IRReader.ReadIR(text); + var assembled_sexp = BinUtils.AssembleFromIR(ir_src); + var input_sexp = SExp.To((assembled_sexp, Array.Empty())); + + // everthing above here matches python + var tree = HelperFunctions.PrintTree(input_sexp); + // var result = Program.RunProgram(null, input_sexp); + + //Need a RunProgramForSearchPaths + + //return result.Item2; + return null; + } + + public static void CompileCLVM(string inputPath, string outputPath, string[] searchPaths) + { + + } + + + /// + /// + //compile_clvm_text + //compile_clvm + //find_files + } +} \ No newline at end of file diff --git a/CLVMDotNet/src/Tools/Stages/Stage2/Compile.cs b/CLVMDotNet/src/Tools/Stages/Stage2/Compile.cs index d2f588d..5b19de3 100644 --- a/CLVMDotNet/src/Tools/Stages/Stage2/Compile.cs +++ b/CLVMDotNet/src/Tools/Stages/Stage2/Compile.cs @@ -1,10 +1,184 @@ -using CLVMDotNet.CLVM; - -namespace CLVMDotNet.Tools.Stages.Stage2; - -public static class Compile -{ - public static byte[] QUOTE_ATOM => CLVM.Operators.KEYWORD_TO_ATOM()["q"]; - public static byte[] APPLY_ATOM => CLVM.Operators.KEYWORD_TO_ATOM()["a"]; - public static byte[] CONS_ATOM => CLVM.Operators.KEYWORD_TO_ATOM()["c"]; -} \ No newline at end of file +// using CLVMDotNet.CLVM; +// +// namespace CLVMDotNet.Tools.Stages.Stage2; +// +// public static class Compile +// { +// public static byte[] QUOTE_ATOM => CLVM.Operators.KEYWORD_TO_ATOM()["q"]; +// public static byte[] APPLY_ATOM => CLVM.Operators.KEYWORD_TO_ATOM()["a"]; +// public static byte[] CONS_ATOM => CLVM.Operators.KEYWORD_TO_ATOM()["c"]; +// +// +// public static SExp DoComProg(SExp prog, SExp macroLookup, SExp symbolTable, Func runProgram) +// { +// // Lower "quote" to "q" +// prog = LowerQuote(prog, macroLookup, symbolTable, runProgram); +// +// // Quote atoms +// if (prog.Nullp() || !prog.Listp()) +// { +// var atom = prog.AsAtom(); +// if (atom == HelperFunctions.ConvertAtomToBytes("@")) +// { +// return SExp.To(NodePath.TOP.AsShortPath()); +// } +// foreach (var pair in symbolTable.AsIter()) +// { +// var symbol = pair.First().AsAtom(); +// var value = pair.Rest().First(); +// if (symbol == atom) +// { +// return SExp.To(value); +// } +// } +// return SExp.To(Quote(prog)); +// } +// +// var operatorObj = prog.First(); +// if (operatorObj.Listp()) +// { +// // (com ((OP) . RIGHT)) => (a (com (q OP)) 1) +// var innerExp = Helpers.Eval(SExp.To(new CLVMObject(new List { "com", Quote(operatorObj), Quote(macroLookup), Quote(symbolTable) })), NodePath.TOP.AsShortPath()); +// return SExp.To(new CLVMObject(new List { innerExp })); +// } +// +// var asAtom = operatorObj.AsAtom(); +// +// foreach (var macroPair in macroLookup.AsIter()) +// { +// var macroName = macroPair.First().AsAtom(); +// if (macroName!.SequenceEqual(asAtom)) +// { +// var macroCode = macroPair.Rest().First(); +// var postProg = Helpers.Brun(macroCode, prog.Rest()); +// return Helpers.Eval(SExp.To(new CLVMObject(new List { "com", postProg, Quote(macroLookup), Quote(symbolTable) })), NodePath.TOP.AsShortPath()); +// } +// } +// +// if (COMPILE_BINDINGS.ContainsKey(asAtom)) +// { +// Func, CLVMObject> f = COMPILE_BINDINGS[asAtom]; +// var postProg = f(prog.Rest(), macroLookup, symbolTable, runProgram); +// return Helpers.Eval(SExp.To(Quote(postProg)), NodePath.TOP.AsShortPath()); +// } +// +// if (operatorObj.Equals(QUOTE_ATOM)) +// { +// return prog; +// } +// +// var compiledArgs = prog.Rest().AsIter().Select(arg => DoComProg(arg, macroLookup, symbolTable, runProgram)).ToList(); +// var r = SExp.To(new CLVMObject(new List { operatorObj }.Concat(compiledArgs))); +// +// if (PASS_THROUGH_OPERATORS.Contains(asAtom) || asAtom.StartsWith("_")) +// { +// return r; +// } +// +// foreach (var pair in symbolTable.AsPython()) +// { +// var symbol = pair.First().AsAtom(); +// var value = pair.Rest().First(); +// if (symbol == "*") +// { +// return r; +// } +// if (symbol.SequenceEqual(asAtom)) +// { +// var newArgs = Helpers.Eval(SExp.To(new CLVMObject(new List { "opt", new CLVMObject(new List { "com", Quote(new CLVMObject(new List { "list" }.Concat(prog.Rest().AsIter()))), Quote(macroLookup), Quote(symbolTable) }) })), TOP.AsPath()); +// r = SExp.To(new CLVMObject(new List { APPLY_ATOM, value, new CLVMObject(new List { NodePath.Left.AsShortPath(), newArgs }) })); +// return r; +// } +// } +// +// throw new SyntaxException($"can't compile , unknown operator"); +// //throw new Exception($"can't compile {Disassemble(prog)}, unknown operator"); +// } +// +// private static SExp Quote(SExp sexp) +// { +// return new SExp(new List { "q", sexp }); +// } +// +// public static SExp CompileMacros(SExp args, SExp macroLookup, SExp symbolTable, Func runProgram) +// { +// return SExp.To(Helpers.Quote(macroLookup)); +// } +// +// public static SExp CompileSymbols(SExp args, SExp macroLookup, SExp symbolTable, Func runProgram) +// { +// return SExp.To(Helpers.Quote(symbolTable)); +// } +// +// public static SExp CompileQQ(SExp args, SExp macroLookup, SExp symbolTable, Func runProgram, int level = 1) +// { +// SExp Com(SExp sexp) +// { +// return DoComProg(sexp, macroLookup, symbolTable, runProgram); +// } +// +// var sexp = args.First(); +// if (!sexp.Listp() || sexp.Nullp()) +// { +// // (qq ATOM) => (q . ATOM) +// return SExp.To(Helpers.Quote(sexp)); +// } +// +// if (sexp.Listp() && !sexp.First().Listp()) +// { +// var op = sexp.First().AsAtom(); +// if (op == HelperFunctions.ConvertAtomToBytes("qq")) +// { +// var subexp = CompileQQ(sexp.Rest(), macroLookup, symbolTable, runProgram, level + 1); +// return Com(SExp.To(new CLVMObject(new List { CONS_ATOM, op, new CLVMObject(new List { CONS_ATOM, subexp, Quote(0) }) })), macroLookup, symbolTable, runProgram); +// } +// if (op == HelperFunctions.ConvertAtomToBytes("unquote")) +// { +// if (level == 1) +// { +// // (qq (unquote X)) => X +// +// //return Com(sexp.Rest().First(), macroLookup, symbolTable, runProgram); +// } +// var subexp = CompileQQ(sexp.Rest(), macroLookup, symbolTable, runProgram, level - 1); +// return Com(SExp.To(new CLVMObject(new List { CONS_ATOM, op, new CLVMObject(new List { CONS_ATOM, subexp, Quote(0) }) })), macroLookup, symbolTable, runProgram); +// } +// } +// +// // (qq (a . B)) => (c (qq a) (qq B)) +// var A = Com(SExp.To(new List { "qq", sexp.First() })); +// var B = Com(SExp.To(new List { "qq", sexp.Rest() })); +// return SExp.To(new SExp(new List { CONS_ATOM, A, B })); +// } +// +// public static SExp LowerQuote(SExp prog, SExp? macroLookup = null, SExp? symbolTable = null, Func runProgram = null) +// { +// if (prog.Nullp()) +// { +// return prog; +// } +// +// if (prog.Listp()) +// { +// if (prog.First().AsAtom() == HelperFunctions.ConvertAtomToBytes("quote")) +// { +// // Note: quote should have exactly one arg, so the length of +// // quoted list should be 2: "(quote arg)" +// if (!prog.Rest().Rest().Nullp()) +// { +// throw new SyntaxException($"Compilation error while compiling quote takes exactly one argument."); +// //throw new SyntaxException($"Compilation error while compiling [{Disassemble(prog)}]. quote takes exactly one argument."); +// } +// return SExp.To(Quote(LowerQuote(prog.Rest().First()))); +// } +// else +// { +// return SExp.To((LowerQuote(prog.First()), LowerQuote(prog.Rest()))); +// } +// } +// else +// { +// return prog; +// } +// } +// } \ No newline at end of file diff --git a/CLVMDotNet/src/Tools/Stages/Stage2/Helpers.cs b/CLVMDotNet/src/Tools/Stages/Stage2/Helpers.cs index a20cb3a..8d7fc44 100644 --- a/CLVMDotNet/src/Tools/Stages/Stage2/Helpers.cs +++ b/CLVMDotNet/src/Tools/Stages/Stage2/Helpers.cs @@ -18,6 +18,15 @@ public static SExp Eval(SExp prog, dynamic args) return eval; } - //Run - //Brun + public static SExp Run(SExp prog, SExp macroLookup) + { + var args = NodePath.TOP.AsShortPath(); + var mac = Quote(macroLookup); + return Helpers.Eval(SExp.To(new List { "com", prog, mac }), args); + } + + public static SExp Brun(SExp prog, SExp args) + { + return Helpers.Eval(SExp.To(Quote(prog)), Quote(args)); + } } \ No newline at end of file diff --git a/CLVMDotNet/src/Tools/Stages/Stage2/Operators.cs b/CLVMDotNet/src/Tools/Stages/Stage2/Operators.cs index 1ecc79a..c6e98eb 100644 --- a/CLVMDotNet/src/Tools/Stages/Stage2/Operators.cs +++ b/CLVMDotNet/src/Tools/Stages/Stage2/Operators.cs @@ -16,7 +16,7 @@ public static Tuple DoRead(SExp args) var sexp = BinUtils.AssembleFromIR(irSexp); return new Tuple(1, sexp); } - + public static Tuple DoWrite(SExp args) { var filename = args.First().AsAtom(); @@ -26,4 +26,34 @@ public static Tuple DoWrite(SExp args) var sexp = BinUtils.AssembleFromIR(irSexp); return new Tuple(1, sexp); } + + + + public static SExp RunProgramProgramForSearchPaths(string[] searchPaths) + { + Dictionary BINDINGS = new Dictionary(); + BINDINGS["com"] = (op, sexp) => DoRead(sexp); + BINDINGS["opt"] = (op, sexp) => DoRead(sexp); + BINDINGS["_full_path_for_name"] = (op, sexp) => DoFullPathForName(sexp); + BINDINGS["_read"] = (op, sexp) => DoRead(sexp); + BINDINGS["_write"] = (op, sexp) => DoWrite(sexp); + + return null; + + Tuple DoFullPathForName(SExp args) + { + var filename = args.First().AsAtom(); + + foreach (string path in searchPaths) + { + string filePath = Path.Combine("", ""); + if (File.Exists(filePath)) + { + var sexp = SExp.To("test"); + return new Tuple(1, sexp); + } + } + throw new EvalError($"can't open {filename}"); + } + } } \ No newline at end of file diff --git a/CLVMDotNet/tests/CLVM/HelperFunctions/ConvertAtomToBytes.cs b/CLVMDotNet/tests/CLVM/HelperFunctions/ConvertAtomToBytes.cs deleted file mode 100644 index e2e74c0..0000000 --- a/CLVMDotNet/tests/CLVM/HelperFunctions/ConvertAtomToBytes.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Xunit; -using x = CLVMDotNet.CLVM; - -namespace CLVMDotNet.Tests.CLVM.HelperFunctions; - -[Trait("HelperFunctions","ConvertAtomToBytes")] -public class ConvertAtomToBytes -{ - -} \ No newline at end of file diff --git a/CLVMDotNet/tests/CLVM/HelperFunctions/ConvertAtomToBytesTests.cs b/CLVMDotNet/tests/CLVM/HelperFunctions/ConvertAtomToBytesTests.cs new file mode 100644 index 0000000..1b3f16f --- /dev/null +++ b/CLVMDotNet/tests/CLVM/HelperFunctions/ConvertAtomToBytesTests.cs @@ -0,0 +1,25 @@ +using Xunit; +using x = CLVMDotNet.CLVM; + +namespace CLVMDotNet.Tests.CLVM.HelperFunctions; + +[Trait("HelperFunctions","ConvertAtomToBytes")] +public class ConvertAtomToBytesTests +{ + [Theory] + [InlineData("@", new byte[] { 0x40})] + [InlineData("unquote", new byte[] { 0x75, 0x6E, 0x71, 0x75, 0x6F, 0x74, 0x65})] + [InlineData("qq", new byte[] { 0x71, 0x71 })] + [InlineData("quote", new byte[] { 0x71, 0x75, 0x6F, 0x74, 0x65 })] + public void ConvertStringToBytes_returnsCorrectBytes(string val, byte[] expectedBytes) + { + // Arrange + + // Act + var bytes = x.HelperFunctions.ConvertAtomToBytes(val); + + // Assert + Assert.True(bytes.SequenceEqual(expectedBytes)); + + } +} \ No newline at end of file diff --git a/CLVMDotNet/tests/CLVM/HelperFunctions/LooksLikeCLVMObject.cs b/CLVMDotNet/tests/CLVM/HelperFunctions/LooksLikeCLVMObjectTests.cs similarity index 79% rename from CLVMDotNet/tests/CLVM/HelperFunctions/LooksLikeCLVMObject.cs rename to CLVMDotNet/tests/CLVM/HelperFunctions/LooksLikeCLVMObjectTests.cs index 14bac6e..4862585 100644 --- a/CLVMDotNet/tests/CLVM/HelperFunctions/LooksLikeCLVMObject.cs +++ b/CLVMDotNet/tests/CLVM/HelperFunctions/LooksLikeCLVMObjectTests.cs @@ -4,7 +4,7 @@ namespace CLVMDotNet.Tests.CLVM.HelperFunctions; [Trait("HelperFunctions","LooksLikeCLVMObject")] -public class LooksLikeCLVMObject +public class LooksLikeCLVMObjectTests { } \ No newline at end of file diff --git a/CLVMDotNet/tests/CLVM/HelperFunctions/MSBMask.cs b/CLVMDotNet/tests/CLVM/HelperFunctions/MSBMaskTests.cs similarity index 96% rename from CLVMDotNet/tests/CLVM/HelperFunctions/MSBMask.cs rename to CLVMDotNet/tests/CLVM/HelperFunctions/MSBMaskTests.cs index 8992b5c..445fbc5 100644 --- a/CLVMDotNet/tests/CLVM/HelperFunctions/MSBMask.cs +++ b/CLVMDotNet/tests/CLVM/HelperFunctions/MSBMaskTests.cs @@ -5,7 +5,7 @@ namespace CLVMDotNet.Tests.CLVM.HelperFunctions { [Trait("HelperFunctions", "MSBMask")] - public class MSBMask + public class MSBMaskTests { [Theory] [InlineData(0x00, 0x00)] diff --git a/CLVMDotNet/tests/CLVM/HelperFunctions/ToSexpType.cs b/CLVMDotNet/tests/CLVM/HelperFunctions/ToSexpTypeTests.cs similarity index 82% rename from CLVMDotNet/tests/CLVM/HelperFunctions/ToSexpType.cs rename to CLVMDotNet/tests/CLVM/HelperFunctions/ToSexpTypeTests.cs index 4d08b0b..6eea954 100644 --- a/CLVMDotNet/tests/CLVM/HelperFunctions/ToSexpType.cs +++ b/CLVMDotNet/tests/CLVM/HelperFunctions/ToSexpTypeTests.cs @@ -4,7 +4,7 @@ namespace CLVMDotNet.Tests.CLVM.HelperFunctions; [Trait("HelperFunctions","ToSexpType")] -public class ToSexpType +public class ToSexpTypeTests { } \ No newline at end of file diff --git a/CLVMDotNet/tests/Tools/Clvmc/CompileCLVMText.cs b/CLVMDotNet/tests/Tools/Clvmc/CompileCLVMText.cs index e4d89db..6b49097 100644 --- a/CLVMDotNet/tests/Tools/Clvmc/CompileCLVMText.cs +++ b/CLVMDotNet/tests/Tools/Clvmc/CompileCLVMText.cs @@ -1,16 +1,16 @@ -// using CLVMDotNet.CLVM; -// using CLVMDotNet.Tests.Helpers; -// using Xunit; -// -// namespace CLVMDotNet.Tests.Tools.Clvmc; -// -// public class CompileCLVMText -// { -// [Fact] -// public void RunBasicProgram() -// { -// var result = CLVMDotNet.Tools.IR.Clvmc.CompileCLVMText("(/ 10 2)", Array.Empty()); -// -// var rs = result; -// } -// } \ No newline at end of file +using CLVMDotNet.CLVM; +using CLVMDotNet.Tests.Helpers; +using Xunit; + +namespace CLVMDotNet.Tests.Tools.Clvmc; + +public class CompileCLVMText +{ + [Fact] + public void RunBasicProgram() + { + var result = CLVMDotNet.Tools.IR.Clvmc.CompileCLVMText("(/ 10 2)", Array.Empty()); + + var rs = result; + } +} \ No newline at end of file