forked from neo-project/neo-devpack-dotnet
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathBinaryExpression.cs
158 lines (149 loc) · 7.67 KB
/
BinaryExpression.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
// Copyright (C) 2015-2023 The Neo Project.
//
// The Neo.Compiler.CSharp is free software distributed under the MIT
// software license, see the accompanying file LICENSE in the main directory
// of the project or http://www.opensource.org/licenses/mit-license.php
// for more details.
//
// Redistribution and use in source and binary forms with or without
// modifications are permitted.
extern alias scfx;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Neo.VM;
namespace Neo.Compiler;
partial class MethodConvert
{
/// <summary>
/// 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.
/// </summary>
/// <param name="model">The semantic model providing context and information about binary expression.</param>
/// <param name="expression">The syntax representation of the binary expression statement being converted.</param>
/// <exception cref="CompilationException">If an unsupported operator is encountered</exception>
/// <seealso href="https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/boolean-logical-operators">Boolean logical operators - AND, OR</seealso>
/// <seealso href="https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast">Type-testing operators and cast expressions - is, as</seealso>
/// <seealso href="https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/null-coalescing-operator">?? operators - the null-coalescing operators</seealso>
/// <seealso href="https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators">Bitwise and shift operators</seealso>
/// <seealso href="https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/arithmetic-operators">Arithmetic operators</seealso>
/// <seealso href="https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/boolean-logical-operators">Boolean logical operators - AND, OR, NOT, XOR</seealso>
private void ConvertBinaryExpression(SemanticModel model, BinaryExpressionSyntax expression)
{
switch (expression.OperatorToken.ValueText)
{
case "||":
ConvertLogicalOrExpression(model, expression.Left, expression.Right);
return;
case "&&":
ConvertLogicalAndExpression(model, expression.Left, expression.Right);
return;
case "is":
ConvertIsExpression(model, expression.Left, expression.Right);
return;
case "as":
ConvertAsExpression(model, expression.Left, expression.Right);
return;
case "??":
ConvertCoalesceExpression(model, expression.Left, expression.Right);
return;
}
IMethodSymbol? symbol = (IMethodSymbol?)model.GetSymbolInfo(expression).Symbol;
if (symbol is not null && TryProcessSystemOperators(model, symbol, expression.Left, expression.Right))
return;
ConvertExpression(model, expression.Left);
ConvertExpression(model, expression.Right);
(OpCode opcode, bool checkResult) = expression.OperatorToken.ValueText switch
{
"+" => (OpCode.ADD, true),
"-" => (OpCode.SUB, true),
"*" => (OpCode.MUL, true),
"/" => (OpCode.DIV, false),
"%" => (OpCode.MOD, false),
"<<" => (OpCode.SHL, true),
">>" => (OpCode.SHR, false),
"|" => (OpCode.OR, false),
"&" => (OpCode.AND, false),
"^" => (OpCode.XOR, false),
"==" => (OpCode.EQUAL, false),
"!=" => (OpCode.NOTEQUAL, false),
"<" => (OpCode.LT, false),
"<=" => (OpCode.LE, false),
">" => (OpCode.GT, false),
">=" => (OpCode.GE, false),
_ => throw new CompilationException(expression.OperatorToken, DiagnosticId.SyntaxNotSupported, $"Unsupported operator: {expression.OperatorToken}")
};
AddInstruction(opcode);
if (checkResult)
{
ITypeSymbol type = model.GetTypeInfo(expression).Type!;
EnsureIntegerInRange(type);
}
}
private void ConvertLogicalOrExpression(SemanticModel model, ExpressionSyntax left, ExpressionSyntax right)
{
JumpTarget rightTarget = new();
JumpTarget endTarget = new();
ConvertExpression(model, left);
Jump(OpCode.JMPIFNOT_L, rightTarget);
Push(true);
Jump(OpCode.JMP_L, endTarget);
rightTarget.Instruction = AddInstruction(OpCode.NOP);
ConvertExpression(model, right);
endTarget.Instruction = AddInstruction(OpCode.NOP);
}
private void ConvertLogicalAndExpression(SemanticModel model, ExpressionSyntax left, ExpressionSyntax right)
{
JumpTarget rightTarget = new();
JumpTarget endTarget = new();
ConvertExpression(model, left);
Jump(OpCode.JMPIF_L, rightTarget);
Push(false);
Jump(OpCode.JMP_L, endTarget);
rightTarget.Instruction = AddInstruction(OpCode.NOP);
ConvertExpression(model, right);
endTarget.Instruction = AddInstruction(OpCode.NOP);
}
private void ConvertIsExpression(SemanticModel model, ExpressionSyntax left, ExpressionSyntax right)
{
ITypeSymbol type = model.GetTypeInfo(right).Type!;
ConvertExpression(model, left);
IsType(type.GetPatternType());
}
private void ConvertAsExpression(SemanticModel model, ExpressionSyntax left, ExpressionSyntax right)
{
JumpTarget endTarget = new();
ITypeSymbol type = model.GetTypeInfo(right).Type!;
ConvertExpression(model, left);
AddInstruction(OpCode.DUP);
IsType(type.GetPatternType());
Jump(OpCode.JMPIF_L, endTarget);
AddInstruction(OpCode.DROP);
Push((object?)null);
endTarget.Instruction = AddInstruction(OpCode.NOP);
}
private void ConvertCoalesceExpression(SemanticModel model, ExpressionSyntax left, ExpressionSyntax right)
{
JumpTarget endTarget = new();
ConvertExpression(model, left);
AddInstruction(OpCode.DUP);
AddInstruction(OpCode.ISNULL);
Jump(OpCode.JMPIFNOT_L, endTarget);
AddInstruction(OpCode.DROP);
ConvertExpression(model, right);
endTarget.Instruction = AddInstruction(OpCode.NOP);
}
}