Forked from RReverser/simple-stack-machine-in-type-system.ts
Created
December 27, 2020 14:11
-
-
Save runewizard/f1dcb05cee8fee3fa1ed14d4c4caec6b to your computer and use it in GitHub Desktop.
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
// Playground link: https://www.typescriptlang.org/play?#code/PTAEHEEsGcBdQG4FMBO1IHsB2AuUALWWAB2hxAHMZYA6K2fAVwCMaBjDAW2ACUelkaVMABMAZgCMbMQDYAHAFZFAQwAmCkWwAMSACwB2VXJHN98hQu1IFAWABQ92AE9iSUAFEAHkjYAeAMJcnMpYqtAANKAAyrDKsG4AvKAA3qBwymwA1ngA2gC6kQA2GGzKhWQpAL6glQB8oAn2oKCBnMGh0KBInvEdoDmQWABmqC1BIaqRNNODIyig-HB5TaAA-B7efouwkV4+re2qvjFxSJEHE7W1K3gn8QDc9o4ubgDygiiQqki+r8wAVpEAHLKThnUAANTKjCQ9SSILBXR6SD6cE+WAoaxSKxyAGlQINQAAKTJIJwYIagP7-ACUoAAPqAEUg8nh8d1emEmaC3OsoYUYaA8NS8aAAGTE0nkynUmnLOzVPBYASoR4OOzOVwQJCwfkw34A4E8uHcxEclFcqUUqkArEi5l5IWgZWCNXPLUAFUYxEKPyBSM5nSwjE4zFQkR4AYtnRCTnyDX6eRNPByAHJfRiGKnHea+v71pG8F6fX7IjlY1Npjwk267IN4ighhk3ECkBQgSGwyhfABBZidXNc4Oh1D1VLKihxSDIPB9zqVd0ttu+D0mj1RvNtjsj7uzUZz+rrOdO9eDoOd0brVvti-d1dOl2qp4al6gOcrtcbrnX7dd3x7+Y53vI9+3XIsv3PHcsTA50VRQWtNTcHtiB9JwokgCgsBXSIAAUMAHZE+mYDAMF9EITTwgjA1AWAUEFdYYOvD8ENfcAdXQzCPwTU9CO-Ldb18Ycu0PUAm3KNw8FomEWK1ABZRhCg4rCe0iAAhE0chU0BVJzXjOhyKTwUMx1GRyMToHBcyWSxQynSsmS3CiENf1QXsIOdW81PcoTRwTHJphoYtfV7WpK0C71gvUvI0wzCgs0dCUfPg59EOiFggp+Ht3NjfIvLPUAcqTBNVPc8ssCcMKAIWJA4B0rEiRWLL8rKirQACqrth7R11ic5gMt8TqIxq2B1KdJjVJilE4vwbNrjsOlZ0mzMZryBy0uYFzuyavSPJ3PKdqSk1ev6-qe1C0B+vU2o1vkwpTuy8rcu0h64wKbTGEpfLCr8oqkhK5qKzamZhlGbY6vWW7TqG2qywC1SPrCrr6jweGhiW6bszWpzOF7NS4Ua7zb3q-6DqJnrnIErTRpR9yfwEqq51G8mNspyJGeR2DBAWgn8rpnd-xBwD+zO4nCag5nNt8VS2eFjmSeovm-wZ-smaZfj+exyW5y09mOcfFBubsZp9axlhce0o6Q3N8arhuhTzdGpJkNQpTfBWSGIp+U7+xC87vegKWrlC92FNdtjYFds7InD12rvsa6UtfPY2AuUJjlieJznGUIjoztx8tSdIslydrBeiWIsje4pSnKPAqoAGRKMp53qlZU9UdzUkQvBU3ryAGzKVNIgQaEkDrsu9Tcap1kLivsn6AKTiySJJ6rpva9ARua5bnA2+zjuC5ol4e6iHUh+dHlx7mU0p-qpfMlK0vr-vyIqtXrFZ4yeeX9Aavm+FD4Xwfhb2bkaMEK9R71EVJzVAhtmjt07kfVwPdw7nywJfAkZdmQ1A-mkOeJdpg-3DpPXwIDyhgNhGvbeeAyE7z3m0CYiDu6gFTD2VQqhUw4PWESe+j9gbPznq-MuWkqrgxSHgr+BCaA-2xg7WoVD-6b3XjvGBBshT0MOEw4+LDeqcOnsSXhzUn6jB-gzIR18xGf2LgvQhgj1pyIURvWhOClRwTgWMBhoQtHIJYbdPRd8558JoFVUxwjzGjEsRI6x-lbFf0iLdBxRRlE0OUS41R7j9b2AWqotaiwFLwCSMnXwOQVhd20amVBkR0Fgh7p4PR4RSlILHiwypF8aksKcPUxpzDUy6JqA0o24iemn1gGgjBqZVCQCGEMLpgyyk+IqWfKp4zJnTNmc0eZzTFmjOWe0iZUyZn9O6eUvxRy5lNJPkstpWyUA1XyXo+wb1kgrD-hvZ5gzmieDwBILQAzmjNCcHgEQWgViVD+VE+e+R7B1DVEAA | |
type Exec<Commands, State = { stack: [], locals: {} }> = | |
Commands extends [infer Command, ...infer Rest] | |
? Exec<Rest, ExecCommand<State, Command>> | |
: State; | |
type Override<Obj, Name, Value> = Name extends string ? { | |
[K in (keyof Obj) | Name]: K extends Name ? Value : Obj[K & (keyof Obj)] | |
} : never; | |
type GetValue<Obj, Name> = Name extends keyof Obj ? Obj[Name] : never; | |
type Tuple<N extends number, R extends any[] = []> = R['length'] extends N ? R : Tuple<N, [any, ...R]>; | |
interface NegNumber<Abs extends number> { negative: Abs } | |
type Neg<T> = T extends NegNumber<infer Abs> ? Abs : T extends number ? NegNumber<T> : never; | |
type Abs<T> = T extends NegNumber<infer AbsT> ? AbsT : T extends number ? T : never; | |
type ApplySign<T, Pos extends boolean> = Pos extends true ? T : Neg<T>; | |
type GetSign<T> = T extends NegNumber<number> ? false : true; | |
type MulSign<A, B> = [A, B] extends [true, true] | [false, false] ? true : false; | |
type SumNumber<A extends number, B extends number> = [...Tuple<A>, ...Tuple<B>]['length'] & number; | |
type SubTuple<A extends any[], B extends any[]> = B extends [any, ...infer RestB] ? ( | |
A extends [any, ...infer RestA] ? SubTuple<RestA, RestB> : Neg<B['length']> | |
) : A['length']; | |
type SubNumber<A extends number, B extends number> = SubTuple<Tuple<A>, Tuple<B>>; | |
type MulTuple<A extends any[], B extends any[], Buf extends any[] = []> = B extends [any, ...infer RestB] ? MulTuple<A, RestB, [...Buf, ...A]> : Buf['length']; | |
type Sum<A, B> = | |
A extends number ? (B extends number ? SumNumber<A, B> : B extends NegNumber<infer AbsB> ? SubNumber<A, AbsB> : never) : | |
A extends NegNumber<infer AbsA> ? (B extends number ? SubNumber<B, AbsA> : B extends NegNumber<infer AbsB> ? NegNumber<SumNumber<AbsA, AbsB>> : never) : | |
never; | |
type Sub<A, B> = Sum<A, Neg<B>>; | |
type Mul<A, B> = ApplySign< | |
MulTuple<Tuple<Abs<A>>, Tuple<Abs<B>>>, | |
MulSign<GetSign<A>, GetSign<B>> | |
>; | |
type ExecCommand<State, Command> = State extends { stack: [...infer Stack], locals: infer Locals } ? ( | |
Command extends { type: 'Literal', value: infer Value } ? { stack: [...Stack, Value], locals: Locals } : | |
Command extends { type: 'Set', name: infer Name } ? (Stack extends [...infer Stack, infer Value] ? { stack: Stack, locals: Override<Locals, Name, Value> } : never) : | |
Command extends { type: 'Get', name: infer Name } ? { stack: [...Stack, GetValue<Locals, Name>], locals: Locals } : | |
Command extends { type: 'Add' } ? (Stack extends [...infer Stack, infer A, infer B] ? { stack: [...Stack, Sum<A, B>], locals: Locals } : never) : | |
Command extends { type: 'Sub' } ? (Stack extends [...infer Stack, infer A, infer B] ? { stack: [...Stack, Sub<A, B>], locals: Locals } : never) : | |
Command extends { type: 'Mul' } ? (Stack extends [...infer Stack, infer A, infer B] ? { stack: [...Stack, Mul<A, B>], locals: Locals } : never) : | |
never | |
) : never; | |
type Result = Exec<[ | |
{ type: 'Get', name: 'x' }, | |
{ type: 'Get', name: 'y' }, | |
{ type: 'Sub' }, | |
{ type: 'Set', name: 'diff' }, | |
{ type: 'Get', name: 'diff' }, | |
{ type: 'Get', name: 'diff' }, | |
{ type: 'Mul' }, | |
{ type: 'Set', name: 'result' } | |
], { | |
locals: { | |
x: 10, | |
y: 20 | |
}, | |
stack: [] | |
}>; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment