Skip to content

Commit a5ae6d8

Browse files
committed
Add a tweaked VM
1 parent 661ee87 commit a5ae6d8

File tree

4 files changed

+204
-23
lines changed

4 files changed

+204
-23
lines changed

lib/uplc/machine.ak

Lines changed: 5 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,15 @@ use aiken/builtin
22
use uplc/builtins.{
33
add_integer, default_arg_counts, default_force_counts, subtract_integer,
44
}
5-
use uplc/constant.{Constant, Integer}
5+
use uplc/constant.{Integer}
66
use uplc/term.{
77
Apply, Builtin, Case, Delay, Error, Force, Lambda, TConstant, TConstr, Term,
88
Var,
99
}
10-
11-
pub type Env =
12-
List<Value>
13-
14-
pub type Context {
15-
FrameAwaitArg(Value, Context)
16-
FrameAwaitFunTerm(Env, Term, Context)
17-
FrameAwaitFunValue(Value, Context)
18-
FrameForce(Context)
19-
FrameConstr(Env, Int, List<Term>, List<Value>, Context)
20-
FrameCases(Env, List<Term>, Context)
21-
NoFrame
22-
}
23-
24-
pub type Value {
25-
VCon(Constant)
26-
VDelay(Term, Env)
27-
VLambda { body: Term, env: Env }
28-
// don't need to hold builtin state
29-
// this is literally serializable
30-
VBuiltin { fun: Int, force_count: Int, args_count: Int, args: List<Value> }
31-
VConstr { tag: Int, fields: List<Value> }
10+
use uplc/value.{
11+
Context, Env, FrameAwaitArg, FrameAwaitFunTerm, FrameAwaitFunValue, FrameCases,
12+
FrameConstr, FrameForce, NoFrame, VBuiltin, VCon, VConstr, VDelay, VLambda,
13+
Value,
3214
}
3315

3416
fn list_at(list: List<a>, index: Int) -> a {

lib/uplc/tweaked_machine.ak

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
use aiken/builtin
2+
use uplc/builtins.{default_arg_counts, default_force_counts}
3+
use uplc/constant.{Constant}
4+
use uplc/tweaked_term.{
5+
Apply, Blake2b_256, Builtin, Delay, Error, Force, Hash, Lambda, TConstant,
6+
Term, TermHash, hashing_algo,
7+
}
8+
9+
pub type EnvHash =
10+
Hash<Blake2b_256, Env>
11+
12+
pub type Env {
13+
value: ValueHash,
14+
next: EnvHash,
15+
}
16+
17+
pub type ContextHash =
18+
Hash<Blake2b_256, Context>
19+
20+
pub type Context {
21+
FrameAwaitArg(Value, ContextHash)
22+
FrameAwaitFunTerm(Env, TermHash, ContextHash)
23+
FrameAwaitFunValue(Value, ContextHash)
24+
FrameForce(ContextHash)
25+
FrameConstr(Env, Int, List<TermHash>, List<Value>, ContextHash)
26+
FrameCases(Env, List<TermHash>, ContextHash)
27+
NoFrame
28+
}
29+
30+
pub type ValueHash =
31+
Hash<Blake2b_256, Value>
32+
33+
pub type Value {
34+
VCon(Constant)
35+
VDelay(TermHash, Env)
36+
VLambda { body: TermHash, env: Env }
37+
// don't need to hold builtin state
38+
// this is literally serializable
39+
VBuiltin {
40+
fun: Int,
41+
force_count: Int,
42+
args_count: Int,
43+
args: List<ValueHash>,
44+
}
45+
VConstr { tag: Int, fields: List<ValueHash> }
46+
}
47+
48+
pub type MachineState {
49+
Compute(Context, Env, TermHash)
50+
// ComputeAwaitTerm(Context, Env, TermHash)
51+
Return(Context, ValueHash)
52+
// ReturnAwaitValue(Context, ValueHash)
53+
Done(TermHash)
54+
IteratingEnv(Context, Env, Int)
55+
ErrorState(ByteArray)
56+
}
57+
58+
pub type MachineWrapper {
59+
ms: MachineState,
60+
value: Option<Value>,
61+
term: Option<Term>,
62+
envs: List<Value>,
63+
}
64+
65+
// pub fn run(machine_state: MachineState) {
66+
// when machine_state is {
67+
// Compute(ctx, env, term) -> compute(ctx, env, term)
68+
// _ -> todo
69+
// }
70+
// }
71+
72+
pub fn iterate_env(ctx: Context, env: Env, index: Int, next_env: Option<Env>) {
73+
if index == 1 {
74+
Return(ctx, env.value)
75+
} else {
76+
expect Some(next_env) = next_env
77+
expect env.next == ( next_env |> builtin.serialise_data |> hashing_algo )
78+
79+
IteratingEnv(ctx, next_env, index - 1)
80+
}
81+
}
82+
83+
pub fn compute(
84+
ctx: Context,
85+
env: Env,
86+
term_hash: TermHash,
87+
term: Term,
88+
) -> MachineState {
89+
expect term_hash == ( term |> builtin.serialise_data |> hashing_algo )
90+
91+
when term is {
92+
Delay(inner_hash) ->
93+
Return(
94+
ctx,
95+
VDelay(inner_hash, env) |> builtin.serialise_data |> hashing_algo,
96+
)
97+
Force(inner_hash) -> {
98+
let ctx = ctx |> builtin.serialise_data |> hashing_algo |> FrameForce
99+
100+
Compute(ctx, env, inner_hash)
101+
}
102+
Lambda { body: body_hash } ->
103+
Return(
104+
ctx,
105+
VLambda(body_hash, env) |> builtin.serialise_data |> hashing_algo,
106+
)
107+
Apply { function, argument } -> {
108+
let ctx =
109+
ctx
110+
|> builtin.serialise_data
111+
|> hashing_algo
112+
|> fn(a) { FrameAwaitFunTerm(env, argument, a) }
113+
114+
Compute(ctx, env, function)
115+
}
116+
TConstant(constant) ->
117+
Return(ctx, VCon(constant) |> builtin.serialise_data |> hashing_algo)
118+
119+
Error -> ErrorState("Evaluation Failure")
120+
121+
Builtin(fun) -> {
122+
let force_count = builtin.index_bytearray(default_force_counts, fun)
123+
124+
let args_count = builtin.index_bytearray(default_arg_counts, fun)
125+
126+
Return(
127+
ctx,
128+
VBuiltin { fun, force_count, args_count, args: [] }
129+
|> builtin.serialise_data
130+
|> hashing_algo,
131+
)
132+
}
133+
134+
_ -> fail
135+
}
136+
}

lib/uplc/tweaked_term.ak

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
use aiken/builtin
2+
use uplc/constant.{Constant}
3+
use uplc/term.{DebruijnIndex}
4+
5+
pub type Blake2b_256 =
6+
ByteArray
7+
8+
pub type Hash<alg, data> =
9+
ByteArray
10+
11+
pub type TermHash =
12+
Hash<Blake2b_256, Term>
13+
14+
pub type Term {
15+
Var(DebruijnIndex)
16+
17+
Delay(TermHash)
18+
// param is excluded since it's always 0
19+
Lambda { body: TermHash }
20+
21+
Apply { function: TermHash, argument: TermHash }
22+
23+
TConstant(Constant)
24+
25+
Force(TermHash)
26+
27+
Error
28+
29+
Builtin(Int)
30+
31+
TConstr { tag: Int, fields: List<TermHash> }
32+
33+
Case { constr: TermHash, branches: List<TermHash> }
34+
}
35+
36+
pub fn hashing_algo(b: ByteArray) -> ByteArray {
37+
builtin.blake2b_256(b)
38+
}

lib/uplc/value.ak

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
use uplc/constant.{Constant}
2+
use uplc/term.{Term}
3+
4+
pub type Env =
5+
List<Value>
6+
7+
pub type Context {
8+
FrameAwaitArg(Value, Context)
9+
FrameAwaitFunTerm(Env, Term, Context)
10+
FrameAwaitFunValue(Value, Context)
11+
FrameForce(Context)
12+
FrameConstr(Env, Int, List<Term>, List<Value>, Context)
13+
FrameCases(Env, List<Term>, Context)
14+
NoFrame
15+
}
16+
17+
pub type Value {
18+
VCon(Constant)
19+
VDelay(Term, Env)
20+
VLambda { body: Term, env: Env }
21+
// don't need to hold builtin state
22+
// this is literally serializable
23+
VBuiltin { fun: Int, force_count: Int, args_count: Int, args: List<Value> }
24+
VConstr { tag: Int, fields: List<Value> }
25+
}

0 commit comments

Comments
 (0)