-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathBoolOperations.cs
More file actions
271 lines (199 loc) · 12 KB
/
BoolOperations.cs
File metadata and controls
271 lines (199 loc) · 12 KB
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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
using GlyphScriptCompiler.Contracts;
using static GlyphScriptCompiler.Models.OperationKind;
namespace GlyphScriptCompiler.TypeOperations;
public class BoolOperations : IOperationProvider
{
private readonly LLVMModuleRef _llvmModule;
private readonly LLVMBuilderRef _llvmBuilder;
public BoolOperations(LLVMModuleRef llvmModule, LLVMBuilderRef llvmBuilder)
{
_llvmModule = llvmModule;
_llvmBuilder = llvmBuilder;
}
public void Initialize()
{
LlvmHelper.CreateStringConstant(_llvmModule, "strp_bool_true", "true\n\0");
LlvmHelper.CreateStringConstant(_llvmModule, "strp_bool_false", "false\n\0");
LlvmHelper.CreateStringConstant(_llvmModule, "strs_bool", "%s\0");
}
public GlyphScriptValue? DefaultValueImplementation(RuleContext context, IReadOnlyList<GlyphScriptValue> parameters) =>
GetDefaultValue();
public GlyphScriptValue GetDefaultValue() =>
new GlyphScriptValue(LLVM.ConstInt(LLVM.Int1Type(), 0, false), GlyphScriptType.Boolean);
public GlyphScriptValue? PrintImplementation(RuleContext context, IReadOnlyList<GlyphScriptValue> parameters)
{
if (parameters.Count != 1)
throw new InvalidOperationException("Invalid number of parameters for print operation");
var value = parameters[0];
if (value.Type != GlyphScriptType.Boolean)
throw new InvalidOperationException("Invalid type for print operation");
var printfFunc = LLVM.GetNamedFunction(_llvmModule, "printf");
if (printfFunc.Pointer == IntPtr.Zero)
throw new InvalidOperationException("printf function not found");
var currentBlock = LLVM.GetInsertBlock(_llvmBuilder);
var function = LLVM.GetBasicBlockParent(currentBlock);
var trueBlock = LLVM.AppendBasicBlock(function, "print_true");
var falseBlock = LLVM.AppendBasicBlock(function, "print_false");
var mergeBlock = LLVM.AppendBasicBlock(function, "print_merge");
LLVM.BuildCondBr(_llvmBuilder, value.Value, trueBlock, falseBlock);
LLVM.PositionBuilderAtEnd(_llvmBuilder, trueBlock);
var trueFormatGlobal = LLVM.GetNamedGlobal(_llvmModule, "strp_bool_true");
if (trueFormatGlobal.Pointer == IntPtr.Zero)
throw new InvalidOperationException("Format string for true printing not found");
var trueFormatPtr = LlvmHelper.GetStringPtr(_llvmBuilder, trueFormatGlobal);
LLVM.BuildCall(_llvmBuilder, printfFunc, [trueFormatPtr], string.Empty);
LLVM.BuildBr(_llvmBuilder, mergeBlock);
LLVM.PositionBuilderAtEnd(_llvmBuilder, falseBlock);
var falseFormatGlobal = LLVM.GetNamedGlobal(_llvmModule, "strp_bool_false");
if (falseFormatGlobal.Pointer == IntPtr.Zero)
throw new InvalidOperationException("Format string for false printing not found");
var falseFormatPtr = LlvmHelper.GetStringPtr(_llvmBuilder, falseFormatGlobal);
LLVM.BuildCall(_llvmBuilder, printfFunc, [falseFormatPtr], string.Empty);
LLVM.BuildBr(_llvmBuilder, mergeBlock);
LLVM.PositionBuilderAtEnd(_llvmBuilder, mergeBlock);
return value;
}
public GlyphScriptValue? ReadImplementation(RuleContext context, IReadOnlyList<GlyphScriptValue> parameters)
{
if (parameters.Count != 1)
throw new InvalidOperationException("Invalid number of parameters for read operation");
var variable = parameters[0];
if (variable.Type != GlyphScriptType.Boolean)
throw new InvalidOperationException("Invalid type for read operation");
var scanfFunc = LLVM.GetNamedFunction(_llvmModule, "scanf");
if (scanfFunc.Pointer == IntPtr.Zero)
throw new InvalidOperationException("scanf function not found");
var formatGlobal = LLVM.GetNamedGlobal(_llvmModule, "strs_bool");
if (formatGlobal.Pointer == IntPtr.Zero)
throw new InvalidOperationException("Format string for boolean reading not found");
var formatPtr = LlvmHelper.GetStringPtr(_llvmBuilder, formatGlobal);
var bufferSize = LLVM.ConstInt(LLVM.Int32Type(), 10, false); // Big enough for "true" or "false"
var buffer = LLVM.BuildArrayAlloca(_llvmBuilder, LLVM.Int8Type(), bufferSize, "bool_buffer");
LLVM.BuildCall(_llvmBuilder, scanfFunc, [formatPtr, buffer], string.Empty);
var trueString = LLVM.BuildGlobalStringPtr(_llvmBuilder, "true", "true_const");
var strcmpFunc = LLVM.GetNamedFunction(_llvmModule, "strcmp");
if (strcmpFunc.Pointer == IntPtr.Zero)
{
var strcmpType = LLVM.FunctionType(LLVM.Int32Type(), [LLVM.PointerType(LLVM.Int8Type(), 0), LLVM.PointerType(LLVM.Int8Type(), 0)], false);
strcmpFunc = LLVM.AddFunction(_llvmModule, "strcmp", strcmpType);
}
var comparisonResult = LLVM.BuildCall(_llvmBuilder, strcmpFunc, [buffer, trueString], "strcmp_result");
var isTrue = LLVM.BuildICmp(_llvmBuilder, LLVMIntPredicate.LLVMIntEQ, comparisonResult, LLVM.ConstInt(LLVM.Int32Type(), 0, false), "is_true");
return new GlyphScriptValue(isTrue, GlyphScriptType.Boolean);
}
public GlyphScriptValue? ParseImmediateImplementation(RuleContext context, IReadOnlyList<GlyphScriptValue> parameters)
{
var immediateValueContext = context as GlyphScriptParser.ImmediateValueContext
?? throw new InvalidOperationException("Invalid context for parsing immediate value");
if (immediateValueContext.TRUE_LITERAL() != null)
{
return new GlyphScriptValue(LLVM.ConstInt(LLVM.Int1Type(), 1, false), GlyphScriptType.Boolean);
}
else if (immediateValueContext.FALSE_LITERAL() != null)
{
return new GlyphScriptValue(LLVM.ConstInt(LLVM.Int1Type(), 0, false), GlyphScriptType.Boolean);
}
throw new InvalidOperationException("Invalid context for parsing boolean value");
}
public GlyphScriptValue? MultiplicationImplementation(RuleContext context, IReadOnlyList<GlyphScriptValue> parameters)
{
if (parameters.Count != 2)
throw new InvalidOperationException("Invalid number of parameters for AND operation");
var left = parameters[0];
var right = parameters[1];
if (left.Type != GlyphScriptType.Boolean || right.Type != GlyphScriptType.Boolean)
throw new InvalidOperationException("Invalid types for AND operation");
return And(left, right);
}
public GlyphScriptValue And(GlyphScriptValue left, GlyphScriptValue right)
{
var currentBlock = LLVM.GetInsertBlock(_llvmBuilder);
var function = LLVM.GetBasicBlockParent(currentBlock);
var rightOperandBlock = LLVM.AppendBasicBlock(function, "and_right_operand");
var mergeBlock = LLVM.AppendBasicBlock(function, "and_merge");
LLVM.BuildCondBr(_llvmBuilder, left.Value, rightOperandBlock, mergeBlock);
LLVM.PositionBuilderAtEnd(_llvmBuilder, mergeBlock);
var phi = LLVM.BuildPhi(_llvmBuilder, LLVM.Int1Type(), "and_result");
LLVM.AddIncoming(phi, [LLVM.ConstInt(LLVM.Int1Type(), 0, false)], [currentBlock], 1u);
LLVM.PositionBuilderAtEnd(_llvmBuilder, rightOperandBlock);
LLVM.BuildBr(_llvmBuilder, mergeBlock);
LLVM.PositionBuilderAtEnd(_llvmBuilder, mergeBlock);
LLVM.AddIncoming(phi, [right.Value], [rightOperandBlock], 1u);
LLVM.PositionBuilderAtEnd(_llvmBuilder, mergeBlock);
return new GlyphScriptValue(phi, GlyphScriptType.Boolean);
}
public GlyphScriptValue? AdditionImplementation(RuleContext context, IReadOnlyList<GlyphScriptValue> parameters)
{
if (parameters.Count != 2)
throw new InvalidOperationException("Invalid number of parameters for OR operation");
var left = parameters[0];
var right = parameters[1];
if (left.Type != GlyphScriptType.Boolean || right.Type != GlyphScriptType.Boolean)
throw new InvalidOperationException("Invalid types for OR operation");
return Or(left, right);
}
public GlyphScriptValue Or(GlyphScriptValue left, GlyphScriptValue right)
{
if (left.Type != GlyphScriptType.Boolean || right.Type != GlyphScriptType.Boolean)
throw new InvalidOperationException("Invalid types for OR operation");
var currentBlock = LLVM.GetInsertBlock(_llvmBuilder);
var function = LLVM.GetBasicBlockParent(currentBlock);
var rightOperandBlock = LLVM.AppendBasicBlock(function, "or_right_operand");
var mergeBlock = LLVM.AppendBasicBlock(function, "or_merge");
LLVM.BuildCondBr(_llvmBuilder, left.Value, mergeBlock, rightOperandBlock);
LLVM.PositionBuilderAtEnd(_llvmBuilder, mergeBlock);
var phi = LLVM.BuildPhi(_llvmBuilder, LLVM.Int1Type(), "or_result");
LLVM.AddIncoming(phi, [LLVM.ConstInt(LLVM.Int1Type(), 1, false)], [currentBlock], 1u);
LLVM.PositionBuilderAtEnd(_llvmBuilder, rightOperandBlock);
LLVM.BuildBr(_llvmBuilder, mergeBlock);
LLVM.PositionBuilderAtEnd(_llvmBuilder, mergeBlock);
LLVM.AddIncoming(phi, [right.Value], [rightOperandBlock], 1u);
return new GlyphScriptValue(phi, GlyphScriptType.Boolean);
}
public GlyphScriptValue? XorImplementation(RuleContext context, IReadOnlyList<GlyphScriptValue> parameters)
{
if (parameters.Count != 2)
throw new InvalidOperationException("Invalid number of parameters for XOR operation");
var left = parameters[0];
var right = parameters[1];
if (left.Type != GlyphScriptType.Boolean || right.Type != GlyphScriptType.Boolean)
throw new InvalidOperationException("Invalid types for XOR operation");
return Xor(left, right);
}
public GlyphScriptValue Xor(GlyphScriptValue left, GlyphScriptValue right)
{
if (left.Type != GlyphScriptType.Boolean || right.Type != GlyphScriptType.Boolean)
throw new InvalidOperationException("Invalid types for XOR operation");
var result = LLVM.BuildXor(_llvmBuilder, left.Value, right.Value, "bool_xor");
return new GlyphScriptValue(result, GlyphScriptType.Boolean);
}
public GlyphScriptValue? NotImplementation(RuleContext context, IReadOnlyList<GlyphScriptValue> parameters)
{
if (parameters.Count != 1)
throw new InvalidOperationException("Invalid number of parameters for NOT operation");
var value = parameters[0];
if (value.Type != GlyphScriptType.Boolean)
throw new InvalidOperationException("Invalid type for NOT operation");
return Not(value);
}
public GlyphScriptValue Not(GlyphScriptValue value)
{
if (value.Type != GlyphScriptType.Boolean)
throw new InvalidOperationException("Invalid type for NOT operation");
var result = LLVM.BuildNot(_llvmBuilder, value.Value, "bool_not");
return new GlyphScriptValue(result, GlyphScriptType.Boolean);
}
public IReadOnlyDictionary<OperationSignature, OperationImplementation> Operations =>
new Dictionary<OperationSignature, OperationImplementation>()
{
{ new OperationSignature(DefaultValue, [GlyphScriptType.Boolean]), DefaultValueImplementation },
{ new OperationSignature(ParseImmediate, [GlyphScriptType.Boolean]), ParseImmediateImplementation },
{ new OperationSignature(Print, [GlyphScriptType.Boolean]), PrintImplementation },
{ new OperationSignature(Read, [GlyphScriptType.Boolean]), ReadImplementation },
// Boolean operations
{ new OperationSignature(Multiplication, [GlyphScriptType.Boolean, GlyphScriptType.Boolean]), MultiplicationImplementation },
{ new OperationSignature(Addition, [GlyphScriptType.Boolean, GlyphScriptType.Boolean]), AdditionImplementation },
{ new OperationSignature(OperationKind.Not, [GlyphScriptType.Boolean]), NotImplementation },
{ new OperationSignature(OperationKind.Xor, [GlyphScriptType.Boolean, GlyphScriptType.Boolean]), XorImplementation }
};
}