From 5709e36a7ffe64eb20495be22549973791d165aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Mon, 4 Mar 2024 11:10:19 +0800 Subject: [PATCH 01/33] update --- .../AnonymousObjectCreationExpression.cs | 15 +++++++++++++ .../Expression/ArrayCreationExpression.cs | 22 +++++++++++++++++++ .../Expression/AssignmentExpression.cs | 20 +++++++++++++++++ .../Expression/TupleExpression.cs | 15 +++++++++++++ 4 files changed, 72 insertions(+) diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/AnonymousObjectCreationExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/AnonymousObjectCreationExpression.cs index ef0307a96..f5a1740b9 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/AnonymousObjectCreationExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/AnonymousObjectCreationExpression.cs @@ -18,6 +18,21 @@ namespace Neo.Compiler; partial class MethodConvert { + /// + /// Methods for converting the creation of an object of an anonymous type into a series of instructions. + /// + /// The semantic model providing context and information about the anonymous object creation. + /// The syntax representation of the anonymous object creation statement being converted. + /// + /// Anonymous types provide a convenient way to encapsulate a set of read-only properties into a single object without having to explicitly define a type first. The type name is generated by the compiler and is not available at the source code level. The type of each property is inferred by the compiler. + /// + /// + /// The following example shows an anonymous type that is initialized with two properties named Amount and Message. + /// + /// var v = new { Amount = 108, Message = "Hello" }; + /// Runtime.Log(v.Amount + v.Message); + /// + /// private void ConvertAnonymousObjectCreationExpression(SemanticModel model, AnonymousObjectCreationExpressionSyntax expression) { AddInstruction(OpCode.NEWARRAY0); diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/ArrayCreationExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/ArrayCreationExpression.cs index 1fc3ea08e..5aa8b49f7 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/ArrayCreationExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/ArrayCreationExpression.cs @@ -19,6 +19,28 @@ namespace Neo.Compiler; partial class MethodConvert { + /// + /// Converts the code for constructing arrays and initializing arrays into a sequence of instructions. + /// This method includes analyzing the array length, array type, array dimension and initial data. + /// + /// The semantic model providing context and information about the array creation. + /// The syntax representation of the array creation statement being converted. + /// Only one-dimensional arrays are supported, otherwise an exception is thrown. + /// + /// When the array is initialized to null, this code converts it to "array length" + OpCode.NEWBUFFER (only for byte[]) or OpCode.NEWARRAY_T. + /// When the array is not initialized to null, this code converts the initialized constants one by one in reverse order, then adds the "array length" and OpCode.PACK + /// + /// + /// Example of a array creation syntax: + /// + /// var array = new byte[4]; + /// + /// The compilation result of the example code is: OpCode.PUSH4, OpCode.NEWBUFFER + /// + /// var array = new int[4] { 5, 6, 7, 8}; + /// + /// The compilation result of the example code is: OpCode.PUSH8, OpCode.PUSH7, OpCode.PUSH6, OpCode.PUSH5, OpCode.PUSH4, OpCode.PACK + /// private void ConvertArrayCreationExpression(SemanticModel model, ArrayCreationExpressionSyntax expression) { ArrayRankSpecifierSyntax specifier = expression.Type.RankSpecifiers[0]; diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/AssignmentExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/AssignmentExpression.cs index 026ef3eff..db77ef901 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/AssignmentExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/AssignmentExpression.cs @@ -17,6 +17,26 @@ namespace Neo.Compiler; partial class MethodConvert { + /// + /// The assignment operator = assigns the value of its right-hand operand to a variable, + /// a property, or an indexer element given by its left-hand operand. + /// The result of an assignment expression is the value assigned to the left-hand operand. + /// The type of the right-hand operand must be the same as the type of the left-hand operand or implicitly convertible to it. + /// The null-coalescing assignment operator ??= assigns the value of its right-hand operand to its left-hand operand only if the left-hand operand evaluates to null. + /// The ??= operator doesn't evaluate its right-hand operand if the left-hand operand evaluates to non-null. + /// + /// The semantic model providing context and information about assignment expression. + /// The syntax representation of the assignment expression statement being converted. + /// + /// The assignment operator = is right-associative, that is, an expression of the form + /// + /// a = b = c + /// + /// is evaluated as + /// + /// a = (b = c) + /// + /// private void ConvertAssignmentExpression(SemanticModel model, AssignmentExpressionSyntax expression) { switch (expression.OperatorToken.ValueText) diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/TupleExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/TupleExpression.cs index 4b5eafdca..f8a1faf80 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/TupleExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/TupleExpression.cs @@ -18,6 +18,21 @@ namespace Neo.Compiler; partial class MethodConvert { + /// + /// Converts the code for tuple type into a sequence of instructions. + /// + /// The semantic model providing context and information about the tuple type. + /// The syntax representation of the tuple type statement being converted. + /// + /// The tuples feature provides concise syntax to group multiple data elements in a lightweight data structure. + /// The following example shows how you can declare a tuple variable, initialize it, and access its data members: + /// + /// (string, int) t1 = ("chris", 3); + /// Runtime.Log($"Tuple with elements {t1.Item1} and {t1.Item2}."); + /// (string Name, int Count) t2 = ("chris", 3); + /// Runtime.Log($"Sum of {t2.Name} elements is {t2.Count}."); + /// + /// private void ConvertTupleExpression(SemanticModel model, TupleExpressionSyntax expression) { AddInstruction(OpCode.NEWSTRUCT0); From 0d8976b0d0260a53e7ec6ede7eac0031c0cf27f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Mon, 4 Mar 2024 11:22:11 +0800 Subject: [PATCH 02/33] Update BinaryExpression.cs --- .../Expression/BinaryExpression.cs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/BinaryExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/BinaryExpression.cs index 534da35f4..824ff6301 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/BinaryExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/BinaryExpression.cs @@ -19,6 +19,26 @@ namespace Neo.Compiler; partial class MethodConvert { + /// + /// The conditional logical OR operator ||, also known as the "short-circuiting" logical OR operator, computes the logical OR of its operands. + /// The result of x || y is true if either x or y evaluates to true. + /// Otherwise, the result is false. If x evaluates to true, y isn't evaluated. + /// + /// The conditional logical AND operator &&, also known as the "short-circuiting" logical AND operator, computes the logical AND of its operands. + /// The result of x && y is true if both x and y evaluate to true. + /// Otherwise, the result is false. If x evaluates to false, y isn't evaluated. + /// + /// The is operator checks if the run-time type of an expression result is compatible with a given type. The is operator also tests an expression result against a pattern. + /// + /// The as operator explicitly converts the result of an expression to a given reference or nullable value type. If the conversion isn't possible, the as operator returns null. Unlike a cast expression, the as operator never throws an exception. + /// + /// The null-coalescing operator ?? returns the value of its left-hand operand if it isn't null; + /// otherwise, it evaluates the right-hand operand and returns its result. + /// The ?? operator doesn't evaluate its right-hand operand if the left-hand operand evaluates to non-null. + /// + /// The semantic model providing context and information about binary expression. + /// The syntax representation of the binary expression statement being converted. + /// If an unsupported operator is encountered private void ConvertBinaryExpression(SemanticModel model, BinaryExpressionSyntax expression) { switch (expression.OperatorToken.ValueText) From 2134fb12ac49892535b7833412f4ee395df84dff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Mon, 4 Mar 2024 14:32:33 +0800 Subject: [PATCH 03/33] Update AnonymousObjectCreationExpression.cs --- .../Expression/AnonymousObjectCreationExpression.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/AnonymousObjectCreationExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/AnonymousObjectCreationExpression.cs index f5a1740b9..a3e3547da 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/AnonymousObjectCreationExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/AnonymousObjectCreationExpression.cs @@ -24,7 +24,9 @@ partial class MethodConvert /// The semantic model providing context and information about the anonymous object creation. /// The syntax representation of the anonymous object creation statement being converted. /// - /// Anonymous types provide a convenient way to encapsulate a set of read-only properties into a single object without having to explicitly define a type first. The type name is generated by the compiler and is not available at the source code level. The type of each property is inferred by the compiler. + /// Anonymous types provide a convenient way to encapsulate a set of read-only properties into a single object without having to explicitly define a type first. + /// The type name is generated by the compiler and is not available at the source code level. + /// The type of each property is inferred by the compiler. /// /// /// The following example shows an anonymous type that is initialized with two properties named Amount and Message. From ceb138bf6297ad0ca54ec9366f667295e0fe8f0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Mon, 4 Mar 2024 14:56:21 +0800 Subject: [PATCH 04/33] Update ElementExpression.cs --- .../Expression/ElementExpression.cs | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/ElementExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/ElementExpression.cs index f9235ad30..d6662cc90 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/ElementExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/ElementExpression.cs @@ -20,6 +20,17 @@ namespace Neo.Compiler; partial class MethodConvert { + /// + /// This method converts an element access expression to OpCodes. + /// An element access expression accesses a single element in an array or a collection. + /// + /// The semantic model providing context and information about element access expression. + /// The syntax representation of the element access expression statement being converted. + /// Only one-dimensional arrays are supported, otherwise an exception is thrown. + /// + /// If the accessed element is a property, the method calls the property's getter. + /// If the accessed element is an array or a collection, the method generates IL instructions to fetch the element. + /// private void ConvertElementAccessExpression(SemanticModel model, ElementAccessExpressionSyntax expression) { if (expression.ArgumentList.Arguments.Count != 1) @@ -36,6 +47,16 @@ private void ConvertElementAccessExpression(SemanticModel model, ElementAccessEx } } + /// + /// This method converts an element binding expression to OpCodes. + /// An element binding expression is used to access a single element in a collection initializer. + /// + /// The semantic model providing context and information about element binding expression. + /// The syntax representation of the element binding expression statement being converted. + /// Only one-dimensional arrays are supported, otherwise an exception is thrown. + /// + /// The method generates IL instructions to fetch the element based on the given index or range. + /// private void ConvertElementBindingExpression(SemanticModel model, ElementBindingExpressionSyntax expression) { if (expression.ArgumentList.Arguments.Count != 1) @@ -44,6 +65,18 @@ private void ConvertElementBindingExpression(SemanticModel model, ElementBinding ConvertIndexOrRange(model, type, expression.ArgumentList.Arguments[0].Expression); } + /// + /// This method converts an index or range expression to OpCodes. + /// An index or range expression specifies the index or range of elements to access in an array or a collection. + /// + /// The semantic model providing contextual information for the expression. + /// The type symbol of the array or collection being accessed. + /// The expression representing the index or range. + /// Only one-dimensional arrays are supported, otherwise an exception is thrown. + /// + /// If the expression is a range, it calculates the start and end indices and extracts the relevant sub-array or sub-collection. + /// If the expression is an index, it generates IL instructions to fetch the element at the specified index. + /// private void ConvertIndexOrRange(SemanticModel model, ITypeSymbol type, ExpressionSyntax indexOrRange) { if (indexOrRange is RangeExpressionSyntax range) From 7f35bfcd51b1b07d7690e947b93178a6f351d5b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Mon, 4 Mar 2024 15:06:44 +0800 Subject: [PATCH 05/33] Update CastExpression.cs --- .../MethodConvert/Expression/CastExpression.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/CastExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/CastExpression.cs index 8e00b824c..402f722db 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/CastExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/CastExpression.cs @@ -19,6 +19,16 @@ namespace Neo.Compiler; partial class MethodConvert { + /// + /// This method converts a cast expression to OpCodes. + /// + /// The semantic model providing context and information about cast expression. + /// The syntax representation of the cast expression statement being converted. + /// + /// This method determines the source type and the target type of the cast expression. + /// If the cast can be resolved to a method symbol, it calls the corresponding method. + /// Otherwise, it generates IL instructions based on the types involved in the cast operation. + /// private void ConvertCastExpression(SemanticModel model, CastExpressionSyntax expression) { ITypeSymbol sType = model.GetTypeInfo(expression.Expression).Type!; From dec24ed9355403d257b91017652f9168d2ef063c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Mon, 4 Mar 2024 16:03:11 +0800 Subject: [PATCH 06/33] Update CastExpression.cs --- .../MethodConvert/Expression/CastExpression.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/CastExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/CastExpression.cs index 402f722db..6eb4dd8fc 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/CastExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/CastExpression.cs @@ -14,13 +14,14 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Neo.VM; - namespace Neo.Compiler; partial class MethodConvert { /// /// This method converts a cast expression to OpCodes. + /// A cast expression of the form (T)E performs an explicit conversion of the result of expression E to type T. + /// If no explicit conversion exists from the type of E to type T, a compile-time error occurs. /// /// The semantic model providing context and information about cast expression. /// The syntax representation of the cast expression statement being converted. @@ -29,6 +30,15 @@ partial class MethodConvert /// If the cast can be resolved to a method symbol, it calls the corresponding method. /// Otherwise, it generates IL instructions based on the types involved in the cast operation. /// + /// + /// This code is cast a ByteString type to an ECPoint type, + /// where the source type is ByteString and the target type is ECPoint. + /// + /// ByteString bytes = ByteString.Empty; + /// ECPoint point = (ECPoint)bytes; + /// Runtime.Log(point.ToString()); + /// + /// private void ConvertCastExpression(SemanticModel model, CastExpressionSyntax expression) { ITypeSymbol sType = model.GetTypeInfo(expression.Expression).Type!; From 9249d59fc971cda74cc50ee2c9d2162be901c93a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Mon, 4 Mar 2024 16:52:34 +0800 Subject: [PATCH 07/33] Update ConditionalAccessExpression.cs --- .../Expression/ConditionalAccessExpression.cs | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/ConditionalAccessExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/ConditionalAccessExpression.cs index 2e2f0b09a..0e19a33d3 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/ConditionalAccessExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/ConditionalAccessExpression.cs @@ -19,6 +19,34 @@ namespace Neo.Compiler; partial class MethodConvert { + /// + /// This method converts a conditional access expression to OpCodes. + /// + /// /// The semantic model providing context and information about conditional access expression. + /// The syntax representation of the conditional access expression statement being converted. + /// + /// The method evaluates the expression and checks if it is null. + /// If the expression is not null, it converts the 'WhenNotNull' part of the expression. + /// If the resulting type of the expression is 'System.Void', it handles the case differently by dropping the result. + /// A null-conditional operator applies a member access (?.) or element access (?[]) operation to its operand only if that operand evaluates to non-null; + /// otherwise, it returns null. + /// + /// + /// If Block is not null, get the block's timestamp; otherwise, it returns null. + /// + /// var block = Ledger.GetBlock(10000); + /// var timestamp = block?.Timestamp; + /// Runtime.Log(timestamp.ToString()); + /// + /// If array is not null, get the array's element; otherwise, it returns null. + /// + /// var a = Ledger.GetBlock(10000); + /// var b = Ledger.GetBlock(10001); + /// var array = new[] { a, b }; + /// var firstItem = array?[0]; + /// Runtime.Log(firstItem?.Timestamp.ToString()); + /// + /// private void ConvertConditionalAccessExpression(SemanticModel model, ConditionalAccessExpressionSyntax expression) { ITypeSymbol type = model.GetTypeInfo(expression).Type!; From 3809a638a1349364eb5420f58ccd6be586f3d6d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Mon, 4 Mar 2024 17:01:55 +0800 Subject: [PATCH 08/33] TernaryConditional & NullConditionalAccess --- .../MethodConvert/Expression/Expression.cs | 4 ++-- ...n.cs => NullConditionalAccessExpression.cs} | 8 ++++---- ...sion.cs => TernaryConditionalExpression.cs} | 18 +++++++++++++++++- 3 files changed, 23 insertions(+), 7 deletions(-) rename src/Neo.Compiler.CSharp/MethodConvert/Expression/{ConditionalAccessExpression.cs => NullConditionalAccessExpression.cs} (88%) rename src/Neo.Compiler.CSharp/MethodConvert/Expression/{ConditionalExpression.cs => TernaryConditionalExpression.cs} (50%) diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs index b317ddf7c..50d1aca05 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs @@ -103,10 +103,10 @@ private void ConvertExpression(SemanticModel model, ExpressionSyntax syntax, Syn ConvertCheckedExpression(model, expression); break; case ConditionalAccessExpressionSyntax expression: - ConvertConditionalAccessExpression(model, expression); + ConvertNullConditionalAccessExpression(model, expression); break; case ConditionalExpressionSyntax expression: - ConvertConditionalExpression(model, expression); + ConvertTernaryConditionalExpression(model, expression); break; case ElementAccessExpressionSyntax expression: ConvertElementAccessExpression(model, expression); diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/ConditionalAccessExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/NullConditionalAccessExpression.cs similarity index 88% rename from src/Neo.Compiler.CSharp/MethodConvert/Expression/ConditionalAccessExpression.cs rename to src/Neo.Compiler.CSharp/MethodConvert/Expression/NullConditionalAccessExpression.cs index 0e19a33d3..f6d4c9d0f 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/ConditionalAccessExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/NullConditionalAccessExpression.cs @@ -20,10 +20,10 @@ namespace Neo.Compiler; partial class MethodConvert { /// - /// This method converts a conditional access expression to OpCodes. + /// This method converts a null-conditional access expression to OpCodes. /// - /// /// The semantic model providing context and information about conditional access expression. - /// The syntax representation of the conditional access expression statement being converted. + /// /// The semantic model providing context and information about null-conditional access expression. + /// The syntax representation of the null-conditional access expression statement being converted. /// /// The method evaluates the expression and checks if it is null. /// If the expression is not null, it converts the 'WhenNotNull' part of the expression. @@ -47,7 +47,7 @@ partial class MethodConvert /// Runtime.Log(firstItem?.Timestamp.ToString()); /// /// - private void ConvertConditionalAccessExpression(SemanticModel model, ConditionalAccessExpressionSyntax expression) + private void ConvertNullConditionalAccessExpression(SemanticModel model, ConditionalAccessExpressionSyntax expression) { ITypeSymbol type = model.GetTypeInfo(expression).Type!; JumpTarget nullTarget = new(); diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/ConditionalExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/TernaryConditionalExpression.cs similarity index 50% rename from src/Neo.Compiler.CSharp/MethodConvert/Expression/ConditionalExpression.cs rename to src/Neo.Compiler.CSharp/MethodConvert/Expression/TernaryConditionalExpression.cs index 6d12e7acc..5c984bd4b 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/ConditionalExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/TernaryConditionalExpression.cs @@ -18,7 +18,23 @@ namespace Neo.Compiler; partial class MethodConvert { - private void ConvertConditionalExpression(SemanticModel model, ConditionalExpressionSyntax expression) + /// + /// This method converts a ternary conditional expression to OpCodes. + /// + /// /// The semantic model providing context and information about ternary conditional expression. + /// The syntax representation of the ternary conditional expression statement being converted. + /// + /// The conditional operator ?:, also known as the ternary conditional operator, + /// evaluates a Boolean expression and returns the result of one of the two expressions, + /// depending on whether the Boolean expression evaluates to true or false, as the following example shows: + /// + /// var index = 10000; + /// var current = Ledger.CurrentIndex; + /// var state = current > index ? "start" : "stop"; + /// Runtime.Log(state.ToString()); + /// + /// + private void ConvertTernaryConditionalExpression(SemanticModel model, ConditionalExpressionSyntax expression) { JumpTarget falseTarget = new(); JumpTarget endTarget = new(); From 6b22cfe0e2c41a9aafc62c13a619341be9e223a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Mon, 4 Mar 2024 17:34:21 +0800 Subject: [PATCH 09/33] revert rename --- ...onalAccessExpression.cs => ConditionalAccessExpression.cs} | 2 +- ...rnaryConditionalExpression.cs => ConditionalExpression.cs} | 2 +- .../MethodConvert/Expression/Expression.cs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) rename src/Neo.Compiler.CSharp/MethodConvert/Expression/{NullConditionalAccessExpression.cs => ConditionalAccessExpression.cs} (95%) rename src/Neo.Compiler.CSharp/MethodConvert/Expression/{TernaryConditionalExpression.cs => ConditionalExpression.cs} (94%) diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/NullConditionalAccessExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/ConditionalAccessExpression.cs similarity index 95% rename from src/Neo.Compiler.CSharp/MethodConvert/Expression/NullConditionalAccessExpression.cs rename to src/Neo.Compiler.CSharp/MethodConvert/Expression/ConditionalAccessExpression.cs index f6d4c9d0f..dcffc00fa 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/NullConditionalAccessExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/ConditionalAccessExpression.cs @@ -47,7 +47,7 @@ partial class MethodConvert /// Runtime.Log(firstItem?.Timestamp.ToString()); /// /// - private void ConvertNullConditionalAccessExpression(SemanticModel model, ConditionalAccessExpressionSyntax expression) + private void ConvertConditionalAccessExpression(SemanticModel model, ConditionalAccessExpressionSyntax expression) { ITypeSymbol type = model.GetTypeInfo(expression).Type!; JumpTarget nullTarget = new(); diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/TernaryConditionalExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/ConditionalExpression.cs similarity index 94% rename from src/Neo.Compiler.CSharp/MethodConvert/Expression/TernaryConditionalExpression.cs rename to src/Neo.Compiler.CSharp/MethodConvert/Expression/ConditionalExpression.cs index 5c984bd4b..aa04849c5 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/TernaryConditionalExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/ConditionalExpression.cs @@ -34,7 +34,7 @@ partial class MethodConvert /// Runtime.Log(state.ToString()); /// /// - private void ConvertTernaryConditionalExpression(SemanticModel model, ConditionalExpressionSyntax expression) + private void ConvertConditionalExpression(SemanticModel model, ConditionalExpressionSyntax expression) { JumpTarget falseTarget = new(); JumpTarget endTarget = new(); diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs index 50d1aca05..b317ddf7c 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs @@ -103,10 +103,10 @@ private void ConvertExpression(SemanticModel model, ExpressionSyntax syntax, Syn ConvertCheckedExpression(model, expression); break; case ConditionalAccessExpressionSyntax expression: - ConvertNullConditionalAccessExpression(model, expression); + ConvertConditionalAccessExpression(model, expression); break; case ConditionalExpressionSyntax expression: - ConvertTernaryConditionalExpression(model, expression); + ConvertConditionalExpression(model, expression); break; case ElementAccessExpressionSyntax expression: ConvertElementAccessExpression(model, expression); From 566af11cead67843e598aa1b3223683de5aea7d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Mon, 4 Mar 2024 18:00:59 +0800 Subject: [PATCH 10/33] update ConvertCheckedExpression.cs --- .../Expression/CastExpression.cs | 1 + .../Expression/CheckedExpression.cs | 31 +++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/CastExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/CastExpression.cs index 6eb4dd8fc..c0f7f562f 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/CastExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/CastExpression.cs @@ -14,6 +14,7 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Neo.VM; + namespace Neo.Compiler; partial class MethodConvert diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/CheckedExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/CheckedExpression.cs index 1d66d00c5..e6cfc63aa 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/CheckedExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/CheckedExpression.cs @@ -18,6 +18,37 @@ namespace Neo.Compiler; partial class MethodConvert { + /// + /// The checked and unchecked statements specify the overflow-checking context for integral-type arithmetic operations and conversions. + /// When integer arithmetic overflow occurs, the overflow-checking context defines what happens. + /// In a checked context, a System.OverflowException is thrown; + /// if overflow happens in a constant expression, a compile-time error occurs. + /// + /// The semantic model providing context and information about checked and unchecked statement. + /// The syntax representation of the checked and unchecked statement being converted. + /// + /// Use the checked keyword to qualify the result of the temp*2 calculation and use a try catch to handle the overflow if it occurs. + /// + /// try + /// { + /// int temp = int.MaxValue; + /// int a = checked(temp * 2); + /// } + /// catch (OverflowException) + /// { + /// Runtime.Log("Overflow"); + /// } + /// + /// + /// + /// This code is not called when the checked keyword modifies a block of statements, for example. + /// + /// checked + /// { + /// int a = temp * 2; + /// } + /// + /// private void ConvertCheckedExpression(SemanticModel model, CheckedExpressionSyntax expression) { _checkedStack.Push(expression.Keyword.IsKind(SyntaxKind.CheckedKeyword)); From 48671e5080b1efd51d286e9ec7e3c21fdfb89924 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Mon, 4 Mar 2024 18:15:39 +0800 Subject: [PATCH 11/33] Update IdentifierNameExpression.cs --- .../Expression/IdentifierNameExpression.cs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/IdentifierNameExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/IdentifierNameExpression.cs index 049439c0c..463a46a7f 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/IdentifierNameExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/IdentifierNameExpression.cs @@ -20,6 +20,26 @@ namespace Neo.Compiler; partial class MethodConvert { + /// + /// This method converts an identifier name expression to OpCodes. + /// + /// The semantic model providing context and information about identifier name expression. + /// The syntax representation of the identifier name expression statement being converted. + /// Unsupported symbols will result in a compilation exception. + /// + /// Processing of the identifier "param" goes to the "IParameterSymbol parameter" branch of the code; + /// processing of the identifier "temp" goes to the "ILocalSymbol local" branch of the code. + /// Unused identifier "param2" will not be processed. + /// + /// public static void MyMethod(int param, int param2) + /// { + /// int temp = int.MaxValue; + /// Runtime.Log(temp.ToString()); + /// Runtime.Log(param.ToString()); + /// Runtime.Log(a.ToString()); + /// } + /// + /// private void ConvertIdentifierNameExpression(SemanticModel model, IdentifierNameSyntax expression) { ISymbol symbol = model.GetSymbolInfo(expression).Symbol!; From 443380bd4a02599cdb7aa8935d4a191dfe3bcccc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Tue, 5 Mar 2024 14:04:33 +0800 Subject: [PATCH 12/33] Update ImplicitArrayCreationExpression.cs --- .../ImplicitArrayCreationExpression.cs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/ImplicitArrayCreationExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/ImplicitArrayCreationExpression.cs index 207172105..2cd8d022f 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/ImplicitArrayCreationExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/ImplicitArrayCreationExpression.cs @@ -18,6 +18,26 @@ namespace Neo.Compiler; partial class MethodConvert { + /// + /// Implicitly typed arrays are those arrays in which the type of the array is deduced from the element specified in the array initializer. + /// The implicitly typed arrays are similar to implicitly typed variable. + /// + /// The semantic model providing context and information about implicit array creation expression. + /// The syntax representation of the implicit array creation expression statement being converted. + /// + /// Below program illustrates how to use 1-Dimensional Implicitly typed array. + /// + /// var authorNames = new[] {"Shilpa", "Soniya", "Shivi", "Ritika"}; + /// Runtime.Log("List of Authors is: "); + /// foreach (var name in authorNames) + /// { + /// Runtime.Log(name); + /// } + /// + /// + /// + /// Multidimensional implicitly typed arrays are not supported. + /// private void ConvertImplicitArrayCreationExpression(SemanticModel model, ImplicitArrayCreationExpressionSyntax expression) { IArrayTypeSymbol type = (IArrayTypeSymbol)model.GetTypeInfo(expression).ConvertedType!; From e580b19503cc53b46de3f06d2b58cc7499be4c33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Tue, 5 Mar 2024 14:55:21 +0800 Subject: [PATCH 13/33] update InterpolatedStringExpression.cs --- .../ImplicitArrayCreationExpression.cs | 1 + .../InterpolatedStringExpression.cs | 22 +++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/ImplicitArrayCreationExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/ImplicitArrayCreationExpression.cs index 2cd8d022f..a0c151ba5 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/ImplicitArrayCreationExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/ImplicitArrayCreationExpression.cs @@ -19,6 +19,7 @@ namespace Neo.Compiler; partial class MethodConvert { /// + /// This method converts an implicit array creation expression to OpCodes. /// Implicitly typed arrays are those arrays in which the type of the array is deduced from the element specified in the array initializer. /// The implicitly typed arrays are similar to implicitly typed variable. /// diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/InterpolatedStringExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/InterpolatedStringExpression.cs index 0f6694cfd..b4d5b9a33 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/InterpolatedStringExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/InterpolatedStringExpression.cs @@ -18,6 +18,28 @@ namespace Neo.Compiler; partial class MethodConvert { + /// + /// This method converts an interpolated string expression to OpCodes. + /// The $ character identifies a string literal as an interpolated string. + /// An interpolated string is a string literal that might contain interpolation expressions. + /// When an interpolated string is resolved to a result string, + /// items with interpolation expressions are replaced by the string representations of the expression results. + /// + /// The semantic model providing context and information about interpolated string expression. + /// The syntax representation of the interpolated string expression statement being converted. + /// + /// The method processes each interpolated string content segment and concatenates them using the CAT opcode. + /// If the interpolated string contains no segments, it pushes an empty string onto the evaluation stack. + /// If the interpolated string contains two or more segments, it changes the type of the resulting string to ByteString. + /// + /// + /// The following interpolated string will be divided into 5 parts and concatenated via OpCode.CAT + /// + /// var name = "Mark"; + /// var timestamp = Ledger.GetBlock(Ledger.CurrentHash).Timestamp; + /// Runtime.Log($"Hello, {name}! Current timestamp is {timestamp}."); + /// + /// private void ConvertInterpolatedStringExpression(SemanticModel model, InterpolatedStringExpressionSyntax expression) { if (expression.Contents.Count == 0) From ff9e30313bb94dc040243d068acdf6e8f338b3a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Tue, 5 Mar 2024 17:06:00 +0800 Subject: [PATCH 14/33] update --- .../Expression/IsPatternExpression.cs | 19 ++++++++++++++++++ .../Expression/MemberExpression.cs | 20 +++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/IsPatternExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/IsPatternExpression.cs index 2008ec418..b18e70af4 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/IsPatternExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/IsPatternExpression.cs @@ -18,6 +18,25 @@ namespace Neo.Compiler; partial class MethodConvert { + /// + /// This method converts an 'is' pattern expression to OpCodes. + /// + /// The semantic model providing context and information about is pattern expression. + /// The syntax representation of the is pattern expression statement being converted. + /// + /// In this example, the 'is' pattern expression is used to check if obj is an instance of the string type. + /// + /// object obj = "Hello"; + /// if (obj is string str) + /// { + /// Runtime.Log($"The object is a string: {str}"); + /// } + /// else + /// { + /// Runtime.Log("The object is not a string."); + /// } + /// + /// private void ConvertIsPatternExpression(SemanticModel model, IsPatternExpressionSyntax expression) { byte anonymousIndex = AddAnonymousVariable(); diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/MemberExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/MemberExpression.cs index 425d58ece..9407e72e0 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/MemberExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/MemberExpression.cs @@ -20,6 +20,26 @@ namespace Neo.Compiler; partial class MethodConvert { + /// + /// This method converts a member access expression to OpCodes. + /// + /// The semantic model providing context and information about member access expression. + /// The syntax representation of the member access expression statement being converted. + /// Unsupported symbols will result in a compilation exception, such as non-static methods. + /// + /// The method determines the symbol associated with the member access expression from the semantic model. + /// It then generates IL instructions based on the type of symbol. + /// Supported symbols include fields, methods, and properties. + /// For fields, it handles constant fields, static fields, and instance fields. + /// For methods, it handles static methods. + /// For properties, it handles accessing static properties and instance properties. + /// + /// + /// This is a member access example. The following code branches to "case IPropertySymbol property". + /// + /// Runtime.Log(Ledger.CurrentHash.ToString()); + /// + /// private void ConvertMemberAccessExpression(SemanticModel model, MemberAccessExpressionSyntax expression) { ISymbol symbol = model.GetSymbolInfo(expression).Symbol!; From 283ee84be1a688d7d8e608bea75e7e2aa48e4ffd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Tue, 5 Mar 2024 17:29:30 +0800 Subject: [PATCH 15/33] Update SwitchExpression.cs --- .../Expression/SwitchExpression.cs | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/SwitchExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/SwitchExpression.cs index 19a5c822b..759422ffc 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/SwitchExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/SwitchExpression.cs @@ -19,6 +19,37 @@ namespace Neo.Compiler; partial class MethodConvert { + /// + /// This method converts a switch expression expression to OpCodes. + /// Switch expressions are a new feature introduced in C# 7.0. + /// For a traditional switch statement, see the ../Statement/SwitchStatement.cs file. + /// + /// The semantic model providing context and information about switch expression. + /// The syntax representation of the switch expression statement being converted. + /// Unsupported symbols will result in a compilation exception, such as methods. + /// + /// The method processes each switch expression arm and evaluates the pattern matching for each case. + /// It generates OpCodes based on the matching results and expressions in each arm. + /// After evaluating each arm, it throws an exception if none of the cases match. + /// + /// + /// The switch statement selects the appropriate case branch based on the value of day. + /// + /// int day = 4; + /// string dayName = day switch + /// { + /// 1 => "Monday", + /// 2 => "Tuesday", + /// 3 => "Wednesday", + /// 4 => "Thursday", + /// 5 => "Friday", + /// 6 => "Saturday", + /// 7 => "Sunday", + /// _ => "Unknown", + /// }; + /// Runtime.Log($"Today is {dayName}"); + /// + /// private void ConvertSwitchExpression(SemanticModel model, SwitchExpressionSyntax expression) { var arms = expression.Arms.Select(p => (p, new JumpTarget())).ToArray(); From 139cd1ae888545820b5e0e8d7b8208b4d2285634 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Wed, 6 Mar 2024 12:40:46 +0800 Subject: [PATCH 16/33] update --- .../Expression/ArrayCreationExpression.cs | 2 +- ...AssignmentExpression.CoalesceAssignment.cs | 34 +++++++++++++++++++ .../AssignmentExpression.ComplexAssignment.cs | 27 +++++++++++++++ .../AssignmentExpression.SimpleAssignment.cs | 22 ++++++++++++ .../Expression/AssignmentExpression.cs | 19 ++--------- .../Expression/TupleExpression.cs | 2 +- .../UnaryExpression.PostfixUnary.cs | 15 ++++++++ .../Expression/UnaryExpression.PrefixUnary.cs | 15 ++++++++ .../MethodConvert/Statement/BlockStatement.cs | 2 +- .../Statement/ExpressionStatement.cs | 2 +- .../MethodConvert/Statement/ForStatement.cs | 2 +- 11 files changed, 121 insertions(+), 21 deletions(-) diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/ArrayCreationExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/ArrayCreationExpression.cs index 5aa8b49f7..422dcf4c6 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/ArrayCreationExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/ArrayCreationExpression.cs @@ -20,7 +20,7 @@ namespace Neo.Compiler; partial class MethodConvert { /// - /// Converts the code for constructing arrays and initializing arrays into a sequence of instructions. + /// Converts the code for constructing arrays and initializing arrays into OpCodes. /// This method includes analyzing the array length, array type, array dimension and initial data. /// /// The semantic model providing context and information about the array creation. diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/AssignmentExpression.CoalesceAssignment.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/AssignmentExpression.CoalesceAssignment.cs index 4d9cccf14..4980a90c3 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/AssignmentExpression.CoalesceAssignment.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/AssignmentExpression.CoalesceAssignment.cs @@ -21,6 +21,40 @@ namespace Neo.Compiler; partial class MethodConvert { + /// + /// Converts the code for null-coalescing assignment expression into OpCodes. + /// The null-coalescing assignment operator ??= assigns the value of its right-hand operand to its left-hand operand only if the left-hand operand evaluates to null. + /// The ??= operator doesn't evaluate its right-hand operand if the left-hand operand evaluates to non-null. + /// + /// The semantic model providing context and information about coalesce assignment expression. + /// The syntax representation of the coalesce assignment expression statement being converted. + /// Thrown when the syntax is not supported. + /// + /// The result of an assignment expression is the value assigned to the left-hand operand. + /// The type of the right-hand operand must be the same as the type of the left-hand operand or implicitly convertible to it. + /// + /// + /// + /// public class Cat + /// { + /// public string Name { get; set; } + /// } + /// + /// + /// Cat nullableCat = null; + /// Cat nonNullableCat = new() { Name = "Mimi" }; + /// nullableCat ??= nonNullableCat; + /// Runtime.Log("Nullable cat: " + nullableCat.Name); + /// + /// "nullableCat ??= nonNullableCat;" this line is evaluated as + /// + /// nullableCat = nullableCat ?? nonNullableCat; + /// + /// is evaluated as + /// + /// if (nullableCat == null) nullableCat = nonNullableCat; + /// + /// private void ConvertCoalesceAssignmentExpression(SemanticModel model, AssignmentExpressionSyntax expression) { switch (expression.Left) diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/AssignmentExpression.ComplexAssignment.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/AssignmentExpression.ComplexAssignment.cs index c1553010b..25c5ae139 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/AssignmentExpression.ComplexAssignment.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/AssignmentExpression.ComplexAssignment.cs @@ -21,6 +21,33 @@ namespace Neo.Compiler; partial class MethodConvert { + /// + /// Converts the code for complex assignment expression into OpCodes. + /// + /// The semantic model providing context and information about complex assignment expression. + /// The syntax representation of the complex assignment expression statement being converted. + /// Thrown when the syntax is not supported. + /// + /// For a binary operator op, a compound assignment expression of the form "x op= y" is equivalent to "x = x op y" except that x is only evaluated once. + /// + /// + /// The following example demonstrates the usage of compound assignment with arithmetic operators: + /// The corresponding code branch is "ConvertComplexAssignmentExpression" + /// + /// int a = 5; + /// a += 9; + /// Runtime.Log(a.ToString()); + /// a -= 4; + /// Runtime.Log(a.ToString()); + /// a *= 2; + /// Runtime.Log(a.ToString()); + /// a /= 4; + /// Runtime.Log(a.ToString()); + /// a %= 3; + /// Runtime.Log(a.ToString()); + /// + /// output: 14, 10, 20, 5, 2 + /// private void ConvertComplexAssignmentExpression(SemanticModel model, AssignmentExpressionSyntax expression) { ITypeSymbol type = model.GetTypeInfo(expression).Type!; diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/AssignmentExpression.SimpleAssignment.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/AssignmentExpression.SimpleAssignment.cs index fa1723346..6c3e16f41 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/AssignmentExpression.SimpleAssignment.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/AssignmentExpression.SimpleAssignment.cs @@ -22,6 +22,28 @@ namespace Neo.Compiler; partial class MethodConvert { + /// + /// Converts the code for simple assignment expression into OpCodes. + /// The assignment operator = assigns the value of its right-hand operand to a variable, + /// a property, or an indexer element given by its left-hand operand. + /// + /// The semantic model providing context and information about simple assignment expression. + /// The syntax representation of the simple assignment expression statement being converted. + /// Thrown when the syntax is not supported. + /// + /// The result of an assignment expression is the value assigned to the left-hand operand. + /// The type of the right-hand operand must be the same as the type of the left-hand operand or implicitly convertible to it. + /// + /// + /// The assignment operator = is right-associative, that is, an expression of the form + /// + /// a = b = c + /// + /// is evaluated as + /// + /// a = (b = c) + /// + /// private void ConvertSimpleAssignmentExpression(SemanticModel model, AssignmentExpressionSyntax expression) { ConvertExpression(model, expression.Right); diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/AssignmentExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/AssignmentExpression.cs index db77ef901..0356ce70f 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/AssignmentExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/AssignmentExpression.cs @@ -18,25 +18,12 @@ namespace Neo.Compiler; partial class MethodConvert { /// - /// The assignment operator = assigns the value of its right-hand operand to a variable, - /// a property, or an indexer element given by its left-hand operand. - /// The result of an assignment expression is the value assigned to the left-hand operand. - /// The type of the right-hand operand must be the same as the type of the left-hand operand or implicitly convertible to it. - /// The null-coalescing assignment operator ??= assigns the value of its right-hand operand to its left-hand operand only if the left-hand operand evaluates to null. - /// The ??= operator doesn't evaluate its right-hand operand if the left-hand operand evaluates to non-null. + /// Converts the code for assignment expression into OpCodes. + /// Include assignment operator (=), null-coalescing assignment operator (??=) and compound assignment(+=, -=, *=, /= ... ) /// /// The semantic model providing context and information about assignment expression. /// The syntax representation of the assignment expression statement being converted. - /// - /// The assignment operator = is right-associative, that is, an expression of the form - /// - /// a = b = c - /// - /// is evaluated as - /// - /// a = (b = c) - /// - /// + private void ConvertAssignmentExpression(SemanticModel model, AssignmentExpressionSyntax expression) { switch (expression.OperatorToken.ValueText) diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/TupleExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/TupleExpression.cs index f8a1faf80..1b0688ab2 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/TupleExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/TupleExpression.cs @@ -19,7 +19,7 @@ namespace Neo.Compiler; partial class MethodConvert { /// - /// Converts the code for tuple type into a sequence of instructions. + /// Converts the code for tuple type into OpCodes. /// /// The semantic model providing context and information about the tuple type. /// The syntax representation of the tuple type statement being converted. diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/UnaryExpression.PostfixUnary.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/UnaryExpression.PostfixUnary.cs index 0039ec6f9..f7bee5c9f 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/UnaryExpression.PostfixUnary.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/UnaryExpression.PostfixUnary.cs @@ -21,6 +21,21 @@ namespace Neo.Compiler; partial class MethodConvert { + /// + /// Converts the postfix operator into OpCodes. + /// + /// The semantic model providing context and information about the postfix operator. + /// The syntax representation of the postfix operator being converted. + /// + /// The result of x++ is the value of x before the operation, as the following example shows: + /// + /// int i = 3; + /// Runtime.Log(i.ToString()); + /// Runtime.Log(i++.ToString()); + /// Runtime.Log(i.ToString()); + /// + /// output: 3、3、4 + /// private void ConvertPostfixUnaryExpression(SemanticModel model, PostfixUnaryExpressionSyntax expression) { switch (expression.OperatorToken.ValueText) diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/UnaryExpression.PrefixUnary.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/UnaryExpression.PrefixUnary.cs index 9535634a6..e0648bb17 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/UnaryExpression.PrefixUnary.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/UnaryExpression.PrefixUnary.cs @@ -21,6 +21,21 @@ namespace Neo.Compiler; partial class MethodConvert { + /// + /// Converts the prefix operator into OpCodes. + /// + /// The semantic model providing context and information about the prefix operator. + /// The syntax representation of the prefix operator being converted. + /// + /// The result of ++x is the value of x before the operation, as the following example shows: + /// + /// int i = 3; + /// Runtime.Log(i.ToString()); + /// Runtime.Log(++i.ToString()); + /// Runtime.Log(i.ToString()); + /// + /// output: 3、4、4 + /// private void ConvertPrefixUnaryExpression(SemanticModel model, PrefixUnaryExpressionSyntax expression) { switch (expression.OperatorToken.ValueText) diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Statement/BlockStatement.cs b/src/Neo.Compiler.CSharp/MethodConvert/Statement/BlockStatement.cs index 0e5c7d091..18241c784 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Statement/BlockStatement.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Statement/BlockStatement.cs @@ -18,7 +18,7 @@ namespace Neo.Compiler partial class MethodConvert { /// - /// Converts a block statement to a sequence of instructions. This method is used for parsing + /// Converts a block statement to OpCodes. This method is used for parsing /// the syntax of block statements within the context of a semantic model. A block statement /// typically consists of a series of statements enclosed in braces `{}`. /// diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Statement/ExpressionStatement.cs b/src/Neo.Compiler.CSharp/MethodConvert/Statement/ExpressionStatement.cs index 6245a8236..688255a9a 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Statement/ExpressionStatement.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Statement/ExpressionStatement.cs @@ -18,7 +18,7 @@ namespace Neo.Compiler partial class MethodConvert { /// - /// Converts an expression statement into a sequence of instructions. + /// Converts an expression statement into OpCodes. /// This method handles the translation of a given expression within a statement, /// considering the type of the expression to determine the necessary instructions. /// diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Statement/ForStatement.cs b/src/Neo.Compiler.CSharp/MethodConvert/Statement/ForStatement.cs index cc3c93195..93d291d58 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Statement/ForStatement.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Statement/ForStatement.cs @@ -19,7 +19,7 @@ namespace Neo.Compiler partial class MethodConvert { /// - /// Converts a 'for' loop statement into a sequence of instructions. This method handles the parsing + /// Converts a 'for' loop statement into OpCodes. This method handles the parsing /// and translation of the 'for' loop construct, including its initialization, condition, and /// increment expressions, as well as the loop body. /// From bdf62efc181e01a09a866399a492b09730aa7cb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Thu, 7 Mar 2024 10:24:57 +0800 Subject: [PATCH 17/33] update --- .../Expression/AssignmentExpression.CoalesceAssignment.cs | 4 ---- .../MethodConvert/Expression/CastExpression.cs | 2 +- .../MethodConvert/Expression/ElementExpression.cs | 6 +++--- .../MethodConvert/Expression/MemberExpression.cs | 2 +- 4 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/AssignmentExpression.CoalesceAssignment.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/AssignmentExpression.CoalesceAssignment.cs index 4980a90c3..d20d87ac0 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/AssignmentExpression.CoalesceAssignment.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/AssignmentExpression.CoalesceAssignment.cs @@ -29,10 +29,6 @@ partial class MethodConvert /// The semantic model providing context and information about coalesce assignment expression. /// The syntax representation of the coalesce assignment expression statement being converted. /// Thrown when the syntax is not supported. - /// - /// The result of an assignment expression is the value assigned to the left-hand operand. - /// The type of the right-hand operand must be the same as the type of the left-hand operand or implicitly convertible to it. - /// /// /// /// public class Cat diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/CastExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/CastExpression.cs index c0f7f562f..fceafd478 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/CastExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/CastExpression.cs @@ -29,7 +29,7 @@ partial class MethodConvert /// /// This method determines the source type and the target type of the cast expression. /// If the cast can be resolved to a method symbol, it calls the corresponding method. - /// Otherwise, it generates IL instructions based on the types involved in the cast operation. + /// Otherwise, it generates OpCodes based on the types involved in the cast operation. /// /// /// This code is cast a ByteString type to an ECPoint type, diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/ElementExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/ElementExpression.cs index d6662cc90..efe981c4b 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/ElementExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/ElementExpression.cs @@ -29,7 +29,7 @@ partial class MethodConvert /// Only one-dimensional arrays are supported, otherwise an exception is thrown. /// /// If the accessed element is a property, the method calls the property's getter. - /// If the accessed element is an array or a collection, the method generates IL instructions to fetch the element. + /// If the accessed element is an array or a collection, the method generates OpCodes to fetch the element. /// private void ConvertElementAccessExpression(SemanticModel model, ElementAccessExpressionSyntax expression) { @@ -55,7 +55,7 @@ private void ConvertElementAccessExpression(SemanticModel model, ElementAccessEx /// The syntax representation of the element binding expression statement being converted. /// Only one-dimensional arrays are supported, otherwise an exception is thrown. /// - /// The method generates IL instructions to fetch the element based on the given index or range. + /// The method generates OpCodes to fetch the element based on the given index or range. /// private void ConvertElementBindingExpression(SemanticModel model, ElementBindingExpressionSyntax expression) { @@ -75,7 +75,7 @@ private void ConvertElementBindingExpression(SemanticModel model, ElementBinding /// Only one-dimensional arrays are supported, otherwise an exception is thrown. /// /// If the expression is a range, it calculates the start and end indices and extracts the relevant sub-array or sub-collection. - /// If the expression is an index, it generates IL instructions to fetch the element at the specified index. + /// If the expression is an index, it generates OpCodes to fetch the element at the specified index. /// private void ConvertIndexOrRange(SemanticModel model, ITypeSymbol type, ExpressionSyntax indexOrRange) { diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/MemberExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/MemberExpression.cs index 9407e72e0..4836643d7 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/MemberExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/MemberExpression.cs @@ -28,7 +28,7 @@ partial class MethodConvert /// Unsupported symbols will result in a compilation exception, such as non-static methods. /// /// The method determines the symbol associated with the member access expression from the semantic model. - /// It then generates IL instructions based on the type of symbol. + /// It then generates OpCodes based on the type of symbol. /// Supported symbols include fields, methods, and properties. /// For fields, it handles constant fields, static fields, and instance fields. /// For methods, it handles static methods. From 5e9077ccd99d1237292bd30f36ca1bc089937716 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Thu, 7 Mar 2024 11:44:47 +0800 Subject: [PATCH 18/33] update --- .../Expression/AssignmentExpression.cs | 18 ++++++ .../Expression/CheckedExpression.cs | 1 + .../Expression/ElementExpression.cs | 59 +++++++++++++++---- .../Expression/MemberExpression.cs | 11 ++++ 4 files changed, 76 insertions(+), 13 deletions(-) diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/AssignmentExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/AssignmentExpression.cs index 0356ce70f..50e76f89c 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/AssignmentExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/AssignmentExpression.cs @@ -23,6 +23,24 @@ partial class MethodConvert /// /// The semantic model providing context and information about assignment expression. /// The syntax representation of the assignment expression statement being converted. + /// + /// The following code covers three branches. If you want to see the example code for only one of the branches, + /// you can look at the comments of the corresponding method. + /// + /// public class Cat + /// { + /// public string Name { get; set; } + /// } + /// + /// + /// Cat nullableCat = null; + /// Cat nonNullableCat = new() { Name = "Mimi" }; + /// nullableCat ??= nonNullableCat; + /// var logInfo = "Nullable cat: "; + /// logInfo += nullableCat.Name; + /// Runtime.Log(log); + /// + /// private void ConvertAssignmentExpression(SemanticModel model, AssignmentExpressionSyntax expression) { diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/CheckedExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/CheckedExpression.cs index e6cfc63aa..a6265a1fd 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/CheckedExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/CheckedExpression.cs @@ -48,6 +48,7 @@ partial class MethodConvert /// int a = temp * 2; /// } /// + /// For a checked statement, see the ../Statement/CheckedStatement.cs file. /// private void ConvertCheckedExpression(SemanticModel model, CheckedExpressionSyntax expression) { diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/ElementExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/ElementExpression.cs index efe981c4b..5e96d2c1f 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/ElementExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/ElementExpression.cs @@ -21,8 +21,8 @@ namespace Neo.Compiler; partial class MethodConvert { /// - /// This method converts an element access expression to OpCodes. - /// An element access expression accesses a single element in an array or a collection. + /// This method converts an array element or indexer access ([]) expression to OpCodes. + /// An array element or indexer access ([]) expression accesses a single element in an array or a collection. /// /// The semantic model providing context and information about element access expression. /// The syntax representation of the element access expression statement being converted. @@ -31,6 +31,18 @@ partial class MethodConvert /// If the accessed element is a property, the method calls the property's getter. /// If the accessed element is an array or a collection, the method generates OpCodes to fetch the element. /// + /// + /// The following example demonstrates how to access array elements: + /// + /// var array = new byte[8]; + /// var sum = 0; + /// for (var i = 0; i< 8; i++) + /// { + /// sum += array[i]; + /// } + /// Runtime.Log(sum.ToString()); + /// + /// private void ConvertElementAccessExpression(SemanticModel model, ElementAccessExpressionSyntax expression) { if (expression.ArgumentList.Arguments.Count != 1) @@ -47,16 +59,6 @@ private void ConvertElementAccessExpression(SemanticModel model, ElementAccessEx } } - /// - /// This method converts an element binding expression to OpCodes. - /// An element binding expression is used to access a single element in a collection initializer. - /// - /// The semantic model providing context and information about element binding expression. - /// The syntax representation of the element binding expression statement being converted. - /// Only one-dimensional arrays are supported, otherwise an exception is thrown. - /// - /// The method generates OpCodes to fetch the element based on the given index or range. - /// private void ConvertElementBindingExpression(SemanticModel model, ElementBindingExpressionSyntax expression) { if (expression.ArgumentList.Arguments.Count != 1) @@ -72,7 +74,38 @@ private void ConvertElementBindingExpression(SemanticModel model, ElementBinding /// The semantic model providing contextual information for the expression. /// The type symbol of the array or collection being accessed. /// The expression representing the index or range. - /// Only one-dimensional arrays are supported, otherwise an exception is thrown. + /// Only byte[] and string type support range access, + /// otherwise, an exception is thrown. For examples. + /// + /// int[] oneThroughTen = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + /// var a = oneThroughTen[..]; + /// + /// + /// + /// The following code is an example of an index or range selector in a collective: + /// + /// byte[] oneThroughTen = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + /// var a = oneThroughTen[..]; + /// var b = oneThroughTen[..3]; + /// var c = oneThroughTen[2..]; + /// var d = oneThroughTen[3..5]; + /// var e = oneThroughTen[^2..]; + /// var f = oneThroughTen[..^3]; + /// var g = oneThroughTen[3..^4]; + /// var h = oneThroughTen[^4..^2]; + /// var i = oneThroughTen[0]; + /// + /// result: + /// a: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 + /// b: 1, 2, 3 + /// c: 3, 4, 5, 6, 7, 8, 9, 10 + /// d: 4, 5 + /// e: 9, 10 + /// f: 1, 2, 3, 4, 5, 6, 7 + /// g: 4, 5, 6 + /// h: 7, 8 + /// i: 1 + /// /// /// If the expression is a range, it calculates the start and end indices and extracts the relevant sub-array or sub-collection. /// If the expression is an index, it generates OpCodes to fetch the element at the specified index. diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/MemberExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/MemberExpression.cs index 4836643d7..f86ddcd36 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/MemberExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/MemberExpression.cs @@ -78,6 +78,17 @@ private void ConvertMemberAccessExpression(SemanticModel model, MemberAccessExpr } } + /// + /// This method converts a member binding expression to OpCodes. + /// + /// The semantic model providing context and information about member binding expression. + /// The syntax representation of the member binding expression statement being converted. + /// Unsupported symbols will result in a compilation exception, such as methods. + /// + /// The method determines the symbol associated with the member binding expression from the semantic model. + /// It then generates OpCodes based on the type of symbol. + /// Supported symbols include fields and properties. + /// private void ConvertMemberBindingExpression(SemanticModel model, MemberBindingExpressionSyntax expression) { ISymbol symbol = model.GetSymbolInfo(expression).Symbol!; From ea2b66603dce15bb100c232734d22a312432ccc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Thu, 7 Mar 2024 16:53:02 +0800 Subject: [PATCH 19/33] add seealso --- .../Expression/AnonymousObjectCreationExpression.cs | 6 ++---- .../Expression/ArrayCreationExpression.cs | 9 +++------ .../AssignmentExpression.CoalesceAssignment.cs | 12 ++++-------- .../AssignmentExpression.ComplexAssignment.cs | 3 ++- .../AssignmentExpression.SimpleAssignment.cs | 9 ++------- .../MethodConvert/Expression/AssignmentExpression.cs | 2 +- .../MethodConvert/Expression/BinaryExpression.cs | 6 ++++++ .../MethodConvert/Expression/CastExpression.cs | 1 + .../MethodConvert/Expression/CheckedExpression.cs | 3 ++- .../Expression/ConditionalAccessExpression.cs | 1 + .../Expression/ConditionalExpression.cs | 1 + .../MethodConvert/Expression/ElementExpression.cs | 1 + .../MethodConvert/Expression/Expression.cs | 6 ++++++ .../Expression/IdentifierNameExpression.cs | 1 + .../Expression/ImplicitArrayCreationExpression.cs | 1 + .../Expression/InterpolatedStringExpression.cs | 2 ++ .../MethodConvert/Expression/IsPatternExpression.cs | 1 + .../MethodConvert/Expression/MemberExpression.cs | 1 + .../MethodConvert/Expression/SwitchExpression.cs | 5 +++-- .../MethodConvert/Expression/TupleExpression.cs | 2 ++ .../Expression/UnaryExpression.PostfixUnary.cs | 1 + .../Expression/UnaryExpression.PrefixUnary.cs | 1 + 22 files changed, 45 insertions(+), 30 deletions(-) diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/AnonymousObjectCreationExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/AnonymousObjectCreationExpression.cs index a3e3547da..aced03d24 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/AnonymousObjectCreationExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/AnonymousObjectCreationExpression.cs @@ -30,11 +30,9 @@ partial class MethodConvert /// /// /// The following example shows an anonymous type that is initialized with two properties named Amount and Message. - /// - /// var v = new { Amount = 108, Message = "Hello" }; - /// Runtime.Log(v.Amount + v.Message); - /// + /// var v = new { Amount = 108, Message = "Hello" }; /// + /// Anonymous types private void ConvertAnonymousObjectCreationExpression(SemanticModel model, AnonymousObjectCreationExpressionSyntax expression) { AddInstruction(OpCode.NEWARRAY0); diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/ArrayCreationExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/ArrayCreationExpression.cs index 422dcf4c6..3618a4f18 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/ArrayCreationExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/ArrayCreationExpression.cs @@ -32,15 +32,12 @@ partial class MethodConvert /// /// /// Example of a array creation syntax: - /// - /// var array = new byte[4]; - /// + /// var array = new byte[4]; /// The compilation result of the example code is: OpCode.PUSH4, OpCode.NEWBUFFER - /// - /// var array = new int[4] { 5, 6, 7, 8}; - /// + /// var array = new int[4] { 5, 6, 7, 8}; /// The compilation result of the example code is: OpCode.PUSH8, OpCode.PUSH7, OpCode.PUSH6, OpCode.PUSH5, OpCode.PUSH4, OpCode.PACK /// + /// Arrays private void ConvertArrayCreationExpression(SemanticModel model, ArrayCreationExpressionSyntax expression) { ArrayRankSpecifierSyntax specifier = expression.Type.RankSpecifiers[0]; diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/AssignmentExpression.CoalesceAssignment.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/AssignmentExpression.CoalesceAssignment.cs index d20d87ac0..61bee1207 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/AssignmentExpression.CoalesceAssignment.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/AssignmentExpression.CoalesceAssignment.cs @@ -25,6 +25,7 @@ partial class MethodConvert /// Converts the code for null-coalescing assignment expression into OpCodes. /// The null-coalescing assignment operator ??= assigns the value of its right-hand operand to its left-hand operand only if the left-hand operand evaluates to null. /// The ??= operator doesn't evaluate its right-hand operand if the left-hand operand evaluates to non-null. + /// Null-coalescing assignment expressions are a new feature introduced in C# 8.0(Released September, 2019). /// /// The semantic model providing context and information about coalesce assignment expression. /// The syntax representation of the coalesce assignment expression statement being converted. @@ -42,15 +43,10 @@ partial class MethodConvert /// nullableCat ??= nonNullableCat; /// Runtime.Log("Nullable cat: " + nullableCat.Name); /// - /// "nullableCat ??= nonNullableCat;" this line is evaluated as - /// - /// nullableCat = nullableCat ?? nonNullableCat; - /// - /// is evaluated as - /// - /// if (nullableCat == null) nullableCat = nonNullableCat; - /// + /// nullableCat ??= nonNullableCat; this line is evaluated as + /// nullableCat = nullableCat ?? nonNullableCat; is evaluated as if (nullableCat == null) nullableCat = nonNullableCat; /// + /// ?? and ??= operators - the null-coalescing operators private void ConvertCoalesceAssignmentExpression(SemanticModel model, AssignmentExpressionSyntax expression) { switch (expression.Left) diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/AssignmentExpression.ComplexAssignment.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/AssignmentExpression.ComplexAssignment.cs index 25c5ae139..1ad574cad 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/AssignmentExpression.ComplexAssignment.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/AssignmentExpression.ComplexAssignment.cs @@ -22,7 +22,7 @@ namespace Neo.Compiler; partial class MethodConvert { /// - /// Converts the code for complex assignment expression into OpCodes. + /// Converts the code for complex assignment (or compound assignment) expression into OpCodes. /// /// The semantic model providing context and information about complex assignment expression. /// The syntax representation of the complex assignment expression statement being converted. @@ -48,6 +48,7 @@ partial class MethodConvert /// /// output: 14, 10, 20, 5, 2 /// + /// Compound assignment private void ConvertComplexAssignmentExpression(SemanticModel model, AssignmentExpressionSyntax expression) { ITypeSymbol type = model.GetTypeInfo(expression).Type!; diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/AssignmentExpression.SimpleAssignment.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/AssignmentExpression.SimpleAssignment.cs index 6c3e16f41..067ace526 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/AssignmentExpression.SimpleAssignment.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/AssignmentExpression.SimpleAssignment.cs @@ -36,14 +36,9 @@ partial class MethodConvert /// /// /// The assignment operator = is right-associative, that is, an expression of the form - /// - /// a = b = c - /// - /// is evaluated as - /// - /// a = (b = c) - /// + /// a = b = c is evaluated as a = (b = c) /// + /// Assignment operators private void ConvertSimpleAssignmentExpression(SemanticModel model, AssignmentExpressionSyntax expression) { ConvertExpression(model, expression.Right); diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/AssignmentExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/AssignmentExpression.cs index 50e76f89c..fd869a9d3 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/AssignmentExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/AssignmentExpression.cs @@ -41,7 +41,7 @@ partial class MethodConvert /// Runtime.Log(log); /// /// - + /// private void ConvertAssignmentExpression(SemanticModel model, AssignmentExpressionSyntax expression) { switch (expression.OperatorToken.ValueText) diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/BinaryExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/BinaryExpression.cs index 824ff6301..cc2c67248 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/BinaryExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/BinaryExpression.cs @@ -39,6 +39,12 @@ partial class MethodConvert /// The semantic model providing context and information about binary expression. /// The syntax representation of the binary expression statement being converted. /// If an unsupported operator is encountered + /// Boolean logical operators - AND, OR + /// Type-testing operators and cast expressions - is, as + /// ?? operators - the null-coalescing operators + /// Bitwise and shift operators + /// Arithmetic operators + /// Boolean logical operators - AND, OR, NOT, XOR private void ConvertBinaryExpression(SemanticModel model, BinaryExpressionSyntax expression) { switch (expression.OperatorToken.ValueText) diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/CastExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/CastExpression.cs index fceafd478..bb5f1e6fd 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/CastExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/CastExpression.cs @@ -40,6 +40,7 @@ partial class MethodConvert /// Runtime.Log(point.ToString()); /// /// + /// Cast expression private void ConvertCastExpression(SemanticModel model, CastExpressionSyntax expression) { ITypeSymbol sType = model.GetTypeInfo(expression.Expression).Type!; diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/CheckedExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/CheckedExpression.cs index a6265a1fd..d35c1680c 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/CheckedExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/CheckedExpression.cs @@ -48,8 +48,9 @@ partial class MethodConvert /// int a = temp * 2; /// } /// - /// For a checked statement, see the ../Statement/CheckedStatement.cs file. + /// For a checked statement, see /// + /// Integer arithmetic overflow private void ConvertCheckedExpression(SemanticModel model, CheckedExpressionSyntax expression) { _checkedStack.Push(expression.Keyword.IsKind(SyntaxKind.CheckedKeyword)); diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/ConditionalAccessExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/ConditionalAccessExpression.cs index dcffc00fa..f38d3f35a 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/ConditionalAccessExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/ConditionalAccessExpression.cs @@ -47,6 +47,7 @@ partial class MethodConvert /// Runtime.Log(firstItem?.Timestamp.ToString()); /// /// + /// Null-conditional operators ?. and ?[] private void ConvertConditionalAccessExpression(SemanticModel model, ConditionalAccessExpressionSyntax expression) { ITypeSymbol type = model.GetTypeInfo(expression).Type!; diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/ConditionalExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/ConditionalExpression.cs index aa04849c5..b9f736a2b 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/ConditionalExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/ConditionalExpression.cs @@ -34,6 +34,7 @@ partial class MethodConvert /// Runtime.Log(state.ToString()); /// /// + /// ?: operator - the ternary conditional operator private void ConvertConditionalExpression(SemanticModel model, ConditionalExpressionSyntax expression) { JumpTarget falseTarget = new(); diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/ElementExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/ElementExpression.cs index 5e96d2c1f..00d91d528 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/ElementExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/ElementExpression.cs @@ -43,6 +43,7 @@ partial class MethodConvert /// Runtime.Log(sum.ToString()); /// /// + /// Indexer operator [] private void ConvertElementAccessExpression(SemanticModel model, ElementAccessExpressionSyntax expression) { if (expression.ArgumentList.Arguments.Count != 1) diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs index b317ddf7c..13c041bc9 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs @@ -81,12 +81,18 @@ private void ConvertExpression(SemanticModel model, ExpressionSyntax syntax, Syn switch (syntax) { + //Convert an expression that creates an object of an anonymous type. + //Example: new { Amount = 108, Message = "Hello" }; case AnonymousObjectCreationExpressionSyntax expression: ConvertAnonymousObjectCreationExpression(model, expression); break; + //Convert an expression that creates an array. + //Example: new int[4] { 5, 6, 7, 8}; case ArrayCreationExpressionSyntax expression: ConvertArrayCreationExpression(model, expression); break; + //Convert an assignment expression. + //Example: new int[4] { 5, 6, 7, 8}; case AssignmentExpressionSyntax expression: ConvertAssignmentExpression(model, expression); break; diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/IdentifierNameExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/IdentifierNameExpression.cs index 463a46a7f..6f2eac064 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/IdentifierNameExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/IdentifierNameExpression.cs @@ -40,6 +40,7 @@ partial class MethodConvert /// } /// /// + /// C# identifier naming rules and conventions private void ConvertIdentifierNameExpression(SemanticModel model, IdentifierNameSyntax expression) { ISymbol symbol = model.GetSymbolInfo(expression).Symbol!; diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/ImplicitArrayCreationExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/ImplicitArrayCreationExpression.cs index a0c151ba5..2a1027825 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/ImplicitArrayCreationExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/ImplicitArrayCreationExpression.cs @@ -39,6 +39,7 @@ partial class MethodConvert /// /// Multidimensional implicitly typed arrays are not supported. /// + /// Implicitly typed arrays private void ConvertImplicitArrayCreationExpression(SemanticModel model, ImplicitArrayCreationExpressionSyntax expression) { IArrayTypeSymbol type = (IArrayTypeSymbol)model.GetTypeInfo(expression).ConvertedType!; diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/InterpolatedStringExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/InterpolatedStringExpression.cs index b4d5b9a33..ade8bbff0 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/InterpolatedStringExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/InterpolatedStringExpression.cs @@ -24,6 +24,7 @@ partial class MethodConvert /// An interpolated string is a string literal that might contain interpolation expressions. /// When an interpolated string is resolved to a result string, /// items with interpolation expressions are replaced by the string representations of the expression results. + /// Interpolated string expression are a new feature introduced in C# 8.0(Released September, 2019). /// /// The semantic model providing context and information about interpolated string expression. /// The syntax representation of the interpolated string expression statement being converted. @@ -40,6 +41,7 @@ partial class MethodConvert /// Runtime.Log($"Hello, {name}! Current timestamp is {timestamp}."); /// /// + /// String interpolation using $ private void ConvertInterpolatedStringExpression(SemanticModel model, InterpolatedStringExpressionSyntax expression) { if (expression.Contents.Count == 0) diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/IsPatternExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/IsPatternExpression.cs index b18e70af4..2ca8474f9 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/IsPatternExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/IsPatternExpression.cs @@ -37,6 +37,7 @@ partial class MethodConvert /// } /// /// + /// is operator private void ConvertIsPatternExpression(SemanticModel model, IsPatternExpressionSyntax expression) { byte anonymousIndex = AddAnonymousVariable(); diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/MemberExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/MemberExpression.cs index f86ddcd36..10943cd46 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/MemberExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/MemberExpression.cs @@ -40,6 +40,7 @@ partial class MethodConvert /// Runtime.Log(Ledger.CurrentHash.ToString()); /// /// + /// Member access expression private void ConvertMemberAccessExpression(SemanticModel model, MemberAccessExpressionSyntax expression) { ISymbol symbol = model.GetSymbolInfo(expression).Symbol!; diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/SwitchExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/SwitchExpression.cs index 759422ffc..afdffac3e 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/SwitchExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/SwitchExpression.cs @@ -21,8 +21,8 @@ partial class MethodConvert { /// /// This method converts a switch expression expression to OpCodes. - /// Switch expressions are a new feature introduced in C# 7.0. - /// For a traditional switch statement, see the ../Statement/SwitchStatement.cs file. + /// Switch expressions are a new feature introduced in C# 8.0(Released September, 2019). + /// For a traditional switch statement, see . /// /// The semantic model providing context and information about switch expression. /// The syntax representation of the switch expression statement being converted. @@ -50,6 +50,7 @@ partial class MethodConvert /// Runtime.Log($"Today is {dayName}"); /// /// + /// switch expression - pattern matching expressions using the switch keyword private void ConvertSwitchExpression(SemanticModel model, SwitchExpressionSyntax expression) { var arms = expression.Arms.Select(p => (p, new JumpTarget())).ToArray(); diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/TupleExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/TupleExpression.cs index 1b0688ab2..5aa1b948b 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/TupleExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/TupleExpression.cs @@ -20,6 +20,7 @@ partial class MethodConvert { /// /// Converts the code for tuple type into OpCodes. + /// Tuple types expressions are a new feature introduced in C# 7.0(Released March, 2017). /// /// The semantic model providing context and information about the tuple type. /// The syntax representation of the tuple type statement being converted. @@ -33,6 +34,7 @@ partial class MethodConvert /// Runtime.Log($"Sum of {t2.Name} elements is {t2.Count}."); /// /// + /// Tuple types private void ConvertTupleExpression(SemanticModel model, TupleExpressionSyntax expression) { AddInstruction(OpCode.NEWSTRUCT0); diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/UnaryExpression.PostfixUnary.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/UnaryExpression.PostfixUnary.cs index f7bee5c9f..a7fc3cdca 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/UnaryExpression.PostfixUnary.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/UnaryExpression.PostfixUnary.cs @@ -36,6 +36,7 @@ partial class MethodConvert /// /// output: 3、3、4 /// + /// Postfix increment operator private void ConvertPostfixUnaryExpression(SemanticModel model, PostfixUnaryExpressionSyntax expression) { switch (expression.OperatorToken.ValueText) diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/UnaryExpression.PrefixUnary.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/UnaryExpression.PrefixUnary.cs index e0648bb17..bae1c325e 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/UnaryExpression.PrefixUnary.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/UnaryExpression.PrefixUnary.cs @@ -36,6 +36,7 @@ partial class MethodConvert /// /// output: 3、4、4 /// + /// Prefix increment operator private void ConvertPrefixUnaryExpression(SemanticModel model, PrefixUnaryExpressionSyntax expression) { switch (expression.OperatorToken.ValueText) From 7c9ed328b7c8ff803e0f19edfb63200bca9cde34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Thu, 7 Mar 2024 17:12:55 +0800 Subject: [PATCH 20/33] update --- .../MethodConvert/Expression/Expression.cs | 33 +++++++++++++++++++ .../Expression/MemberExpression.cs | 11 ------- .../Expression/SwitchExpression.cs | 2 +- 3 files changed, 34 insertions(+), 12 deletions(-) diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs index 13c041bc9..9db9a2f4b 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs @@ -102,57 +102,88 @@ private void ConvertExpression(SemanticModel model, ExpressionSyntax syntax, Syn case BinaryExpressionSyntax expression: ConvertBinaryExpression(model, expression); break; + //Converts a cast expression. + //Example: (ECPoint)ByteString.Empty; case CastExpressionSyntax expression: ConvertCastExpression(model, expression); break; + //Converts a checked expression. + //Example: checked(temp * 2); case CheckedExpressionSyntax expression: ConvertCheckedExpression(model, expression); break; + //Converts a null-conditional access expression. + //Example: people?.Name; array?[i]; case ConditionalAccessExpressionSyntax expression: ConvertConditionalAccessExpression(model, expression); break; + //Converts a null-conditional access expression. + //Example: var x = a > b ? a : b; case ConditionalExpressionSyntax expression: ConvertConditionalExpression(model, expression); break; + //Converts an array element or indexer access ([]) expression. + //Example: array[i]; case ElementAccessExpressionSyntax expression: ConvertElementAccessExpression(model, expression); break; + // ???? case ElementBindingExpressionSyntax expression: ConvertElementBindingExpression(model, expression); break; + //Converts an identifier name expression. + //Example: int a = 1; case IdentifierNameSyntax expression: ConvertIdentifierNameExpression(model, expression); break; + //Converts an implicit array creation expression. + //Example: var authorNames = new[] {"Shilpa", "Soniya", "Shivi", "Ritika"}; case ImplicitArrayCreationExpressionSyntax expression: ConvertImplicitArrayCreationExpression(model, expression); break; + //TODO case InitializerExpressionSyntax expression: ConvertInitializerExpression(model, expression); break; + //Converts an interpolated string expression; + //Example: $"Hello, {name}" case InterpolatedStringExpressionSyntax expression: ConvertInterpolatedStringExpression(model, expression); break; + //TODO case InvocationExpressionSyntax expression: ConvertInvocationExpression(model, expression); break; + //Converts an 'is' pattern expression; + //Example: if (obj is string) case IsPatternExpressionSyntax expression: ConvertIsPatternExpression(model, expression); break; + //Converts a member access expression. + //Example: Ledger.CurrentHash case MemberAccessExpressionSyntax expression: ConvertMemberAccessExpression(model, expression); break; + // ???? case MemberBindingExpressionSyntax expression: ConvertMemberBindingExpression(model, expression); break; + //TODO case ParenthesizedExpressionSyntax expression: ConvertExpression(model, expression.Expression); break; + //Converts postfix operator. + //Example: i++, i-- case PostfixUnaryExpressionSyntax expression: ConvertPostfixUnaryExpression(model, expression); break; + //Converts prefix operator. + //Example: ++i, --i, !flag case PrefixUnaryExpressionSyntax expression: ConvertPrefixUnaryExpression(model, expression); break; + //Converts a switch expression. + //Example: day switch { 1 => "Monday", 2 => "Tuesday", 3 => "Wednesday", 4 => "Thursday", 5 => "Friday", 6 => "Saturday", 7 => "Sunday", _ => "Unknown" }; case SwitchExpressionSyntax expression: ConvertSwitchExpression(model, expression); break; @@ -163,6 +194,8 @@ private void ConvertExpression(SemanticModel model, ExpressionSyntax syntax, Syn case ThrowExpressionSyntax expression: Throw(model, expression.Expression); break; + //Converts a tuple type expression. + //Example: (string, int) t1 = ("chris", 3); case TupleExpressionSyntax expression: ConvertTupleExpression(model, expression); break; diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/MemberExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/MemberExpression.cs index 10943cd46..616613bc1 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/MemberExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/MemberExpression.cs @@ -79,17 +79,6 @@ private void ConvertMemberAccessExpression(SemanticModel model, MemberAccessExpr } } - /// - /// This method converts a member binding expression to OpCodes. - /// - /// The semantic model providing context and information about member binding expression. - /// The syntax representation of the member binding expression statement being converted. - /// Unsupported symbols will result in a compilation exception, such as methods. - /// - /// The method determines the symbol associated with the member binding expression from the semantic model. - /// It then generates OpCodes based on the type of symbol. - /// Supported symbols include fields and properties. - /// private void ConvertMemberBindingExpression(SemanticModel model, MemberBindingExpressionSyntax expression) { ISymbol symbol = model.GetSymbolInfo(expression).Symbol!; diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/SwitchExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/SwitchExpression.cs index afdffac3e..41b12b24a 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/SwitchExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/SwitchExpression.cs @@ -20,7 +20,7 @@ namespace Neo.Compiler; partial class MethodConvert { /// - /// This method converts a switch expression expression to OpCodes. + /// This method converts a switch expression to OpCodes. /// Switch expressions are a new feature introduced in C# 8.0(Released September, 2019). /// For a traditional switch statement, see . /// From 5831fce93051b58ba10cb599e3ccb4cb96044c32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Thu, 7 Mar 2024 18:12:56 +0800 Subject: [PATCH 21/33] update --- .../MethodConvert/Expression/Expression.cs | 6 ++-- .../Expression/InitializerExpression.cs | 14 +++++++++ .../Expression/InvocationExpression.cs | 31 +++++++++++++++++++ 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs index 9db9a2f4b..4c3c73a20 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs @@ -141,7 +141,8 @@ private void ConvertExpression(SemanticModel model, ExpressionSyntax syntax, Syn case ImplicitArrayCreationExpressionSyntax expression: ConvertImplicitArrayCreationExpression(model, expression); break; - //TODO + //Converts an initialValue attribute + //Example: [InitialValue("NVg7LjGcUSrgxgjX3zEgqaksfMaiS8Z6e1"] case InitializerExpressionSyntax expression: ConvertInitializerExpression(model, expression); break; @@ -150,7 +151,8 @@ private void ConvertExpression(SemanticModel model, ExpressionSyntax syntax, Syn case InterpolatedStringExpressionSyntax expression: ConvertInterpolatedStringExpression(model, expression); break; - //TODO + //Converts Invocation, include method invocation, event invocation and delegate invocation + //Example: Runtime.Log("hello"); case InvocationExpressionSyntax expression: ConvertInvocationExpression(model, expression); break; diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/InitializerExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/InitializerExpression.cs index bfcdfff25..5f1b0ee0c 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/InitializerExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/InitializerExpression.cs @@ -20,6 +20,20 @@ namespace Neo.Compiler; partial class MethodConvert { + /// + /// Converts an InitialValue attribute into OpCodes. + /// + /// The semantic model providing context and information about InitialValue expression. + /// The syntax representation of the InitialValue expression statement being converted. + /// + /// Specifies an initial value for a static field within a smart contract, + /// Example of initializing a UInt160 field with a Hash160 address + /// + /// [InitialValue("NVg7LjGcUSrgxgjX3zEgqaksfMaiS8Z6e1", ContractParameterType.Hash160)] + /// static readonly UInt160 Owner = default; + /// + /// + /// InitialValueAttribute private void ConvertInitializerExpression(SemanticModel model, InitializerExpressionSyntax expression) { IArrayTypeSymbol type = (IArrayTypeSymbol)model.GetTypeInfo(expression).ConvertedType!; diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/InvocationExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/InvocationExpression.cs index b7b58e5cb..56acf393c 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/InvocationExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/InvocationExpression.cs @@ -21,6 +21,11 @@ namespace Neo.Compiler; partial class MethodConvert { + /// + /// Converts Invocation, include method invocation, event invocation and delegate invocation to OpCodes. + /// + /// The semantic model providing context and information about invocation expression. + /// The syntax representation of the invocation expression statement being converted. private void ConvertInvocationExpression(SemanticModel model, InvocationExpressionSyntax expression) { ArgumentSyntax[] arguments = expression.ArgumentList.Arguments.ToArray(); @@ -39,6 +44,13 @@ private void ConvertInvocationExpression(SemanticModel model, InvocationExpressi } } + /// + /// Convert the event invocation expression to OpCodes. + /// + /// The semantic model providing context and information about event invocation expression. + /// Symbol of the event + /// Arguments of the event + /// private void ConvertEventInvocationExpression(SemanticModel model, IEventSymbol symbol, ArgumentSyntax[] arguments) { AddInstruction(OpCode.NEWARRAY0); @@ -52,6 +64,16 @@ private void ConvertEventInvocationExpression(SemanticModel model, IEventSymbol Call(ApplicationEngine.System_Runtime_Notify); } + /// + /// Convert the method invocation expression to OpCodes. + /// + /// The semantic model providing context and information about method invocation expression. + /// Symbol of the method + /// The syntax representation of the method invocation expression statement being converted. + /// Arguments of the method + /// + /// Runtime.Log("hello World!"); + /// private void ConvertMethodInvocationExpression(SemanticModel model, IMethodSymbol symbol, ExpressionSyntax expression, ArgumentSyntax[] arguments) { switch (expression) @@ -73,6 +95,15 @@ private void ConvertMethodInvocationExpression(SemanticModel model, IMethodSymbo } } + /// + /// Convert the delegate invocation expression to OpCodes. + /// + /// The semantic model providing context and information about delegate invocation expression. + /// The syntax representation of the delegate invocation expression statement being converted. + /// Arguments of the delegate + /// + /// TODO + /// private void ConvertDelegateInvocationExpression(SemanticModel model, ExpressionSyntax expression, ArgumentSyntax[] arguments) { INamedTypeSymbol type = (INamedTypeSymbol)model.GetTypeInfo(expression).Type!; From f2c27c26515990f295982781ed61b081a1c79512 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Fri, 8 Mar 2024 10:47:26 +0800 Subject: [PATCH 22/33] ConvertMemberBindingExpression and ConvertElementBindingExpression --- .../Expression/ConditionalAccessExpression.cs | 1 + .../Expression/ElementExpression.cs | 15 +++++++++++++ .../MethodConvert/Expression/Expression.cs | 6 +++-- .../Expression/MemberExpression.cs | 22 +++++++++++++++++++ .../Contract_NULL.cs | 6 +---- 5 files changed, 43 insertions(+), 7 deletions(-) diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/ConditionalAccessExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/ConditionalAccessExpression.cs index f38d3f35a..7c34c5bb1 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/ConditionalAccessExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/ConditionalAccessExpression.cs @@ -30,6 +30,7 @@ partial class MethodConvert /// If the resulting type of the expression is 'System.Void', it handles the case differently by dropping the result. /// A null-conditional operator applies a member access (?.) or element access (?[]) operation to its operand only if that operand evaluates to non-null; /// otherwise, it returns null. + /// It will jump to and to handle the case where the variable or array is not null. /// /// /// If Block is not null, get the block's timestamp; otherwise, it returns null. diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/ElementExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/ElementExpression.cs index 00d91d528..10cf8f098 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/ElementExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/ElementExpression.cs @@ -60,6 +60,21 @@ private void ConvertElementAccessExpression(SemanticModel model, ElementAccessEx } } + /// + /// Further conversion of the ?[] statement in the method + /// + /// The semantic model providing context and information about element binding expression. + /// The syntax representation of the element binding expression statement being converted. + /// Only one-dimensional arrays are supported, otherwise an exception is thrown. + /// + /// + /// var a = Ledger.GetBlock(10000); + /// var b = Ledger.GetBlock(10001); + /// var array = new[] { a, b }; + /// var firstItem = array?[0]; + /// Runtime.Log(firstItem?.Timestamp.ToString()); + /// + /// private void ConvertElementBindingExpression(SemanticModel model, ElementBindingExpressionSyntax expression) { if (expression.ArgumentList.Arguments.Count != 1) diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs index 4c3c73a20..006d8ef6f 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs @@ -127,7 +127,8 @@ private void ConvertExpression(SemanticModel model, ExpressionSyntax syntax, Syn case ElementAccessExpressionSyntax expression: ConvertElementAccessExpression(model, expression); break; - // ???? + //Further conversion of the ?[] statement in the ConvertConditionalAccessExpression method. + //Example: array?[i]; case ElementBindingExpressionSyntax expression: ConvertElementBindingExpression(model, expression); break; @@ -166,7 +167,8 @@ private void ConvertExpression(SemanticModel model, ExpressionSyntax syntax, Syn case MemberAccessExpressionSyntax expression: ConvertMemberAccessExpression(model, expression); break; - // ???? + //Further conversion of the ?. statement in the ConvertConditionalAccessExpression method + //Example: people?.Name; case MemberBindingExpressionSyntax expression: ConvertMemberBindingExpression(model, expression); break; diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/MemberExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/MemberExpression.cs index 616613bc1..d5e5abf98 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/MemberExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/MemberExpression.cs @@ -79,6 +79,28 @@ private void ConvertMemberAccessExpression(SemanticModel model, MemberAccessExpr } } + /// + /// Further conversion of the ?. statement in the method + /// + /// The semantic model providing context and information about member binding expression. + /// The syntax representation of the member binding expression statement being converted. + /// Only attributes and fields are supported, otherwise an exception is thrown. + /// + /// + /// public class Person + /// { + /// public string Name; + /// public int Age { get; set; } + /// } + /// + /// + /// Person person = null; + /// Runtime.Log(person?.Name); + /// Runtime.Log(person?.Age.ToString()); + /// + /// person?.Name code executes the case IFieldSymbol field branch; + /// person?.Age code executes the case IPropertySymbol property branch. + /// private void ConvertMemberBindingExpression(SemanticModel model, MemberBindingExpressionSyntax expression) { ISymbol symbol = model.GetSymbolInfo(expression).Symbol!; diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_NULL.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_NULL.cs index 676fd21f4..6b0a1f463 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_NULL.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_NULL.cs @@ -30,11 +30,7 @@ public static bool EqualNotNullB(byte[] value) return value != null; } - public static string NullCoalescing(string code) - { - string myname = code?.Substring(1, 2); - return myname; - } + public static string NullCollation(string code) { From 637c061201fd278c7ab1fea6065a292b67dcb509 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Fri, 8 Mar 2024 11:04:26 +0800 Subject: [PATCH 23/33] ConvertInitializerExpression --- .../MethodConvert/Expression/Expression.cs | 4 ++-- .../Expression/InitializerExpression.cs | 24 ++++++++++++------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs index 006d8ef6f..d1051af65 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs @@ -142,8 +142,8 @@ private void ConvertExpression(SemanticModel model, ExpressionSyntax syntax, Syn case ImplicitArrayCreationExpressionSyntax expression: ConvertImplicitArrayCreationExpression(model, expression); break; - //Converts an initialValue attribute - //Example: [InitialValue("NVg7LjGcUSrgxgjX3zEgqaksfMaiS8Z6e1"] + //Converts initialization of array fields + //Example: static UInt160 Owner = UInt160.Zero; case InitializerExpressionSyntax expression: ConvertInitializerExpression(model, expression); break; diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/InitializerExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/InitializerExpression.cs index 5f1b0ee0c..40ce9be29 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/InitializerExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/InitializerExpression.cs @@ -21,19 +21,27 @@ namespace Neo.Compiler; partial class MethodConvert { /// - /// Converts an InitialValue attribute into OpCodes. + /// Converts initialization of array fields into OpCodes. /// - /// The semantic model providing context and information about InitialValue expression. - /// The syntax representation of the InitialValue expression statement being converted. + /// The semantic model providing context and information about initialization of array fields expression. + /// The syntax representation of the initialization of array fields expression statement being converted. /// - /// Specifies an initial value for a static field within a smart contract, - /// Example of initializing a UInt160 field with a Hash160 address + /// The following 4 static fields will each be converted in this method. /// - /// [InitialValue("NVg7LjGcUSrgxgjX3zEgqaksfMaiS8Z6e1", ContractParameterType.Hash160)] - /// static readonly UInt160 Owner = default; + /// static string[] A = { "BTC", "NEO", "GAS" }; + /// static int[] B = { 1, 2 }; + /// static byte[] C = { 1, 2 }; + /// static UInt160 D = UInt160.Zero; + /// + /// public static void MyMethod() + /// { + /// Runtime.Log(A[0]); + /// Runtime.Log(B[0]); + /// Runtime.Log(C[0]); + /// Runtime.Log(D.ToAddress()); + /// } /// /// - /// InitialValueAttribute private void ConvertInitializerExpression(SemanticModel model, InitializerExpressionSyntax expression) { IArrayTypeSymbol type = (IArrayTypeSymbol)model.GetTypeInfo(expression).ConvertedType!; From 3ce867a2c63183950ffe3ff6b6429fd6d6b27d7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Fri, 8 Mar 2024 11:22:43 +0800 Subject: [PATCH 24/33] BaseExpression and ThisExpression --- .../MethodConvert/Expression/Expression.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs index d1051af65..4dcb92138 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs @@ -172,7 +172,9 @@ private void ConvertExpression(SemanticModel model, ExpressionSyntax syntax, Syn case MemberBindingExpressionSyntax expression: ConvertMemberBindingExpression(model, expression); break; - //TODO + //Converts a parenthesized expression. + //Continuing the recursive processing of the expression with the parentheses removed. + //Example: (a / b), (a + b), (new byte[33]) case ParenthesizedExpressionSyntax expression: ConvertExpression(model, expression.Expression); break; @@ -191,7 +193,11 @@ private void ConvertExpression(SemanticModel model, ExpressionSyntax syntax, Syn case SwitchExpressionSyntax expression: ConvertSwitchExpression(model, expression); break; + //Converts a base expression. + //Example: public A() : base() { } case BaseExpressionSyntax: + //Converts a extended methods + //Examples: UInt160.Zero.ToAddress(); case ThisExpressionSyntax: AddInstruction(OpCode.LDARG0); break; From fb99b89b1a41809a4dc2f1e66e83e1d6e9a2cbe4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Fri, 8 Mar 2024 11:57:56 +0800 Subject: [PATCH 25/33] Create Contract_Logical.cs --- .../Contract_Logical.cs | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 tests/Neo.Compiler.CSharp.TestContracts/Contract_Logical.cs diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Logical.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Logical.cs new file mode 100644 index 000000000..ab2cfa7b8 --- /dev/null +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Logical.cs @@ -0,0 +1,38 @@ +using Neo.SmartContract.Framework; +using System.Numerics; + +namespace Neo.Compiler.CSharp.UnitTests.TestClasses +{ + public class Contract_Logical : SmartContract.Framework.SmartContract + { + public static bool TestConditionalLogicalAnd(bool x, bool y) + { + return x && y; + } + + public static bool TestConditionalLogicalOr(bool x, bool y) + { + return x || y; + } + + public static bool TestLogicalExclusiveOr(bool x, bool y) + { + return x ^ y; + } + + public static byte TestLogicalAnd(byte x, byte y) + { + return x & y; + } + + public static byte TestLogicalOr(byte x, byte y) + { + return x | y; + } + + public static byte TestLogicalNegation(bool x) + { + return !x; + } + } +} From c4027cdc095dba16bf11f30f8ef3cdc5e630ef1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Fri, 8 Mar 2024 11:58:44 +0800 Subject: [PATCH 26/33] Update Contract_Logical.cs --- tests/Neo.Compiler.CSharp.TestContracts/Contract_Logical.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Logical.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Logical.cs index ab2cfa7b8..bc18a9e21 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Logical.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Logical.cs @@ -20,17 +20,17 @@ public static bool TestLogicalExclusiveOr(bool x, bool y) return x ^ y; } - public static byte TestLogicalAnd(byte x, byte y) + public static int TestLogicalAnd(byte x, byte y) { return x & y; } - public static byte TestLogicalOr(byte x, byte y) + public static int TestLogicalOr(byte x, byte y) { return x | y; } - public static byte TestLogicalNegation(bool x) + public static bool TestLogicalNegation(bool x) { return !x; } From a57885bf7d802f2ea17aec9fa9b6dafe6cbd3135 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Fri, 8 Mar 2024 13:27:07 +0800 Subject: [PATCH 27/33] format --- tests/Neo.Compiler.CSharp.TestContracts/Contract_NULL.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_NULL.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_NULL.cs index 6b0a1f463..c56a35c2b 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_NULL.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_NULL.cs @@ -30,8 +30,6 @@ public static bool EqualNotNullB(byte[] value) return value != null; } - - public static string NullCollation(string code) { string myname = code ?? "linux"; From aeb9abf3f5c618155a90c67fe9d4fed34f3880da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Fri, 8 Mar 2024 13:52:27 +0800 Subject: [PATCH 28/33] add ut --- .../Contract_Array.cs | 11 +++++++++++ .../Contract_Initializer.cs | 9 +++++++++ .../Contract_String.cs | 16 ++++++++++++++++ 3 files changed, 36 insertions(+) create mode 100644 tests/Neo.Compiler.CSharp.TestContracts/Contract_String.cs diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Array.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Array.cs index 0758bee40..3f012990b 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Array.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Array.cs @@ -1,3 +1,5 @@ +using Neo.SmartContract.Framework.Native; +using Neo.SmartContract.Framework.Services; using System; using System.Numerics; @@ -129,5 +131,14 @@ public static object TestSupportedStandards() { return SupportedStandards; } + + public static void TestElementBinding() + { + var a = Ledger.GetBlock(10000); + var b = Ledger.GetBlock(10001); + var array = new[] { a, b }; + var firstItem = array?[0]; + Runtime.Log(firstItem?.Timestamp.ToString()); + } } } diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Initializer.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Initializer.cs index db35d573e..b57bcee87 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Initializer.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Initializer.cs @@ -1,5 +1,6 @@ using System; using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Services; namespace Neo.Compiler.CSharp.UnitTests.TestClasses { @@ -34,5 +35,13 @@ public int sum2(int a, int b) x.B = b; return x.A + x.B; } + + public void anonymousObjectCreation() + { + var v = new { Amount = 108, Message = "Hello" }; + Runtime.Log(v.Message); + var anonArray = new[] { new { name = "apple", diam = 4 }, new { name = "grape", diam = 1 } }; + Runtime.Log(anonArray[0].name); + } } } diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_String.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_String.cs new file mode 100644 index 000000000..f5701cbb8 --- /dev/null +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_String.cs @@ -0,0 +1,16 @@ +using Neo.SmartContract.Framework.Native; +using Neo.SmartContract.Framework.Services; + +namespace Neo.Compiler.CSharp.UnitTests.TestClasses +{ + public class Contract_String : SmartContract.Framework.SmartContract + { + public static void TestMain() + { + var firstName = "Mark"; + var lastName = $""; + var timestamp = Ledger.GetBlock(Ledger.CurrentHash).Timestamp; + Runtime.Log($"Hello, {firstName} {lastName}! Current timestamp is {timestamp}."); + } + } +} From d922352f22c584412bd48899c065df9265824a05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Fri, 8 Mar 2024 13:56:49 +0800 Subject: [PATCH 29/33] Update Contract_NULL.cs --- tests/Neo.Compiler.CSharp.TestContracts/Contract_NULL.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_NULL.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_NULL.cs index c56a35c2b..676fd21f4 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_NULL.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_NULL.cs @@ -30,6 +30,12 @@ public static bool EqualNotNullB(byte[] value) return value != null; } + public static string NullCoalescing(string code) + { + string myname = code?.Substring(1, 2); + return myname; + } + public static string NullCollation(string code) { string myname = code ?? "linux"; From 1cc369dd90447b4e45dce5d94635b11471cf61c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Fri, 8 Mar 2024 14:41:27 +0800 Subject: [PATCH 30/33] throw --- .../MethodConvert/Expression/Expression.cs | 3 +++ .../MethodConvert/MethodConvert.cs | 25 ++++++++++++++++++ .../Contract_Throw.cs | 26 +++++++++++++++++++ 3 files changed, 54 insertions(+) create mode 100644 tests/Neo.Compiler.CSharp.TestContracts/Contract_Throw.cs diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs index 4dcb92138..e305305fc 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs @@ -201,6 +201,9 @@ private void ConvertExpression(SemanticModel model, ExpressionSyntax syntax, Syn case ThisExpressionSyntax: AddInstruction(OpCode.LDARG0); break; + //Converts a throw expression + //Examples: string a = null; var b = a ?? throw new Exception(); + //Examples: var first = args.Length >= 1 ? args[0] : throw new Exception(); case ThrowExpressionSyntax expression: Throw(model, expression.Expression); break; diff --git a/src/Neo.Compiler.CSharp/MethodConvert/MethodConvert.cs b/src/Neo.Compiler.CSharp/MethodConvert/MethodConvert.cs index 20ff4c58f..c49d28f4c 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/MethodConvert.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/MethodConvert.cs @@ -556,6 +556,31 @@ private Instruction Jump(OpCode opcode, JumpTarget target) }); } + /// + /// Convert a throw expression or throw statement to OpCodes. + /// + /// The semantic model providing context and information about the Throw. + /// The content of exception + /// Only a single parameter is supported for exceptions. + /// + /// throw statement: + /// + /// if (shapeAmount <= 0) + /// { + /// throw new Exception("Amount of shapes must be positive."); + /// } + /// + /// throw expression: + /// + /// string a = null; + /// var b = a ?? throw new Exception(); + /// + /// + /// var first = args.Length >= 1 ? args[0] : throw new Exception(); + /// + /// + /// The throw expression + /// Exception-handling statements - throw private void Throw(SemanticModel model, ExpressionSyntax? exception) { if (exception is not null) diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Throw.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Throw.cs new file mode 100644 index 000000000..37afccd8b --- /dev/null +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Throw.cs @@ -0,0 +1,26 @@ +using System; +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Services; + +namespace Neo.Compiler.CSharp.UnitTests.TestClasses +{ + public class Contract_Throw : SmartContract.Framework.SmartContract + { + public static void TestMain(string[] args) + { + string first = args.Length >= 1 ? args[0] : throw new ArgumentException("Please supply at least one argument."); + } + } + + public class Person + { + private string name; + + public string Name + { + get => name; + set => name = value ?? + throw new ArgumentNullException(paramName: nameof(value), message: "Name cannot be null"); + } + } +} From c6a9ab36ad758a66161166897b8d01f27c4be20c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Fri, 8 Mar 2024 16:37:34 +0800 Subject: [PATCH 31/33] fix --- .../MethodConvert/Expression/Expression.cs | 4 +++- .../MethodConvert/Expression/IdentifierNameExpression.cs | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs index e305305fc..5e94fff96 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs @@ -196,7 +196,9 @@ private void ConvertExpression(SemanticModel model, ExpressionSyntax syntax, Syn //Converts a base expression. //Example: public A() : base() { } case BaseExpressionSyntax: - //Converts a extended methods + //Converts "this" keyword + //The "this" keyword in extended methods is also handled here. + //Examples: private string name; public void MyMethod(){ Runtime.Log(this.name); } //Examples: UInt160.Zero.ToAddress(); case ThisExpressionSyntax: AddInstruction(OpCode.LDARG0); diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/IdentifierNameExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/IdentifierNameExpression.cs index 6f2eac064..0ee3873d2 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/IdentifierNameExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/IdentifierNameExpression.cs @@ -33,12 +33,14 @@ partial class MethodConvert /// /// public static void MyMethod(int param, int param2) /// { - /// int temp = int.MaxValue; + /// int temp = 0; + /// byte[] temp2 = new byte[1]; /// Runtime.Log(temp.ToString()); + /// Runtime.Log(temp2[0].ToString()); /// Runtime.Log(param.ToString()); - /// Runtime.Log(a.ToString()); /// } /// + /// The symbol.Name of the above code is as follows: "temp", "temp2", "param"; /// /// C# identifier naming rules and conventions private void ConvertIdentifierNameExpression(SemanticModel model, IdentifierNameSyntax expression) From bbcd3e03d283f55383a87bc77a118510eb6f9936 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Fri, 8 Mar 2024 16:47:12 +0800 Subject: [PATCH 32/33] delegate --- .../Expression/InvocationExpression.cs | 19 ++++++++++++++++++- .../Contract_Delegate.cs | 15 +++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/InvocationExpression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/InvocationExpression.cs index 56acf393c..d929d6a15 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/InvocationExpression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/InvocationExpression.cs @@ -15,6 +15,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Neo.SmartContract; using Neo.VM; +using System; using System.Linq; namespace Neo.Compiler; @@ -102,7 +103,23 @@ private void ConvertMethodInvocationExpression(SemanticModel model, IMethodSymbo /// The syntax representation of the delegate invocation expression statement being converted. /// Arguments of the delegate /// - /// TODO + /// + /// public delegate int MyDelegate(int x, int y); + /// + /// static int CalculateSum(int x, int y) + /// { + /// return x + y; + /// } + /// + /// public void MyMethod() + /// { + /// MyDelegate myDelegate = CalculateSum; + /// int result = myDelegate(5, 6); + /// Runtime.Log($"Sum: {result}"); + /// } + /// + /// myDelegate(5, 6) This line will be converted by the following method. + /// The IdentifierNameSyntax is "myDelegate" the "type" is "MyDelegate". /// private void ConvertDelegateInvocationExpression(SemanticModel model, ExpressionSyntax expression, ArgumentSyntax[] arguments) { diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Delegate.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Delegate.cs index 2ee2f6808..b227353cf 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Delegate.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Delegate.cs @@ -1,5 +1,6 @@ using System; using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Services; namespace Neo.Compiler.CSharp.UnitTests.TestClasses { @@ -14,5 +15,19 @@ private static int privateSum(int a, int b) { return a + b; } + + public delegate int MyDelegate(int x, int y); + + static int CalculateSum(int x, int y) + { + return x + y; + } + + public void TestDelegate() + { + MyDelegate myDelegate = CalculateSum; + int result = myDelegate(5, 6); + Runtime.Log($"Sum: {result}"); + } } } From 0b8358be097b779e460653cf39c0e76ad692c2ba Mon Sep 17 00:00:00 2001 From: Shargon Date: Mon, 11 Mar 2024 15:31:46 -0700 Subject: [PATCH 33/33] Update src/Neo.Compiler.CSharp/MethodConvert/Expression/AssignmentExpression.SimpleAssignment.cs --- .../Expression/AssignmentExpression.SimpleAssignment.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/AssignmentExpression.SimpleAssignment.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/AssignmentExpression.SimpleAssignment.cs index 067ace526..1ae9f98dd 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/AssignmentExpression.SimpleAssignment.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/AssignmentExpression.SimpleAssignment.cs @@ -21,7 +21,6 @@ namespace Neo.Compiler; partial class MethodConvert { - /// /// Converts the code for simple assignment expression into OpCodes. /// The assignment operator = assigns the value of its right-hand operand to a variable,