@@ -206,6 +206,13 @@ class BackendLua : CompilerBackend {
206206 }
207207
208208 override void End () {
209+ // call destructors
210+ foreach (name, global ; globals) {
211+ output ~= format(" mem[dsp] = %d\n " , global.addr);
212+ output ~= " dsp = dsp + 1\n " ;
213+ output ~= format(" type_deinit_%s()\n " , global.type.name.Sanitise());
214+ }
215+
209216 output ~= " end\n " ;
210217
211218 // create arrays
@@ -326,6 +333,12 @@ class BackendLua : CompilerBackend {
326333 size_t scopeSize;
327334 foreach (ref var ; variables) {
328335 scopeSize += var.Size();
336+
337+ if (var.type.hasDeinit) {
338+ output ~= format(" mem[dsp] = vsp + %d\n " , var.offset);
339+ output ~= " dsp = dsp + 1\n " ;
340+ output ~= format(" type_deinit_%s()\n " , var.type.name.Sanitise());
341+ }
329342 }
330343 output ~= format(" vsp = vsp + %d\n " , scopeSize);
331344 output ~= " end\n " ;
@@ -358,6 +371,14 @@ class BackendLua : CompilerBackend {
358371 }
359372
360373 // remove scope
374+ foreach (ref var ; variables) {
375+ if (oldVars.canFind(var)) continue ;
376+ if (! var.type.hasDeinit) continue ;
377+
378+ output ~= format(" mem[dsp] = vsp + %d\n " , var.offset);
379+ output ~= " dsp = dsp + 1\n " ;
380+ output ~= format(" type_deinit_%s()\n " , var.type.name.Sanitise());
381+ }
361382 if (GetStackSize() - oldSize > 0 ) {
362383 output ~= format(" vsp = vsp + %d\n " , GetStackSize() - oldSize);
363384 }
@@ -370,9 +391,27 @@ class BackendLua : CompilerBackend {
370391 }
371392
372393 if (node.hasElse) {
394+ // create scope
395+ auto oldVars = variables.dup ;
396+ auto oldSize = GetStackSize();
397+
373398 foreach (ref inode ; node.doElse) {
374399 compiler.CompileNode(inode);
375400 }
401+
402+ // remove scope
403+ foreach (ref var ; variables) {
404+ if (oldVars.canFind(var)) continue ;
405+ if (! var.type.hasDeinit) continue ;
406+
407+ output ~= format(" mem[dsp] = vsp + %d\n " , var.offset);
408+ output ~= " dsp = dsp + 1\n " ;
409+ output ~= format(" type_deinit_%s()\n " , var.type.name.Sanitise());
410+ }
411+ if (GetStackSize() - oldSize > 0 ) {
412+ output ~= format(" vsp = vsp + %d\n " , GetStackSize() - oldSize);
413+ }
414+ variables = oldVars;
376415 }
377416
378417 output ~= format(" ::if_%d_end::\n " , blockNum);
@@ -399,6 +438,14 @@ class BackendLua : CompilerBackend {
399438
400439 // restore scope
401440 output ~= format(" ::while_%d_next::\n " , blockNum);
441+ foreach (ref var ; variables) {
442+ if (oldVars.canFind(var)) continue ;
443+ if (! var.type.hasDeinit) continue ;
444+
445+ output ~= format(" mem[dsp] = vsp + %d\n " , var.offset);
446+ output ~= " dsp = dsp + 1\n " ;
447+ output ~= format(" type_deinit_%s()\n " , var.type.name.Sanitise());
448+ }
402449 if (GetStackSize() - oldSize > 0 ) {
403450 output ~= format(" vsp = vsp + %d\n " , GetStackSize() - oldSize);
404451 }
@@ -447,6 +494,12 @@ class BackendLua : CompilerBackend {
447494 if (var.Size() == 1 ) {
448495 output ~= " mem[vsp] = 0\n " ;
449496 }
497+
498+ if (var.type.hasInit) { // call constructor
499+ output ~= " mem[dsp] = vsp\n " ;
500+ output ~= " dsp = dsp + 1\n " ;
501+ output ~= format(" type_init_%s()\n " , var.type.name.Sanitise());
502+ }
450503 }
451504 else {
452505 Global global;
@@ -458,6 +511,12 @@ class BackendLua : CompilerBackend {
458511 globals ~= global;
459512
460513 globalStack += global.Size();
514+
515+ if (global.type.hasInit) { // call constructor
516+ output ~= format(" mem[dsp] = %d\n " , global.addr);
517+ output ~= " dsp = dsp + 1\n " ;
518+ output ~= format(" type_init_%s()\n " , global.type.name.Sanitise());
519+ }
461520 }
462521 }
463522
@@ -622,6 +681,12 @@ class BackendLua : CompilerBackend {
622681 size_t scopeSize;
623682 foreach (ref var ; variables) {
624683 scopeSize += var.Size();
684+
685+ if (var.type.hasDeinit) {
686+ output ~= format(" mem[dsp] = vsp + %d\n " , var.offset);
687+ output ~= " dsp = dsp + 1\n " ;
688+ output ~= format(" type_deinit_%s()\n " , var.type.name.Sanitise());
689+ }
625690 }
626691 output ~= format(" vsp = vsp + %d\n " , scopeSize);
627692
@@ -754,7 +819,64 @@ class BackendLua : CompilerBackend {
754819 output ~= " dsp = dsp + 1\n " ;
755820 }
756821
757- override void CompileImplement (ImplementNode node) {}
822+ override void CompileImplement (ImplementNode node) {
823+ if (! TypeExists(node.structure)) {
824+ Error(node.error, " Type '%s' doesn't exist" , node.structure);
825+ }
826+ auto type = GetType(node.structure);
827+
828+ string labelName;
829+
830+ switch (node.method) {
831+ case " init" : {
832+ if (GetType(node.structure).hasInit) {
833+ Error(node.error, " Already implemented in type" );
834+ }
835+
836+ type.hasInit = true ;
837+ labelName = format(" type_init_%s" , Sanitise(node.structure));
838+ break ;
839+ }
840+ case " deinit" : {
841+ if (GetType(node.structure).hasDeinit) {
842+ Error(node.error, " Already implemented in type" );
843+ }
844+
845+ type.hasDeinit = true ;
846+ labelName = format(" type_deinit_%s" , Sanitise(node.structure));
847+ break ;
848+ }
849+ default : Error (node.error, " Unknown method '%s'" , node.method);
850+ }
851+
852+ SetType(type.name, type);
853+
854+ assert (! inScope);
855+ inScope = true ;
856+
857+ output ~= format(" function %s()\n " , labelName);
858+
859+ foreach (ref inode ; node.nodes) {
860+ compiler.CompileNode(inode);
861+ }
862+
863+ size_t scopeSize;
864+ foreach (ref var ; variables) {
865+ scopeSize += var.Size();
866+
867+ if (var.type.hasDeinit) {
868+ output ~= format(" lea rax, [rsp + %d\n ]" , var.offset);
869+ output ~= " mov [r15], rax\n " ;
870+ output ~= " add r15, 8\n " ;
871+ output ~= format(" call __type_deinit_%s\n " , Sanitise(var.type.name));
872+ }
873+ }
874+ output ~= format(" vsp = vsp + %d\n " , scopeSize);
875+ output ~= " end\n " ;
876+
877+ inScope = false ;
878+ variables = [];
879+ }
758880
759881 override void CompileSet (SetNode node) {
760882 if (VariableExists(node.var)) {
0 commit comments