min is actually mainly an interpreted language, BUT it can actually as of recently be transpiled to Nim (which in turns generates C code which can be compiled), so you can actually create executable files from min, which is pretty cool.
Adding this form of compilation was actually really easy because in a stack-based language there's essentially one instruction: push an item on the stack... the only things I had to add was wrapping external files in functions to delay their evaluation to when they are required.
Combinators like linrec etc are no different from ordinary operators, they are pushed on the stack and they rearrange it...
Consider the following program that takes an integer as input and prints its factorial:
args
(compiled?)
(0)
(1)
if get int
(dup 0 ==) (1 +)
(dup 1 -) (*) linrec
puts
Note how I am getting the first or second argument from the command line depending if I am running the program through the interpreter (min factorial.min 5) or as a stand-alone executable (./factorial 5).When running the min "compiler":
min -c factorial.min
...the following Nim code gets generated. As you can see, it's mostly just pushing items on the stack :) import min
MINCOMPILED = true
var i = newMinInterpreter("factorial.min")
i.stdLib()
### factorial.min (main)
i.push MinValue(kind: minSymbol, symVal: "args", column: 4, line: 1, filename: "factorial.min")
var q1 = newSeq[MinValue](0)
q1.add MinValue(kind: minSymbol, symVal: "compiled?", column: 10, line: 2, filename: "factorial.min")
i.push MinValue(kind: minQuotation, qVal: q1)
var q2 = newSeq[MinValue](0)
q2.add MinValue(kind: minInt, intVal: 0)
i.push MinValue(kind: minQuotation, qVal: q2)
var q3 = newSeq[MinValue](0)
q3.add MinValue(kind: minInt, intVal: 1)
i.push MinValue(kind: minQuotation, qVal: q3)
i.push MinValue(kind: minSymbol, symVal: "if", column: 2, line: 5, filename: "factorial.min")
i.push MinValue(kind: minSymbol, symVal: "get", column: 6, line: 5, filename: "factorial.min")
i.push MinValue(kind: minSymbol, symVal: "int", column: 10, line: 5, filename: "factorial.min")
var q4 = newSeq[MinValue](0)
q4.add MinValue(kind: minSymbol, symVal: "dup", column: 4, line: 6, filename: "factorial.min")
q4.add MinValue(kind: minInt, intVal: 0)
q4.add MinValue(kind: minSymbol, symVal: "==", column: 9, line: 6, filename: "factorial.min")
i.push MinValue(kind: minQuotation, qVal: q4)
var q5 = newSeq[MinValue](0)
q5.add MinValue(kind: minInt, intVal: 1)
q5.add MinValue(kind: minSymbol, symVal: "+", column: 15, line: 6, filename: "factorial.min")
i.push MinValue(kind: minQuotation, qVal: q5)
var q6 = newSeq[MinValue](0)
q6.add MinValue(kind: minSymbol, symVal: "dup", column: 4, line: 7, filename: "factorial.min")
q6.add MinValue(kind: minInt, intVal: 1)
q6.add MinValue(kind: minSymbol, symVal: "-", column: 8, line: 7, filename: "factorial.min")
i.push MinValue(kind: minQuotation%, qVal: q6)
var q7 = newSeq[MinValue](0)
q7.add MinValue(kind: minSymbol, symVal: "*", column: 12, line: 7, filename: "factorial.min")
i.push MinValue(kind: minQuotation, qVal: q7)
i.push MinValue(kind: minSymbol, symVal: "linrec", column: 20, line: 7, filename: "factorial.min")
i.push MinValue(kind: minSymbol, symVal: "puts", column: 4, line: 8, filename: "factorial.min")