@@ -15,6 +15,7 @@ private struct Word {
1515 bool raw;
1616 bool inline;
1717 Node[] inlineNodes;
18+ bool error;
1819}
1920
2021private struct StructEntry {
@@ -85,6 +86,7 @@ class BackendUXN : CompilerBackend {
8586 types ~= Type(" size" , 2 );
8687 types ~= Type(" usize" , 2 );
8788 types ~= Type(" cell" , 2 );
89+ types ~= Type(" bool" , 2 );
8890
8991 // built in structs
9092 types ~= Type(" Array" , 6 , true , [
@@ -108,13 +110,15 @@ class BackendUXN : CompilerBackend {
108110 foreach (ref type ; types) {
109111 NewConst(format(" %s.sizeof" , type.name), cast (long ) type.size);
110112 }
113+
114+ globals[" _cal_exception" ] = Global(GetType(" Exception" ), false , 0 );
111115 }
112116
113117 override string [] GetVersions () => [
114118 // platform
115119 " UXN" , " BigEndian" , " 16Bit" ,
116120 // features
117- " IO"
121+ " IO" , " Exit "
118122 ];
119123
120124 override string [] FinalCommands () => [
@@ -281,6 +285,31 @@ class BackendUXN : CompilerBackend {
281285 output ~= format(" func__%s\n " , node.name.Sanitise());
282286 }
283287 }
288+
289+ if (word.error) {
290+ if (" __uxn_exception" in words) {
291+ bool crash;
292+
293+ if (inScope) {
294+ crash = ! words[thisFunc].error;
295+ }
296+ else {
297+ crash = true ;
298+ }
299+
300+ if (crash) {
301+ output ~= format(" ;global_%s LDA2\n " , Sanitise(" _cal_exception" ));
302+ output ~= " #0000 NEQ2\n " ;
303+ output ~= format(" ;func__%s JCN\n " , Sanitise(" __uxn_exception" ));
304+ }
305+ else {
306+ CompileReturn(node);
307+ }
308+ }
309+ else {
310+ Warn(node.error, " No exception handler" );
311+ }
312+ }
284313 }
285314 else if (VariableExists(node.name)) {
286315 auto var = GetVariable(node.name);
@@ -346,19 +375,27 @@ class BackendUXN : CompilerBackend {
346375 thisFunc = node.name;
347376
348377 if (node.inline) {
349- words[node.name] = Word(false , true , node.nodes);
378+ if (node.errors) {
379+ output ~= format(" #0000 ;global_%s STA2\n " , Sanitise(" _cal_exception" ));
380+ }
381+
382+ words[node.name] = Word(false , true , node.nodes, node.errors);
350383 }
351384 else {
352385 assert (! inScope);
353386 inScope = true ;
354387
355- words[node.name] = Word(node.raw, false , []);
388+ words[node.name] = Word(node.raw, false , [], node.errors );
356389
357390 string symbol =
358391 node.raw? node.name : format(" func__%s" , node.name.Sanitise());
359392
360393 output ~= format(" @%s\n " , symbol);
361394
395+ if (node.errors) {
396+ output ~= format(" #0000 ;global_%s STA2\n " , Sanitise(" _cal_exception" ));
397+ }
398+
362399 // allocate parameters
363400 size_t paramSize = node.params.length * 2 ;
364401 foreach (ref type ; node.paramTypes) {
@@ -1001,6 +1038,82 @@ class BackendUXN : CompilerBackend {
10011038 }
10021039 }
10031040
1004- override void CompileTryCatch (TryCatchNode node) {}
1005- override void CompileThrow (WordNode node) {}
1041+ override void CompileTryCatch (TryCatchNode node) {
1042+ if (node.func ! in words) {
1043+ Error(node.error, " Function '%s' doesn't exist" , node.func);
1044+ }
1045+
1046+ auto word = words[node.func];
1047+
1048+ if (! word.error) {
1049+ Error(node.error, " Function '%s' doesn't throw" , node.func);
1050+ }
1051+ if (word.raw) {
1052+ Error(node.error, " Non-callisto functions can't throw" );
1053+ }
1054+
1055+ if (word.inline) {
1056+ foreach (inode ; word.inlineNodes) {
1057+ compiler.CompileNode(inode);
1058+ }
1059+ }
1060+ else {
1061+ output ~= format(" func__%s\n " , node.func.Sanitise());
1062+ }
1063+
1064+ ++ blockCounter;
1065+
1066+ output ~= format(" ;global_%s LDA2 #0000 EQU\n " , Sanitise(" _cal_exception" ));
1067+ output ~= format(" ;catch_%d_end JCN\n " , blockCounter);
1068+
1069+ // create scope
1070+ auto oldVars = variables.dup ;
1071+ auto oldSize = GetStackSize();
1072+
1073+ foreach (inode ; node.catchBlock) {
1074+ compiler.CompileNode(inode);
1075+ }
1076+
1077+ // remove scope
1078+ foreach (ref var ; variables) {
1079+ if (oldVars.canFind(var)) continue ;
1080+ if (! var.type.hasDeinit) continue ;
1081+
1082+ output ~= format(" .vsp LDZ2 #.2x ADD2" , var.offset);
1083+ output ~= format(" type_deinit_%s\n " , Sanitise(var.type.name));
1084+ }
1085+ if (GetStackSize() - oldSize > 0 ) {
1086+ output ~= format(
1087+ " .vsp LDZ2 #%.4x ADD .vsp STZ2\n " , GetStackSize() - oldSize
1088+ );
1089+ }
1090+ variables = oldVars;
1091+
1092+ output ~= format(" @catch_%d_end\n " , blockCounter);
1093+ }
1094+
1095+ override void CompileThrow (WordNode node) {
1096+ if (! inScope || (! words[thisFunc].error)) {
1097+ Error(node.error, " Not in a function that can throw" );
1098+ }
1099+ if (words[thisFunc].inline) {
1100+ Error(node.error, " Can't use throw in an inline function" );
1101+ }
1102+
1103+ // set exception error
1104+ output ~= format(" #ffff ;global_%s STA2\n " , Sanitise(" _cal_exception" ));
1105+
1106+ // copy exception message
1107+ // TODO: make this less bloat
1108+ foreach (i ; 0 .. 3 ) {
1109+ output ~= " DUP2 LDA2\n " ;
1110+ output ~= format(
1111+ " ;global_%s #%.2x ADD2 STA2\n " , Sanitise(" _cal_exception" ), i + 1
1112+ );
1113+ output ~= " #0002 ADD2\n " ;
1114+ }
1115+ output ~= " POP2\n " ;
1116+
1117+ CompileReturn(node);
1118+ }
10061119}
0 commit comments