@@ -22,6 +22,7 @@ private struct Word {
2222 WordType type;
2323 bool inline;
2424 Node[] inlineNodes;
25+ bool error;
2526}
2627
2728private struct StructEntry {
@@ -120,6 +121,11 @@ class BackendLua : CompilerBackend {
120121 foreach (ref type ; types) {
121122 NewConst(format(" %s.sizeof" , type.name), cast (long ) type.size);
122123 }
124+
125+ globals ~= Global(
126+ " _cal_exception" , GetType(" Exception" ), globalStack, false , 0
127+ );
128+ globalStack += globals[$ - 1 ].Size();
123129 }
124130
125131 override void NewConst (string name, long value, ErrorInfo error = ErrorInfo.init) {
@@ -217,6 +223,8 @@ class BackendLua : CompilerBackend {
217223 override void End () {
218224 // call destructors
219225 foreach (name, global ; globals) {
226+ if (! global.type.hasDeinit) continue ;
227+
220228 output ~= format(" mem[dsp] = %d\n " , global.addr);
221229 output ~= " dsp = dsp + 1\n " ;
222230 output ~= format(" type_deinit_%s()\n " , global.type.name.Sanitise());
@@ -270,6 +278,19 @@ class BackendLua : CompilerBackend {
270278 else {
271279 output ~= format(" func__%s();\n " , node.name.Sanitise());
272280 }
281+
282+ if (word.error) {
283+ if (" __lua_exception" in words) {
284+ auto exception = GetGlobal(" _cal_exception" );
285+
286+ output ~= format(" if mem[%d] ~= 0 then\n " , exception.addr);
287+ output ~= format(" func__%s()\n " , Sanitise(" __lua_exception" ));
288+ output ~= " end\n " ;
289+ }
290+ else {
291+ Warn(node.error, " No exception handler" );
292+ }
293+ }
273294 }
274295 else if (VariableExists(node.name)) {
275296 auto var = GetVariable(node.name);
@@ -326,16 +347,20 @@ class BackendLua : CompilerBackend {
326347 thisFunc = node.name;
327348
328349 if (node.inline) {
329- words[node.name] = Word(WordType.Callisto, true , node.nodes);
350+ output ~= format(" mem[%d] = 0\n " , GetGlobal(" _cal_exception" ).addr);
351+
352+ words[node.name] = Word(WordType.Callisto, true , node.nodes, node.errors);
330353 }
331354 else {
332355 assert (! inScope);
333356 inScope = true ;
334357
335- words[node.name] = Word(WordType.Callisto, false );
358+ words[node.name] = Word(WordType.Callisto, false , [], node.errors );
336359
337360 output ~= format(" function func__%s()\n " , node.name.Sanitise());
338361
362+ output ~= format(" mem[%d] = 0\n " , GetGlobal(" _cal_exception" ).addr);
363+
339364 // allocate parameters
340365 size_t paramSize = node.params.length;
341366 foreach (ref type ; node.paramTypes) {
@@ -948,6 +973,79 @@ class BackendLua : CompilerBackend {
948973 }
949974 }
950975
951- override void CompileTryCatch (TryCatchNode node) {}
952- override void CompileThrow (WordNode node) {}
976+ override void CompileTryCatch (TryCatchNode node) {
977+ if (node.func ! in words) {
978+ Error(node.error, " Function '%s' doesn't exist" , node.func);
979+ }
980+
981+ auto word = words[node.func];
982+
983+ if (! word.error) {
984+ Error(node.error, " Function '%s' doesn't throw" , node.func);
985+ }
986+ if (word.type != WordType.Callisto) {
987+ Error(node.error, " Non-callisto functions can't throw" );
988+ }
989+
990+ if (word.inline) {
991+ foreach (inode ; word.inlineNodes) {
992+ compiler.CompileNode(inode);
993+ }
994+ }
995+ else {
996+ output ~= format(" func__%s()\n " , node.func.Sanitise());
997+ }
998+
999+ ++ blockCounter;
1000+
1001+ output ~= format(" if mem[%d] == 0 then\n " , GetGlobal(" _cal_exception" ).addr);
1002+ output ~= format(" goto catch_%d_end\n " , blockCounter);
1003+ output ~= " end\n " ;
1004+
1005+ // create scope
1006+ auto oldVars = variables.dup ;
1007+ auto oldSize = GetStackSize();
1008+
1009+ foreach (inode ; node.catchBlock) {
1010+ compiler.CompileNode(inode);
1011+ }
1012+
1013+ // remove scope
1014+ foreach (ref var ; variables) {
1015+ if (oldVars.canFind(var)) continue ;
1016+ if (! var.type.hasDeinit) continue ;
1017+
1018+ output ~= format(" mem[dsp] = vsp + %d\n " , var.offset);
1019+ output ~= " dsp = dsp + 1\n " ;
1020+ output ~= format(" type_deinit_%s()\n " , var.type.name.Sanitise());
1021+ }
1022+ if (GetStackSize() - oldSize > 0 ) {
1023+ output ~= format(" vsp = vsp + %d\n " , GetStackSize() - oldSize);
1024+ }
1025+ variables = oldVars;
1026+
1027+ output ~= format(" ::catch_%d_end::\n " , blockCounter);
1028+ }
1029+
1030+ override void CompileThrow (WordNode node) {
1031+ if (! inScope || (! words[thisFunc].error)) {
1032+ Error(node.error, " Not in a function that can throw" );
1033+ }
1034+ if (words[thisFunc].inline) {
1035+ Error(node.error, " Can't use throw in an inline function" );
1036+ }
1037+
1038+ // set exception error
1039+ output ~= format(" mem[%d] = -1\n " , GetGlobal(" _cal_exception" ).addr);
1040+
1041+ // copy exception message
1042+ output ~= " dsp = dsp - 1\n " ;
1043+ output ~= " for i = 1, 3 do\n " ;
1044+ output ~= format(
1045+ " mem[%d + i] = mem[mem[dsp] + (i - 1)]\n " , GetGlobal(" _cal_exception" ).addr
1046+ );
1047+ output ~= " end\n " ;
1048+
1049+ CompileReturn(node);
1050+ }
9531051}
0 commit comments