@@ -15,6 +15,7 @@ private struct Word {
15
15
bool raw;
16
16
bool inline;
17
17
Node[] inlineNodes;
18
+ bool error;
18
19
}
19
20
20
21
private struct StructEntry {
@@ -121,6 +122,8 @@ class BackendRM86 : CompilerBackend {
121
122
globals[" __rm86_argv" ] = Global(GetType(" addr" ), false , 0 );
122
123
globals[" __rm86_arglen" ] = Global(GetType(" cell" ), false , 0 );
123
124
}
125
+
126
+ globals[" _cal_exception" ] = Global(GetType(" Exception" ), false , 0 );
124
127
}
125
128
126
129
override void NewConst (string name, long value, ErrorInfo error = ErrorInfo.init) {
@@ -179,7 +182,7 @@ class BackendRM86 : CompilerBackend {
179
182
" RM86" , " LittleEndian" , " 16Bit" ,
180
183
// features
181
184
" IO"
182
- ] ~ (os == " dos" ? [" DOS" , " Args" ] : os == " bare-metal" ? [" BareMetal" ] : []);
185
+ ] ~ (os == " dos" ? [" DOS" , " Args" , " Exit " ] : os == " bare-metal" ? [" BareMetal" ] : []);
183
186
184
187
override string [] FinalCommands () => [
185
188
format(" mv %s %s.asm" , compiler.outFile, compiler.outFile),
@@ -330,6 +333,32 @@ class BackendRM86 : CompilerBackend {
330
333
output ~= format(" call __func__%s\n " , node.name.Sanitise());
331
334
}
332
335
}
336
+
337
+ if (word.error) {
338
+ if (" __rm86_exception" in words) {
339
+ bool crash;
340
+
341
+ if (inScope) {
342
+ crash = ! words[thisFunc].error;
343
+ }
344
+ else {
345
+ crash = true ;
346
+ }
347
+
348
+ if (crash) {
349
+ output ~= format(" mov bx, __global_%s\n " , Sanitise(" _cal_exception" ));
350
+ output ~= " mov ax, [bx]\n " ;
351
+ output ~= " cmp ax, 0\n " ;
352
+ output ~= format(" jne __func__%s\n " , Sanitise(" __rm86_exception" ));
353
+ }
354
+ else {
355
+ CompileReturn(node);
356
+ }
357
+ }
358
+ else {
359
+ Warn(node.error, " No exception handler" );
360
+ }
361
+ }
333
362
}
334
363
else if (VariableExists(node.name)) {
335
364
auto var = GetVariable(node.name);
@@ -405,19 +434,27 @@ class BackendRM86 : CompilerBackend {
405
434
thisFunc = node.name;
406
435
407
436
if (node.inline) {
408
- words[node.name] = Word(false , true , node.nodes);
437
+ if (node.errors) {
438
+ output ~= format(" mov word [__global_%s], 0\n " , Sanitise(" _cal_exception" ));
439
+ }
440
+
441
+ words[node.name] = Word(false , true , node.nodes, node.errors);
409
442
}
410
443
else {
411
444
assert (! inScope);
412
445
inScope = true ;
413
446
414
- words[node.name] = Word(node.raw, false , []);
447
+ words[node.name] = Word(node.raw, false , [], node.errors );
415
448
416
449
string symbol =
417
450
node.raw? node.name : format(" __func__%s" , node.name.Sanitise());
418
451
419
452
output ~= format(" %s:\n " , symbol);
420
453
454
+ if (node.errors) {
455
+ output ~= format(" mov word [__global_%s], 0\n " , Sanitise(" _cal_exception" ));
456
+ }
457
+
421
458
// allocate parameters
422
459
size_t paramSize = node.params.length * 2 ;
423
460
foreach (ref type ; node.paramTypes) {
@@ -1073,6 +1110,78 @@ class BackendRM86 : CompilerBackend {
1073
1110
}
1074
1111
}
1075
1112
1076
- override void CompileTryCatch (TryCatchNode node) {}
1077
- override void CompileThrow (WordNode node) {}
1113
+ override void CompileTryCatch (TryCatchNode node) {
1114
+ if (node.func ! in words) {
1115
+ Error(node.error, " Function '%s' doesn't exist" , node.func);
1116
+ }
1117
+
1118
+ auto word = words[node.func];
1119
+
1120
+ if (! word.error) {
1121
+ Error(node.error, " Function '%s' doesn't throw" , node.func);
1122
+ }
1123
+ if (word.raw) {
1124
+ Error(node.error, " Non-callisto functions can't throw" );
1125
+ }
1126
+
1127
+ if (word.inline) {
1128
+ foreach (inode ; word.inlineNodes) {
1129
+ compiler.CompileNode(inode);
1130
+ }
1131
+ }
1132
+ else {
1133
+ output ~= format(" call __func__%s\n " , node.func.Sanitise());
1134
+ }
1135
+
1136
+ ++ blockCounter;
1137
+
1138
+ output ~= format(" mov ax, [__global_%s]\n " , Sanitise(" _cal_exception" ));
1139
+ output ~= " cmp ax, 0\n " ;
1140
+ output ~= format(" je __catch_%d_end\n " , blockCounter);
1141
+
1142
+ // create scope
1143
+ auto oldVars = variables.dup ;
1144
+ auto oldSize = GetStackSize();
1145
+
1146
+ foreach (inode ; node.catchBlock) {
1147
+ compiler.CompileNode(inode);
1148
+ }
1149
+
1150
+ // remove scope
1151
+ foreach (ref var ; variables) {
1152
+ if (oldVars.canFind(var)) continue ;
1153
+ if (! var.type.hasDeinit) continue ;
1154
+
1155
+ output ~= format(" lea ax, [sp + %d\n ]" , var.offset);
1156
+ output ~= " mov [si], ax\n " ;
1157
+ output ~= " add si, 2\n " ;
1158
+ output ~= format(" call __type_deinit_%s\n " , Sanitise(var.type.name));
1159
+ }
1160
+ if (GetStackSize() - oldSize > 0 ) {
1161
+ output ~= format(" add sp, %d\n " , GetStackSize() - oldSize);
1162
+ }
1163
+ variables = oldVars;
1164
+
1165
+ output ~= format(" __catch_%d_end:\n " , blockCounter);
1166
+ }
1167
+
1168
+ override void CompileThrow (WordNode node) {
1169
+ if (! inScope || (! words[thisFunc].error)) {
1170
+ Error(node.error, " Not in a function that can throw" );
1171
+ }
1172
+
1173
+ // set exception error
1174
+ output ~= format(" mov word [__global_%s], 0xFFFF\n " , Sanitise(" _cal_exception" ));
1175
+
1176
+ // copy exception message
1177
+ output ~= " sub si, 2\n " ;
1178
+ output ~= " mov bx, si\n " ;
1179
+ output ~= " mov si, [bx]\n " ;
1180
+ output ~= format(" lea di, [__global_%s + 2]\n " , Sanitise(" _cal_exception" ));
1181
+ output ~= " mov cx, 3\n " ;
1182
+ output ~= " rep movsw\n " ;
1183
+ output ~= " mov si, bx\n " ;
1184
+
1185
+ CompileReturn(node);
1186
+ }
1078
1187
}
0 commit comments