/
VM.fs
124 lines (110 loc) · 3.96 KB
/
VM.fs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
namespace Fslisp.Core
type VM(context: IContext, env: Env<Value>, code: Code<Value>) =
let mutable stack = []
let mutable env = env
let mutable code = code
let mutable dump = []
member _.Context = context
member _.Push(value: Value) =
stack <- value :: stack
member _.Pop(): Value =
match stack with
| head :: rest ->
stack <- rest
head
| _ ->
raise (InternalErrorException "Inconsistent stack")
member _.Enter(nextEnv: Env<Value>, nextCode: Code<Value>) =
match code with
| Code [Inst.Leave] -> () // tailcall: skip this frame
| _ -> dump <- (env, code) :: dump
env <- nextEnv
code <- nextCode
member _.Leave() =
match dump with
| (lastEnv, lastCode) :: rest ->
env <- lastEnv
code <- lastCode
dump <- rest
| _ ->
raise (InternalErrorException "Inconsistent dump")
member self.Apply(f: Value, args: Value list) =
match f with
| Sexp.Pure (Native.Builtin builtin) ->
builtin.Run self (f :: args)
| Sexp.Pure (Native.Fun closure) ->
let env = Env(Some closure.Env)
match Pattern.bind closure.Pattern args with
| Ok mapping ->
Map.iter env.Define mapping
self.Enter(env, closure.Body)
| Error e ->
raise (InternalErrorException ("This function " + e))
| _ ->
raise (EvaluationErrorException "Cannot call: ")
member self.ApplyNever(f: Value, args: Value list) =
stack <- []
code <- Code [Inst.Leave]
dump <- []
self.Apply(f, args)
member _.ApplyCont(cont: Cont) =
stack <- cont.Stack
env <- cont.Env
code <- cont.Code
dump <- cont.Dump
member _.CaptureCont(): Cont =
{ Stack = stack
Env = env
Code = code
Dump = dump }
member self.RunInst(inst: Inst<Value>) =
match inst with
| Inst.Ldc constant ->
self.Push constant
| Inst.Ldv variable ->
self.Push (env.Get variable)
| Inst.Ldf (pattern, body) ->
self.Push (Sexp.Pure (Native.Fun { Env = env; Pattern = pattern; Body = body }))
| Inst.Ldm (pattern, body) ->
self.Push (Sexp.Pure (Native.Macro { Env = env; Pattern = pattern; Body = body }))
| Inst.Ldb name ->
match context.Builtins.Get name with
| Some builtin ->
self.Push (Sexp.Pure (Native.Builtin builtin))
| None ->
raise (EvaluationErrorException ("Unsupported builtin: " + name))
| Inst.Sel (a, b) ->
let branch = if self.Pop() |> Sexp.test then a else b
self.Enter(Env(Some env), branch)
| Inst.App argc ->
let mutable args = []
for _ = 1 to argc do args <- self.Pop() :: args
let f = self.Pop()
self.Apply(f, args)
| Inst.Leave ->
self.Leave()
| Inst.Pop ->
self.Pop() |> ignore
| Inst.Def name ->
let v = self.Pop()
env.Define name v
| Inst.Set name ->
let v = self.Pop()
env.Set name v
member self.Run(): Value =
match code.Next() with
| Some (inst, rest) ->
code <- rest
self.RunInst inst
self.Run()
| None ->
self.Pop()
interface IVM with
member self.Push(value) = self.Push(value)
member self.Apply(f, args) = self.Apply(f, args)
member self.ApplyNever(f, args) = self.ApplyNever(f, args)
member self.ApplyCont(cont) = self.ApplyCont(cont)
member self.CaptureCont() = self.CaptureCont()
member self.Context = self.Context
static member Execute (context: IContext) (env: Env<Value>) (code: Code<Value>): Value =
VM(context, env, code).Run()