From 1c083487093de2faa6052377e73348804a9ad7e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Tue, 12 Mar 2024 16:58:25 +0800 Subject: [PATCH 1/6] update --- .../MethodConvert/Pattern/BinaryPattern.cs | 69 +++++++++++++++++++ .../MethodConvert/Pattern/Pattern.cs | 10 +++ .../Contract_Foreach.cs | 61 +++++++++++++++- .../Contract_Pattern.cs | 25 +++++++ 4 files changed, 164 insertions(+), 1 deletion(-) diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Pattern/BinaryPattern.cs b/src/Neo.Compiler.CSharp/MethodConvert/Pattern/BinaryPattern.cs index 551e420fb..1370164e4 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Pattern/BinaryPattern.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Pattern/BinaryPattern.cs @@ -33,29 +33,98 @@ private void ConvertBinaryPattern(SemanticModel model, BinaryPatternSyntax patte } } + /// + /// Convet a "and" pattern to OpCodes. + /// + /// + /// Conjunctive "and" pattern that matches an expression when both patterns match the expression. + /// + /// The semantic model providing context and information about "and" pattern. + /// The left pattern to be converted. + /// The right pattern to be converted. + /// The index of the local variable. + /// + /// The following example shows how you can combine relational patterns to check if a value is in a certain range: + /// + /// public static string Classify(int measurement) => measurement switch + /// { + /// < -40 => "Too low", + /// >= -40 and < 0 => "Low", + /// >= 0 and < 10 => "Acceptable", + /// >= 10 and < 20 => "High", + /// >= 20 => "Too high" + /// }; + /// + /// private void ConvertAndPattern(SemanticModel model, PatternSyntax left, PatternSyntax right, byte localIndex) { + // Define jump targets for the right pattern and the end of the conversion process JumpTarget rightTarget = new(); JumpTarget endTarget = new(); + + // Convert the left pattern ConvertPattern(model, left, localIndex); + + // Jump to the right pattern if the left pattern matches Jump(OpCode.JMPIF_L, rightTarget); + + // Push 'false' onto the evaluation stack and jump to the end if the left pattern does not match Push(false); Jump(OpCode.JMP_L, endTarget); + + // Define an instruction for the right pattern and convert it rightTarget.Instruction = AddInstruction(OpCode.NOP); ConvertPattern(model, right, localIndex); + + // Define an instruction for the end of the conversion process endTarget.Instruction = AddInstruction(OpCode.NOP); } + /// + /// Convet a "or" pattern to OpCodes. + /// + /// + /// Disjunctive "or" pattern that matches an expression when either pattern matches the expression. + /// + /// The semantic model providing context and information about "or" pattern. + /// The left pattern to be converted. + /// The right pattern to be converted. + /// The index of the local variable. + /// + /// As the following example shows: + /// + /// public static string GetCalendarSeason(int month) => month switch + /// { + /// 3 or 4 or 5 => "spring", + /// 6 or 7 or 8 => "summer", + /// 9 or 10 or 11 => "autumn", + /// 12 or 1 or 2 => "winter", + /// _ => throw new Exception($"Unexpected month: {month}."), + /// }; + /// + /// As the preceding example shows, you can repeatedly use the pattern combinators in a pattern. + /// private void ConvertOrPattern(SemanticModel model, PatternSyntax left, PatternSyntax right, byte localIndex) { + // Define jump targets for the right pattern and the end of the conversion process JumpTarget rightTarget = new(); JumpTarget endTarget = new(); + + // Convert the left pattern ConvertPattern(model, left, localIndex); + + // Jump to the right pattern if the left pattern does not match Jump(OpCode.JMPIFNOT_L, rightTarget); + + // Push 'true' onto the evaluation stack and jump to the end if the left pattern matches Push(true); Jump(OpCode.JMP_L, endTarget); + + // Define an instruction for the right pattern and convert it rightTarget.Instruction = AddInstruction(OpCode.NOP); ConvertPattern(model, right, localIndex); + + // Define an instruction for the end of the conversion process endTarget.Instruction = AddInstruction(OpCode.NOP); } } diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Pattern/Pattern.cs b/src/Neo.Compiler.CSharp/MethodConvert/Pattern/Pattern.cs index 14246bfec..5be10b43f 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Pattern/Pattern.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Pattern/Pattern.cs @@ -17,6 +17,16 @@ namespace Neo.Compiler; partial class MethodConvert { + /// + /// Convert pattern to OpCodes. + /// + /// + /// + /// + /// + /// + /// Pattern matching - the is and switch expressions, and operators and, or and not in patterns + /// private void ConvertPattern(SemanticModel model, PatternSyntax pattern, byte localIndex) { switch (pattern) diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Foreach.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Foreach.cs index 44f19e4d9..de23be194 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Foreach.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Foreach.cs @@ -1,5 +1,6 @@ using Neo.SmartContract.Framework; using Neo.SmartContract.Framework.Attributes; +using Neo.SmartContract.Framework.Services; using System.Numerics; namespace Neo.Compiler.CSharp.UnitTests.TestClasses @@ -147,7 +148,25 @@ public static int IntForeachBreak(int breakIndex) { foreach (var item in a) { - if (breakIndex-- <= 0) break; + if (breakIndex-- <= 0) + break; + sum += item; + } + } + catch { } + return sum; + } + + public static int TestContinue() + { + int[] a = new int[] { 1, 2, 3, 4, 5 }; + int sum = 0; + try + { + foreach (var item in a) + { + if (item % 2 == 0) + continue; sum += item; } } @@ -166,5 +185,45 @@ public static int IntForloop() } return sum; } + + public static void TestIteratorForEach() + { + var tokens = new StorageMap(Storage.CurrentContext, 3).Find(FindOptions.KeysOnly | FindOptions.RemovePrefix); + foreach (var item in tokens) + { + Runtime.Log(item.ToString()); + } + } + + static (int, string)[] Function1() => new (int, string)[] { new(1, "hello"), new(2, "world") }; + + public static void TestForEachVariable() + { + + foreach (var (a, b) in Function1()) + { + Runtime.Log($"{a}: {b}"); + } + } + + public static void TestDo() + { + int n = 0; + do + { + Runtime.Log(n.ToString()); + n++; + } while (n < 5); + } + + public static void TestWhile() + { + int n = 0; + while (n < 5) + { + Runtime.Log(n.ToString()); + n++; + } + } } } diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Pattern.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Pattern.cs index 0aecc210a..4c1900412 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Pattern.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Pattern.cs @@ -24,5 +24,30 @@ public bool between3(int value) _ => false, }; } + + public bool between4(int value) + { + return value is <= 0; + } + + public static bool TestNotPattern(bool? x) => x is not null; + + public static string Classify(int measurement) => measurement switch + { + < -40 => "Too low", + >= -40 and < 0 => "Low", + >= 0 and < 10 => "Acceptable", + >= 10 and < 20 => "High", + >= 20 => "Too high" + }; + + public static string GetCalendarSeason(int month) => month switch + { + 3 or 4 or 5 => "spring", + 6 or 7 or 8 => "summer", + 9 or 10 or 11 => "autumn", + 12 or 1 or 2 => "winter", + _ => throw new Exception($"Unexpected month: {month}."), + }; } } From 62b5844617e38b51e171cf12be0d952f408b11f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Tue, 12 Mar 2024 17:19:17 +0800 Subject: [PATCH 2/6] update --- .../MethodConvert/Pattern/ConstantPattern.cs | 25 +++++++++++++++++++ .../MethodConvert/Pattern/NotPattern.cs | 18 +++++++++++++ .../MethodConvert/Pattern/Pattern.cs | 13 ++++++++++ 3 files changed, 56 insertions(+) diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Pattern/ConstantPattern.cs b/src/Neo.Compiler.CSharp/MethodConvert/Pattern/ConstantPattern.cs index f95b1624f..5d3bb51e8 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Pattern/ConstantPattern.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Pattern/ConstantPattern.cs @@ -13,11 +13,36 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using Neo.VM; +using System.Drawing; namespace Neo.Compiler; partial class MethodConvert { + /// + /// Convet a constant pattern to OpCodes. + /// + /// The semantic model providing context and information about constant pattern. + /// The constant pattern to be converted. + /// The index of the local variable. + /// + /// You use a constant pattern to test if an expression result equals a specified constant. + /// In a constant pattern, you can use any constant expression, such as: + /// integer, char, string, Boolean value true or false, enum value, the name of a declared const field or local, null + /// + /// + /// + /// public static int GetGroupTicketPrice(int visitorCount) => visitorCount switch + /// { + /// 1 => 12, + /// 2 => 20, + /// 3 => 27, + /// 4 => 32, + /// 0 => 0, + /// _ => throw new Exception($"Not supported number of visitors: {visitorCount}"), + /// }; + /// + /// private void ConvertConstantPattern(SemanticModel model, ConstantPatternSyntax pattern, byte localIndex) { AccessSlot(OpCode.LDLOC, localIndex); diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Pattern/NotPattern.cs b/src/Neo.Compiler.CSharp/MethodConvert/Pattern/NotPattern.cs index 4a6e0fb04..8362baa2d 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Pattern/NotPattern.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Pattern/NotPattern.cs @@ -18,6 +18,24 @@ namespace Neo.Compiler; partial class MethodConvert { + /// + /// Convet a "not" pattern to OpCodes. + /// + /// + /// Negation "not" pattern that matches an expression when the negated pattern doesn't match the expression. + /// + /// The semantic model providing context and information about "not" pattern. + /// The "not" pattern to be converted. + /// The index of the local variable. + /// + /// The following example shows how you can negate a constant null pattern to check if an expression is non-null: + /// + /// if (input is not null) + /// { + /// // ... + /// } + /// + /// private void ConvertNotPattern(SemanticModel model, UnaryPatternSyntax pattern, byte localIndex) { ConvertPattern(model, pattern.Pattern, localIndex); diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Pattern/Pattern.cs b/src/Neo.Compiler.CSharp/MethodConvert/Pattern/Pattern.cs index 5be10b43f..bca2908e4 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Pattern/Pattern.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Pattern/Pattern.cs @@ -31,27 +31,40 @@ private void ConvertPattern(SemanticModel model, PatternSyntax pattern, byte loc { switch (pattern) { + //Convet "and" / "or" pattern to OpCodes. + //Example: return value is > 1 and < 100; + //Example: return value is >= 80 or <= 20; case BinaryPatternSyntax binaryPattern: ConvertBinaryPattern(model, binaryPattern, localIndex); break; + //Convet constant pattern to OpCodes. + //Example: return value is > 1; + //Example: return value is null; case ConstantPatternSyntax constantPattern: ConvertConstantPattern(model, constantPattern, localIndex); break; + //TODO case DeclarationPatternSyntax declarationPattern: ConvertDeclarationPattern(model, declarationPattern, localIndex); break; + //TODO case DiscardPatternSyntax: Push(true); break; + //TODO case RelationalPatternSyntax relationalPattern: ConvertRelationalPattern(model, relationalPattern, localIndex); break; + //TODO case TypePatternSyntax typePattern: ConvertTypePattern(model, typePattern, localIndex); break; + //Convet "not" pattern to OpCodes. + //Example: return value is not null; case UnaryPatternSyntax unaryPattern when unaryPattern.OperatorToken.ValueText == "not": ConvertNotPattern(model, unaryPattern, localIndex); break; + //TODO case ParenthesizedPatternSyntax parenthesizedPattern: ConvertParenthesizedPatternSyntax(model, parenthesizedPattern, localIndex); break; From e43f0a714afa7358019c993936f93df734426356 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Wed, 13 Mar 2024 16:26:08 +0800 Subject: [PATCH 3/6] DeclarationPatternSyntax --- .../Pattern/DeclarationPattern.cs | 24 +++++++++++++++++++ .../MethodConvert/Pattern/Pattern.cs | 8 +++++-- .../Contract_Pattern.cs | 15 ++++++++++++ 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Pattern/DeclarationPattern.cs b/src/Neo.Compiler.CSharp/MethodConvert/Pattern/DeclarationPattern.cs index 4c2da4290..f819c1e3c 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Pattern/DeclarationPattern.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Pattern/DeclarationPattern.cs @@ -18,6 +18,30 @@ namespace Neo.Compiler; partial class MethodConvert { + /// + /// Convet declaration pattern to OpCodes. + /// + /// The semantic model providing context and information about declaration pattern. + /// The declaration pattern to be converted. + /// The index of the local variable. + /// + /// With a declaration pattern, you can also declare a new local variable. + /// When a declaration pattern matches an expression, that variable is assigned a converted expression result, + /// as the following example shows: + /// + /// object greeting = "Hello, World!"; + /// if (greeting is string message) + /// { + /// Runtime.Log(message); + /// } + /// object greeting2 = "Hello, World!"; + /// if (greeting2 is string _) + /// { + /// Runtime.Log("greeting2 is string"); + /// } + /// + /// string message is DiscardDesignationSyntax, string _ is SingleVariableDesignationSyntax. + /// private void ConvertDeclarationPattern(SemanticModel model, DeclarationPatternSyntax pattern, byte localIndex) { ITypeSymbol type = model.GetTypeInfo(pattern.Type).Type!; diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Pattern/Pattern.cs b/src/Neo.Compiler.CSharp/MethodConvert/Pattern/Pattern.cs index bca2908e4..eaf86ae0e 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Pattern/Pattern.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Pattern/Pattern.cs @@ -37,13 +37,14 @@ private void ConvertPattern(SemanticModel model, PatternSyntax pattern, byte loc case BinaryPatternSyntax binaryPattern: ConvertBinaryPattern(model, binaryPattern, localIndex); break; - //Convet constant pattern to OpCodes. + //Convet constant pattern to OpCodes. //Example: return value is > 1; //Example: return value is null; case ConstantPatternSyntax constantPattern: ConvertConstantPattern(model, constantPattern, localIndex); break; - //TODO + //Convet declaration pattern to OpCodes. + //Example: if (greeting is string message) case DeclarationPatternSyntax declarationPattern: ConvertDeclarationPattern(model, declarationPattern, localIndex); break; @@ -69,6 +70,9 @@ private void ConvertPattern(SemanticModel model, PatternSyntax pattern, byte loc ConvertParenthesizedPatternSyntax(model, parenthesizedPattern, localIndex); break; default: + //Example: + //object greeting = "Hello, World!"; + //if (greeting3 is var message) { } throw new CompilationException(pattern, DiagnosticId.SyntaxNotSupported, $"Unsupported pattern: {pattern}"); } } diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Pattern.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Pattern.cs index 4c1900412..46203cd1a 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Pattern.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Pattern.cs @@ -1,5 +1,6 @@ using System; using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Services; namespace Neo.Compiler.CSharp.UnitTests.TestClasses { @@ -49,5 +50,19 @@ public bool between4(int value) 12 or 1 or 2 => "winter", _ => throw new Exception($"Unexpected month: {month}."), }; + + public static void TestDeclarationPattern() + { + object greeting = "Hello, World!"; + if (greeting is string message) + { + Runtime.Log(message); + } + object greeting2 = "Hello, World!"; + if (greeting2 is string _) + { + Runtime.Log("greeting2 is string"); + } + } } } From 6b628b858ac647a12273a9111e9e72b8c2bd5386 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Thu, 14 Mar 2024 11:53:42 +0800 Subject: [PATCH 4/6] update --- .../MethodConvert/Expression/Expression.cs | 1 + .../MethodConvert/Pattern/BinaryPattern.cs | 8 ++++++ .../Pattern/ParenthesizedPattern.cs | 14 ++++++++++ .../MethodConvert/Pattern/Pattern.cs | 23 +++++++++++++--- .../Pattern/RelationalPattern.cs | 26 +++++++++++++++++++ .../MethodConvert/Pattern/TypePattern.cs | 25 ++++++++++++++++++ .../Contract_Pattern.cs | 9 +++++++ 7 files changed, 102 insertions(+), 4 deletions(-) diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs index 5e94fff96..e3a10ea16 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs @@ -215,6 +215,7 @@ private void ConvertExpression(SemanticModel model, ExpressionSyntax syntax, Syn ConvertTupleExpression(model, expression); break; default: + //Example: typeof(Transaction); throw new CompilationException(syntax, DiagnosticId.SyntaxNotSupported, $"Unsupported syntax: {syntax}"); } } diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Pattern/BinaryPattern.cs b/src/Neo.Compiler.CSharp/MethodConvert/Pattern/BinaryPattern.cs index 1370164e4..e616fb5a0 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Pattern/BinaryPattern.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Pattern/BinaryPattern.cs @@ -18,6 +18,14 @@ namespace Neo.Compiler; partial class MethodConvert { + /// + /// Convet a binary pattern to OpCodes. + /// + /// The semantic model providing context and information about binary pattern. + /// The binary pattern to be converted. + /// The index of the local variable. + /// + /// private void ConvertBinaryPattern(SemanticModel model, BinaryPatternSyntax pattern, byte localIndex) { switch (pattern.OperatorToken.ValueText) diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Pattern/ParenthesizedPattern.cs b/src/Neo.Compiler.CSharp/MethodConvert/Pattern/ParenthesizedPattern.cs index 694c8f571..7e87f9076 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Pattern/ParenthesizedPattern.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Pattern/ParenthesizedPattern.cs @@ -18,6 +18,20 @@ namespace Neo.Compiler; partial class MethodConvert { + /// + /// Convet a parenthesized pattern to OpCodes. + /// + /// The semantic model providing context and information about parenthesized pattern. + /// The parenthesized pattern to be converted. + /// The index of the local variable. + /// + /// You can put parentheses around any pattern. + /// Typically, you do that to emphasize or change the precedence in logical patterns, + /// as the following example shows: + /// + /// + /// return value is (> 1 and < 100); + /// private void ConvertParenthesizedPatternSyntax(SemanticModel model, ParenthesizedPatternSyntax pattern, byte localIndex) { ConvertPattern(model, pattern.Pattern, localIndex); diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Pattern/Pattern.cs b/src/Neo.Compiler.CSharp/MethodConvert/Pattern/Pattern.cs index eaf86ae0e..b3a18beee 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Pattern/Pattern.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Pattern/Pattern.cs @@ -48,15 +48,23 @@ private void ConvertPattern(SemanticModel model, PatternSyntax pattern, byte loc case DeclarationPatternSyntax declarationPattern: ConvertDeclarationPattern(model, declarationPattern, localIndex); break; - //TODO + //Convet discard pattern (_) to OpCodes. + //Example: if (greeting2 is string _) case DiscardPatternSyntax: Push(true); break; - //TODO + //Convet relational pattern to OpCodes. + //Example: return value is > 1; case RelationalPatternSyntax relationalPattern: ConvertRelationalPattern(model, relationalPattern, localIndex); break; - //TODO + //Convert type pattern to OpCodes. + //Example: + //switch (o1) + //{ + // case byte[]: break; + // case string: break; + //} case TypePatternSyntax typePattern: ConvertTypePattern(model, typePattern, localIndex); break; @@ -65,7 +73,8 @@ private void ConvertPattern(SemanticModel model, PatternSyntax pattern, byte loc case UnaryPatternSyntax unaryPattern when unaryPattern.OperatorToken.ValueText == "not": ConvertNotPattern(model, unaryPattern, localIndex); break; - //TODO + //Convet parenthesized to OpCodes. + //Example: return value is (> 1 and < 100); case ParenthesizedPatternSyntax parenthesizedPattern: ConvertParenthesizedPatternSyntax(model, parenthesizedPattern, localIndex); break; @@ -73,6 +82,12 @@ private void ConvertPattern(SemanticModel model, PatternSyntax pattern, byte loc //Example: //object greeting = "Hello, World!"; //if (greeting3 is var message) { } + //Example: + //public static void M(object o1, object o2) + //{ + // var t = (o1, o2); + // if (t is (int, string)) { } + //} throw new CompilationException(pattern, DiagnosticId.SyntaxNotSupported, $"Unsupported pattern: {pattern}"); } } diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Pattern/RelationalPattern.cs b/src/Neo.Compiler.CSharp/MethodConvert/Pattern/RelationalPattern.cs index 4d0e6f89e..f25ecd333 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Pattern/RelationalPattern.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Pattern/RelationalPattern.cs @@ -18,6 +18,32 @@ namespace Neo.Compiler; partial class MethodConvert { + /// + /// Convet relational pattern to OpCodes. + /// + /// The semantic model providing context and information about convert pattern. + /// The convert pattern to be converted. + /// The index of the local variable. + /// + /// + /// In a relational pattern, you can use any of the relational operators , <=, or >=]]>. + /// The right-hand part of a relational pattern must be a constant expression. + /// The constant expression can be of an integer, char, or enum type. + /// To check if an expression result is in a certain range, match it against a conjunctive and pattern. + /// + /// + /// You use a relational pattern to compare an expression result with a constant, + /// as the following example shows: + /// + /// int a = 1; + /// var b = a switch + /// { + /// > 1 => true, + /// <= 1 => false + /// }; + /// + /// > 1 and <= 1 is RelationalPatternSyntax; + /// private void ConvertRelationalPattern(SemanticModel model, RelationalPatternSyntax pattern, byte localIndex) { AccessSlot(OpCode.LDLOC, localIndex); diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Pattern/TypePattern.cs b/src/Neo.Compiler.CSharp/MethodConvert/Pattern/TypePattern.cs index 5e09c3b3d..9af335cf2 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Pattern/TypePattern.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Pattern/TypePattern.cs @@ -18,6 +18,31 @@ namespace Neo.Compiler; partial class MethodConvert { + /// + /// Convet type pattern to OpCodes. + /// + /// The semantic model providing context and information about type pattern. + /// The type pattern to be converted. + /// The index of the local variable. + /// + /// + /// public void M(object o1) + /// { + /// switch (o1) + /// { + /// case byte[]: break; + /// case string: break; + /// } + /// } + /// + /// byte[] and string is TypePatternSyntax. + /// + /// + /// Only few type judgments are supported, such as: bool, byte[], string, + /// Not supported ByteString, BigInteger. + /// + /// + private void ConvertTypePattern(SemanticModel model, TypePatternSyntax pattern, byte localIndex) { ITypeSymbol type = model.GetTypeInfo(pattern.Type).Type!; diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Pattern.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Pattern.cs index 46203cd1a..a8c3f5c15 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Pattern.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Pattern.cs @@ -64,5 +64,14 @@ public static void TestDeclarationPattern() Runtime.Log("greeting2 is string"); } } + + public void TestTypePattern(object o1) + { + switch (o1) + { + case byte[]: break; + case string: break; + } + } } } From 3e503a469775a06512e02d385ba407ef5f5f3709 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Thu, 14 Mar 2024 14:15:20 +0800 Subject: [PATCH 5/6] Update Contract_Pattern.cs --- tests/Neo.Compiler.CSharp.TestContracts/Contract_Pattern.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Pattern.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Pattern.cs index a8c3f5c15..baf4fac82 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Pattern.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Pattern.cs @@ -71,6 +71,7 @@ public void TestTypePattern(object o1) { case byte[]: break; case string: break; + case bool: break; } } } From 13e25ac91ab5a8624b5f6304ece303f3be5218e5 Mon Sep 17 00:00:00 2001 From: Shargon Date: Wed, 13 Mar 2024 23:59:04 -0700 Subject: [PATCH 6/6] Apply suggestions from code review --- src/Neo.Compiler.CSharp/MethodConvert/Pattern/ConstantPattern.cs | 1 - src/Neo.Compiler.CSharp/MethodConvert/Pattern/TypePattern.cs | 1 - 2 files changed, 2 deletions(-) diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Pattern/ConstantPattern.cs b/src/Neo.Compiler.CSharp/MethodConvert/Pattern/ConstantPattern.cs index 5d3bb51e8..437e90ee4 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Pattern/ConstantPattern.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Pattern/ConstantPattern.cs @@ -13,7 +13,6 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using Neo.VM; -using System.Drawing; namespace Neo.Compiler; diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Pattern/TypePattern.cs b/src/Neo.Compiler.CSharp/MethodConvert/Pattern/TypePattern.cs index 9af335cf2..da28b344f 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Pattern/TypePattern.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Pattern/TypePattern.cs @@ -42,7 +42,6 @@ partial class MethodConvert /// Not supported ByteString, BigInteger. /// /// - private void ConvertTypePattern(SemanticModel model, TypePatternSyntax pattern, byte localIndex) { ITypeSymbol type = model.GetTypeInfo(pattern.Type).Type!;