Created
April 7, 2020 18:40
-
-
Save nasser/bd3de4582ed96ab496971d4967f15626 to your computer and use it in GitHub Desktop.
MAGE Generators/Coroutines
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Reflection; | |
[assembly: AssemblyVersion("0.0.0.0")] | |
public class ManualCoro | |
{ | |
private int <state>; | |
public void CoroutineMethod() | |
{ | |
switch (this.<state>) | |
{ | |
case 0: | |
this.<state> = -1; | |
Console.WriteLine("A"); | |
this.<state> = 1; | |
return; | |
case 1: | |
this.<state> = -1; | |
Console.WriteLine("B"); | |
this.<state> = 2; | |
return; | |
case 2: | |
this.<state> = -1; | |
if (!DateTime.IsLeapYear(2005)) | |
{ | |
Console.WriteLine("C1"); | |
this.<state> = 3; | |
return; | |
} | |
break; | |
case 3: | |
this.<state> = -1; | |
Console.WriteLine("C2"); | |
break; | |
case 4: | |
this.<state> = -1; | |
break; | |
case 5: | |
this.<state> = -1; | |
this.<state> = 6; | |
return; | |
case 6: | |
this.<state> = -1; | |
Console.WriteLine("F"); | |
return; | |
default: | |
return; | |
} | |
if (DateTime.IsLeapYear(2009)) | |
{ | |
Console.WriteLine("D"); | |
this.<state> = 4; | |
return; | |
} | |
Console.WriteLine("E"); | |
this.<state> = 5; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(defn yield [field state] | |
[(il/ldarg-0) | |
(il/ldc-i4 (int state)) | |
(il/stfld field) | |
(il/ret) | |
(il/label (str "state" state)) | |
(il/ldarg-0) | |
(il/ldc-i4-m1) | |
(il/stfld field)]) | |
(defn yield-header [field count] | |
[(il/ldarg-0) | |
(il/ldfld field) | |
(il/switch (mapv #(il/label (str "state" %)) (range count))) | |
(il/ret) | |
(il/label "state0") | |
(il/ldarg-0) | |
(il/ldc-i4-m1) | |
(il/stfld field)]) | |
(il/emit! | |
(il/assembly+module | |
"out" | |
(il/type | |
"ManualCoro" | |
(let [state-field (il/field Int32 "<state>" System.Reflection.FieldAttributes/Private) | |
cond-label (il/label) | |
loop-start-label (il/label) | |
loop-end-label (il/label)] | |
(il/method | |
"CoroutineMethod" System.Void [] | |
[(yield-header state-field 7) | |
;; (print "A") | |
(il/ldstr "A") | |
(il/call (interop/method Console "WriteLine" String)) | |
;; (yield) | |
(yield state-field 1) | |
;; (print "B") | |
(il/ldstr "B") | |
(il/call (interop/method Console "WriteLine" String)) | |
;; (yield) | |
(yield state-field 2) | |
;; (when (DateTime/IsLeapYear 2005) | |
(il/ldc-i4 (int 2005)) | |
(il/call (interop/method DateTime "IsLeapYear" Int32)) | |
(il/brtrue cond-label) | |
;; (print "C1") | |
(il/ldstr "C1") | |
(il/call (interop/method Console "WriteLine" String)) | |
;; (yield) | |
(yield state-field 3) | |
;; (print "C2") | |
(il/ldstr "C2") | |
(il/call (interop/method Console "WriteLine" String)) | |
;; ) | |
cond-label | |
;; (while (DateTime/IsLeapYear 2009) | |
loop-start-label | |
(il/ldc-i4 (int 2009)) | |
(il/call (interop/method DateTime "IsLeapYear" Int32)) | |
(il/brfalse loop-end-label) | |
;; (print "D") | |
(il/ldstr "D") | |
(il/call (interop/method Console "WriteLine" String)) | |
;; (yield) | |
(yield state-field 4) | |
(il/br loop-start-label) | |
loop-end-label | |
;; ) | |
;; (print "E") | |
(il/ldstr "E") | |
(il/call (interop/method Console "WriteLine" String)) | |
;; (yield) | |
(yield state-field 5) | |
;; (yield) | |
(yield state-field 6) | |
;; (print "F") | |
(il/ldstr "F") | |
(il/call (interop/method Console "WriteLine" String)) | |
(il/ret)] | |
))))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(print "A") | |
(yield) | |
(print "B") | |
(yield) | |
(when (DateTime/IsLeapYear 2005) | |
(print "C1") | |
(yield) | |
(print "C2")) | |
(while (DateTime/IsLeapYear 2009) | |
(print "D") | |
(yield)) | |
(print "E") | |
(yield) | |
(yield) | |
(print "F") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Playing around with emitting coroutines using MAGE, trying to mimic the transformation that C# does. The idea is to turn a function with
yield
expressions into a stateful generator object that implements a state machine. You wantyield
to work inside of loops and conditionals. It seems to be pretty simple when operating against bytecode for a stack machine?yield
expression represents a state in the finite state machineyield
expression a sequential state number, as captured by theyield
function inmage-code.clj
.yield
expands into the following instructions:yield-header
inmage-source.clj
):I am not sure how important assigning -1 to the state field is. I do it here to mimic Roslyn's output.